dvander@0: /* 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@0: dvander@0: using namespace jc; dvander@0: dvander@0: Parser::Parser(const char *stream, size_t length) dvander@0: : pool_(ZONE()->pool()), dvander@0: strings_(pool_), dvander@0: scanner_(stream, length), dvander@0: scope_(NULL), dvander@0: unbound_(NULL) dvander@0: { dvander@0: unbound_ = new std::vector(); 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@0: Parser::expect(TokenKind kind) dvander@0: { dvander@0: TokenKind got = scanner_.scan(); dvander@0: if (got == kind) dvander@0: return true; dvander@0: fprintf(stderr, "error: expected %s, got %s\n", 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@0: Parser::bind(Name *name) dvander@0: { dvander@0: BoundName *bound = scope_->lookup(name); dvander@0: NameProxy *proxy = new (pool_) NameProxy(name, bound); dvander@0: if (!bound) dvander@0: unbound_->push_back(proxy); dvander@0: return proxy; dvander@0: } dvander@0: dvander@0: Expression * dvander@0: Parser::primitive() dvander@0: { dvander@0: switch (scanner_.peek()) { dvander@0: case TOK_NAME: dvander@0: { dvander@0: scanner_.scan(); dvander@0: Name *name = strings_.add(scanner_.literal()); dvander@0: return bind(name); dvander@0: } dvander@0: dvander@0: case TOK_INTEGER_LITERAL: dvander@0: { dvander@0: scanner_.scan(); dvander@0: int value = atoi(scanner_.literal()); dvander@0: return new (pool_) IntegerLiteralExpression(value); dvander@0: } dvander@0: dvander@0: default: dvander@0: { dvander@0: fprintf(stderr, "error: expected expression!\n"); 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@0: ExpressionList *arguments = new ExpressionList(); dvander@0: 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@0: arguments->push_back(expr); 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@0: return new (pool_) CallExpression(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@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@0: return new (pool_) IndexExpression(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@0: return primary(); 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@0: TokenKind kind = scanner_.last(); dvander@0: Expression *right = unary(); dvander@0: if (!right) dvander@0: return NULL; dvander@0: left = new (pool_) BinaryExpression(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@0: TokenKind kind = scanner_.last(); dvander@0: Expression *right = multiplication(); dvander@0: if (!right) dvander@0: return NULL; dvander@0: left = new (pool_) BinaryExpression(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@2: if (!match(TOK_SHL)) dvander@2: break; dvander@2: TokenKind kind = scanner_.last(); dvander@2: Expression *right = addition(); dvander@2: if (!right) dvander@2: return NULL; dvander@2: left = new (pool_) BinaryExpression(kind, left, right); dvander@2: } dvander@2: return left; dvander@2: } dvander@2: dvander@2: Expression * dvander@0: Parser::relational() dvander@0: { dvander@2: Expression *left = shift(); 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@2: Expression *right = shift(); dvander@0: if (!right) dvander@0: return NULL; dvander@0: left = new (pool_) BinaryExpression(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@0: Expression *right = relational(); dvander@0: if (!right) dvander@0: return NULL; dvander@0: left = new (pool_) BinaryExpression(kind, left, right); dvander@0: } dvander@0: return left; dvander@0: } dvander@0: dvander@0: Expression * dvander@0: Parser::expression() dvander@0: { dvander@0: return equals(); dvander@0: } dvander@0: dvander@0: Statement * dvander@0: Parser::forStatement() dvander@0: { dvander@0: scanner_.scan(); dvander@0: if (!expect(TOK_LPAREN)) dvander@0: return NULL; dvander@0: dvander@0: VariableDeclaration *decl = NULL; dvander@0: if (!match(TOK_SEMICOLON)) { dvander@0: if (!enterScope(Scope::BLOCK)) dvander@0: return NULL; dvander@0: if ((decl = variableDeclaration()) == NULL) dvander@0: return NULL; 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@0: Statement *body = localStatement(); dvander@0: if (!body) dvander@0: return NULL; dvander@0: dvander@0: Scope *blockScope = NULL; dvander@0: if (decl) { dvander@0: blockScope = scope_->unlinkIfEmpty(); dvander@0: scope_ = scope_->enclosing(); dvander@0: } dvander@0: return new (pool_) ForStatement(blockScope, 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@0: // Get the name. dvander@0: if (!expect(TOK_NAME)) dvander@0: return NULL; dvander@0: dvander@0: Name *name = strings_.add(scanner_.literal()); dvander@0: dvander@0: ExpressionList *postDimensions = NULL; dvander@0: if (scanner_.peek() == TOK_LBRACKET) { dvander@0: postDimensions = new 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@0: postDimensions->push_back(dim); 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@0: if (scope_->localLookup(name)) { dvander@0: redeclarationError(); dvander@0: return NULL; dvander@0: } dvander@0: dvander@0: Variable *var = scope_->declareVariable(name); dvander@0: VariableDeclaration *decl = new (pool_) VariableDeclaration(var, postDimensions, expr); dvander@0: dvander@0: return decl; dvander@0: } dvander@0: dvander@0: Statement * dvander@0: Parser::returnStatement() dvander@0: { 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@0: return new (pool_) ReturnStatement(expr); dvander@0: } dvander@0: dvander@0: Statement * dvander@0: Parser::expressionStatement() dvander@0: { dvander@0: Expression *left = primary(); dvander@0: if (!left) { dvander@0: fprintf(stderr, "expected expression or statement\n"); dvander@0: return NULL; dvander@0: } dvander@0: dvander@0: if (match(TOK_ASSIGN)) { dvander@0: Expression *expr = expression(); dvander@0: if (!expr) dvander@0: return NULL; dvander@0: dvander@0: left = new (pool_) Assignment(left, expr); dvander@0: } dvander@0: dvander@0: return new (pool_) ExpressionStatement(left); dvander@0: } dvander@0: dvander@0: Statement * dvander@0: Parser::block() dvander@0: { dvander@0: if (!expect(TOK_LBRACE)) dvander@0: return NULL; dvander@0: dvander@0: if (!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@0: statements->append(pool_, statement); dvander@0: } dvander@0: dvander@0: Scope *blockScope = scope_->unlinkIfEmpty(); dvander@0: BlockStatement *block = new (pool_) BlockStatement(blockScope, statements); dvander@0: dvander@0: scope_ = scope_->enclosing(); dvander@0: return block; dvander@0: } dvander@0: dvander@0: Statement * dvander@0: Parser::if_() dvander@0: { dvander@0: expect(TOK_IF); dvander@0: 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@0: IfStatement *outer = new (pool_) IfStatement(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@0: return false; dvander@0: 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@0: IfStatement *inner = new (pool_) IfStatement(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@0: statement = variableDeclaration(); dvander@0: break; dvander@0: dvander@0: case TOK_FOR: dvander@0: return forStatement(); dvander@0: dvander@0: case TOK_RETURN: dvander@0: statement = returnStatement(); dvander@0: break; dvander@0: dvander@2: case TOK_ENUM: dvander@2: statement = enum_(); 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@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@2: Name *name = NULL; dvander@2: if (match(TOK_NAME)) { dvander@2: if ((name = strings_.add(scanner_.literal())) == NULL) dvander@2: return NULL; dvander@2: dvander@2: if (scope_->localLookup(name)) { dvander@2: redeclarationError(); dvander@2: return NULL; dvander@2: } dvander@2: dvander@2: NamedEnum *e = scope_->declareEnum(name); dvander@2: if (!e) dvander@2: return NULL; dvander@2: } dvander@2: dvander@2: EnumStatement::EntryList *entries = new 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@2: if (!expect(TOK_NAME)) dvander@2: return NULL; dvander@2: dvander@2: Name *name = strings_.add(scanner_.literal()); dvander@2: if (!name) dvander@2: return NULL; dvander@2: dvander@2: if (scope_->localLookup(name)) { dvander@2: redeclarationError(); dvander@2: return NULL; dvander@2: } dvander@2: dvander@2: NamedConstant *constant = scope_->declareConstant(name); 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@2: entries->push_back(EnumStatement::Entry(constant, expr)); dvander@2: } while (match(TOK_COMMA)); dvander@2: if (!expect(TOK_RBRACE)) dvander@2: return NULL; dvander@2: dvander@2: return new (pool_) EnumStatement(name, entries); dvander@2: } dvander@2: dvander@2: Statement * dvander@0: Parser::function() dvander@0: { dvander@0: expect(TOK_NAME); dvander@0: dvander@0: Name *name = strings_.add(scanner_.literal()); dvander@0: if (!name) dvander@0: return NULL; dvander@0: dvander@0: // The function name goes into the outer (global) scope. dvander@0: assert(!scope_->enclosing()); dvander@0: dvander@0: if (scope_->localLookup(name)) { dvander@0: redeclarationError(); dvander@0: return NULL; dvander@0: } dvander@0: NamedFunction *fun = scope_->declareFunction(name); dvander@0: if (!fun) dvander@0: return NULL; dvander@0: dvander@0: Scope *scope = enterScope(Scope::FUNCTION); dvander@0: if (!scope) dvander@0: return NULL; dvander@0: dvander@0: if (!expect(TOK_LPAREN)) dvander@0: return NULL; dvander@0: if (!match(TOK_RPAREN)) { dvander@0: while (true) { dvander@0: if (!expect(TOK_NAME)) dvander@0: return NULL; dvander@0: dvander@0: Name *name = strings_.add(scanner_.literal()); dvander@0: if (!name) dvander@0: return NULL; dvander@0: dvander@0: if (scope_->localLookup(name)) { dvander@0: redeclarationError(); dvander@0: return NULL; dvander@0: } dvander@0: if (!scope_->declareArgument(name)) dvander@0: return NULL; dvander@0: 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@0: Statement *body = block(); dvander@0: if (!body) dvander@0: return NULL; dvander@0: dvander@0: scope_ = scope_->enclosing(); dvander@0: return new (pool_) FunctionStatement(scope, fun, body); 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@0: if ((statement = function()) == NULL) dvander@0: return NULL; dvander@0: break; dvander@0: dvander@2: case TOK_ENUM: dvander@2: if ((statement = enum_()) == NULL) dvander@2: return NULL; dvander@2: // :TODO: require semicolon dvander@2: break; dvander@2: dvander@0: default: dvander@0: fprintf(stderr, "expected function or global variable\n"); dvander@0: return NULL; dvander@0: } dvander@0: dvander@0: if (!statement) dvander@0: break; dvander@0: dvander@0: statements->append(pool_, statement); 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@0: fprintf(fp_, "[ NameProxy (%s)%s\n", name->name(), 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@0: for (size_t i = 0; i < node->arguments()->size(); i++) dvander@0: node->arguments()->at(i)->accept(this); dvander@0: unindent(); dvander@0: } dvander@0: void visit(FunctionStatement *node) { dvander@0: prefix(); dvander@0: fprintf(fp_, "[ FunctionStatement (%s)\n", node->fun()->name()); dvander@0: indent(); dvander@0: 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@0: if (node->declaration()) dvander@0: node->declaration()->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@0: fprintf(fp_, "[ VariableDeclaration (%s)\n", node->variable()->name()); dvander@0: indent(); dvander@0: if (node->initialization()) dvander@0: node->initialization()->accept(this); dvander@0: unindent(); dvander@0: } dvander@0: void visit(IntegerLiteralExpression *node) { dvander@0: prefix(); dvander@0: fprintf(fp_, "[ LiteralExpression (%d)\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@2: fprintf(fp_, "[ EnumStatement (%s)\n", node->name() ? node->name() : ""); dvander@2: indent(); dvander@2: for (size_t i = 0; i < node->entries()->size(); i++) { dvander@2: prefix(); dvander@2: fprintf(fp_, "%s =\n", node->entries()->at(i).name->name()); 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@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: }