/*
 * GrammarIteration.h
 *
 * This file is part of Algorithms library toolkit.
 * Copyright (C) 2017 Jan Travnicek (jan.travnicek@fit.cvut.cz)

 * Algorithms library toolkit is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * Algorithms library toolkit is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with Algorithms library toolkit.  If not, see <http://www.gnu.org/licenses/>.
 *
 *  Created on: 05. 11. 2019
 *	  Author: Tomas Pecka
 */

#ifndef GRAMMAR_ITERATION_H_
#define GRAMMAR_ITERATION_H_

#include <grammar/ContextFree/CFG.h>
#include <common/createUnique.hpp>

#include <label/InitialStateLabel.h>

namespace grammar::transform {

/**
 * Iteration of two grammars.
 * For two regular grammars G1 and G2, we create a regular grammar such that L(G) = L(G1) \cup L(G2).
 * For CFG and CFG/RG we create a context free grammar such that L(G) = L(G1) \cup L(G2).
 * Source:
 */
class GrammarIteration {
public:
	/**
	 * Iterates a grammar.
	 * @tparam TerminalSymbolType Type for terminal symbols.
	 * @tparam NonterminalSymbolType Type for nonterminal symbols.
	 * @param grammar grammar
	 * @return CFG grammar for iteartion of a CFG grammar
	 */
	template < class TerminalSymbolType, class NonterminalSymbolType >
	static grammar::CFG < TerminalSymbolType, NonterminalSymbolType > iteration ( const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > & grammar );
};

template < class TerminalSymbolType, class NonterminalSymbolType >
grammar::CFG < TerminalSymbolType, NonterminalSymbolType > GrammarIteration::iteration ( const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > & grammar ) {
	NonterminalSymbolType S = common::createUnique ( label::InitialStateLabel::instance < NonterminalSymbolType > ( ), grammar.getNonterminalAlphabet ( ) );
	grammar::CFG < TerminalSymbolType, NonterminalSymbolType > res = grammar;

	res.addNonterminalSymbol ( S );
	res.setInitialSymbol ( S );
	res.addRule ( S, { } );
	res.addRule ( S, { grammar.getInitialSymbol ( ), S } );

	return res;
}

} /* namespace grammar::transform */

#endif /* GRAMMAR_ITERATION_H_ */
