diff ide/compiler/parser.py @ 4:0d5ef85b8698

Improved link between ast viewer and code edit
author windel-eee
date Wed, 21 Sep 2011 19:05:18 +0200
parents 92df07bc2081
children 818f80afa78b
line wrap: on
line diff
--- a/ide/compiler/parser.py	Sun Sep 18 21:21:54 2011 +0200
+++ b/ide/compiler/parser.py	Wed Sep 21 19:05:18 2011 +0200
@@ -37,20 +37,23 @@
      
    def NextToken(self):
      self.token = self.tokens.__next__()
+     self.location = (self.token.row, self.token.col)
 
-   def setLocation(self):
-      pass
-   def attachLocation(self, node):
-      node.row, node.col = self.token.row, self.token.col
-      return node
+   # Helpers to find location of the error in the code:
+   def setLocation(self, obj, location):
+      obj.location = location
+      return obj
+   def getLocation(self):
+      return self.location
+
    """
      Recursive descent parser functions:
         A set of mutual recursive functions.
         Starting symbol is the Module.
    """
-
    def parseModule(self):
        self.imports = []
+       loc = self.getLocation()
        self.Consume('module')
        modname = self.Consume('ID')
        self.Consume(';')
@@ -81,7 +84,7 @@
        self.Consume('.')
 
        mod.imports = self.imports
-       return mod
+       return self.setLocation(mod, loc)
 
    # Import part
    def parseImportList(self):
@@ -92,15 +95,21 @@
          self.Consume(';')
 
    def parseImport(self):
+      loc = self.getLocation()
       modname = self.Consume('ID')
       mod = loadModule(modname)
+      self.setLocation(mod, loc)
       self.cst.addSymbol(mod)
 
    # Helper to parse an identifier defenitions
    def parseIdentDef(self):
+      loc = self.getLocation()
       name = self.Consume('ID')
       ispublic = self.hasConsumed('*')
-      return (name, ispublic)
+      # Make a node of this thing:
+      i = Id(name)
+      i.ispublic = ispublic
+      return self.setLocation(i, loc)
 
    def parseIdentList(self):
       ids = [ self.parseIdentDef() ]
@@ -138,6 +147,7 @@
            The base location in memory is denoted by the qualified identifier
            The actual address depends on the selector.
       """
+      loc = self.getLocation()
       obj = self.parseQualIdent()
       typ = obj.typ
       selectors = []
@@ -164,7 +174,7 @@
          elif self.hasConsumed('^'):
             selectors.append(Deref())
             typ = typ.pointedType
-      return Designator(obj, selectors, typ)
+      return self.setLocation(Designator(obj, selectors, typ), loc)
 
    # Declaration sequence
    def parseDeclarationSequence(self):
@@ -222,11 +232,12 @@
       """ Parse const part of a module """
       if self.hasConsumed('const'):
          while self.token.typ == 'ID':
-            name, ispublic = self.parseIdentDef()
+            i = self.parseIdentDef()
             self.Consume('=')
             constvalue, typ = self.parseConstExpression()
             self.Consume(';')
-            c = Constant(constvalue, typ, name=name, public=ispublic)
+            c = Constant(constvalue, typ, name=i.name, public=i.ispublic)
+            self.setLocation(c, i.location)
             self.cst.addSymbol(c)
      
    # Type system
@@ -276,10 +287,10 @@
             self.Consume(':')
             typ = self.parseType()
             self.Consume(';')
-            for id, public in identifiers:
-               if id in fields.keys():
-                  self.Error('record field "{0}" multiple defined.'.format(id))
-               fields[id] = typ
+            for i in identifiers:
+               if i.name in fields.keys():
+                  self.Error('record field "{0}" multiple defined.'.format(i.name))
+               fields[i.name] = typ
             # TODO store this in another way, symbol table?
          self.Consume('end')
          return RecordType(fields)
@@ -302,8 +313,9 @@
                self.Consume(':')
                typename = self.parseType()
                self.Consume(';')
-               for name, ispublic in ids:
-                  v = Variable(name, typename, public=ispublic)
+               for i in ids:
+                  v = Variable(i.name, typename, public=i.ispublic)
+                  self.setLocation(v, i.location)
                   self.cst.addSymbol(v)
          else:
             self.Error('Expected ID, got'+str(self.token))
@@ -349,7 +361,8 @@
 
    def parseProcedureDeclaration(self):
      self.Consume('procedure')
-     name, ispublic = self.parseIdentDef()
+     i = self.parseIdentDef()
+     procname = i.name
      proctyp = self.parseFormalParameters()
      procsymtable = SymbolTable(parent = self.cst)
      self.cst = procsymtable    # Switch symbol table:
@@ -388,16 +401,17 @@
 
      self.Consume('end')
      endname = self.Consume('ID')
-     if endname != name:
+     if endname != procname:
         self.Error('endname should match {0}'.format(name))
      self.cst = procsymtable.parent    # Switch back to parent symbol table
-     proc = Procedure(name, proctyp, block, procsymtable, returnexpression)
+     proc = Procedure(procname, proctyp, block, procsymtable, returnexpression)
      self.cst.addSymbol(proc)
-     proc.public = ispublic
+     proc.public = i.ispublic
      return proc
 
    # Statements:
    def parseAssignment(self, lval):
+      loc = self.getLocation()
       self.Consume(':=')
       rval = self.parseExpression()
       if isType(lval.typ, real) and isType(rval.typ, integer):
@@ -407,7 +421,7 @@
             self.Error('Can assign nil only to pointers or procedure types, not {0}'.format(lval))
       elif not isType(lval.typ, rval.typ):
          self.Error('Type mismatch {0} != {1}'.format(lval.typ, rval.typ))
-      return Assignment(lval, rval)
+      return self.setLocation(Assignment(lval, rval), loc)
 
    def parseExpressionList(self):
       expressions = [ self.parseExpression() ]
@@ -432,6 +446,7 @@
       return ProcedureCall(procedure, args)
 
    def parseIfStatement(self):
+     loc = self.getLocation()
      self.Consume('if')
      ifs = []
      condition = self.parseExpression()
@@ -454,7 +469,7 @@
      self.Consume('end')
      for condition, truestatement in reversed(ifs):
          statement = IfStatement(condition, truestatement, statement)
-     return statement
+     return self.setLocation(statement, loc)
 
    def parseCase(self):
       # TODO
@@ -470,6 +485,7 @@
       self.Consume('end')
 
    def parseWhileStatement(self):
+      loc = self.getLocation()
       self.Consume('while')
       condition = self.parseExpression()
       self.Consume('do')
@@ -477,7 +493,7 @@
       if self.hasConsumed('elsif'):
          self.Error('elsif in while not yet implemented')
       self.Consume('end')
-      return WhileStatement(condition, statements)
+      return self.setLocation(WhileStatement(condition, statements), loc)
 
    def parseRepeatStatement(self):
       self.Consume('repeat')
@@ -486,6 +502,7 @@
       cond = self.parseBoolExpression()
 
    def parseForStatement(self):
+      loc = self.getLocation()
       self.Consume('for')
       variable = self.parseDesignator()
       if not variable.typ.isType(integer):
@@ -509,9 +526,10 @@
       self.Consume('do')
       statements = self.parseStatementSequence()
       self.Consume('end')
-      return ForStatement(variable, begin, end, increment, statements)
+      return self.setLocation(ForStatement(variable, begin, end, increment, statements), loc)
 
    def parseAsmcode(self):
+      # TODO: move this to seperate file
       def parseOpcode():
          return self.Consume('ID')
       def parseOperand():
@@ -622,6 +640,7 @@
    def parseTerm(self):
        a = self.parseFactor()
        while self.token.typ in ['*', '/', 'mod', 'div', 'and']:
+           loc = self.getLocation()
            op = self.Consume()
            b = self.parseTerm()
            # Type determination and checking:
@@ -668,7 +687,7 @@
            else:
               self.Error('Unknown operand {0}'.format(op))
 
-           a = Binop(a, op, b, typ)
+           a = self.setLocation(Binop(a, op, b, typ), loc)
        return a
 
    def parseFactor(self):
@@ -677,11 +696,13 @@
          self.Consume(')')
          return e
       elif self.token.typ == 'NUMBER':
-          val = self.Consume('NUMBER')
-          return Constant(val, integer)
+         loc = self.getLocation() 
+         val = self.Consume('NUMBER')
+         return self.setLocation(Constant(val, integer), loc)
       elif self.token.typ == 'REAL':
-          val = self.Consume('REAL')
-          return Constant(val, real)
+         loc = self.getLocation()
+         val = self.Consume('REAL')
+         return self.setLocation(Constant(val, real), loc)
       elif self.token.typ == 'CHAR':
           val = self.Consume('CHAR')
           return Constant(val, char)
@@ -723,6 +744,7 @@
       else:
          a = self.parseTerm()
       while self.token.typ in ['+', '-', 'or']:
+           loc = self.getLocation()
            op = self.Consume()
            b = self.parseTerm()
            if op in ['+', '-']:
@@ -749,6 +771,6 @@
               typ = boolean
            else:
               self.Error('Unknown operand {0}'.format(op))
-           a = Binop(a, op, b, typ)
+           a = self.setLocation(Binop(a, op, b, typ), loc)
       return a