package edu.cmu.cs.l3.parse;

import edu.cmu.cs.l3.errormsg.ErrorMsg;
import edu.cmu.cs.l3.general.*;
import java.util.*;

/**
  This file is used by JLex to create lexer.lex.java, which
  contains the Yylex class for lexical analysis.

  References: Appel, Chapter 2: Lexical Analysis
*/

%%

%implements Lexer
%function nextToken
%type java_cup.runtime.Symbol
%char

%state COMMENT
%state LINECOMMENT
%state FILENAME
%state CPPDESC

ALPHA=[A-Za-z_]
DIGIT=[0-9]
SPECIAL=[\*!@$%&\?\.\(\)\[\]\-\+\=/,<>:;\{\}\ ]
CTOKEN={ALPHA}|{DIGIT}|{SPECIAL}
WHITE_SPACE_CHAR=[\ \t\b\r\n]
NONNEWLINE_WHITE_SPACE_CHAR=[\r\ \t\b]
COMMENT_TEXT=([^/*\n]|[^*\n]"/"[^*\n]|[^*/\n]"*"[^*/\n]|"*"[^*/\n]|"/"[^*\n]|"*")
LINECOMMENT_TEXT=[^\n]

%{
private int comment_count = 0;
private int last_linenumber = 0;
private boolean inlinecomment = false;
private String filename = "";
private Hashtable outputted = new Hashtable();

private void newline() {
  errorMsg.newline(yychar);
}

private void err(int pos, String s) {
  errorMsg.error(pos,s);
}

private void err(String s) {
  err(yychar,s);
}

private void outfile(String s) {
  if (!s.startsWith("<") && outputted.get(s) == null) {
    outputted.put(s, new Integer(1));
    Globals.verbosePrintln("  --- " + s);
  }
}

private java_cup.runtime.Symbol tok(int kind, Object value) {
    return new java_cup.runtime.Symbol(kind, yychar, yychar+yylength(), value);
}

private ErrorMsg errorMsg;

Yylex(java.io.InputStream s, ErrorMsg e) {
  this(s);
  errorMsg=e;
}

%}

%eofval{
	{
	 return tok(sym.EOF, null);
        }
%eofval}       

%%

<YYINITIAL> \012 { newline(); }
<YYINITIAL> {NONNEWLINE_WHITE_SPACE_CHAR} { }

<YYINITIAL> "{"  { return tok(sym.LBRACE, null); }
<YYINITIAL> "}"  { return tok(sym.RBRACE, null); }
<YYINITIAL> "("  { return tok(sym.LPAREN, null); }
<YYINITIAL> ")"  { return tok(sym.RPAREN, null); }
<YYINITIAL> "+"  { return tok(sym.PLUS, null); }
<YYINITIAL> "*"  { return tok(sym.TIMES, null); }
<YYINITIAL> "-"  { return tok(sym.MINUS, null); }
<YYINITIAL> "/"  { return tok(sym.DIVIDE, null); }
<YYINITIAL> "="  { return tok(sym.ASSIGN, null); }
<YYINITIAL> "%"  { return tok(sym.MOD, null); }
<YYINITIAL> "+=" { return tok(sym.PLUSASSIGN, null); }
<YYINITIAL> "*=" { return tok(sym.TIMESASSIGN, null); }
<YYINITIAL> "-=" { return tok(sym.MINUSASSIGN, null); }
<YYINITIAL> "/=" { return tok(sym.DIVIDEASSIGN, null); }
<YYINITIAL> "%=" { return tok(sym.MODASSIGN, null); }
<YYINITIAL> "~"  { return tok(sym.BNOT, null); }
<YYINITIAL> ";"  { return tok(sym.SEMICOL, null); }
<YYINITIAL> "return"  { return tok(sym.RETURN, null); }
<YYINITIAL> "if"  { return tok(sym.IF, null); }
<YYINITIAL> "else"  { return tok(sym.ELSE, null); }
<YYINITIAL> "var"  { return tok(sym.VAR, null); }
<YYINITIAL> ":"  { return tok(sym.COLON, null); }
<YYINITIAL> ","  { return tok(sym.COMMA, null); }
<YYINITIAL> "&&"  { return tok(sym.BOOLAND, null); }
<YYINITIAL> "||"  { return tok(sym.BOOLOR, null); }
<YYINITIAL> "^^"  { return tok(sym.BOOLXOR, null); }
<YYINITIAL> "!"  { return tok(sym.BOOLNOT, null); }
<YYINITIAL> "true"  { return tok(sym.TRUE, null); }
<YYINITIAL> "false"  { return tok(sym.FALSE, null); }
<YYINITIAL> "."  { return tok(sym.DOT, null); }
<YYINITIAL> "->"  { return tok(sym.ARROW, null); }
<YYINITIAL> "alloc"  { return tok(sym.ALLOC, null); }
<YYINITIAL> "struct"  { return tok(sym.STRUCT, null); }
<YYINITIAL> "<"  { return tok(sym.LESSTHAN, null); }
<YYINITIAL> "<="  { return tok(sym.LESSTHANOREQUAL, null); }
<YYINITIAL> ">"  { return tok(sym.GREATERTHAN, null); }
<YYINITIAL> ">="  { return tok(sym.GREATERTHANOREQUAL, null); }
<YYINITIAL> "=="  { return tok(sym.EQUAL, null); }
<YYINITIAL> "!="  { return tok(sym.NOTEQUAL, null); }
<YYINITIAL> "NULL"  { return tok(sym.NULL, null); }
<YYINITIAL> "int"  { return tok(sym.DINT, null); }
<YYINITIAL> "bool"  { return tok(sym.DBOOL, null); }
<YYINITIAL> "["  { return tok(sym.LBRACKET, null); }
<YYINITIAL> "]"  { return tok(sym.RBRACKET, null); }
<YYINITIAL> "&"  { return tok(sym.BAND, null); }
<YYINITIAL> "offset"  { return tok(sym.OFFSET, null); }
<YYINITIAL> "size"  { return tok(sym.SIZE, null); }
<YYINITIAL> "*+"  { return tok(sym.PPLUS, null); }
<YYINITIAL> "*-"  { return tok(sym.PMINUS, null); }
<YYINITIAL> "*=="  { return tok(sym.PEQUAL, null); }
<YYINITIAL> "*!="  { return tok(sym.PNOTEQUAL, null); }
<YYINITIAL> "for"  { return tok(sym.FOR, null); }
<YYINITIAL> "while"  { return tok(sym.WHILE, null); }
<YYINITIAL> "void"  { return tok(sym.VOID, null); }
<YYINITIAL> "foreign"  { return tok(sym.FOREIGN, null); }
<YYINITIAL> "break"  { return tok(sym.BREAK, null); }
<YYINITIAL> "continue"  { return tok(sym.CONTINUE, null); }
<YYINITIAL> "|"  { return tok(sym.BOR, null); }
<YYINITIAL> "^"  { return tok(sym.BXOR, null); }
<YYINITIAL> "<<"  { return tok(sym.LSHIFT, null); }
<YYINITIAL> ">>"  { return tok(sym.RSHIFT, null); }
<YYINITIAL> "#"  { yybegin(CPPDESC); }

<YYINITIAL> {DIGIT}+ { return tok(sym.INT, yytext()); }

<YYINITIAL> {ALPHA}({DIGIT}|{ALPHA}|_)* { return tok(sym.ID, yytext()); }

<YYINITIAL> "//" { yybegin(LINECOMMENT); }
<LINECOMMENT> {LINECOMMENT_TEXT} { }
<LINECOMMENT> \n { newline(); yybegin(YYINITIAL); }

<CPPDESC> "\"" { filename = ""; yybegin(FILENAME); }
<CPPDESC> {DIGIT}+ { last_linenumber = Integer.parseInt(yytext()); }
<CPPDESC> \n { newline(); yybegin(YYINITIAL); }
<CPPDESC> {NONNEWLINE_WHITE_SPACE_CHAR} { }

<FILENAME> "\"" { outfile(filename); errorMsg.newfile(filename, last_linenumber); yybegin(CPPDESC); }
<FILENAME> \n { newline(); }
<FILENAME> {CTOKEN}* { filename += yytext(); }

<YYINITIAL> "/*" {  yybegin(COMMENT); comment_count = comment_count + 1; }
<COMMENT> "/*" { comment_count = comment_count + 1; }
<COMMENT> "*/" { 
	comment_count = comment_count - 1; 

	if (comment_count == 0) {
    		yybegin(YYINITIAL);
	}
}
<YYINITIAL> "*/" {
        err("Unbalanced comment");
}

<COMMENT> \n { newline(); }
<COMMENT> {COMMENT_TEXT} {  }


<YYINITIAL,COMMENT,LINECOMMENT> . {
        err("Illegal character: <" + yytext() + ">");
}
