def make_parser(maker): def empty(): return maker.empty def literal(char): return maker.literal(char) def dot(): return maker.anyone def chain(r, s): return maker.chain(r, s) def either(r, s): return maker.either(r, s) def both(r, s): return maker.both(r, s) def optional(r): return either(r, empty()) if not hasattr(maker, 'star') and not hasattr(maker, 'plus'): def star(r): raise Exception("No star() or star() constructor supplied") def plus(r): raise Exception("No plus() or star() constructor supplied") else: if hasattr(maker, 'star'): star = maker.star else: def star(r): return optional(plus(r)) if hasattr(maker, 'plus'): plus = maker.plus else: def plus(r): return chain(r, star(r)) if hasattr(maker, 'oneof'): oneof = maker.oneof else: def oneof(chars): return reduce(either, map(literal, chars)) parser = Parser(r""" regex = exp $ exp = term [|] exp either | term & exp both | term | empty term = factor term chain | factor factor = primary [*] star | primary [+] plus | primary [?] optional | primary primary = \( exp \) | \[ charset \] join oneof | [.] dot | \\(.) literal | ([^.()&*+?|[\]]) literal charset = char charset | char = \\(.) | ([^\]]) """, join=join, **locals()) return lambda s: parser(s)[0]
def parse(grammar): rules = { '-a-': a_an, '-an-': a_an, '-a-an-': a_an, '-adjoining-': abut, '-capitalize-': capitalize } parser = Parser( r""" grammar = _ rules rules = rule rules | rule = name [=] _ exp hug exp = alts mk_choice alts = alt [/] _ alts | alt alt = \[ number \] _ seq mk_weight | seq mk_unit seq = factor seq mk_seq | mk_empty factor = name ![=] mk_ref | punct mk_punct | \( _ exp \) _ | { _ alts } _ mk_shuffle | word { _ alts } _ mk_fixed | word mk_literal punct = ([.,;?!]) _ | (--?)\s _ word = ([A-Za-z0-9']+) _ name = (-[A-Za-z0-9'-]+-) _ number = (\d+) _ int _ = (?:\s|#.*)* """, hug=hug, int=int, mk_choice=lambda *pairs: pairs[0][0] if 1 == len(pairs) else weighted_choice(dict(pairs)), mk_empty=lambda: empty, mk_fixed=lambda tag, *pairs: fixed(tag)(dict(pairs)), mk_literal=literal, mk_punct=mk_punct, mk_ref=lambda name: delay(lambda: rules[name]), mk_seq=lambda p, q: sequence(p, q) if q is not empty else p, mk_shuffle=lambda *pairs: shuffled(dict(pairs)), mk_unit=lambda p: (p, 1), mk_weight=lambda w, p: (p, w), ) rules.update(parser(grammar)) return rules
regex_parse = Parser( r""" regex = exp $ exp = term [|] exp either | term | empty term = factor term chain | factor factor = primary [*] star | primary [+] plus | primary [?] optional | primary primary = \( exp \) | \[ charset \] join oneof | [.] dot | \\(.) literal | ([^.()*+?|[\]]) literal charset = char charset | char = \\(.) | ([^\]]) """, **globals()) ## generate('.+', range(5))
fp_parse = Parser(r""" program = _ defs !. defs = def defs | def = name == _ exp [.] _ mk_def exp = term -> _ term ; _ exp mk_if | term term = factor term mk_compose | factor factor = @ _ factor mk_map | / _ factor mk_insertr | \\ _ factor mk_insertl | \? _ factor mk_filter | primary primary = integer mk_aref | ~ _ integer mk_literal | name mk_call | ([<=>*+-]) !opchar _ mk_op | \[ _ list \] _ mk_list | \( _ exp \) _ opchar = [\w@/\\?<=>*+-] list = exp , _ list | exp | decimal = (\d+) _ int integer = (-?\d+) _ int name = ([A-Za-z]\w*) _ _ = \s* """, int=int, **globals())
exp1 = exp2 ops1 apply ops1 = ([*/%]) _ exp2 rhs ops1 compose | identity exp2 = term (\^) _ exp2 hug | term term = (-) _ exp1 hug | \( _ exp0 \) _ | (\d+) _ int _ = \s* """ calc = OneResult(Parser(g, int=int, **globals())) ## calc('3') #. 3 ## calc('3-1') #. (3, '-', 1) ## calc('5-4-3-2-1') #. ((((5, '-', 4), '-', 3), '-', 2), '-', 1) ## calc('60/5/6') #. ((60, '/', 5), '/', 6) ## calc('3-1-(1-2)') #. ((3, '-', 1), '-', (1, '-', 2)) ## calc('2 - 4/5') #. (2, '-', (4, '/', 5)) ## calc('2^3^4') #. (2, '^', (3, '^', 4))
| term => _ term mk_impl | term term = factor term mk_and | factor factor = ~ _ primary mk_not | primary primary = \( _ expr \) _ | id _ mk_var id = ([A-Za-z_]\w*) _ _ = (?:\s|#[^\n]*)* """ parse = Parser(grammar, mk_eqv=dd.Equiv, mk_impl=dd.Implies, mk_and=operator.and_, mk_or=operator.or_, mk_not=operator.inv, mk_var=mk_var) def solve(puzzle_text): condition, = parse(puzzle_text) if dd.is_valid(condition): print("Valid.") else: show(dd.satisfy(condition, 1)) def show(opt_env): if opt_env is None:
json_parse = Parser(r""" start = _ value object = { _ members } _ mk_object | { _ } _ mk_object members = pair , _ members | pair pair = string : _ value hug array = \[ _ elements \] _ hug | \[ _ \] _ hug elements = value , _ elements | value value = string | number | object | array | (true|false|null)\b _ mk_literal string = " chars " _ join chars = char chars | char = ([^\x00-\x1f"\\]) | \\(["/\\]) | (\\[bfnrt]) escape | (\\u) xd xd xd xd join escape xd = ([0-9a-fA-F]) number = int frac exp _ join mk_number | int frac _ join mk_number | int exp _ join mk_number | int _ join mk_number int = (-?) (0) !\d | (-?) ([1-9]\d*) frac = ([.]\d+) exp = ([eE][+-]?\d+) _ = \s* """, **globals())
| term term = factor term mk_and | factor factor = ~ _ primary mk_not | primary primary = \( _ expr \) _ | id _ mk_var id = ([A-Za-z_]\w*) _ _ = (?:\s|#[^\n]*)* """ parse = OneResult( Parser(grammar, mk_eqv=Eqv, mk_impl=V.impl, mk_and=V.and_, mk_or=V.or_, mk_not=V.not_, mk_var=V.Variable)) def solve(puzzle_text): condition = parse(puzzle_text) if V.is_valid(condition): print("Valid.") else: show(V.satisfy(condition, 1)) def show(opt_env): if not opt_env:
if isinstance(y, tuple): return reassociate(x, op, y[0]), y[1], expose(y[2]) else: return x, op, expose(y) parse = Parser(r""" top = _ exp0 $ exp0 = exp1 ([+-]) _ exp0 reassociate | exp1 Shelter exp1 = exp2 ([*/%]) _ exp1 reassociate | exp2 Shelter exp2 = term (\^) _ exp2 hug | term term = (-) _ exp1 hug | ([\d+]) _ int | \( _ exp0 \) _ _ = \s* """, int=int, hug=hug, Shelter=Shelter, reassociate=reassociate) def calc(s): exp, = parse(s) return expose(exp)
toy_grammar = Parser(r""" Main _ E !. E Fp ` V ` E :fold_infix_app E Fp :fold_apps E & _ Vp => _ E :fold_lam E let\b _ Decls E :make_let E case\b _ E Cases :make_case Cases Case Cases :cons Cases Case :singleton Case \| _ Param => _ E :chunk Param Const Param V Param \( _ Param \) _ Param \[ _ ParamList \] _ ParamList Param , _ Param :make_list_pattern Decls Decl Decls :cons Decls Decl :singleton Decl defer\b _ V ; _ :make_defer Decl bind\b _ V = _ E ; _ :make_bind Decl Vp = _ E ; _ :make_eqn Fp F Fs :cons Fs F Fs :cons Fs :nil F Const :make_const F V :make_var F \( _ E \) _ F { _ F Fp } _ :fold_send F \[ _ EList \] _ :make_list_expr EList E , _ EList :cons EList E :singleton EList :nil Vp V Vp :cons Vp V :singleton V Identifier V Operator Identifier (?!let\b|case\b|defer\b|bind\b)([A-Za-z_]\w*)\b\s* Operator (<=|:=|[!+-.])\s* Const \. _ V :make_lit_sym Const "([^"]*)" _ :repr Const (-?\d+) _ Const \( _ \) _ :parens Const \[ _ \] _ :brackets _ \s* """, repr=repr, **globals())
float = int frac exp | int frac | int exp int = (-[1-9]) digits | (-) digit | ([1-9]) digits | digit frac = ([.]) digits exp = ([eE][+-]?) digits digits = (\d+) digit = (\d) _ = \s* """ scan_em = Parser(token_grammar, make_int=int, make_float=float, **globals()) def calc(string): tokens = iter(scan_em(string)) def scan(): scan.token = next(tokens, None) scan() parse_expr = make_parse_expr(scan, infix_ops, parse_primary) result = parse_expr(0) assert scan.token is None, "Input not fully consumed" return result
p = Parser(grammar, hug = lambda *xs: '[%s]' % ' '.join(xs), join = join, mk_array = maker('array'), mk_assign = maker('assign'), # mk_binop = lambda *vals: repr(vals), #maker('binop'), mk_binop1 = maker('binop1'), mk_binop2 = maker('binop2'), mk_binop3 = maker('binop3'), mk_binop4 = maker('binop4'), mk_binop5 = maker('binop5'), mk_binop6 = maker('binop6'), mk_binop7 = maker('binop7'), mk_binop8 = maker('binop8'), mk_call = maker('call'), mk_comma_expression = maker('comma_expression'), mk_compound_statement = maker('compound_statement'), mk_dot = maker('dot'), mk_float = maker('float'), mk_function = maker('function'), mk_if = maker('if'), mk_new = maker('new'), mk_object = maker('object'), mk_return = maker('return'), mk_string = maker('string'), mk_unop = maker('unop'), mk_var = maker('var'), mk_var_assign = maker('var_assign'), mk_varref = maker('_'), )