dvander@48: /* vim: set ts=4 sw=4 tw=99 et: dvander@48: * dvander@0: * Copyright (C) 2012 David Anderson dvander@0: * dvander@117: * This file is part of SourcePawn. dvander@0: * dvander@117: * SourcePawn 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@117: * SourcePawn 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@117: * SourcePawn. If not, see http://www.gnu.org/licenses/. dvander@0: */ danderson@92: #include 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@145: #include "TypeManager.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@145: Parser::peek(TokenKind kind) dvander@145: { dvander@145: return scanner_.peek() == kind; dvander@145: } dvander@145: dvander@145: bool dvander@0: Parser::match(TokenKind kind) dvander@0: { dvander@145: if (!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@145: BoundName * dvander@145: Parser::bindType(Handle name) dvander@145: { dvander@145: if (BoundName *binding = scope_->lookup(name)) dvander@145: return binding; dvander@145: dvander@145: return new (pool_) UnboundName(scope_, name); dvander@145: } dvander@145: 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@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@176: case TOK_HEX_LITERAL: dvander@176: { dvander@176: scanner_.scan(); dvander@176: int value = strtol(scanner_.literal(), NULL, 16); dvander@176: return new (pool_) IntegerLiteral(scanner_.begin(), value); dvander@176: } dvander@176: 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@143: case TOK_TRUE: dvander@143: case TOK_FALSE: dvander@143: scanner_.scan(); dvander@143: return new (pool_) BooleanLiteral(scanner_.begin(), kind); dvander@143: 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@187: Parser::arrayLiteral(TokenKind kind) dvander@187: { dvander@187: assert(kind == TOK_LBRACE || kind == TOK_LBRACKET); dvander@187: dvander@187: TokenKind close = (kind == TOK_LBRACE) dvander@187: ? TOK_RBRACE dvander@187: : TOK_RBRACKET; dvander@187: dvander@187: SourcePosition pos = scanner_.begin(); dvander@187: dvander@187: ExpressionList *list = new (pool_) ExpressionList(); dvander@187: do { dvander@187: if (match(close)) dvander@187: break; dvander@187: dvander@187: Expression *expr = NULL; dvander@187: if (kind == TOK_LBRACE) { dvander@187: if (peek(TOK_LBRACE)) dvander@187: expr = arrayLiteral(TOK_LBRACE); dvander@187: else dvander@187: expr = primitive(); dvander@187: } else { dvander@187: expr = expression(); dvander@187: } dvander@187: if (!expr) dvander@187: return NULL; dvander@187: dvander@187: if (!list->append(expr)) dvander@187: return NULL; dvander@187: dvander@187: if (!match(TOK_COMMA)) { dvander@187: if (!expect(close)) dvander@187: return NULL; dvander@187: break; dvander@187: } dvander@187: } while (true); dvander@187: dvander@187: return new (pool_) ArrayLiteral(pos, kind, list); dvander@187: } dvander@187: dvander@187: 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@187: case TOK_NAME: dvander@187: { dvander@187: Local name(zone_, expectName()); dvander@187: if (!name) dvander@187: return NULL; dvander@187: return bind(name); dvander@187: } dvander@187: 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@148: Parser::field(Expression *left) dvander@148: { dvander@148: expect(TOK_DOT); dvander@148: dvander@148: SourcePosition pos = scanner_.begin(); dvander@148: Local name(zone_, expectName()); dvander@148: if (!name) dvander@148: return NULL; dvander@148: dvander@148: return new (pool_) FieldExpression(pos, left, name); dvander@148: } dvander@148: dvander@148: 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@148: if ((expr = call(expr)) == NULL) dvander@0: return NULL; dvander@0: break; dvander@0: dvander@0: case TOK_LBRACKET: dvander@148: if ((expr = index(expr)) == NULL) dvander@148: return NULL; dvander@148: break; dvander@148: dvander@148: case TOK_DOT: dvander@148: if ((expr = field(expr)) == NULL) 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@141: Expression *expr = unary(); dvander@23: if (!expr) dvander@23: return NULL; dvander@25: return new (pool_) IncDecExpression(pos, token, expr, false); dvander@23: } dvander@78: dvander@80: case TOK_MINUS: dvander@79: case TOK_NOT: dvander@78: case TOK_TILDE: dvander@78: { dvander@78: scanner_.scan(); dvander@141: Expression *expr = unary(); dvander@78: if (!expr) dvander@78: return NULL; dvander@78: return new (pool_) UnaryExpression(pos, token, expr); dvander@78: } dvander@78: dvander@194: case TOK_SIZEOF: dvander@194: { dvander@194: scanner_.scan(); dvander@194: if (!expect(TOK_LPAREN)) dvander@194: return NULL; dvander@194: Expression *expr = unary(); dvander@194: if (!expr) dvander@194: return NULL; dvander@194: if (!expect(TOK_RPAREN)) dvander@194: return NULL; dvander@194: return new (pool_) UnaryExpression(pos, token, expr); dvander@194: } dvander@194: dvander@141: case TOK_LABEL: dvander@141: { dvander@141: scanner_.scan(); dvander@141: Local tag(zone_, zone_->makeSymbol(scanner_.literal(), scanner_.literal_length())); dvander@141: if (!tag) dvander@141: return NULL; dvander@141: dvander@145: BoundName *type = NULL; dvander@145: if (tag) dvander@145: type = bindType(tag); dvander@145: dvander@141: Expression *expr = unary(); dvander@141: if (!expr) dvander@141: return NULL; dvander@141: dvander@145: return new (pool_) UnaryExpression(pos, TOK_LABEL, expr, type); dvander@141: } dvander@141: dvander@28: default: dvander@28: break; dvander@23: } dvander@23: 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@82: if (!match(TOK_SLASH) && !match(TOK_STAR) && !match(TOK_PERCENT)) 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@75: Expression *right = bitxor(); 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@75: Parser::and_() dvander@75: { dvander@75: Expression *left = equals(); dvander@75: while (left) { dvander@75: if (!match(TOK_AND)) dvander@75: break; dvander@75: SourcePosition pos = scanner_.begin(); dvander@75: Expression *right = equals(); dvander@75: if (!right) dvander@75: return NULL; dvander@75: left = new (pool_) BinaryExpression(pos, TOK_AND, left, right); dvander@75: } dvander@75: return left; dvander@75: } dvander@75: dvander@75: Expression * dvander@75: Parser::or_() dvander@75: { dvander@75: Expression *left = and_(); dvander@75: while (left) { dvander@75: if (!match(TOK_OR)) dvander@75: break; dvander@75: SourcePosition pos = scanner_.begin(); dvander@75: Expression *right = and_(); dvander@75: if (!right) dvander@75: return NULL; dvander@75: left = new (pool_) BinaryExpression(pos, TOK_OR, left, right); dvander@75: } dvander@75: return left; dvander@75: } dvander@75: dvander@75: Expression * dvander@83: Parser::ternary() dvander@83: { dvander@83: Expression *cond = or_(); dvander@83: if (!cond) dvander@83: return NULL; dvander@83: dvander@83: if (!match(TOK_QMARK)) dvander@83: return cond; dvander@83: dvander@172: Expression *left; dvander@83: SourcePosition pos = scanner_.begin(); dvander@172: AutoAllowTags disableTags(scanner_); dvander@172: { dvander@172: if ((left = expression()) == NULL) dvander@172: return NULL; dvander@172: } dvander@83: dvander@83: if (!expect(TOK_COLON)) dvander@83: return NULL; dvander@83: dvander@83: Expression *right = expression(); dvander@83: if (!right) dvander@83: return NULL; dvander@83: dvander@83: return new (pool_) TernaryExpression(pos, cond, left, right); dvander@83: } dvander@83: dvander@83: Expression * dvander@22: Parser::assignment() dvander@22: { dvander@83: Expression *left = ternary(); 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@83: Expression *expr = ternary(); 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@172: Parser::switch_() dvander@172: { dvander@172: expect(TOK_SWITCH); dvander@172: dvander@172: SourcePosition pos = scanner_.begin(); dvander@172: dvander@172: if (!expect(TOK_LPAREN)) dvander@172: return NULL; dvander@172: Expression *expr = expression(); dvander@172: if (!expr) dvander@172: return NULL; dvander@172: if (!expect(TOK_RPAREN)) dvander@172: return NULL; dvander@172: dvander@172: if (!expect(TOK_LBRACE)) dvander@172: return NULL; dvander@172: dvander@172: SourcePosition defaultPos; dvander@172: PoolList *cases = new (pool_) PoolList(); dvander@172: dvander@172: Statement *defaultCase = NULL; dvander@172: dvander@172: while (!peek(TOK_RBRACE)) { dvander@172: Expression *expr = NULL; dvander@172: ExpressionList *others = NULL; dvander@172: if (match(TOK_DEFAULT)) { dvander@172: if (defaultCase) { dvander@172: cc_.reportError(scanner_.begin(), Message_OneDefaultPerSwitch); dvander@172: return NULL; dvander@172: } dvander@172: dvander@172: defaultPos = scanner_.begin(); dvander@172: } else { dvander@172: if (defaultCase) { dvander@172: cc_.reportError(defaultPos, Message_DefaultMustBeLastCase); dvander@172: return NULL; dvander@172: } dvander@172: dvander@172: if (!expect(TOK_CASE)) dvander@172: return NULL; dvander@172: dvander@172: // A limitation in the grammar is that |case :| will be dvander@172: // detected as a label. dvander@172: AutoAllowTags disableTags(scanner_); dvander@172: dvander@172: if ((expr = expression()) == NULL) dvander@172: return NULL; dvander@172: dvander@172: if (peek(TOK_COMMA)) { dvander@172: others = new (pool_) ExpressionList(); dvander@172: while (match(TOK_COMMA)) { dvander@172: Expression *other = expression(); dvander@172: if (!other) dvander@172: return NULL; dvander@172: if (!others->append(other)) dvander@172: return NULL; dvander@172: } dvander@172: } dvander@172: } dvander@172: dvander@172: if (!expect(TOK_COLON)) dvander@172: return NULL; dvander@172: dvander@172: Statement *statement = localStatement(); dvander@172: if (!statement) dvander@172: return NULL; dvander@172: dvander@172: if (!peek(TOK_CASE) && dvander@172: !peek(TOK_DEFAULT) && dvander@172: !peek(TOK_RBRACE)) dvander@172: { dvander@172: cc_.reportError(scanner_.begin(), Message_SingleStatementPerCase); dvander@172: return NULL; dvander@172: } dvander@172: dvander@172: if (expr) { dvander@172: Case *caze = new (pool_) Case(expr, others, statement); dvander@172: if (!cases->append(caze)) dvander@172: return NULL; dvander@172: } else { dvander@172: defaultCase = statement; dvander@172: } dvander@172: } dvander@172: dvander@172: if (!expect(TOK_RBRACE)) dvander@172: return NULL; dvander@172: dvander@172: return new (pool_) SwitchStatement(pos, expr, cases, defaultCase); dvander@172: } dvander@172: dvander@172: 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@135: if (match(TOK_NEW)) { dvander@22: if (!enterScope(Scope::BLOCK)) dvander@22: return NULL; dvander@170: if ((decl = vars(TOK_STOCK, TOK_NEW)) == 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@165: if (decl && (decl->isVariableDeclaration() || decl->isBlockStatement())) { 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@145: ExpressionList * dvander@145: Parser::dimensions() dvander@145: { dvander@145: ExpressionList *postDimensions = new (pool_) ExpressionList(); dvander@145: while (match(TOK_LBRACKET)) { dvander@145: Expression *dim = NULL; dvander@145: if (!match(TOK_RBRACKET)) { dvander@145: if ((dim = expression()) == NULL) dvander@145: return NULL; dvander@145: if (!expect(TOK_RBRACKET)) dvander@145: return NULL; dvander@145: } dvander@145: dvander@145: if (!postDimensions->append(dim)) dvander@145: return NULL; dvander@145: } dvander@145: return postDimensions; dvander@145: } dvander@145: dvander@0: VariableDeclaration * dvander@170: Parser::var(TokenKind scope, TokenKind kind) dvander@0: { dvander@54: Local tag(zone_); dvander@54: if (matchName(tag.ref(), TOK_LABEL) && !tag) dvander@0: return NULL; dvander@4: dvander@145: BoundName *type = NULL; dvander@145: if (tag) dvander@145: type = bindType(tag); dvander@145: dvander@54: Local name(zone_, expectName()); dvander@4: if (!name) dvander@4: return NULL; dvander@0: dvander@189: SourcePosition pos = scanner_.begin(); dvander@189: dvander@25: if (BoundName *other = scope_->localLookup(name)) { dvander@25: redeclarationError(other); dvander@25: return NULL; dvander@25: } dvander@25: dvander@0: ExpressionList *postDimensions = NULL; dvander@145: if (peek(TOK_LBRACKET)) { dvander@145: if ((postDimensions = dimensions()) == NULL) dvander@145: return NULL; dvander@0: } dvander@0: dvander@0: Expression *expr = NULL; dvander@0: if (match(TOK_ASSIGN)) { dvander@187: switch (scanner_.peek()) { dvander@187: // Note: we don't support [] literals yet. dvander@187: case TOK_LBRACE: dvander@187: if ((expr = arrayLiteral(scanner_.scan())) == NULL) dvander@187: return NULL; dvander@187: break; dvander@187: dvander@187: default: dvander@187: if ((expr = expression()) == NULL) dvander@187: return NULL; dvander@187: break; dvander@187: } dvander@0: } dvander@0: dvander@189: Variable *var = scope_->declareVariable(name, pos); dvander@189: if (!var) dvander@189: return NULL; dvander@189: dvander@189: if (scope == TOK_PUBLIC) dvander@189: var->setPublic(); dvander@189: dvander@145: return new (pool_) VariableDeclaration(var->pos(), kind, var, type, postDimensions, expr); dvander@0: } dvander@0: dvander@0: Statement * dvander@170: Parser::vars(TokenKind scope, TokenKind kind) dvander@165: { dvander@170: VariableDeclaration *decl = var(scope, kind); dvander@165: if (!decl) dvander@165: return NULL; dvander@165: dvander@165: if (!peek(TOK_COMMA)) dvander@165: return decl; dvander@165: dvander@165: StatementList *statements = new (pool_) StatementList(); dvander@165: if (!statements->append(decl)) dvander@165: return NULL; dvander@165: dvander@165: while (match(TOK_COMMA)) { dvander@170: Statement *decl = var(scope, kind); dvander@165: if (!decl) dvander@165: return NULL; dvander@165: if (!statements->append(decl)) dvander@165: return NULL; dvander@165: } dvander@165: dvander@165: // Create a fake-o block with no scope to create a statement list. dvander@165: return new (pool_) BlockStatement(decl->pos(), NULL, statements); dvander@165: } dvander@165: dvander@165: 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@72: Expression *expr = NULL; dvander@72: if (scanner_.peek() != TOK_SEMICOLON) { dvander@72: if ((expr = expression()) == NULL) dvander@72: return NULL; dvander@0: dvander@72: // We only care about non-void returns when determining whether a dvander@72: // tagless function is non-void. dvander@72: encounteredReturn_ = true; dvander@72: } dvander@71: 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@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@135: TokenKind kind = scanner_.peek(); dvander@135: switch (kind) { dvander@135: case TOK_CONST: dvander@131: case TOK_NEW: dvander@135: scanner_.scan(); dvander@170: if ((statement = vars(TOK_STOCK, kind)) == NULL) dvander@172: return NULL; dvander@131: break; dvander@0: dvander@131: case TOK_FOR: dvander@131: return forStatement(); dvander@0: dvander@131: case TOK_WHILE: dvander@131: return while_(); dvander@9: dvander@131: case TOK_BREAK: dvander@131: scanner_.scan(); dvander@131: statement = new (pool_) BreakStatement(scanner_.begin()); dvander@131: break; dvander@10: dvander@131: case TOK_CONTINUE: dvander@131: scanner_.scan(); dvander@131: statement = new (pool_) ContinueStatement(scanner_.begin()); dvander@131: break; dvander@10: dvander@131: case TOK_DO: dvander@131: if ((statement = do_()) == NULL) dvander@131: return NULL; dvander@131: break; dvander@9: dvander@131: case TOK_RETURN: dvander@131: if ((statement = returnStatement()) == NULL) dvander@172: return NULL; dvander@131: break; dvander@0: dvander@131: case TOK_ENUM: dvander@131: if ((statement = enum_()) == NULL) dvander@172: return NULL; dvander@131: break; dvander@2: dvander@146: case TOK_STRUCT: dvander@146: if ((statement = struct_()) == NULL) dvander@172: return NULL; dvander@146: break; dvander@146: dvander@172: case TOK_SWITCH: dvander@172: return switch_(); dvander@172: dvander@131: case TOK_IF: dvander@131: return if_(); dvander@0: dvander@131: case TOK_LBRACE: dvander@131: return block(); dvander@28: dvander@131: default: dvander@131: 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@146: Parser::struct_() dvander@146: { dvander@146: expect(TOK_STRUCT); dvander@146: dvander@146: Local name(zone_, expectName()); dvander@146: if (!name) dvander@146: return NULL; dvander@146: dvander@146: SourcePosition pos = scanner_.begin(); dvander@146: dvander@146: if (BoundName *other = scope_->localLookup(name)) { dvander@146: redeclarationError(other); dvander@146: return NULL; dvander@146: } dvander@146: dvander@146: NamedType *type; dvander@146: if ((type = scope_->declareType(name, scanner_.begin())) == NULL) dvander@146: return NULL; dvander@146: dvander@146: if (!expect(TOK_LBRACE)) dvander@146: return NULL; dvander@146: dvander@146: FieldList *fields = new (pool_) FieldList(); dvander@146: dvander@146: while (!peek(TOK_RBRACE)) { dvander@146: if (matchName(name.ref(), TOK_LABEL) && !name) dvander@146: return NULL; dvander@146: dvander@146: BoundName *type = NULL; dvander@146: if (name) { dvander@146: if ((type = bindType(name)) == NULL) dvander@146: return NULL; dvander@146: } dvander@146: dvander@146: name = expectName(); dvander@146: if (!name) dvander@146: return NULL; dvander@146: dvander@146: SourcePosition pos = scanner_.begin(); dvander@146: dvander@146: ExpressionList *postDimensions = NULL; dvander@192: if (peek(TOK_LBRACKET)) { dvander@192: if ((postDimensions = dimensions()) == NULL) dvander@192: return NULL; dvander@192: } dvander@146: dvander@146: if (!matchSemicolon()) dvander@146: return NULL; dvander@146: dvander@146: StructureStatement::Field *field = dvander@146: new (pool_) StructureStatement::Field(pos, type, name, postDimensions); dvander@146: if (!field || !fields->append(field)) dvander@146: return NULL; dvander@146: } dvander@146: dvander@146: if (!expect(TOK_RBRACE)) dvander@146: return NULL; dvander@146: mibusby@180: if (fields->empty()) { mibusby@180: cc_.reportError(pos, Message_StructCantBeEmpty); mibusby@180: return NULL; mibusby@180: } mibusby@180: dvander@146: return new (pool_) StructureStatement(pos, type, fields); dvander@146: } dvander@146: dvander@146: Statement * dvander@2: Parser::enum_() dvander@2: { dvander@2: expect(TOK_ENUM); dvander@2: dvander@145: NamedType *type = NULL; 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@145: if ((type = scope_->declareType(name, scanner_.begin())) == NULL) 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@145: return new (pool_) EnumStatement(pos, type, name, entries); dvander@2: } dvander@2: dvander@2: Statement * dvander@63: Parser::function(TokenKind token) dvander@0: { dvander@132: Local returnTag(zone_); dvander@145: if (token == TOK_LABEL) { dvander@145: returnTag = zone_->makeSymbol(scanner_.literal(), scanner_.literal_length()); dvander@145: if (!returnTag) dvander@145: return NULL; dvander@145: dvander@145: token = TOK_STOCK; dvander@145: } else { dvander@191: if (peek(TOK_LABEL)) { dvander@191: if (matchName(returnTag.ref(), TOK_LABEL) && !returnTag) dvander@191: return NULL; dvander@191: } else if (peek(TOK_NAME)) { dvander@191: // Peek for a type that has no : dvander@191: returnTag = expectName(); dvander@191: if (!returnTag) dvander@191: return NULL; dvander@191: } dvander@191: } dvander@191: dvander@191: Local name(zone_); dvander@191: ExpressionList *returnDimensions = NULL; dvander@191: dvander@191: bool allowArrayReturns = token != TOK_NATIVE && dvander@191: token != TOK_PUBLIC && dvander@191: token != TOK_FORWARD; dvander@191: dvander@191: if (allowArrayReturns && peek(TOK_LBRACKET)) { dvander@191: if ((returnDimensions = dimensions()) == NULL) dvander@145: return NULL; dvander@191: if ((name = expectName()) == NULL) dvander@191: return NULL; dvander@191: } else if (peek(TOK_NAME)) { dvander@191: if ((name = expectName()) == NULL) dvander@191: return NULL; dvander@191: } else { dvander@191: // We predicted |type name|, but just got |name| instead. dvander@191: name = returnTag; dvander@191: returnTag = NULL; dvander@145: } dvander@145: dvander@145: BoundName *returnType = NULL; dvander@145: if (returnTag) dvander@145: returnType = bindType(returnTag); dvander@132: 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@174: NamedType *type = NULL; dvander@174: NamedFunction *fun = NULL; 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@174: if (token == TOK_TYPEDEF || 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@174: } else if (token == TOK_TYPEDEF) { dvander@174: type = scope_->declareType(name, scanner_.begin()); dvander@174: if (!type) dvander@174: return NULL; 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@174: if (fun && fun->isPublic()) dvander@137: fun->setUsed(); dvander@137: 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@133: dvander@0: if (!match(TOK_RPAREN)) { dvander@0: while (true) { dvander@67: bool isConst = match(TOK_CONST); dvander@14: bool ref = match(TOK_AMPERSAND); dvander@14: dvander@66: SourcePosition begin = scanner_.begin(); dvander@66: Local tag(zone_); dvander@66: if (matchName(tag.ref(), TOK_LABEL) && !tag) dvander@66: return NULL; dvander@66: dvander@145: BoundName *type = NULL; dvander@145: if (tag) dvander@145: type = bindType(tag); dvander@145: dvander@68: if (match(TOK_ELLIPSES)) { dvander@68: if (isConst || ref) { dvander@68: cc_.reportError(begin, Message_InvalidVarArgs); dvander@68: return NULL; dvander@68: } dvander@68: dvander@68: if (token != TOK_NATIVE) { dvander@68: cc_.reportError(begin, Message_VarArgsOutsideNative); dvander@68: return NULL; dvander@68: } dvander@68: dvander@68: fun->markNativeVariadic(); dvander@68: break; dvander@68: } dvander@68: 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@66: // Look for dimensions. dvander@66: ExpressionList *postDimensions = NULL; dvander@145: if (peek(TOK_LBRACKET)) { dvander@145: if ((postDimensions = dimensions()) == NULL) dvander@66: return NULL; dvander@66: } dvander@66: dvander@133: Expression *expr = NULL; dvander@133: if (match(TOK_ASSIGN)) { dvander@133: if ((expr = expression()) == NULL) dvander@133: return NULL; dvander@133: } dvander@133: dvander@145: Parameter *parameter = new (pool_) Parameter(arg, type, ref, isConst, postDimensions, dvander@133: expr); 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@71: encounteredReturn_ = false; dvander@71: dvander@63: Statement *body = NULL; dvander@174: if (token != TOK_FORWARD && token != TOK_NATIVE && token != TOK_TYPEDEF) { dvander@63: body = block(); dvander@63: if (!body) dvander@63: return NULL; dvander@63: } dvander@0: dvander@0: scope_ = scope_->enclosing(); dvander@174: dvander@191: FunctionSignature signature(returnType, returnDimensions, parameters); dvander@174: if (token == TOK_TYPEDEF) dvander@174: return new (pool_) FunctionTypeStatement(pos, type, signature); dvander@174: dvander@174: return new (pool_) FunctionStatement(pos, scope, fun, body, signature, encounteredReturn_); dvander@0: } dvander@0: dvander@145: static inline bool dvander@167: DeclareIntrinsicType(Zone *zone, Scope *scope, const char *name, Handle type) dvander@145: { dvander@145: Local tag(zone, zone->makeSymbol(name)); dvander@145: if (!tag) dvander@145: return false; dvander@145: dvander@167: return !!scope->declareType(tag, type); dvander@167: } dvander@167: dvander@167: static inline bool dvander@167: DeclareIntrinsicType(Zone *zone, Scope *scope, const char *name, PrimitiveType type) dvander@167: { dvander@145: Local primitive(zone, zone->types()->getPrimitive(type)); dvander@145: assert(primitive); dvander@167: return DeclareIntrinsicType(zone, scope, name, primitive); dvander@145: } dvander@145: dvander@145: bool dvander@145: Parser::setupIntrinsics() dvander@145: { dvander@145: if (!DeclareIntrinsicType(zone_, scope_, "Float", PrimitiveType_Float)) dvander@145: return false; dvander@145: if (!DeclareIntrinsicType(zone_, scope_, "_", PrimitiveType_Int32)) dvander@145: return false; dvander@145: if (!DeclareIntrinsicType(zone_, scope_, "bool", PrimitiveType_Bool)) dvander@145: return false; dvander@145: if (!DeclareIntrinsicType(zone_, scope_, "String", PrimitiveType_Char)) dvander@145: return false; dvander@167: dvander@167: Local unchecked(zone_, zone_->types()->getUnchecked()); dvander@167: if (!DeclareIntrinsicType(zone_, scope_, "unchecked", unchecked)) dvander@167: return false; dvander@167: dvander@174: Local voidType(zone_, zone_->types()->getVoid()); dvander@174: if (!DeclareIntrinsicType(zone_, scope_, "void", voidType)) dvander@174: return false; dvander@174: dvander@174: Local intType(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32)); dvander@174: if (!DeclareIntrinsicType(zone_, scope_, "int", intType)) dvander@174: return false; dvander@174: dvander@145: return true; dvander@145: } dvander@145: 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@145: if (!setupIntrinsics()) dvander@145: return NULL; dvander@145: dvander@0: for (;;) { dvander@0: Statement *statement = NULL; dvander@0: dvander@135: TokenKind kind = scanner_.peek(); dvander@135: switch (kind) { 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@68: case TOK_NATIVE: dvander@134: case TOK_STOCK: dvander@145: case TOK_LABEL: dvander@174: case TOK_TYPEDEF: dvander@63: { dvander@135: scanner_.scan(); dvander@170: if (kind == TOK_PUBLIC && peek(TOK_CONST)) { dvander@170: if ((statement = var(TOK_PUBLIC, scanner_.scan())) == NULL) dvander@170: return NULL; dvander@170: if (!matchSemicolon()) dvander@170: return NULL; dvander@170: } else { dvander@170: if ((statement = function(kind)) == NULL) dvander@170: return NULL; dvander@174: if ((kind == TOK_FORWARD || kind == TOK_NATIVE || kind == TOK_TYPEDEF) && !matchSemicolon()) dvander@170: return NULL; dvander@170: } dvander@63: break; dvander@63: } dvander@63: dvander@135: case TOK_CONST: dvander@85: case TOK_NEW: dvander@85: { dvander@165: // Note: at global scope, we don't accept comma-delimited dvander@165: // declarations yet, to see if we can get away with forcing dvander@165: // a nicer top-level style. dvander@135: scanner_.scan(); dvander@170: if ((statement = var(TOK_STOCK, kind)) == NULL) dvander@170: return NULL; dvander@85: if (!matchSemicolon()) dvander@85: return NULL; dvander@85: break; dvander@85: } dvander@74: 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@146: case TOK_STRUCT: dvander@146: if ((statement = struct_()) == NULL) dvander@146: return NULL; dvander@146: if (!matchSemicolon()) dvander@146: return NULL; dvander@146: break; dvander@146: 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@191: void dump(const FunctionSignature &sig) { dvander@191: prefix(); dvander@191: fprintf(fp_, "%s", sig.returnType() dvander@191: ? sig.returnType()->name()->chars() dvander@191: : "_"); dvander@191: if (sig.returnDimensions()) { dvander@191: for (size_t i = 0; i < sig.returnDimensions()->length(); i++) dvander@191: fprintf(fp_, "[]"); dvander@191: } dvander@191: fprintf(fp_, "()\n"); dvander@191: } 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@174: void visit(FunctionTypeStatement *node) { dvander@174: prefix(); dvander@174: fprintf(fp_, "[ FunctionTypeStatement (%s)\n", node->decl()->name()->chars()); dvander@191: indent(); dvander@191: dump(node->signature()); dvander@191: unindent(); dvander@174: } dvander@0: void visit(FunctionStatement *node) { dvander@0: prefix(); dvander@54: fprintf(fp_, "[ FunctionStatement (%s)\n", node->fun()->name()->chars()); dvander@0: indent(); dvander@191: dump(node->signature()); 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@83: void visit(TernaryExpression *node) { dvander@83: prefix(); dvander@83: fprintf(fp_, "[ TernaryExpression\n"); dvander@83: indent(); dvander@83: node->condition()->accept(this); dvander@83: node->left()->accept(this); dvander@83: node->right()->accept(this); dvander@83: unindent(); dvander@83: } 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@78: void visit(UnaryExpression *node) { dvander@78: prefix(); dvander@78: fprintf(fp_, "[ UnaryExpression (%s)\n", TokenNames[node->token()]); dvander@78: indent(); dvander@78: node->expression()->accept(this); dvander@78: unindent(); dvander@78: } dvander@0: void visit(ReturnStatement *node) { dvander@0: prefix(); dvander@0: fprintf(fp_, "[ ReturnStatement\n"); dvander@0: indent(); dvander@72: if (node->expression()) dvander@72: 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@143: void visit(BooleanLiteral *node) { dvander@143: prefix(); dvander@143: fprintf(fp_, "[ BooleanLiteral (%s)\n", dvander@143: (node->token() == TOK_TRUE) ? "true" : "false"); dvander@143: } 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@146: void visit(StructureStatement *node) { dvander@146: prefix(); dvander@148: fprintf(fp_, "[ StructureStatement %s\n", node->decl()->name()->chars()); dvander@148: } dvander@148: void visit(FieldExpression *node) { dvander@148: prefix(); dvander@148: fprintf(fp_, "[ FieldExpression %s\n", node->field()->chars()); dvander@148: indent(); dvander@148: node->left()->accept(this); dvander@148: unindent(); dvander@146: } dvander@172: void visit(SwitchStatement *node) { dvander@172: prefix(); dvander@172: fprintf(fp_, "[ SwitchStatement\n"); dvander@172: indent(); dvander@172: node->expression()->accept(this); dvander@172: for (size_t i = 0; i < node->cases()->length(); i++) { dvander@172: Case *c = node->cases()->at(i); dvander@172: c->expression()->accept(this); dvander@172: if (c->others()) { dvander@172: for (size_t j = 0; j < c->others()->length(); j++) dvander@172: c->others()->at(j)->accept(this); dvander@172: } dvander@172: indent(); dvander@172: c->statement()->accept(this); dvander@172: unindent(); dvander@172: } dvander@172: if (node->defaultCase()) dvander@172: node->defaultCase()->accept(this); dvander@172: unindent(); dvander@172: } dvander@187: void visit(ArrayLiteral *node) { dvander@187: prefix(); dvander@187: fprintf(fp_, "[ ArrayLiteral\n"); dvander@187: indent(); dvander@187: for (size_t i = 0; i < node->expressions()->length(); i++) { dvander@187: Expression *expr = node->expressions()->at(i); dvander@187: indent(); dvander@187: expr->accept(this); dvander@187: unindent(); dvander@187: } dvander@187: } 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: }