| @@ -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) | |||