changeset 44:495188f9078e new_gen

Big update - Moving towards a better, more seperated parser The parser no loner creates the AST directly, but through callbacks(actions). This means the parser can be run with a different set of actions that do something else. The parser is not back to full strength yet, the main thing missing is the various statements and structs. Also added a SmallArray that uses the stack only until a given size is exceeded, after which the array is copied unto the heap.
author Anders Halager <halager@gmail.com>
date Wed, 23 Apr 2008 00:57:45 +0200
parents a712c530b7cc
children 9bc660cbdbec
files ast/Decl.d ast/Exp.d ast/Stmt.d basic/SmallArray.d dang/compiler.d gen/LLVMGen.d lexer/Token.d parser/Action.d parser/Parser.d sema/SymbolTableBuilder.d sema/Visitor.d
diffstat 11 files changed, 583 insertions(+), 369 deletions(-) [+]
line wrap: on
line diff
--- a/ast/Decl.d	Tue Apr 22 22:31:39 2008 +0200
+++ b/ast/Decl.d	Wed Apr 23 00:57:45 2008 +0200
@@ -42,14 +42,21 @@
 
 class FuncDecl : Decl
 {
-    this(Identifier type, Identifier identifier, 
-            VarDecl[] funcArgs, Stmt[] statements)
+    this(Identifier type, Identifier identifier)
     {
         super(DeclType.FuncDecl);
         this.type = type;
         this.identifier = identifier;
-        this.funcArgs = funcArgs;
-        this.statements = statements;
+    }
+
+    void addParam(Identifier type, Identifier name)
+    {
+        funcArgs ~= new VarDecl(type, name, null);
+    }
+
+    void setBody(CompoundStatement stmts)
+    {
+        statements = stmts.statements;
     }
 
     Identifier type, identifier;
--- a/ast/Exp.d	Tue Apr 22 22:31:39 2008 +0200
+++ b/ast/Exp.d	Wed Apr 23 00:57:45 2008 +0200
@@ -60,10 +60,12 @@
     public enum Operator
     {
         Eq, Ne,
+
         Lt, Le,
         Gt, Ge,
-        Mul, Div,
+
         Add, Sub,
+        Mul, Div, Mod,
     }
 
     this(Operator op, Exp left, Exp right)
--- a/ast/Stmt.d	Tue Apr 22 22:31:39 2008 +0200
+++ b/ast/Stmt.d	Wed Apr 23 00:57:45 2008 +0200
@@ -12,6 +12,7 @@
 enum StmtType
 {
     Stmt,
+    Compound,
     Decl,
     Exp,
     Return,
@@ -31,6 +32,17 @@
     Scope env;
 }
 
+class CompoundStatement : Stmt
+{
+    this(Stmt[] stmts)
+    {
+        super(StmtType.Compound);
+        this.statements = stmts;
+    }
+
+    Stmt[] statements;
+}
+
 class ReturnStmt : Stmt
 {
     this()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/basic/SmallArray.d	Wed Apr 23 00:57:45 2008 +0200
@@ -0,0 +1,106 @@
+module basic.SmallArray;
+
+/**
+  This struct acts like a normal dynamic array, with one difference.
+  A size is given, which is how many elements are preallocated on the stack.
+
+  Example:
+  --------
+  SmallArray!(float, 4) array;
+  array ~= 1.0;
+  array ~= 2.0;
+  array ~= 3.0;
+  float[] three_floats = array[0 .. 3];
+  // The slice gives a reference to the stack, remember to .dup
+  array ~= 4.0;
+  // not using the heap yet, but after the next line all values will have been
+  // copied to the heap.
+  array ~= 5.0;
+  --------
+
+  Compared to a normal dynamic array there is 8 bytes overhead (on 32 bit cpus)
+  and ofcourse size * T.sizeof bytes for the stack allocated array.
+ */
+struct SmallArray(T, ubyte size = 8)
+{
+    T[] opSlice(size_t low, size_t high)
+    {
+        assert(high <= len && low <= high, "Array index out of range");
+        return ptr[low .. high];
+    }
+
+    T[] opSlice()
+    {
+        return ptr[0 .. len].dup;
+    }
+    alias opSlice unsafe;
+
+    T[] safe()
+    {
+        if (len <= size)
+            return static_array[0 .. len].dup;
+        return array[0 .. len].dup;
+    }
+
+    T[] opSliceAssign(T val, size_t low, size_t high)
+    {
+        assert(high <= len && low <= high, "Array index out of range");
+        return ptr[low .. high] = val;
+    }
+
+    T[] opSliceAssign(T val)
+    {
+        return ptr[0 .. len] = val;
+    }
+
+    T opIndex(size_t index)
+    {
+        assert(index < len, "Array index out of range");
+        return ptr[index];
+    }
+
+    T opIndexAssign(T val, size_t index)
+    {
+        assert(index < len, "Array index out of range");
+        return ptr[index] = val;
+    }
+
+    void opCatAssign(T val)
+    {
+        if (len < size)
+        {
+            ptr = static_array.ptr;
+            static_array[len] = val;
+        }
+        else if (len == size)
+        {
+            T[] tmp = static_array[].dup;
+            array = tmp;
+            array ~= val;
+            ptr = array.ptr;
+        }
+        else
+            array ~= val;
+
+        ++len;
+    }
+
+    size_t length() { return len; }
+
+    static SmallArray opCall()
+    {
+        SmallArray array;
+        array.ptr = array.static_array.ptr;
+        return array;
+    }
+
+private:
+    T* ptr;
+    size_t len;
+    union
+    {
+        T[] array;
+        T[size] static_array;
+    }
+}
+
--- a/dang/compiler.d	Tue Apr 22 22:31:39 2008 +0200
+++ b/dang/compiler.d	Wed Apr 23 00:57:45 2008 +0200
@@ -174,7 +174,7 @@
         preParse(lexer);
 
         auto parser = new Parser;
-        auto decls = parser.parse(lexer);
+        auto decls = cast(Decl[])parser.parse(lexer);
 
         (new SymbolTableBuilder).visit(decls);
         (new Declarations).visit(decls);
--- a/gen/LLVMGen.d	Tue Apr 22 22:31:39 2008 +0200
+++ b/gen/LLVMGen.d	Wed Apr 23 00:57:45 2008 +0200
@@ -285,6 +285,11 @@
     {
         switch(stmt.stmtType)
         {
+            case StmtType.Compound:
+                auto stmts = cast(CompoundStatement)stmt;
+                foreach (s; stmts.statements)
+                    genStmt(s);
+                break;
             case StmtType.Return:
                 auto ret = cast(ReturnStmt)stmt;
                 auto sym = stmt.env.parentFunction();
--- a/lexer/Token.d	Tue Apr 22 22:31:39 2008 +0200
+++ b/lexer/Token.d	Wed Apr 23 00:57:45 2008 +0200
@@ -56,6 +56,23 @@
     {
         return location.get(length);
     }
+
+    /**
+      Returns true if the type of this token is a basic type (int, float, ...).
+      Void is included, although a void in it self is not really a type.
+     */
+    bool isBasicType()
+    {
+        return type >= Tok.Byte && type <= Tok.Void;
+    }
+
+    /**
+      Just a shortcut to avoid `token.type == Tok.Identifier`.
+     */
+    bool isIdentifier()
+    {
+        return type == Tok.Identifier;
+    }
 }
 
 /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/parser/Action.d	Wed Apr 23 00:57:45 2008 +0200
@@ -0,0 +1,267 @@
+module parser.Action;
+
+import lexer.Token;
+
+import ast.Exp,
+       ast.Stmt,
+       ast.Decl;
+
+import misc.Error;
+
+import tango.io.Stdout,
+       Integer = tango.text.convert.Integer;
+
+/**
+  Used to indicate what type of operator is used in a given binary expression
+  (and unary expressions?)
+ */
+public enum Operator
+{
+    Eq, Ne,
+
+    Lt, Le,
+    Gt, Ge,
+
+    Add, Sub,
+    Mul, Div, Mod,
+}
+
+
+struct Id
+{
+    Token tok;
+
+    char[] toString()
+    {
+        return tok.get;
+    }
+}
+
+/**
+  All methods are optional.
+
+Warning: Interface is not stable yet. Use the `override` keyword in all classes
+            inheriting from this to get warning if the interface changes.
+ */
+abstract class Action
+{
+    /**
+      A few aliases to indicate what methods should be dealing with the same
+      types.
+
+      Not typesafe, and not using typedef because users would need a lot of
+      casts (and base type would be void*, so no possibility to synchronize,
+      print etc.)
+     */
+    alias Object ExprT;
+    alias Object StmtT; /// ditto
+    alias Object DeclT; /// ditto
+
+    // -- Declarations --
+
+    /**
+      Either we should have one case that handles a lot of things, or we should
+      have a lot of separate cases.
+      As an example, this method could handle the params in `int f(int, int)`
+      as well as handling `int x` at both top-level, in classes and in methods.
+      
+      The other solution is an addParamToFunc or similar.
+     */
+    DeclT actOnDeclarator(ref Id type, ref Id name, ExprT init)
+    {
+        return null;
+    }
+
+    /**
+      Add an initialization expression to a previously created decl.
+
+      Used for default values on function params and for values to local
+      variables.
+     */
+    void addInitToDeclarator(DeclT decl, ExprT exp)
+    {
+    }
+
+    /**
+      Called at the start of a function, doesn't get a lot of info - that is
+      added later on, through addFuncArg and actOnEndOfFunction.
+     */
+    DeclT actOnStartOfFunctionDef(ref Id type, ref Id name)
+    {
+        return null;
+    }
+
+    /**
+      Add a new parameter to the function func.
+     */
+    void addFuncArg(DeclT func, Id type, Id name)
+    {
+    }
+
+    /**
+      Finish off the function, by giving it the body (a single statement, so
+      you probably want some sort of compound statement)
+     */
+    DeclT actOnEndOfFunction(DeclT func, StmtT stmts)
+    {
+        return func;
+    }
+
+    // -- Statements --
+
+    /**
+      Called after parsing a function/while/for/whatever body.
+
+      Note that stmts is to be considered temporary, it might point into the
+      stack and needs to be copied before saving.
+     */
+    StmtT actOnCompoundStmt(ref Token left, ref Token right, StmtT[] stmts)
+    {
+        return null;
+    }
+
+    /**
+      Called after parsing return statements.
+
+      loc is the return token.
+     */
+    StmtT actOnReturnStmt(ref Token loc, ExprT exp)
+    {
+        return null;
+    }
+
+    StmtT actOnStartOfSwitchStmt()
+    {
+        return null;
+    }
+
+    void actOnCaseStmt()
+    {
+    }
+
+    void actOnDefaultStmt()
+    {
+    }
+
+    StmtT actOnFinishSwitchStmt(StmtT sw)
+    {
+        return sw;
+    }
+
+    // -- Expressions --
+
+    /**
+      A single numerical constant -- this can be absolutely any kind of number.
+      Integers, floats, hex, octal, binary, imaginary and so on.
+     */
+    ExprT actOnNumericConstant(Token op)
+    {
+        return null;
+    }
+
+    /**
+      This is called when identifiers are used in expressions.
+     */
+    ExprT actOnIdentifierExp(Id id)
+    {
+        return null;
+    }
+
+    /**
+      Unary operator.
+     */
+    ExprT actOnUnaryOp(Token op, ExprT operand)
+    {
+        return null;
+    }
+
+    /**
+      Binary operator.
+     */
+    ExprT actOnBinaryOp(Operator op, ExprT l, ExprT r)
+    {
+        return null;
+    }
+
+    /**
+      Called when using the 'dot' operator.
+      The left hand side can be any expression, but its only possible to look
+      up an identifier.
+     */
+    ExprT actOnMemberReference(ExprT lhs, Location op, Id member)
+    {
+        return null;
+    }
+}
+
+/**
+  This class implements the default actions for Dang, by building up an AST
+  with the data needed in a compiler.
+ */
+class AstAction : Action
+{
+    override DeclT actOnDeclarator(ref Id type, ref Id id, ExprT init)
+    {
+        Exp exp = cast(Exp)init;
+        return new VarDecl(new Identifier(type.tok), new Identifier(id.tok), exp);
+    }
+
+    override DeclT actOnStartOfFunctionDef(ref Id type, ref Id name)
+    {
+        return new FuncDecl(new Identifier(type.tok), new Identifier(name.tok));
+    }
+
+    override void addFuncArg(DeclT func, Id type, Id name)
+    {
+        FuncDecl fd = cast(FuncDecl)func;
+        fd.addParam(new Identifier(type.tok), new Identifier(name.tok));
+    }
+
+    override DeclT actOnEndOfFunction(DeclT func, StmtT stmts)
+    {
+        FuncDecl fd = cast(FuncDecl)func;
+        fd.setBody(cast(CompoundStatement)stmts);
+        return fd;
+    }
+
+    override StmtT actOnCompoundStmt(ref Token l, ref Token r, StmtT[] stmts)
+    {
+        StmtT[] array = stmts.dup;
+        Stmt[] statements = cast(Stmt[])array;
+        Stdout(statements).newline;
+        return new CompoundStatement(cast(Stmt[])array);
+    }
+
+    override StmtT actOnReturnStmt(ref Token loc, ExprT exp)
+    {
+        Exp e = cast(Exp)exp;
+        auto res = new ReturnStmt;
+        res.exp = e;
+        return res;
+    }
+
+    override ExprT actOnNumericConstant(Token c)
+    {
+        return new IntegerLit(c);
+    }
+
+    override ExprT actOnIdentifierExp(Id id)
+    {
+        return new Identifier(id.tok);
+    }
+
+    override ExprT actOnBinaryOp(Operator op, ExprT l, ExprT r)
+    {
+        Exp left = cast(Exp)l;
+        Exp right = cast(Exp)r;
+        return new BinaryExp(cast(BinaryExp.Operator)op, left, right);
+    }
+
+    override ExprT actOnUnaryOp(Token op, ExprT operand)
+    {
+        Exp target = cast(Exp)operand;
+        // can only be -x for now
+        return new NegateExp(target);
+    }
+}
+
--- a/parser/Parser.d	Tue Apr 22 22:31:39 2008 +0200
+++ b/parser/Parser.d	Wed Apr 23 00:57:45 2008 +0200
@@ -3,30 +3,33 @@
 import lexer.Lexer,
        lexer.Token;
 
-import ast.Exp,
-       ast.Stmt,
-       ast.Decl;
+import parser.Action;
 
 import misc.Error;
 
+import basic.SmallArray;
+
 import tango.io.Stdout,
        Integer = tango.text.convert.Integer;
 
 class Parser
 {
+    Action action;
+    alias Object Exp;
+    alias Object Stmt;
+    alias Object Decl;
 
 public:
     Decl[] parse(Lexer lexer)
     {
         this.lexer = lexer;
+        action = new AstAction;
 
 
         Decl[] declarations;
 
         while(lexer.peek.type != Tok.EOF)
-        {
-            declarations ~= parseRootDecl;
-        }
+            declarations ~= parseRootDecl();
 
         return declarations;
     }
@@ -35,147 +38,42 @@
     {
         Token t = lexer.peek;
 
-        switch(t.type)
+        if (t.isBasicType || t.isIdentifier)
         {
-            case Tok.Byte,  Tok.Ubyte,
-                 Tok.Short, Tok.Ushort,
-                 Tok.Int,   Tok.Uint,
-                 Tok.Long,  Tok.Ulong,
-                 Tok.Float, Tok.Double,
-                 Tok.Bool,
-                 Tok.Void,
-                 Tok.Identifier:
-                Identifier type = new Identifier(t);
-
-                Token iden = lexer.peek(1);
-
-                switch(iden.type)
-                {
-                    case Tok.Identifier:
-                        Identifier identifier = new Identifier(iden);
-                        Token p = lexer.peek(2);
-                        switch(p.type)
-                        {
-                            case Tok.OpenParentheses:
-                                lexer.next; lexer.next;
-                                return parseFunc(type, identifier);
-                            case Tok.Seperator:
-                                lexer.next; lexer.next;
-                                require(Tok.Seperator);
-                                return new VarDecl(type, identifier, null);
-                            case Tok.Assign:
-                                lexer.next; lexer.next;
-                                lexer.next();
-                                auto exp = parseExpression();
-                                require(Tok.Seperator);
-                                return new VarDecl(type, identifier, exp);
-                            default:
-                                char[] c = p.getType;
-                                throw error(__LINE__, UnexpectedTokMulti)
-                                    .tok(p)
-                                    .arg(c)
-                                    .arg(Tok.OpenParentheses, Tok.Seperator, Tok.Assign);
-                        }
-                        break;
-                    default:
-                        char[] c = t.getType;
-                        throw error(__LINE__, UnexpectedTok).tok(iden).arg(c);
-                }
-                break;
-            case Tok.Struct:
-                lexer.next;
-                Token iden = lexer.next;
-                switch(iden.type)
-                {
-                    case Tok.Identifier:
-                        Identifier identifier = new Identifier(iden);
-                        return new StructDecl (identifier, parseStruct());
-                    default:
-                        throw error(__LINE__, "Expected struct identifier, but got %0").arg(iden.getType);
-                }
-            case Tok.EOF:
-                return null;
-            default:
-                char[] c = t.getType;
-                throw error(__LINE__, UnexpectedTok).tok(t).arg(c);
+            Id type = Id(lexer.next);
+            Id iden = Id(require(Tok.Identifier));
+            Token next = lexer.peek();
+            if (next.type == Tok.Seperator)
+            {
+                Token sep = lexer.next();
+                return action.actOnDeclarator(type, iden, null);
+            }
+            else if (next.type == Tok.Assign)
+            {
+                Token assign = lexer.next();
+                Exp exp = parseExpression();
+                require(Tok.Seperator);
+                return action.actOnDeclarator(type, iden, exp);
+            }
+            else if (next.type == Tok.OpenParentheses)
+                return parseFunc(type, iden);
+            else
+                throw error(__LINE__, PE.UnexpectedTok)
+                    .tok(next)
+                    .arg(next.getType);
         }
+        else if (t.type == Tok.Struct)
+        {
+        }
+        char[] c = t.getType;
+        throw error(__LINE__, PE.UnexpectedTok).tok(t).arg(c);
     }
 
-    Decl parseDecl()
-    {
-        Token t = lexer.peek;
-
-        switch(t.type)
-        {
-            case Tok.Byte,  Tok.Ubyte,
-                 Tok.Short, Tok.Ushort,
-                 Tok.Int,   Tok.Uint,
-                 Tok.Long,  Tok.Ulong,
-                 Tok.Float, Tok.Double,
-                 Tok.Bool,
-                 Tok.Void,
-                 Tok.Identifier:
-                Identifier type = new Identifier(t);
-
-                Token iden = lexer.peek(1);
+    /**
+      Parse statements.
 
-                switch(iden.type)
-                {
-                    case Tok.Identifier:
-                        Identifier identifier = new Identifier(iden);
-                        Token p = lexer.peek(2);
-                        switch(p.type)
-                        {
-                            case Tok.OpenParentheses:
-                                lexer.next; lexer.next;
-                                return parseFunc(type, identifier);
-                            case Tok.Seperator:
-                                lexer.next; lexer.next;
-                                require(Tok.Seperator);
-                                return new VarDecl(type, identifier, null);
-                            case Tok.Assign:
-                                lexer.next; lexer.next;
-                                lexer.next();
-                                auto exp = parseExpression();
-                                require(Tok.Seperator);
-                                return new VarDecl(type, identifier, exp);
-                            default:
-                                char[] c = p.getType;
-                                throw error(__LINE__, UnexpectedTokMulti)
-                                    .tok(p)
-                                    .arg(c)
-                                    .arg(Tok.OpenParentheses, Tok.Seperator, Tok.Assign);
-                        }
-                        break;
-                    default:
-                        char[] c = iden.getType;
-                        throw error(__LINE__, UnexpectedTokSingle)
-                            .tok(iden)
-                            .arg(c)
-                            .arg(Tok.Identifier);
-                }
-                break;
-            case Tok.EOF:
-                return null;
-            default:
-                char[] c = t.getType;
-                throw error(__LINE__, UnexpectedTok).arg(c);
-        }
-    }
-
-    VarDecl[] parseStruct()
-    {
-        VarDecl[] varDecls;
-        require(Tok.OpenBrace);
-        while(lexer.peek.type != Tok.CloseBrace)
-        {
-            varDecls ~= cast(VarDecl)parseDecl;
-        }
-
-        require(Tok.CloseBrace);
-        return varDecls;
-    }
-
+      This is the place to attack!
+     */
     Stmt parseStatement()
     {
         Token t = lexer.peek;
@@ -183,212 +81,107 @@
         switch(t.type)
         {
             case Tok.Return:
-                lexer.next;
-                auto ret = new ReturnStmt();
-                if (!skip(Tok.Seperator))
-                {
-                    ret.exp = parseExpression();
-                    require(Tok.Seperator);
-                }
-                return ret;
+                Token ret = lexer.next;
+                Exp exp = parseExpression();
+                require(Tok.Seperator);
+                return action.actOnReturnStmt(ret, exp);
 
             case Tok.If:
-                lexer.next;
-                require(Tok.OpenParentheses);
-                auto condition = parseExpression();
-                require(Tok.CloseParentheses);
-
-                auto then_body = parseBlockOrSingleStmt();
-
-                Stmt[] else_body;
-                if (lexer.peek.type == Tok.Else)
-                {
-                    lexer.next;
-                    else_body = parseBlockOrSingleStmt();
-                }
-
-                return new IfStmt(condition, then_body, else_body);
+                return null;
 
             case Tok.While:
-                lexer.next;
-                require(Tok.OpenParentheses);
-                auto condition = parseExpression();
-                require(Tok.CloseParentheses);
-                return new WhileStmt(condition, parseBlockOrSingleStmt());
+                return null;
 
             case Tok.Identifier:
-                Token n = lexer.peek(1);
-                switch(n.type)
-                {
-                    case Tok.Dot:
-                        Exp iden = parseExpIdentifier(new Identifier(lexer.next));
-                        switch(lexer.peek.type)
-                        {
-                            case Tok.Assign:
-                                lexer.next;
-                                auto stmt = new ExpStmt(new AssignExp(iden , parseExpression()));
-                                require(Tok.Seperator);
-                                return stmt;
-                                break;
-                        }
-                    case Tok.Assign:
-                        lexer.next;
-                        lexer.next;
-                        auto stmt = new ExpStmt(new AssignExp(new Identifier(t), parseExpression()));
-                        require(Tok.Seperator);
-                        return stmt;
-                        break;
-                    case Tok.Identifier:
-                        auto decl = new DeclStmt(parseDecl());
-                        return decl;
-
-                    default:
-                        auto e = new ExpStmt(parseExpression());
-                        require(Tok.Seperator);
-                        return e;
-
-                }
-                break;
+                return null;
 
             case Tok.Switch:
-                lexer.next;
-                require(Tok.OpenParentheses);
-                auto target = parseExpression();
-                auto res = new SwitchStmt(target);
-                require(Tok.CloseParentheses);
-                require(Tok.OpenBrace);
-                while (true)
-                {
-                    Stmt[] statements;
-                    if (skip(Tok.Default))
-                    {
-                        require(Tok.Colon);
-                        statements.length = 0;
-                        while (lexer.peek.type != Tok.Case
-                                && lexer.peek.type != Tok.Default
-                                && lexer.peek.type != Tok.CloseBrace)
-                            statements ~= parseStatement();
-                        res.setDefault(statements);
-                        continue;
-                    }
-
-                    Token _case = lexer.peek;
-                    if (_case.type != Tok.Case)
-                        break;
-                    lexer.next();
-
-                    IntegerLit[] literals;
-                    do
-                    {
-                        Exp e = parseExpression();
-                        IntegerLit lit = cast(IntegerLit)e;
-                        if (lit is null)
-                            throw error(__LINE__, CaseValueMustBeInt)
-                                .tok(_case);
-
-                        literals ~= lit;
-                    }
-                    while (skip(Tok.Comma));
-                    require(Tok.Colon);
-
-                    while (lexer.peek.type != Tok.Case
-                            && lexer.peek.type != Tok.Default
-                            && lexer.peek.type != Tok.CloseBrace)
-                        statements ~= parseStatement();
-
-                    res.addCase(literals, statements);
-
-                    if (lexer.peek.type == Tok.CloseBrace)
-                        break;
-                }
-                require(Tok.CloseBrace);
-                return res;
+                return null;
 
             default:
-                auto decl = new DeclStmt(parseDecl());
-                //require(Tok.Seperator);
-                return decl;
+                return null;
         }
-        return new Stmt();
+        error(__LINE__, "").tok(t);
+        return null;
     }
 
-    FuncDecl parseFunc(Identifier type, Identifier identifier)
+    /**
+      Parses a function/method given the already parsed
+     */
+    Decl parseFunc(ref Id type, ref Id name)
     {
-        VarDecl[] funcArgs = parseFuncArgs();
-
-        lexer.next; // Remove the "{"
+        Decl func = action.actOnStartOfFunctionDef(type, name);
+        parseFuncArgs(func);
 
-        Stmt[] statements;
+        Stmt stmt = parseCompoundStatement();
 
-        while(lexer.peek.type != Tok.CloseBrace)
-            statements ~= parseStatement();
-
-        lexer.next; // Remove "}"
-
-        return new FuncDecl(type, identifier, funcArgs, statements);
+        action.actOnEndOfFunction(func, stmt);
+        return func;
     }
 
-    VarDecl[] parseFuncArgs()
+    /**
+      Parse the function arguments, assumes current token is (.
+
+      Both the intitial paren and the ending paren is consumed.
+     */
+    void parseFuncArgs(Decl func)
     {
-        lexer.next; // Remove the "(" token.
-
-        VarDecl[] funcArgs;
+        require(Tok.OpenParentheses); // Remove the "(" token.
 
         while(lexer.peek.type != Tok.CloseParentheses)
         {
-            auto t = parseType;
-            auto i = parseIdentifier;
-            funcArgs ~= new VarDecl(t, i);
+            auto t = parseType();
+            auto i = parseIdentifier();
+            action.addFuncArg(func, t, i);
 
             if(lexer.peek.type == Tok.Comma)
                 lexer.next;
         }
 
-        lexer.next; // Remove the ")"
-
-        return funcArgs;
+        require(Tok.CloseParentheses); // Remove the ")"
     }
 
-    Identifier parseIdentifier()
+    /**
+      Parses a function-body or similar, expects { to be current token.
+      
+      Will consume both the starting { and ending }
+     */
+    Stmt parseCompoundStatement()
     {
-        Token identifier = lexer.next;
-
-        switch(identifier.type)
-        {
-            case Tok.Identifier:
-                return new Identifier(identifier);
-                break;
-            default:
-                throw error(__LINE__, "Unexpected token in Identifier parsing. Got %0")
-                    .arg(identifier.getType)
-                    .tok(identifier);
-        }
+        Token lbrace = require(Tok.OpenBrace);
+        SmallArray!(Stmt, 32) stmts; // Try to use the stack only
+        while (lexer.peek.type != Tok.CloseBrace)
+            stmts ~= parseStatement();
+        Token rbrace = require(Tok.CloseBrace);
+        return action.actOnCompoundStmt(lbrace, rbrace, stmts.unsafe());
     }
 
-    Identifier parseType()
+    Id parseIdentifier()
+    {
+        Token tok = lexer.next;
+
+        if (tok.type is Tok.Identifier)
+            return Id(tok);
+
+        throw error(__LINE__, PE.UnexpectedTokSingle)
+            .arg(tok.getType)
+            .arg(Tok.Identifier)
+            .tok(tok);
+    }
+
+    Id parseType()
     {
         Token type = lexer.next;
 
-        switch(type.type)
-        {
-            case Tok.Byte,  Tok.Ubyte,
-                 Tok.Short, Tok.Ushort,
-                 Tok.Int,   Tok.Uint,
-                 Tok.Long,  Tok.Ulong,
-                 Tok.Float, Tok.Double,
-                 Tok.Bool,
-                 Tok.Void,
-                 Tok.Identifier:
-                return new Identifier(type);
-                break;
-            default:
-                char[] c = type.getType;
-                error(__LINE__, "Unexpected token in Type parsing. Got %0").arg(c);
-        }
+        if (type.isBasicType || type.type == Tok.Identifier)
+            return Id(type);
+
+        char[] c = type.getType;
+        error(__LINE__, "Unexpected token in Type parsing. Got %0").arg(c);
     }
 
+private:
     // -- Expression parsing -- //
-private:
     Exp parseExpIdentifier(Exp target)
     {
         switch(lexer.peek.type)
@@ -397,12 +190,13 @@
                 switch(lexer.peek(1).type)
                 {
                     case Tok.Identifier:
-                        lexer.next;
-                        return parseExpIdentifier(
-                                new MemberLookup(target, new Identifier(lexer.next)));
+                        Token op = lexer.next;
+                        Id member = Id(lexer.next);
+                        Exp exp = action.actOnMemberReference(target, op.location, member);
+                        return parseExpIdentifier(exp);
                     default:
                         Token t = lexer.peek(1);
-                        throw error(__LINE__, "Expected identifier after '.'", &t);
+                        throw error(__LINE__, "Expected identifier after '.'").tok(t);
                 }
             default:
                 return target;
@@ -419,7 +213,7 @@
             lexer.next();
             int q = op.leftAssoc? 1 + op.prec : op.prec;
             auto exp2 = parseExpression(q);
-            exp = new BinaryExp(op.operator, exp, exp2);
+            exp = action.actOnBinaryOp(op.operator, exp, exp2);
             next = lexer.peek();
         }
 
@@ -430,7 +224,7 @@
     {
         Token next = lexer.next();
         if (auto op = unary(next.type))
-            return new NegateExp(parseExpression(op.prec));
+            return action.actOnUnaryOp(next, parseExpression(op.prec));
         else if (next.type == Tok.OpenParentheses)
         {
             auto e = parseExpression(0);
@@ -439,9 +233,11 @@
         }
         else if (next.type == Tok.Identifier)
         {
-            Exp iden = parseExpIdentifier(new Identifier(next));
+            Exp value = action.actOnIdentifierExp(Id(next));
+            Exp iden = parseExpIdentifier(value);
             switch(lexer.peek.type)
             {
+                // TODO: Function calls are parsed but ignored
                 case Tok.OpenParentheses:
                     lexer.next;
                     Exp[] args;
@@ -455,42 +251,26 @@
                     }
 
                     lexer.next();
-                    return new CallExp(iden, args);
+                    return null;//new CallExp(iden, args);
 
                 default:
                     return iden;
             }
         }
         else if (next.type == Tok.Integer)
-            return new IntegerLit(next);
+            return action.actOnNumericConstant(next);
 
         Stdout.formatln("{}", next.getType);
         assert(0, "Should not happen");
     }
 
-    private Stmt[] parseBlockOrSingleStmt()
-    {
-        Stmt[] stmts;
-        if (lexer.peek.type == Tok.OpenBrace)
-        {
-            lexer.next;
-            while(lexer.peek.type != Tok.CloseBrace)
-                stmts ~= parseStatement();
-            lexer.next;
-        }
-        else
-            stmts ~= parseStatement();
-
-        return stmts;
-    }
-
     struct UnOp
     {
         Tok tokenType;
         int prec;
     }
 
-    static UnOp[] _unary = [{Tok.Sub, 4}];
+    static const UnOp[] _unary = [{Tok.Sub, 4}];
     UnOp* unary(Tok t)
     {
         foreach (ref op; _unary)
@@ -504,23 +284,24 @@
         Tok tokenType;
         int prec;
         bool leftAssoc;
-        BinaryExp.Operator operator;
+        Operator operator;
     }
 
-    static BinOp[] _binary =
+    static const BinOp[] _binary =
     [
-        {Tok.Eq,        2, true, BinaryExp.Operator.Eq},
-        {Tok.Ne,        2, true, BinaryExp.Operator.Ne},
-        {Tok.Lt,        2, true, BinaryExp.Operator.Lt},
-        {Tok.Le,        2, true, BinaryExp.Operator.Le},
-        {Tok.Gt,        2, true, BinaryExp.Operator.Gt},
-        {Tok.Ge,        2, true, BinaryExp.Operator.Ge},
+        {Tok.Eq,        2, true, Operator.Eq},
+        {Tok.Ne,        2, true, Operator.Ne},
 
-        {Tok.Add,       3, true, BinaryExp.Operator.Add},
-        {Tok.Sub,       3, true, BinaryExp.Operator.Sub},
+        {Tok.Lt,        2, true, Operator.Lt},
+        {Tok.Le,        2, true, Operator.Le},
+        {Tok.Gt,        2, true, Operator.Gt},
+        {Tok.Ge,        2, true, Operator.Ge},
 
-        {Tok.Mul,       5, true, BinaryExp.Operator.Mul},
-        {Tok.Div,       5, true, BinaryExp.Operator.Div}
+        {Tok.Add,       3, true, Operator.Add},
+        {Tok.Sub,       3, true, Operator.Sub},
+
+        {Tok.Mul,       5, true, Operator.Mul},
+        {Tok.Div,       5, true, Operator.Div}
     ];
     BinOp* binary(Tok t)
     {
@@ -535,7 +316,7 @@
     Token require(Tok t)
     {
         if (lexer.peek().type != t)
-            throw error(__LINE__, UnexpectedTokSingle)
+            throw error(__LINE__, PE.UnexpectedTokSingle)
                 .arg(lexer.peek.getType)
                 .arg(t);
         return lexer.next();
@@ -549,28 +330,25 @@
         return true;
     }
 
-    Error error(uint line, char[] errMsg, Token* tok = null)
+    Error error(uint line, char[] errMsg)
     {
-        Location loc;
-        if (tok is null)
-            loc = lexer.peek.location;
-        else
-            loc = tok.location;
+        Location loc = lexer.peek.location;
         auto e =
             new Error("Parser.d(" ~ Integer.toString(line) ~ "): " ~errMsg);
             e.loc(loc);
-            if (tok !is null)
-                e.tok(*tok);
             return e;
     }
 
-    static char[]
-        UnexpectedTokMulti = "Unexpected token, got %0 expected one of %1",
-        UnexpectedTokSingle = "Unexpected token, got %0 expected %1",
-        UnexpectedTok = "Unexpected token %0";
+    struct PE
+    {
+        static char[]
+            UnexpectedTokMulti  = "Unexpected token, got %0 expected one of %1",
+            UnexpectedTokSingle = "Unexpected token, got %0 expected %1",
+            UnexpectedTok       = "Unexpected token %0";
 
-    static char[]
-        CaseValueMustBeInt = "Cases can only be integer literals";
+        static char[]
+            CaseValueMustBeInt  = "Cases can only be integer literals";
+    }
 
     Lexer lexer;
 }
--- a/sema/SymbolTableBuilder.d	Tue Apr 22 22:31:39 2008 +0200
+++ b/sema/SymbolTableBuilder.d	Wed Apr 23 00:57:45 2008 +0200
@@ -133,6 +133,14 @@
         pop(sc);
     }
 
+    override void visitCompoundStmt(CompoundStatement s)
+    {
+        s.env = current();
+        auto sc = push();
+        super.visitCompoundStmt(s);
+        pop(sc);
+    }
+
 private:
     Scope[] table;
 
--- a/sema/Visitor.d	Tue Apr 22 22:31:39 2008 +0200
+++ b/sema/Visitor.d	Wed Apr 23 00:57:45 2008 +0200
@@ -43,6 +43,8 @@
         {
             case StmtType.Return:
                 return visitReturnStmt(cast(ReturnStmt)stmt);
+            case StmtType.Compound:
+                return visitCompoundStmt(cast(CompoundStatement)stmt);
             case StmtType.Decl:
                 return visitDeclStmt(cast(DeclStmt)stmt);
             case StmtType.Exp:
@@ -143,6 +145,16 @@
             return StmtT.init;
     }
 
+    StmtT visitCompoundStmt(CompoundStatement c)
+    {
+        foreach (stmt; c.statements)
+            visitStmt(stmt);
+        static if (is(StmtT == void))
+            return;
+        else
+            return StmtT.init;
+    }
+
     StmtT visitIfStmt(IfStmt s)
     {
         visitExp(s.cond);