Algorithms Library Toolkit
A toolkit for algorithms, especially for algorithms on formal languages
LeftRecursionRemover.h
Go to the documentation of this file.
1
6#pragma once
7
8#include <ext/algorithm>
9
19
22
23#include <alib/vector>
25
26namespace grammar {
27
28namespace simplify {
29
31 template < class TerminalSymbolType, class NonterminalSymbolType >
33
34 template < class TerminalSymbolType, class NonterminalSymbolType >
36public:
47 template < class TerminalSymbolType, class NonterminalSymbolType >
49
60 template < class TerminalSymbolType, class NonterminalSymbolType >
62
73 template < class TerminalSymbolType, class NonterminalSymbolType >
75
86 template < class TerminalSymbolType, class NonterminalSymbolType >
88
99 template < class TerminalSymbolType, class NonterminalSymbolType >
101
112 template < class TerminalSymbolType, class NonterminalSymbolType >
114
125 template < class TerminalSymbolType, class NonterminalSymbolType >
127};
128
129template < class TerminalSymbolType, class NonterminalSymbolType >
132 res.setNonterminalAlphabet(grammar.getNonterminalAlphabet());
133 res.setTerminalAlphabet(grammar.getTerminalAlphabet());
134 res.setGeneratesEpsilon(grammar.getGeneratesEpsilon());
135
136 for(const auto& nonterminal : grammar.getNonterminalAlphabet()) {
137 if(grammar.getRules().find(nonterminal) == grammar.getRules().end()) continue;
138
139 if(std::any_of(grammar.getRules().find(nonterminal)->second.begin(), grammar.getRules().find(nonterminal)->second.end(), [&](const ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > & singleRHS ) {
140 return singleRHS[0] == nonterminal; // is there a direct left recursion?
141 } ) && std::all_of(grammar.getRules().find(nonterminal)->second.begin(), grammar.getRules().find(nonterminal)->second.end(), [&](const ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > & singleRHS) {
142 return grammar.getTerminalAlphabet().count(singleRHS[0]) || singleRHS[0] >= nonterminal; // only remove left recursion when all nonterminals are bigger than the left hand side
143 })) {
144 NonterminalSymbolType primed = common::createUnique(nonterminal, res.getTerminalAlphabet(), res.getNonterminalAlphabet());
145 res.addNonterminalSymbol(primed);
146 for(const ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > & singleRHS : grammar.getRules().find(nonterminal)->second) { // do the removal
147 if(singleRHS[0] == nonterminal) { // A -> A alpha
148 ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > tmpRHS(singleRHS.begin() + 1, singleRHS.end());
149
150 res.addRule(primed, tmpRHS); // A' -> alpha
151
152 tmpRHS.push_back(primed);
153 res.addRule(primed, tmpRHS); // A' -> alpha A'
154 } else { // a -> beta
156
157 res.addRule(nonterminal, tmpRHS); // A -> beta
158
159 tmpRHS.push_back(primed);
160 res.addRule(nonterminal, tmpRHS); // A -> beta A'
161 }
162 }
163 } else {
164 for(const ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > & singleRHS : grammar.getRules().at(nonterminal)) {
165 res.addRule(nonterminal, singleRHS);
166 }
167 }
168 }
169 return res;
170}
171
172template < class TerminalSymbolType, class NonterminalSymbolType >
175 res.setNonterminalAlphabet(grammar.getNonterminalAlphabet());
176 res.setTerminalAlphabet(grammar.getTerminalAlphabet());
177 res.setGeneratesEpsilon(grammar.getGeneratesEpsilon());
178
179 for(const NonterminalSymbolType& lhs : grammar.getNonterminalAlphabet()) {
180 if(i > 0) {
181 if(grammar.getRules().find(lhs) == grammar.getRules().end()) continue;
182 for ( const ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > & rule : grammar.getRules().find(lhs)->second) {
183 res.addRule(lhs, rule);
184 }
185
186 i--;
187 continue; // substitue only in i-th up to n-th nonterminals
188 }
189 if(grammar.getRules().find(lhs) == grammar.getRules().end()) continue;
190 if(!origNonterminals.contains(lhs)) { // do not subsitute in nonoriginal nonterminals
191 for ( const ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > & rule : grammar.getRules().find(lhs)->second) {
192 res.addRule(lhs, rule);
193 }
194 continue;
195 }
196
198
200 if(res.getTerminalAlphabet().contains(singleRHS[0])) { //do not substitute terminals
201 res.addRule(lhs, singleRHS);
202 continue;
203 }
204 const ext::variant < TerminalSymbolType, NonterminalSymbolType > & secondLHS = singleRHS[0];
205 if(secondLHS >= lhs) { // substitute only by 0th up to i-th nonterminals right hand sides
206 res.addRule(lhs, singleRHS);
207 continue;
208 }
209 if(grammar.getRules().find(secondLHS) == grammar.getRules().end()) { //is there any right hand side to substitue with?
210 //if not well this rule does not generate anything anyway
211 continue;
212 }
213
214 for(const ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > & secondSingleRHS : grammar.getRules().find(secondLHS)->second) { // do the substitution
216 newRHS.insert(newRHS.end(), singleRHS.begin() + 1, singleRHS.end());
217 res.addRule(lhs, newRHS);
218 }
219 }
220 }
221 return res;
222}
223
224template < class TerminalSymbolType, class NonterminalSymbolType >
227 for(const NonterminalSymbolType& nonterminal : step.getNonterminalAlphabet()) { // remove identities
229 }
230 unsigned i = 0;
231 while(i < grammar.getNonterminalAlphabet().size()) {
232 grammar::EpsilonFreeCFG < TerminalSymbolType, NonterminalSymbolType > nextStep = assignAsOrder(directLeftRecursionRemoveAsOrder(step), i, grammar.getNonterminalAlphabet());
233
234 if(step == nextStep) break;
235 step = std::move(nextStep);
236 i++;
237 };
238
239 return step;
240}
241
242template < class TerminalSymbolType, class NonterminalSymbolType >
245 tmp.setTerminalAlphabet(grammar.getTerminalAlphabet());
246 tmp.setNonterminalAlphabet(grammar.getNonterminalAlphabet());
247 tmp.setGeneratesEpsilon(grammar.getGeneratesEpsilon());
248 for(const auto& rule : grammar.getRules()) {
249 for(const auto& rhs : rule.second) {
250 if(rhs.template is < TerminalSymbolType > ( ) ) {
251 tmp.addRule ( rule.first, { rhs.template get < TerminalSymbolType > ( ) } );
252 } else {
253 const auto & rhsPair = rhs.template get < ext::pair < NonterminalSymbolType, NonterminalSymbolType > > ( );
254 tmp.addRule(rule.first, {rhsPair.first, rhsPair.second});
255 }
256 }
257 }
258 return remove(tmp);
259}
260
261template < class TerminalSymbolType, class NonterminalSymbolType >
263 return grammar;
264}
265
266template < class TerminalSymbolType, class NonterminalSymbolType >
268 return grammar;
269}
270
271template < class TerminalSymbolType, class NonterminalSymbolType >
273 return grammar;
274}
275
276template < class TerminalSymbolType, class NonterminalSymbolType >
279}
280
281template < class TerminalSymbolType, class NonterminalSymbolType >
283 throw exception::CommonException("LeftRecursionRemover: Removing from LeftLG NYI"); // TODO
284}
285
286} /* namespace simplify */
287
288} /* namespace grammar */
289
Basic exception from which all other exceptions are derived.
Definition: CommonException.h:21
Definition: set.hpp:44
Implementation of the variant class allowing to store any type of those listed in the template parame...
Definition: variant.hpp:98
Class extending the vector class from the standard library. Original reason is to allow printing of t...
Definition: vector.hpp:45
Chomsky normal form of a context free grammar in Chomsky hierarchy or type 2 in Chomsky hierarchy....
Definition: CNF.h:66
Context free grammar without epsilon rules in Chomsky hierarchy or type 2 in Chomsky hierarchy....
Definition: EpsilonFreeCFG.h:65
void setTerminalAlphabet(ext::set< TerminalSymbolType > symbols)
Definition: EpsilonFreeCFG.h:240
void setNonterminalAlphabet(ext::set< NonterminalSymbolType > symbols)
Definition: EpsilonFreeCFG.h:202
const ext::set< NonterminalSymbolType > & getNonterminalAlphabet() const &
Definition: EpsilonFreeCFG.h:173
bool addRule(NonterminalSymbolType leftHandSide, ext::vector< ext::variant< TerminalSymbolType, NonterminalSymbolType > > rightHandSide)
Add a new rule of a grammar.
Definition: EpsilonFreeCFG.h:308
void setGeneratesEpsilon(bool genEps)
Definition: EpsilonFreeCFG.h:355
bool removeRule(const NonterminalSymbolType &leftHandSide, const ext::vector< ext::variant< TerminalSymbolType, NonterminalSymbolType > > &rightHandSide)
Definition: EpsilonFreeCFG.h:350
Greibach normal form of a context free grammar in Chomsky hierarchy or type 2 in Chomsky hierarchy....
Definition: GNF.h:65
Left linear grammar in Chomsky hierarchy or type 3 in Chomsky hierarchy. Generates regular languages.
Definition: LeftLG.h:66
Left regular grammar in Chomsky hierarchy or type 3 in Chomsky hierarchy. Generates regular languages...
Definition: LeftRG.h:70
Right linear grammar in Chomsky hierarchy or type 3 in Chomsky hierarchy. Generates regular languages...
Definition: RightLG.h:65
Right regular grammar in Chomsky hierarchy or type 3 in Chomsky hierarchy. Generates regular language...
Definition: RightRG.h:70
static grammar::RightRG< TerminalSymbolType, NonterminalSymbolType > convert(const grammar::LeftRG< TerminalSymbolType, NonterminalSymbolType > &grammar)
Definition: ToGrammarRightRG.h:37
Definition: LeftRecursionRemover.h:30
static grammar::EpsilonFreeCFG< TerminalSymbolType, NonterminalSymbolType > remove(const grammar::EpsilonFreeCFG< TerminalSymbolType, NonterminalSymbolType > &grammar)
Definition: LeftRecursionRemover.h:225
return grammar
Definition: ToGrammarLeftRG.h:99
int i
Definition: AllEpsilonClosure.h:118
return res
Definition: MinimizeByPartitioning.h:145
T createUnique(T object, const Alphabets &... alphabets)
Definition: createUnique.hpp:46
all_of(T &&...) -> all_of< T... >
any_of(T &&...) -> any_of< T... >
Definition: ToAutomaton.h:24