Esempio n. 1
0
    def _compile_if_statement(self, node: ParseTreeNode):
        condition_node = node.get_child("bool")
        self.oreo_to_tac(condition_node)

        condition_is_false_label = Label('if_false')

        # IfZ a Goto L1;
        # > result=L1 op=IfFalseGoto, arg1=a
        self._add_instruction(
            arg1=condition_node.result,
            op=IF_FALSE_GOTO,
            result_var=condition_is_false_label
        )

        # the if statement was true
        self.oreo_to_tac(node.get_child("compound"))

        if node.has_child("optional_else"):
            end_of_else_block_label = Label('else_end')

            # if condition held, skip the else block
            self._add_goto_instruction(end_of_else_block_label)

            # the else block
            self.program.append(condition_is_false_label)
            self.oreo_to_tac(node.get_child("optional_else"))
            self.program.append(end_of_else_block_label)

        else:
            # there's no else block: if condition doesn't hold, just jump down here
            self.program.append(condition_is_false_label)
Esempio n. 2
0
 def _compile_print_expression(self, node: ParseTreeNode):
     if node.has_child("GET"):
         return self._add_instruction(
             op="GET"
         )
     else:
         self._add_instruction(
             result_var=node.get_child("expression").result,
             op=node.get_a_child(["PRINT", "PRINTLN"]).content.token.name
         )
         return "NULL RESULT"
Esempio n. 3
0
    def oreo_to_tac(self, node: ParseTreeNode):
        if hasattr(node, "result"):
            return  # this node has already been processed, no need to do it again

        if node.is_non_terminal("p"):
            # ignore the top level program declaration, just process the program compound itself
            self.oreo_to_tac(node.get_child("compound"))
            return

        # if statements and while loops are carefully compiled in order, so the right things are in the right labels
        elif node.is_non_terminal("i"):
            self._compile_if_statement(node)
            return

        elif node.is_non_terminal("w"):
            self._compile_while_statement(node)
            return

        for child in node.children:
            self.oreo_to_tac(child)

        if node.is_terminal("NUMBER") or node.is_terminal("STRING"):
            literal = node.content.token.attribute
            if node.is_terminal("NUMBER"):
                literal = int(literal)
            node.result = NodeResult(literal=literal)

        elif node.is_terminal("TRUE") or node.is_terminal("FALSE"):
            bool_literal = TRUE_TAC if node.is_terminal("TRUE") else FALSE_TAC
            node.result = NodeResult(literal=bool_literal)

        elif node.is_terminal("ID"):
            node.result = NodeResult(variable=self._get_variable(node.content.token.attribute, create=True))

        elif node.is_in(["term", "factor", "simple_expr", "compare_expr", "bool"]):
            node.result = self._compile_optional_combiner(node)

        elif node.is_non_terminal("expression"):
            node.result = self._compile_optional_combiner(node, specific_combiners=["and_or_b"])

        elif node.is_non_terminal("a"):
            self._compile_assignment(node.get_child("ID"), node.get_child("expression"))

        elif node.is_non_terminal("v") and node.has_child("var_assign"):
            self._compile_assignment(node.get_child("ID"), node.get_child("var_assign").get_child("expression"))

        elif node.is_non_terminal("pr"):
            node.result = self._compile_print_expression(node)

        if hasattr(node, "result"):
            assert isinstance(node.result, NodeResult)
        else:
            node.result = "NULL RESULT"  # to prevent reprocessing processed nodes which do not have a result
Esempio n. 4
0
def _analyse(node: ParseTreeNode, scope):
    node.scope = scope

    if node.is_non_terminal("function_definition"):
        _analyse_func_definition(node)

    elif node.is_non_terminal(
            "v"):  # variable declaration, with optional assignment
        _analyse_variable_assignment(node, scope, is_declaration=True)

    elif node.is_non_terminal(
            "a"):  # assignment of an already declared variable
        _analyse_variable_assignment(node, scope, is_declaration=False)

    elif node.is_non_terminal("pr") and node.has_child(
            "GET"):  # assign declared variable to user input
        _analyse_variable_assignment(node, scope, is_declaration=False)

    elif node.is_terminal("ID"):
        scope.use_var(node)

    elif node.children:
        for child in node.children:
            _analyse(child, scope)