def push_if(self, optimizer): if_ = optimizer.rewind() # Create mark beyond END of if statement. self.push_then_mark(optimizer) end_mark = self.then_marks[-1] # Push statements block followed by a jump to the end mark. def push_if_block(block): goto = tokens.Command(tokens.Command.GOTO, mark=end_mark) optimizer.push_node(goto) optimizer.push_node(block) # Push all statements blocks but the first and prepare a THEN mark for # each of them. for block in if_.blocks[:0:-1]: push_if_block(block) self.push_then_mark(optimizer) # Push first statements block and a conditional jump (if false) to the # current THEN mark. This will be the end mark if there are no THEN # statements blocks. mark = self.then_marks[-1] beq = tokens.Command(tokens.Command.BEQ, mark=mark).from_node(if_) push_if_block(if_.blocks[0]) optimizer.push_node(beq) return True
def word_cond(self, optimizer): word, cond = optimizer.rewind(2) type = cond.get_type() if (type == tokens.Command.BEQ and word.value == 0) or \ (type == tokens.Command.BNE and word.value != 0): node = tokens.Command(tokens.Command.GOTO, command=cond).from_node(cond) optimizer.push_node(node) return True
def make_command(t): t.type = 'COMMAND' if t.value == '?': t.value = 'print' elif t.value == '&': t.value = 'gosub' t.value = tokens.Command(t.value.lower()).from_token(t) return t
def word_eq_cond(self, optimizer): word, eq, cond = optimizer.peek(3) if word.value != 0: return False elif cond.get_type() == tokens.Command.BEQ: type = tokens.Command.BNE else: type = tokens.Command.BEQ node = tokens.Command(type, command=cond).from_node(cond) optimizer.rewind(3) optimizer.push_node(node) return True
def cond_goto_mark(self, optimizer): cond, goto, mark = optimizer.peek(3) if cond.mark is not mark or goto.mark is None: return False elif cond.get_type() == tokens.Command.BEQ: cond_type = tokens.Command.BNE else: cond_type = tokens.Command.BEQ node = tokens.Command(cond_type, mark=goto.mark).from_node(cond) optimizer.rewind(3) optimizer.push_node(mark) optimizer.push_node(node) return True
def cond_return_mark(self, optimizer): cond, return_, mark = optimizer.peek(3) if cond.mark is not mark: return False elif cond.get_type() == tokens.Command.BEQ: cond_type = tokens.Command.RNE else: cond_type = tokens.Command.REQ node = tokens.Command(cond_type).from_node(cond) optimizer.rewind(3) optimizer.push_node(mark) optimizer.push_node(node) return True
def compile_proc(self, mark, statements, optimizer): # Create new optimizer to compile data statements actions = ProcActions() parser = actions.make_parser() opt = optimizer.create_new(parser) # Add an implicit return statement to the procedure. return_ = tokens.Command(tokens.Command.RETURN) opt.push_node(return_) # Push a final THEN mark as target for any CONT IF statement. actions.push_then_mark(opt) # Compile the procedure statements to a CodeBlock. Add all blocks to # the optimizer. opt.push_node(statements) opt.push_node(mark) opt.compile_to(blocks.CodeBlock, optimizer.blocks)
def compare_not(self, optimizer): compare, not_ = optimizer.rewind(2) op = compare.get_type() if op == tokens.Command.LT: op = tokens.Command.GEQ elif op == tokens.Command.LEQ: op = tokens.Command.GT elif op == tokens.Command.NEQ: op = tokens.Command.EQ elif op == tokens.Command.EQ: op = tokens.Command.NEQ elif op == tokens.Command.GT: op = tokens.Command.LEQ elif op == tokens.Command.GEQ: op = tokens.Command.LT node = tokens.Command(op).from_node(not_) optimizer.push_node(node) return True
def push_program(self, optimizer): program = optimizer.rewind() # End with a mark for any contif statement and an implicit stop # statement. stop = tokens.Command(tokens.Command.STOP) optimizer.push_node(stop) self.push_then_mark(optimizer) # Optimize the program body statements. optimizer.push_node(program.statements) # Begin the program with an implicit preamble to invoke the byte code # interpreter at the provided runtime address.. preamble = tokens.Preamble(program.rt) optimizer.push_node(preamble) # Create program level scope. optimizer.open_scope() # Program node has been reduced. return True
def newToken(text, *args, **kwargs): "Returns an instance of the correct Token subclass." if text in operators.operators: return tokens.Operator(text) elif text in operators.commands: return tokens.Command(text) elif text[0] == "'": return tokens.Char(text) elif text[0] == '"': return tokens.String(text) elif text[:2] == '\\"': return tokens.EscapedString(text) elif text[0] == '`': return tokens.Pattern(text) elif symbolsRgx.fullmatch(text): return tokens.Symbol(text) elif nameRgx.fullmatch(text): return tokens.Name(text) elif numberRgx.fullmatch(text): return tokens.Number(text) # Others as needed else: return None
def gosub_return(self, optimizer): gosub, return_ = optimizer.rewind(2) goto = tokens.Command(tokens.Command.GOTO, command=gosub).from_node(gosub) optimizer.push_node(goto) return True
return False elif (marked_type := marked.get_type()) != tokens.Command.RETURN and \ (marked_type != tokens.Command.GOTO or marked.mark is None): # Marked command is not a RETURN and not a GOTO with a target mark. # Nothing to optimize. return False # Replace conditional branch by a new conditional node. optimizer.rewind() # Get the branch type (either BEQ or BNE). cond_type = cond.get_type() if marked_type == tokens.Command.GOTO: # Replace branch to a GOTO by a short circuited branch. node = tokens.Command(cond_type, mark=marked.mark) elif cond_type == tokens.Command.BEQ: # Replace BEQ to a RETURN by a REQ. node = tokens.Command(tokens.Command.REQ) else: # Replace BNE to a RETURN by a RNE. node = tokens.Command(tokens.Command.RNE) node.from_node(cond) optimizer.push_node(node) return True def push_gosub(self, optimizer): gosub = optimizer.peek() if (mark := gosub.mark) is None or \ (marked := mark.marked) is None:
def push_if_block(block): goto = tokens.Command(tokens.Command.GOTO, mark=end_mark) optimizer.push_node(goto) optimizer.push_node(block)
def push_contif(self, optimizer): contif = optimizer.rewind() mark = self.then_marks[-1] beq = tokens.Command(tokens.Command.BEQ, mark=mark).from_node(contif) optimizer.push_node(beq) return True
def p_contif(self, p): 'contif : CONT IF' p[0] = tokens.Command(tokens.Command.CONTIF).from_node(p[1])