comparison 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
comparison
equal deleted inserted replaced
320:84d67cce67b7 321:8c569fbe60e4
20 pass 20 pass
21 p = MyParser() 21 p = MyParser()
22 p.parse() 22 p.parse()
23 23
24 24
25 Alternatively you can load the parser on the fly:
26
27 .. code::
28
29 import yacc
30 parser_mod = yacc.load_as_module('mygrammar.x')
31 class MyParser(parser_mod.Parser):
32 pass
33 p = MyParser()
34 p.parse()
35
25 """ 36 """
26 37
27 import argparse 38 import argparse
28 import re 39 import re
29 import sys 40 import sys
30 import datetime 41 import datetime
42 import types
43 import io
31 from pyyacc import Grammar, print_grammar 44 from pyyacc import Grammar, print_grammar
32 45
33 46
34 class XaccLexer: 47 class XaccLexer:
35 def __init__(self): 48 def __init__(self):
99 112
100 def next_token(self): 113 def next_token(self):
101 t = self.token 114 t = self.token
102 if t[0] != 'eof': 115 if t[0] != 'eof':
103 self.token = self.tokens.__next__() 116 self.token = self.tokens.__next__()
104 #print(t)
105 return t 117 return t
106 118
107 119
108 class ParseError(Exception): 120 class ParseError(Exception):
109 pass 121 pass
190 """ Generator that writes generated parser to file """ 202 """ Generator that writes generated parser to file """
191 def __init__(self): 203 def __init__(self):
192 pass 204 pass
193 205
194 def generate(self, grammar, headers, output_file): 206 def generate(self, grammar, headers, output_file):
195 print_grammar(grammar) 207 self.output_file = output_file
196 self.grammar = grammar 208 self.grammar = grammar
197 self.headers = headers 209 self.headers = headers
198 self.action_table, self.goto_table = grammar.doGenerate() 210 self.action_table, self.goto_table = grammar.doGenerate()
199 self.generate_python_script(output_file) 211 self.generate_python_script()
200 212
201 def generate_python_script(self, output_file): 213 def print(self, *args):
214 """ Print helper function that prints to output file """
215 print(*args, file=self.output_file)
216
217 def generate_python_script(self):
202 """ Generate python script with the parser table """ 218 """ Generate python script with the parser table """
203 print('#!/usr/bin/python', file=output_file) 219 self.print('#!/usr/bin/python')
204 stamp = datetime.datetime.now().ctime() 220 stamp = datetime.datetime.now().ctime()
205 print('""" Automatically generated by xacc on {} """'.format(stamp), file=output_file) 221 self.print('""" Automatically generated by xacc on {} """'.format(stamp))
206 print('from pyyacc import LRParser, Reduce, Shift, Accept, Production, Grammar', file=output_file) 222 self.print('from pyyacc import LRParser, Reduce, Shift, Accept, Production, Grammar')
207 print('from ppci import Token', file=output_file) 223 self.print('from ppci import Token')
208 print(file=output_file) 224 self.print('')
209 for h in self.headers: 225 for h in self.headers:
210 print(h, file=output_file) 226 print(h, file=output_file)
211 print(file=output_file) 227 self.print('')
212 print('class Parser(LRParser):', file=output_file) 228 self.print('class Parser(LRParser):')
213 print(' def __init__(self):', file=output_file) 229 self.print(' def __init__(self):')
214 # Generate rules: 230 # Generate rules:
215 print(' self.start_symbol = "{}"'.format(self.grammar.start_symbol), file=output_file) 231 self.print(' self.start_symbol = "{}"'.format(self.grammar.start_symbol))
216 print(' self.grammar = Grammar({})'.format(self.grammar.terminals), file=output_file) 232 self.print(' self.grammar = Grammar({})'.format(self.grammar.terminals))
217 for rule_number, rule in enumerate(self.grammar.productions): 233 for rule_number, rule in enumerate(self.grammar.productions):
218 rule.f_name = 'action_{}_{}'.format(rule.name, rule_number) 234 rule.f_name = 'action_{}_{}'.format(rule.name, rule_number)
219 print(' self.grammar.add_production("{}", {}, self.{})'.format(rule.name, rule.symbols, rule.f_name), file=output_file) 235 self.print(' self.grammar.add_production("{}", {}, self.{})'.format(rule.name, rule.symbols, rule.f_name))
220 # Fill action table: 236 # Fill action table:
221 print(' self.action_table = {}', file=output_file) 237 self.print(' self.action_table = {}')
222 for state in self.action_table: 238 for state in self.action_table:
223 action = self.action_table[state] 239 action = self.action_table[state]
224 print(' self.action_table[{}] = {}'.format(state, action), file=output_file) 240 self.print(' self.action_table[{}] = {}'.format(state, action))
225 print('', file=output_file) 241 self.print('')
226 242
227 # Fill goto table: 243 # Fill goto table:
228 print(' self.goto_table = {}', file=output_file) 244 self.print(' self.goto_table = {}')
229 for gt in self.goto_table: 245 for gt in self.goto_table:
230 to = self.goto_table[gt] 246 to = self.goto_table[gt]
231 print(' self.goto_table[{}] = {}'.format(gt, to), file=output_file) 247 self.print(' self.goto_table[{}] = {}'.format(gt, to))
232 print('', file=output_file) 248 self.print('')
233 249
234 # Generate a function for each action: 250 # Generate a function for each action:
235 for rule in self.grammar.productions: 251 for rule in self.grammar.productions:
236 M = len(rule.symbols) 252 M = len(rule.symbols)
237 args = ', '.join('arg{}'.format(n + 1) for n in range(M)) 253 args = ', '.join('arg{}'.format(n + 1) for n in range(M))
238 print(' def {}(self, {}):'.format(rule.f_name, args), file=output_file) 254 self.print(' def {}(self, {}):'.format(rule.f_name, args))
239 if rule.f == None: 255 if rule.f == None:
240 semantics = 'pass' 256 semantics = 'pass'
241 else: 257 else:
242 semantics = str(rule.f) 258 semantics = str(rule.f)
243 if semantics.strip() == '': 259 if semantics.strip() == '':
244 semantics = 'pass' 260 semantics = 'pass'
245 for n in range(M): 261 for n in range(M):
246 semantics = semantics.replace('${}'.format(n + 1), 'arg{}'.format(n + 1)) 262 semantics = semantics.replace('${}'.format(n + 1), 'arg{}'.format(n + 1))
247 print(' {}'.format(semantics), file=output_file) 263 self.print(' {}'.format(semantics))
248 264
249 265
250 def main(): 266 def make_argument_parser():
251 # Parse arguments: 267 # Parse arguments:
252 parser = argparse.ArgumentParser(description='xacc compiler compiler') 268 parser = argparse.ArgumentParser(description='xacc compiler compiler')
253 parser.add_argument('source', type=argparse.FileType('r'), \ 269 parser.add_argument('source', type=argparse.FileType('r'), \
254 help='the parser specification') 270 help='the parser specification')
255 parser.add_argument('-o', '--output', type=argparse.FileType('w'), \ 271 parser.add_argument('-o', '--output', type=argparse.FileType('w'), \
256 default=sys.stdout) 272 default=sys.stdout)
257 args = parser.parse_args() 273
274
275 def load_as_module(filename):
276 """ Load a parser spec file, generate LR tables and create module """
277 ob = io.StringIO()
278 args = argparse.Namespace(source=open(filename), output=ob)
279 main(args)
280
281 parser_mod = types.ModuleType('generated_parser')
282 exec(ob.getvalue(), parser_mod.__dict__)
283 return parser_mod
284
285 def main(args):
258 src = args.source.read() 286 src = args.source.read()
259 args.source.close() 287 args.source.close()
260 288
261 # Construction of generator parts: 289 # Construction of generator parts:
262 lexer = XaccLexer() 290 lexer = XaccLexer()
264 generator = XaccGenerator() 292 generator = XaccGenerator()
265 293
266 # Sequence source through the generator parts: 294 # Sequence source through the generator parts:
267 lexer.feed(src) 295 lexer.feed(src)
268 grammar = parser.parse_grammar() 296 grammar = parser.parse_grammar()
297 # TODO: optionize this: print_grammar(grammar)
269 generator.generate(grammar, parser.headers, args.output) 298 generator.generate(grammar, parser.headers, args.output)
270 args.output.close()
271 299
272 300
273 if __name__ == '__main__': 301 if __name__ == '__main__':
274 main() 302 args = make_argument_parser().parse_args()
303 main(args)