Mercurial > lcfOS
diff python/yacc.py @ 321:8c569fbe60e4
Load yacc and burg dynamic
author | Windel Bouwman |
---|---|
date | Sun, 19 Jan 2014 18:48:45 +0100 |
parents | 8d07a4254f04 |
children | 44f336460c2a |
line wrap: on
line diff
--- a/python/yacc.py Sun Jan 19 16:09:44 2014 +0100 +++ b/python/yacc.py Sun Jan 19 18:48:45 2014 +0100 @@ -22,12 +22,25 @@ p.parse() +Alternatively you can load the parser on the fly: + +.. code:: + + import yacc + parser_mod = yacc.load_as_module('mygrammar.x') + class MyParser(parser_mod.Parser): + pass + p = MyParser() + p.parse() + """ import argparse import re import sys import datetime +import types +import io from pyyacc import Grammar, print_grammar @@ -101,7 +114,6 @@ t = self.token if t[0] != 'eof': self.token = self.tokens.__next__() - #print(t) return t @@ -192,50 +204,54 @@ pass def generate(self, grammar, headers, output_file): - print_grammar(grammar) + self.output_file = output_file self.grammar = grammar self.headers = headers self.action_table, self.goto_table = grammar.doGenerate() - self.generate_python_script(output_file) + self.generate_python_script() - def generate_python_script(self, output_file): + def print(self, *args): + """ Print helper function that prints to output file """ + print(*args, file=self.output_file) + + def generate_python_script(self): """ Generate python script with the parser table """ - print('#!/usr/bin/python', file=output_file) + self.print('#!/usr/bin/python') stamp = datetime.datetime.now().ctime() - 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) + self.print('""" Automatically generated by xacc on {} """'.format(stamp)) + self.print('from pyyacc import LRParser, Reduce, Shift, Accept, Production, Grammar') + self.print('from ppci import Token') + self.print('') 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) + self.print('') + self.print('class Parser(LRParser):') + self.print(' def __init__(self):') # Generate rules: - print(' self.start_symbol = "{}"'.format(self.grammar.start_symbol), file=output_file) - print(' self.grammar = Grammar({})'.format(self.grammar.terminals), file=output_file) + self.print(' self.start_symbol = "{}"'.format(self.grammar.start_symbol)) + self.print(' self.grammar = Grammar({})'.format(self.grammar.terminals)) 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=output_file) + self.print(' self.grammar.add_production("{}", {}, self.{})'.format(rule.name, rule.symbols, rule.f_name)) # Fill action table: - print(' self.action_table = {}', file=output_file) + self.print(' self.action_table = {}') for state in self.action_table: action = self.action_table[state] - print(' self.action_table[{}] = {}'.format(state, action), file=output_file) - print('', file=output_file) + self.print(' self.action_table[{}] = {}'.format(state, action)) + self.print('') # Fill goto table: - print(' self.goto_table = {}', file=output_file) + self.print(' self.goto_table = {}') for gt in self.goto_table: to = self.goto_table[gt] - print(' self.goto_table[{}] = {}'.format(gt, to), file=output_file) - print('', file=output_file) + self.print(' self.goto_table[{}] = {}'.format(gt, to)) + self.print('') # 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=output_file) + self.print(' def {}(self, {}):'.format(rule.f_name, args)) if rule.f == None: semantics = 'pass' else: @@ -244,17 +260,29 @@ semantics = 'pass' for n in range(M): semantics = semantics.replace('${}'.format(n + 1), 'arg{}'.format(n + 1)) - print(' {}'.format(semantics), file=output_file) + self.print(' {}'.format(semantics)) -def main(): +def make_argument_parser(): # Parse arguments: parser = argparse.ArgumentParser(description='xacc compiler compiler') parser.add_argument('source', type=argparse.FileType('r'), \ help='the parser specification') parser.add_argument('-o', '--output', type=argparse.FileType('w'), \ default=sys.stdout) - args = parser.parse_args() + + +def load_as_module(filename): + """ Load a parser spec file, generate LR tables and create module """ + ob = io.StringIO() + args = argparse.Namespace(source=open(filename), output=ob) + main(args) + + parser_mod = types.ModuleType('generated_parser') + exec(ob.getvalue(), parser_mod.__dict__) + return parser_mod + +def main(args): src = args.source.read() args.source.close() @@ -266,9 +294,10 @@ # Sequence source through the generator parts: lexer.feed(src) grammar = parser.parse_grammar() + # TODO: optionize this: print_grammar(grammar) generator.generate(grammar, parser.headers, args.output) - args.output.close() if __name__ == '__main__': - main() + args = make_argument_parser().parse_args() + main(args)