// file: $isip/class/asr/JSGFParser/jp_05.cc
// version: $Id: jp_05.cc 10499 2006-03-15 21:43:17Z may $
//

// isip include files
//
#include "JSGFParser.h"

// method: getToken
//
// arguments: none
//
// return: a boolean value indicating status
//
// This method checks through the class-protected source grammar string
// while spliting the string into a cluster of JSGF tokens and store them
// into the class-protected token vector
//
boolean JSGFParser::getToken() {

  // Step 1:
  // declare and initialize method scope variables
  //
  long i = 0;
  Char ch(expression_d(i));
  long max_len = expression_d.length();

  // loop through all characters until reaching to the end of the grammar
  // get each token and insert it to the class-protected token vector
  //
  while (i < max_len - 1 ) {

    // skip whitespace (space, tab and new-line character)
    //
    while (i < max_len - 1) {
      if (!ch.isPrint() || ch.isSpace() ){
	i++;
	ch.assign(expression_d(i));
      }
      else
	break;
    }

    // deal with empty things at the end
    //
    if ( i >= max_len - 1 ){
      break;
    }
    
    // ignore comments and get weight as token
    //
    if ((ch == '/') && (i < max_len - 1)) {
      
      // get the first two characters
      //
      String sub;
      expression_d.substr(sub, i, 2);
      
      // Case 1: comment starting with "//"
      //
      if (sub.eq(L"//")) {
	
	// skip characters until the new-line chacracter is reached
	//
	while ((ch != '\n') && (i < max_len - 1)) {
	  i++;
	  ch.assign(expression_d(i));
	} 
      }
      // Case 2: comment starting with "/*"
      //
      else if (sub.eq(L"/*")) {
	
	// skip characters util "*/" is reached
	//
	while (!sub.eq(L"*/") && (i < max_len - 1)) {
	  i++;
	  ch.assign(expression_d(i));
	  expression_d.substr(sub, i-1, 2);
	}
	// error if no */ symbol is found
	//
	if (!sub.eq(L"*/")) {
	  return Error::handle(L"JSGF grammar", L"bad comment", Error::TEST,
			       __FILE__, __LINE__);
	}
	// move to the next character
	//
	i++;
	ch.assign(expression_d(i));
      }     
      // Case 3: weight surrounded by slashes
      //
      else {
	// useful variables
	//
	JSGFToken t;
	String token_str;
	token_str.concat(ch);
	
	// add chacracters util the closing slash is reached
	//
	do { 	
	  i++;
	  ch.assign(expression_d(i));
	  token_str.concat(ch);
	} while ((ch != '/' ) && (i < max_len - 1));

	i++;
	ch.assign(expression_d(i));
	  
	// set a weight token
	//      
	if (t.setToken(token_str)) {	
	  token_vect_d.concat(t);
	}
	else {
	  String err_msg(L"***Bad Token: ");
	  err_msg.concat(token_str);
	  Console::put(err_msg);
	  return Error::handle(name(), L"JSGF grammar parsing error",
			       Error::TEST, __FILE__, __LINE__);
	}
      }
    } // end: if ((ch == '/') && (i < max_len - 1))
    
    // check if a header token is reached
    //
    else if ((ch == '#') && (i < max_len - 1)) {
      
      String header, tail;
      JSGFToken t;
      
      // header is terminated by a semi-colon and a newline character
      //
      while ((!tail.eq(L";\n")) && (i < max_len - 1)) {
	header.concat(ch);
	i++;
	ch.assign(expression_d(i));
	expression_d.substr(tail, i - 1, 2);
      }
      ch.assign(expression_d(i));
      
      // set a header token
      //
      if (t.setToken(header)) {
	token_vect_d.concat(t);
      }
      else {
	String err_msg(L"***Bad Token: ");
	err_msg.concat(header);
	Console::put(err_msg);
	return Error::handle(name(), L"JSGF grammar parsing error",
			     Error::TEST, __FILE__, __LINE__);
      }
    }

    // check if a JSGF rulename token is reached
    //
    else if ((ch == '<') && (i < max_len - 1)) {
      
      String rulename;
      JSGFToken t;
      
      // rulename is terminated by > sign
      //
      while ((ch != '>') && (i < max_len - 1)) {
	rulename.concat(ch);
	i++;
	ch.assign(expression_d(i));
      }
      rulename.concat(ch);
      i++;
      ch.assign(expression_d(i));

      // if rulename is the ISIP reserved graph starting symbols
      //
      if(rulename.eq(L"<ISIP_JSGF_1_0_START>", true)) {
	JSGFToken t;
	t.setToken(graph_start_d);
	token_vect_d.concat(t);
      }

      // if the sub-string is the ISIP reserved graph starting symbols
      //
      else if(rulename.eq(L"<ISIP_JSGF_1_0_TERM>", true)) {
	JSGFToken t;
	t.setToken(graph_term_d);
	token_vect_d.concat(t);
	}
      
      // set a rulename token
      //
      else {
	if (t.setToken(rulename)) {
	  token_vect_d.concat(t);
	}
	else {
	  String err_msg(L"***Bad Token: ");
	  err_msg.concat(rulename);
	  Console::put(err_msg);
	  return Error::handle(name(), L"JSGF grammar parsing error",
			       Error::TEST, __FILE__, __LINE__);
	}
      }
    }
    
    // check if a quoted token is reached
    //
    else if ((ch == '"') && (i < max_len - 1)) {
      
      String quoted_tok;
      JSGFToken t;
      
      quoted_tok.concat(ch);
      i++;
      ch.assign(expression_d(i));
      
      // quoted token is terminated by " sign
      //
      while ((ch != '"') && (i < max_len - 1)) {
	
	// check the preceded backslash required for including
	// a backslash or a quote symbol in quoted token
	//
	if (ch == '\\') {
	  ch.assign(expression_d(i + 1));
	  quoted_tok.concat(ch);
	  i += 2;
	  ch.assign(expression_d(i));
	}
	else {	
	  quoted_tok.concat(ch);
	  i++;
	  ch.assign(expression_d(i));
	}
      }
      quoted_tok.concat(ch);
      i++;
      ch.assign(expression_d(i));
      
      // set a quoted token
      //
      if (t.setToken(quoted_tok)) {
	token_vect_d.concat(t);
      }
      else {
	String err_msg(L"***Bad Token: ");
	err_msg.concat(quoted_tok);
	Console::put(err_msg);
	return Error::handle(name(), L"JSGF grammar parsing error",
			     Error::TEST, __FILE__, __LINE__);
      }
    }
    
    // check if a tag token is reached
    //
    else if ((ch == '{') && (i < max_len - 1)) {
      
      String tag;
      JSGFToken t;
      
      // tag is terminated by closing brace
      //
      while ((ch != '}') && (i < max_len - 1)) {
	
	// check the preceded backslash required for including
	// a backslash or a quote symbol in quoted token
	//
	if (ch == '\\') {
	  ch.assign(expression_d(i + 1));
	  tag.concat(ch);
	  i += 2;
	  ch.assign(expression_d(i));
	}
	else {	
	  tag.concat(ch);
	  i++;
	  ch.assign(expression_d(i));
	}
      }
      tag.concat(ch);
      i++;
      ch.assign(expression_d(i));
      
      // set a tag token
      //
      if (t.setToken(tag)) {
	token_vect_d.concat(t);
      }
      else {
	String err_msg(L"***Bad Token: ");
	err_msg.concat(tag);
	Console::put(err_msg);
	return Error::handle(name(), L"JSGF grammar parsing error",
			     Error::TEST, __FILE__, __LINE__);
      }
    }

    // check if an operator token is reached
    //
    else if (((ch == '=') || (ch == ';') || (ch == '|') ||
	      (ch == '*') || (ch == '+') ||
	      (ch == '(') || (ch == ')') ||
	      (ch == '[') || (ch == ']')) && (i < max_len - 1)) {

      JSGFToken t;
      String op;
      op.assign(ch);

      i++;
      ch.assign(expression_d(i));
      
      // set an operator token
      //
      if (t.setToken(op)) {
	token_vect_d.concat(t);
      }
      else {
	String err_msg(L"***Bad Token: ");
	err_msg.concat(op);
	Console::put(err_msg);
	return Error::handle(name(), L"JSGF grammar parsing error",
			     Error::TEST,  __FILE__, __LINE__);
      }
    }
    
    // check if a JSGF keyword token or a terminal symbol token is reached
    //
    else {
      
      JSGFToken t;
      String sub;
      
      // a terminal symbol is terminated by any of the following symbols
      // keyword is terminated by whitespace
      //
      while ((ch.isPrint()) && (!ch.isSpace()) && (ch != '"') && (ch != ';')
	     && (ch != '=') && (ch != '|') && (ch != '*')
	     && (ch != '+') && (ch != '<') && (ch != '>')
	     && (ch != '(') && (ch != ')') && (ch != '[')
	     && (ch != ']') && (ch != '{') && (ch != '}')
	     && (ch != '/') && (i < max_len - 1)) {
	
	sub.concat(ch);
	i++;
	ch.assign(expression_d(i));
      }

      // Case 1: a grammar declaration is reached
      //
      if (sub.eq(L"grammar")) {

	// get grammar name which is terminated by semi-colon
	//      
	while ((ch != ';') && (i < max_len - 1)) {
	  sub.concat(ch);
	  i++;
	  ch.assign(expression_d(i));
	}
	sub.concat(ch);

	// set a grammar name token
	//
	if (t.setToken(sub)) {
	  token_vect_d.concat(t);
	}
	else {
	  String err_msg(L"***Bad Token: ");
	  err_msg.concat(sub);
	  Console::put(err_msg);
	  return Error::handle(name(), L"JSGF grammar parsing error",
			       Error::TEST, __FILE__, __LINE__);
	}
      }
      
      // Case 2: an import grammar statement is reached
      //
      else if (sub.eq(L"import")) {

	// get import grammar name which is terminated by semi-colon
	//      
	while ((ch != ';') && (i < max_len - 1)) {
	  sub.concat(ch);
	  i++;
	  ch.assign(expression_d(i));
	}
	sub.concat(ch);

	// set a import grammar token
	//
	if (t.setToken(sub)) {
	  token_vect_d.concat(t);
	}
	else {
	  String err_msg(L"***Bad Token: ");
	  err_msg.concat(sub);
	  Console::put(err_msg);
	  return Error::handle(name(), L"JSGF grammar parsing error",
			       Error::TEST, __FILE__, __LINE__);
	}
      }
      
      // Case 3: a public keyword is reached
      //
      else if (sub.eq(L"public")) {

	// set a keyword token
	//
	if (t.setToken(sub)) {
	  token_vect_d.concat(t);
	}
	else {
	  String err_msg(L"***Bad Token: ");
	  err_msg.concat(sub);
	  Console::put(err_msg);
	  return Error::handle(name(),L"JSGF grammar parsing error",
			       Error::TEST, __FILE__, __LINE__);
	}
      }

      // Case 4: a terminal symbol is reached
      //
      else {
	// error if an odd number of following symbol is met
	//
	if (((ch == '>') || (ch == '}')) && (i < max_len - 1)) {

	  String err_msg(L"invalid use of the symbol '");
	  err_msg.concat(ch);
	  err_msg.concat(L"'");
	  return Error::handle(name(), err_msg, Error::TEST,
			       __FILE__, __LINE__); 
	}
	
	// set a terminal symbol token
	//
	if (t.setToken(sub)) {
	  token_vect_d.concat(t);
	}
	else {
	  String err_msg(L"***Bad Token: ");
	  err_msg.concat(sub);
	  Console::put(err_msg);
	  return Error::handle(name(), L"JSGF grammar parsing error",
			       Error::TEST, __FILE__, __LINE__);
	}
      }
    }
  } // end: while (true)
  
  // exit gracefully
  //
  return true;
}
