Algorithms Library Toolkit
A toolkit for algorithms, especially for algorithms on formal languages
CFG.h
Go to the documentation of this file.
1
6/*
7 * This file is part of Algorithms library toolkit.
8 * Copyright (C) 2017 Jan Travnicek (jan.travnicek@fit.cvut.cz)
9
10 * Algorithms library toolkit is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 3 of the License, or
13 * (at your option) any later version.
14
15 * Algorithms library toolkit is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19
20 * You should have received a copy of the GNU General Public License
21 * along with Algorithms library toolkit. If not, see <http://www.gnu.org/licenses/>.
22 */
23
24#pragma once
25
26
27#include <ext/algorithm>
28
29#include <alib/map>
30#include <alib/set>
31#include <alib/vector>
32
33#include <core/components.hpp>
34
36
38
39#include <core/normalize.hpp>
42
43#include "EpsilonFreeCFG.h"
44
45namespace grammar {
46
47class TerminalAlphabet;
48class NonterminalAlphabet;
49class InitialSymbol;
50
66template < class TerminalSymbolType = DefaultSymbolType, class NonterminalSymbolType = DefaultSymbolType >
67class CFG final : public core::Components < CFG < TerminalSymbolType, NonterminalSymbolType >, ext::set < TerminalSymbolType >, component::Set, TerminalAlphabet, ext::set < NonterminalSymbolType >, component::Set, NonterminalAlphabet, NonterminalSymbolType, component::Value, InitialSymbol > {
72
73public:
79 explicit CFG ( NonterminalSymbolType initialSymbol );
80
88 explicit CFG ( ext::set < NonterminalSymbolType > nonterminalAlphabet, ext::set < TerminalSymbolType > terminalAlphabet, NonterminalSymbolType initialSymbol );
89
90 /*
91 * \brief Creates a new instance of the grammar based on the Epsilon free context free grammar.
92 *
93 * \param other the Epsilon free context free grammar
94 */
96
107 bool addRule ( NonterminalSymbolType leftHandSide, ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > rightHandSide );
108
117 void addRules ( NonterminalSymbolType leftHandSide, ext::set < ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > > rightHandSide );
118
125
132
141 bool removeRule ( const NonterminalSymbolType & leftHandSide, const ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > & rightHandSide );
142
148 const NonterminalSymbolType & getInitialSymbol ( ) const & {
149 return this->template accessComponent < InitialSymbol > ( ).get ( );
150 }
151
157 NonterminalSymbolType && getInitialSymbol ( ) && {
158 return std::move ( this->template accessComponent < InitialSymbol > ( ).get ( ) );
159 }
160
168 bool setInitialSymbol ( NonterminalSymbolType symbol ) {
169 return this->template accessComponent < InitialSymbol > ( ).set ( std::move ( symbol ) );
170 }
171
178 return this->template accessComponent < NonterminalAlphabet > ( ).get ( );
179 }
180
187 return std::move ( this->template accessComponent < NonterminalAlphabet > ( ).get ( ) );
188 }
189
197 bool addNonterminalSymbol ( NonterminalSymbolType symbol ) {
198 return this->template accessComponent < NonterminalAlphabet > ( ).add ( std::move ( symbol ) );
199 }
200
207 this->template accessComponent < NonterminalAlphabet > ( ).set ( std::move ( symbols ) );
208 }
209
216 return this->template accessComponent < TerminalAlphabet > ( ).get ( );
217 }
218
225 return std::move ( this->template accessComponent < TerminalAlphabet > ( ).get ( ) );
226 }
227
235 bool addTerminalSymbol ( TerminalSymbolType symbol ) {
236 return this->template accessComponent < TerminalAlphabet > ( ).add ( std::move ( symbol ) );
237 }
238
245 this->template accessComponent < TerminalAlphabet > ( ).set ( std::move ( symbols ) );
246 }
247
255 auto operator <=> ( const CFG & other ) const {
256 return std::tie ( getTerminalAlphabet ( ), getNonterminalAlphabet ( ), getInitialSymbol ( ), rules ) <=> std::tie ( other.getTerminalAlphabet ( ), other.getNonterminalAlphabet ( ), other.getInitialSymbol ( ), other.rules );
257 }
258
266 bool operator == ( const CFG & other ) const {
267 return std::tie ( getTerminalAlphabet ( ), getNonterminalAlphabet ( ), getInitialSymbol ( ), rules ) == std::tie ( other.getTerminalAlphabet ( ), other.getNonterminalAlphabet ( ), other.getInitialSymbol ( ), other.rules );
268 }
269
278 friend ext::ostream & operator << ( ext::ostream & out, const CFG & instance ) {
279 return out << "(CFG"
280 << " nonterminalAlphabet = " << instance.getNonterminalAlphabet ( )
281 << " terminalAlphabet = " << instance.getTerminalAlphabet ( )
282 << " initialSymbol = " << instance.getInitialSymbol ( )
283 << " rules = " << instance.getRules ( )
284 << ")";
285 }
286};
287
288template < class TerminalSymbolType, class NonterminalSymbolType >
289CFG < TerminalSymbolType, NonterminalSymbolType >::CFG ( NonterminalSymbolType initialSymbol ) : CFG ( ext::set < NonterminalSymbolType > { initialSymbol }, ext::set < TerminalSymbolType > ( ), initialSymbol ) {
290}
291
292template < class TerminalSymbolType, class NonterminalSymbolType >
293CFG < TerminalSymbolType, NonterminalSymbolType >::CFG ( ext::set < NonterminalSymbolType > nonterminalAlphabet, ext::set < TerminalSymbolType > terminalAlphabet, NonterminalSymbolType initialSymbol ) : core::Components < CFG, ext::set < TerminalSymbolType >, component::Set, TerminalAlphabet, ext::set < NonterminalSymbolType >, component::Set, NonterminalAlphabet, NonterminalSymbolType, component::Value, InitialSymbol > ( std::move ( terminalAlphabet), std::move ( nonterminalAlphabet ), std::move ( initialSymbol ) ) {
294}
295
296template < class TerminalSymbolType, class NonterminalSymbolType >
297CFG < TerminalSymbolType, NonterminalSymbolType >::CFG ( const EpsilonFreeCFG < TerminalSymbolType, NonterminalSymbolType > & other ) : CFG ( other.getNonterminalAlphabet ( ), other.getTerminalAlphabet ( ), other.getInitialSymbol ( ) ) {
298 for ( const std::pair < const NonterminalSymbolType, ext::set < ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > > > & rule : other.getRules ( ) ) {
299 const NonterminalSymbolType & lhs = rule.first;
300
302 addRule ( lhs, rhs );
303 }
304}
305
306template < class TerminalSymbolType, class NonterminalSymbolType >
308 if ( !getNonterminalAlphabet ( ).count ( leftHandSide ) )
309 throw GrammarException ( "Rule must rewrite nonterminal symbol" );
310
311 for ( const ext::variant < TerminalSymbolType, NonterminalSymbolType > & symbol : rightHandSide )
312 if ( !getTerminalAlphabet ( ).count ( symbol ) && !getNonterminalAlphabet ( ).count ( symbol ) )
313 throw GrammarException ( "Symbol \"" + ext::to_string ( symbol ) + "\" is neither terminal nor nonterminal symbol" );
314
315 return rules[std::move ( leftHandSide )].insert ( std::move ( rightHandSide ) ).second;
316}
317
318template < class TerminalSymbolType, class NonterminalSymbolType >
320 if ( !getNonterminalAlphabet ( ).count ( leftHandSide ) )
321 throw GrammarException ( "Rule must rewrite nonterminal symbol" );
322
323 for ( const ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > & rhs : rightHandSide )
325 if ( ! getTerminalAlphabet ( ).count ( symbol ) && ! getNonterminalAlphabet ( ).count ( symbol ) )
326 throw GrammarException ( "Symbol \"" + ext::to_string ( symbol ) + "\" is neither terminal nor nonterminal symbol" );
327
328 rules [ std::move ( leftHandSide ) ].insert ( ext::make_mover ( rightHandSide ).begin ( ), ext::make_mover ( rightHandSide ).end ( ) );
329}
330
331template < class TerminalSymbolType, class NonterminalSymbolType >
333 return rules;
334}
335
336template < class TerminalSymbolType, class NonterminalSymbolType >
338 return std::move ( rules );
339}
340
341template < class TerminalSymbolType, class NonterminalSymbolType >
343 return rules[leftHandSide].erase ( rightHandSide );
344}
345
346} /* namespace grammar */
347
348namespace core {
349
356template < class TerminalSymbolType, class NonterminalSymbolType >
357class SetConstraint< grammar::CFG < TerminalSymbolType, NonterminalSymbolType >, TerminalSymbolType, grammar::TerminalAlphabet > {
358public:
367 static bool used ( const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > & grammar, const TerminalSymbolType & symbol ) {
368 for ( const std::pair < const NonterminalSymbolType, ext::set < ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > > > & rule : grammar.getRules ( ) )
370 if ( std::find ( rhs.begin ( ), rhs.end ( ), symbol ) != rhs.end ( ) )
371 return true;
372
373 return false;
374 }
375
384 static bool available ( const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > &, const TerminalSymbolType & ) {
385 return true;
386 }
387
396 static void valid ( const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > & grammar, const TerminalSymbolType & symbol ) {
397 if ( grammar.template accessComponent < grammar::NonterminalAlphabet > ( ).get ( ).count ( ext::poly_comp ( symbol ) ) )
398 throw grammar::GrammarException ( "Symbol " + ext::to_string ( symbol ) + " cannot be in the terminal alphabet since it is already in the nonterminal alphabet." );
399 }
400};
401
408template < class TerminalSymbolType, class NonterminalSymbolType >
409class SetConstraint< grammar::CFG < TerminalSymbolType, NonterminalSymbolType >, NonterminalSymbolType, grammar::NonterminalAlphabet > {
410public:
419 static bool used ( const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > & grammar, const NonterminalSymbolType & symbol ) {
420 for ( const std::pair < const NonterminalSymbolType, ext::set < ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > > > & rule : grammar.getRules ( ) ) {
421 if ( rule.first == symbol )
422 return true;
423
425 if ( std::find ( rhs.begin ( ), rhs.end ( ), symbol ) != rhs.end ( ) )
426 return true;
427
428 }
429
430 return grammar.template accessComponent < grammar::InitialSymbol > ( ).get ( ) == symbol;
431 }
432
441 static bool available ( const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > &, const NonterminalSymbolType & ) {
442 return true;
443 }
444
453 static void valid ( const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > & grammar, const NonterminalSymbolType & symbol ) {
454 if ( grammar.template accessComponent < grammar::TerminalAlphabet > ( ).get ( ).count ( ext::poly_comp ( symbol ) ) )
455 throw grammar::GrammarException ( "Symbol " + ext::to_string ( symbol ) + " cannot be in the nonterminal alphabet since it is already in the terminal alphabet." );
456 }
457};
458
465template < class TerminalSymbolType, class NonterminalSymbolType >
466class ElementConstraint< grammar::CFG < TerminalSymbolType, NonterminalSymbolType >, NonterminalSymbolType, grammar::InitialSymbol > {
467public:
476 static bool available ( const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > & grammar, const NonterminalSymbolType & symbol ) {
477 return grammar.template accessComponent < grammar::NonterminalAlphabet > ( ).get ( ).count ( symbol );
478 }
479
486 static void valid ( const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > &, const NonterminalSymbolType & ) {
487 }
488};
489
495template < class TerminalSymbolType, class NonterminalSymbolType >
496struct normalize < grammar::CFG < TerminalSymbolType, NonterminalSymbolType > > {
498 ext::set < DefaultSymbolType > nonterminals = alphabet::SymbolNormalize::normalizeAlphabet ( std::move ( value ).getNonterminalAlphabet ( ) );
499 ext::set < DefaultSymbolType > terminals = alphabet::SymbolNormalize::normalizeAlphabet ( std::move ( value ).getTerminalAlphabet ( ) );
500 DefaultSymbolType initialSymbol = alphabet::SymbolNormalize::normalizeSymbol ( std::move ( value ).getInitialSymbol ( ) );
501
502 grammar::CFG < > res ( std::move ( nonterminals ), std::move ( terminals ), std::move ( initialSymbol ) );
503
504 for ( std::pair < NonterminalSymbolType, ext::set < ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > > > && rule : ext::make_mover ( std::move ( value ).getRules ( ) ) ) {
505
508 rhs.insert ( alphabet::SymbolNormalize::normalizeVariantSymbols ( std::move ( target ) ) );
509
510 DefaultSymbolType lhs = alphabet::SymbolNormalize::normalizeSymbol ( std::move ( rule.first ) );
511
512 res.addRules ( std::move ( lhs ), std::move ( rhs ) );
513 }
514
515 return res;
516 }
517};
518
519} /* namespace core */
520
521extern template class grammar::CFG < >;
522
static ext::set< DefaultSymbolType > normalizeAlphabet(ext::set< SymbolType > &&symbols)
Definition: SymbolNormalize.h:50
static ext::vector< ext::variant< DefaultSymbolType, DefaultSymbolType > > normalizeVariantSymbols(ext::vector< ext::variant< FirstSymbolType, SecondSymbolType > > &&symbols)
Definition: SymbolNormalize.h:95
static DefaultSymbolType normalizeSymbol(SymbolType &&symbol)
Definition: SymbolNormalize.h:68
Definition: components.hpp:181
static bool available(const grammar::CFG< TerminalSymbolType, NonterminalSymbolType > &grammar, const NonterminalSymbolType &symbol)
Definition: CFG.h:476
static void valid(const grammar::CFG< TerminalSymbolType, NonterminalSymbolType > &, const NonterminalSymbolType &)
Definition: CFG.h:486
Definition: components.hpp:25
static void valid(const grammar::CFG< TerminalSymbolType, NonterminalSymbolType > &grammar, const TerminalSymbolType &symbol)
Definition: CFG.h:396
static bool available(const grammar::CFG< TerminalSymbolType, NonterminalSymbolType > &, const TerminalSymbolType &)
Definition: CFG.h:384
static bool used(const grammar::CFG< TerminalSymbolType, NonterminalSymbolType > &grammar, const TerminalSymbolType &symbol)
Definition: CFG.h:367
static bool available(const grammar::CFG< TerminalSymbolType, NonterminalSymbolType > &, const NonterminalSymbolType &)
Definition: CFG.h:441
static void valid(const grammar::CFG< TerminalSymbolType, NonterminalSymbolType > &grammar, const NonterminalSymbolType &symbol)
Definition: CFG.h:453
static bool used(const grammar::CFG< TerminalSymbolType, NonterminalSymbolType > &grammar, const NonterminalSymbolType &symbol)
Definition: CFG.h:419
Definition: setComponents.hpp:26
Class extending the map class from the standard library. Original reason is to allow printing of the ...
Definition: map.hpp:48
Definition: ostream.h:14
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
Context free grammar in Chomsky hierarchy or type 2 in Chomsky hierarchy. Generates context free lang...
Definition: CFG.h:67
const NonterminalSymbolType & getInitialSymbol() const &
Definition: CFG.h:148
friend ext::ostream & operator<<(ext::ostream &out, const CFG &instance)
Definition: CFG.h:278
const ext::set< TerminalSymbolType > & getTerminalAlphabet() const &
Definition: CFG.h:215
bool setInitialSymbol(NonterminalSymbolType symbol)
Definition: CFG.h:168
const ext::set< NonterminalSymbolType > & getNonterminalAlphabet() const &
Definition: CFG.h:177
void setNonterminalAlphabet(ext::set< NonterminalSymbolType > symbols)
Definition: CFG.h:206
void setTerminalAlphabet(ext::set< TerminalSymbolType > symbols)
Definition: CFG.h:244
bool addNonterminalSymbol(NonterminalSymbolType symbol)
Definition: CFG.h:197
NonterminalSymbolType && getInitialSymbol() &&
Definition: CFG.h:157
bool operator==(const CFG &other) const
Definition: CFG.h:266
ext::set< TerminalSymbolType > && getTerminalAlphabet() &&
Definition: CFG.h:224
bool removeRule(const NonterminalSymbolType &leftHandSide, const ext::vector< ext::variant< TerminalSymbolType, NonterminalSymbolType > > &rightHandSide)
Definition: CFG.h:342
void addRules(NonterminalSymbolType leftHandSide, ext::set< ext::vector< ext::variant< TerminalSymbolType, NonterminalSymbolType > > > rightHandSide)
Add new rules of a grammar.
Definition: CFG.h:319
auto operator<=>(const CFG &other) const
Definition: CFG.h:255
CFG(NonterminalSymbolType initialSymbol)
Creates a new instance of the grammar with a concrete initial symbol.
Definition: CFG.h:289
const ext::map< NonterminalSymbolType, ext::set< ext::vector< ext::variant< TerminalSymbolType, NonterminalSymbolType > > > > & getRules() const &
Definition: CFG.h:332
ext::set< NonterminalSymbolType > && getNonterminalAlphabet() &&
Definition: CFG.h:186
bool addTerminalSymbol(TerminalSymbolType symbol)
Definition: CFG.h:235
bool addRule(NonterminalSymbolType leftHandSide, ext::vector< ext::variant< TerminalSymbolType, NonterminalSymbolType > > rightHandSide)
Add a new rule of a grammar.
Definition: CFG.h:307
Context free grammar without epsilon rules in Chomsky hierarchy or type 2 in Chomsky hierarchy....
Definition: EpsilonFreeCFG.h:65
Definition: GrammarException.h:15
Definition: Object.h:16
return res
Definition: MinimizeByPartitioning.h:145
Definition: normalize.hpp:10
constexpr tuple< Elements &... > tie(Elements &... args) noexcept
Helper of extended tuple of references construction. The tuple is constructed to reffer to values in ...
Definition: tuple.hpp:218
reference_mover< T > make_mover(T &param)
Move adaptor construction function specialized to lvalue reference parameter.
Definition: iterator.hpp:468
std::string to_string(const T &value)
To string method designated for objects that can be casted to string.
Definition: string.hpp:131
PolyComp< T > poly_comp(const T &inst)
Definition: functional.hpp:60
auto begin(Container &&cont) -> decltype(std::forward(cont).begin())
Definition: iterator.hpp:900
Definition: ToAutomaton.h:24
void end()
Definition: measurements.cpp:19
auto & get(ext::ptr_array< Type, N > &tpl)
Specialisation of get function for pointer arrays.
Definition: ptr_array.hpp:693
static grammar::CFG< > eval(grammar::CFG< TerminalSymbolType, NonterminalSymbolType > &&value)
Definition: CFG.h:497
Definition: normalize.hpp:13