src/parser/Parse_Table.cc
Token Parse_Table::parse(Token_Stream &tokens) const {
  // The is_recovering flag is used during error recovery to suppress additional
  // error messages.  This reduces the likelihood that a single error in a token
  // stream will generate a large number of error messages.

  bool is_recovering = false;

  // Create a comparator object that will be used to attempt to match keywords
  // in the Token_Stream to keywords in the Parse_Table.  This comparator object
  // incorporates the current settings of the Parse_Table, such as case
  // sensitivity and partial matching options.

  Keyword_Compare_ const comp(flags_);

  // Now begin the process of pulling keywords off the input token stream, and
  // attempting to match these to the keyword table.

  for (;;) {
    Token const token = tokens.shift();

    // The END, EXIT, and ERROR tokens are terminating tokens.  EXIT means the
    // end of the token stream has been reached.  END is used to flag the end of
    // a nested parse, where the result of matching a keyword in one parse table
    // is to begin parsing keywords in a second parse table.  An END indicates
    // that the second parse table should return control to the first parse
    // table.  ERROR means that something went very wrong and we're probably
    // hosed, but it allows some error recovery from within a nested parse
    // table.

    if (token.type() == END || token.type() == EXIT || token.type() == rtt_parser::ERROR) {
      return token;
    }

    // A Parse_Table assumes that every construct begins with a keyword.  This
    // keyword is matched to the keyword table, and if a match is found, control
    // is directed to the associated parse function, which can be written to
    // accept just about any construct you wish.  However, by the time return
    // controls from a parse function, the token stream should be pointing
    // either at a terminating token or the next keyword.

    if (token.type() == KEYWORD) {
      // Attempt to match the keyword to the keyword table.  The following call
      // returns an iterator pointing to the first keyword in the table whose
      // lexical ordering is greater than or equal to the keyword token.  The
      // lexical ordering is supplied by the comp object.

      vector<Keyword>::const_iterator const match =
          lower_bound(vec.begin(), vec.end(), token, comp);

      if (match == vec.end() || comp.kt_comparison(match->moniker, token.text().c_str()) != 0) {
        // The token was not lexically equal to anything in the keyword table.
        // In other words, the keyword is unrecognized by the Parse_Table.  The
        // error recovery procedure is to generate a diagnostic, then pull
        // additional tokens off the token stream (without generating further
        // diagnostics) until one is recognized as either a keyword or a
        // terminating token.  We implement this behavior by setting the
        // is_recovering flag when the first invalid token is encountered, and
        // resetting this flag as soon as a valid token is encountered.

        if (!is_recovering) {
          // We are not recovering from a previous error.  Generate a
          // diagnostic, and flag that we are now in error recovery mode.

          tokens.report_semantic_error(token, ": unrecognized keyword: " + token.text());

          // Give the user the possibilities.
          tokens.comment("Perhaps you meant one of:");
          for (auto const &i : vec) {
            tokens.comment(string("  ") + i.moniker);
            if (i.description != nullptr) {
              tokens.comment(string("    ") + i.description);
            }
          }

          is_recovering = true;
        }
        // else we are in recovery mode, and additional diagnostics are disabled
        // until we see a valid construct.
      } else {
        // We have a valid match.  However, depending on Parse_Table options,
        // the match might be ambiguous.  For example if the Parse_Table option
        // to allow partial matches is active, the keyword token may partially
        // match more than one keyword in the keyword table.  Check for an
        // ambiguous match:

        if (match + 1 != vec.end() &&
            comp.kt_comparison(match[1].moniker, token.text().c_str()) == 0) {
          // The match is ambiguous.  This is diagnosed whether or not we are
          // already in recovery mode, but it does put us into recovery mode.

          tokens.report_semantic_error(token, "ambiguous keyword: " + token.text());
          is_recovering = true;
        } else {
          is_recovering = false;
          // We successfully processed something, so we are no longer in
          // recovery mode.

          try {
            // Call the parse function associated with the keyword.
            match->func(tokens, match->index);

            if (flags_ & ONCE)
            // Quit after parsing a single keyword. This is useful for parse
            // tables for selecting one of a set of short options.
            {
              return Token(END, "");
            }
          } catch (const Syntax_Error &) {
            // If the parse function detects a syntax error, and if it does not
            // have its own error recovery policy (or is unable to recover), it
            // should call tokens.Report_Syntax_Error which generates a
            // diagnostic and throws a Syntax_Error exception. This puts the
            // main parser into recovery mode.

            is_recovering = true;
          }
        }
      }
    } else if (token.type() == OTHER && token.text() == ";") {
      // Treat a semicolon token as an empty keyword.  We are no longer in
      // recovery mode, but we don't actually do anything.

      is_recovering = false;
    } else {
      // The next token in the token stream is not a keyword, indicating a
      // syntax error. Error recovery consists of generating a diagnostic
      // message, then continuing to pull tokens off the token stream (without
      // generating any further diagnostics) until one is recognized as either a
      // keyword or a terminating token.  We implement this behavior by setting
      // the is_recovering flag when the first invalid token is encountered, and
      // resetting this flag as soon as a valid token is encountered.

      if (!is_recovering) {
        // We are not recovering from a previous error.  Generate a diagnostic,
        // and flag that we are now in error recovery mode.

        std::ostringstream msg;
        msg << "expected a keyword, but saw " << token.text();
        tokens.report_semantic_error(token, msg.str());
        is_recovering = true;
      }
      // else we are in recovery mode, and additional diagnostics are disabled
      // until we see a valid construct.
    }
  }
}
//------------------------------------------------------------------------------------------------//
/*!
 * Parse the stream of tokens until an END, EXIT, or ERROR token is
 * reached.
 *
 * \param tokens
 * The Token Stream from which to obtain the stream of tokens.
 *
 * \return The terminating token: either END, EXIT, or ERROR.
 *
 * \throw rtt_dsxx::assertion If the keyword table is ambiguous.
 */
Parse the stream of tokens until an END, EXIT, or ERROR token is
reached.

\param tokens
The Token Stream from which to obtain the stream of tokens.

\return The terminating token: either END, EXIT, or ERROR.

\throw rtt_dsxx::assertion If the keyword table is ambiguous.
Parse the stream of tokens until an END EXIT or ERROR token is reached . \ param tokens The Token Stream from which to obtain the stream of tokens . \ return The terminating token : either END EXIT or ERROR . \ throw rtt_dsxx :: assertion If the keyword table is ambiguous .
Token Parse_Table::parse(Token_Stream &tokens) const {
  bool is_recovering = false;
  Keyword_Compare_ const comp(flags_);
  for (;;) {
    Token const token = tokens.shift();
    if (token.type() == END || token.type() == EXIT || token.type() == rtt_parser::ERROR) {
      return token;
    }
    if (token.type() == KEYWORD) {
      vector<Keyword>::const_iterator const match =
          lower_bound(vec.begin(), vec.end(), token, comp);
      if (match == vec.end() || comp.kt_comparison(match->moniker, token.text().c_str()) != 0) {
        if (!is_recovering) {
          tokens.report_semantic_error(token, ": unrecognized keyword: " + token.text());
          tokens.comment("Perhaps you meant one of:");
          for (auto const &i : vec) {
            tokens.comment(string("  ") + i.moniker);
            if (i.description != nullptr) {
              tokens.comment(string("    ") + i.description);
            }
          }
          is_recovering = true;
        }
      } else {
        if (match + 1 != vec.end() &&
            comp.kt_comparison(match[1].moniker, token.text().c_str()) == 0) {
          tokens.report_semantic_error(token, "ambiguous keyword: " + token.text());
          is_recovering = true;
        } else {
          is_recovering = false;
          try {
            match->func(tokens, match->index);
            if (flags_ & ONCE)
            {
              return Token(END, "");
            }
          } catch (const Syntax_Error &) {
            is_recovering = true;
          }
        }
      }
    } else if (token.type() == OTHER && token.text() == ";") {
      is_recovering = false;
    } else {
      if (!is_recovering) {
         diagnostic,
        std::ostringstream msg;
        msg << "expected a keyword, but saw " << token.text();
        tokens.report_semantic_error(token, msg.str());
        is_recovering = true;
      }
    }
  }
}
Token Parse_Table :: parse ( Token_Stream & tokens ) const { bool is_recovering = false ; Keyword_Compare_ const comp ( flags_ ) ; for ( ; ; ) { Token const token = tokens . shift ( ) ; if ( token . type ( ) == END || token . type ( ) == EXIT || token . type ( ) == rtt_parser :: ERROR ) { return token ; } if ( token . type ( ) == KEYWORD ) { vector < Keyword > :: const_iterator const match = lower_bound ( vec . begin ( ) , vec . end ( ) , token , comp ) ; if ( match == vec . end ( ) || comp . kt_comparison ( match -> moniker , token . text ( ) . c_str ( ) ) != 0 ) { if ( ! is_recovering ) { tokens . report_semantic_error ( token , " " + token . text ( ) ) ; tokens . comment ( " " ) ; for ( auto const & i : vec ) { tokens . comment ( string ( " " ) + i . moniker ) ; if ( i . description != nullptr ) { tokens . comment ( string ( " " ) + i . description ) ; } } is_recovering = true ; } } else { if ( match + 1 != vec . end ( ) && comp . kt_comparison ( match [ 1 ] . moniker , token . text ( ) . c_str ( ) ) == 0 ) { tokens . report_semantic_error ( token , " " + token . text ( ) ) ; is_recovering = true ; } else { is_recovering = false ; try { match -> func ( tokens , match -> index ) ; if ( flags_ & ONCE ) { return Token ( END , " " ) ; } } catch ( const Syntax_Error & ) { is_recovering = true ; } } } } else if ( token . type ( ) == OTHER && token . text ( ) == " " ) { is_recovering = false ; } else { if ( ! is_recovering ) { std :: ostringstream msg ; msg << " " << token . text ( ) ; tokens . report_semantic_error ( token , msg . str ( ) ) ; is_recovering = true ; } } } }
Parse the stream of tokens until an END, EXIT, or ERROR token is
 reached.
Parse the stream of tokens until an END EXIT or ERROR token is reached .
// The is_recovering flag is used during error recovery to suppress additional // error messages.  This reduces the likelihood that a single error in a token // stream will generate a large number of error messages. // Create a comparator object that will be used to attempt to match keywords // in the Token_Stream to keywords in the Parse_Table.  This comparator object // incorporates the current settings of the Parse_Table, such as case // sensitivity and partial matching options. // Now begin the process of pulling keywords off the input token stream, and // attempting to match these to the keyword table. // The END, EXIT, and ERROR tokens are terminating tokens.  EXIT means the // end of the token stream has been reached.  END is used to flag the end of // a nested parse, where the result of matching a keyword in one parse table // is to begin parsing keywords in a second parse table.  An END indicates // that the second parse table should return control to the first parse // table.  ERROR means that something went very wrong and we're probably // hosed, but it allows some error recovery from within a nested parse // table. // A Parse_Table assumes that every construct begins with a keyword.  This // keyword is matched to the keyword table, and if a match is found, control // is directed to the associated parse function, which can be written to // accept just about any construct you wish.  However, by the time return // controls from a parse function, the token stream should be pointing // either at a terminating token or the next keyword. // Attempt to match the keyword to the keyword table.  The following call // returns an iterator pointing to the first keyword in the table whose // lexical ordering is greater than or equal to the keyword token.  The // lexical ordering is supplied by the comp object. // The token was not lexically equal to anything in the keyword table. // In other words, the keyword is unrecognized by the Parse_Table.  The // error recovery procedure is to generate a diagnostic, then pull // additional tokens off the token stream (without generating further // diagnostics) until one is recognized as either a keyword or a // terminating token.  We implement this behavior by setting the // is_recovering flag when the first invalid token is encountered, and // resetting this flag as soon as a valid token is encountered. // We are not recovering from a previous error.  Generate a // diagnostic, and flag that we are now in error recovery mode. // Give the user the possibilities. // else we are in recovery mode, and additional diagnostics are disabled // until we see a valid construct. // We have a valid match.  However, depending on Parse_Table options, // the match might be ambiguous.  For example if the Parse_Table option // to allow partial matches is active, the keyword token may partially // match more than one keyword in the keyword table.  Check for an // ambiguous match: // The match is ambiguous.  This is diagnosed whether or not we are // already in recovery mode, but it does put us into recovery mode. // We successfully processed something, so we are no longer in // recovery mode. // Call the parse function associated with the keyword. // Quit after parsing a single keyword. This is useful for parse // tables for selecting one of a set of short options. // If the parse function detects a syntax error, and if it does not // have its own error recovery policy (or is unable to recover), it // should call tokens.Report_Syntax_Error which generates a // diagnostic and throws a Syntax_Error exception. This puts the // main parser into recovery mode. // Treat a semicolon token as an empty keyword.  We are no longer in // recovery mode, but we don't actually do anything. // The next token in the token stream is not a keyword, indicating a // syntax error. Error recovery consists of generating a diagnostic // message, then continuing to pull tokens off the token stream (without // generating any further diagnostics) until one is recognized as either a // keyword or a terminating token.  We implement this behavior by setting // the is_recovering flag when the first invalid token is encountered, and // resetting this flag as soon as a valid token is encountered. // We are not recovering from a previous error.  Generate a diagnostic, // and flag that we are now in error recovery mode. // else we are in recovery mode, and additional diagnostics are disabled // until we see a valid construct.