Mercurial > lcfOS
diff python/yacc.py @ 319:8d07a4254f04
Work on burg
author | Windel Bouwman |
---|---|
date | Sat, 18 Jan 2014 18:58:43 +0100 |
parents | e84047f29c78 |
children | 8c569fbe60e4 |
line wrap: on
line diff
--- a/python/yacc.py Tue Dec 31 12:38:15 2013 +0100 +++ b/python/yacc.py Sat Jan 18 18:58:43 2014 +0100 @@ -1,6 +1,28 @@ #!/usr/bin/python -""" Parser generator utility """ +""" +Parser generator utility. This script can generate a python script from a +grammar description. + +Invoke the script on a grammar specification file: + +.. code:: + + $ ./yacc.py test.x -o test_parser.py + +And use the generated parser by deriving a user class: + + +.. code:: + + import test_parser + class MyParser(test_parser.Parser): + pass + p = MyParser() + p.parse() + + +""" import argparse import re @@ -131,6 +153,7 @@ else: headers.append(self.consume('HEADER')[1]) self.consume('%%') + self.headers = headers self.grammar = Grammar(terminals) while self.Peak != 'eof': self.parse_rule() @@ -140,6 +163,7 @@ return self.consume('ID')[1] def parse_rhs(self): + """ Parse the right hand side of a rule definition """ symbols = [] while self.Peak not in [';', 'BRACEDCODE', '|']: symbols.append(self.parse_symbol()) @@ -151,6 +175,7 @@ return symbols, action def parse_rule(self): + """ Parse a rule definition """ p = self.parse_symbol() self.consume(':') symbols, action = self.parse_rhs() @@ -166,47 +191,51 @@ def __init__(self): pass - def generate(self, grammar, output_file): + def generate(self, grammar, headers, output_file): print_grammar(grammar) self.grammar = grammar + self.headers = headers self.action_table, self.goto_table = grammar.doGenerate() self.generate_python_script(output_file) - def generate_python_script(self, f): + def generate_python_script(self, output_file): """ Generate python script with the parser table """ - print('#!/usr/bin/python', file=f) + print('#!/usr/bin/python', file=output_file) stamp = datetime.datetime.now().ctime() - print('""" Automatically generated by xacc on {} """'.format(stamp), file=f) - print('from pyyacc import LRParser, Reduce, Shift, Accept, Production, Grammar', file=f) - print('from ppci import Token', file=f) - print(file=f) - print('class Parser(LRParser):', file=f) - print(' def __init__(self):', file=f) + print('""" Automatically generated by xacc on {} """'.format(stamp), file=output_file) + print('from pyyacc import LRParser, Reduce, Shift, Accept, Production, Grammar', file=output_file) + print('from ppci import Token', file=output_file) + print(file=output_file) + for h in self.headers: + print(h, file=output_file) + print(file=output_file) + print('class Parser(LRParser):', file=output_file) + print(' def __init__(self):', file=output_file) # Generate rules: - print(' self.start_symbol = "{}"'.format(self.grammar.start_symbol), file=f) - print(' self.grammar = Grammar({})'.format(self.grammar.terminals), file=f) + print(' self.start_symbol = "{}"'.format(self.grammar.start_symbol), file=output_file) + print(' self.grammar = Grammar({})'.format(self.grammar.terminals), file=output_file) for rule_number, rule in enumerate(self.grammar.productions): rule.f_name = 'action_{}_{}'.format(rule.name, rule_number) - print(' self.grammar.add_production("{}", {}, self.{})'.format(rule.name, rule.symbols, rule.f_name), file=f) + print(' self.grammar.add_production("{}", {}, self.{})'.format(rule.name, rule.symbols, rule.f_name), file=output_file) # Fill action table: - print(' self.action_table = {}', file=f) + print(' self.action_table = {}', file=output_file) for state in self.action_table: action = self.action_table[state] - print(' self.action_table[{}] = {}'.format(state, action), file=f) - print('', file=f) + print(' self.action_table[{}] = {}'.format(state, action), file=output_file) + print('', file=output_file) # Fill goto table: - print(' self.goto_table = {}', file=f) + print(' self.goto_table = {}', file=output_file) for gt in self.goto_table: to = self.goto_table[gt] - print(' self.goto_table[{}] = {}'.format(gt, to), file=f) - print('', file=f) + print(' self.goto_table[{}] = {}'.format(gt, to), file=output_file) + print('', file=output_file) # Generate a function for each action: for rule in self.grammar.productions: M = len(rule.symbols) args = ', '.join('arg{}'.format(n + 1) for n in range(M)) - print(' def {}(self, {}):'.format(rule.f_name, args), file=f) + print(' def {}(self, {}):'.format(rule.f_name, args), file=output_file) if rule.f == None: semantics = 'pass' else: @@ -215,8 +244,7 @@ semantics = 'pass' for n in range(M): semantics = semantics.replace('${}'.format(n + 1), 'arg{}'.format(n + 1)) - print(' {}'.format(semantics), file=f) - print('', file=f) + print(' {}'.format(semantics), file=output_file) def main(): @@ -238,7 +266,7 @@ # Sequence source through the generator parts: lexer.feed(src) grammar = parser.parse_grammar() - generator.generate(grammar, args.output) + generator.generate(grammar, parser.headers, args.output) args.output.close()