コード例 #1
0
ファイル: Function.py プロジェクト: puntje/co-c2p
    def validateReturnType(self):
        for statement in self.content.statements:
            # find return statement
            if statement.type is SmallCParser.RETURNSTATEMENT:
                # validate functions with void as return type
                if isinstance(self.return_type, VoidType):
                    raise C2PException("return-statement with a value, in function '" + self.identifier +
                                       "' returning 'void'")

                from_type = statement.expression.result_type.getCSymbol()
                if statement.expression.result_type.is_pointer:
                    from_type += "*"

                to_type = self.return_type.getCSymbol()
                if self.return_type.is_pointer:
                    to_type += "*"
                elif self.return_type.is_reference:
                    to_type += "&"

                # validate expected return types (basic)
                if self.return_type.getName() != statement.expression.result_type.getName():
                    raise C2PException("In return statement of functon '" + self.identifier +
                                       "' invalid conversion from " + from_type + " to " + to_type)
                else:
                    # validate pointers
                    if self.return_type.is_pointer:
                        if statement.expression.result_type.is_pointer and not statement.expression.indirection:
                            return
                        if not statement.expression.result_type.is_pointer and statement.expression.address_of:
                            return
                        raise C2PException("Function '" + self.identifier + "' should return " +
                                           to_type + " instead of " + from_type)
コード例 #2
0
    def __init__(self, environment, name, indirection, address_of, array_size):
        super().__init__(environment)
        self.type = SmallCParser.ID
        symbol = environment.symbol_table.getSymbol(name)
        self.name = name
        self.indirection = indirection
        self.address_of = address_of
        if symbol is not None:
            self.operand_type = symbol.type
            self.result_type = self.operand_type
        else:
            raise C2PException("use of undeclared identifier '" + self.name +
                               "'")

        if self.operand_type.isArray():
            self.array_size = array_size
        else:
            self.array_size = 0

        self.address = symbol.address
        self.depth = symbol.getRelativeDepth(environment.call_stack)

        if self.indirection and not self.operand_type.is_pointer:
            raise C2PException(
                "'" + self.name +
                "' is not a pointer and therefore can not be dereferenced")
コード例 #3
0
    def checkFunctionSignature(self, name, parameters, return_type=None):
        arg_types = []
        # prepare `arg_types` with Type objects from parameter (declaration)
        # list
        if isinstance(parameters, ParameterList):
            # function call
            for arg in parameters.arguments:
                arg_types.append(arg.result_type)
        elif isinstance(parameters, ParameterDeclarationList):
            # function definition
            if parameters is not None:
                for param_decl in parameters.parameter_declarations:
                    if isinstance(param_decl, TypeSpecifier):
                        arg_types.append(param_decl.type_object)
                    else:
                        arg_types.append(param_decl)
        else:
            raise C2PException("Unexpected parameters type for function '" +
                               name + "'")

        # try to match function signature in our symbol table
        for scope in reversed(self.functions):
            if name in scope:
                # we start by checking the return type of the function
                if return_type is not None:
                    if return_type.getName(
                    ) != scope[name].return_type.getName():
                        continue

                # check whether amount of arguments is the same
                if len(arg_types) != len(scope[name].arg_types):
                    continue

                isTotalMatching = True
                for i in range(len(arg_types)):
                    # match actual Type of arguments
                    if arg_types[i].getName(
                    ) == scope[name].arg_types[i].getName():
                        # check that both are either pointers or none of them
                        # are
                        if not (arg_types[i].is_pointer
                                ^ scope[name].arg_types[i].is_pointer):
                            # this doesn't check possible indirection or references,
                            # it is left out in this stage else it would over
                            # complicate things
                            continue
                        isTotalMatching = False
                        break
                    else:
                        isTotalMatching = False
                        break

                # as long as something went wrong, keep looking up in outer
                # scope
                if isTotalMatching:
                    return scope[name]

        raise C2PException("Calling an undefined function '" + name + "'")
コード例 #4
0
    def __init__(self, environment, typename, var_decl_list):
        super().__init__(environment, SmallCParser.VARIABLEDECLARATION)

        if isinstance(typename, VoidType):
            raise C2PException("variable has incomplete type 'void'")

        self.typename = typename
        self.variable_identifiers = var_decl_list

        for var in self.variable_identifiers.variable_ids:
            if var.identifier not in environment.symbol_table.stack[-1]:
                var.setType(typename)
                self.addChild(var)
            else:
                raise C2PException("redefinition of '" + var.identifier + "'")
コード例 #5
0
    def __init__(self, environment, value):
        super().__init__(environment)
        self.type = SmallCParser.PRIMARY

        if isinstance(value, int):
            self.value = value
            self.operand_type = IntegerType()
            self.result_type = self.operand_type
        elif isinstance(value, float):
            self.value = value
            self.operand_type = FloatType()
            self.result_type = self.operand_type
        elif isinstance(value, bool):
            if value:
                self.value = 1
            else:
                self.value = 0
            self.operand_type = IntegerType()
            self.result_type = BooleanType()
        elif isinstance(value, str):
            self.value = "'" + value + "'"
            self.operand_type = CharacterType()
            self.result_type = self.operand_type
        else:
            raise C2PException("use of unrecognized primary value " +
                               str(value))
コード例 #6
0
ファイル: Term.py プロジェクト: puntje/co-c2p
    def generateCode(self, out):
        # Get p-code datatype for this expression
        p_type = self.operand_type.getPSymbol()

        # Get the first operand on top of the stack
        self.term.generateCode(out)
        self.cast(self.term, out)

        # Execute the relevant operation on the operands ('*' and '/' load
        # the factor in the condition to permit '%' to execute it later)
        if self.operator == "*":
            self.factor.generateCode(out)
            self.cast(self.factor, out)
            self.writeInstruction("mul " + p_type, out)
        elif self.operator == "/":
            self.factor.generateCode(out)
            self.cast(self.factor, out)
            self.writeInstruction("div " + p_type, out)
        elif self.operator == "%":
            # Duplicate the result of the term first, instead of recomputing it
            # This way we effectively cut the cost of the second computation
            # OPTIMALIZATION: try to find a way to duplicate the factor as well, instead of
            # computing it twice
            self.writeInstruction("dpl " + p_type, out)
            self.factor.generateCode(out)
            self.cast(self.factor, out)
            self.writeInstruction("div " + p_type, out)
            self.factor.generateCode(out)
            self.cast(self.factor, out)
            self.writeInstruction("mul " + p_type, out)
            self.writeInstruction("sub " + p_type, out)
        else:
            raise C2PException(self.operator + " is not supported")
コード例 #7
0
    def addFunction(self, name, return_type, parameter_decl_list, address,
                    depth):
        try:
            self.checkFunctionSignature(name, parameter_decl_list, return_type)
        except C2PException:
            self.functions[len(self.functions) - 1][name] = Function(
                return_type, parameter_decl_list, address, depth)
            return

        raise C2PException("redefinition of existing function '" + name + "'")
コード例 #8
0
ファイル: Assignment.py プロジェクト: puntje/co-c2p
    def __init__(self, environment, identifier, expression):
        super().__init__(environment)
        self.type = SmallCParser.ASSIGNMENT
        self.identifier = identifier
        self.expression = expression
        self.addChild(self.identifier)
        self.addChild(self.expression)

        symbol = environment.symbol_table.getSymbol(self.identifier.name)
        if symbol is None:
            raise C2PException("Can't assign to undeclared variable '" +
                               self.identifier.name + "'")
        self.expression.result_type = symbol.type
        self.address = symbol.address
        self.depth = symbol.getRelativeDepth(environment.call_stack)
        self.expression.operand_type = self.expression.result_type

        if self.expression.result_type.is_const:
            raise C2PException("Can't assign to const variable '" +
                               self.identifier.name + "'")
コード例 #9
0
ファイル: Factor.py プロジェクト: puntje/co-c2p
    def generateCode(self, out):
        # first get the operand on top of the stack
        self.factor.generateCode(out)
        self.cast(self.factor, out)

        # execute the relevant operation on the operand
        if self.operator == "-":
            self.writeInstruction("neg " + self.operand_type.getPSymbol(), out)
        elif self.operator == "!":
            self.writeInstruction("not ", out)
        else:
            raise C2PException(self.operator + " is not supported")
コード例 #10
0
ファイル: Comparison.py プロジェクト: puntje/co-c2p
    def generateCode(self, out):
        # Get p-code datatype for this expression
        p_type = self.operand_type.getPSymbol()

        # First get the operands on top of the stack
        self.relation1.generateCode(out)
        self.cast(self.relation1, out)
        self.relation2.generateCode(out)
        self.cast(self.relation2, out)

        # Execute the operation on the operands
        if self.operator == "==":
            self.writeInstruction("equ " + p_type, out)
        elif self.operator == "!=":
            self.writeInstruction("neq " + p_type, out)
        else:
            raise C2PException(self.operator, " is not supported")
コード例 #11
0
    def generateCode(self, out):
        # Get p-code datatype for this expression
        p_type = self.operand_type.getPSymbol()

        # First get the operands on top of the stack
        self.equation1.generateCode(out)
        self.cast(self.equation1, out)
        self.equation2.generateCode(out)
        self.cast(self.equation2, out)

        # Execute the relevant operation on the operands
        if self.operator is "<":
            self.writeInstruction("les " + p_type, out)
        elif self.operator is ">":
            self.writeInstruction("grt " + p_type, out)
        else:
            raise C2PException(self.operator + " is not supported.")
コード例 #12
0
    def generateCode(self, out):
        # Get p-code datatype for this expression
        p_type = self.operand_type.getPSymbol()

        # First get the operands on top of the stack
        self.equation.generateCode(out)
        self.cast(self.equation, out)

        # Then get the right side of the equation on top of the stack
        self.term.generateCode(out)
        self.cast(self.term, out)

        # Execute the relevant operation on the operands
        if self.operator == "+":
            self.writeInstruction("add " + p_type, out)
        elif self.operator == "-":
            self.writeInstruction("sub " + p_type, out)
        else:
            raise C2PException(self.operator + " is not supported")
コード例 #13
0
    def setType(self, typename):
        self.typename = typename
        self.typename.is_pointer = self.is_pointer
        self.typename.array_size = self.array_size

        if self.expression is not None:
            if isinstance(self.expression, Primary):
                self.value = self.expression.value
            if self.typename.getName() != self.expression.result_type.getName(
            ):
                raise C2PException("identifier '" + self.identifier +
                                   "' is assigned a value of type " +
                                   self.expression.result_type.getCSymbol() +
                                   ", while " + self.typename.getCSymbol() +
                                   " is expected")

            if self.is_pointer:
                if not self.expression.result_type.is_pointer and not self.expression.address_of:
                    raise C2PException(
                        "identifier '" + self.identifier +
                        "' is assigned a value of type " +
                        self.expression.result_type.getCSymbol() + ", while " +
                        self.typename.getCSymbol() + "* is expected")
        else:
            if self.is_pointer:
                raise C2PException(
                    "variable '" + self.identifier + "' is of type " +
                    self.typename.getCSymbol() +
                    "*, can't initialize pointer elements with default value.")
            else:
                # determine default value for uninitialized variable
                c_type = self.typename.getCSymbol()
                if c_type == "int":
                    self.value = 0
                elif c_type == "float":
                    self.value = 0.0
                elif c_type == "char":
                    self.value = '0'
                elif c_type == "bool":
                    self.value = False

                if not self.typename.isArray():
                    # initialize variable of basic type
                    self.addChild(Primary(self.environment, self.value))
                else:
                    for element in self.array_elements:
                        self.addChild(Primary(self.environment, element))
                    if len(self.array_elements) > self.array_size:
                        raise C2PException("Array '" + self.identifier +
                                           "' has size " +
                                           str(self.array_size) +
                                           ". You cannot fill it with " +
                                           str(len(self.array_elements)) +
                                           " elements.")
                    if len(self.array_elements) < self.array_size:
                        print(
                            "Warning: array '", self.identifier, "' has size ",
                            self.array_size,
                            ". Remaining elements will be filled with default values."
                        )
                    # initialize array of basic type
                    while (len(self.array_elements) != self.array_size):
                        self.array_elements.append(self.value)
                        self.addChild(Primary(self.environment, self.value))

        self.allocate()
コード例 #14
0
 def getRelativeDepth(self, call_stack):
     stack_depth = call_stack.getNestingDepth()
     if stack_depth < self.depth:
         raise C2PException(
             "scope of function is larger than stack's depth")
     return stack_depth - self.depth
コード例 #15
0
    parser = SmallCParser(stream)
    parser.removeErrorListeners()
    parser.addErrorListener(MyErrorListener())
    parsetree = parser.smallc_program()

    environment = Environment()
    ast = ASTGenerator(environment, parsetree).generate()

    if os.path.isfile(output):
        # empty the file so only new code is saved
        open(output, 'w').close()
    ast.generateCode(output)

    if saveast:
        ast.storeASTToDisk()
        draw(ast)


if __name__ == '__main__':
    try:
        if len(sys.argv) == 3:
            run(sys.argv[1], sys.argv[2], False)
        elif len(sys.argv) == 4 and sys.argv[3] == "-saveast":
            run(sys.argv[1], sys.argv[2], True)
        else:
            raise C2PException("ERROR: minimum 2 arguments needed: `input.c` \
                            and `output.p`, with an optional -saveast as last argument"
                               )
    except C2PException as error:
        print(error)