def run(top, prime_start_time = True, quiet = False): # The following gets a little confusing because we have two kinds of word # objects: # # 1. ww objects ("word_word", i.e., instances of the # ucc.word.word.word class) # 2. word_obj objects (either subclasses or instances of the # ucclib.built_in.declaration.declaration class) # if prime_start_time: elapsed() # prime the Start_time... compile_start_time = Start_time else: compile_start_time = Start_time if not quiet: print "top: %.2f" % elapsed() with crud.db_connection(top.packages[-1].package_dir): if not quiet: print "crud.db_connection: %.2f" % elapsed() types.init() if not quiet: print "types.init: %.2f" % elapsed() # Create symbols, word_objs and build the parsers for each package: # # {package_name: parser module} package_parsers = create_parsers(top) # Also loads all of the word objs if not quiet: print "create parsers: %.2f" % elapsed() # word files => ast words_done = parse_needed_words(top, package_parsers, quiet) if not quiet: print "parse_needed_words: %.2f" % elapsed() # ast => intermediate code for word_label in words_done: with crud.db_transaction(): symbol_table.get(word_label).word_obj.compile() if not quiet: print "generate intermediate code: %.2f" % elapsed() # intermediate code => optimized intermediate code optimize() if not quiet: print "optimize: %.2f" % elapsed() # intermediate code => assembler gen_assembler() if not quiet: print "gen_assembler: %.2f" % elapsed() # assembler => .hex files assemble_program(top.packages[-1].package_dir) if not quiet: print "assemble_program: %.2f" % elapsed() if not quiet: print "TOTAL: %.2f" % (Start_time - compile_start_time)
def prepare(self, fn_symbol, words_needed): r'''Called immediately after parsing, before writing to the database. Calls `prepare_args` on itself first, then prepare_<expect> on the word in the first arg. Also updates `fn_xref` and `symbol_table.symbol.side_effects` info so that these data will be known during the intermediate code generation phase that follows parsing. See prepare_args_ function for more info. .. _prepare_args: ucc.database.ast-module.html#prepare_args ''' if self.kind == 'call': self.prepare_args(fn_symbol, words_needed) if self.args and isinstance(self.args[0], ast) and \ self.args[0].kind == 'word': word_obj = symbol_table.get(self.args[0].label).word_obj fn_xref.calls(fn_symbol.id, word_obj.ww.symbol.id) prepare_method = word_obj.get_method('prepare', self.expect) return prepare_method(fn_symbol, self, words_needed) if self.kind == 'word': sym = symbol_table.get_by_id(self.symbol_id) if sym.context is None: words_needed.add(sym.label) if self.expect == 'lvalue': fn_xref.sets(fn_symbol.id, self.symbol_id) else: fn_xref.uses(fn_symbol.id, self.symbol_id) if self.kind in ('ioreg', 'ioreg-bit'): fn_symbol.side_effects = 1 return self
def delete_word_by_label(word_label): r'''Delete all ast nodes associated with word_label from the database. This does not report an error if the word is not in the database. ''' sym = symbol_table.get(word_label, default=None) if sym is not None: delete_word_by_id(sym.id)
def word(cls, symbol_id, syntax_position_info = (None, None, None, None), **kws): r'''Returns an ast node for the 'symbol_id' word. 'symbol_id' may be either the integer id, or the label of the global word as a string. 'kws' are simply passed to __init__ as attributes, along with the 'kind' and the 'label' attributes. ''' line_start, column_start, line_end, column_end = syntax_position_info if isinstance(symbol_id, (str, unicode)): symbol_id = symbol_table.get(symbol_id).id return cls(kind='word', label=symbol_table.get_by_id(symbol_id).label, symbol_id=symbol_id, line_start=line_start, column_start=column_start, line_end=line_end, column_end=column_end, **kws)
def macro_expand(self, fn_symbol, ast_node, words_needed): #print "repeat.macro_expand" _, count, body = ast_node.args loop_label = crud.gensym('repeat') if not count: #print "no count" new_args = ( ast.ast(kind='label', label=loop_label, expect='statement'), body, ast.ast(kind='jump', label=loop_label, expect='statement'), ) else: count = count[0] #print "count", count if count.kind == 'int': assert count.int1 >= 0, \ "repeat must not have negative repeat count" if count.int1 == 0: return ast_node.macro_expand(fn_symbol, words_needed, (), kind='no-op') if count.int1 == 1: return ast_node.macro_expand(fn_symbol, words_needed, body, kind='series') first_jmp = () else: first_jmp = ( ast.ast(kind='jump', label=test, expect='statement'), ) loop_var = crud.gensym('repeat_var') symbol_id = \ symbol_table.symbol.create(loop_var, 'var', fn_symbol).id test = crud.gensym('repeat_test') new_args = ( ast.ast(ast.ast.word(symbol_table.get('set').id), (ast.ast.word(symbol_id), count, ), kind='call', expect='statement') \ .prepare(fn_symbol, words_needed), ) + first_jmp + ( ast.ast(kind='label', label=loop_label, expect='statement'), ) + body + ( ast.ast(ast.ast.word(symbol_table.get('set').id), (ast.ast.word(symbol_id), ast.ast(ast.ast.word(symbol_table.get('-').id), ast.ast.word(symbol_id), ast.ast(kind='int', int1=1), kind='call', ) \ .prepare(fn_symbol, words_needed), ), kind='call', expect='statement') \ .prepare(fn_symbol, words_needed), ast.ast(kind='label', label=test, expect='statement'), ast.ast(ast.ast.word(symbol_id, expect='condition'), kind='if-true', label=loop_label, expect='statement'), ) return ast_node.macro_expand(fn_symbol, words_needed, new_args, kind='series')
def compile(self): r'''Generates intermediate code for this AST node. ''' if self.kind in ('approx', 'int', 'ratio'): return block.Current_block.gen_triple( self.kind, self.int1, self.int2, syntax_position_info= self.get_syntax_position_info()) if self.kind == 'string': name = crud.gensym('strlit') sym = symbol_table.symbol.create(name, 'const') asm_block = assembler.block(self.word_symbol.id, 'flash', name) asm_block.append_inst('int16', str(len(self.str1))) asm_block.append_inst('bytes', repr(self.str1)) asm_block.write() return block.Current_block.gen_triple( 'global', sym.id, syntax_position_info=self.get_syntax_position_info()) if self.kind == 'call': if self.args and isinstance(self.args[0], ast) and \ self.args[0].kind == 'word': word_obj = symbol_table.get(self.args[0].label).word_obj compile_method = word_obj.get_method('compile', self.expect) return compile_method(self) else: raise AssertionError("call indirect not supported yet") if self.kind == 'word': sym = symbol_table.get_by_id(self.symbol_id) if sym.context is None: word_obj = symbol_table.get_by_id(self.symbol_id).word_obj compile_method = word_obj.get_method('compile', self.expect) ans = compile_method(self) return ans if sym.kind in ('parameter', 'var'): return block.Current_block.gen_triple('local', sym, syntax_position_info=self.get_syntax_position_info()) raise ValueError("%s.compile: unknown symbol.kind %r" % sym.kind) if self.kind in ('no-op', 'None'): return None if self.kind == 'label': block.new_label(self.label, self.word_symbol.id) return None if self.kind == 'jump': block.Current_block.unconditional_to(self.label) return None if self.kind == 'if-true': arg_triples = self.compile_args() block.Current_block.true_to(arg_triples[0], self.label) return None if self.kind == 'if-false': arg_triples = self.compile_args() block.Current_block.false_to(arg_triples[0], self.label) return None if self.kind == 'series': self.compile_args() return None if self.kind in ('ioreg', 'ioreg-bit'): if self.expect in ('value', 'condition'): return block.Current_block.gen_triple( 'input' if self.kind == 'ioreg' else 'input-bit', string=self.label, int1=self.int1, syntax_position_info=self.get_syntax_position_info()) else: raise AssertionError("ast node[%s]: expect %s not supported " "for %s" % (self.id, self.expect, self.kind)) raise AssertionError("ast node[%s]: unknown ast kind -- %s" % (self.id, self.kind))