#!/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()