dvander@48: /* vim: set ts=4 sw=4 tw=99 et: dvander@48: * dvander@0: * Copyright (C) 2012 David Anderson dvander@0: * dvander@0: * This file is part of JITCraft. dvander@0: * dvander@0: * JITCraft is free software: you can redistribute it and/or modify it under dvander@0: * the terms of the GNU General Public License as published by the Free dvander@0: * Software Foundation, either version 3 of the License, or (at your option) dvander@0: * any later version. dvander@0: * dvander@0: * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY dvander@0: * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS dvander@0: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. dvander@0: * dvander@0: * You should have received a copy of the GNU General Public License along with dvander@0: * JITCraft. If not, see http://www.gnu.org/licenses/. dvander@0: */ dvander@0: #include "Zone.h" dvander@0: #include "Parser.h" dvander@21: #include "FixedArray.h" dvander@21: #include "Heap.h" dvander@54: #include "Strings.h" dvander@21: #include "Heap-inl.h" dvander@0: dvander@59: using namespace ke; dvander@0: dvander@54: Parser::Parser(Zone *zone, CompileContext &cc, const char *stream, size_t length) dvander@54: : zone_(zone), dvander@54: cc_(cc), dvander@54: pool_(zone_->pool()), dvander@25: scanner_(cc, stream, length), dvander@0: scope_(NULL), dvander@0: unbound_(NULL) dvander@0: { dvander@57: unbound_ = new (pool_) PoolList(); dvander@0: } dvander@0: dvander@0: bool dvander@0: Parser::match(TokenKind kind) dvander@0: { dvander@0: if (scanner_.peek() != kind) dvander@0: return false; dvander@0: scanner_.scan(); dvander@0: return true; dvander@0: } dvander@0: dvander@0: bool dvander@63: Parser::matchSemicolon() dvander@63: { dvander@63: return expect(TOK_SEMICOLON); dvander@63: } dvander@63: dvander@63: bool dvander@0: Parser::expect(TokenKind kind) dvander@0: { dvander@0: TokenKind got = scanner_.scan(); dvander@0: if (got == kind) dvander@0: return true; dvander@25: cc_.reportError(scanner_.begin(), Message_WrongToken, TokenNames[kind], TokenNames[got]); dvander@0: return false; dvander@0: } dvander@0: dvander@0: Scope * dvander@0: Parser::enterScope(Scope::Kind kind) dvander@0: { dvander@0: scope_ = new (pool_) Scope(pool_, kind, scope_); dvander@0: if (!scope_->initialize()) dvander@0: return NULL; dvander@0: return scope_; dvander@0: } dvander@0: dvander@0: NameProxy * dvander@54: Parser::bind(Handle name) dvander@0: { dvander@0: BoundName *bound = scope_->lookup(name); dvander@25: NameProxy *proxy = new (pool_) NameProxy(scanner_.begin(), name, bound); dvander@57: if (!bound && !unbound_->append(proxy)) dvander@57: return NULL; dvander@0: return proxy; dvander@0: } dvander@0: dvander@4: bool dvander@54: Parser::matchName(String **name, TokenKind kind) dvander@4: { dvander@4: assert(kind == TOK_NAME || kind == TOK_LABEL); dvander@4: *name = NULL; dvander@4: if (!match(kind)) dvander@4: return false; dvander@54: *name = zone_->makeSymbol(scanner_.literal(), scanner_.literal_length()); dvander@4: return true; dvander@4: } dvander@4: dvander@54: String * dvander@4: Parser::expectName() dvander@4: { dvander@4: if (!expect(TOK_NAME)) dvander@4: return NULL; dvander@54: return zone_->makeSymbol(scanner_.literal(), scanner_.literal_length()); dvander@4: } dvander@4: dvander@25: void dvander@25: Parser::redeclarationError(BoundName *other) dvander@25: { dvander@63: cc_.reportError(scanner_.begin(), Message_RedeclaredName, other->name()->chars(), dvander@63: other->pos().line, other->pos().col); dvander@25: } dvander@25: dvander@0: Expression * dvander@0: Parser::primitive() dvander@0: { dvander@25: TokenKind kind = scanner_.peek(); dvander@25: switch (kind) { dvander@0: case TOK_NAME: dvander@0: { dvander@54: Local name(zone_, expectName()); dvander@54: if (!name) dvander@54: return NULL; dvander@0: return bind(name); dvander@0: } dvander@0: dvander@4: case TOK_FLOAT_LITERAL: dvander@4: { dvander@4: scanner_.scan(); dvander@4: double value = Scanner::ParseDouble(scanner_.literal()); dvander@25: return new (pool_) FloatLiteral(scanner_.begin(), value); dvander@4: } dvander@4: dvander@0: case TOK_INTEGER_LITERAL: dvander@0: { dvander@0: scanner_.scan(); dvander@0: int value = atoi(scanner_.literal()); dvander@25: return new (pool_) IntegerLiteral(scanner_.begin(), value); dvander@0: } dvander@0: dvander@21: case TOK_STRING_LITERAL: dvander@21: { dvander@21: scanner_.scan(); dvander@54: Local array(zone_, ByteArray::New(zone_, scanner_.literal_length() + 1)); dvander@21: if (!array) dvander@21: return NULL; dvander@54: memcpy(array->raw(), scanner_.literal(), scanner_.literal_length() + 1); dvander@25: return new (pool_) StringLiteral(scanner_.begin(), array); dvander@21: } dvander@21: dvander@0: default: dvander@0: { dvander@25: if (kind != TOK_ERROR) dvander@25: cc_.reportError(scanner_.begin(), Message_ExpectedExpression, TokenNames[kind]); dvander@0: return NULL; dvander@0: } dvander@0: } dvander@0: } dvander@0: dvander@0: Expression * dvander@0: Parser::prefix() dvander@0: { dvander@0: switch (scanner_.peek()) { dvander@0: case TOK_LPAREN: dvander@0: { dvander@0: scanner_.scan(); dvander@0: Expression *expr = expression(); dvander@0: if (!expr) dvander@0: return NULL; dvander@0: if (!expect(TOK_RPAREN)) dvander@0: return NULL; dvander@0: return expr; dvander@0: } dvander@0: dvander@0: default: dvander@0: return primitive(); dvander@0: } dvander@0: } dvander@0: dvander@0: Expression * dvander@0: Parser::call(Expression *callee) dvander@0: { dvander@56: ExpressionList *arguments = new (pool_) ExpressionList(); dvander@0: dvander@25: SourcePosition pos = scanner_.begin(); dvander@0: expect(TOK_LPAREN); dvander@0: dvander@0: if (!match(TOK_RPAREN)) { dvander@0: while (true) { dvander@0: Expression *expr = expression(); dvander@0: if (!expr) dvander@0: return NULL; dvander@0: dvander@55: if (!arguments->append(expr)) dvander@55: return NULL; dvander@0: dvander@0: if (!match(TOK_COMMA)) dvander@0: break; dvander@0: } dvander@0: dvander@0: if (!expect(TOK_RPAREN)) dvander@0: return NULL; dvander@0: } dvander@0: dvander@25: return new (pool_) CallExpression(pos, callee, arguments); dvander@0: } dvander@0: dvander@0: Expression * dvander@0: Parser::index(Expression *left) dvander@0: { dvander@0: expect(TOK_LBRACKET); dvander@0: dvander@25: SourcePosition pos = scanner_.begin(); dvander@0: Expression *expr = expression(); dvander@0: if (!expr) dvander@0: return NULL; dvander@0: dvander@0: if (!expect(TOK_RBRACKET)) dvander@0: return NULL; dvander@0: dvander@25: return new (pool_) IndexExpression(pos, left, expr); dvander@0: } dvander@0: dvander@0: Expression * dvander@0: Parser::primary() dvander@0: { dvander@0: Expression *expr = prefix(); dvander@0: if (!expr) dvander@0: return NULL; dvander@0: dvander@0: for (;;) { dvander@0: switch (scanner_.peek()) { dvander@0: case TOK_LPAREN: dvander@0: expr = call(expr); dvander@0: if (!expr) dvander@0: return NULL; dvander@0: break; dvander@0: dvander@0: case TOK_LBRACKET: dvander@0: expr = index(expr); dvander@0: if (!expr) dvander@0: return NULL; dvander@0: break; dvander@0: dvander@0: default: dvander@0: return expr; dvander@0: } dvander@0: } dvander@0: } dvander@0: dvander@0: Expression * dvander@0: Parser::unary() dvander@0: { dvander@23: TokenKind token = scanner_.peek(); dvander@23: dvander@25: SourcePosition pos = scanner_.begin(); dvander@23: switch (token) { dvander@23: case TOK_INCREMENT: dvander@23: case TOK_DECREMENT: dvander@23: { dvander@23: scanner_.scan(); dvander@23: Expression *expr = expression(); dvander@23: if (!expr) dvander@23: return NULL; dvander@23: dvander@25: return new (pool_) IncDecExpression(pos, token, expr, false); dvander@23: } dvander@28: default: dvander@28: break; dvander@23: } dvander@23: dvander@25: dvander@23: Expression *expr = primary(); dvander@23: dvander@23: token = scanner_.peek(); dvander@23: if (token == TOK_INCREMENT || token == TOK_DECREMENT) { dvander@23: scanner_.scan(); dvander@25: return new (pool_) IncDecExpression(pos, token, expr, true); dvander@23: } dvander@23: dvander@23: return expr; dvander@0: } dvander@0: dvander@0: Expression * dvander@0: Parser::multiplication() dvander@0: { dvander@0: Expression *left = unary(); dvander@0: do { dvander@0: if (!match(TOK_SLASH) && !match(TOK_STAR)) dvander@0: break; dvander@25: SourcePosition pos = scanner_.begin(); dvander@0: TokenKind kind = scanner_.last(); dvander@0: Expression *right = unary(); dvander@0: if (!right) dvander@0: return NULL; dvander@25: left = new (pool_) BinaryExpression(pos, kind, left, right); dvander@0: } while (left); dvander@0: return left; dvander@0: } dvander@0: dvander@0: Expression * dvander@0: Parser::addition() dvander@0: { dvander@0: Expression *left = multiplication(); dvander@0: while (left) { dvander@0: if (!match(TOK_PLUS) && !match(TOK_MINUS)) dvander@0: break; dvander@25: SourcePosition pos = scanner_.begin(); dvander@0: TokenKind kind = scanner_.last(); dvander@0: Expression *right = multiplication(); dvander@0: if (!right) dvander@0: return NULL; dvander@25: left = new (pool_) BinaryExpression(pos, kind, left, right); dvander@0: } dvander@0: return left; dvander@0: } dvander@0: dvander@0: Expression * dvander@2: Parser::shift() dvander@2: { dvander@2: Expression *left = addition(); dvander@2: while (left) { dvander@8: if (!match(TOK_SHL) && !match(TOK_SHR) && !match(TOK_USHR)) dvander@2: break; dvander@25: SourcePosition pos = scanner_.begin(); dvander@2: TokenKind kind = scanner_.last(); dvander@2: Expression *right = addition(); dvander@2: if (!right) dvander@2: return NULL; dvander@25: left = new (pool_) BinaryExpression(pos, kind, left, right); dvander@2: } dvander@2: return left; dvander@2: } dvander@2: dvander@2: Expression * dvander@28: Parser::bitand_() dvander@8: { dvander@8: Expression *left = shift(); dvander@8: while (left) { dvander@8: if (!match(TOK_BITAND)) dvander@8: break; dvander@25: SourcePosition pos = scanner_.begin(); dvander@8: Expression *right = shift(); dvander@8: if (!right) dvander@8: return NULL; dvander@25: left = new (pool_) BinaryExpression(pos, TOK_BITAND, left, right); dvander@8: } dvander@8: return left; dvander@8: } dvander@8: dvander@8: Expression * dvander@8: Parser::bitxor() dvander@8: { dvander@28: Expression *left = bitand_(); dvander@8: while (left) { dvander@8: if (!match(TOK_BITXOR)) dvander@8: break; dvander@25: SourcePosition pos = scanner_.begin(); dvander@8: Expression *right = shift(); dvander@8: if (!right) dvander@8: return NULL; dvander@25: left = new (pool_) BinaryExpression(pos, TOK_BITXOR, left, right); dvander@8: } dvander@8: return left; dvander@8: } dvander@8: dvander@8: Expression * dvander@28: Parser::bitor_() dvander@8: { dvander@8: Expression *left = bitxor(); dvander@8: while (left) { dvander@8: if (!match(TOK_BITOR)) dvander@8: break; dvander@25: SourcePosition pos = scanner_.begin(); dvander@8: Expression *right = shift(); dvander@8: if (!right) dvander@8: return NULL; dvander@25: left = new (pool_) BinaryExpression(pos, TOK_BITOR, left, right); dvander@8: } dvander@8: return left; dvander@8: } dvander@8: dvander@8: Expression * dvander@0: Parser::relational() dvander@0: { dvander@28: Expression *left = bitor_(); dvander@0: while (left) { dvander@0: TokenKind kind = scanner_.peek(); dvander@0: if (kind < TOK_LT || kind > TOK_GE) dvander@0: break; dvander@0: scanner_.scan(); dvander@25: SourcePosition pos = scanner_.begin(); dvander@2: Expression *right = shift(); dvander@0: if (!right) dvander@0: return NULL; dvander@25: left = new (pool_) BinaryExpression(pos, kind, left, right); dvander@0: } dvander@0: return left; dvander@0: } dvander@0: dvander@0: Expression * dvander@0: Parser::equals() dvander@0: { dvander@0: Expression *left = relational(); dvander@0: while (left) { dvander@0: if (!match(TOK_EQUALS) && !match(TOK_NOTEQUALS)) dvander@0: break; dvander@0: TokenKind kind = scanner_.last(); dvander@25: SourcePosition pos = scanner_.begin(); dvander@0: Expression *right = relational(); dvander@0: if (!right) dvander@0: return NULL; dvander@25: left = new (pool_) BinaryExpression(pos, kind, left, right); dvander@0: } dvander@0: return left; dvander@0: } dvander@0: dvander@0: Expression * dvander@22: Parser::assignment() dvander@22: { dvander@22: Expression *left = equals(); dvander@22: while (left) { dvander@22: TokenKind token = scanner_.peek(); dvander@22: if (token != TOK_ASSIGN && (token < TOK_ASSIGN_ADD || token > TOK_ASSIGN_SHL)) dvander@22: break; dvander@22: scanner_.scan(); dvander@25: SourcePosition pos = scanner_.begin(); dvander@22: Expression *expr = equals(); dvander@22: if (!expr) dvander@22: return NULL; dvander@22: dvander@25: left = new (pool_) Assignment(pos, token, left, expr); dvander@22: } dvander@22: return left; dvander@22: } dvander@22: dvander@22: Expression * dvander@0: Parser::expression() dvander@0: { dvander@22: return assignment(); dvander@0: } dvander@0: dvander@0: Statement * dvander@9: Parser::while_() dvander@9: { dvander@25: SourcePosition pos = scanner_.begin(); dvander@9: scanner_.scan(); dvander@9: dvander@9: if (!expect(TOK_LPAREN)) dvander@9: return NULL; dvander@25: dvander@9: Expression *condition = expression(); dvander@9: if (!condition) dvander@9: return NULL; dvander@25: dvander@9: if (!expect(TOK_RPAREN)) dvander@9: return NULL; dvander@9: dvander@48: // Inside a loop, we force the creation of a scope object. Normally, we dvander@48: // will cull scopes if they have no variables. However inside a loop, dvander@48: // function calls that take references may compute a LIFO object, and to dvander@48: // avoid temporarily leaking many such objects, we ensure that a scope dvander@48: // is present so a LIFO slot can be allocated. dvander@48: if (!enterScope(Scope::BLOCK)) dvander@48: return NULL; dvander@48: dvander@48: Statement *body; dvander@48: if (scanner_.peek() == TOK_LBRACE) dvander@48: body = block(scope_); dvander@48: else dvander@48: body = localStatement(); dvander@9: if (!body) dvander@9: return NULL; dvander@9: dvander@48: scope_ = scope_->enclosing(); dvander@25: return new (pool_) WhileStatement(pos, TOK_WHILE, condition, body); dvander@9: } dvander@9: dvander@9: Statement * dvander@9: Parser::do_() dvander@9: { dvander@25: SourcePosition pos = scanner_.begin(); dvander@9: scanner_.scan(); dvander@9: dvander@48: // See the comment in ::while_() as to why we force a scope. dvander@48: if (!enterScope(Scope::BLOCK)) dvander@48: return NULL; dvander@48: dvander@48: Statement *body; dvander@48: if (scanner_.peek() == TOK_LBRACE) dvander@48: body = block(scope_); dvander@48: else dvander@48: body = localStatement(); dvander@9: if (!body) dvander@9: return NULL; dvander@9: dvander@48: scope_ = scope_->enclosing(); dvander@48: dvander@9: if (!expect(TOK_WHILE)) dvander@9: return NULL; dvander@9: dvander@9: if (!expect(TOK_LPAREN)) dvander@9: return NULL; dvander@9: Expression *condition = expression(); dvander@9: if (!condition) dvander@9: return NULL; dvander@9: if (!expect(TOK_RPAREN)) dvander@9: return NULL; dvander@9: dvander@25: return new (pool_) WhileStatement(pos, TOK_DO, condition, body); dvander@9: } dvander@9: dvander@9: Statement * dvander@0: Parser::forStatement() dvander@0: { dvander@25: SourcePosition pos = scanner_.begin(); dvander@0: scanner_.scan(); dvander@0: if (!expect(TOK_LPAREN)) dvander@0: return NULL; dvander@0: dvander@22: Statement *decl = NULL; dvander@0: if (!match(TOK_SEMICOLON)) { dvander@22: if (scanner_.peek() == TOK_NEW) { dvander@22: if (!enterScope(Scope::BLOCK)) dvander@22: return NULL; dvander@22: if ((decl = variableDeclaration()) == NULL) dvander@22: return NULL; dvander@22: } else { dvander@22: if ((decl = expressionStatement()) == NULL) dvander@22: return NULL; dvander@22: } dvander@0: if (!expect(TOK_SEMICOLON)) dvander@0: return NULL; dvander@0: } dvander@0: dvander@0: Expression *condition = NULL; dvander@0: if (!match(TOK_SEMICOLON)) { dvander@0: if ((condition = expression()) == NULL) dvander@0: return NULL; dvander@0: if (!expect(TOK_SEMICOLON)) dvander@0: return NULL; dvander@0: } dvander@0: dvander@0: Statement *update = NULL; dvander@0: if (!match(TOK_RPAREN)) { dvander@0: if ((update = expressionStatement()) == NULL) dvander@0: return NULL; dvander@0: if (!expect(TOK_RPAREN)) dvander@0: return NULL; dvander@0: } dvander@0: dvander@48: // See the comment in ::while_() as to why we force a scope. dvander@48: if (!enterScope(Scope::BLOCK)) dvander@48: return NULL; dvander@48: dvander@48: Statement *body; dvander@48: if (scanner_.peek() == TOK_LBRACE) dvander@48: body = block(scope_); dvander@48: else dvander@48: body = localStatement(); dvander@0: if (!body) dvander@0: return NULL; dvander@0: dvander@48: scope_ = scope_->enclosing(); dvander@48: dvander@48: Scope *declScope = NULL; dvander@22: if (decl && decl->isVariableDeclaration()) { dvander@48: declScope = scope_->unlinkIfEmpty(); dvander@0: scope_ = scope_->enclosing(); dvander@0: } dvander@48: return new (pool_) ForStatement(pos, declScope, decl, condition, update, body); dvander@0: } dvander@0: dvander@0: VariableDeclaration * dvander@0: Parser::variableDeclaration() dvander@0: { dvander@0: if (!expect(TOK_NEW)) dvander@0: return NULL; dvander@0: dvander@54: Local tag(zone_); dvander@54: if (matchName(tag.ref(), TOK_LABEL) && !tag) dvander@0: return NULL; dvander@4: dvander@54: Local name(zone_, expectName()); dvander@4: if (!name) dvander@4: return NULL; dvander@0: dvander@25: if (BoundName *other = scope_->localLookup(name)) { dvander@25: redeclarationError(other); dvander@25: return NULL; dvander@25: } dvander@25: dvander@25: Variable *var = scope_->declareVariable(name, scanner_.begin()); dvander@25: if (!var) dvander@25: return NULL; dvander@25: dvander@0: ExpressionList *postDimensions = NULL; dvander@0: if (scanner_.peek() == TOK_LBRACKET) { dvander@56: postDimensions = new (pool_) ExpressionList(); dvander@0: while (match(TOK_LBRACKET)) { dvander@0: Expression *dim = expression(); dvander@0: if (!dim) dvander@0: return NULL; dvander@0: dvander@0: if (!expect(TOK_RBRACKET)) dvander@0: return NULL; dvander@0: dvander@55: if (!postDimensions->append(dim)) dvander@55: return NULL; dvander@0: } dvander@0: } dvander@0: dvander@0: Expression *expr = NULL; dvander@0: if (match(TOK_ASSIGN)) { dvander@0: if ((expr = expression()) == NULL) dvander@0: return NULL; dvander@0: } dvander@0: dvander@25: return new (pool_) VariableDeclaration(var->pos(), var, tag, postDimensions, expr); dvander@0: } dvander@0: dvander@0: Statement * dvander@0: Parser::returnStatement() dvander@0: { dvander@25: SourcePosition pos = scanner_.begin(); dvander@0: if (!expect(TOK_RETURN)) dvander@0: return NULL; dvander@0: dvander@0: Expression *expr = expression(); dvander@0: if (!expr) dvander@0: return NULL; dvander@0: dvander@25: return new (pool_) ReturnStatement(pos, expr); dvander@0: } dvander@0: dvander@0: Statement * dvander@0: Parser::expressionStatement() dvander@0: { dvander@22: Expression *left = assignment(); dvander@21: if (!left) dvander@0: return NULL; dvander@0: dvander@0: return new (pool_) ExpressionStatement(left); dvander@0: } dvander@0: dvander@0: Statement * dvander@48: Parser::block(Scope *scope) dvander@0: { dvander@0: if (!expect(TOK_LBRACE)) dvander@0: return NULL; dvander@0: dvander@25: SourcePosition pos = scanner_.begin(); dvander@48: if (!scope && !enterScope(Scope::BLOCK)) dvander@0: return NULL; dvander@0: dvander@0: StatementList *statements = new (pool_) StatementList(); dvander@0: while (!match(TOK_RBRACE)) { dvander@0: Statement *statement = localStatement(); dvander@0: if (statement == NULL) dvander@0: return NULL; dvander@56: if (!statements->append(statement)) dvander@56: return NULL; dvander@0: } dvander@0: dvander@48: if (!scope) { dvander@48: scope = scope_->unlinkIfEmpty(); dvander@48: scope_ = scope_->enclosing(); dvander@48: } dvander@48: BlockStatement *block = new (pool_) BlockStatement(pos, scope, statements); dvander@0: return block; dvander@0: } dvander@0: dvander@0: Statement * dvander@0: Parser::if_() dvander@0: { dvander@0: expect(TOK_IF); dvander@25: dvander@25: SourcePosition pos = scanner_.begin(); dvander@0: if (!expect(TOK_LPAREN)) dvander@0: return NULL; dvander@0: dvander@0: Expression *cond = expression(); dvander@0: if (!cond) dvander@0: return NULL; dvander@0: dvander@0: if (!expect(TOK_RPAREN)) dvander@0: return NULL; dvander@0: dvander@0: Statement *ifTrue = localStatement(); dvander@0: if (!ifTrue) dvander@0: return NULL; dvander@0: dvander@25: IfStatement *outer = new (pool_) IfStatement(pos, cond, ifTrue); dvander@0: dvander@0: IfStatement *last = outer; dvander@0: while (match(TOK_ELSE)) { dvander@0: if (!match(TOK_IF)) { dvander@0: Statement *ifFalse = localStatement(); dvander@0: if (!ifFalse) dvander@0: return NULL; dvander@0: dvander@0: last->setIfFalse(ifFalse); dvander@0: break; dvander@0: } dvander@0: dvander@0: if (!expect(TOK_IF)) dvander@28: return NULL; dvander@0: dvander@25: SourcePosition pos = scanner_.begin(); dvander@0: if (!expect(TOK_LPAREN)) dvander@0: return NULL; dvander@0: dvander@0: Expression *otherCond = expression(); dvander@0: if (!otherCond) dvander@0: return NULL; dvander@0: dvander@0: if (!expect(TOK_RPAREN)) dvander@0: return NULL; dvander@0: dvander@0: Statement *otherIfTrue = localStatement(); dvander@0: if (!otherIfTrue) dvander@0: return NULL; dvander@0: dvander@25: IfStatement *inner = new (pool_) IfStatement(pos, otherCond, otherIfTrue); dvander@0: last->setIfFalse(inner); dvander@0: last = inner; dvander@0: } dvander@0: dvander@0: return outer; dvander@0: } dvander@0: dvander@0: Statement * dvander@0: Parser::localStatement() dvander@0: { dvander@0: Statement *statement = NULL; dvander@0: dvander@0: // Statements which must be followed by a semicolon will break out of the dvander@0: // switch. If they may end in BlockStatements, they'll immediately return. dvander@0: dvander@0: switch (scanner_.peek()) { dvander@0: case TOK_NEW: dvander@21: if ((statement = variableDeclaration()) == NULL) dvander@21: return NULL; dvander@0: break; dvander@0: dvander@0: case TOK_FOR: dvander@0: return forStatement(); dvander@0: dvander@9: case TOK_WHILE: dvander@9: return while_(); dvander@9: dvander@10: case TOK_BREAK: dvander@10: scanner_.scan(); dvander@25: statement = new (pool_) BreakStatement(scanner_.begin()); dvander@10: break; dvander@10: dvander@10: case TOK_CONTINUE: dvander@10: scanner_.scan(); dvander@25: statement = new (pool_) ContinueStatement(scanner_.begin()); dvander@10: break; dvander@10: dvander@9: case TOK_DO: dvander@9: if ((statement = do_()) == NULL) dvander@9: return NULL; dvander@9: break; dvander@9: dvander@0: case TOK_RETURN: dvander@21: if ((statement = returnStatement()) == NULL) dvander@21: return NULL; dvander@0: break; dvander@0: dvander@2: case TOK_ENUM: dvander@21: if ((statement = enum_()) == NULL) dvander@21: return NULL; dvander@2: break; dvander@2: dvander@0: case TOK_IF: dvander@0: return if_(); dvander@0: dvander@0: case TOK_LBRACE: dvander@0: return block(); dvander@28: dvander@28: default: dvander@28: break; dvander@0: } dvander@0: dvander@0: if (!statement) { dvander@0: if ((statement = expressionStatement()) == NULL) dvander@0: return NULL; dvander@0: } dvander@0: dvander@0: if (!expect(TOK_SEMICOLON)) dvander@0: return NULL; dvander@0: dvander@0: return statement; dvander@0: } dvander@0: dvander@0: Statement * dvander@2: Parser::enum_() dvander@2: { dvander@2: expect(TOK_ENUM); dvander@2: dvander@25: SourcePosition pos = scanner_.begin(); dvander@25: dvander@54: Local name(zone_); dvander@54: if (matchName(name.ref())) { dvander@54: if (!name) dvander@2: return NULL; dvander@2: dvander@25: if (BoundName *other = scope_->localLookup(name)) { dvander@25: redeclarationError(other); dvander@2: return NULL; dvander@2: } dvander@2: dvander@25: if (!scope_->declareEnum(name, scanner_.begin())) dvander@2: return NULL; dvander@2: } dvander@2: dvander@57: EnumStatement::EntryList *entries = new (pool_) EnumStatement::EntryList(); dvander@2: dvander@2: if (!expect(TOK_LBRACE)) dvander@2: return NULL; dvander@2: dvander@2: do { dvander@2: if (scanner_.peek() == TOK_RBRACE) dvander@2: break; dvander@2: dvander@54: Local name(zone_, expectName()); dvander@2: if (!name) dvander@2: return NULL; dvander@2: dvander@25: if (BoundName *other = scope_->localLookup(name)) { dvander@25: redeclarationError(other); dvander@2: return NULL; dvander@2: } dvander@2: dvander@25: NamedConstant *constant = scope_->declareConstant(name, scanner_.begin()); dvander@2: if (!constant) dvander@2: return NULL; dvander@2: dvander@2: Expression *expr = NULL; dvander@2: if (match(TOK_ASSIGN)) { dvander@2: if ((expr = expression()) == NULL) dvander@2: return NULL; dvander@2: } dvander@2: dvander@57: if (!entries->append(EnumStatement::Entry(constant, expr))) dvander@57: return NULL; dvander@2: } while (match(TOK_COMMA)); dvander@2: if (!expect(TOK_RBRACE)) dvander@2: return NULL; dvander@2: dvander@25: return new (pool_) EnumStatement(pos, name, entries); dvander@2: } dvander@2: dvander@2: Statement * dvander@63: Parser::function(TokenKind token) dvander@0: { dvander@54: Local name(zone_, expectName()); dvander@0: if (!name) dvander@0: return NULL; dvander@0: dvander@25: SourcePosition pos = scanner_.begin(); dvander@25: dvander@0: // The function name goes into the outer (global) scope. dvander@0: assert(!scope_->enclosing()); dvander@0: dvander@63: NamedFunction *fun; dvander@25: if (BoundName *other = scope_->localLookup(name)) { dvander@63: // We allow a redeclaration if the new type is a public, and the old dvander@63: // type was a forward. However, the forward must come first. dvander@63: if (other->kind() != BoundName::FUNCTION) { dvander@63: redeclarationError(other); dvander@63: return NULL; dvander@63: } dvander@63: dvander@63: fun = other->toNamedFunction(); dvander@63: if (!fun->isForward() || token != TOK_PUBLIC) { dvander@63: redeclarationError(other); dvander@63: return NULL; dvander@63: } dvander@63: dvander@63: // We've got the same name, but the original is a forward, so let it dvander@63: // slide and re-use the original declaration. dvander@63: fun->setImplemented(scanner_.begin()); dvander@63: } else { dvander@63: fun = scope_->declareFunction(name, scanner_.begin(), token); dvander@63: if (!fun) dvander@63: return NULL; dvander@0: } dvander@0: dvander@0: Scope *scope = enterScope(Scope::FUNCTION); dvander@0: if (!scope) dvander@0: return NULL; dvander@0: dvander@57: ParameterList *parameters = new (pool_) ParameterList(); dvander@14: dvander@0: if (!expect(TOK_LPAREN)) dvander@0: return NULL; dvander@0: if (!match(TOK_RPAREN)) { dvander@0: while (true) { dvander@14: bool ref = match(TOK_AMPERSAND); dvander@14: dvander@54: Local name(zone_, expectName()); dvander@0: if (!name) dvander@0: return NULL; dvander@0: dvander@25: if (BoundName *other = scope_->localLookup(name)) { dvander@25: redeclarationError(other); dvander@0: return NULL; dvander@0: } dvander@25: Variable *arg = scope_->declareArgument(name, scanner_.begin()); dvander@14: if (!arg) dvander@0: return NULL; dvander@0: dvander@54: Local tag(zone_); dvander@54: Parameter *parameter = new (pool_) Parameter(arg, tag, ref); dvander@57: if (!parameters->append(parameter)) dvander@57: return NULL; dvander@14: dvander@0: if (!match(TOK_COMMA)) dvander@0: break; dvander@0: } dvander@0: if (!expect(TOK_RPAREN)) dvander@0: return NULL; dvander@0: } dvander@0: dvander@63: Statement *body = NULL; dvander@63: if (token != TOK_FORWARD) { dvander@63: body = block(); dvander@63: if (!body) dvander@63: return NULL; dvander@63: } dvander@0: dvander@0: scope_ = scope_->enclosing(); dvander@25: return new (pool_) FunctionStatement(pos, scope, fun, body, parameters); dvander@0: } dvander@0: dvander@0: ParseTree * dvander@0: Parser::parse() dvander@0: { dvander@0: StatementList *statements = new (pool_) StatementList(); dvander@0: dvander@0: if (!enterScope(Scope::GLOBAL)) dvander@0: return NULL; dvander@0: dvander@0: for (;;) { dvander@0: Statement *statement = NULL; dvander@0: dvander@0: switch (scanner_.peek()) { dvander@0: case TOK_ERROR: dvander@0: return NULL; dvander@0: dvander@0: case TOK_EOF: dvander@0: break; dvander@0: dvander@0: case TOK_NAME: dvander@63: if ((statement = function(TOK_NAME)) == NULL) dvander@0: return NULL; dvander@0: break; dvander@0: dvander@63: case TOK_FORWARD: dvander@63: case TOK_PUBLIC: dvander@63: { dvander@63: TokenKind kind = scanner_.scan(); dvander@63: if ((statement = function(kind)) == NULL) dvander@63: return NULL; dvander@63: if (kind == TOK_FORWARD && !matchSemicolon()) dvander@63: return NULL; dvander@63: break; dvander@63: } dvander@63: dvander@2: case TOK_ENUM: dvander@2: if ((statement = enum_()) == NULL) dvander@2: return NULL; dvander@63: if (!matchSemicolon()) dvander@63: return NULL; dvander@2: break; dvander@2: dvander@0: default: dvander@63: cc_.reportError(scanner_.begin(), Message_ExpectedGlobal); dvander@0: return NULL; dvander@0: } dvander@0: dvander@0: if (!statement) dvander@0: break; dvander@0: dvander@56: if (!statements->append(statement)) dvander@56: return NULL; dvander@0: } dvander@0: dvander@0: return new (pool_) ParseTree(scope_, statements, unbound_); dvander@0: } dvander@0: dvander@0: class AstPrinter : public AstVisitor dvander@0: { dvander@0: FILE *fp_; dvander@0: size_t level_; dvander@0: dvander@0: private: dvander@0: void prefix() { dvander@0: for (size_t i = 0; i < level_; i++) dvander@0: fprintf(fp_, " "); dvander@0: } dvander@0: void indent() { dvander@0: level_++; dvander@0: } dvander@0: void unindent() { dvander@0: level_--; dvander@0: } dvander@0: dvander@0: public: dvander@0: AstPrinter(FILE *fp) dvander@0: : fp_(fp), dvander@0: level_(0) dvander@0: { dvander@0: } dvander@0: dvander@0: void visit(NameProxy *name) { dvander@0: prefix(); dvander@54: fprintf(fp_, "[ NameProxy (%s)%s\n", name->name()->chars(), dvander@0: (name->binding() ? "" : " unbound")); dvander@0: } dvander@0: void visit(CallExpression *node) { dvander@0: prefix(); dvander@0: fprintf(fp_, "[ CallExpression\n"); dvander@0: indent(); dvander@0: node->callee()->accept(this); dvander@55: for (size_t i = 0; i < node->arguments()->length(); i++) dvander@0: node->arguments()->at(i)->accept(this); dvander@0: unindent(); dvander@0: } dvander@0: void visit(FunctionStatement *node) { dvander@0: prefix(); dvander@54: fprintf(fp_, "[ FunctionStatement (%s)\n", node->fun()->name()->chars()); dvander@0: indent(); dvander@63: if (node->body()) dvander@63: node->body()->accept(this); dvander@0: unindent(); dvander@0: } dvander@0: void visit(ExpressionStatement *node) { dvander@0: prefix(); dvander@0: fprintf(fp_, "[ ExpressionStatement\n"); dvander@0: indent(); dvander@0: node->expression()->accept(this); dvander@0: unindent(); dvander@0: } dvander@0: void visit(Assignment *node) { dvander@0: prefix(); dvander@0: fprintf(fp_, "[ Assignment\n"); dvander@0: indent(); dvander@0: node->lvalue()->accept(this); dvander@0: node->expression()->accept(this); dvander@0: unindent(); dvander@0: } dvander@0: void visit(BinaryExpression *node) { dvander@0: prefix(); dvander@0: fprintf(fp_, "[ BinaryExpression (%s)\n", TokenNames[node->token()]); dvander@0: indent(); dvander@0: node->left()->accept(this); dvander@0: node->right()->accept(this); dvander@0: unindent(); dvander@0: } dvander@0: void visit(ReturnStatement *node) { dvander@0: prefix(); dvander@0: fprintf(fp_, "[ ReturnStatement\n"); dvander@0: indent(); dvander@0: node->expression()->accept(this); dvander@0: unindent(); dvander@0: } dvander@0: void visit(ForStatement *node) { dvander@0: prefix(); dvander@0: fprintf(fp_, "[ ForStatement\n"); dvander@0: indent(); dvander@22: if (node->initialization()) dvander@22: node->initialization()->accept(this); dvander@0: if (node->condition()) dvander@0: node->condition()->accept(this); dvander@0: if (node->update()) dvander@0: node->update()->accept(this); dvander@0: node->body()->accept(this); dvander@0: unindent(); dvander@0: } dvander@0: void visit(BlockStatement *node) { dvander@0: prefix(); dvander@0: fprintf(fp_, "[ BlockStatement\n"); dvander@0: indent(); dvander@0: for (size_t i = 0; i < node->statements()->length(); i++) dvander@0: node->statements()->at(i)->accept(this); dvander@0: unindent(); dvander@0: } dvander@0: void visit(VariableDeclaration *node) { dvander@0: prefix(); dvander@54: fprintf(fp_, "[ VariableDeclaration (%s)\n", node->variable()->name()->chars()); dvander@0: indent(); dvander@0: if (node->initialization()) dvander@0: node->initialization()->accept(this); dvander@0: unindent(); dvander@0: } dvander@4: void visit(IntegerLiteral *node) { dvander@0: prefix(); dvander@4: fprintf(fp_, "[ IntegerLiteral (%d)\n", node->value()); dvander@4: } dvander@4: void visit(FloatLiteral *node) { dvander@4: prefix(); dvander@4: fprintf(fp_, "[ FloatLiteral (%f)\n", node->value()); dvander@0: } dvander@0: void visit(IfStatement *node) { dvander@0: prefix(); dvander@0: fprintf(fp_, "[ IfStatement\n"); dvander@0: indent(); dvander@0: node->ifTrue()->accept(this); dvander@0: if (node->ifFalse()) dvander@0: node->ifFalse()->accept(this); dvander@0: unindent(); dvander@0: } dvander@0: void visit(IndexExpression *node) { dvander@0: prefix(); dvander@0: fprintf(fp_, "[ IndexExpression\n"); dvander@0: indent(); dvander@0: node->left()->accept(this); dvander@0: node->right()->accept(this); dvander@0: unindent(); dvander@0: } dvander@2: void visit(EnumStatement *node) { dvander@2: prefix(); dvander@54: fprintf(fp_, "[ EnumStatement (%s)\n", node->name() ? node->name()->chars() : ""); dvander@2: indent(); dvander@57: for (size_t i = 0; i < node->entries()->length(); i++) { dvander@2: prefix(); dvander@54: fprintf(fp_, "%s =\n", node->entries()->at(i).name->name()->chars()); dvander@2: if (node->entries()->at(i).expr) { dvander@2: indent(); dvander@2: node->entries()->at(i).expr->accept(this); dvander@2: unindent(); dvander@2: } dvander@2: } dvander@2: unindent(); dvander@2: } dvander@9: void visit(WhileStatement *node) { dvander@9: prefix(); dvander@9: fprintf(fp_, "[ WhileStatement (%s)\n", dvander@9: (node->token() == TOK_DO) ? "do" : "while"); dvander@9: indent(); dvander@9: if (node->token() == TOK_DO) { dvander@9: node->condition()->accept(this); dvander@9: node->body()->accept(this); dvander@9: } else { dvander@9: node->condition()->accept(this); dvander@9: node->body()->accept(this); dvander@9: } dvander@9: unindent(); dvander@9: } dvander@10: void visit(BreakStatement *node) { dvander@10: prefix(); dvander@10: fprintf(fp_, "[ BreakStatement\n"); dvander@10: } dvander@10: void visit(ContinueStatement *node) { dvander@10: prefix(); dvander@10: fprintf(fp_, "[ ContinueStatement\n"); dvander@10: } dvander@21: void visit(StringLiteral *node) { dvander@21: prefix(); dvander@21: fprintf(fp_, "[ StringLiteral\n"); dvander@21: } dvander@23: void visit(IncDecExpression *node) { dvander@23: prefix(); dvander@23: fprintf(fp_, "[ IncDecExpression (postfix=%d)\n", node->postfix()); dvander@23: indent(); dvander@23: node->expression()->accept(this); dvander@23: unindent(); dvander@23: } dvander@0: }; dvander@0: dvander@0: void dvander@0: ParseTree::dump(FILE *fp) dvander@0: { dvander@0: AstPrinter printer(fp); dvander@0: dvander@0: for (size_t i = 0; i < statements_->length(); i++) dvander@0: statements_->at(i)->accept(&printer); dvander@0: }