int Parser::parse() try { push__(0); // initial state clearin(); // clear the tokens. while (true) { try { if (s_state[d_state__]->d_type & REQ_TOKEN) nextToken(); // obtain next token int action = lookup(false); // lookup d_token__ in d_state__ if (action > 0) // SHIFT: push a new state { push__(action); popToken__(); // token processed } else if (action < 0) // REDUCE: execute and pop. { executeAction(-action); // next token is the rule's LHS reduce__(s_productionInfo[-action]); } else ACCEPT(); } catch (ErrorRecovery__) { errorRecovery(); } } } catch (Return__ retValue) { return retValue; }
// If d_token__ is _UNDETERMINED_ then if d_nextToken__ is _UNDETERMINED_ // another // token is obtained from lex(). Then d_nextToken__ is assigned to d_token__. void Parser::nextToken() { if (d_token__ != _UNDETERMINED_) // no need for a token: got one return; // already if (d_nextToken__ != _UNDETERMINED_) { popToken__(); // consume pending token } else { ++d_acceptedTokens__; // accept another token (see // errorRecover()) d_token__ = lex(); if (d_token__ <= 0) d_token__ = _EOF_; } print(); }
// When an error has occurred, pop elements off the stack until the top // state has an error-item. If none is found, the default recovery // mode (which is to abort) is activated. // // If EOF is encountered without being appropriate for the current state, // then the error recovery will fall back to the default recovery mode. // (i.e., parsing terminates) void JSONTokenizer::errorRecovery() try { if (d_acceptedTokens__ >= d_requiredTokens__)// only generate an error- { // message if enough tokens ++d_nErrors__; // were accepted. Otherwise std::string _str("Syntax error at line "); muzzley::tostr(_str, d_scanner.lineNr()); error(_str.data()); // simply skip input } // get the error state while (not (s_state[top__()][0].d_type & ERR_ITEM)) { pop__(); } // In the error state, lookup a token allowing us to proceed. // Continuation may be possible following multiple reductions, // but eventuall a shift will be used, requiring the retrieval of // a terminal token. If a retrieved token doesn't match, the catch below // will ensure the next token is requested in the while(true) block // implemented below: int lastToken = d_token__; // give the unexpected token a // chance to be processed // again. pushToken__(_error_); // specify _error_ as next token push__(lookup(true)); // push the error state d_token__ = lastToken; // reactivate the unexpected // token (we're now in an // ERROR state). bool gotToken = true; // the next token is a terminal while (true) { try { if (s_state[d_state__]->d_type & REQ_TOKEN) { gotToken = d_token__ == _UNDETERMINED_; nextToken(); // obtain next token } int action = lookup(true); if (action > 0) // push a new state { push__(action); popToken__(); if (gotToken) { d_acceptedTokens__ = 0; return; } } else if (action < 0) { // no actions executed on recovery but save an already // available token: if (d_token__ != _UNDETERMINED_) pushToken__(d_token__); // next token is the rule's LHS reduce__(s_productionInfo[-action]); } else ABORT(); // abort when accepting during // error recovery } catch (...) { if (d_token__ == _EOF_) ABORT(); // saw inappropriate _EOF_ popToken__(); // failing token now skipped } } } catch (ErrorRecovery__) // This is: DEFAULT_RECOVERY_MODE { ABORT(); }