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