import re def Generate(outfile, parser): write = outfile.write if parser.options.get('mapping'): write_body = MappingBody elif parser.options.get('tuple'): write_body = TupleBody else: write_body = ActionBody write('\n# modules required for action routines\n') for (package, module) in parser.imports: if package: write('from %s ' % package) write('import %s\n' % module) if parser.options.get('debug'): write('\n# helper for displaying debugging information\n') write('def __dump_stack(name, stack):\n') write(' sys.stderr.write("--%s(" % name)\n') write(' for item in stack:\n') write(' sys.stderr.write(", %s" % item)\n') write(' sys.stderr.write("\\n")\n') # the list of all action routine function names functions = [None] # make sure we don't assign the same name twice lhs = {} write('\n# the action code for each rule\n') for rule in parser.grammar.rules: count = lhs.get(rule.lhs, 0) lhs[rule.lhs] = count + 1 func_name = '%s%d' % (rule.lhs, lhs[rule.lhs]) if rule.action.has_key('python'): # Only write functions that have an action write('def %s(self, __stack, __ptr):\n' % func_name) write(' """\n') write(' from %s, line %d\n' % (rule.filename, rule.lineno)) grammar = reduce(lambda a, b: a + ' ' + b, rule.rhs, rule.lhs+':') write(' %s\n' % grammar) write(' """\n') if parser.options.get('debug'): write(' if self.verbose:\n') write(' sys.stderr.write("--%s(")\n' % rule.lhs) for n in range(len(rule.rhs)): write(' sys.stderr.write(') if n > 0: write('", " + ') write('repr(__stack[__ptr+%d]))\n' % (n + 1)) write(' sys.stderr.write(")\\n")\n') write_body(write, rule) functions.append(func_name) else: functions.append('None') routines = 'action_routines = [' write(routines) indent = ' '*len(routines) for name in functions: write('%s,\n%s' % (name, indent)) write(']\n') return def MappingBody(write, rule): write(" return {'TYPE' : %s,\n" % repr(rule.lhs.upper())) for n in range(len(rule.rhs)): write(' %d : __stack[__ptr+%d],\n' % (n, n+1)) write(' }\n\n') return def TupleBody(write, rule): write(' return (%s,\n' % repr(rule.lhs.upper())) for n in range(len(rule.rhs)): write(' __stack[__ptr+%d],\n' % (n+1)) write(' )\n\n') return whitespace = re.compile('\s*') equals = re.compile('\s*=') stack_ptr = re.compile('\$(\d+|\$)') def ActionBody(write, rule): # defaults to first item (allows for pass-through) # handle the case of no right-hand side if len(rule.rhs): offset = 1 else: offset = 0 retval = '__stack[__ptr%+d]' % offset lines = rule.action['python'].split('\n') # Remove leading and trailing lines that are only whitespace while not lines[0].strip(): lines = lines[1:] while not lines[-1].strip(): lines = lines[:-1] # find length of minimum amount of preceding whitespace space = len(lines[0]) for line in lines: match = whitespace.match(line) if match and match.end() < len(line): if match.end() < space: space = match.end() for line in lines: # replace stack pointers match = stack_ptr.search(line) while match: pre = line[:match.start()] post = line[match.end():] if match.group(1) == '$': match = equals.match(post) # the return value retval = subst = '__val' else: # it is a position in the stack subst = '__stack[__ptr%+d]' % int(match.group(1)) line = pre + subst + post match = stack_ptr.search(line) write(' %s\n' % line.strip()[space:]) write(' return %s\n\n' % retval) return