Mercurial > projects > dang
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; }