Mercurial > projects > dil
view trunk/src/Parser.d @ 103:511a1aa25896
- Added reportErrors member to Lexer. Moved peek() down and rewrote it a bit making use of reportErrors. error() uses reportErrors too.
- Started implementation of parseDeclaration(), parseAttributeSpecifier() and parseImportDeclaration().
author | aziz |
---|---|
date | Sun, 08 Jul 2007 10:14:00 +0000 |
parents | 6e8b67ae15b7 |
children | b535016f8c3f |
line wrap: on
line source
/++ Author: Aziz Köksal License: GPL2 +/ module Parser; import Lexer; import Token; import Messages; import Information; import Declarations; import Statements; import Expressions; import Types; class Argument { StorageClass stc; Type type; string ident; Expression assignExpr; this(StorageClass stc, Type type, string ident, Expression assignExpr) { this.stc = stc; this.type = type; this.ident = ident; this.assignExpr = assignExpr; } bool isVariadic() { return !!(stc & StorageClass.Variadic); } bool isOnlyVariadic() { return stc == StorageClass.Variadic; } } private alias TOK T; class Parser { Lexer lx; Token* token; Information[] errors; this(char[] srcText, string fileName) { lx = new Lexer(srcText, fileName); } void nT() { lx.nextToken(); token = &lx.token; } void skipToOnePast(TOK tok) { for (; token.type != tok && token.type != T.EOF; nT()) {} nT(); } /* ReturnType try_(ReturnType)(lazy ReturnType parseMethod, out failed) { auto len = errors.length; // lx.saveCheckPoint(); auto result = parseMethod(); if (errors.length != len) { // lx.revertCheckPoint(); errors = errors[0..len]; failed = true; } // lx.removeCheckPoint(); return result; } */ /++++++++++++++++++++++++++++++ + Declaration parsing methods + ++++++++++++++++++++++++++++++/ Declaration[] parseModule() { Declaration[] decls; if (token.type == T.Module) { nT(); string[] idents; do { nT(); if (token.type == T.Identifier) { nT(); idents ~= token.srcText; } else { errorIfNot(T.Identifier); skipToOnePast(T.Semicolon); goto Lreturn; } } while (token.type == T.Dot) require(T.Semicolon); decls ~= new ModuleDeclaration(idents); } decls ~= parseDeclarations(); Lreturn: return decls; } Declaration[] parseDeclarations() { Declaration[] decls; while (token.type != T.EOF) decls ~= parseDeclaration(); return decls; } Declaration parseDeclaration() { Declaration decl; switch (token.type) { case T.Extern, T.Align, T.Pragma, T.Deprecated, T.Private, T.Package, T.Protected, T.Public, T.Export, //T.Static, T.Final, T.Override, T.Abstract, T.Const, T.Auto, T.Scope: case_AttributeSpecifier: decl = parseAttributeSpecifier(); break; case T.Static: Token t; lx.peek(t); if (t.type != T.Import) goto case_AttributeSpecifier; //goto case T.Import; case T.Import: parseImportDeclaration(); case T.Module: // Error: module is optional and can only appear once at the top of the source file. default: } return null; } Declaration parseAttributeSpecifier() { // Attribute : // Attribute DeclarationBlock return null; } Declaration parseImportDeclaration() { Declaration decl; bool isStatic; if (token.type == T.Static) { isStatic = true; nT(); } return decl; } /+++++++++++++++++++++++++++++ + Expression parsing methods + +++++++++++++++++++++++++++++/ Expression parseExpression() { auto e = parseAssignExpression(); while (token.type == TOK.Comma) e = new CommaExpression(e, parseAssignExpression()); return e; } Expression parseAssignExpression() { auto e = parseCondExpression(); while (1) { switch (token.type) { case T.Assign: nT(); e = new AssignExpression(e, parseAssignExpression()); break; case T.LShiftAssign: nT(); e = new LShiftAssignExpression(e, parseAssignExpression()); break; case T.RShiftAssign: nT(); e = new RShiftAssignExpression(e, parseAssignExpression()); break; case T.URShiftAssign: nT(); e = new URShiftAssignExpression(e, parseAssignExpression()); break; case T.OrAssign: nT(); e = new OrAssignExpression(e, parseAssignExpression()); break; case T.AndAssign: nT(); e = new AndAssignExpression(e, parseAssignExpression()); break; case T.PlusAssign: nT(); e = new PlusAssignExpression(e, parseAssignExpression()); break; case T.MinusAssign: nT(); e = new MinusAssignExpression(e, parseAssignExpression()); break; case T.DivAssign: nT(); e = new DivAssignExpression(e, parseAssignExpression()); break; case T.MulAssign: nT(); e = new MulAssignExpression(e, parseAssignExpression()); break; case T.ModAssign: nT(); e = new ModAssignExpression(e, parseAssignExpression()); break; case T.XorAssign: nT(); e = new XorAssignExpression(e, parseAssignExpression()); break; case T.CatAssign: nT(); e = new CatAssignExpression(e, parseAssignExpression()); break; default: break; } break; } return e; } Expression parseCondExpression() { auto e = parseOrOrExpression(); if (token.type == T.Question) { nT(); auto iftrue = parseExpression(); require(T.Colon); auto iffalse = parseCondExpression(); e = new CondExpression(e, iftrue, iffalse); } return e; } Expression parseOrOrExpression() { alias parseAndAndExpression parseNext; auto e = parseNext(); if (token.type == T.OrLogical) { nT(); e = new OrOrExpression(e, parseNext()); } return e; } Expression parseAndAndExpression() { alias parseOrExpression parseNext; auto e = parseNext(); if (token.type == T.AndLogical) { nT(); e = new AndAndExpression(e, parseNext()); } return e; } Expression parseOrExpression() { alias parseXorExpression parseNext; auto e = parseNext(); if (token.type == T.OrBinary) { nT(); e = new OrExpression(e, parseNext()); } return e; } Expression parseXorExpression() { alias parseAndExpression parseNext; auto e = parseNext(); if (token.type == T.Xor) { nT(); e = new XorExpression(e, parseNext()); } return e; } Expression parseAndExpression() { alias parseCmpExpression parseNext; auto e = parseNext(); if (token.type == T.AndBinary) { nT(); e = new AndExpression(e, parseNext()); } return e; } Expression parseCmpExpression() { TOK operator = token.type; auto e = parseShiftExpression(); switch (operator) { case T.Equal, T.NotEqual: nT(); e = new EqualExpression(e, parseShiftExpression(), operator); break; case T.Not: Token t; lx.peek(t); if (t.type != T.Is) break; nT(); operator = T.NotIdentity; goto LNotIdentity; case T.Identity: operator = T.Identity; LNotIdentity: nT(); e = new IdentityExpression(e, parseShiftExpression(), operator); break; case T.LessEqual, T.Less, T.GreaterEqual, T.Greater, T.Unordered, T.UorE, T.UorG, T.UorGorE, T.UorL, T.UorLorE, T.LorEorG, T.LorG: nT(); e = new RelExpression(e, parseShiftExpression(), operator); break; case T.In: nT(); e = new InExpression(e, parseShiftExpression(), operator); break; default: } return e; } Expression parseShiftExpression() { auto e = parseAddExpression(); while (1) { switch (token.type) { case T.LShift: nT(); e = new LShiftExpression(e, parseAddExpression()); break; case T.RShift: nT(); e = new RShiftExpression(e, parseAddExpression()); break; case T.URShift: nT(); e = new URShiftExpression(e, parseAddExpression()); break; default: break; } break; } return e; } Expression parseAddExpression() { auto e = parseMulExpression(); while (1) { switch (token.type) { case T.Plus: nT(); e = new PlusExpression(e, parseMulExpression()); break; case T.Minus: nT(); e = new MinusExpression(e, parseMulExpression()); break; case T.Tilde: nT(); e = new CatExpression(e, parseMulExpression()); break; default: break; } break; } return new Expression(); } Expression parseMulExpression() { auto e = parseUnaryExpression(); while (1) { switch (token.type) { case T.Mul: nT(); e = new MulExpression(e, parseUnaryExpression()); break; case T.Div: nT(); e = new DivExpression(e, parseUnaryExpression()); break; case T.Mod: nT(); e = new ModExpression(e, parseUnaryExpression()); break; default: break; } break; } return new Expression(); } Expression parseUnaryExpression() { Expression e; switch (token.type) { case T.AndBinary: nT(); e = new AddressExpression(parseUnaryExpression()); break; case T.PlusPlus: nT(); e = new PreIncrExpression(parseUnaryExpression()); break; case T.MinusMinus: nT(); e = new PreDecrExpression(parseUnaryExpression()); break; case T.Mul: nT(); e = new DerefExpression(parseUnaryExpression()); break; case T.Minus: case T.Plus: nT(); e = new SignExpression(parseUnaryExpression(), token.type); break; case T.Not: nT(); e = new NotExpression(parseUnaryExpression()); break; case T.Tilde: nT(); e = new CompExpression(parseUnaryExpression()); break; case T.New: // TODO: parseNewExpression(); break; case T.Delete: nT(); e = new DeleteExpression(parseUnaryExpression()); break; case T.Cast: requireNext(T.LParen); auto type = parseType(); require(T.RParen); e = new CastExpression(parseUnaryExpression(), type); break; case T.LParen: // ( Type ) . Identifier auto type = parseType(); require(T.RParen); require(T.Dot); string ident; if (token.type == T.Identifier) { ident = token.srcText; nT(); } else errorIfNot(T.Identifier); e = new TypeDotIdExpression(type, ident); break; default: e = parsePostExpression(parsePrimaryExpression()); break; } assert(e !is null); return e; } Expression parsePostExpression(Expression e) { while (1) { switch (token.type) { case T.Dot: nT(); if (token.type == T.Identifier) { e = new DotIdExpression(e); break; } else if (token.type == T.New) e = parseNewExpression(e); else errorIfNot(T.Identifier); continue; case T.PlusPlus: e = new PostIncrExpression(e); break; case T.MinusMinus: e = new PostDecrExpression(e); break; case T.LParen: e = new CallExpression(e, parseArgumentList(T.LParen)); continue; case T.LBracket: // parse Slice- and IndexExpression nT(); if (token.type == T.RBracket) { e = new SliceExpression(e, null, null); break; } Expression[] es = [parseAssignExpression()]; if (token.type == T.Slice) { nT(); e = new SliceExpression(e, es[0], parseAssignExpression()); require(T.RBracket); continue; } else if (token.type == T.Comma) { es ~= parseArgumentList(T.RBracket); } else require(T.RBracket); e = new IndexExpression(e, es); continue; default: return e; } nT(); } assert(0); } Expression parsePrimaryExpression() { Expression e; switch (token.type) { case T.Identifier: e = new IdentifierExpression(token.srcText); nT(); break; case T.Dot: requireNext(T.Identifier); e = new GlobalIdExpression(token.srcText); break; case T.This: nT(); e = new ThisExpression(); break; case T.Super: nT(); e = new SuperExpression(); break; case T.Null: nT(); e = new NullExpression(); break; case T.True, T.False: nT(); e = new BoolExpression(token.type == T.True ? true : false); break; case T.Dollar: nT(); e = new DollarExpression(); break; case T.Int32, T.Int64, T.Uint32, T.Uint64: nT(); e = new IntNumberExpression(token.type, token.ulong_); break; case T.Float32, T.Float64, T.Float80, T.Imaginary32, T.Imaginary64, T.Imaginary80: nT(); e = new RealNumberExpression(token.type, token.real_); break; case T.CharLiteral, T.WCharLiteral, T.DCharLiteral: nT(); e = new CharLiteralExpression(token.type); break; case T.String: char[] buffer = token.str; char postfix = token.pf; nT(); while (token.type == T.String) { string tmp = token.str; // if (postfix != token.pf) // error(); if (tmp.length > 1) { buffer[$-1] = tmp[0]; // replace '\0' buffer ~= tmp[1..$]; // append the rest } nT(); } e = new StringLiteralExpression(buffer); break; case T.LBracket: Expression[] values; nT(); if (token.type != T.RBracket) { e = parseAssignExpression(); if (token.type == T.Colon) goto LparseAssocArray; else if (token.type == T.Comma) values = [e] ~ parseArgumentList(T.RBracket); else require(T.RBracket); } e = new ArrayLiteralExpression(values); break; LparseAssocArray: Expression[] keys; keys ~= e; nT(); // Skip colon. values ~= parseAssignExpression(); if (token.type != T.RBracket) { require(T.Comma); while (1) { keys ~= parseAssignExpression(); if (token.type != T.Colon) { errorIfNot(T.Colon); values ~= null; if (token.type == T.RBracket) break; else continue; } nT(); values ~= parseAssignExpression(); if (token.type == T.RBracket) break; require(T.Comma); } } assert(token.type == T.RBracket); nT(); e = new AssocArrayLiteralExpression(keys, values); break; case T.LBrace: // TODO: parse delegate literals: FunctionBody break; case T.Function, T.Delegate: // TODO: parse delegate/function literals: // function Type? ( ArgumentList ) FunctionBody // function FunctionBody // delegate Type? ( ArgumentList ) FunctionBody // delegate FunctionBody break; case T.Assert: Expression msg; requireNext(T.LParen); e = parseAssignExpression(); if (token.type == T.Comma) { nT(); msg = parseAssignExpression(); } require(T.RParen); e = new AssertExpression(e, msg); break; case T.Mixin: requireNext(T.LParen); e = parseAssignExpression(); require(T.RParen); e = new MixinExpression(e); break; case T.Import: requireNext(T.LParen); e = parseAssignExpression(); require(T.RParen); e = new ImportExpression(e); break; case T.Typeid: requireNext(T.LParen); auto type = parseType(); require(T.RParen); e = new TypeidExpression(type); break; case T.Typeof: requireNext(T.LParen); auto type = new TypeofType(parseExpression()); require(T.RParen); if (token.type == T.Dot) { nT(); string ident; if (token.type == T.Identifier) { ident = token.srcText; nT(); } else errorIfNot(T.Identifier); e = new TypeDotIdExpression(type, ident); } else e = new TypeofExpression(type); break; case T.Is: requireNext(T.LParen); Type type; SpecializationType specType; string ident; // optional Identifier type = parseDeclarator(ident, true); switch (token.type) { case T.Colon, T.Equal: TOK specTok = token.type; nT(); switch (token.type) { case T.Typedef, T.Struct, T.Union, T.Class, T.Interface, T.Enum, T.Function, T.Delegate, T.Super, T.Return: nT(); specType = new SpecializationType(specTok, token.type); break; default: specType = new SpecializationType(specTok, parseType()); } default: } require(T.RParen); e = new IsExpression(type, ident, specType); break; case T.LParen: // TODO: parse ( ArgumentList ) FunctionBody type delegates nT(); e = parseExpression(); require(T.RParen); break; // BasicType . Identifier case T.Void, T.Char, T.Wchar, T.Dchar, T.Bool, T.Byte, T.Ubyte, T.Short, T.Ushort, T.Int, T.Uint, T.Long, T.Ulong, T.Float, T.Double, T.Real, T.Ifloat, T.Idouble, T.Ireal, T.Cfloat, T.Cdouble, T.Creal: auto type = new Type(token.type); requireNext(T.Dot); string ident; if (token.type == T.Identifier) { ident = token.srcText; nT(); } else errorIfNot(T.Identifier); e = new TypeDotIdExpression(type, ident); break; default: // TODO: issue error msg and decide what to return. } return e; } Expression parseNewExpression(Expression e) { // TODO: implement this method. return null; } Expression[] parseArgumentList(TOK terminator) { Expression[] es; nT(); if (token.type == terminator) { nT(); return null; } while (1) { es ~= parseAssignExpression(); if (token.type == terminator) break; require(T.Comma); } nT(); return es; } Type parseType() { return parseDeclaratorSuffix(parseBasicType2(parseBasicType())); } Type parseBasicType() { Type t; IdentifierType tident; switch (token.type) { case T.Void, T.Char, T.Wchar, T.Dchar, T.Bool, T.Byte, T.Ubyte, T.Short, T.Ushort, T.Int, T.Uint, T.Long, T.Ulong, T.Float, T.Double, T.Real, T.Ifloat, T.Idouble, T.Ireal, T.Cfloat, T.Cdouble, T.Creal: t = new Type(token.type); nT(); break; case T.Identifier, T.Dot: tident = new IdentifierType([token.srcText]); nT(); // TODO: parse template instance // if (token.type == T.Not) // parse template instance Lident: while (token.type == T.Dot) { nT(); if (token.type == T.Identifier) { tident ~= token.srcText; } else errorIfNot(T.Identifier); nT(); // TODO: parse template instance // if (token.type == T.Not) // parse template instance } t = tident; break; case T.Typeof: requireNext(T.LParen); tident = new TypeofType(parseExpression()); require(T.RParen); goto Lident; default: // TODO: issue error msg and return UndefinedType. } return t; } Type parseBasicType2(Type t) { while (1) { switch (token.type) { case T.Mul: t = new PointerType(t); nT(); break; case T.LBracket: nT(); if (token.type == T.RBracket) { t = new ArrayType(t, null); nT(); } else { // TODO: try parsing as Type for assoc arrays and then as Expression. t = new ArrayType(t, parseExpression()); require(T.RBracket); } break; case T.Function, T.Delegate: TOK tok = token.type; nT(); auto args = parseParameters(); // TODO: create appropriate Type. // if (tok == T.Function) // t = new FunctionType(); // else // t = new DelegateType(); break; default: return t; } } assert(0); } Type parseDeclaratorSuffix(Type t) { while (1) { switch (token.type) { case T.LBracket: nT(); if (token.type == T.RBracket) { t = new ArrayType(t, null); nT(); } else { // TODO: try parsing as Type for assoc arrays and then as Expression. t = new ArrayType(t, parseExpression()); require(T.RBracket); } continue; case T.LParen: auto params = parseParameters(); // TODO: create FunctionType. // new FunctionType(params); break; default: break; } break; } return t; } Type parseDeclarator(ref string ident, bool identOptional = false) { auto t = parseBasicType2(parseBasicType()); if (token.type == T.Identifier) { ident = token.srcText; nT(); } else if (!identOptional) errorIfNot(T.Identifier); return parseDeclaratorSuffix(t); } Argument[] parseParameters() out(args) { if (args.length > 1) foreach (arg; args[0..$-1]) { if (arg.isVariadic()) assert(0, "variadic arguments can only appear at the end of the parameter list."); } } body { require(T.LParen); if (token.type == T.RParen) { nT(); return null; } Argument[] args; StorageClass stc; while (1) { stc = StorageClass.In; switch (token.type) { case T.In: stc = StorageClass.In; nT(); goto default; case T.Out: stc = StorageClass.Out; nT(); goto default; case T.Ref: stc = StorageClass.Ref; nT(); goto default; case T.Lazy: stc = StorageClass.Lazy; nT(); goto default; case T.Ellipses: args ~= new Argument(StorageClass.Variadic, null, null, null); break; default: string ident; auto type = parseDeclarator(ident); Expression assignExpr; if (token.type == T.Assign) { nT(); assignExpr = parseAssignExpression(); } if (token.type == T.Ellipses) { stc |= StorageClass.Variadic; args ~= new Argument(stc, type, ident, assignExpr); nT(); break; } args ~= new Argument(stc, type, ident, assignExpr); if (token.type == T.Comma) { nT(); continue; } break; } break; } require(T.RParen); return args; } void errorIfNot(TOK tok) { if (token.type != tok) error(MID.ExpectedButFound, tok, token.srcText); } void require(TOK tok) { if (token.type == tok) nT(); else error(MID.ExpectedButFound, tok, token.srcText); } void requireNext(TOK tok) { nT(); if (token.type == tok) nT(); else error(MID.ExpectedButFound, tok, token.srcText); } void error(MID id, ...) { errors ~= new Information(InfoType.Parser, id, lx.loc, arguments(_arguments, _argptr)); } }