changeset 149:74241ca312cc

Fixes on parser and semantics
author Windel Bouwman
date Fri, 01 Mar 2013 11:43:52 +0100
parents e5263f74b287
children 4ae0e02599de
files python/c3/astnodes.py python/c3/lexer.py python/c3/parser.py python/c3/semantics.py python/testc3.py
diffstat 5 files changed, 100 insertions(+), 74 deletions(-) [+]
line wrap: on
line diff
--- a/python/c3/astnodes.py	Fri Mar 01 10:24:01 2013 +0100
+++ b/python/c3/astnodes.py	Fri Mar 01 11:43:52 2013 +0100
@@ -64,7 +64,7 @@
    else:
       return False
 
-class Type:
+class Type(Node):
    def isType(self, b):
       return isType(self, b)
 
@@ -93,25 +93,21 @@
    pass
 
 class Constant(Symbol):
-   def __init__(self, value, typ, name=None, public=False):
+   def __init__(self, value, name=None):
       self.name = name
       self.value = value
-      self.typ = typ
-      self.public = public
    def __repr__(self):
       return 'CONSTANT {0} = {1}'.format(self.name, self.value)
 
 class Variable(Symbol):
-   def __init__(self, name, typ, public):
+   def __init__(self, name, typ):
       self.name = name
       self.typ = typ
-      self.public = public
       self.isLocal = False
       self.isReadOnly = False
       self.isParameter = False
    def __repr__(self):
-      txt = '[public] ' if self.public else ''
-      return '{2}VAR {0} : {1}'.format(self.name, self.typ, txt)
+      return 'VAR {0} : {1}'.format(self.name, self.typ)
 
 class Parameter(Node):
    """ A parameter has a passing method, name and typ """
@@ -135,7 +131,7 @@
       self.b = b
       self.op = op # Operation: '+', '-', '*', '/', 'mod'
    def __repr__(self):
-      return 'BINOP {0} {1}'.format(self.op, self.typ)
+      return 'BINOP {0}'.format(self.op)
 
 # Modules
 class Package(Node):
@@ -147,9 +143,9 @@
 # Procedure types
 class Procedure(Symbol):
    """ Actual implementation of a function """
-   def __init__(self, name, typ, block):
+   def __init__(self, name, typ=None, block=None):
       self.name = name
-      self.block = block
+      self.body = block
       self.typ = typ
    def __repr__(self):
       return 'PROCEDURE {0} {1}'.format(self.name, self.typ)
@@ -161,9 +157,11 @@
    def __repr__(self):
       return 'COMPOUND STATEMENT'
 
-class EmptyStatement(Node):
+class ReturnStatement(Node):
+   def __init__(self, expr):
+      self.expr = expr
    def __repr__(self):
-      return 'EMPTY STATEMENT'
+      return 'RETURN STATEMENT'
 
 class Assignment(Node):
    def __init__(self, lval, rval):
--- a/python/c3/lexer.py	Fri Mar 01 10:24:01 2013 +0100
+++ b/python/c3/lexer.py	Fri Mar 01 11:43:52 2013 +0100
@@ -10,7 +10,7 @@
 
 keywords = ['and', 'or', 'not','true', 'false', \
    'else', 'if', 'while', 'return', \
-   'public', 'function', 'var', 'type', \
+   'function', 'var', 'type', \
    'import', 'package' ]
 
 def tokenize(s):
--- a/python/c3/parser.py	Fri Mar 01 10:24:01 2013 +0100
+++ b/python/c3/parser.py	Fri Mar 01 11:43:52 2013 +0100
@@ -6,11 +6,6 @@
    '<': 20, '>': 20, '==': 20, '<=': 20, '>=': 20, '!=': 20, \
    '+': 30, '-': 30, '*': 40, '/': 40 }
 
-def getTokenPrecedence(typ):
-   if typ in binopPrecs:
-      return binopPrecs[typ]
-   return -1
-
 class Parser:
    """ Parses sourcecode into an abstract syntax tree (AST) """
    def __init__(self, sema, diag):
@@ -38,7 +33,9 @@
       return self.token.typ
    @property
    def PeakPrec(self):
-      return getTokenPrecedence(self.Peak)
+      if self.Peak in binopPrecs:
+         return binopPrecs[self.Peak]
+      return -1
    def hasConsumed(self, typ):
       if self.Peak == typ:
          self.Consume(typ)
@@ -64,16 +61,18 @@
       self.Consume('END')
 
    def parseTopLevel(self):
-      is_public = self.hasConsumed('public')
       if self.Peak == 'function':
-         self.parseFunctionDefinition(is_public)
+         self.parseFunctionDefinition()
       elif self.Peak == 'var':
-         self.parseVarDef(is_public)
+         self.parseVarDef()
+         self.Consume(';')
+      else:
+         self.Error('Expected function or variable')
 
    def parseDesignator(self):
       """ A designator designates an object """
       name = self.Consume('ID')
-      return name
+      return name.val
 
    # Type system
    def parseType(self):
@@ -81,19 +80,25 @@
       return d
 
    # Variable declarations:
-   def parseVarDef(self, is_public):
+   def parseVarDef(self):
       self.Consume('var')
-      typ = self.parseType()
-      ID = self.Consume('ID')
-      self.Consume(';')
-      v = Variable(i.name, typename, public=is_public)
-      self.curScope.add(v)
+      t = self.parseType()
+      def parseVar():
+         name = self.Consume('ID')
+         ival = None
+         if self.hasConsumed('='):
+            ival = self.parseExpression()
+         self.sema.actOnVarDef(name.val, name.loc, t, ival)
+      parseVar()
+      while self.hasConsumed(','):
+         parseVar()
 
    # Procedures
-   def parseFunctionDefinition(self, is_pub):
+   def parseFunctionDefinition(self):
       self.Consume('function')
       returntype = self.parseType()
-      procname = self.Consume('ID')
+      pname = self.Consume('ID')
+      self.sema.actOnFuncDef1(pname.val, pname.loc)
       self.Consume('(')
       parameters = []
       if not self.hasConsumed(')'):
@@ -105,9 +110,8 @@
             name = self.Consume('ID')
             parameters.append(astnodes.Parameter(name, typ))
          self.Consume(')')
-      proctyp = astnodes.FunctionType(parameters, returntype)
       body = self.parseCompoundStatement()
-      return astnodes.Procedure(procname, proctyp, body)
+      self.sema.actOnFuncDef2(parameters, returntype, body)
 
    # Statements:
    def parseAssignment(self, lval):
@@ -125,48 +129,37 @@
          self.Consume(')')
       return ProcedureCall(procedure, args)
 
-   def parseLocal(self, t):
-      name = self.Consume('ID')
-      if self.hasConsumed('='):
-         ival = self.parseExpression()
-      else:
-         ival = None
-      self.sema.actOnLocal(t, name, ival)
-   def parseLocalDeclaration(self):
-      self.Consume('var')
-      t = self.parseType()
-      self.parseLocal(t)
-      while self.hasConsumed(','):
-         self.parseLocal(t)
-
    def parseIfStatement(self):
       self.Consume('if')
       self.Consume('(')
       condition = self.parseExpression()
       self.Consume(')')
-      truestatement = self.parseStatement()
+      yes = self.parseCompoundStatement()
       if self.hasConsumed('else'):
-         els = self.parseStatement()
-         return astnodes.IfStatement(condition, truestatement, els)
-      return astnodes.IfStatement(condition, truestatement)
+         no = self.parseCompoundStatement()
+         return astnodes.IfStatement(condition, yes, no)
+      return astnodes.IfStatement(condition, yes)
 
    def parseWhileStatement(self):
       self.Consume('while')
       self.Consume('(')
       condition = self.parseExpression()
       self.Consume(')')
-      statements = self.parseStatement()
+      statements = self.parseCompoundStatement()
+      return astnodes.WhileStatement(condition, statements)
+
    def parseReturnStatement(self):
       self.Consume('return')
       expr = self.parseExpression()
+      return astnodes.ReturnStatement(expr)
 
    def parseCompoundStatement(self):
-       self.Consume('{')
-       statements = [self.parseStatement()]
-       while self.hasConsumed(';'):
+      self.Consume('{')
+      statements = [self.parseStatement()]
+      while self.hasConsumed(';'):
          statements.append(self.parseStatement())
-       self.Consume('}')
-       return astnodes.CompoundStatement(statements)
+      self.Consume('}')
+      return astnodes.CompoundStatement(statements)
 
    def parseStatement(self):
       # Determine statement type based on the pending token:
@@ -177,11 +170,10 @@
       elif self.Peak == '{':
          return self.parseCompoundStatement()
       elif self.Peak == 'var':
-         return self.parseLocalDeclaration()
+         return self.parseVarDef()
       elif self.Peak == 'return':
          return self.parseReturnStatement()
       elif self.Peak == 'ID':
-         # Assignment or procedure call
          designator = self.parseDesignator()
          if self.Peak == '(':
             return self.parseProcedureCall(designator)
@@ -199,7 +191,7 @@
          return e
       elif self.Peak == 'NUMBER':
          val = self.Consume('NUMBER')
-         return astnodes.Constant(val, val)
+         return self.sema.actOnNumber(val.val, val.loc)
       elif self.Peak == 'ID':
          d = self.parseDesignator()
          return d
@@ -212,6 +204,6 @@
          rhs = self.parsePrimary()
          while self.PeakPrec > op_prec:
             rhs = self.parseBinopRhs(rhs, self.PeakPrec)
-         lhs = astnodes.Binop(lhs, op, rhs)
+         lhs = self.sema.actOnBinop(lhs, op.typ, rhs, op.loc)
       return lhs
 
--- a/python/c3/semantics.py	Fri Mar 01 10:24:01 2013 +0100
+++ b/python/c3/semantics.py	Fri Mar 01 11:43:52 2013 +0100
@@ -5,6 +5,8 @@
    def __init__(self, parent=None):
       self.symbols = {}
       self.parent = parent
+   def __iter__(self):
+      return iter(self.symbols.values())
    def getType(self, name):
       t = self.getSymbol(name)
       print(t)
@@ -39,11 +41,28 @@
       self.mod.loc = loc
       self.mod.scope = self.curScope = Scope()
       createBuiltins(self.curScope)
-   def handleBinop(self, lhs, op, rhs):
-      pass
-   def actOnLocal(self, t, name, ival):
-      s = astnodes.Variable(name, t, False)
+   def actOnBinop(self, lhs, op, rhs, loc):
+      bo = astnodes.Binop(lhs, op, rhs)
+      bo.loc = loc
+      return bo
+   def actOnNumber(self, num, loc):
+      n = astnodes.Constant(num)
+      n.loc = loc
+      return n
+   def actOnVarDef(self, name, loc, t, ival):
+      s = astnodes.Variable(name, t)
+      s.loc = loc
       self.curScope.addSymbol(s)
+   def actOnFuncDef1(self, name, loc):
+      self.curFunc = astnodes.Procedure(name)
+      self.curFunc.loc = loc
+      self.curScope.addSymbol(self.curFunc)
+      self.curScope = self.curFunc.scope = Scope(self.curScope)
+   def actOnFuncDef2(self, parameters, returntype, body):
+      self.curFunc.body = body
+      self.curFunc.typ = astnodes.FunctionType(parameters, returntype)
+      self.curFunc = None
+      self.curScope = self.curScope.parent
    def actOnType(self, tok):
       # Try to lookup type, in case of failure return void
       pass
--- a/python/testc3.py	Fri Mar 01 10:24:01 2013 +0100
+++ b/python/testc3.py	Fri Mar 01 11:43:52 2013 +0100
@@ -1,10 +1,14 @@
 import c3.parser, c3.semantics
 from ppci.errors import printError, Diagnostics
+import time
 
 testsrc = """
 package test;
 
-public function void test1() 
+var u32 a ;
+var u32 c, d;
+
+function void test1() 
 {
     var u32 b;
     var int a = 10;
@@ -18,20 +22,31 @@
     }
 }
 
-public function int t2(u32 a, u32 b)
+function int t2(u32 a, u32 b)
 {
    return a + b;
    a = 2
 }
 
+function int t2(u32 a, u32 b)
+{
+   return a + b;
+   a = 2 + 33 - 1;
+   a = a - 2
+}
+
 """
 
-def printAst(ast):
-   print(ast)
+def printAst(ast, indent=''):
+   print(indent + str(ast))
+   if isinstance(ast, c3.astnodes.Package):
+      for s in ast.scope:
+         printAst(s, indent + '  ')
+   if isinstance(ast, c3.astnodes.Procedure):
+      for s in ast.scope:
+         printAst(s, indent + '  ')
    for c in ast.getChildren():
-      printAst(c)
-   if isinstance(ast, c3.astnodes.Package):
-      print('PACK', ast.scope)
+      printAst(c, indent + '  ')
 
 def do():
    print('[0] source:')
@@ -40,8 +55,10 @@
    diag = Diagnostics()
    sema = c3.semantics.Semantics(diag)
    p = c3.parser.Parser(sema, diag)
-   
+   t1 = time.time()
    p.parseSource(testsrc)
+   t2 = time.time() 
+   print('parsetime: {0} [s]'.format(t2 - t1))
 
    for d in diag.diags:
       print('ERROR:', d)