168 lines
4.2 KiB
Python
Executable file
168 lines
4.2 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
|
|
import sys as _sys
|
|
import re as _re
|
|
import json as _json
|
|
|
|
|
|
def coin(template, arguments):
|
|
result = template
|
|
for (key, value, ) in arguments.items():
|
|
result = result.replace("{{%s}}" % key, value)
|
|
return result
|
|
|
|
|
|
def convert_symbol(symbol):
|
|
if (symbol.startswith("<")):
|
|
return {"type": "variable", "parameters": {"id": symbol[1:-1]}}
|
|
elif (symbol.startswith("[")):
|
|
return {"type": "terminal", "parameters": {"id": symbol[1:-1]}}
|
|
elif (symbol.startswith("{")):
|
|
return {"type": "label", "parameters": {"id": symbol[1:-1]}}
|
|
else:
|
|
raise ValueError("unknown symbol: %s" % symbol)
|
|
|
|
|
|
def extract_name(symbol, type_):
|
|
conversion = convert_symbol(symbol)
|
|
if (not (conversion["type"] == type_)):
|
|
raise ValueError("type mismatch")
|
|
else:
|
|
name = conversion["parameters"]["id"]
|
|
return (None if (name == "") else name)
|
|
|
|
|
|
|
|
def main():
|
|
pattern_name = "[0-9a-zA-Z_-]*"
|
|
pattern_terminal = coin("\\[{{pattern_name}}\\]", {"pattern_name": pattern_name})
|
|
pattern_variable = coin("<{{pattern_name}}>", {"pattern_name": pattern_name})
|
|
pattern_label = coin("\\{{{pattern_name}}\\}", {"pattern_name": pattern_name})
|
|
|
|
rules = [
|
|
# version
|
|
{
|
|
"pattern": coin(
|
|
"@{{space}}(.+)",
|
|
{
|
|
"space": "\\s*",
|
|
}
|
|
),
|
|
"action": lambda state, matching: {
|
|
"version": matching.group(1),
|
|
"specification": state["specification"],
|
|
},
|
|
},
|
|
# lexer_rule
|
|
{
|
|
"pattern": coin(
|
|
"{{space}}({{pattern_terminal}}){{space}}:{{space}}\"(.*)\"(?:{{space}}:{{space}}(\\S+){{space}})?",
|
|
{
|
|
"space": "\\s*",
|
|
"pattern_terminal": pattern_terminal,
|
|
}
|
|
),
|
|
"action": lambda state, matching: {
|
|
"version": state["version"],
|
|
"specification": {
|
|
"version": state["specification"]["version"],
|
|
"lexer_rules": (
|
|
state["specification"]["lexer_rules"]
|
|
+
|
|
[{
|
|
"pattern": matching.group(2),
|
|
"name": extract_name(matching.group(1), "terminal"),
|
|
"pass": (len(matching.groups()) >= 3),
|
|
}]
|
|
),
|
|
"parser_rules": state["specification"]["parser_rules"],
|
|
"parser_start": state["specification"]["parser_start"],
|
|
}
|
|
}
|
|
},
|
|
# parser_rule
|
|
{
|
|
"pattern": coin(
|
|
"({{pattern_label}}){{space}}:{{space}}({{pattern_variable}}){{space}}:(.*)",
|
|
{
|
|
"space": "\\s*",
|
|
"pattern_variable": pattern_variable,
|
|
"pattern_label": pattern_label,
|
|
}
|
|
),
|
|
"action": lambda state, matching: {
|
|
"version": state["version"],
|
|
"specification": {
|
|
"version": state["specification"]["version"],
|
|
"lexer_rules": state["specification"]["lexer_rules"],
|
|
"parser_rules": (
|
|
state["specification"]["parser_rules"]
|
|
+
|
|
[{
|
|
"label": extract_name(matching.group(1), "label"),
|
|
"premise": extract_name(matching.group(2), "variable"),
|
|
"conclusion": list(map(
|
|
convert_symbol,
|
|
_re.findall(
|
|
coin(
|
|
"{{pattern_terminal}}|{{pattern_variable}}",
|
|
{
|
|
"pattern_terminal": pattern_terminal,
|
|
"pattern_variable": pattern_variable,
|
|
}
|
|
),
|
|
matching.group(3)
|
|
)
|
|
)),
|
|
}]
|
|
),
|
|
"parser_start": state["specification"]["parser_start"],
|
|
}
|
|
}
|
|
},
|
|
# parser_start
|
|
{
|
|
"pattern": coin(
|
|
"({{pattern_variable}})",
|
|
{
|
|
"space": "\\s*",
|
|
"pattern_variable": pattern_variable,
|
|
}
|
|
),
|
|
"action": lambda state, matching: {
|
|
"version": state["version"],
|
|
"specification": {
|
|
"version": state["specification"]["version"],
|
|
"lexer_rules": state["specification"]["lexer_rules"],
|
|
"parser_rules": state["specification"]["parser_rules"],
|
|
"parser_start": extract_name(matching.group(1), "variable"),
|
|
}
|
|
}
|
|
},
|
|
# empty
|
|
{
|
|
"pattern": ".*",
|
|
"action": lambda state, matching: state,
|
|
},
|
|
]
|
|
|
|
state = {
|
|
"version": "1",
|
|
"specification": {
|
|
"version": "2",
|
|
"lexer_rules": [],
|
|
"parser_rules": [],
|
|
"parser_start": None,
|
|
},
|
|
}
|
|
content = _sys.stdin.read()
|
|
for line in content.split("\n"):
|
|
for rule in rules:
|
|
matching = _re.match("^%s$" % rule["pattern"], line)
|
|
if (not (matching is None)):
|
|
state = rule["action"](state, matching)
|
|
break
|
|
_sys.stdout.write(_json.dumps(state["specification"], indent = "\t"))
|
|
|
|
main()
|