/* CS211 Final Project
 * Author: Max Khavin
 * Yylex.java
 * Produced using JLex
 ***************************************************************
 * This file contains the code implementing the lexical analyzer
 * for the Java programming language.  Do not try to understand what
 * it does!  I don't... :)
 */
  
/* scattered things modified by Geoffrey Hoffman
 */ 

class Utility {  
  public static void assert
    (
     boolean expr
     )
      { 
	if (false == expr) {
	  throw (new Error("Error: Assertion failed."));
	}
      }
  
  private static final String errorMsg[] = {
    "Error: Unmatched end-of-comment punctuation.",
    "Error: Unmatched start-of-comment punctuation.",
    "Error: Unclosed string.",
    "Error: Illegal character."
    };
  
  public static final int E_ENDCOMMENT = 0; 
  public static final int E_STARTCOMMENT = 1; 
  public static final int E_UNCLOSEDSTR = 2; 
  public static final int E_UNMATCHED = 3; 

  public static void error
    (
     int code
     )
      {
	System.out.println(errorMsg[code]);
      }
}

class Yytoken {
  Yytoken 
    (
     int m_type,
     String m_text
     )
      {
	type = m_type;
	text = new String(m_text);
      }

  private int type;
  private String text;

  public int getType() { return type; }
  public String getText() { return text; }
}

%%
%{
  private String comments = "";
%} 
%public
%state COMMENT, LINECOMMENT

ALPHA=[.A-Za-z]
DIGIT=[0-9]
NONNEWLINE_WHITE_SPACE_CHAR=[\ \t\b\012]
WHITE_SPACE_CHAR=[\n\ \t\b\012]
STRING_TEXT=(\\\"|[^\n\"]|\\{WHITE_SPACE_CHAR}+\\)*
COMMENT_TEXT=([^/*\n]|[^*\n]"/"[^*\n]|[^/\n]"*"[^/\n]|"*"[^/\n]|"/"[^*\n])*
NEW_LINE = ([\n\r])+
LINE_COMMENT_TEXT=([^\n\r])*

%% 

<YYINITIAL> "abstract" { return (new Yytoken(TokenType.ABSTRACT, yytext())); }
<YYINITIAL> "boolean" { return (new Yytoken(TokenType.BOOLEAN, yytext())); }
<YYINITIAL> "break" { return (new Yytoken(TokenType.BREAK, yytext())); }
<YYINITIAL> "byte" { return (new Yytoken(TokenType.BYTE, yytext())); }
<YYINITIAL> "case" { return (new Yytoken(TokenType.CASE, yytext())); }
<YYINITIAL> "catch" { return (new Yytoken(TokenType.CATCH, yytext())); }
<YYINITIAL> "char" { return (new Yytoken(TokenType.CHAR, yytext())); }
<YYINITIAL> "class" { return (new Yytoken(TokenType.CLASS, yytext())); }
<YYINITIAL> "const" { return (new Yytoken(TokenType.CONST, yytext())); }
<YYINITIAL> "continue" { return (new Yytoken(TokenType.CONTINUE, yytext())); }
<YYINITIAL> "do" { return (new Yytoken(TokenType.DO, yytext())); }
<YYINITIAL> "double" { return (new Yytoken(TokenType.DOUBLE, yytext())); }
<YYINITIAL> "else" { return (new Yytoken(TokenType.ELSE, yytext())); }
<YYINITIAL> "extends" { return (new Yytoken(TokenType.EXTENDS, yytext())); }
<YYINITIAL> "final" { return (new Yytoken(TokenType.FINAL, yytext())); }
<YYINITIAL> "finally" { return (new Yytoken(TokenType.FINALLY, yytext())); }
<YYINITIAL> "float" { return (new Yytoken(TokenType.FLOAT, yytext())); }
<YYINITIAL> "for" { return (new Yytoken(TokenType.FOR, yytext())); }
<YYINITIAL> "default" { return (new Yytoken(TokenType.DEFAULT, yytext())); }
<YYINITIAL> "if" { return (new Yytoken(TokenType.IF, yytext())); }
<YYINITIAL> "implements" { return (new Yytoken(TokenType.IMPLEMENTS, yytext())); }
<YYINITIAL> "import" { return (new Yytoken(TokenType.IMPORT, yytext())); }
<YYINITIAL> "instanceof" { return (new Yytoken(TokenType.INSTANCEOF, yytext())); }
<YYINITIAL> "int" { return (new Yytoken(TokenType.INT, yytext())); } 
<YYINITIAL> "interface" { return (new Yytoken(TokenType.INTERFACE, yytext())); }
<YYINITIAL> "long" { return (new Yytoken(TokenType.LONG, yytext())); }
<YYINITIAL> "native" { return (new Yytoken(TokenType.NATIVE, yytext())); }
<YYINITIAL> "new" { return (new Yytoken(TokenType.NEW, yytext())); }
<YYINITIAL> "goto" { return (new Yytoken(TokenType.GOTO, yytext())); }
<YYINITIAL> "public" { return (new Yytoken(TokenType.PUBLIC, yytext())); }
<YYINITIAL> "short" { return (new Yytoken(TokenType.SHORT, yytext())); }
<YYINITIAL> "super" { return (new Yytoken(TokenType.SUPER, yytext())); }
<YYINITIAL> "switch" { return (new Yytoken(TokenType.SWITCH, yytext())); }
<YYINITIAL> "synchronized" { return (new Yytoken(TokenType.SYNCHRONIZED, yytext())); }
<YYINITIAL> "package" { return (new Yytoken(TokenType.PACKAGE, yytext())); }
<YYINITIAL> "this" { return (new Yytoken(TokenType.THIS, yytext())); }
<YYINITIAL> "private" { return (new Yytoken(TokenType.PRIVATE, yytext())); }
<YYINITIAL> "protected" { return (new Yytoken(TokenType.PROTECTED, yytext())); }
<YYINITIAL> "transient" { return (new Yytoken(TokenType.TRANSIENT, yytext())); }
<YYINITIAL> "return" { return (new Yytoken(TokenType.RETURN, yytext())); }
<YYINITIAL> "try" { return (new Yytoken(TokenType.TRY, yytext())); }
<YYINITIAL> "void" { return (new Yytoken(TokenType.VOID, yytext())); }
<YYINITIAL> "static" { return (new Yytoken(TokenType.STATIC, yytext())); }
<YYINITIAL> "volatile" { return (new Yytoken(TokenType.VOLATILE, yytext())); }
<YYINITIAL> "while" { return (new Yytoken(TokenType.WHILE, yytext())); }
<YYINITIAL> "throw" { return (new Yytoken(TokenType.THROW, yytext())); }
<YYINITIAL> "throws" { return (new Yytoken(TokenType.THROWS, yytext())); }
<YYINITIAL> "(" { return (new Yytoken(TokenType.LPARAN, yytext())); }
<YYINITIAL> ")" { return (new Yytoken(TokenType.RPARAN, yytext())); }
<YYINITIAL> "{" { return (new Yytoken(TokenType.LCURLY, yytext())); }
<YYINITIAL> "}" { return (new Yytoken(TokenType.RCURLY, yytext())); }
<YYINITIAL> "[" { return (new Yytoken(TokenType.LBRACKET, yytext())); }
<YYINITIAL> "]" { return (new Yytoken(TokenType.RBRACKET, yytext())); }
<YYINITIAL> ";" { return (new Yytoken(TokenType.SEMICOLON, yytext())); }
<YYINITIAL> ":" { return (new Yytoken(TokenType.COLON, yytext())); }
<YYINITIAL> "true" { return (new Yytoken(TokenType.TRUE, yytext())); }
<YYINITIAL> "false" { return (new Yytoken(TokenType.FALSE, yytext())); }
<YYINITIAL> "null" { return (new Yytoken(TokenType.NULL, yytext())); }
<YYINITIAL> "," { return (new Yytoken(TokenType.COMMA, yytext())); }

<YYINITIAL> "=" { return (new Yytoken(TokenType.OPERATOR, yytext())); }
<YYINITIAL> "==" { return (new Yytoken(TokenType.OPERATOR, yytext())); }
<YYINITIAL> "+" { return (new Yytoken(TokenType.OPERATOR, yytext())); }
<YYINITIAL> "+=" { return (new Yytoken(TokenType.OPERATOR, yytext())); }
<YYINITIAL> ">" { return (new Yytoken(TokenType.OPERATOR, yytext())); }
<YYINITIAL> "<=" { return (new Yytoken(TokenType.OPERATOR, yytext())); }
<YYINITIAL> "-" { return (new Yytoken(TokenType.OPERATOR, yytext())); }
<YYINITIAL> "-=" { return (new Yytoken(TokenType.OPERATOR, yytext())); }
<YYINITIAL> "<" { return (new Yytoken(TokenType.OPERATOR, yytext())); }
<YYINITIAL> ">=" { return (new Yytoken(TokenType.OPERATOR, yytext())); }
<YYINITIAL> "*" { return (new Yytoken(TokenType.OPERATOR, yytext())); }
<YYINITIAL> "*=" { return (new Yytoken(TokenType.OPERATOR, yytext())); }
<YYINITIAL> "!" { return (new Yytoken(TokenType.OPERATOR, yytext())); }
<YYINITIAL> "!=" { return (new Yytoken(TokenType.OPERATOR, yytext())); }
<YYINITIAL> "/" { return (new Yytoken(TokenType.OPERATOR, yytext())); }
<YYINITIAL> "/=" { return (new Yytoken(TokenType.OPERATOR, yytext())); }
<YYINITIAL> "~" { return (new Yytoken(TokenType.OPERATOR, yytext())); }
<YYINITIAL> "&&" { return (new Yytoken(TokenType.OPERATOR, yytext())); }
<YYINITIAL> "&" { return (new Yytoken(TokenType.OPERATOR, yytext())); }
<YYINITIAL> "&=" { return (new Yytoken(TokenType.OPERATOR, yytext())); }
<YYINITIAL> "||" { return (new Yytoken(TokenType.OPERATOR, yytext())); }
<YYINITIAL> "|" { return (new Yytoken(TokenType.OPERATOR, yytext())); }
<YYINITIAL> "|=" { return (new Yytoken(TokenType.OPERATOR, yytext())); }
<YYINITIAL> "^^" { return (new Yytoken(TokenType.OPERATOR, yytext())); }
<YYINITIAL> "^" { return (new Yytoken(TokenType.OPERATOR, yytext())); }
<YYINITIAL> "^=" { return (new Yytoken(TokenType.OPERATOR, yytext())); }
<YYINITIAL> "?" { return (new Yytoken(TokenType.OPERATOR, yytext())); }
<YYINITIAL> "++" { return (new Yytoken(TokenType.OPERATOR, yytext())); }
<YYINITIAL> "^" { return (new Yytoken(TokenType.OPERATOR, yytext())); }
<YYINITIAL> "^=" { return (new Yytoken(TokenType.OPERATOR, yytext())); }
<YYINITIAL> "--" { return (new Yytoken(TokenType.OPERATOR, yytext())); }
<YYINITIAL> "%" { return (new Yytoken(TokenType.OPERATOR, yytext())); }
<YYINITIAL> "%=" { return (new Yytoken(TokenType.OPERATOR, yytext())); }
<YYINITIAL> "<<" { return (new Yytoken(TokenType.OPERATOR, yytext())); }
<YYINITIAL> "<<=" { return (new Yytoken(TokenType.OPERATOR, yytext())); }
<YYINITIAL> ">>" { return (new Yytoken(TokenType.OPERATOR, yytext())); }
<YYINITIAL> ">>=" { return (new Yytoken(TokenType.OPERATOR, yytext())); }
<YYINITIAL> ">>>" { return (new Yytoken(TokenType.OPERATOR, yytext())); }
<YYINITIAL> ">>>=" { return (new Yytoken(TokenType.OPERATOR, yytext())); }



<YYINITIAL, COMMENT> {NONNEWLINE_WHITE_SPACE_CHAR}+ { }



<YYINITIAL> "//" {  comments = ""; yybegin(LINECOMMENT); }

<LINECOMMENT> . {comments=comments+yytext();}

<LINECOMMENT> {NEW_LINE} {
	yybegin(YYINITIAL);
	return (new Yytoken(TokenType.LINECOMMENT, comments));
}


<YYINITIAL> "/*" { comments=""; yybegin(COMMENT);}

<COMMENT> [*]+"/" {
	yybegin(YYINITIAL);
	return (new Yytoken(TokenType.COMMENT, comments+yytext().substring(1, yytext().length() - 1)));
}

<COMMENT> {COMMENT_TEXT} {comments=comments+yytext()+ Beautify.UI_Frame.Update_Thing.newLine() + " ";}

<YYINITIAL> \"{STRING_TEXT}\" {
	String str =  yytext().substring(1,yytext().length() - 1);
	
	Utility.assert(str.length() == yytext().length() - 2);
	return (new Yytoken(TokenType.STRING,str));
}

<YYINITIAL> \"{STRING_TEXT} {
	String str =  yytext().substring(1,yytext().length());

	Utility.error(Utility.E_UNCLOSEDSTR);
	Utility.assert(str.length() == yytext().length() - 1);
	return (new Yytoken(TokenType.STRING,str));
} 



<YYINITIAL> {DIGIT}+ { 
	return (new Yytoken(TokenType.NUMBER,yytext()));
}	
<YYINITIAL> {DIGIT}+"."{DIGIT}+ { 
	return (new Yytoken(TokenType.NUMBER,yytext()));
}	
<YYINITIAL> {ALPHA}({ALPHA}|{DIGIT}|_|"."|".*")* {
	return (new Yytoken(TokenType.IDENTIFIER,yytext()));
}




<YYINITIAL,COMMENT, LINECOMMENT> . {
        System.out.println("Illegal character: <" + yytext() + ">");
	Utility.error(Utility.E_UNMATCHED);
}
