#ifdef __BCPLUSPLUS__
#pragma hdrstop
#endif

#include <stdexcept>
#include <ctype.h>
#include <math.h>
#include <iostream>	//debug
#include "../../config.h"
#include "vhdl_bison_parser.hpp"


using namespace std;

//---------------------------------------------------------------------------
void LexanVhdl::init(istream & istr, const string& fn) {
   Lexan::init (istr, fn);
   if (keywords.size() == 0)  kw_init();
   rowcount_=1;
}
//---------------------------------------------------------------------------
int charval( char c ){
	if( isdigit(c) ) return c-'0';
	if( c == 'A'|| c == 'a'  ) return 10;
	if( c == 'B'|| c == 'b'  ) return 11;
	if( c == 'C'|| c == 'c'  ) return 12;
	if( c == 'D'|| c == 'd'  ) return 13;
	if( c == 'E'|| c == 'e'  ) return 14;
	if( c == 'F'|| c == 'f'  ) return 15;
	return 255;
}
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
yytokentype LexanVhdl::NextToken(YYSTYPE * yylval, yy::location* yyloc) {

	int state = 0;
	int base = 10;
	int exp = 0,expsign = 1;
	double dmspos = 0.1;
	char c;
    (*in_)>>noskipws;
	yyloc->step();
    while(true) {
	(*in_)>>c;
	yyloc->columns();
	if(c=='\n') {  rowcount_++; yyloc->lines();   }
	switch(state) {
	    // ------------------ symbol start -------------------------
	    case 0:
		if (!(*in_)) { cerr << endl; return LEX_V_EOF; }
		if ( (isspace(c)) ) { yyloc->step(); break; }
		//cout << "Calling step "<<endl;
		//yyloc->step();
		if( c ==  '\'' ) { 
			(*in_)>>c;
			char tmpchar = c;
			Lex_AStr = c;
			(*in_)>>c;
			if( c == '\'' ) {
				yylval->chval = tmpchar;
				return LEX_V_LITCHAR;
			}
			in_->putback(tmpchar);
			in_->putback( c );
			return LEX_V_SQUOT;
			
		}
		if ( c == '-' ) { 
			(*in_)>>c;
			if ( c == '-' ) { state = 1; break; }
			if(!isspace(c)) in_->unget(); 
			return LEX_V_MINUS; 
		}
		switch( c ){
			case '+': return LEX_V_PLUS;
			case '&': return LEX_V_AMPER;
			case '(': return LEX_V_LPAR;
			case ')': return LEX_V_RPAR;
			case '[': return LEX_V_SLPAR;
			case ']': return LEX_V_SRPAR;
			case '.': return LEX_V_DOT;
			case ',': return LEX_V_COMMA;
			case '|': return LEX_V_VLINE;
			case '#': return LEX_V_CROSS;
			case ';': return LEX_V_SEMICOL;
			case '/': 
				(*in_)>>c;
				if( c == '=' ) return LEX_V_NEQ;
				if(!isspace(c)) in_->unget();
				return LEX_V_SLASH;;
			case ':':
				(*in_)>>c;
				if( c == '=' ) return LEX_V_ASSIGN;
				if(!isspace(c))in_->unget();
				return LEX_V_DDOT;
			case '*':
				(*in_)>>c;
				if( c == '*' ) return LEX_V_POWER;
				else { in_->unget(); return LEX_V_ASTER; }
			case '<':
				(*in_)>>c;
				if( c == '=' ) return LEX_V_LOEQ;
				if( c == '>' ) return LEX_V_RHOMB;
				else { in_->unget(); return LEX_V_LESS; }
			case '>':
				(*in_)>>c;
				if( c == '=' ) return LEX_V_GOREQ;
				else { if(!isspace(c)) in_->unget(); return LEX_V_GRT; }
			case '=': 
				(*in_)>>c;
				if( c == '>' ) return LEX_V_ASR;
				if(!isspace(c))in_->unget();
				return LEX_V_EQUAL;
		}
		Lex_AStr = "";
		Lex_AInt = 0;
		Lex_AReal= 0;
		

		if( c == '\"' ) { state = 3;  break; }

		if( c == 'B' || c == 'O' || c == 'X' ||
			c == 'b' || c == 'o' || c == 'x') {
			if( c == 'B' || c == 'b' ) base = 2; 
			if( c == 'O' || c == 'o' ) base = 8;
			if( c == 'X' || c == 'x' ) base = 16;
			dmspos = 1/base;
			state = 2;
			Lex_AStr = c;
			break;
		}

		if (isalpha (c)) {
		    state = 4;
		    Lex_AStr = c;
		    break;
		}

		if ( isdigit (c)) {
			base = 10;
		    state= 5 ;
		    Lex_AInt = c-'0';
		    Lex_AReal = c-'0';
		    break;
		}
		return LEX_V_ERROR;

	//-------------------- comment --------------------------
		case 1:
			if(c=='\n') state=0;
            break;
	//----------- ident or keyword or bit string literal ---------
		case 2:
			if( c == '"' ) { state = 10; break; }
			if (isalpha(c) || isdigit(c) || c == '_' ){ Lex_AStr += c; state = 4 ; break; } // ident
			if(!isspace(c)) in_->unget();
			yylval->sval = new string( Lex_AStr );
			return LEX_V_IDENT;
	//----------- STRING LITERAL ----------------------------------------
		case 3:
			if( c != '\"' && c !='\n' ) { 
				//cout << "STRING_LIT "<< c << endl;
				Lex_AStr += c;
				break;
			}
			if( c == '\"' ) return LEX_V_LITSTRING;
			return LEX_V_ERROR;
	//------------- IDENT OR KEYWORD ------------------------------------
		case 4:
            if (isalpha(c) || isdigit(c) || c == '_' ) {
                Lex_AStr+=c;
                break;
			}
			if(!isspace(c)) in_->unget();
			// -------------- KEYWORD DECODE ----------------------------------- 
			 for(list<pair<int,std::string> >::iterator 
			i=keywords.begin();
			i!=keywords.end();
			i++) {
				std::string s1 =i->second;
				std::string s2 =Lex_AStr;
				if(!CompareText(i->second,Lex_AStr)) return (yytokentype) i->first;
				}
			yylval->sval = new string( Lex_AStr );
            return LEX_V_IDENT;
      
	//--------------- NUMBER OR BASE LITERAL --------------------------------------
	  case 5:
		 if ( c == '_' ) break;
		 if (isdigit(c)) {
			Lex_AInt*= base;
			Lex_AReal*= base;
			Lex_AInt+= c-'0';
			Lex_AReal+= c-'0';
			break;
            }
		 if ( c == '#' && Lex_AInt <= 16 ){ 
			 if( Lex_AInt == 2 ) base = 2;
			 else if( Lex_AInt == 8 ) base = 8;
			 else if( Lex_AInt == 16) base = 16;
			 else return LEX_V_ERROR;
			 Lex_AInt = 0;
			 Lex_AReal = 0;
			 state = 12; break; 
		 }
		 if ( c == 'E' ) {
			 state = 6;
			 break;
		 }
		 if ( c == '.' ) {
			 state = 9; 
			 break;
		 }
		 if(!isspace(c))in_->unget();
		 yylval->ival = Lex_AInt;
		 return LEX_V_LITABSTR;

	//---------------- EXPONENT SIGN -------------------------------------------------
	  case 6:
		  state = 7;
		  if (c=='+' || c=='-') { expsign = (c=='-')?-1:1; break; }
	// ------------------ exponent first number -------------------------
      case 7:
	     if (isdigit (c)) {
 		 state = 8;
 		 exp*= base;
		 exp+= c-'0';
		 break;
	     }
	     return LEX_V_ERROR;
	 // ------------------ exponent ------------------------------    
        case 8:
            if (isdigit(c)) {
                exp*= base;
                exp+=c-'0';
                break;
	    }
        if(!isspace(c)) in_->unget();
        Lex_AReal *= pow(10.0,exp*expsign);
		yylval->ival = Lex_AInt;
        return LEX_V_LITABSTR;
	// ------------------ float dec part start -------------------------
		case 9:
            if (isdigit (c)) {
               Lex_AReal += dmspos*(c-'0');
               dmspos *= 0.1;
               break;
            }
            if (c=='e' || c=='E') {
                state=6;
                break;
            }
            if (!isspace(c)) in_->unget();
			yylval->ival = Lex_AInt;
            return LEX_V_LITABSTR;

	//----------- BIT STRING LITERAL START -------------------------------------
		case 10:
			if (isdigit(c) || ( c >='A' && c <='F' ) || ( c >='a' && c <='f' ) ) {
				if( charval(c) > (base-1) ) return LEX_V_ERROR;
				Lex_AInt  *= base;
				Lex_AInt  += charval(c);
				state = 11;
				break;
            }
			return LEX_V_ERROR;
	//----------- BIT STRING LITERAL  -------------------------------------
		case 11:
			if ( c == '_' ) break;
			if (isdigit(c) || ( c >='A' && c <='F' ) || ( c >='a' && c <='f' ) ) {
				if( charval(c) > (base-1) ) return LEX_V_ERROR;
				Lex_AInt  *= base;
				Lex_AInt  += charval(c);
			break;
            }
			if( c == '\"' ) return LEX_V_LITBITSTR;
			return LEX_V_ERROR;
	//------------ BASED LITERAL START ------------------------------------
		case 12:
			if (isdigit(c)|| ( c >='A' && c <='F' )) {
				if( charval(c) > (base-1) ) return LEX_V_ERROR;
					Lex_AInt  *= base;
					Lex_AReal *= base;
					Lex_AInt  += charval(c);
					Lex_AReal += charval(c);
					state = 13;
				break;
            }
			return LEX_V_ERROR;
	//------------ BASED LITERAL -------------------------------------------
		case 13:
			if ( c == '_' ) break;
			if (isdigit(c) || ( c >='A' && c <='F' ) || ( c >='a' && c <='f' ) ) {
				if( charval(c) > (base-1) ) return LEX_V_ERROR;
					Lex_AInt  *= base;
					Lex_AReal *= base;
					Lex_AInt  += charval(c);
					Lex_AReal += charval(c);
				break;
            }
			if ( c == '#' ) { state = 14;  break; }
			if ( c == '.' ) { state = 18;  break; }
			return LEX_V_ERROR;
	//------------ BASED LIT END --------------------------------------------
		case 14:
			if ( c == 'E' ) { state = 15; break; }
			if(!isspace(c))in_->unget();
			yylval->ival = Lex_AInt;
			return LEX_V_LITABSTR;
	//------------------- BASED LIT EXP SIGN ---------------------------------
		case 15:
		  state = 16;
		  if (c=='+' || c=='-') { expsign = (c=='-')?-1:1; break; }
	// ------------------ BASED LIT EXP first number -------------------------
		case 16:

			 if (isdigit(c)) {
 				state = 17;
 				exp *= 10;
				exp += c-'0';
				break;
			}
	     return LEX_V_ERROR;
	 // ------------------ BASED LIT EXP  -----------------------------------    
        case 17:
            if (isdigit(c)) {
                exp *= 10;
                exp += c-'0';
                break;
	    }
        if(!isspace(c))in_->unget();
        Lex_AReal *= pow(10.0,exp*expsign);
		yylval->ival = Lex_AInt;
        return LEX_V_LITABSTR;
	// ------------------ BASED LIT float dec part  -------------------------
		case 18:
			if ( c == '_' ) break;
            if (isdigit (c) || ( c >='A' && c <='F' ) || ( c >='a' && c <='f' ) ) {
			   if( charval(c) > (base-1) ) return LEX_V_ERROR;
               Lex_AReal += dmspos*(c-'0');
               dmspos *= 1/base;
               break;
            }
			if ( c == '#' ) { state = 14;  break; }
            return LEX_V_ERROR;




	}
}
}


//---------------------------------------------------------------------------
void LexanVhdl::kw_init()
{
keywords.clear();
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_ABS,"abs"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_ACCESS,"access"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_AFTER,"after"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_ALIAS,"alias"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_ALL,"all"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_AND,"and"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_ARCHITECTURE,"architecture"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_ARRAY,"array"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_ASSERT,"assert"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_ATTRIBUTE,"attribute"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_BEGIN,"begin"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_BLOCK,"block"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_BODY,"body"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_BUFFER,"buffer"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_BUS,"bus"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_CASE,"case"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_COMPONENT,"component"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_CONFIGURATION,"configuration"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_CONSTANT,"constant"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_DISCONNECT,"disconnect"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_DOWNTO,"downto"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_ELSE,"else"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_ELSIF,"elsif"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_END,"end"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_ENTITY,"entity"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_EXIT,"exit"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_FILE,"file"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_FOR,"for"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_FUNCTION,"function"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_GENERATE,"generate"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_GENERIC,"generic"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_GROUP,"group"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_GUARDED,"guarded"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_IF,"if"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_IMPURE,"impure"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_IN,"in"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_INERTIAL,"inerial"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_INOUT,"inout"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_IS,"is"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_LABEL,"label"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_LIBRARY,"library"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_LINKAGE,"linkage"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_LITERAL,"literal"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_LOOP,"loop"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_MAP,"map"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_MOD,"mod"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_NAND,"nand"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_NEW,"new"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_NEXT,"next"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_NOR,"nor"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_NOT,"not"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_NULL,"null"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_OF,"of"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_ON,"on"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_OPEN,"open"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_OR,"or"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_OTHERS,"others"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_OUT,"out"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_PACKAGE,"package"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_PORT,"port"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_POSTOPENED,"postopened"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_PROCEDURE,"procedure"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_PROCESS,"process"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_PROTECTED,"protected"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_PURE,"pure"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_RANGE,"range"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_RECORD,"record"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_REGISTER,"register"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_REJECT,"reject"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_REM,"rem"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_REPORT,"report"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_RETURN,"return"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_ROL,"rol"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_ROR ,"ror"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_SELECT,"select"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_SEVERENITY,"severenity"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_SHARED,"shared"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_SIGNAL,"signal"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_SLA,"sla"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_SLL,"sll"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_SRA,"sra"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_SRL,"srl"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_SUBTYPE,"subtype"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_THEN,"then"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_TO,"to"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_TRANSPORT,"transport"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_TYPE,"type"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_UNAFFECTED,"unaffected"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_UNITS,"units"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_UNTIL,"until"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_USE,"use"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_VARIABLE,"variable"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_WAIT,"wait"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_WHEN,"when"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_WHILE,"while"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_WITH,"with"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_XNOR,"xnor"));
keywords.push_back(pair<yytokentype ,std::string>(LEX_V_XOR,"xor"));

symbols.clear();
symbols.push_back(pair<yytokentype ,std::string>(LEX_V_EOF,"(eof)"));
symbols.push_back(pair<yytokentype ,std::string>(LEX_V_ERROR,"(unknown)"));
symbols.push_back(pair<yytokentype ,std::string>(LEX_V_IDENT,"(ident)"));
symbols.push_back(pair<yytokentype ,std::string>(LEX_V_LITCHAR,"(litchar)"));
symbols.push_back(pair<yytokentype ,std::string>(LEX_V_LITSTRING,"(litstring)"));
symbols.push_back(pair<yytokentype ,std::string>(LEX_V_LITBITSTR,"(litbitstring)"));
symbols.push_back(pair<yytokentype ,std::string>(LEX_V_LITABSTR,"(litabstract)"));
symbols.push_back(pair<yytokentype ,std::string>(LEX_V_PLUS,"+"));
symbols.push_back(pair<yytokentype ,std::string>(LEX_V_MINUS,"-"));
symbols.push_back(pair<yytokentype ,std::string>(LEX_V_ASTER,"*"));
symbols.push_back(pair<yytokentype ,std::string>(LEX_V_SLASH,"/"));
symbols.push_back(pair<yytokentype ,std::string>(LEX_V_EQUAL,"="));
symbols.push_back(pair<yytokentype ,std::string>(LEX_V_GRT,">"));
symbols.push_back(pair<yytokentype ,std::string>(LEX_V_LESS,"<"));
symbols.push_back(pair<yytokentype ,std::string>(LEX_V_AMPER,"&"));
symbols.push_back(pair<yytokentype ,std::string>(LEX_V_QUOT,"\""));
symbols.push_back(pair<yytokentype ,std::string>(LEX_V_SQUOT,"'"));
symbols.push_back(pair<yytokentype ,std::string>(LEX_V_LPAR,"("));
symbols.push_back(pair<yytokentype ,std::string>(LEX_V_RPAR,")"));
symbols.push_back(pair<yytokentype ,std::string>(LEX_V_SLPAR,"["));
symbols.push_back(pair<yytokentype ,std::string>(LEX_V_SRPAR,"]"));
symbols.push_back(pair<yytokentype ,std::string>(LEX_V_DOT,"."));
symbols.push_back(pair<yytokentype ,std::string>(LEX_V_COMMA,","));
symbols.push_back(pair<yytokentype ,std::string>(LEX_V_CROSS,"#"));
symbols.push_back(pair<yytokentype ,std::string>(LEX_V_VLINE,"|"));
symbols.push_back(pair<yytokentype ,std::string>(LEX_V_LOEQ,"<="));
symbols.push_back(pair<yytokentype ,std::string>(LEX_V_GOREQ,">="));
symbols.push_back(pair<yytokentype ,std::string>(LEX_V_NEQ,"/="));
symbols.push_back(pair<yytokentype ,std::string>(LEX_V_RHOMB,"<>"));
symbols.push_back(pair<yytokentype ,std::string>(LEX_V_ASSIGN,":="));
symbols.push_back(pair<yytokentype ,std::string>(LEX_V_POWER,"**"));
symbols.push_back(pair<yytokentype ,std::string>(LEX_V_DDOT,":"));
symbols.push_back(pair<yytokentype ,std::string>(LEX_V_ASR,"=>"));
symbols.push_back(pair<yytokentype ,std::string>(LEX_V_SEMICOL,";"));

}
