Teuchos - Trilinos Tools Package  Version of the Day
Teuchos_Grammar.cpp
1 #include "Teuchos_Grammar.hpp"
2 
3 #include <Teuchos_Assert.hpp>
4 #include <set>
5 #include <iostream>
6 
7 #include "Teuchos_vector.hpp"
8 #include "Teuchos_Parser.hpp"
9 
10 namespace Teuchos {
11 
12 int get_nnonterminals(Grammar const& g) {
13  return g.nsymbols - g.nterminals;
14 }
15 
16 bool is_terminal(Grammar const& g, int symbol) {
17  TEUCHOS_DEBUG_ASSERT(0 <= symbol);
18  TEUCHOS_DEBUG_ASSERT(symbol <= g.nsymbols);
19  return symbol < g.nterminals;
20 }
21 
22 bool is_nonterminal(Grammar const& g, int symbol) {
23  return !is_terminal(g, symbol);
24 }
25 
26 int as_nonterminal(Grammar const& g, int symbol) {
27  return symbol - g.nterminals;
28 }
29 
30 int find_goal_symbol(Grammar const& g) {
31  std::set<int> nonterminals_in_rhss;
32  for (int i = 0; i < size(g.productions); ++i) {
33  const Grammar::Production& p = at(g.productions, i);
34  for (int j = 0; j < size(p.rhs); ++j) {
35  const int s = at(p.rhs, j);
36  TEUCHOS_DEBUG_ASSERT(0 <= s);
37  if (is_nonterminal(g, s)) nonterminals_in_rhss.insert(s);
38  }
39  }
40  int result = -1;
41  for (int s = g.nterminals; s < g.nsymbols; ++s)
42  if (!nonterminals_in_rhss.count(s)) {
43  TEUCHOS_TEST_FOR_EXCEPTION(result != -1, ParserFail,
44  "ERROR: there is more than one root nonterminal ("
45  << at(g.symbol_names, result) << " and "
46  << at(g.symbol_names, s) << ") in this grammar\n");
47  result = s;
48  }
49  TEUCHOS_TEST_FOR_EXCEPTION(result == -1, ParserFail,
50  "ERROR: the root nonterminal is unclear for this grammar\n"
51  "usually this means all nonterminals appear in the RHS of a production\n"
52  "and can be fixed by adding a new nonterminal root2, root2 -> root\n");
53  return result;
54 }
55 
56 void add_end_terminal(Grammar& g) {
57  for (int i = 0; i < size(g.productions); ++i) {
58  Grammar::Production& prod = at(g.productions, i);
59  if (is_nonterminal(g, prod.lhs)) prod.lhs++;
60  for (int j = 0; j < size(prod.rhs); ++j) {
61  int& rhs_symb = at(prod.rhs, j);
62  if (is_nonterminal(g, rhs_symb)) rhs_symb++;
63  }
64  }
65  g.symbol_names.insert(g.symbol_names.begin() + g.nterminals, "EOF");
66  g.nterminals++;
67  g.nsymbols++;
68 }
69 
70 int get_end_terminal(Grammar const& g) {
71  return g.nterminals - 1;
72 }
73 
74 void add_accept_production(Grammar& g) {
75  int goal_symbol = find_goal_symbol(g);
76  Grammar::Production p;
77  p.lhs = g.nsymbols;
78  p.rhs.push_back(goal_symbol);
79  g.productions.push_back(p);
80  g.symbol_names.push_back("ACCEPT");
81  g.nsymbols++;
82 }
83 
84 int get_accept_production(Grammar const& g) {
85  return size(g.productions) - 1;
86 }
87 
88 int get_accept_nonterminal(Grammar const& g) {
89  return g.nsymbols - 1;
90 }
91 
92 std::ostream& operator<<(std::ostream& os, Grammar const& g) {
93  os << "symbols:\n";
94  for (int i = 0; i < size(g.symbol_names); ++i) {
95  os << i << ": " << at(g.symbol_names, i) << "\n";
96  }
97  os << "productions:\n";
98  for (int i = 0; i < size(g.productions); ++i) {
99  const Grammar::Production& prod = at(g.productions, i);
100  os << i << ": " << prod.lhs << " ::=";
101  for (int j = 0; j < size(prod.rhs); ++j) {
102  int symb = at(prod.rhs, j);
103  os << ' ' << symb;
104  }
105  os << '\n';
106  }
107  os << '\n';
108  return os;
109 }
110 
111 }
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging.
Declares Teuchos::Parser, ParserFail and make_lalr1_parser.
The Teuchos namespace contains all of the classes, structs and enums used by Teuchos, as well as a number of utility routines.