view parser/Parser.d @ 21:0fb2d13dce37

Now working with gdc also (gdc use reverse paremeter validating on function calls)
author johnsen@johnsen-laptop
date Fri, 18 Apr 2008 21:39:17 +0200
parents 6282db07115f
children e331e4e816e4
line wrap: on
line source

module parser.Parser;

import lexer.Lexer,
       lexer.Token;

import ast.Exp,
       ast.Stmt,
       ast.Decl;

import misc.Error;

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.Bool,
                 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.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);

            case Tok.While:
                lexer.next;
                require(Tok.OpenParentheses);
                auto condition = parseExpression();
                require(Tok.CloseParentheses);
                return new WhileStmt(condition, parseBlockOrSingleStmt());

            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)
        {
            auto t = parseType;
            auto i = parseIdentifier;
            funcArgs ~= new VarDecl(t, i);

            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:
                throw new Error("Unexpexted token in Identifier parsing. Got "~identifier.getType, identifier.location);
        }
    }

    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.Bool,
                 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");
    }

    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}];
    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.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.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;
}