//---------------------------------------------------------------------------
#include "lexan_blif.h"
#include "config.h"
//---------------------------------------------------------------------------
void LexanBlif::init (std::istream& in, const std::string& fi) {
  Lexan::init(in, fi);
  if( keywords.size() == 0 ) kw_init();
}
//---------------------------------------------------------------------------
int LexanBlif::NextToken() {
    int state = 0;
    char c;
    *in_ >> noskipws;
    while(true) {
        *in_ >> c;
        if( c == '\n' ) rowcount_++;
        switch (state) {
        case 0:
            if (!*in_) return LEX_BLIF_NULL;
            if (isspace(c)) break;
            if (c == '#') { state = 1; break; }
            if (c == '.') { state = 2; Lex_AStr = c; break; }
            if (isalpha(c) || isdigit(c) || c == '-' || c=='_' || c=='[' || c==']' ) {
                state = 3;
                Lex_AStr = c;
                break;
            }
            return LEX_BLIF_ERROR;

        case 1:
            if (c == '\n' ) state = 0;
            break;

        case 2:
            if ((isalpha(c) || c == '_') && *in_ ) { Lex_AStr += c; break; }
            if (c != '\n' ) in_->unget();
            for (list<pair<int,std::string> >::iterator i=keywords.begin();i!=keywords.end();i++)
                if (!stricmp (i->second.c_str(),Lex_AStr.c_str())) return i->first;
            return LEX_BLIF_ERROR;

        case 3:
            if(c == '\\' ) { //concatenation of subsequent line to the current line
                //*in_ >> c; //followed by newline
                //*in_ >> c;
                do { *in_ >> c; } while (c != '\n');    // JS skips rubbish & '\r'
                *in_ >> c;
                rowcount_++;                            // JS every line counts
            }
            if( isalpha(c) || isdigit(c) || c=='_' || c=='/' || c=='[' || c==']' ||
            c == '-' || c == '~' || c == '|' || c=='=' || c==' ' || c=='.') {   // JS dots in names are common in BLIF
                Lex_AStr+=c;
                break;
            }
            if(c!='\n') in_->unget();
            return LEX_BLIF_DATA;
        }
    }
}
//---------------------------------------------------------------------------
void LexanBlif::kw_init() {
  symbols.clear();
  symbols.push_back (std::pair<int,std::string>(LEX_BLIF_NULL, "(eof)"));
  symbols.push_back (std::pair<int,std::string>(LEX_BLIF_DATA, "(data)"));

  keywords.clear();
  keywords.push_back (std::pair<int,std::string>(LEX_BLIF_MODEL, ".model"));
  keywords.push_back (std::pair<int,std::string>(LEX_BLIF_INPUTS, ".inputs"));
  keywords.push_back (std::pair<int,std::string>(LEX_BLIF_OUTPUTS, ".outputs"));
  keywords.push_back (std::pair<int,std::string>(LEX_BLIF_CLOCK, ".clock"));
  keywords.push_back (std::pair<int,std::string>(LEX_BLIF_END, ".end"));
  keywords.push_back (std::pair<int,std::string>(LEX_BLIF_NAMES, ".names"));
  keywords.push_back (std::pair<int,std::string>(LEX_BLIF_EXDC, ".exdc"));
  keywords.push_back (std::pair<int,std::string>(LEX_BLIF_LATCH, ".latch"));
  keywords.push_back (std::pair<int,std::string>(LEX_BLIF_GATE, ".gate"));
  keywords.push_back (std::pair<int,std::string>(LEX_BLIF_MLATCH, ".mlatch"));
  keywords.push_back (std::pair<int,std::string>(LEX_BLIF_SUBCKT, ".subckt"));
  keywords.push_back (std::pair<int,std::string>(LEX_BLIF_SEARCH, ".search"));
  keywords.push_back (std::pair<int,std::string>(LEX_BLIF_START_KISS, ".start_kiss"));
  keywords.push_back (std::pair<int,std::string>(LEX_BLIF_END_KISS, ".end_kiss"));
  keywords.push_back (std::pair<int,std::string>(LEX_BLIF_LATCH_ORDER, ".latch_order"));
  keywords.push_back (std::pair<int,std::string>(LEX_BLIF_CODE, ".code"));
  keywords.push_back (std::pair<int,std::string>(LEX_BLIF_CYCLE, ".cycle"));
  keywords.push_back (std::pair<int,std::string>(LEX_BLIF_CLOCK_EVENT, ".clock_event"));
  keywords.push_back (std::pair<int,std::string>(LEX_BLIF_AREA, ".area"));
  keywords.push_back (std::pair<int,std::string>(LEX_BLIF_DELAY, ".delay"));
  keywords.push_back (std::pair<int,std::string>(LEX_BLIF_WIRE_LOAD_SLOPE, ".wire_load_slope"));
  keywords.push_back (std::pair<int,std::string>(LEX_BLIF_WIRE, ".wire"));
  keywords.push_back (std::pair<int,std::string>(LEX_BLIF_INPUT_ARRIVAL, ".input_arrival"));
  keywords.push_back (std::pair<int,std::string>(LEX_BLIF_DEFAULT_INPUT_ARRIVAL, ".default_input_arrival"));
  keywords.push_back (std::pair<int,std::string>(LEX_BLIF_OUTPUT_REQUIRED, ".output_required"));
  keywords.push_back (std::pair<int,std::string>(LEX_BLIF_DEFAULT_OUTPUT_REQUIRED, ".default_output_required"));
  keywords.push_back (std::pair<int,std::string>(LEX_BLIF_INPUT_DRIVE, ".input_drive"));
  keywords.push_back (std::pair<int,std::string>(LEX_BLIF_DEFAULT_INPUT_DRIVE, ".default_input_drive"));
  keywords.push_back (std::pair<int,std::string>(LEX_BLIF_OUTPUT_LOAD, ".output_load"));
  keywords.push_back (std::pair<int,std::string>(LEX_BLIF_DEFAULT_OUTPUT_LOAD, ".default_output_load"));
  keywords.push_back (std::pair<int,std::string>(LEX_BLIF_KISS_INPUT, ".i"));
  keywords.push_back (std::pair<int,std::string>(LEX_BLIF_KISS_OUTPUT, ".o"));
  keywords.push_back (std::pair<int,std::string>(LEX_BLIF_KISS_TERMS, ".p"));
  keywords.push_back (std::pair<int,std::string>(LEX_BLIF_KISS_STATES, ".s"));
  keywords.push_back (std::pair<int,std::string>(LEX_BLIF_KISS_RESET, ".r"));
}
//---------------------------------------------------------------------------
