ASTNode::Link StatementParser::statement() { if (accept(TT::TYPE)) { return type(); } else if (accept(TT::IF)) { skip(); return ifStatement(); } else if (accept(TT::FOR)) { auto loop = Node<LoopNode>::make(); loop->setTrace(current().trace); skip(); // Skip "for" loop->setInit(declaration(false)); expectSemi(); loop->setCondition(expression(false)); expectSemi(); loop->setUpdate(expression(false)); loop->setCode(block(CODE_BLOCK)); return loop; } if (accept(TT::WHILE)) { skip(); // Skip "while" auto loop = Node<LoopNode>::make(); loop->setTrace(current().trace); loop->setCondition(expression()); loop->setCode(block(CODE_BLOCK)); return loop; } else if (accept(TT::DO)) { return block(CODE_BLOCK); } else if (accept(TT::DEFINE)) { auto decl = declaration(); expectSemi(); return decl; } else if (accept(TT::IDENTIFIER)) { skip(); if (accept(TT::IDENTIFIER) || accept(",")) { skip(-1); // Go back to the prev identifier auto decl = declaration(); expectSemi(); return decl; } else { skip(-1); // Get the entire expression auto e = expression(); expectSemi(); return e; } } else if (accept(TT::BREAK)) { skip(); return Node<BreakLoopNode>::make(); } else if (accept(TT::CONTINUE)) { throw InternalError("Unimplemented", {METADATA_PAIRS, {"token", "loop continue"}}); } else if (accept(TT::RETURN)) { auto trace = current().trace; skip(); // Skip "return" auto retValue = expression(false); expectSemi(); auto retNode = Node<ReturnNode>::make(); retNode->setTrace(trace); if (retValue != nullptr) retNode->setValue(retValue); return retNode; } else if (accept(TT::FUNCTION)) { return function(); } else if (accept(TT::FOREIGN)) { return function(true); } else { auto e = expression(); expectSemi(); return e; } }
AST* Parser::statement(Scope* ps) { AST* ret = NULL; if (expect(";")) { ret = emptyStatement(); } else if (expect("var")) { ret = varStatement(ps); opteol(); } else if (expect("{")) { ret = block(ps); opteol(); } else if (expect("if")) { ret = ifStatement(ps); } else if (expect("switch")) { ret = switchStatement(ps); } else if (expect("do")) { ret = doStatement(ps); opteol(); } else if (expect("while")) { ret = whileStatement(ps); } else if (expect("for")) { ret = forStatement(ps); } else if (expect("with")) { ret = withStatement(ps); } else if (expect("continue")) { ret = continueStatement(); opteol(); } else if (expect("break")) { ret = breakStatement(); opteol(); } else if (expect("return")) { ret = returnStatement(ps); opteol(); } else if (expect("try")) { ret = tryStatement(ps); } else if (expect("throw")) { ret = throwStatement(ps); opteol(); } else { ret = expression(0, ps); opteol(); } return ret; }
void statement (void) { //------------------------------------------------------------------- // NOTE: Since we currently don't support generic BEGIN/END (compound // statement) blocks... if ((curToken != TKN_CODE) /*&& (curToken != TKN_BEGIN)*/) crunchStatementMarker(); switch (curToken) { case TKN_IDENTIFIER: { SymTableNodePtr IdPtr = NULL; //-------------------------------------------------------------- // First, do we have an assignment statement or a function call? searchAndFindAllSymTables(IdPtr); if ((IdPtr->defn.key == DFN_FUNCTION)/* || (IdPtr->defn.key == DFN_MODULE)*/) { RoutineKey key = IdPtr->defn.info.routine.key; if ((key == RTN_ASSERT) || (key == RTN_PRINT) || (key == RTN_CONCAT)) { bool uncrunch = ((key == RTN_ASSERT) && !AssertEnabled) || ((key == RTN_PRINT) && !PrintEnabled) || ((key == RTN_CONCAT) && !StringFunctionsEnabled); if (uncrunch) { uncrunchStatementMarker(); Crunch = false; } } crunchSymTableNodePtr(IdPtr); if (IdPtr->defn.info.routine.flags & ROUTINE_FLAG_ORDER) { if (NumOrderCalls == MAX_ORDERS) syntaxError(ABL_ERR_SYNTAX_TOO_MANY_ORDERS); crunchByte((unsigned char)(NumOrderCalls / 32)); crunchByte((unsigned char)(NumOrderCalls % 32)); NumOrderCalls++; } getToken(); SymTableNodePtr thisRoutineIdPtr = CurRoutineIdPtr; routineCall(IdPtr, 1); CurRoutineIdPtr = thisRoutineIdPtr; Crunch = true; } else assignmentStatement(IdPtr); } break; case TKN_REPEAT: repeatStatement(); break; case TKN_WHILE: whileStatement(); break; case TKN_IF: ifStatement(); break; case TKN_FOR: forStatement(); break; case TKN_SWITCH: switchStatement(); break; case TKN_TRANS: transStatement(); break; case TKN_TRANS_BACK: transBackStatement(); break; } //--------------------------------------------------------------------- // Now, make sure the statement is closed off with the proper block end // statement, if necessary (which is usually the case :). synchronize(statementEndList, NULL, NULL); if (tokenIn(statementStartList)) syntaxError(ABL_ERR_SYNTAX_MISSING_SEMICOLON); }