Exemplo n.º 1
0
    def visit(self, node, enviroment):
        child_enviroment = enviroment.create_child_enviroment()
        child_enviroment.define_symbol('self',
                                       'SELF_TYPE' + self.current_type.name, 0,
                                       0)

        for formal_param in node.formal_parameter_list:
            child_enviroment.define_symbol(formal_param.name,
                                           formal_param.type_parameter,
                                           formal_param.line,
                                           formal_param.column)

        self.visit(node.expression, child_enviroment)

        if node.return_type_method == 'SELF_TYPE':
            _type = Type('SELF_TYPE', self.current_type.name)
        else:
            # type_builder guarantee that _type exists
            _type = enviroment.get_type(node.return_type_method)

        if not enviroment.conforms(node.expression.computed_type, _type):
            errors.throw_error(
                errors.TypeError(
                    text=
                    f"Body expression type for method '{node.name}' does not conforms with its return type.",
                    line=node.line,
                    column=node.column))

        node.computed_type = node.expression.computed_type
Exemplo n.º 2
0
 def p_error(self, parse):
     if parse:
         errors.throw_error(
             errors.SyntacticError(text=f"Token error '{parse.value}'.",
                                   line=parse.lineno,
                                   column=parse.lexpos))
     else:
         errors.throw_error(errors.SyntacticError(text='EOF error.'))
Exemplo n.º 3
0
 def visit(self, node, enviroment):
     node_type = enviroment.get_symbol_type(node.name)
     if node_type is None:
         errors.throw_error(
             errors.NameError(
                 text=f"Variable '{node.name}' is not defined.",
                 line=node.line,
                 column=node.column))
     node.computed_type = node_type
Exemplo n.º 4
0
 def detect_cycles(self):
     #self.build_types_graph()
     self.visited = [False]*len(self.types_list)
     for u in range(len(self.types_list)):
         if not self.visited[u]:
             if self.dfs_cycles(u):
                 errors.throw_error(errors.SemanticError(text="The inheritance graph contains cycles.", line=0, column=0))
                 return 0
     return 1
Exemplo n.º 5
0
 def t_error(self, token):
     """
     Error Handling and Reporting Rule.
     """
     token.lexpos = (token.lexpos - self.lexer.line_start)
     errors.throw_error(
         errors.LexicographicError(text=f'Illegal character {token.value}',
                                   line=token.lineno,
                                   column=token.lexpos))
Exemplo n.º 6
0
 def t_string_newline(self, token):
     token.lexer.lineno += 1
     if not token.lexer.backslashEscaped:
         errors.throw_error(
             errors.LexicographicError(text='String \'\\n\' not scaped.',
                                       line=token.lineno,
                                       column=token.lexpos))
     else:
         token.lexer.backslashEscaped = False
         token.lexer.string_buf += '\n'
Exemplo n.º 7
0
    def visit(self, node, enviroment):
        self.visit(node.expression, enviroment)

        if node.expression.computed_type.name != "Int":
            errors.throw_error(
                errors.TypeError(
                    text=
                    f"The expression for unary operation 'Neg' must have type 'Int'.",
                    line=node.line,
                    column=node.column))

        node.computed_type = enviroment.get_type("Int")
Exemplo n.º 8
0
    def visit(self, node, enviroment):
        self.visit(node.while_expression, enviroment)
        self.visit(node.loop_expression, enviroment)

        if node.while_expression.computed_type.name != "Bool":
            errors.throw_error(
                errors.TypeError(
                    text=f"The predicate of a loop must have type 'Bool'.",
                    line=node.line,
                    column=node.column))

        node.computed_type = enviroment.get_type("Object")
Exemplo n.º 9
0
    def visit(self, node, enviroment):
        self.visit(node.left_expression, enviroment)
        self.visit(node.right_expression, enviroment)

        if node.left_expression.computed_type.name != 'Int' or node.right_expression.computed_type.name != 'Int':
            errors.throw_error(
                errors.TypeError(
                    text=
                    f"In arithmetic operation type of letf and right expressions must be 'Int'.",
                    line=node.line,
                    column=node.column))

        node.computed_type = enviroment.get_type("Int")
Exemplo n.º 10
0
 def visit(self, node, enviroment):
     if node.new_type == 'SELF_TYPE':
         node.computed_type = Type('SELF_TYPE', self.current_type.name)
     else:
         _type = enviroment.get_type(node.new_type)
         if _type is None:
             errors.throw_error(
                 errors.TypeError(
                     text=
                     f"In new expression type '{node.new_type}' does not exists.",
                     line=node.line,
                     column=node.column))
         node.computed_type = _type
Exemplo n.º 11
0
    def visit(self, node, enviroment):
        self.visit(node.if_expression, enviroment)
        self.visit(node.then_expression, enviroment)
        self.visit(node.else_expression, enviroment)

        if node.if_expression.computed_type.name != "Bool":
            errors.throw_error(
                errors.TypeError(text=f"If expression type must be 'Bool'.",
                                 line=node.line,
                                 column=node.column))

        node.computed_type = enviroment.lca([
            node.then_expression.computed_type,
            node.else_expression.computed_type
        ])
Exemplo n.º 12
0
 def t_string_end(self, token):
     if not token.lexer.backslashEscaped:
         token.value = token.lexer.string_buf
         token.type = 'STRING'
         token.lineno = token.lexer.string_lineno
         token.lexpos = token.lexer.string_lexpos
         if len(token.lexer.string_buf) > 1024:
             errors.throw_error(
                 errors.LexicographicError(
                     text="Strings may be at most 1024 characters long.",
                     line=token.lineno,
                     column=token.lexpos))
         token.lexer.pop_state()
         return token
     else:
         token.lexer.string_buf += '"'
         token.lexer.backslashEscaped = False
Exemplo n.º 13
0
    def visit(self, node, enviroment):
        self.visit(node.left_expression, enviroment)
        self.visit(node.right_expression, enviroment)

        basic_types = ['Int', 'String', 'Bool']

        if node.left_expression.computed_type.name in basic_types \
            or node.right_expression.computed_type.name in basic_types:

            if node.left_expression.computed_type.name != node.right_expression.computed_type.name:
                errors.throw_error(
                    errors.TypeError(
                        text=
                        f"In an equal operation, both expressions must have the same basic type.",
                        line=node.line,
                        column=node.column))

        node.computed_type = enviroment.get_type('Bool')
Exemplo n.º 14
0
    def visit(self, node, enviroment):
        if node.instance.name == 'self':
            errors.throw_error(
                errors.SemanticError(text=f"It is an error to assign to self.",
                                     line=node.line,
                                     column=node.column))

        self.visit(node.instance, enviroment)
        self.visit(node.expression, enviroment)

        if not enviroment.conforms(node.expression.computed_type,
                                   node.instance.computed_type):
            errors.throw_error(
                errors.TypeError(
                    text=
                    f"In assign expression type does not conforms with variable '{node.instance.name}' declared type.",
                    line=node.line,
                    column=node.column))

        node.computed_type = node.expression.computed_type
Exemplo n.º 15
0
 def visit(self, node):
     # node.type_attribute can be SELF_TYPE
     if node.type_attribute == 'SELF_TYPE':
         attribute_type = Type('SELF_TYPE', self.current_type.name)
     else:
         attribute_type = self.enviroment.get_type(node.type_attribute)
     if attribute_type is not None:
         if node.name == "self":
             errors.throw_error(
                 errors.SemanticError(
                     text=f"Name attribute can not be self.",
                     line=node.line,
                     column=node.column))
         else:
             ans = self.current_type.define_attribute(
                 node.name, node.type_attribute, node.line, node.column)
             if not ans:
                 errors.throw_error(
                     errors.SemanticError(
                         text=
                         f"In class '{self.current_type.name}' attribute '{node.name}' is defined multiple times.",
                         line=node.line,
                         column=node.column))
     else:
         errors.throw_error(
             errors.TypeError(
                 text=
                 f"The type '{node.type_attribute}' of attribute '{node.name}' is missing.",
                 line=node.line,
                 column=node.column))
Exemplo n.º 16
0
    def visit(self, node, enviroment):
        # [Attr-No-Init]
        node.computed_type = enviroment.get_symbol_type(node.name)

        # check if attribute has an initialization expression
        if node.expression is not None:
            # [Attr-Init]
            child_enviroment = enviroment.create_child_enviroment()
            child_enviroment.define_symbol(
                'self', 'SELF_TYPE' + self.current_type.name, 0, 0)

            self.visit(node.expression, child_enviroment)

            if not enviroment.conforms(node.expression.computed_type,
                                       node.computed_type):
                errors.throw_error(
                    errors.TypeError(
                        text=
                        f"Initialization expression type for attribute '{node.name}' does not conforms with its declared type.",
                        line=node.line,
                        column=node.column))

            node.computed_type = node.expression.computed_type
Exemplo n.º 17
0
    def visit(self, node):
        self.current_type = self.enviroment.get_type(node.name)

        parent_type = self.enviroment.get_type(node.parent)
        if parent_type is None and node.name != "Object":
            errors.throw_error(
                errors.TypeError(
                    text=
                    f"In class '{self.current_type.name}' parent type '{node.parent}' is missing.",
                    line=node.line,
                    column=node.column))
        if parent_type.name in ['Int', 'String', 'Bool']:
            errors.throw_error(
                errors.SemanticError(
                    text=
                    f"In class '{self.current_type.name}' it is an error to inherit from basic class '{node.parent}'.",
                    line=node.line,
                    column=node.column))

        for attribute in node.attribute_list:
            self.visit(attribute)

        for method in node.method_list:
            self.visit(method)
Exemplo n.º 18
0
    def visit(self, node, enviroment):
        self.visit(node.case_expression, enviroment)

        variable_types = []
        for _branch in node.branch_list:
            if _branch.name == 'self':
                errors.throw_error(
                    errors.SemanticError(
                        text=
                        f"It is an error to bind self in a case expression.",
                        line=_branch.line,
                        column=_branch.column))
            if _branch.type_branch == 'SELF_TYPE':
                errors.throw_error(
                    errors.SemanticError(
                        text=f"Branch declared type cannot be 'SELF_TYPE'.",
                        line=_branch.line,
                        column=_branch.column))
            _type = enviroment.get_type(_branch.type_branch)
            if _type is None:
                errors.throw_error(
                    errors.TypeError(
                        text=
                        f"Type '{_branch.type_branch}' declared for variable '{_branch.name}' is not defined.",
                        line=_branch.line,
                        column=_branch.column))
            if _type in variable_types:
                errors.throw_error(
                    errors.SemanticError(
                        text=
                        f"In case expression all types declared type must be different.",
                        line=node.line,
                        column=node.column))
            variable_types.append(_type)

        static_types = []
        for _branch in node.branch_list:
            child_enviroment = enviroment.create_child_enviroment()
            child_enviroment.define_symbol(_branch.name, _branch.type_branch,
                                           _branch.line, _branch.column)
            self.visit(_branch.expression, child_enviroment)
            _branch.computed_type = _branch.expression.computed_type  # in a BranchNode computed_type means the computed type of its expression
            static_types.append(_branch.computed_type)

        node.computed_type = enviroment.lca(static_types)
Exemplo n.º 19
0
    def dfs_inheritance_features(self, u, inherited_scope):
        # scope represent the scope inherited for the current type
        self.visited[u] = True
        valid = 1
        # take the current type
        _type = self.types_list[u]
        # check my attributes and methods first
        for attr, attr_obj in _type.attribute_dict.items():
            if inherited_scope.isdefined_attr(attr):
                valid = 0
                errors.throw_error(errors.SemanticError(text=f"In class '{_type.name}' attribute '{attr}' is redefined.", line=attr_obj.line, column=attr_obj.column))
            else:
                inherited_scope.define_attr(attr, _type.attribute_dict[attr]._type, attr_obj.line, attr_obj.column)

        # setting inherited attributes to the type
        for attr, (attr_type, attr_line, attr_column) in inherited_scope.attribute_dict.items():
            _type.define_attribute(attr, attr_type, attr_line, attr_column) # working on error

        for meth in _type.method_dict.values():
            arg_list = [attr._type for attr in meth.attribute_list]
            arg_list.append(meth.return_type)
            if inherited_scope.isdefined_meth(meth.name):
                arg_def_method = inherited_scope.get_method(meth.name)
                if len(arg_def_method) != len(arg_list):
                    valid = 0
                    errors.throw_error(errors.SemanticError(text=f"In class '{_type.name}' method '{meth.name}' is redefined with a different number of arguments.", line=meth.line, column=meth.column))
                else:
                    if arg_def_method[len(arg_def_method)-1] != arg_list[len(arg_list)-1]:
                        valid = 0
                        errors.throw_error(errors.SemanticError(text=f"In class '{_type.name}' method '{meth.name}' is redefined with a different return type.", line=meth.line, column=meth.column))
                    
                    for i in range(len(arg_list)-1):
                        if arg_def_method[i] != arg_list[i]:
                            valid = 0
                            errors.throw_error(errors.SemanticError(text=f"In class '{_type.name}' method '{meth.name}' is redefined with argument at position {i} with different type.", line=meth.line, column=meth.column))
            else:
                inherited_scope.define_meth(meth.name, arg_list)
        
        for v in self.inheritance_graph[u]:
            if not self.visited[v]:
                valid &= self.dfs_inheritance_features(v, Scope(inherited_scope))
        
        return valid
Exemplo n.º 20
0
 def check_main(self):
     _type = self.get_type("Main")
     if _type is not None: # checking if there is the program has a class Main 
         method = _type.get_method("main") # the method main is not inherited because enviroment is None
         if method is None: # checking if the a class Main has a method named main
             errors.throw_error(errors.SemanticError(text="Main class must have a method main.", line=0, column=0))
             return 0
         if len(method.attribute_list) > 0: # checking if the method main takes no formal parameters
             errors.throw_error(errors.SemanticError(text="Method main must not take formal parameters.", line=0, column=0))
             return 0
         return 1
     else:
         errors.throw_error(errors.SemanticError(text="Program must have a class Main.", line=0, column=0))
         return 0
Exemplo n.º 21
0
    def visit(self, node, enviroment):
        current_enviroment = enviroment
        for _decl in node.declaration_list:
            if _decl.name == 'self':
                errors.throw_error(
                    errors.SemanticError(
                        text=
                        f"It is an error to bind self in a let expression.",
                        line=_decl.line,
                        column=_decl.column))
            if _decl._type == 'SELF_TYPE':
                _type = Type('SELF_TYPE', self.current_type.name)
            else:
                _type = current_enviroment.get_type(_decl._type)
                if _type is None:
                    errors.throw_error(
                        errors.TypeError(
                            text=
                            f"Type '{_decl._type}' declared for variable '{_decl.name}' is not defined.",
                            line=_decl.line,
                            column=_decl.column))

            # check if _decl has an init expression
            if _decl.expression is not None:
                self.visit(_decl.expression, current_enviroment)

                if not enviroment.conforms(_decl.expression.computed_type,
                                           _type):
                    errors.throw_error(
                        errors.TypeError(
                            text=
                            f"Type of initialization expression for variable '{_decl.name}' does not conform with its declared type '{_decl._type}'.",
                            line=_decl.line,
                            column=_decl.column))

            new_child_enviroment = current_enviroment.create_child_enviroment()
            if _type.name == 'SELF_TYPE':
                new_child_enviroment.define_symbol(_decl.name,
                                                   'SELF_TYPE' + _type.parent,
                                                   _decl.line, _decl.column)
            else:
                new_child_enviroment.define_symbol(_decl.name, _type.name,
                                                   _decl.line, _decl.column)

            current_enviroment = new_child_enviroment

        self.visit(node.expression, current_enviroment)
        node.computed_type = node.expression.computed_type
Exemplo n.º 22
0
    def visit(self, node, enviroment):
        self.visit(node.instance, enviroment)

        for _expr in node.arguments:
            self.visit(_expr, enviroment)

        instance_type = node.instance.computed_type if node.instance.computed_type.name != 'SELF_TYPE' else enviroment.get_type(
            node.instance.computed_type.parent)
        meth = instance_type.get_method(
            node.method,
            enviroment)  # enviroment is used to search for inherited methods

        if meth is None:
            errors.throw_error(
                errors.AttributeError(
                    text=
                    f"Class '{instance_type.name}' does not contain a method named '{node.method}'.",
                    line=node.line,
                    column=node.column))

        # check if the number of arguments is correct
        if len(node.arguments) != len(meth.attribute_list):
            errors.throw_error(
                errors.SemanticError(
                    text=
                    f"Dynamic dispatch does not match with the signature of method '{node.method}'.",
                    line=node.line,
                    column=node.column))

        # check if each arg type conforms with the formal parameter type in the method signautre
        for i in range(len(node.arguments)):
            if not enviroment.conforms(
                    node.arguments[i].computed_type,
                    enviroment.get_type(meth.attribute_list[i]._type)):
                errors.throw_error(
                    errors.TypeError(
                        text=
                        f"In dynamic dispatch of method '{node.method}' the type of the argument at index {i} does not conforms with the type of the formal parameter in the method signature.",
                        line=node.line,
                        column=node.column))

        # The return type of a method always exits, its garanty in the type_builder
        if meth.return_type == 'SELF_TYPE':
            node.computed_type = node.instance.computed_type
        else:
            node.computed_type = enviroment.get_type(meth.return_type)
Exemplo n.º 23
0
 def visit(self, node):
     ans = self.enviroment.create_type(node.name, node.parent)
     if ans is None:
         errors.throw_error(errors.SemanticError(text=f"Class '{node.name}' may not be redefined", line=node.line, column=node.column))
Exemplo n.º 24
0
 def t_string_eof(self, token):
     errors.throw_error(
         errors.LexicographicError(text="String can't end with EOF.",
                                   line=token.lineno,
                                   column=token.lexpos))
Exemplo n.º 25
0
    def visit(self, node):
        # node.return_type_method can be SELF_TYPE
        if node.return_type_method == 'SELF_TYPE':
            return_type = Type('SELF_TYPE', self.current_type.name)
        else:
            return_type = self.enviroment.get_type(node.return_type_method)
        if return_type is not None:
            # formal_parameter_list
            argument_list = []
            for parameter in node.formal_parameter_list:
                if parameter.name == 'self':
                    errors.throw_error(
                        errors.SemanticError(
                            text=
                            f"In method '{node.name}' it is an error to bind self as a formal parameter.",
                            line=node.line,
                            column=node.column))
                if parameter.name in argument_list:
                    errors.throw_error(
                        errors.SemanticError(
                            text=
                            f"In method '{node.name}' the argument '{parameter.name}' is defined multiple times.",
                            line=node.line,
                            column=node.column))
                argument_list.append(parameter.name)

            argument_types = []
            for parameter in node.formal_parameter_list:
                if parameter.type_parameter == 'SELF_TYPE':
                    errors.throw_error(
                        errors.TypeError(
                            text=
                            f"In method '{node.name}' the type of argument '{parameter.name}' cannot be SELF_TYPE.",
                            line=node.line,
                            column=node.column))
                _type = self.enviroment.get_type(parameter.type_parameter)
                if _type is not None:
                    argument_types.append(parameter.type_parameter)
                else:
                    errors.throw_error(
                        errors.TypeError(
                            text=
                            f"The type of the parameter '{parameter.name}' in method '{node.name}' is missing.",
                            line=node.line,
                            column=node.column))

            ans = self.current_type.define_method(node.name,
                                                  node.return_type_method,
                                                  argument_list,
                                                  argument_types, node.line,
                                                  node.column)
            if not ans:
                errors.throw_error(
                    errors.SemanticError(
                        text=
                        f"In class '{self.current_type.name}' method '{node.name}' is defined multiple times.",
                        line=node.line,
                        column=node.column))
        else:
            errors.throw_error(
                errors.TypeError(
                    text=
                    f"In class '{self.current_type.name}' return type of method '{node.name}' is missing.",
                    line=node.line,
                    column=node.column))
Exemplo n.º 26
0
 def t_comment2_eof(self, token):
     errors.throw_error(
         errors.LexicographicError(
             text="Comment (* ... *) can't end with EOF.",
             line=token.lineno,
             column=token.lexpos))
Exemplo n.º 27
0
 def t_string_error(self, token):
     token.lexpos = (token.lexpos - self.lexer.line_start)
     errors.throw_error(
         errors.LexicographicError(text=f'Illegal character {token.value}',
                                   line=token.lineno,
                                   column=token.lexpos))
Exemplo n.º 28
0
def main():
    # TAKE THE INPUT
    programs = sys.argv[1:]

    # CHECK IF AT LEAST ONE FILE IS GIVEN
    if len(programs) == 0:
            errors.throw_error(errors.CompilerError(text="No file is given to coolc compiler."))

    # CHECK IF FILEOUT IS GIVEN
    if programs[0] == '-o':
        if len(programs) == 1:
            errors.throw_error(errors.CompilerError(text="No fileout is given to coolc compiler."))
        fileout = programs[1]
        if not str(fileout).endswith(".asm"):
            errors.throw_error(errors.CompilerError(text="Fileout must end with .asm extension."))
        if len(programs) == 2:
            errors.throw_error(errors.CompilerError(text="No file is given to coolc compiler."))
        programs = programs[2:]
    else:
        fileout = programs[0].split(".cl")[0] + ".asm"

    # Check all programs have the *.cl extension.
    for program in programs:
        if not str(program).endswith(".cl"):
            errors.throw_error(errors.CompilerError(text="Cool program files must end with a .cl extension."))
    
    code = ""
    # Read all program source codes.
    for program in programs:
        try:
            with open(program, encoding="utf-8") as file:
                code += file.read() + '\n'
        except (IOError, FileNotFoundError):
            errors.throw_error(errors.CompilerError(text=f'File "{program}" was not found.'))
        except Exception:
            errors.throw_error(errors.CompilerError(text="An unexpected error occurred!"))

    print(f"Compiling file '{fileout}'...")

    # ===============================================================
    # ==================ANALISIS-LEXICOGRAFICO=======================
    # ===============================================================

    from lexicography.lexer_rules import CoolLex

    # BUILD THE LEXER
    lexer = CoolLex()
    lexer.build()

    # ===============================================================


    # ===============================================================
    # =====================ANALISIS-SINTACTICO=======================
    # ===============================================================

    from lexicography.grammar_rules import CoolParse

    # BUILD THE PARSER
    parser = CoolParse(lexer)
    parser.build()
    
    program_ast = parser.parse(code)

    # ===============================================================


    # ===============================================================
    # ======================ANALISIS-SEMANTICO=======================
    # ===============================================================

    from semantic.type_collector import TypeCollectorVisitor
    from semantic.type_builder import TypeBuilderVisitor
    from semantic.type_checker import TypeCheckerVisitor
    # from semantic.ast_types_painter import Painter

    typeCollector = TypeCollectorVisitor()
    typeCollector.visit(program_ast)

    typeBuilder = TypeBuilderVisitor(typeCollector.enviroment)
    typeBuilder.visit(program_ast)

    ## CHECK SEMANTIC ERRORS IN THE ENVIROMENT(check_main, cycles and inheritance rules)
    final_enviroment = typeBuilder.enviroment
    final_enviroment.build_types_graph()

    type_checker = TypeCheckerVisitor()
    type_checker.visit(program_ast, typeBuilder.enviroment)

    typed_ast = program_ast

    # ast_painter = Painter()
    # print(ast_painter.visit(typed_ast, 0))


    # ===============================================================


    # ===============================================================
    # ========================CODE-GENERATION========================
    # ===============================================================

    # COOL --> CIL

    from generation.cil.cil_generator import CilGeneratorVisitor
    # from general.cil_hierarchy import get_formatter

    cil_code_generator = CilGeneratorVisitor(typed_ast, typeBuilder.enviroment)
    ast_cil = cil_code_generator.generate_code()

    # cil_painter = get_formatter()
    # print(cil_painter(ast_cil))

    # CIL --> MIPS

    from generation.mips.mips_writer import MIPSWriterVisitor
    from operator import itemgetter

    types_ids = typeBuilder.enviroment.types_dict
    hierarchy = [0]*len(types_ids)
    for _type in typeBuilder.enviroment.types_list[1:]:
        hierarchy[types_ids[_type.name]] = types_ids[_type.parent]

    # tag_names = sorted(types_ids.items(), key=itemgetter(1))

    ast_cil.typesHierarchy = hierarchy
    # ast_cil.tag_names = tag_names
    mips_code_generator = MIPSWriterVisitor(ast_cil, fileout)
    mips_code_generator.generate_Mips()