Mercurial > projects > dang
changeset 44:495188f9078e new_gen
Big update - Moving towards a better, more seperated parser
The parser no loner creates the AST directly, but through
callbacks(actions). This means the parser can be run with a different set
of actions that do something else.
The parser is not back to full strength yet, the main thing missing is the
various statements and structs.
Also added a SmallArray that uses the stack only until a given size is
exceeded, after which the array is copied unto the heap.
author | Anders Halager <halager@gmail.com> |
---|---|
date | Wed, 23 Apr 2008 00:57:45 +0200 |
parents | a712c530b7cc |
children | 9bc660cbdbec |
files | ast/Decl.d ast/Exp.d ast/Stmt.d basic/SmallArray.d dang/compiler.d gen/LLVMGen.d lexer/Token.d parser/Action.d parser/Parser.d sema/SymbolTableBuilder.d sema/Visitor.d |
diffstat | 11 files changed, 583 insertions(+), 369 deletions(-) [+] |
line wrap: on
line diff
--- a/ast/Decl.d Tue Apr 22 22:31:39 2008 +0200 +++ b/ast/Decl.d Wed Apr 23 00:57:45 2008 +0200 @@ -42,14 +42,21 @@ class FuncDecl : Decl { - this(Identifier type, Identifier identifier, - VarDecl[] funcArgs, Stmt[] statements) + this(Identifier type, Identifier identifier) { super(DeclType.FuncDecl); this.type = type; this.identifier = identifier; - this.funcArgs = funcArgs; - this.statements = statements; + } + + void addParam(Identifier type, Identifier name) + { + funcArgs ~= new VarDecl(type, name, null); + } + + void setBody(CompoundStatement stmts) + { + statements = stmts.statements; } Identifier type, identifier;
--- a/ast/Exp.d Tue Apr 22 22:31:39 2008 +0200 +++ b/ast/Exp.d Wed Apr 23 00:57:45 2008 +0200 @@ -60,10 +60,12 @@ public enum Operator { Eq, Ne, + Lt, Le, Gt, Ge, - Mul, Div, + Add, Sub, + Mul, Div, Mod, } this(Operator op, Exp left, Exp right)
--- a/ast/Stmt.d Tue Apr 22 22:31:39 2008 +0200 +++ b/ast/Stmt.d Wed Apr 23 00:57:45 2008 +0200 @@ -12,6 +12,7 @@ enum StmtType { Stmt, + Compound, Decl, Exp, Return, @@ -31,6 +32,17 @@ Scope env; } +class CompoundStatement : Stmt +{ + this(Stmt[] stmts) + { + super(StmtType.Compound); + this.statements = stmts; + } + + Stmt[] statements; +} + class ReturnStmt : Stmt { this()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/basic/SmallArray.d Wed Apr 23 00:57:45 2008 +0200 @@ -0,0 +1,106 @@ +module basic.SmallArray; + +/** + This struct acts like a normal dynamic array, with one difference. + A size is given, which is how many elements are preallocated on the stack. + + Example: + -------- + SmallArray!(float, 4) array; + array ~= 1.0; + array ~= 2.0; + array ~= 3.0; + float[] three_floats = array[0 .. 3]; + // The slice gives a reference to the stack, remember to .dup + array ~= 4.0; + // not using the heap yet, but after the next line all values will have been + // copied to the heap. + array ~= 5.0; + -------- + + Compared to a normal dynamic array there is 8 bytes overhead (on 32 bit cpus) + and ofcourse size * T.sizeof bytes for the stack allocated array. + */ +struct SmallArray(T, ubyte size = 8) +{ + T[] opSlice(size_t low, size_t high) + { + assert(high <= len && low <= high, "Array index out of range"); + return ptr[low .. high]; + } + + T[] opSlice() + { + return ptr[0 .. len].dup; + } + alias opSlice unsafe; + + T[] safe() + { + if (len <= size) + return static_array[0 .. len].dup; + return array[0 .. len].dup; + } + + T[] opSliceAssign(T val, size_t low, size_t high) + { + assert(high <= len && low <= high, "Array index out of range"); + return ptr[low .. high] = val; + } + + T[] opSliceAssign(T val) + { + return ptr[0 .. len] = val; + } + + T opIndex(size_t index) + { + assert(index < len, "Array index out of range"); + return ptr[index]; + } + + T opIndexAssign(T val, size_t index) + { + assert(index < len, "Array index out of range"); + return ptr[index] = val; + } + + void opCatAssign(T val) + { + if (len < size) + { + ptr = static_array.ptr; + static_array[len] = val; + } + else if (len == size) + { + T[] tmp = static_array[].dup; + array = tmp; + array ~= val; + ptr = array.ptr; + } + else + array ~= val; + + ++len; + } + + size_t length() { return len; } + + static SmallArray opCall() + { + SmallArray array; + array.ptr = array.static_array.ptr; + return array; + } + +private: + T* ptr; + size_t len; + union + { + T[] array; + T[size] static_array; + } +} +
--- a/dang/compiler.d Tue Apr 22 22:31:39 2008 +0200 +++ b/dang/compiler.d Wed Apr 23 00:57:45 2008 +0200 @@ -174,7 +174,7 @@ preParse(lexer); auto parser = new Parser; - auto decls = parser.parse(lexer); + auto decls = cast(Decl[])parser.parse(lexer); (new SymbolTableBuilder).visit(decls); (new Declarations).visit(decls);
--- a/gen/LLVMGen.d Tue Apr 22 22:31:39 2008 +0200 +++ b/gen/LLVMGen.d Wed Apr 23 00:57:45 2008 +0200 @@ -285,6 +285,11 @@ { switch(stmt.stmtType) { + case StmtType.Compound: + auto stmts = cast(CompoundStatement)stmt; + foreach (s; stmts.statements) + genStmt(s); + break; case StmtType.Return: auto ret = cast(ReturnStmt)stmt; auto sym = stmt.env.parentFunction();
--- a/lexer/Token.d Tue Apr 22 22:31:39 2008 +0200 +++ b/lexer/Token.d Wed Apr 23 00:57:45 2008 +0200 @@ -56,6 +56,23 @@ { return location.get(length); } + + /** + Returns true if the type of this token is a basic type (int, float, ...). + Void is included, although a void in it self is not really a type. + */ + bool isBasicType() + { + return type >= Tok.Byte && type <= Tok.Void; + } + + /** + Just a shortcut to avoid `token.type == Tok.Identifier`. + */ + bool isIdentifier() + { + return type == Tok.Identifier; + } } /**
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/parser/Action.d Wed Apr 23 00:57:45 2008 +0200 @@ -0,0 +1,267 @@ +module parser.Action; + +import lexer.Token; + +import ast.Exp, + ast.Stmt, + ast.Decl; + +import misc.Error; + +import tango.io.Stdout, + Integer = tango.text.convert.Integer; + +/** + Used to indicate what type of operator is used in a given binary expression + (and unary expressions?) + */ +public enum Operator +{ + Eq, Ne, + + Lt, Le, + Gt, Ge, + + Add, Sub, + Mul, Div, Mod, +} + + +struct Id +{ + Token tok; + + char[] toString() + { + return tok.get; + } +} + +/** + All methods are optional. + +Warning: Interface is not stable yet. Use the `override` keyword in all classes + inheriting from this to get warning if the interface changes. + */ +abstract class Action +{ + /** + A few aliases to indicate what methods should be dealing with the same + types. + + Not typesafe, and not using typedef because users would need a lot of + casts (and base type would be void*, so no possibility to synchronize, + print etc.) + */ + alias Object ExprT; + alias Object StmtT; /// ditto + alias Object DeclT; /// ditto + + // -- Declarations -- + + /** + Either we should have one case that handles a lot of things, or we should + have a lot of separate cases. + As an example, this method could handle the params in `int f(int, int)` + as well as handling `int x` at both top-level, in classes and in methods. + + The other solution is an addParamToFunc or similar. + */ + DeclT actOnDeclarator(ref Id type, ref Id name, ExprT init) + { + return null; + } + + /** + Add an initialization expression to a previously created decl. + + Used for default values on function params and for values to local + variables. + */ + void addInitToDeclarator(DeclT decl, ExprT exp) + { + } + + /** + Called at the start of a function, doesn't get a lot of info - that is + added later on, through addFuncArg and actOnEndOfFunction. + */ + DeclT actOnStartOfFunctionDef(ref Id type, ref Id name) + { + return null; + } + + /** + Add a new parameter to the function func. + */ + void addFuncArg(DeclT func, Id type, Id name) + { + } + + /** + Finish off the function, by giving it the body (a single statement, so + you probably want some sort of compound statement) + */ + DeclT actOnEndOfFunction(DeclT func, StmtT stmts) + { + return func; + } + + // -- Statements -- + + /** + Called after parsing a function/while/for/whatever body. + + Note that stmts is to be considered temporary, it might point into the + stack and needs to be copied before saving. + */ + StmtT actOnCompoundStmt(ref Token left, ref Token right, StmtT[] stmts) + { + return null; + } + + /** + Called after parsing return statements. + + loc is the return token. + */ + StmtT actOnReturnStmt(ref Token loc, ExprT exp) + { + return null; + } + + StmtT actOnStartOfSwitchStmt() + { + return null; + } + + void actOnCaseStmt() + { + } + + void actOnDefaultStmt() + { + } + + StmtT actOnFinishSwitchStmt(StmtT sw) + { + return sw; + } + + // -- Expressions -- + + /** + A single numerical constant -- this can be absolutely any kind of number. + Integers, floats, hex, octal, binary, imaginary and so on. + */ + ExprT actOnNumericConstant(Token op) + { + return null; + } + + /** + This is called when identifiers are used in expressions. + */ + ExprT actOnIdentifierExp(Id id) + { + return null; + } + + /** + Unary operator. + */ + ExprT actOnUnaryOp(Token op, ExprT operand) + { + return null; + } + + /** + Binary operator. + */ + ExprT actOnBinaryOp(Operator op, ExprT l, ExprT r) + { + return null; + } + + /** + Called when using the 'dot' operator. + The left hand side can be any expression, but its only possible to look + up an identifier. + */ + ExprT actOnMemberReference(ExprT lhs, Location op, Id member) + { + return null; + } +} + +/** + This class implements the default actions for Dang, by building up an AST + with the data needed in a compiler. + */ +class AstAction : Action +{ + override DeclT actOnDeclarator(ref Id type, ref Id id, ExprT init) + { + Exp exp = cast(Exp)init; + return new VarDecl(new Identifier(type.tok), new Identifier(id.tok), exp); + } + + override DeclT actOnStartOfFunctionDef(ref Id type, ref Id name) + { + return new FuncDecl(new Identifier(type.tok), new Identifier(name.tok)); + } + + override void addFuncArg(DeclT func, Id type, Id name) + { + FuncDecl fd = cast(FuncDecl)func; + fd.addParam(new Identifier(type.tok), new Identifier(name.tok)); + } + + override DeclT actOnEndOfFunction(DeclT func, StmtT stmts) + { + FuncDecl fd = cast(FuncDecl)func; + fd.setBody(cast(CompoundStatement)stmts); + return fd; + } + + override StmtT actOnCompoundStmt(ref Token l, ref Token r, StmtT[] stmts) + { + StmtT[] array = stmts.dup; + Stmt[] statements = cast(Stmt[])array; + Stdout(statements).newline; + return new CompoundStatement(cast(Stmt[])array); + } + + override StmtT actOnReturnStmt(ref Token loc, ExprT exp) + { + Exp e = cast(Exp)exp; + auto res = new ReturnStmt; + res.exp = e; + return res; + } + + override ExprT actOnNumericConstant(Token c) + { + return new IntegerLit(c); + } + + override ExprT actOnIdentifierExp(Id id) + { + return new Identifier(id.tok); + } + + override ExprT actOnBinaryOp(Operator op, ExprT l, ExprT r) + { + Exp left = cast(Exp)l; + Exp right = cast(Exp)r; + return new BinaryExp(cast(BinaryExp.Operator)op, left, right); + } + + override ExprT actOnUnaryOp(Token op, ExprT operand) + { + Exp target = cast(Exp)operand; + // can only be -x for now + return new NegateExp(target); + } +} +
--- a/parser/Parser.d Tue Apr 22 22:31:39 2008 +0200 +++ b/parser/Parser.d Wed Apr 23 00:57:45 2008 +0200 @@ -3,30 +3,33 @@ import lexer.Lexer, lexer.Token; -import ast.Exp, - ast.Stmt, - ast.Decl; +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; - } + declarations ~= parseRootDecl(); return declarations; } @@ -35,147 +38,42 @@ { Token t = lexer.peek; - switch(t.type) + if (t.isBasicType || t.isIdentifier) { - case Tok.Byte, Tok.Ubyte, - Tok.Short, Tok.Ushort, - Tok.Int, Tok.Uint, - Tok.Long, Tok.Ulong, - Tok.Float, Tok.Double, - Tok.Bool, - Tok.Void, - Tok.Identifier: - Identifier type = new Identifier(t); - - Token iden = lexer.peek(1); - - switch(iden.type) - { - case Tok.Identifier: - Identifier identifier = new Identifier(iden); - Token p = lexer.peek(2); - switch(p.type) - { - case Tok.OpenParentheses: - lexer.next; lexer.next; - return parseFunc(type, identifier); - case Tok.Seperator: - lexer.next; lexer.next; - require(Tok.Seperator); - return new VarDecl(type, identifier, null); - case Tok.Assign: - lexer.next; lexer.next; - lexer.next(); - auto exp = parseExpression(); - require(Tok.Seperator); - return new VarDecl(type, identifier, exp); - default: - char[] c = p.getType; - throw error(__LINE__, UnexpectedTokMulti) - .tok(p) - .arg(c) - .arg(Tok.OpenParentheses, Tok.Seperator, Tok.Assign); - } - break; - default: - char[] c = t.getType; - throw error(__LINE__, UnexpectedTok).tok(iden).arg(c); - } - break; - case Tok.Struct: - lexer.next; - Token iden = lexer.next; - switch(iden.type) - { - case Tok.Identifier: - Identifier identifier = new Identifier(iden); - return new StructDecl (identifier, parseStruct()); - default: - throw error(__LINE__, "Expected struct identifier, but got %0").arg(iden.getType); - } - case Tok.EOF: - return null; - default: - char[] c = t.getType; - throw error(__LINE__, UnexpectedTok).tok(t).arg(c); + 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); } - Decl parseDecl() - { - Token t = lexer.peek; - - 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.Void, - Tok.Identifier: - Identifier type = new Identifier(t); - - Token iden = lexer.peek(1); + /** + Parse statements. - switch(iden.type) - { - case Tok.Identifier: - Identifier identifier = new Identifier(iden); - Token p = lexer.peek(2); - switch(p.type) - { - case Tok.OpenParentheses: - lexer.next; lexer.next; - return parseFunc(type, identifier); - case Tok.Seperator: - lexer.next; lexer.next; - require(Tok.Seperator); - return new VarDecl(type, identifier, null); - case Tok.Assign: - lexer.next; lexer.next; - lexer.next(); - auto exp = parseExpression(); - require(Tok.Seperator); - return new VarDecl(type, identifier, exp); - default: - char[] c = p.getType; - throw error(__LINE__, UnexpectedTokMulti) - .tok(p) - .arg(c) - .arg(Tok.OpenParentheses, Tok.Seperator, Tok.Assign); - } - break; - default: - char[] c = iden.getType; - throw error(__LINE__, UnexpectedTokSingle) - .tok(iden) - .arg(c) - .arg(Tok.Identifier); - } - break; - case Tok.EOF: - return null; - default: - char[] c = t.getType; - throw error(__LINE__, UnexpectedTok).arg(c); - } - } - - VarDecl[] parseStruct() - { - VarDecl[] varDecls; - require(Tok.OpenBrace); - while(lexer.peek.type != Tok.CloseBrace) - { - varDecls ~= cast(VarDecl)parseDecl; - } - - require(Tok.CloseBrace); - return varDecls; - } - + This is the place to attack! + */ Stmt parseStatement() { Token t = lexer.peek; @@ -183,212 +81,107 @@ switch(t.type) { case Tok.Return: - lexer.next; - auto ret = new ReturnStmt(); - if (!skip(Tok.Seperator)) - { - ret.exp = parseExpression(); - require(Tok.Seperator); - } - return ret; + Token ret = lexer.next; + Exp exp = parseExpression(); + require(Tok.Seperator); + return action.actOnReturnStmt(ret, exp); 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); + return null; case Tok.While: - lexer.next; - require(Tok.OpenParentheses); - auto condition = parseExpression(); - require(Tok.CloseParentheses); - return new WhileStmt(condition, parseBlockOrSingleStmt()); + return null; case Tok.Identifier: - Token n = lexer.peek(1); - switch(n.type) - { - case Tok.Dot: - Exp iden = parseExpIdentifier(new Identifier(lexer.next)); - switch(lexer.peek.type) - { - case Tok.Assign: - lexer.next; - auto stmt = new ExpStmt(new AssignExp(iden , parseExpression())); - require(Tok.Seperator); - return stmt; - break; - } - case Tok.Assign: - lexer.next; - lexer.next; - auto stmt = new ExpStmt(new AssignExp(new Identifier(t), parseExpression())); - require(Tok.Seperator); - return stmt; - break; - case Tok.Identifier: - auto decl = new DeclStmt(parseDecl()); - return decl; - - default: - auto e = new ExpStmt(parseExpression()); - require(Tok.Seperator); - return e; - - } - break; + return null; case Tok.Switch: - lexer.next; - require(Tok.OpenParentheses); - auto target = parseExpression(); - auto res = new SwitchStmt(target); - require(Tok.CloseParentheses); - require(Tok.OpenBrace); - while (true) - { - Stmt[] statements; - if (skip(Tok.Default)) - { - require(Tok.Colon); - statements.length = 0; - while (lexer.peek.type != Tok.Case - && lexer.peek.type != Tok.Default - && lexer.peek.type != Tok.CloseBrace) - statements ~= parseStatement(); - res.setDefault(statements); - continue; - } - - Token _case = lexer.peek; - if (_case.type != Tok.Case) - break; - lexer.next(); - - IntegerLit[] literals; - do - { - Exp e = parseExpression(); - IntegerLit lit = cast(IntegerLit)e; - if (lit is null) - throw error(__LINE__, CaseValueMustBeInt) - .tok(_case); - - literals ~= lit; - } - while (skip(Tok.Comma)); - require(Tok.Colon); - - while (lexer.peek.type != Tok.Case - && lexer.peek.type != Tok.Default - && lexer.peek.type != Tok.CloseBrace) - statements ~= parseStatement(); - - res.addCase(literals, statements); - - if (lexer.peek.type == Tok.CloseBrace) - break; - } - require(Tok.CloseBrace); - return res; + return null; default: - auto decl = new DeclStmt(parseDecl()); - //require(Tok.Seperator); - return decl; + return null; } - return new Stmt(); + error(__LINE__, "").tok(t); + return null; } - FuncDecl parseFunc(Identifier type, Identifier identifier) + /** + Parses a function/method given the already parsed + */ + Decl parseFunc(ref Id type, ref Id name) { - VarDecl[] funcArgs = parseFuncArgs(); - - lexer.next; // Remove the "{" + Decl func = action.actOnStartOfFunctionDef(type, name); + parseFuncArgs(func); - Stmt[] statements; + Stmt stmt = parseCompoundStatement(); - while(lexer.peek.type != Tok.CloseBrace) - statements ~= parseStatement(); - - lexer.next; // Remove "}" - - return new FuncDecl(type, identifier, funcArgs, statements); + action.actOnEndOfFunction(func, stmt); + return func; } - VarDecl[] parseFuncArgs() + /** + Parse the function arguments, assumes current token is (. + + Both the intitial paren and the ending paren is consumed. + */ + void parseFuncArgs(Decl func) { - lexer.next; // Remove the "(" token. - - VarDecl[] funcArgs; + require(Tok.OpenParentheses); // Remove the "(" token. while(lexer.peek.type != Tok.CloseParentheses) { - auto t = parseType; - auto i = parseIdentifier; - funcArgs ~= new VarDecl(t, i); + auto t = parseType(); + auto i = parseIdentifier(); + action.addFuncArg(func, t, i); if(lexer.peek.type == Tok.Comma) lexer.next; } - lexer.next; // Remove the ")" - - return funcArgs; + require(Tok.CloseParentheses); // Remove the ")" } - Identifier parseIdentifier() + /** + Parses a function-body or similar, expects { to be current token. + + Will consume both the starting { and ending } + */ + Stmt parseCompoundStatement() { - Token identifier = lexer.next; - - switch(identifier.type) - { - case Tok.Identifier: - return new Identifier(identifier); - break; - default: - throw error(__LINE__, "Unexpected token in Identifier parsing. Got %0") - .arg(identifier.getType) - .tok(identifier); - } + 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()); } - Identifier parseType() + 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; - 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.Void, - Tok.Identifier: - return new Identifier(type); - break; - default: - char[] c = type.getType; - error(__LINE__, "Unexpected token in Type parsing. Got %0").arg(c); - } + 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 -- // -private: Exp parseExpIdentifier(Exp target) { switch(lexer.peek.type) @@ -397,12 +190,13 @@ switch(lexer.peek(1).type) { case Tok.Identifier: - lexer.next; - return parseExpIdentifier( - new MemberLookup(target, new Identifier(lexer.next))); + 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 '.'", &t); + throw error(__LINE__, "Expected identifier after '.'").tok(t); } default: return target; @@ -419,7 +213,7 @@ lexer.next(); int q = op.leftAssoc? 1 + op.prec : op.prec; auto exp2 = parseExpression(q); - exp = new BinaryExp(op.operator, exp, exp2); + exp = action.actOnBinaryOp(op.operator, exp, exp2); next = lexer.peek(); } @@ -430,7 +224,7 @@ { Token next = lexer.next(); if (auto op = unary(next.type)) - return new NegateExp(parseExpression(op.prec)); + return action.actOnUnaryOp(next, parseExpression(op.prec)); else if (next.type == Tok.OpenParentheses) { auto e = parseExpression(0); @@ -439,9 +233,11 @@ } else if (next.type == Tok.Identifier) { - Exp iden = parseExpIdentifier(new Identifier(next)); + 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; @@ -455,42 +251,26 @@ } lexer.next(); - return new CallExp(iden, args); + return null;//new CallExp(iden, args); default: return iden; } } else if (next.type == Tok.Integer) - return new IntegerLit(next); + return action.actOnNumericConstant(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}]; + static const UnOp[] _unary = [{Tok.Sub, 4}]; UnOp* unary(Tok t) { foreach (ref op; _unary) @@ -504,23 +284,24 @@ Tok tokenType; int prec; bool leftAssoc; - BinaryExp.Operator operator; + Operator operator; } - static BinOp[] _binary = + static const 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.Eq, 2, true, Operator.Eq}, + {Tok.Ne, 2, true, Operator.Ne}, - {Tok.Add, 3, true, BinaryExp.Operator.Add}, - {Tok.Sub, 3, true, BinaryExp.Operator.Sub}, + {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.Mul, 5, true, BinaryExp.Operator.Mul}, - {Tok.Div, 5, true, BinaryExp.Operator.Div} + {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) { @@ -535,7 +316,7 @@ Token require(Tok t) { if (lexer.peek().type != t) - throw error(__LINE__, UnexpectedTokSingle) + throw error(__LINE__, PE.UnexpectedTokSingle) .arg(lexer.peek.getType) .arg(t); return lexer.next(); @@ -549,28 +330,25 @@ return true; } - Error error(uint line, char[] errMsg, Token* tok = null) + Error error(uint line, char[] errMsg) { - Location loc; - if (tok is null) - loc = lexer.peek.location; - else - loc = tok.location; + Location loc = lexer.peek.location; auto e = new Error("Parser.d(" ~ Integer.toString(line) ~ "): " ~errMsg); e.loc(loc); - if (tok !is null) - e.tok(*tok); return e; } - static char[] - UnexpectedTokMulti = "Unexpected token, got %0 expected one of %1", - UnexpectedTokSingle = "Unexpected token, got %0 expected %1", - UnexpectedTok = "Unexpected token %0"; + 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"; + static char[] + CaseValueMustBeInt = "Cases can only be integer literals"; + } Lexer lexer; }
--- a/sema/SymbolTableBuilder.d Tue Apr 22 22:31:39 2008 +0200 +++ b/sema/SymbolTableBuilder.d Wed Apr 23 00:57:45 2008 +0200 @@ -133,6 +133,14 @@ pop(sc); } + override void visitCompoundStmt(CompoundStatement s) + { + s.env = current(); + auto sc = push(); + super.visitCompoundStmt(s); + pop(sc); + } + private: Scope[] table;
--- a/sema/Visitor.d Tue Apr 22 22:31:39 2008 +0200 +++ b/sema/Visitor.d Wed Apr 23 00:57:45 2008 +0200 @@ -43,6 +43,8 @@ { case StmtType.Return: return visitReturnStmt(cast(ReturnStmt)stmt); + case StmtType.Compound: + return visitCompoundStmt(cast(CompoundStatement)stmt); case StmtType.Decl: return visitDeclStmt(cast(DeclStmt)stmt); case StmtType.Exp: @@ -143,6 +145,16 @@ return StmtT.init; } + StmtT visitCompoundStmt(CompoundStatement c) + { + foreach (stmt; c.statements) + visitStmt(stmt); + static if (is(StmtT == void)) + return; + else + return StmtT.init; + } + StmtT visitIfStmt(IfStmt s) { visitExp(s.cond);