19 #include "Teuchos_string.hpp" 
   20 #include "Teuchos_vector.hpp" 
   27 void print_indicator(std::ostream& os, std::string 
const& above, std::size_t pos) {
 
   28   for (std::size_t i = 0; i < pos; ++i) {
 
   29     if (above.at(i) == 
'\t') os << 
'\t';
 
   35 void print_underline(std::ostream& os, std::string 
const& above, std::size_t start, std::size_t end) {
 
   36   for (std::size_t i = 0; i < start; ++i) {
 
   37     if (above.at(i) == 
'\t') os << 
'\t';
 
   40   for (std::size_t i = start; i < end; ++i) os << 
'~';
 
   46 Reader::IndentStackEntry::IndentStackEntry(std::size_t l, std::size_t s, std::size_t e):
 
   47   line(l),start_length(s),end_length(e) {
 
   50 void Reader::at_token(std::istream& stream) {
 
   55     const Action& parser_action = get_action(parser, parser_state, lexer_token);
 
   56     if (parser_action.kind == ACTION_NONE) {
 
   58       ss << 
"error: Parser failure at line " << line;
 
   59       ss << 
" column " << column << 
" of " << stream_name << 
'\n';
 
   60       error_print_line(stream, ss);
 
   61       std::set<std::string> expect_names;
 
   62       for (
int expect_token = 0;
 
   63            expect_token < grammar->nterminals; ++expect_token) {
 
   64         const Action& expect_action = get_action(parser, parser_state, expect_token);
 
   65         if (expect_action.kind != ACTION_NONE) {
 
   66           expect_names.insert(at(grammar->symbol_names, expect_token));
 
   69       ss << 
"Expected one of {";
 
   70       for (std::set<std::string>::iterator it = expect_names.begin();
 
   71            it != expect_names.end(); ++it) {
 
   72         if (it != expect_names.begin()) ss << 
", ";
 
   73         if (*it == 
",") ss << 
"','";
 
   77       ss << 
"Got: " << at(grammar->symbol_names, lexer_token) << 
'\n';
 
   78       ss << 
"Lexer text: \"" << lexer_text << 
"\"\n";
 
   79       ss << 
"Parser was in state " << parser_state << 
'\n';
 
   80       throw ParserFail(ss.str());
 
   81     } 
else if (parser_action.kind == ACTION_SHIFT) {
 
   83         symbol_indentation_stack.push_back(indent_text.size());
 
   86       this->at_shift(shift_result, lexer_token, lexer_text);
 
   87       add_back(value_stack, shift_result);
 
   89     } 
else if (parser_action.kind == ACTION_REDUCE) {
 
   90       if (parser_action.production == get_accept_production(*grammar)) {
 
   94       const Grammar::Production& prod = at(grammar->productions, parser_action.production);
 
   95       reduction_rhs.clear();
 
   96       for (
int i = 0; i < Teuchos::size(prod.rhs); ++i) {
 
   97         add_back(reduction_rhs, at(value_stack, Teuchos::size(value_stack) - Teuchos::size(prod.rhs) + i));
 
   99       resize(value_stack, Teuchos::size(value_stack) - Teuchos::size(prod.rhs));
 
  102         this->at_reduce(reduce_result, parser_action.production, reduction_rhs);
 
  103       } 
catch (
const ParserFail& e) {
 
  104         std::stringstream ss;
 
  105         ss << 
"error: Parser failure at line " << line;
 
  106         ss << 
" column " << column << 
" of " << stream_name << 
'\n';
 
  107         error_print_line(stream, ss);
 
  108         ss << 
'\n' << e.what();
 
  109         throw ParserFail(ss.str());
 
  111       add_back(value_stack, reduce_result);
 
  112       if (sensing_indent) {
 
  113         if (Teuchos::size(prod.rhs)) {
 
  114           resize(symbol_indentation_stack,
 
  115               (Teuchos::size(symbol_indentation_stack) + 1)
 
  116               - Teuchos::size(prod.rhs));
 
  118           symbol_indentation_stack.push_back(symbol_indentation_stack.back());
 
  123           "SERIOUS BUG: Action::kind enum value not in range\n");
 
  125     parser_state = execute_action(parser, parser_stack, parser_action);
 
  129 void Reader::indent_mismatch() {
 
  131   const IndentStackEntry& top = indent_stack.back();
 
  132   std::stringstream ss;
 
  133   ss << 
"error: Indentation characters beginning line " << line << 
" of " << stream_name
 
  134     << 
" don't match those beginning line " << top.line << 
'\n';
 
  135   ss << 
"It is strongly recommended not to mix tabs and spaces in indentation-sensitive formats\n";
 
  136   throw ParserFail(ss.str());
 
  139 void Reader::at_token_indent(std::istream& stream) {
 
  140   if (!sensing_indent || lexer_token != tables->indent_info.newline_token) {
 
  144   std::size_t last_newline_pos = lexer_text.find_last_of(
"\n");
 
  145   if (last_newline_pos == std::string::npos) {
 
  146     throw ParserFail(
"INDENT token did not contain a newline '\\n' !\n");
 
  148   std::string lexer_indent = lexer_text.substr(last_newline_pos + 1, std::string::npos);
 
  152   std::size_t minlen = std::min(lexer_indent.length(), indent_text.length());
 
  153   if (lexer_indent.length() > indent_text.length()) {
 
  154     if (0 != lexer_indent.compare(0, indent_text.length(), indent_text)) {
 
  157     indent_stack.push_back(IndentStackEntry(line, indent_text.length(), lexer_indent.length()));
 
  158     indent_text = lexer_indent;
 
  159     lexer_token = tables->indent_info.indent_token;
 
  161   } 
else if (lexer_indent.length() < indent_text.length()) {
 
  162     if (0 != indent_text.compare(0, lexer_indent.length(), lexer_indent)) {
 
  165     while (!indent_stack.empty()) {
 
  166       const IndentStackEntry& top = indent_stack.back();
 
  167       if (top.end_length <= minlen) 
break;
 
  168       indent_stack.pop_back();
 
  169       lexer_token = tables->indent_info.dedent_token;
 
  172     indent_text = lexer_indent;
 
  174     if (0 != lexer_indent.compare(indent_text)) {
 
  180 void Reader::backtrack_to_last_accept(std::istream& stream) {
 
  183   line = last_lexer_accept_line;
 
  184   column = last_lexer_accept_column;
 
  185   line_text = last_lexer_accept_line_text;
 
  186   while (lexer_text.size() > last_lexer_accept) {
 
  187     bool ok = !stream.unget().fail();
 
  189     resize(lexer_text, Teuchos::size(lexer_text) - 1);
 
  193 void Reader::reset_lexer_state() {
 
  199 void Reader::at_lexer_end(std::istream& stream) {
 
  200   if (lexer_token == -1) {
 
  201     std::stringstream ss;
 
  202     if (lexer_text.find(
'\n') == std::string::npos) {
 
  203       ss << 
"error: Could not tokenize this (line " <<  line;
 
  204       ss << 
" column " << column << 
" of " << stream_name << 
"):\n";
 
  205       ss << line_text << 
'\n';
 
  207       print_underline(ss, line_text, line_text.size() - lexer_text.size(), line_text.size());
 
  209       ss << 
"error: Could not tokenize this (ends at line " << line;
 
  210       ss << 
" column " << column << 
" of " << stream_name << 
"):\n";
 
  211       ss << lexer_text << 
'\n';
 
  213     throw ParserFail(ss.str());
 
  215   backtrack_to_last_accept(stream);
 
  216   at_token_indent(stream);
 
  222   parser(tables->parser),
 
  223   lexer(tables->lexer),
 
  224   grammar(get_grammar(parser))
 
  229 void Reader::update_position(
char c) {
 
  239 void Reader::error_print_line(std::istream& is, std::ostream& os) {
 
  240   std::size_t oldpos = line_text.size();
 
  243     if (c == 
'\n' || c == 
'\r') 
break;
 
  244     line_text.push_back(c);
 
  246   if (line_text.empty()) 
return;
 
  247   os << line_text << 
'\n';
 
  248   if (oldpos > 0) print_indicator(os, line_text, oldpos - 1);
 
  260   parser_stack.clear();
 
  261   parser_stack.push_back(parser_state);
 
  264   stream_name = stream_name_in;
 
  265   if (tables->indent_info.is_sensitive) {
 
  266     sensing_indent = 
true;
 
  268     indent_stack.clear();
 
  270     sensing_indent = 
false;
 
  273   while (stream.get(c)) {
 
  275       std::stringstream ss;
 
  276       ss << 
"error: Unexpected character code " << int(c);
 
  277       ss << 
" at line " << line << 
" column " << column;
 
  278       ss << 
" of " << stream_name << 
'\n';
 
  279       error_print_line(stream, ss);
 
  282     line_text.push_back(c);
 
  283     lexer_text.push_back(c);
 
  284     int lexer_symbol = get_symbol(c);
 
  285     lexer_state = step(lexer, lexer_state, lexer_symbol);
 
  286     if (lexer_state == -1) {
 
  287       at_lexer_end(stream);
 
  289       int token = accepts(lexer, lexer_state);
 
  293         last_lexer_accept = lexer_text.size();
 
  294         last_lexer_accept_line = line;
 
  295         last_lexer_accept_column = column;
 
  296         last_lexer_accept_line_text = line_text;
 
  300   if (last_lexer_accept < lexer_text.size()) {
 
  301     std::stringstream ss;
 
  302     std::string bad_str = lexer_text.substr(last_lexer_accept, std::string::npos);
 
  303     ss << 
"error: Could not tokenize \"" << bad_str;
 
  304     ss << 
"\" at end of " << stream_name << 
'\n';
 
  307   at_lexer_end(stream);
 
  308   lexer_token = get_end_terminal(*grammar);
 
  311       "The EOF terminal was accepted but the root nonterminal was not reduced\n" 
  312       "This indicates a bug in Teuchos::Reader\n");
 
  314   swap(result, value_stack.back());
 
  318   std::istringstream stream(
string);
 
  323   std::ifstream stream(file_name.c_str());
 
  326       "Could not open file " << file_name);
 
  336 DebugReader::DebugReader(
ReaderTablesPtr tables_in, std::ostream& os_in):
 
  337   Reader(tables_in),os(os_in)
 
  341 void DebugReader::at_shift(any& result, 
int token, std::string& text) {
 
  342   std::string& text_escaped = make_any_ref<std::string>(result);
 
  343   for (std::size_t i = 0; i < text.size(); ++i) {
 
  346       case '\n': text_escaped.append(
"\\n"); 
break;
 
  347       case '\t': text_escaped.append(
"\\t"); 
break;
 
  348       case '\r': text_escaped.append(
"\\r"); 
break;
 
  349       default: text_escaped.push_back(c);
 
  352   os << 
"SHIFT (" << at(grammar->symbol_names, token) << 
")[" << text_escaped << 
"]\n";
 
  355 void DebugReader::at_reduce(any& result, 
int prod_i, std::vector<any>& rhs) {
 
  357   std::string& lhs_text = make_any_ref<std::string>(result);
 
  358   const Grammar::Production& prod = at(grammar->productions, prod_i);
 
  359   for (
int i = 0; i < Teuchos::size(prod.rhs); ++i) {
 
  360     const std::string& rhs_name = at(grammar->symbol_names, at(prod.rhs, i));
 
  361     const std::string& rhs_text = any_ref_cast<std::string>(at(rhs, i));
 
  362     os << 
" (" << rhs_name << 
")[" << rhs_text << 
"]";
 
  363     lhs_text.append(rhs_text);
 
  365   const std::string& lhs_name = at(grammar->symbol_names, prod.lhs);
 
  366   os << 
" -> (" << lhs_name << 
")[" << lhs_text << 
"]\n";
 
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging. 
Tries to create LALR(1) parser tables for a given grammar. 
void read_file(any &result, std::string const &file_name)
A convenience method for reading a file. 
void read_string(any &result, std::string const &string, std::string const &string_name)
A convenience method for reading a string. 
Modified boost::any class, which is a container for a templated value. 
Declares Teuchos::Parser, ParserFail and make_lalr1_parser. 
The main class for users to read text using TeuchosParser. 
virtual void at_reduce(any &result, int production, std::vector< any > &rhs)
User-overridable REDUCE (production) method. 
virtual void at_shift(any &result, int token, std::string &text)
User-overridable SHIFT (token) method. 
#define TEUCHOS_ASSERT(assertion_test)
This macro is throws when an assert fails. 
void read_stream(any &result, std::istream &stream, std::string const &stream_name_in)
The main method for reading a stream of text. 
Declares Teuchos::Reader.