diff parser/Parser.d @ 1:2168f4cb73f1

First push
author johnsen@johnsen-desktop
date Fri, 18 Apr 2008 02:01:38 +0200
parents
children 2c5a8f4c254a
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/parser/Parser.d	Fri Apr 18 02:01:38 2008 +0200
@@ -0,0 +1,305 @@
+module parser.Parser;
+
+import lexer.Lexer,
+       lexer.Token;
+
+import ast.Exp,
+       ast.Stmt,
+       ast.Decl;
+
+import tango.io.Stdout,
+       Integer = tango.text.convert.Integer;
+
+class Parser
+{
+
+public:
+    Decl[] parse(Lexer lexer)
+    {
+        this.lexer = lexer;
+
+
+        Decl[] declarations;
+
+        while(lexer.peek.type != Tok.EOF)
+        {
+            declarations ~= parseDecl;
+        }
+
+        return declarations;
+    }
+
+    Decl parseDecl()
+    {
+        Token t = lexer.next;
+
+        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.Identifier:
+                Identifier type = new Identifier(t);
+
+                Token iden = lexer.next;
+                switch(iden.type)
+                {
+                    case Tok.Identifier:
+                        Identifier identifier = new Identifier(iden);
+                        Token p = lexer.peek();
+                        switch(p.type)
+                        {
+                            case Tok.OpenParentheses:
+                                return parseFunc(type, identifier);
+                            case Tok.Seperator:
+                                require(Tok.Seperator);
+                                return new VarDecl(type, identifier, null);
+                            case Tok.Assign:
+                                lexer.next();
+                                auto exp = parseExpression();
+                                require(Tok.Seperator);
+                                return new VarDecl(type, identifier, exp);
+                            default:
+                                char[] c = t.getType;
+                                error("Unexpexted token "~c~" at line "~Integer.toString(__LINE__));
+                        }
+                        break;
+                    default:
+                        char[] c = t.getType;
+                        error("Unexpexted token "~c~" at line "~Integer.toString(__LINE__));
+                }
+                break;
+
+            case Tok.EOF:
+                return null;
+            default:
+                char[] c = t.getType;
+                error("Unexpexted token "~c~" at line "~Integer.toString(__LINE__));
+        }
+    }
+
+    Stmt parseStatement()
+    {
+        Token t = lexer.peek;
+
+        switch(t.type)
+        {
+            case Tok.Return:
+                lexer.next;
+                auto ret = new ReturnStmt();
+                ret.exp = parseExpression();
+                require(Tok.Seperator);
+                return ret;
+            case Tok.Identifier:
+                Token n = lexer.peek(1);
+                switch(n.type)
+                {
+                    case Tok.Assign:
+                        lexer.next;
+                        lexer.next;
+                        auto stmt = new ExpStmt(new AssignExp(new Identifier(t), parseExpression()));
+                        require(Tok.Seperator);
+                        return stmt;
+                        break;
+
+                    default:
+                        auto e = new ExpStmt(parseExpression());
+                        require(Tok.Seperator);
+                        return e;
+
+                }
+                break;
+
+            default:
+                auto decl = new DeclStmt(parseDecl());
+                //require(Tok.Seperator);
+                return decl;
+        }
+        return new Stmt();
+    }
+
+    FuncDecl parseFunc(Identifier type, Identifier identifier)
+    {
+        VarDecl[] funcArgs = parseFuncArgs();
+
+        lexer.next; // Remove the "{"
+
+        Stmt[] statements;
+
+        while(lexer.peek.type != Tok.CloseBrace)
+            statements ~= parseStatement();
+
+        lexer.next; // Remove "}"
+
+        return new FuncDecl(type, identifier, funcArgs, statements);
+    }
+
+    VarDecl[] parseFuncArgs()
+    {
+        lexer.next; // Remove the "(" token.
+
+        VarDecl[] funcArgs;
+
+        while(lexer.peek.type != Tok.CloseParentheses)
+        {
+            funcArgs ~= new VarDecl(parseType, parseIdentifier);
+
+            if(lexer.peek.type == Tok.Comma)
+                lexer.next;
+        }
+
+        lexer.next; // Remove the ")"
+
+        return funcArgs;
+    }
+
+    Identifier parseIdentifier()
+    {
+        Token identifier = lexer.next;
+
+        switch(identifier.type)
+        {
+            case Tok.Identifier:
+                return new Identifier(identifier);
+                break;
+            default:
+                error("Unexpexted token in Identifier parsing");
+        }
+    }
+
+    Identifier 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.Identifier:
+                return new Identifier(type);
+                break;
+            default:
+                char[] c = type.getType;
+                error("Unexpexted token in Type parsing. Got "~c);
+        }
+    }
+
+    // -- Expression parsing -- //
+private:
+    Exp parseExpression(int p = 0)
+    {
+        auto exp = P();
+        Token next = lexer.peek();
+        BinOp* op = null;
+        while ((op = binary(next.type)) != null && op.prec >= p)
+        {
+            lexer.next();
+            int q = op.leftAssoc? 1 + op.prec : op.prec;
+            auto exp2 = parseExpression(q);
+            exp = new BinaryExp(op.operator, exp, exp2);
+            next = lexer.peek();
+        }
+
+        return exp;
+    }
+
+    Exp P()
+    {
+        Token next = lexer.next();
+        if (auto op = unary(next.type))
+            return new NegateExp(parseExpression(op.prec));
+        else if (next.type == Tok.OpenParentheses)
+        {
+            auto e = parseExpression(0);
+            require(Tok.CloseParentheses);
+            return e;
+        }
+        else if (next.type == Tok.Identifier)
+        {
+            switch(lexer.peek.type)
+            {
+                case Tok.OpenParentheses:
+                    lexer.next;
+                    Exp[] args;
+                    while(lexer.peek.type != Tok.CloseParentheses)
+                    {
+                        if(lexer.peek.type == Tok.Comma)
+                        {
+                            lexer.next;
+                        }
+                        args ~= parseExpression();
+                    }
+
+                    lexer.next();
+                    return new CallExp(new Identifier(next), args);
+
+                default:
+                    return new Identifier(next);
+            }
+        }
+        else if (next.type == Tok.Integer)
+            return new IntegerLit(next);
+
+        Stdout.formatln("{}", next.getType);
+        assert(0, "Should not happen");
+    }
+
+    struct UnOp
+    {
+        Tok tokenType;
+        int prec;
+    }
+
+    static UnOp[] _unary = [{Tok.Sub, 4}];
+    UnOp* unary(Tok t)
+    {
+        foreach (ref op; _unary)
+            if (op.tokenType == t)
+                return &op;
+        return null;
+    }
+
+    struct BinOp
+    {
+        Tok tokenType;
+        int prec;
+        bool leftAssoc;
+        BinaryExp.Operator operator;
+    }
+
+    static BinOp[] _binary =
+    [
+        {Tok.Add, 3, true, BinaryExp.Operator.Add},
+        {Tok.Sub, 3, true, BinaryExp.Operator.Sub},
+        {Tok.Mul, 5, true, BinaryExp.Operator.Mul},
+        {Tok.Div, 5, true, BinaryExp.Operator.Div}
+    ];
+    BinOp* binary(Tok t)
+    {
+        foreach (ref op; _binary)
+            if (op.tokenType == t)
+                return &op;
+        return null;
+    }
+
+private:
+
+    void require(Tok t)
+    {
+        if (lexer.peek().type != t)
+            error("Unexpexted token: Got '"~lexer.peek.getType~"' Expected '"~typeToString[t]~"'");
+        lexer.next();
+    }
+
+    void error(char[] errMsg)
+    {
+        throw new Exception("Parser error: " ~errMsg);
+    }
+
+    Lexer lexer;
+}