#include "lexan.h"
#include <math.h>

void Lexan::init(const char *n)
{
   if(F.is_open()) F.close();
   else kw_init();
   F.open(n);
   if(!F.is_open()) throw std::runtime_error("nelze otevrit vstupni soubor");
   rowcount=0;
}

int Lexan::NextToken()
{

   int Exp=0,ExpSign=1;
   double DmsPos=0.1;
   int state=0;
   char c;
   F>>noskipws;
   while(true)
   {
      F>>c;
      if(c=='\n') rowcount++;

      switch(state)
      {
       case 0:
         if(!F)
         {
            return LEX_NULL;
         }
         if(c==' ' || c=='\n' || c=='\t' || c=='\r') break;
         if(c=='=') return LEX_ASSIGN;
//         if(Char=='<') return LEX_LESS;
//         if(Char=='>') return LEX_GREATER;
//         if(Char=='+') return LEX_PLUS;
//         if(Char=='*') return LEX_MULT;
         if(c=='(') return LEX_LPA;
         if(c==')') return LEX_RPA;
//         if(Char==';') return LEX_SEMICOLON;
         if(c==',') return LEX_COMMA;
//         if(Char=='.') return LEX_DOT; */
         if(isdigit(c))
         {
            state=5;
            Lex_AInt=c-'0';
            Lex_AReal=c-'0';
            break;
         }
//         if(Char==':')
//         {
//            State=10;
//            break;
//         }
            if(c=='#')
            {
               state=1;
               break;
            }
            if(isalpha(c) || c=='_')
            {
               state=14;
               Lex_AStr=MStr(c);
               break;
            }
            return LEX_ERROR;

         case 1:
//            if(!F) return LEX_ERROR;
            if(c=='\n') state=0;
            break;
         case 5:
            if(isdigit(c))
            {
               Lex_AInt*=10;
               Lex_AReal*=10;
               Lex_AInt+=c-'0';
               Lex_AReal+=c-'0';
               break;
            }
            if(c=='.')
            {
               state=6;
               break;
            }
            if(c=='e' || c=='E')
            {
               state=7;
               break;
            }
            if(c!='\n') F.unget();
            return LEX_INTEGER;
         case 6:
            if(isdigit(c))
            {
               Lex_AReal+=DmsPos*(c-'0');
               DmsPos*=.1;
               break;
            }
            if(c=='e' || c=='E')
            {
               state=7;
               break;
            }
            if(c!='\n') F.unget();
            return LEX_REAL;
         case 7:
            state=8;
            if(c=='+' || c=='-')
            {
               ExpSign=(c=='-')?-1:1;
               break;
            }
         case 8:
            if(isdigit(c))
            {
               state=9;
               Exp*=10;
               Exp+=c-'0';
               break;
            }
            return LEX_ERROR;
         case 9:
            if(isdigit(c))
            {
               Exp*=10;
               Exp+=c-'0';
               break;
            }
            if(c!='\n') F.unget();
            Lex_AReal*=pow(10.0,Exp*ExpSign);
            return LEX_REAL;
//         case 10:
//            if(c=='=') return LEX_ASSIGN;
//            if(c!='\n') F.unget();
//            return LEX_COLON;
         case 14:
            if(isalpha(c) || isdigit(c) || c=='_' || c=='.')
            {
               Lex_AStr+=MStr(c);
               break;
            }
            if(c!='\n') F.unget();
            for(list<pair<int,MStr> >::iterator i=keywords.begin();i!=keywords.end();i++)
#ifdef nonansi
               if(!stricmp(i->second.c_str(),Lex_AStr.c_str())) return i->first;
#else
               if(!strcasecmp(i->second.c_str(),Lex_AStr.c_str())) return i->first;
#endif
            return LEX_IDENT;
      }
   }  //end while
}

void Lexan::kw_init()
{
   keywords.clear();
   keywords.push_back(pair<int,MStr>(LEX_INPUT,"input"));
   keywords.push_back(pair<int,MStr>(LEX_OUTPUT,"output"));
//    keywords.push_back(pair<int,MStr>(LEX_DFF,"dff"));
   keywords.push_back(pair<int,MStr>(LEX_NOT,"not"));
   keywords.push_back(pair<int,MStr>(LEX_AND,"and"));
   keywords.push_back(pair<int,MStr>(LEX_OR,"or"));
   keywords.push_back(pair<int,MStr>(LEX_NAND,"nand"));
   keywords.push_back(pair<int,MStr>(LEX_NOR,"nor"));
   keywords.push_back(pair<int,MStr>(LEX_XOR,"xor"));
   keywords.push_back(pair<int,MStr>(LEX_XNOR,"xnor"));
   keywords.push_back(pair<int,MStr>(LEX_BUFF,"buf"));
   keywords.push_back(pair<int,MStr>(LEX_BUFF,"buff"));
}
