// Tokenizerr.cc  P. Conrad, CISC220 06J
// A class that tokenizes input



#include <iostream>
using std::istream;
using std::ostream;

#include <string>
using std::string;

#include <cctype> // for isalpha, isdigit

#include "Tokenizer.h"

void Tokenizer_C::tokenize()
{
  char c;

  in.get(c);

  while (!in.eof())
    {
      process(c);
      in.get(c);
    }
  
}

void Tokenizer_C::process(char c)
{

#ifdef DEBUG_CHAR
  std::cerr << "I found character '" << c 
	    << "' at line " << line 
	    << " char " << pos << endl;

#endif

  switch(state)
    {
    case S0_START:
      {
	if (c == ' ' || c == '\n')
	  {
	    state = S0_START;
	  }
	else if (isalpha(c))
	  {
	    token += c;
	    state = S1_VARIABLE;
	  }
	else if (isdigit(c))
	  {
	    token += c;
	    state = S2_INT;
	  }
	else if (c == '+' || c == '=' || c=='*')
	  {
	    token += c;
	    state = S5_OPERATOR;
	  }
	else
	  {
	    out << "Illegal character " 
		<< c << " at ";
	      reportLineAndChar(out);
	    out << endl;
	  }
	break;
      }
    case S1_VARIABLE:
      {
	if (isalpha(c) || isdigit(c) || c=='_')
	  {
	    token += c;
	    state = S1_VARIABLE;
	  }
	else
	  {
	    out << "Found variable " << token << " at ";
	    reportLineAndChar(out);
	    out << endl;

            state = S0_START;
	    token = "";
            process(c);
	    return;
	    
	  }

	break;
      }
    case S2_INT:
      {
	if (isdigit(c))
	  {
	    token += c;
	    state = S2_INT;	   
	  }
	else if (c=='.')
	  {
	    token += c;
	    state = S3;
	  }
	else
	  {
	    out << "Found integer " << token << " at ";
	    reportLineAndChar(out);
	    out << endl;
	    
	    
            state = S0_START;
	    token="";
            process(c);
	    return;
	  }
	break;
      }
    case S3:
      {
	if (isdigit(c) )
	  {
	    token+=c;
	    state=S4_DOUBLE;
	  }
	else
	  {
	    out << "Found illegal character " << c << " at ";
	    reportLineAndChar(out);
	    out << endl;
	  }
	  
	  
	break;
      }
    case S4_DOUBLE:
      {
	if (isdigit(c))
	  {
	    token += c;
	    state = S4_DOUBLE;	   
	  }
	else
	  {
	    out << "Found double " << token << " at ";
	    reportLineAndChar(out);
	    out << endl;
	    
	    
            state = S0_START;
	    token="";
            process(c);
	    return;
	  }

	break;
      }
    case S5_OPERATOR:
      {
	out << "Found operator " << token << " at ";
	reportLineAndChar(out);
	out << endl;
	    
	    
	state = S0_START;
	token="";
	process(c);
	return;
	
	break;
      }
    default:
      {
	std::cerr << "Illegal state " << state << endl;
	exit(1);
      }


    } 
  

  
  if (c=='\n')
    {
      pos = 1;
      line++;
    }
  else
    {
      pos++;
    }

}







void Tokenizer_C::reportLineAndChar(ostream & out)
{
  out << "line: " << line << " char: " << pos;
}
