import java.lang.*;
import java.awt.*;




/*
 *	Purpose: A container of return value (due to the problem that JAVA
 *               don't has pass by reference in primitive data type like
 *               int, Sring... and don't has pass by pointer also )
 */
class container {
    ControlObj ReturnObj;
    String content;
    int position;
}


/*
 *	Purpose: Parse the user inputed program and convert it to the internal 
 *               representation
 */
public class Parse {
  protected String str;
  char array[];
  int ConditionCount=1;
  int StatementCount=1;

  int parseOne = 0;
  int parseMulti = 1;

  boolean ErrStatus=false;
  String ErrStr;

  public Parse(String s) {
    str = new String(s);
    str = str.toLowerCase();
    array = new char[10000];
    str.getChars(0, str.length(), array, 0);
  }

  /*
   *	Purpose: start parsing
   */
  public ProgramObj go() {

    /*
     *  Empty program
     */
    if (start(array, 0) < 0) return null;

    ProgramObj p = new ProgramObj();
    StmtList list = new StmtList();
    parse(array, 0, str.length()-1, list);
    p.content = list;

    return p;
  }	/* End Method go() */


  /*
   *	Purpose: parse the program between from and end
   */
  void parse(char a[], int from, int end, StmtList list) {

    container con = parseOneStatement(a, from, parseMulti);
    if (con == null) {
      ErrStatus = true;
      ErrStr = "Error in Parsing";
      return;
    }
      

    list.CodeSeg = con.ReturnObj;
    int tmp = start(a, con.position);
    if (tmp > end || tmp < 0) {
      list.next = null;
    } else {
      list.next = new StmtList();
      parse(a, con.position, end, list.next);
    }

  }  /* End parse() */



  /*
   *	Parameters: mode - when equal to parseOne, this method will parse one
   *                       control statement or one group of normal statements
   *                       when equal to parseMulti, this method will pare one
   *                       control statement or one normal statement
   *	Purpose: parse one control statement or one group of normal statements
   *             or one normal statement
   *	return: return the current parsing position after parseOneStatement()
   */
  container parseOneStatement(char a[], int from, int mode) {

    String ControlName;
    ControlObj obj;
    int tmppos;

    int pos = start(a, from);
    if (pos < 0) {
      ErrStatus = true;
      ErrStr = "Error in Parsing";
      return null;
    }
    ControlName = Type(a, pos);

    if (ControlName == "if") {
      StmtList List = new StmtList();

      IfObj ifobj = new IfObj();
      ifobj.ConditionNo = ConditionCount++;
      tmppos = pos;
      pos = readCondition(a, pos+2); 
      if (pos < 0) {
        ErrStatus = true;
        ErrStr = "Error in Parsing";
        return null;
      }
      ifobj.ConditionContent = getStringCondition(a, tmppos+2);
/*      System.out.println(ifobj.ConditionContent); */
      pos = parseBlock(a, pos, List);
      if (pos < 0) {
        ErrStatus = true;
        ErrStr = "Error in Parsing";
        return null;
      }
      ifobj.yes = List;

      if (start(a, pos) != -1) {
        pos = start(a, pos);
        if (pos < 0) {
          ErrStatus = true;
          ErrStr = "Error in Parsing";
          return null;
        }
        if (Type(a, pos) == "else") {
          StmtList List2 = new StmtList();

          pos = parseBlock(a, pos+4, List2);
          if (pos < 0) {
            ErrStatus = true;
            ErrStr = "Error in Parsing";
            return null;
          }
          ifobj.no = List2;
        } else {
          ifobj.no = null;
        } 
      }
      
      obj = ifobj;

    } else if (ControlName == "while") {
      StmtList List = new StmtList();

      WhileObj whileobj = new WhileObj();
      whileobj.ConditionNo = ConditionCount++;
      tmppos = pos;
      pos = readCondition(a, pos+5);
      if (pos < 0) {
        ErrStatus = true;
        ErrStr = "Error in Parsing";
        return null;
      }
      whileobj.ConditionContent = getStringCondition(a, tmppos+5);
/*      System.out.println(whileobj.ConditionContent); */
      pos = parseBlock(a, pos, List);
      if (pos < 0) {
        ErrStatus = true;
        ErrStr = "Error in Parsing";
        return null;
      }

      whileobj.content = List;
      obj = whileobj;
     
    } else if (ControlName == "do") {
      StmtList List = new StmtList();

      RepeatObj repeatobj = new RepeatObj();
      repeatobj.ConditionNo = ConditionCount++;
      pos = parseBlock(a, pos+2, List);

      pos = start(a, pos);
      if (pos < 0) {
        ErrStatus = true;
        ErrStr = "Error in Parsing";
        return null;
      }
      if (Type(a, pos) != "while") {
        System.out.println("Error: do not followed by while");
        ErrStatus = true;
        ErrStr = "Error in Parsing";
        return null;
      }
      tmppos = pos;
      pos = readCondition(a, pos+5);
      if (pos < 0) {
        ErrStatus = true;
        ErrStr = "Error in Parsing";
        return null;
      }
      repeatobj.ConditionContent = getStringCondition(a, tmppos+5);
/*      System.out.println(repeatobj.ConditionContent); */
    
      pos = start(a, pos);
      if (pos < 0) {
        ErrStatus = true;
        ErrStr = "Error in Parsing";
        return null;
      }
      if (Type(a, pos) != ";") {
        System.out.println("Error: do...while missing \";\"");
        ErrStatus = true;
        ErrStr = "Error in Parsing";
        return null;
      }
      pos++;

      repeatobj.content = List;
      obj = repeatobj;

    } else {
      int flag;
      int begin=pos, end=0;

      while (true) {
        flag = 0;
        for (int i=pos; i<str.length(); i++) {
          if (a[i] == ';') {

            pos = start(a, i+1);
            if (pos == -1) {
              flag = 1;
              pos = i+1;
              break;
            }
            String tmp = Type(a, pos);

            if (tmp=="while" || tmp=="if" || tmp=="do" ||
                tmp=="else" || mode==parseOne) {
              flag = 1;		/* finish */
              end = i;
            } else
              flag = 2;
              
            break;    
          }

          /* { */
          if (a[i] == '}') {
            pos = i+1;
            flag = 1;
            end = i-1;
            break;		/* finish */
          }
        }

        if (flag == 0) {
          System.out.println("Error inside parseOneStatement\n");
          ErrStatus = true;
          ErrStr = "Error in Parsing";
          return null;
        } else if (flag == 1) {
          break;
        }
 
      }

      obj = new StatementObj();
      ((StatementObj)obj).StatementNo = StatementCount++;
      ((StatementObj)obj).StatementContent = String.copyValueOf(a, begin,
		end-begin+1);
      System.out.println(((StatementObj)obj).StatementContent);

    }

    container con = new container();
    con.ReturnObj = obj;
    con.position = pos;

    return con;

  }  /* end method parseOneStatement() */



  /*
   *	Purpose: parse a block of statement surrounded by { } or parse one
   *             control statement by calling pasreOneStatement()
   *	return: return the current parsing position after parseBlock()
   */
  int parseBlock(char a[], int from, StmtList list) {
    int head = start(a, from);
    int count = 0;
    int i;

    if (Type(a, head) == "{" /*}*/) {

      for (i=head; i<str.length(); i++) {
        if (a[i] == '{') count++;
        if (a[i] == '}') count--;
        if (count == 0) {
          break;
        }
      }

      if (count != 0) {
        System.out.println("Error inside parseBlock\n");
        ErrStatus = true;
        ErrStr = "Error in Parsing";
        return -1;
      }

      parse(a, head+1, i-1, list);
      return i+1;

    } else {
      container con = parseOneStatement(a, from, parseOne);
      if (con == null) {
        ErrStatus = true;
        ErrStr = "Error in Parsing";
        return -1;
      }
      list.CodeSeg = con.ReturnObj;
      list.next = null;
      return(con.position);
    }


  }  /* end method parseBlock() */



  /*
   *	Purpose: Check end of the program
   *	return: true if reach the end, false otherwise
   */
  boolean NotEnd(char a[], int from) {
    if (start(a, from) != -1) return true;
    else return false;
  }


  /*
   *	Purpose: Read the condition content
   *	return: the current parsing position after reading the condition content
   */
  int readCondition(char a[], int from) {
    int head = start(a, from);
    if (Type(a, head) != "(" /*)*/) return -1;

    int i=head;
    int count=0;
    while (i<str.length()) {
      if (a[i] == '(') count++;

      if (a[i] == ')') {
        count--;
        if (count == 0) return(i+1);
      }

      i++;
    }

    return -1;

  }	/* End Method readCondition() */


  /*
   *	Purpose: Read the condition content
   *	return: the condition content
   */
  String getStringCondition(char a[], int from) {
    int begin=0;
    String string="";
    int head = start(a, from);

    int i=head;
    int count=0;
    while (i<str.length()) {
      if (a[i] == '(') {
        if (count == 0) begin = start(a, i+1);
        count++;
      }

      if (a[i] == ')') {
        count--;
        if (count == 0) {
         string = String.copyValueOf(a, begin, (i-1)-begin+1);
         break;
        }
      }

      i++;
    }
    return string;

  }	/* End Method getStringCondition() */



  /*
   *	Purpose: return the type of the next token
   */
  String Type(char a[], int from) {
    if (str.startsWith("if", from)) return "if";
    if (str.startsWith("while", from)) return "while";
    if (str.startsWith("do", from)) return "do";
    if (str.startsWith("else", from)) return "else";
    if (str.startsWith("{", from)) return ("{");
    if (str.startsWith("}", from)) return ("}");
    if (str.startsWith("(", from)) return ("(");
    if (str.startsWith(")", from)) return (")");
    if (str.startsWith(";", from)) return (";");

    return ("UNKNOWN");
  }	/* End Method Type() */


  /*
   *	Purpose: return the next position which is not a delimilter
   */
  int start(char a[], int from) {
    if (from >= str.length()) return -1;

    for (int i=from; i<str.length(); i++) {
      switch (a[i]) {
	case ' ':
	case '\t':
	case '\n':
	case '\r':
	  break;
	default:
	  return i;
      }
    }
    return -1;
  }	/* End Method start() */


}
