Teuchos - Trilinos Tools Package  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Teuchos_Grammar.cpp
1 // @HEADER
2 // *****************************************************************************
3 // Teuchos: Common Tools Package
4 //
5 // Copyright 2004 NTESS and the Teuchos contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #include "Teuchos_Grammar.hpp"
11 
12 #include <Teuchos_Assert.hpp>
13 #include <set>
14 #include <iostream>
15 
16 #include "Teuchos_vector.hpp"
17 #include "Teuchos_Parser.hpp"
18 
19 namespace Teuchos {
20 
21 int get_nnonterminals(Grammar const& g) {
22  return g.nsymbols - g.nterminals;
23 }
24 
25 bool is_terminal(Grammar const& g, int symbol) {
26  TEUCHOS_DEBUG_ASSERT(0 <= symbol);
27  TEUCHOS_DEBUG_ASSERT(symbol <= g.nsymbols);
28  return symbol < g.nterminals;
29 }
30 
31 bool is_nonterminal(Grammar const& g, int symbol) {
32  return !is_terminal(g, symbol);
33 }
34 
35 int as_nonterminal(Grammar const& g, int symbol) {
36  return symbol - g.nterminals;
37 }
38 
39 int find_goal_symbol(Grammar const& g) {
40  std::set<int> nonterminals_in_rhss;
41  for (int i = 0; i < Teuchos::size(g.productions); ++i) {
42  const Grammar::Production& p = at(g.productions, i);
43  for (int j = 0; j < Teuchos::size(p.rhs); ++j) {
44  const int s = at(p.rhs, j);
45  TEUCHOS_DEBUG_ASSERT(0 <= s);
46  if (is_nonterminal(g, s)) nonterminals_in_rhss.insert(s);
47  }
48  }
49  int result = -1;
50  for (int s = g.nterminals; s < g.nsymbols; ++s) {
51  if (!nonterminals_in_rhss.count(s)) {
52  TEUCHOS_TEST_FOR_EXCEPTION(result != -1, ParserFail,
53  "ERROR: there is more than one root nonterminal ("
54  << at(g.symbol_names, result) << " [" << result << "] and "
55  << at(g.symbol_names, s) << " [" << s << "]) in this grammar\n");
56  result = s;
57  }
58  }
59  TEUCHOS_TEST_FOR_EXCEPTION(result == -1, ParserFail,
60  "ERROR: the root nonterminal is unclear for this grammar\n"
61  "usually this means all nonterminals appear in the RHS of a production\n"
62  "and can be fixed by adding a new nonterminal root2, root2 -> root\n");
63  return result;
64 }
65 
66 void add_end_terminal(Grammar& g) {
67  for (int i = 0; i < Teuchos::size(g.productions); ++i) {
68  Grammar::Production& prod = at(g.productions, i);
69  if (is_nonterminal(g, prod.lhs)) prod.lhs++;
70  for (int j = 0; j < Teuchos::size(prod.rhs); ++j) {
71  int& rhs_symb = at(prod.rhs, j);
72  if (is_nonterminal(g, rhs_symb)) rhs_symb++;
73  }
74  }
75  g.symbol_names.insert(g.symbol_names.begin() + g.nterminals, "EOF");
76  g.nterminals++;
77  g.nsymbols++;
78 }
79 
80 int get_end_terminal(Grammar const& g) {
81  return g.nterminals - 1;
82 }
83 
84 void add_accept_production(Grammar& g) {
85  int goal_symbol = find_goal_symbol(g);
86  Grammar::Production p;
87  p.lhs = g.nsymbols;
88  p.rhs.push_back(goal_symbol);
89  g.productions.push_back(p);
90  g.symbol_names.push_back("ACCEPT");
91  g.nsymbols++;
92 }
93 
94 int get_accept_production(Grammar const& g) {
95  return Teuchos::size(g.productions) - 1;
96 }
97 
98 int get_accept_nonterminal(Grammar const& g) {
99  return g.nsymbols - 1;
100 }
101 
102 std::ostream& operator<<(std::ostream& os, Grammar const& g) {
103  os << "symbols:\n";
104  for (int i = 0; i < Teuchos::size(g.symbol_names); ++i) {
105  os << i << ": " << at(g.symbol_names, i) << "\n";
106  }
107  os << "productions:\n";
108  for (int i = 0; i < Teuchos::size(g.productions); ++i) {
109  const Grammar::Production& prod = at(g.productions, i);
110  os << i << ": " << prod.lhs << " ::=";
111  for (int j = 0; j < Teuchos::size(prod.rhs); ++j) {
112  int symb = at(prod.rhs, j);
113  os << ' ' << symb;
114  }
115  os << '\n';
116  }
117  os << '\n';
118  return os;
119 }
120 
121 }
#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.