aboutsummaryrefslogtreecommitdiffstats
path: root/docs/_scripts/siphon/parsers.py
diff options
context:
space:
mode:
Diffstat (limited to 'docs/_scripts/siphon/parsers.py')
-rw-r--r--docs/_scripts/siphon/parsers.py164
1 files changed, 164 insertions, 0 deletions
diff --git a/docs/_scripts/siphon/parsers.py b/docs/_scripts/siphon/parsers.py
new file mode 100644
index 00000000000..1a7d1f59539
--- /dev/null
+++ b/docs/_scripts/siphon/parsers.py
@@ -0,0 +1,164 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import html
+import pyparsing as pp
+
+# Some useful primitives
+ident = pp.Word(pp.alphas + "_", pp.alphas + pp.nums + "_")
+intNum = pp.Word(pp.nums)
+hexNum = pp.Literal("0x") + pp.Word(pp.hexnums)
+octalNum = pp.Literal("0") + pp.Word("01234567")
+integer = (hexNum | octalNum | intNum) + pp.Optional(
+ pp.Literal("ULL") | pp.Literal("LL") | pp.Literal("L")
+)
+floatNum = pp.Regex(r"\d+(\.\d*)?([eE]\d+)?") + pp.Optional(pp.Literal("f"))
+char = pp.Literal("'") + pp.Word(pp.printables, exact=1) + pp.Literal("'")
+arrayIndex = integer | ident
+
+lbracket = pp.Literal("(").suppress()
+rbracket = pp.Literal(")").suppress()
+lbrace = pp.Literal("{").suppress()
+rbrace = pp.Literal("}").suppress()
+comma = pp.Literal(",").suppress()
+equals = pp.Literal("=").suppress()
+dot = pp.Literal(".").suppress()
+semicolon = pp.Literal(";").suppress()
+
+# initializer := { [member = ] (variable | expression | { initializer } ) }
+typeName = ident
+varName = ident
+typeSpec = (
+ pp.Optional("unsigned")
+ + pp.oneOf("int long short float double char u8 i8 void")
+ + pp.Optional(pp.Word("*"), default="")
+)
+typeCast = pp.Combine("(" + (typeSpec | typeName) + ")").suppress()
+
+string = pp.Combine(
+ pp.OneOrMore(pp.QuotedString(quoteChar='"', escChar="\\", multiline=True)),
+ adjacent=False,
+)
+literal = pp.Optional(typeCast) + (integer | floatNum | char | string)
+var = pp.Combine(pp.Optional(typeCast) + varName + pp.Optional("[" + arrayIndex + "]"))
+
+# This could be more complete, but suffices for our uses
+expr = literal | var
+
+"""Parse and render a block of text into a Python dictionary."""
+
+
+class Parser(object):
+ """Compiled PyParsing BNF"""
+
+ _parser = None
+
+ def __init__(self):
+ super(Parser, self).__init__()
+ self._parser = self.BNF()
+
+ def BNF(self):
+ raise NotImplementedError
+
+ def item(self, item):
+ raise NotImplementedError
+
+ def parse(self, input):
+ item = self._parser.parseString(input).asList()
+ return self.item(item)
+
+
+"""Parser for function-like macros - without the closing semi-colon."""
+
+
+class ParserFunctionMacro(Parser):
+ def BNF(self):
+ # VLIB_CONFIG_FUNCTION (unix_config, "unix")
+ macroName = ident
+ params = pp.Group(pp.ZeroOrMore(expr + comma) + expr)
+ macroParams = lbracket + params + rbracket
+
+ return macroName + macroParams
+
+ def item(self, item):
+ r = {
+ "macro": item[0],
+ "name": item[1][1],
+ "function": item[1][0],
+ }
+
+ return r
+
+
+"""Parser for function-like macros with a closing semi-colon."""
+
+
+class ParseFunctionMacroStmt(ParserFunctionMacro):
+ def BNF(self):
+ # VLIB_CONFIG_FUNCTION (unix_config, "unix");
+ function_macro = super(ParseFunctionMacroStmt, self).BNF()
+ mi = function_macro + semicolon
+ mi.ignore(pp.cppStyleComment)
+
+ return mi
+
+
+"""
+Parser for our struct initializers which are composed from a
+function-like macro, equals sign, and then a normal C struct initializer
+block.
+"""
+
+
+class MacroInitializer(ParserFunctionMacro):
+ def BNF(self):
+ # VLIB_CLI_COMMAND (show_sr_tunnel_command, static) = {
+ # .path = "show sr tunnel",
+ # .short_help = "show sr tunnel [name <sr-tunnel-name>]",
+ # .function = show_sr_tunnel_fn,
+ # };
+ cs = pp.Forward()
+
+ member = pp.Combine(
+ dot + varName + pp.Optional("[" + arrayIndex + "]"), adjacent=False
+ )
+ value = expr | cs
+
+ entry = pp.Group(pp.Optional(member + equals, default="") + value)
+ entries = (pp.ZeroOrMore(entry + comma) + entry + pp.Optional(comma)) | (
+ pp.ZeroOrMore(entry + comma)
+ )
+
+ cs << (lbrace + entries + rbrace)
+
+ macroName = ident
+ params = pp.Group(pp.ZeroOrMore(expr + comma) + expr)
+ macroParams = lbracket + params + rbracket
+
+ function_macro = super(MacroInitializer, self).BNF()
+ mi = function_macro + equals + pp.Group(cs) + semicolon
+ mi.ignore(pp.cppStyleComment)
+
+ return mi
+
+ def item(self, item):
+ r = {
+ "macro": item[0],
+ "name": item[1][0],
+ "params": item[2],
+ "value": {},
+ }
+
+ for param in item[2]:
+ r["value"][param[0]] = html.escape(param[1])
+
+ return r