/*
 * GrammarFromStringLexer.cpp
 *
 *  Created on: Nov 23, 2013
 *      Author: Jan Travnicek
 */

#include "GrammarFromStringLexer.h"

namespace grammar {

GrammarFromStringLexer::Token GrammarFromStringLexer::next(std::istream& input) {
	GrammarFromStringLexer::Token token;
	token.type = TokenType::ERROR;
	token.value = "";
	token.raw = "";
	char character;

L0:
	character = input.get();
	if ( input.eof ( ) || character == EOF ) {
		token.type = TokenType::TEOF;
		return token;
	} else if ( ext::isspace ( character ) ) {
		token.raw += character;
		goto L0;
	} else if(character == '|') {
		token.type = TokenType::SEPARATOR;
		token.value += character;
		token.raw += character;
		return token;
	} else if(character == '{') {
		token.type = TokenType::SET_BEGIN;
		token.value += character;
		token.raw += character;
		return token;
	} else if(character == '}') {
		token.type = TokenType::SET_END;
		token.value += character;
		token.raw += character;
		return token;
	} else if(character == '(') {
		token.type = TokenType::TUPLE_BEGIN;
		token.value += character;
		token.raw += character;
		return token;
	} else if(character == ')') {
		token.type = TokenType::TUPLE_END;
		token.value += character;
		token.raw += character;
		return token;
	} else if(character == ',') {
		token.type = TokenType::COMMA;
		token.value += character;
		token.raw += character;
		return token;
	} else if(character == '-') {
		token.value += character;
		token.raw += character;
		goto L2;
	} else if(character == '#') {
		token.value += character;
		token.raw += character;
		goto L1;
	} else if(input.clear (), input.unget(), input >> ext::string ( "RIGHT_RG" ) ) {
		token.type = TokenType::RIGHT_RG;
		token.value = "RIGHT_RG";
		token.raw += "RIGHT_RG";
		return token;
	} else if(input.clear(), input >> ext::string ( "LEFT_RG" ) ) {
		token.type = TokenType::LEFT_RG;
		token.value = "LEFT_RG";
		token.raw += "LEFT_RG";
		return token;
	} else if(input.clear(), input >> ext::string ( "RIGHT_LG" ) ) {
		token.type = TokenType::RIGHT_LG;
		token.value = "RIGHT_LG";
		token.raw += "RIGHT_LG";
		return token;
	} else if(input.clear(), input >> ext::string ( "LEFT_LG" ) ) {
		token.type = TokenType::LEFT_LG;
		token.value = "LEFT_LG";
		token.raw += "LEFT_LG";
		return token;
	} else if(input.clear(), input >> ext::string ( "LG" ) ) {
		token.type = TokenType::LG;
		token.value = "LG";
		token.raw += "LG";
		return token;
	} else if(input.clear(), input >> ext::string ( "CFG" ) ) {
		token.type = TokenType::CFG;
		token.value = "CFG";
		token.raw += "CFG";
		return token;
	} else if(input.clear(), input >> ext::string ( "EPSILON_FREE_CFG" ) ) {
		token.type = TokenType::EPSILON_FREE_CFG;
		token.value = "EPSILON_FREE_CFG";
		token.raw += "EPSILON_FREE_CFG";
		return token;
	} else if(input.clear(), input >> ext::string ( "GNF" ) ) {
		token.type = TokenType::GNF;
		token.value = "GNF";
		token.raw += "GNF";
		return token;
	} else if(input.clear(), input >> ext::string ( "CNF" ) ) {
		token.type = TokenType::CNF;
		token.value = "CNF";
		token.raw += "CNF";
		return token;
	} else if(input.clear(), input >> ext::string ( "CSG" ) ) {
		token.type = TokenType::CSG;
		token.value = "CSG";
		token.raw += "CSG";
		return token;
	} else if(input.clear(), input >> ext::string ( "NON_CONTRACTING_GRAMMAR" ) ) {
		token.type = TokenType::NON_CONTRACTING_GRAMMAR;
		token.value = "NON_CONTRACTING_GRAMMAR";
		token.raw += "NON_CONTRACTING_GRAMMAR";
		return token;
	} else if(input.clear(), input >> ext::string ( "CONTEXT_PRESERVING_UNRESTRICTED_GRAMMAR" ) ) {
		token.type = TokenType::CONTEXT_PRESERVING_UNRESTRICTED_GRAMMAR;
		token.value = "CONTEXT_PRESERVING_UNRESTRICTED_GRAMMAR";
		token.raw += "CONTEXT_PRESERVING_UNRESTRICTED_GRAMMAR";
		return token;
	} else if(input.clear(), input >> ext::string ( "UNRESTRICTED_GRAMMAR" ) ) {
		token.type = TokenType::UNRESTRICTED_GRAMMAR;
		token.value = "UNRESTRICTED_GRAMMAR";
		token.raw += "UNRESTRICTED_GRAMMAR";
		return token;
	} else {
		putback(input, token);
		token.type = TokenType::ERROR;
		token.raw = "";
		return token;
	}
L1:
	character = input.get();
	if(input.eof()) {
		token.type = TokenType::TEOF;
		return token;
	} else if(character == 'E') {
		token.value += character;
		token.raw += character;
		token.type = TokenType::EPSILON;
		return token;
	} else {
		input.clear ( );
		input.unget ( );
		putback(input, token);
		token.raw = "";
		token.type = TokenType::ERROR;
		return token;
	}
L2:
	character = input.get();
	if(input.eof()) {
		token.type = TokenType::TEOF;
		return token;
	} else if(character == '>') {
		token.value += character;
		token.raw += character;
		token.type = TokenType::MAPS_TO;
		return token;
	} else {
		input.clear ( );
		input.unget ( );
		putback(input, token);
		token.raw = "";
		token.type = TokenType::ERROR;
		return token;
	}
}

} /* namespace grammar */
