view parser/Parser.d @ 45:9bc660cbdbec new_gen

If statements are back Also fixed a bug in the codegen preventing return in the else branch, now it is optional. Also found an issue with the way we are generating our llvm from ifs - it doesn't mean anything but the code looks ugly. if (cond_1) if (cond_2) statement; return 0; Becomes: br cond_1, then, merge then: br cond_2 then2, merge2 merge: ret 0 then2: statements merge2: br merge This is because we use appendBasicBlock on the function
author Anders Halager <halager@gmail.com>
date Wed, 23 Apr 2008 16:43:42 +0200
parents 495188f9078e
children 90fb4fdfefdd
line wrap: on
line source

module parser.Parser;

import lexer.Lexer,
       lexer.Token;

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();

        return declarations;
    }

    Decl parseRootDecl()
    {
        Token t = lexer.peek;

        if (t.isBasicType || t.isIdentifier)
        {
            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);
    }

    /**
      Parse statements.

      This is the place to attack!
     */
    Stmt parseStatement()
    {
        Token t = lexer.peek;

        switch(t.type)
        {
            case Tok.Return:
                Token ret = lexer.next;
                Exp exp = parseExpression();
                require(Tok.Seperator);
                return action.actOnReturnStmt(ret, exp);

            /*
               if (cond)
                single statement | compound statement
               [else
                single statement | compound statement]
             */
            case Tok.If:
                Token _if = lexer.next();

                require(Tok.OpenParentheses);
                Exp cond = parseExpression();
                require(Tok.CloseParentheses);

                Stmt thenB = parseSingleOrCompoundStatement();

                // if there is no else part we use the if as token, to have
                // something than can be passed along
                Token _else = _if;
                Stmt elseB;
                if (lexer.peek.type == Tok.Else)
                {
                    _else = lexer.next;
                    elseB = parseSingleOrCompoundStatement();
                }

                return action.actOnIfStmt(_if, cond, thenB, _else, elseB);

            case Tok.While:
                return null;

            case Tok.Identifier:
                return null;

            case Tok.Switch:
                return null;

            default:
                return null;
        }
        error(__LINE__, "").tok(t);
        return null;
    }

    /**
      Parses a function/method given the already parsed
     */
    Decl parseFunc(ref Id type, ref Id name)
    {
        Decl func = action.actOnStartOfFunctionDef(type, name);
        parseFuncArgs(func);

        Stmt stmt = parseCompoundStatement();

        action.actOnEndOfFunction(func, stmt);
        return func;
    }

    /**
      Parse the function arguments, assumes current token is (.

      Both the intitial paren and the ending paren is consumed.
     */
    void parseFuncArgs(Decl func)
    {
        require(Tok.OpenParentheses); // Remove the "(" token.

        while(lexer.peek.type != Tok.CloseParentheses)
        {
            auto t = parseType();
            auto i = parseIdentifier();
            action.addFuncArg(func, t, i);

            if(lexer.peek.type == Tok.Comma)
                lexer.next;
        }

        require(Tok.CloseParentheses); // Remove the ")"
    }

    /**
      Parse either a block, or a single statement as allowed after if, while
      and for.
     */
    Stmt parseSingleOrCompoundStatement()
    {
        if (lexer.peek.type == Tok.OpenBrace)
            return parseCompoundStatement();
        return parseStatement();
    }
    /**
      Parses a function-body or similar, expects { to be current token.
      
      Will consume both the starting { and ending }
     */
    Stmt parseCompoundStatement()
    {
        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());
    }

    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;

        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 -- //
    Exp parseExpIdentifier(Exp target)
    {
        switch(lexer.peek.type)
        {
            case Tok.Dot:
                switch(lexer.peek(1).type)
                {
                    case Tok.Identifier:
                        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 '.'").tok(t);
                }
            default:
                return target;
        }
    }

    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 = action.actOnBinaryOp(op.operator, exp, exp2);
            next = lexer.peek();
        }

        return exp;
    }

    Exp P()
    {
        Token next = lexer.next();
        if (auto op = unary(next.type))
            return action.actOnUnaryOp(next, parseExpression(op.prec));
        else if (next.type == Tok.OpenParentheses)
        {
            auto e = parseExpression(0);
            require(Tok.CloseParentheses);
            return e;
        }
        else if (next.type == Tok.Identifier)
        {
            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;
                    while(lexer.peek.type != Tok.CloseParentheses)
                    {
                        if(lexer.peek.type == Tok.Comma)
                        {
                            lexer.next;
                        }
                        args ~= parseExpression();
                    }

                    lexer.next();
                    return null;//new CallExp(iden, args);

                default:
                    return iden;
            }
        }
        else if (next.type == Tok.Integer)
            return action.actOnNumericConstant(next);

        Stdout.formatln("{}", next.getType);
        assert(0, "Should not happen");
    }

    struct UnOp
    {
        Tok tokenType;
        int prec;
    }

    static const 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;
        Operator operator;
    }

    static const BinOp[] _binary =
    [
        {Tok.Eq,        2, true, Operator.Eq},
        {Tok.Ne,        2, true, Operator.Ne},

        {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.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)
    {
        foreach (ref op; _binary)
            if (op.tokenType == t)
                return &op;
        return null;
    }

private:

    Token require(Tok t)
    {
        if (lexer.peek().type != t)
            throw error(__LINE__, PE.UnexpectedTokSingle)
                .arg(lexer.peek.getType)
                .arg(t);
        return lexer.next();
    }

    bool skip(Tok t)
    {
        if (lexer.peek().type != t)
            return false;
        lexer.next();
        return true;
    }

    Error error(uint line, char[] errMsg)
    {
        Location loc = lexer.peek.location;
        auto e =
            new Error("Parser.d(" ~ Integer.toString(line) ~ "): " ~errMsg);
            e.loc(loc);
            return e;
    }

    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";
    }

    Lexer lexer;
}