Mercurial > lcfOS
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) |