| @@ -0,0 +1,122 @@ | |||||
| from lark import Lark, Transformer, Discard, v_args | |||||
| grammar = r""" | |||||
| start: statement+ | |||||
| ?statement: rule | |||||
| | terminal | |||||
| | "parser"? "grammar" name ";" -> ignore | |||||
| | "options" _CODE -> ignore | |||||
| rule: RULE ":" expansions ";" | |||||
| terminal: "fragment"? TOKEN ":" term_expansions ";" | |||||
| ?expansions: alias ("|" alias)* | |||||
| ?alias: expansion ["#" name] | |||||
| ?term_expansions: term_alias ("|" term_alias)* | |||||
| ?term_alias: term_expansion ["->" name ["(" name ")"]] | |||||
| term_expansion: expr* | |||||
| ?expansion: expr* | |||||
| ?expr: atom OP? | |||||
| ?atom: "(" expansions ")" | |||||
| | value | |||||
| | _CODE -> ignore | |||||
| | "~" atom -> not_ | |||||
| ?value: name | |||||
| | STRING -> string | |||||
| | REGEXP -> regexp | |||||
| name: RULE | |||||
| | TOKEN | |||||
| OP: /[+*][?]?|[?](?![a-z])/ | |||||
| RULE: /[a-z][_a-zA-Z0-9]*/ | |||||
| TOKEN: /[A-Z][_a-zA-Z0-9]*/ | |||||
| REGEXP: /\[.*?\]|\./ | |||||
| _STRING_INNER: /.*?/ | |||||
| _STRING_ESC_INNER: _STRING_INNER /(?<!\\)(\\\\)*?/ | |||||
| STRING : "'" _STRING_ESC_INNER "'" | |||||
| %import common.INT -> NUMBER | |||||
| %import common.WS | |||||
| COMMENT: /\s*/ "//" /[^\n]/* | |||||
| COMMENT2: /\/\*.*?\*\//s | |||||
| _CODE: /{.*?}/s | |||||
| %ignore WS | |||||
| %ignore COMMENT | |||||
| %ignore COMMENT2 | |||||
| """ | |||||
| parser = Lark(grammar, parser='lalr') | |||||
| class T(Transformer): | |||||
| def ignore(self, args): | |||||
| raise Discard() | |||||
| def expansions(self, x): | |||||
| return '\n | '.join(x) | |||||
| def term_expansions(self, x): | |||||
| return '\n | '.join(x) | |||||
| def term_alias(self, x): | |||||
| # TODO channel hidden -> ignore | |||||
| return x[0] | |||||
| def expansion(self, x): | |||||
| return "(" + ' '.join(x) + ")" | |||||
| def term_expansion(self, x): | |||||
| return "(" + ' '.join(x) + ")" | |||||
| @v_args(inline=True) | |||||
| def expr(self, expr, op): | |||||
| return expr + op.value | |||||
| @v_args(inline=True) | |||||
| def rule(self, name, exprs): | |||||
| return name + ": " + exprs | |||||
| @v_args(inline=True) | |||||
| def terminal(self, name, exprs): | |||||
| if not isinstance(exprs, str): | |||||
| breakpoint() | |||||
| return name + ": " + exprs | |||||
| @v_args(inline=True) | |||||
| def name(self, t): | |||||
| return t.value | |||||
| @v_args(inline=True) | |||||
| def string(self, t): | |||||
| return t.value.replace('\\', '\\\\').replace('"', '\\"').replace("'", '"') | |||||
| @v_args(inline=True) | |||||
| def regexp(self, t): | |||||
| return f'/{t.value}/' | |||||
| @v_args(inline=True) | |||||
| def not_(self, t): | |||||
| return f" /(?!){t}/ " | |||||
| def start(self, stmts): | |||||
| return '\n\n'.join(stmts) | |||||
| with open('SQLite.g4') as f: | |||||
| res = parser.parse(f.read()) | |||||
| # print('###', res.pretty()) | |||||
| res = T().transform(res) | |||||
| with open('sqlite.lark', 'w') as f: | |||||
| f.write(res) | |||||