Beispiel #1
0
class Generator(object):
   class EnumArchitetureType:
      PARALLEL = 0
      SERIAL   = 1

   def __init__(self):
      self.ImmediateCode          = [] # unoptimized immediate code
      self.ImmediateCodeOptimized = [] # optimized immediate code
      self.Variables              = []

      self.ArchOutput = Architecture()

      # type:

      # while       begin of a while loop
      #             statement    statement of the header
      #             body         the body of the while loop (is a list)

      # number      (statement) only a number
      #             value        the value of the number

      # TODO< remove this >
      # assigment   asign a new value to a number
      #             variable     the name of the target variable
      #             statement    a statement for the assigment of a new value

      # assigment2       assign the right side to the left
      #                  left          leftside
      #                  right         rightside

      # minusAssigment   -=
      #                  left          leftside
      #                  right         rightside

      # variable         access a variable
      #                  name          the name of the variable

      # mul              multiplication
      #                  left          leftside
      #                  right         rightside

      # div              division
      #                  left          leftside
      #                  right         rightside

      # add              addition
      #                  left          leftside
      #                  right         rightside

      # sub              subtraction
      #                  left          leftside
      #                  right         rightside

      # if               if thing
      #                  statement     the statement
      #                  block         the contained block
      #                  else          None or another block with the else part

      # true             (statement)

      # false            (statement)

      # greaterEqual     (statement)
      #                  left          leftside
      #                  right         rightside

      # TODO< smallerEqual, Equal, Unequal, Smaller, Greater >

      # break            break expression

      # postinc          (statement)
      #                  statement

      # preinc           (statement)
      #                  statement

      # postdec          (statement)
      #                  statement

      # preinc           (statement)
      #                  statement

      # return           (statement)
      #                  expression       is the expression that have to be avaluated, can also be not set (None)
      #                  expressionSet    was the Expression set (True or False)

      # newConstArray    creates a new constant unchangable array
      #                  name             is the name of the array
      #                  info             Typeinformation, is a 'Datatype' Object

      # newVar2          allocates space for a new (scoped) variable
      #                  name             is the Variablename
      #                  info             Typeinformation, is a 'Datatype' Object
      
      # constantFloat    is a contant float
      #                  value            is the floatingpoint value

      """
      self.Root = [
         {"type":"newVar", "name":"Counter", "dataType":0,"bits":32},
         {"type":"assigment2", "left":{"type":"variable", "name":"Counter"}, "right":{"type":"number", "value":20}},
         {"type":"newVar", "name":"Xn", "dataType":0, "bits":32},
         {"type":"assigment2", "left":{"type":"variable", "name":"Xn"}, "right":{"type":"number", "value":5}},
         {"type":"newVar", "name":"Number", "dataType":0, "bits":32},
         {"type":"assigment2", "left":{"type":"variable", "name":"Number"}, "right":{"type":"number", "value":500}},

         {"type":"while", "statement":{"type":"number", "value":1}, "body":[
            {"type":"minusAssignment", "left":{"type":"variable", "name":"Counter"}, "right":{"type":"number", "value":1}},
            {"type":"assigment2", "left":{"type":"variable", "name":"Xn"}, "right":{
               "type":"div", "left":{"type":"add", "left":{"type":"variable", "name":"Xn"}, "right":{"type":"div", "left":{"type":"variable", "name":"Number"}, "right":{"type":"variable", "name":"Xn"}}}, "right":{"type":"number", "value":2}
            }}
         ]}
      ]"""

      # algorithm for calculating of the sqrt

      # (examples/calc my sqrt)
      # (is a serial code)
      # works

      """

      Type1 = Datatype(Datatype.EnumBasetype.UNSIGNED)
      Type1.Bits = 32

      Type2 = Datatype(Datatype.EnumBasetype.UNSIGNED)
      Type2.Bits = 32

      Type3 = Datatype(Datatype.EnumBasetype.UNSIGNED)
      Type3.Bits = 32

      self.Root = [
         {"type":"newVar2", "name":"Input", "info":Type1},
         {"type":"assigment2", "left":{"type":"variable", "name":"Input"}, "right":{"type":"number", "value":29}},
         {"type":"newVar2", "name":"Counter", "info":Type2},
         {"type":"assigment2", "left":{"type":"variable", "name":"Counter"}, "right":{"type":"number", "value":0}},
         {"type":"newVar2", "name":"Old", "info":Type3},
         {"type":"assigment2", "left":{"type":"variable", "name":"Old"}, "right":{"type":"number", "value":0}},
         
         {"type":"while", "statement":{"type":"true"}, "body":[
            {"type":"assigment2", "left":{"type":"variable", "name":"Old"}, "right":{
               "type":"add", "left":{"type":"variable", "name":"Old"}, "right":{
                  "type":"add", "left":{"type":"mul", "left":{"type":"number", "value":2}, "right":{"type":"variable", "name":"Counter"}}, "right":{"type":"number", "value":1}
               }
            }},

            {
               "type":"if",
               "statement":{"type":"greaterEqual", "left":{"type":"variable", "name":"Old"}, "right":{"type":"variable", "name":"Input"}},
               "block":[
                  {"type":"break"}
               ]
            },

            {
               "type":"postinc",
               "statement":{"type":"variable", "name":"Counter"}
            }
         ]}
      ]

      """

      # cordic algorithm

      """
      const fixed6p12 ATanTable[1] = [0.7853981633974483 , 0.4636476090008061,
                                0.24497866312686414, 0.12435499454676144,
                                0.06241880999595735, 0.031239833430268277,
                                0.015623728620476831];
      """

      """
      Type1 = Datatype(Datatype.EnumBasetype.FIXEDPOINT) # fixedpoint Datatype
      Type1.PrePointBits = 6
      Type1.PostPointBits = 12
      Type1.IsArray = True
      Type1.IsConst = True
      Type1.ArrayValues = [0.7853981633974483 , 0.4636476090008061, 0.24497866312686414, 0.12435499454676144, 0.06241880999595735, 0.031239833430268277, 0.015623728620476831]

      Type2 = Datatype(Datatype.EnumBasetype.FIXEDPOINT) # fixedpoint Datatype
      Type2.PrePointBits = 6
      Type2.PostPointBits = 12

      Type3 = Datatype(Datatype.EnumBasetype.FIXEDPOINT) # fixedpoint Datatype
      Type3.PrePointBits = 6
      Type3.PostPointBits = 12

      Type4 = Datatype(Datatype.EnumBasetype.FIXEDPOINT) # fixedpoint Datatype
      Type4.PrePointBits = 6
      Type4.PostPointBits = 12

      self.Root = [
         {"type":"newConstArray", "name":"ATanTable", "info":Type1},
         {"type":"newVar2", "name":"X", "info":Type2},
         {"type":"assigment2", "left":{"type":"variable", "name":"X"}, "right":{"type":"constantFloat", "value":4.0}},
         {"type":"newVar2", "name":"Y", "info":Type3},
         {"type":"assigment2", "left":{"type":"variable", "name":"Y"}, "right":{"type":"constantFloat", "value":1.0}},
         
         {"type":"newVar2", "name":"Phi", "info":Type4},
         {"type":"assigment2", "left":{"type":"variable", "name":"Phi"}, "right":{"type":"constantFloat", "value":0.907571}}
         
         
      ]
      """

      # Testcode for the parallelistation code

      Type1 = Datatype(Datatype.EnumBasetype.UNSIGNED)
      Type1.Bits = 32

      Type2 = Datatype(Datatype.EnumBasetype.UNSIGNED)
      Type2.Bits = 32

      Type3 = Datatype(Datatype.EnumBasetype.UNSIGNED)
      Type3.Bits = 32

      self.Root = [
         {"type":"newVar2", "name":"A", "info":Type1},
         {"type":"newVar2", "name":"B", "info":Type2},
         {"type":"newVar2", "name":"C", "info":Type3},
         
         {"type":"assigment2", "left":{"type":"variable", "name":"A"}, "right":{
            "type":"add", "left":{"type":"variable", "name":"A"}, "right":{"type":"add", "left":{"type":"variable", "name":"B"}, "right":{"type":"variable", "name":"C"}}
         #}}
         }}
      ]


      self.ImmediateCodeObj = ImmediateCode()

   def doIt(self, ArchitectureType):
      ReturnedTuple = self.transformObjectsIntoCode(self.Root, 0, 0, [])

      if ReturnedTuple[0]:
         print("Compilation successfull")
      else:
         print("Compilation Error")
         print(ReturnedTuple[1])

      print("\n\n")

      print(self.ImmediateCodeObj.debugImmediateCode(self.ImmediateCodeObj.ImmCodeData))

      self.ImmediateCode = self.ImmediateCodeObj.ImmCodeData

      OptimizerObj = Optimizer()
      OptimizerObj.ImmediateInstructions = self.ImmediateCode
      OptimizerObj.Variables = self.ImmediateCodeObj.Variables


      OptimizeAddSubToIncDec = True

      if ArchitectureType == Generator.EnumArchitetureType.PARALLEL:
         OptimizeAddSubToIncDec = False


      OptimizerObj.doOptimization(OptimizeAddSubToIncDec)


      self.ImmediateCodeOptimized = OptimizerObj.ImmediateInstructions
      self.Variables              = OptimizerObj.Variables
      
      print("\n\n")
      
      print(self.ImmediateCodeObj.debugImmediateCode(self.ImmediateCodeOptimized))

      if   ArchitectureType == Generator.EnumArchitetureType.PARALLEL:
         self.ArchOutput.ImmediateCodeOptimized = self.ImmediateCodeOptimized
         self.ArchOutput.VariablesOptimized     = self.Variables

         (CalleeSuccess, CalleeMessage) = self.ArchOutput.generateParallelDesign()

         if not CalleeSuccess:
            print("Error: " + CalleeMessage)


      elif ArchitectureType == Generator.EnumArchitetureType.SERIAL:
         pass
      else:
         print("Internal error")
         return False


   # "IntoVariable"    is the Id of the variable the result must be written into

   # returns (Success State, Error Message)
   def evaluateStatement(self, Statement, IntoVariable, IntoDatatype, VariableStack):
      print(Statement["type"])

      if   Statement["type"] == "variable":
         # lookup the variable name
         (Found, VariableId, VariableDatatype) = self.lookupVariable(VariableStack, Statement["name"])

         if not Found:
            return (False, "Variable " + Statement["name"] + " was not declared!")

         # check if the types and bits are equal
         TypeCheckResult = VariableDatatype.compareType(IntoType)

         if TypeCheckResult == Datatype.EnumTypeResult.DIFFERENTBITS:
            return (False, "Variable " + Statement["name"] + " don't have matching number of bits!")
         elif TypeCheckResult == Datatype.EnumTypeResult.DIFFERENTTYPE:
            return (False, "Variable " + Statement["name"] + " is of wrong type!")
         elif TypeCheckResult == Datatype.EnumTypeResult.EQUAL:
            # all right
            pass
         else:
            return (False, "Internal Error #42")

         self.ImmediateCodeObj.writeMov(IntoVariable, VariableId)

         return (True, 0)

      elif Statement["type"] == "number":
         self.ImmediateCodeObj.writeConstAssigment(IntoVariable, Statement["value"])
         
         return (True, 0)

      elif (Statement["type"] == "div") or (Statement["type"] == "add") or (Statement["type"] == "mul") or (Statement["type"] == "div"):
         VarLeft = None
         VarRight = None

         # do a simple optimization
         # if it is a variable, we don't need to create a Temporary Variable, evaluate it and move it into it
         if Statement["left"]["type"] == "variable":
            (Found, VarLeft, VarLeftDatatype) = self.lookupVariable(VariableStack, Statement["left"]["name"])

            if not Found:
               return (False, "Variable " + Statement["name"] + " was not declared!")

         else:
            VarLeft = self.ImmediateCodeObj.allocateVariable(IntoDatatype)
            VarLeftDatatype = IntoDatatype

            (CalleeSuccess, CalleeErrorMessage) = self.evaluateStatement(Statement["left"], VarLeft, VarLeftDatatype, VariableStack)
            if not CalleeSuccess:
               return (False, CalleeErrorMessage)

         # the same for the right side
         if Statement["right"]["type"] == "variable":
            (Found, VarRight, VarRightDatatype) = self.lookupVariable(VariableStack, Statement["right"]["name"])

            if not Found:
               return (False, "Variable " + Statement["name"] + " was not declared!")

         else:
            VarRight = self.ImmediateCodeObj.allocateVariable(IntoDatatype)
            VarRightDatatype = IntoDatatype

            (CalleeSuccess, CalleeErrorMessage) = self.evaluateStatement(Statement["right"], VarRight, VarRightDatatype, VariableStack)
            if not CalleeSuccess:
               return (False, CalleeErrorMessage)

         # check if the types are equal
         TypeCheckResult = VarLeftDatatype.compareType(VarRightDatatype)

         if   TypeCheckResult == Datatype.EnumTypeResult.DIFFERENTBITS:
            return (False, "Left and right variables don't have matching number of bits!")
         elif TypeCheckResult == Datatype.EnumTypeResult.DIFFERENTTYPE:
            return (False, "Left an right variables are of different type!")
         elif TypeCheckResult == Datatype.EnumTypeResult.EQUAL:
            # all right
            pass
         else:
            return (False, "Internal Error #42")


         if Statement["type"] == "add":
            self.ImmediateCodeObj.writeAdd(VarLeft, VarRight, IntoVariable)
         elif Statement["type"] == "sub":
            self.ImmediateCodeObj.writeSub(VarLeft, VarRight, IntoVariable)
         elif Statement["type"] == "mul":
            self.ImmediateCodeObj.writeMul(VarLeft, VarRight, IntoVariable)
         elif Statement["type"] == "div":
            self.ImmediateCodeObj.writeDiv(VarLeft, VarRight, IntoVariable)

         return (True, 0)

      else:
         # TODO

         # return an error
         print("Eval error")
         return (False,0)
         

   # ScopeType is the Type of the Scope
   # 0 : inside "main"
   # 1 : inside a "while"

   # ReturnLabelId is the Id of the Label a return/break instruction would jump to

   # VariableStack  is a stack with lists of the scoped variables
   #                each Element in the List is a dict with
   #                "name"   the name of the variable
   #                "id"     the id of the Variable
   #                "info"   typeinfo as a 'Datatype' object
   def transformObjectsIntoCode(self, Objects, ScopeType, ReturnLabelId, VariableStack):
      VariableStack.append([])

      for Object in Objects:
         print(Object["type"])

         if Object["type"] == "newVar2":
            # check if the variable was allready declared inside this scope
            for Variable in VariableStack[-1]:
               if Variable["name"] == Object["name"]:
                  return (False, "Variable '{0}' was allready defined in this scope!".format(Object["name"]))

            VariableId = self.ImmediateCodeObj.allocateVariable(Object["info"])

            # store the variable in the variable stack
            NewVar = {}
            NewVar["name"] = Object["name"]
            NewVar["id"]   = VariableId
            NewVar["info"] = Object["info"]

            VariableStack[-1].append(NewVar)

         elif Object["type"] == "assigment":
            # Emit an error

            return (False, "Internal Error #2 (Outdated)")
         
         elif Object["type"] == "assigment2":
            # check if on the left is a Variable, if not, emit an error
            # TODO< here is the right place for a struct lookup for for example a C-expression like "blub.a = ..." or "ax->ab = ..." >

            if Object["left"]["type"] != "variable":
               # emit an error
               return (False, "Internal Error #1 (TODO)")

            # do the variable lookup
            (VariableFound, LeftVariableId, LeftVariableInfo) = self.lookupVariable(VariableStack, Object["left"]["name"])

            if not VariableFound:
               # emit syntax error
               return (False, "Variable " + Object["left"]["name"] + " was not declared!")

            # evaluate the right statement
            (CalleeSuccess, CalleeMessage) = self.evaluateStatement(Object["right"], LeftVariableId, LeftVariableInfo, VariableStack)

            # check for errors of the function call
            if not CalleeSuccess:
               # TODO< return better error description >
               return (False, CalleeMessage)

         elif Object["type"] == "minusAssignment":
            # check if on the left is a Variable, if not, emit an error
            # TODO< here is the right place for a struct lookup for for example a C-expression like "blub.a = ..." or "ax->ab = ..." >

            if Object["left"]["type"] != "variable":
               # emit an error
               return (False, "Internal Error #1 (TODO)")

            (VariableFound, LeftVariableId, LeftVariableInfo) = self.lookupVariable(VariableStack, Object["left"]["name"])

            if not VariableFound:
               # emit syntax error
               return (False, "Variable " + Object["left"]["name"] + " was not declared!")

            # create a new temporary variable
            TempVar = self.ImmediateCodeObj.allocateVariable(LeftVariableInfo)

            (CalleeSuccess, CalleeMessage) = self.evaluateStatement(Object["right"], TempVar, LeftVariableInfo, VariableStack)

            # check for errors
            if not CalleeSuccess:
               # TODO< return better error description >
               return (False, CalleeMessage)

            self.ImmediateCodeObj.writeSub(LeftVariableId, TempVar, LeftVariableId)

         elif Object["type"] == "while":
            
            LabelIdStart = self.ImmediateCodeObj.getNewLableIdentifier()
            LabelIdEnd   = self.ImmediateCodeObj.getNewLableIdentifier()
   
            self.ImmediateCodeObj.writeLable(LabelIdStart)

            
            # TODO< emit code for evaluation of the statement >

            (CalleeSuccess, CalleeMessage) = self.transformObjectsIntoCode(Object["body"], 1, LabelIdEnd, VariableStack)
            
            if not CalleeSuccess:
               return (False, CalleeMessage)

            self.ImmediateCodeObj.writeGoto(LabelIdStart)

            self.ImmediateCodeObj.writeLable(LabelIdEnd)
         elif Object["type"] == "if":

            if Object["statement"]["type"] == "greaterEqual":
               if (Object["statement"]["left"]["type"] != "variable") and (Object["statement"]["right"]["type"] != "variable"):
                  return (False, "TODO 'if' #2")

               VariableNameLeft  = Object["statement"]["left"]["name"]
               VariableNameRight = Object["statement"]["right"]["name"]

               (VariableFound, VariableIdLeft, VarLeftDatatype) = self.lookupVariable(VariableStack, VariableNameLeft)

               if not VariableFound:
                  return (False, "Variable " + VariableNameLeft + " was not declared!")

               (VariableFound, VariableIdRight, VarRightDatatype) = self.lookupVariable(VariableStack, VariableNameRight)

               if not VariableFound:
                  return (False, "Variable " + VariableNameRight + " was not declared!")

               # check if the types do match
               TypeCheckResult = VarLeftDatatype.compareType(VarRightDatatype)

               if   TypeCheckResult == Datatype.EnumTypeResult.DIFFERENTBITS:
                  return (False, "Left and right variables don't have matching number of bits!")
               elif TypeCheckResult == Datatype.EnumTypeResult.DIFFERENTTYPE:
                  return (False, "Left an right variables are of different type!")
               elif TypeCheckResult == Datatype.EnumTypeResult.EQUAL:
                  # all right
                  pass
               else:
                  return (False, "Internal Error #42")


               # write Immediate code
               LabelIdTrue  = self.ImmediateCodeObj.getNewLableIdentifier()
               LabelIdIfEnd = self.ImmediateCodeObj.getNewLableIdentifier()

               self.ImmediateCodeObj.writeIf(VariableIdLeft, VariableIdRight, 0, LabelIdTrue, LabelIdIfEnd)
               self.ImmediateCodeObj.writeLable(LabelIdTrue)

               # TODO< add and remove new level of variable stack ! >

               (CalleeSuccess, CalleeMessage) = self.transformObjectsIntoCode(Object["block"], ScopeType, ReturnLabelId, VariableStack)

               if not CalleeSuccess:
                  return (False, CalleeMessage)

               self.ImmediateCodeObj.writeLable(LabelIdIfEnd)

            else:
               # TODO
               return (False, "TODO 'if' #1")

         elif Object["type"] == "break":
            if (ScopeType != 1) and (ScopeType != 2) : # if we are not in in a while or for
               return (False, "Using of break outside of an loop!")

            self.ImmediateCodeObj.writeGoto(ReturnLabelId)

         elif Object["type"] == "return":
            # TODO< check for beeing in a function >
            # TODO< check for needed return argument! >

            self.ImmediateCodeObj.writeGoto(ReturnLabelId)

         elif Object["type"] == "postinc":
            if Object["statement"]["type"] != "variable":
               return (False, "postinc TODO")

            (VariableFound, VariableId, VariableDatatype) = self.lookupVariable(VariableStack, Object["statement"]["name"])

            if not VariableFound:
               return (False, "Variable " + Object["statement"]["name"] + " was not declared!")

            self.ImmediateCodeObj.writeInc(VariableId, VariableId)

         elif Object["type"] == "preinc":
            return (False, "TODO #A")

         elif Object["type"] == "postdec":
            return (False, "TODO #B")

         elif Object["type"] == "predec":
            return (False, "TODO #C")

         else:
            # internal error

            return (False, "Internal Error!")

      VariableStack.pop()

      return (True, None)

   # this does the variable lookup
   def lookupVariable(self, VariableStack, VariableName):
      ActualStackIndex = len(VariableStack)-1
      Found = False
      VariableId = None
      VariableInfo = None

      while True:
         for Variable in VariableStack[ActualStackIndex]:
            if Variable["name"] == VariableName:
               Found = True
               VariableId = Variable["id"]
               VariableInfo = Variable["info"]

               break

         if Found:
            break

         if ActualStackIndex == 0:
            break

         ActualStackIndex -= 1

      return (Found, VariableId, VariableInfo)