/******************************************************************************
// -*- LEX -*-  // To make emacs recognize the correct program type.
// -*- C -*-  // To make emacs recognize the correct program type.
///////////////////////////////////////////////////////////////////////////////
// Language: SRC3
// Purpose:  
//
// By: Hung-chih Yang
// Initiate date:  DATELL--Tue Apr  8 15:52:58 2003--DATERL
// Finalized date: DATEFL--Tue Apr 22 12:55:40 2003--DATEFR
// To do List:
// Change List:
// Notes:
// Functionalities should be implemented:
//
///////////////////////////////////////////////////////////////////////////////
******************************************************************************/

/******************************************************************************
///////////////////////////////////////////////////////////////////////////////
// definition section
///////////////////////////////////////////////////////////////////////////////
******************************************************************************/

%option nounput

%{

    /**************************************************************************
    ///////////////////////////////////////////////////////////////////////////
    // C code
    ///////////////////////////////////////////////////////////////////////////
    **************************************************************************/

    /**************************************************************************
    ///////////////////////////////////////////////////////////////////////////
    // macros
    ///////////////////////////////////////////////////////////////////////////
    **************************************************************************/

    #include "ast.h"

    #if !defined(LEX_TO_PRINT_LEXER_DEBUG_MESSAGE)
         #define LEX_TO_PRINT_LEXER_DEBUG_MESSAGE 1
    #endif
    #if !defined(LEX_TO_PRINT_LEXER_ERROR_MESSAGE)
         #define LEX_TO_PRINT_LEXER_ERROR_MESSAGE 1
    #endif
    #if !defined(LEX_TO_PRINT_LEXER_OUTPUT)
         #define LEX_TO_PRINT_LEXER_OUTPUT 1
    #endif

    #if !defined(LEX_TO_RETURN_TOKEN_FOR_PASER)
         #define LEX_TO_RETURN_TOKEN_FOR_PASER 0
    #endif
    #undef GET_TOKEN_FOR_PARSER
    #if LEX_TO_RETURN_TOKEN_FOR_PASER != 0
         #include "src3.tab.h"
         extern YYSTYPE yylval;
         #define GET_TOKEN_FOR_PARSER(x)                                      \
         {                                                                    \
           return x;                                                          \
         }
         #define GET_INTEGER_TOKEN_FOR_PARSER(x)                              \
         {                                                                    \
           yylval.integerValue = atoi(yytext);                                \
           return x;                                                          \
         }
         #define GET_REAL_TOKEN_FOR_PARSER(x)                                 \
         {                                                                    \
           yylval.doubleValue = atof(yytext);                                 \
           return x;                                                          \
         }
	   #define GET_ID_TOKEN_FOR_PARSER(x)						\
	   {												\
	     yylval.IDValuePtr = malloc(sizeof(ID_Type));				\
	     yylval.IDValuePtr->_lineno = glex_LineNumber;				\
           yylval.IDValuePtr->id = strdup(yytext);                            \
           return x;                                                          \
         }
	   #define GET_STRING_TOKEN_FOR_PARSER(x)						\
	   {												\
           yylval.stringValue = strdup(yytext);                               \
           return x;                                                          \
         }
    #else
         #define GET_TOKEN_FOR_PARSER(x)
         #define GET_INTEGER_TOKEN_FOR_PARSER(x)
         #define GET_REAL_TOKEN_FOR_PARSER(x)
         #define GET_STRING_TOKEN_FOR_PARSER(x)
    #endif

    /**************************************************************************
    ///////////////////////////////////////////////////////////////////////////
    // header files
    ///////////////////////////////////////////////////////////////////////////
    **************************************************************************/

    #include <stdio.h>
    #include <string.h>

    /**************************************************************************
    ///////////////////////////////////////////////////////////////////////////
    // control variables
    ///////////////////////////////////////////////////////////////////////////
    **************************************************************************/
    int glex_LineNumber = 1;
    int lineNumberCommentBegin = 1;
    int characterPosition = 0;
    int countCommentsNested = 0;

    int lexToPrintLexerDebugMessage = LEX_TO_PRINT_LEXER_DEBUG_MESSAGE;
    int lexToPrintLexerErrorMessage = LEX_TO_PRINT_LEXER_ERROR_MESSAGE;
    int lexToPrintLexerOutput = LEX_TO_PRINT_LEXER_OUTPUT;

    int lexToReturnTokensToParser = LEX_TO_RETURN_TOKEN_FOR_PASER;

    /**************************************************************************
    ///////////////////////////////////////////////////////////////////////////
    // auxiliary subroutines
    ///////////////////////////////////////////////////////////////////////////
    **************************************************************************/

   int returnTokenForParser(int token) {
     if (lexToReturnTokensToParser) {
       return token;
     }
     return 0;
   }

    void generalProcessing(void) {
      characterPosition += yyleng;
    }

    void newlineProcessing(void) {
      characterPosition = 0;
      glex_LineNumber++;
    }

    void debugPrint(const char* message) {
      if (lexToPrintLexerDebugMessage) {
        printf("%s", message);
        printf("\n");
      }
    }
    void debugPrintInt(const char* message, int number) {
      if (lexToPrintLexerDebugMessage) {
        printf("%s%d", message, number);
        printf("\n");
      }
    }
    void debugPrintUnsignedInt(const char* message, unsigned int number) {
      if (lexToPrintLexerDebugMessage) {
        printf("%s%u", message, number);
        printf("\n");
      }
    }
    void debugPrintString(const char* message, const char* inString) {
      if (lexToPrintLexerDebugMessage) {
        printf("%s[%s]", message, inString);
        printf("\n");
      }
    }

    void printErrorMessageAndLineNumber(const char* errorMessage,
                                        int alineNumber) {
      if (lexToPrintLexerErrorMessage) {
        printf("ERROR ");
        printf("LINE %d:\t", alineNumber);
        printf("%s", errorMessage);
      }
    }
    void printErrorMessage(const char* errorMessage) {
      if (lexToPrintLexerErrorMessage) {
        printErrorMessageAndLineNumber(errorMessage, glex_LineNumber);
      }
    }
    void printErrorAndExit(const char* errorMessage) {
      if (lexToPrintLexerErrorMessage) {
        printErrorMessage(errorMessage);
        printf("\n");
        exit(-1);
      }
    }
    void printErrorSymbolAndExit(const char* errorMessage,
                                 const char* unknownSymbol) {
      if (lexToPrintLexerErrorMessage) {
        printErrorMessage(errorMessage);
        printf(": ");
        printf("%s", unknownSymbol);
        printf("\n");
        exit(-1);
      }
    }
    void printErrorCommentAndExit(const char* errorMessage) {
      if (lexToPrintLexerErrorMessage) {
        printErrorMessageAndLineNumber(errorMessage, lineNumberCommentBegin);
        printf("\n");
        exit(-1);
      }
    }

    void printLineNumber(void) {
      if (lexToPrintLexerOutput) {
        printf(":\t%d", glex_LineNumber);
        printf("\n");
      }
    }
    void printToken(const char* token) {
      if (lexToPrintLexerOutput) {
        printf("%s", token);
        printLineNumber();
      }
    }
    void printTokenString(const char* token, const char* inString) {
      if (lexToPrintLexerOutput) {
        printf("%s(%s)", token, inString);
        printLineNumber();
      }
    }
    void printTokenInt(const char* token, int inInt) {
      if (lexToPrintLexerOutput) {
        printf("%s(%d)", token, inInt);
        printLineNumber();
      }
    }
    void printTokenDouble(const char* token, double inDouble) {
      if (lexToPrintLexerOutput) {
        printf("%s(%f)", token, inDouble);
        printLineNumber();
      }
    }
    void printTokenStringInt(const char* token,
                             const char* inString,
                             int inInt) {
      if (lexToPrintLexerOutput) {
        printf("%s(%s;%d)", token, inString, inInt);
        printLineNumber();
      }
    }
    void printTokenLiteralString(const char* token,
                                 const char* inString,
                                 int inInt) {
      if (lexToPrintLexerOutput) {
        printf("%s(%s;%d)", token, inString, inInt);
        printLineNumber();
      }
    }
    void printProcessTokenLiteralString(const char* token,
                                        char* inString) {
      int stringLength = strlen(inString);
      int numberOfDoubleQuotes = 0;
      int i = 1;
      int j = 1;
      if (stringLength < 2) {
        printErrorAndExit("internal logic error -- in "
                          "literal strings");
      }
      while(i < stringLength - 1) {
        if (inString[i] == '\"') {
          numberOfDoubleQuotes++;
          i++;
        }
        inString[j] = inString[i];
        i++;
        j++;
      }
      inString[stringLength - numberOfDoubleQuotes - 1] = '\0';
	memmove(inString, inString + 1, strlen(inString));
      if (lexToPrintLexerOutput) {
        printTokenLiteralString(token,
                                inString,
                                stringLength - numberOfDoubleQuotes - 2);
      }
    }
    void printTokenStringDouble(const char* token,
                                const char* inString,
                                      double inDouble) {
      if (lexToPrintLexerOutput) {
        printf("%s(%s;%f)", token, inString, inDouble);
        printLineNumber();
      }
    }

    /**************************************************************************
      We cannot define yywrap in this section, it should be in the user
      definition section (the third one).
    **************************************************************************/
    /**************************************************************************
    #ifdef yywrap
      #undef yywrap
    #endif
    int yywrap() {
      if (countCommentsNested != 0) {
        printErrorCommentAndExit("Unclosed Comment");
      }
      return 1;
    }
    **************************************************************************/

%}

/******************************************************************************
///////////////////////////////////////////////////////////////////////////////
// regular expression definitions
///////////////////////////////////////////////////////////////////////////////
******************************************************************************/

reserved_var            ("var")

reserved_int            ("int")
reserved_real           ("real")
reserved_string         ("string")
reserved_bool           ("bool")

reserved_array          ("array")
reserved_of             ("of")

reserved_begin          ("begin")
reserved_end            ("end")

reserved_read           ("read")
reserved_write          ("write")
reserved_writeln        ("writeln")

reserved_if             ("if")
reserved_then           ("then")
reserved_else           ("else")

reserved_while          ("while")
reserved_do             ("do")

reserved_return         ("return")

operator_not            ("!")
operator_mul            ("*")
operator_div            ("/")
operator_mod            ("%")
operator_plus           ("+")
operator_minus          ("-")
operator_lt             ("<")
operator_gt             (">")
operator_eq             ("=")
operator_lbracket       ("[")
operator_rlbracket      ("]")
operator_lparen         ("(")
operator_rparen         (")")
operator_colon          (":")
operator_semi           (";")
operator_comma          (",")
operator_neq            ("<>")
operator_lte            ("<=")
operator_gte            (">=")
operator_or             ("||")
operator_and            ("&&")
operator_assign         (":=")
operator_subrange       ("..")

identifier              ([a-zA-Z][a-zA-Z0-9]*)

literal_integer         ([0-9]+)

literal_real_wo_dot     ([0-9]+([eE][+-]?[0-9]+))
literal_real_w_dot_exp  (([0-9])*"."([0-9])+([eE][+-]?[0-9]+)?)
literal_real_w_dot      ({literal_real_w_dot_exp})
literal_real            ({literal_real_wo_dot}|{literal_real_w_dot})

white_space             ([ \t]+)
new_line                (\r?\n)

unclosed_string         (\"([^\"]*){new_line})
literal_string          (\"(([^\"\n])|(\"\"))*\")

begin_comment           ("/*")

end_comment             ("*/")

/******************************************************************************
///////////////////////////////////////////////////////////////////////////////
// states
///////////////////////////////////////////////////////////////////////////////
******************************************************************************/


/******************************************************************************
 The exclusive state COMMENT is used to deal with C-style comment.
 It is necessary to use exclusive state (%x), becuase a normal state
 (%s) would allow other regular expression to be matched also in
 a context-sensitive situation. Simulation of exclusive state using
 normal states (%s) is cumbersome.
******************************************************************************/
%x COMMENT

/******************************************************************************
///////////////////////////////////////////////////////////////////////////////
// rule section
///////////////////////////////////////////////////////////////////////////////
******************************************************************************/

%%

{reserved_var}     {
                     generalProcessing();
                     printToken("VAR");
                     GET_TOKEN_FOR_PARSER(VAR);
                   }

{reserved_int}     {
                     generalProcessing();
                     printToken("INT");
                     GET_TOKEN_FOR_PARSER(INT);
                   }
{reserved_real}    {
                     generalProcessing();
                     printToken("REAL");
                     GET_TOKEN_FOR_PARSER(REAL);
                   }
{reserved_string}  {
                     generalProcessing();
                     printToken("STRING");
                     GET_TOKEN_FOR_PARSER(STRING);
                   }
{reserved_bool}    {
                     generalProcessing();
                     printToken("BOOL");
                     GET_TOKEN_FOR_PARSER(BOOL);
                   }

{reserved_array}   {
                     generalProcessing();
                     printToken("ARRAY");
                     GET_TOKEN_FOR_PARSER(ARRAY);
                   }
{reserved_of}      {
                     generalProcessing();
                     printToken("OF");
                     GET_TOKEN_FOR_PARSER(OF);
                   }

{reserved_begin}   {
                     generalProcessing();
                     /*printToken("BEGIN");*/
                     printToken("KWBEGIN");
                     GET_TOKEN_FOR_PARSER(KWBEGIN);
                   }
{reserved_end}     {
                     generalProcessing();
                     printToken("END");
                     GET_TOKEN_FOR_PARSER(END);
                   }

{reserved_read}    {
                     generalProcessing();
                     printToken("READ");
                     GET_TOKEN_FOR_PARSER(READ);
                   }
{reserved_write}   {
                     generalProcessing();
                     printToken("WRITE");
                     GET_TOKEN_FOR_PARSER(WRITE);
                   }
{reserved_writeln} {
                     generalProcessing();
                     printToken("WRITELN");
                     GET_TOKEN_FOR_PARSER(WRITELN);
                   }

{reserved_if}      {
                     generalProcessing();
                     printToken("IF");
                     GET_TOKEN_FOR_PARSER(IF);
                   }
{reserved_then}    {
                     generalProcessing();
                     printToken("THEN");
                     GET_TOKEN_FOR_PARSER(THEN);
                   }
{reserved_else}    {
                     generalProcessing();
                     printToken("ELSE");
                     GET_TOKEN_FOR_PARSER(ELSE);
                   }

{reserved_while}   {
                     generalProcessing();
                     printToken("WHILE");
                     GET_TOKEN_FOR_PARSER(WHILE);
                   }
{reserved_do}      {
                     generalProcessing();
                     printToken("DO");
                     GET_TOKEN_FOR_PARSER(DO);
                   }
{reserved_return}  {
                     generalProcessing();
                     printToken("RETURN");
                     GET_TOKEN_FOR_PARSER(RETURN);
                   }

{identifier}       {
                     generalProcessing();
                     printTokenString("ID", yytext);
                     GET_ID_TOKEN_FOR_PARSER(ID);
                   }

{literal_integer}  {
                     generalProcessing();
                     printTokenInt("LITINT", atoi(yytext));
                     GET_INTEGER_TOKEN_FOR_PARSER(LITINT);
                   }

{literal_real}     {
                     generalProcessing();
                     printTokenDouble("LITREAL", atof(yytext));
                     GET_REAL_TOKEN_FOR_PARSER(LITREAL);
                   }

{unclosed_string}  {
                     generalProcessing();
                     printErrorAndExit("Unclosed String");
                   }
{literal_string}   {
                     generalProcessing();
                     printProcessTokenLiteralString("LITSTRING",
                                                    yytext);
                     GET_STRING_TOKEN_FOR_PARSER(LITSTRING);
                   }

{operator_not}     {
                     generalProcessing();
                     printToken("NOT");
                     GET_TOKEN_FOR_PARSER(NOT);
                   }
{operator_mul}     {
                     generalProcessing();
                     printToken("MUL");
                     GET_TOKEN_FOR_PARSER(MUL);
                   }
{operator_div}     {
                     generalProcessing();
                     printToken("DIV");
                     GET_TOKEN_FOR_PARSER(DIV);
                   }
{operator_mod}     {
                     generalProcessing();
                     printToken("MOD");
                     GET_TOKEN_FOR_PARSER(MOD);
                   }
{operator_plus}    {
                     generalProcessing();
                     printToken("PLUS");
                     GET_TOKEN_FOR_PARSER(PLUS);
                   }
{operator_minus}   {
                     generalProcessing();
                     printToken("MINUS");
                     GET_TOKEN_FOR_PARSER(MINUS);
                   }
{operator_lt}      {
                     generalProcessing();
                     printToken("LT");
                     GET_TOKEN_FOR_PARSER(LT);
                   }
{operator_gt}      {
                     generalProcessing();
                     printToken("GT");
                     GET_TOKEN_FOR_PARSER(GT);
                   }
{operator_eq}      {
                     generalProcessing();
                     printToken("EQ");
                     GET_TOKEN_FOR_PARSER(EQ);
                   }
{operator_lbracket} {
                     generalProcessing();
                     printToken("LBRACKET");
                     GET_TOKEN_FOR_PARSER(LBRACKET);
                   }
{operator_rlbracket} {
                     generalProcessing();
                     printToken("RBRACKET");
                     GET_TOKEN_FOR_PARSER(RBRACKET);
                   }
{operator_lparen}  {
                     generalProcessing();
                     printToken("LPAREN");
                     GET_TOKEN_FOR_PARSER(LPAREN);
                   }
{operator_rparen}  {
                     generalProcessing();
                     printToken("RPAREN");
                     GET_TOKEN_FOR_PARSER(RPAREN);
                   }
{operator_colon}   {
                     generalProcessing();
                     printToken("COLON");
                     GET_TOKEN_FOR_PARSER(COLON);
                   }
{operator_semi}    {
                     generalProcessing();
                     printToken("SEMI");
                     GET_TOKEN_FOR_PARSER(SEMI);
                   }
{operator_comma}   {
                     generalProcessing();
                     printToken("COMMA");
                     GET_TOKEN_FOR_PARSER(COMMA);
                   }
{operator_neq}     {
                     generalProcessing();
                     printToken("NEQ");
                     GET_TOKEN_FOR_PARSER(NEQ);
                   }
{operator_lte}     {
                     generalProcessing();
                     printToken("LTE");
                     GET_TOKEN_FOR_PARSER(LTE);
                   }
{operator_gte}     {
                     generalProcessing();
                     printToken("GTE");
                     GET_TOKEN_FOR_PARSER(GTE);
                   }
{operator_or}      {
                     generalProcessing();
                     printToken("OR");
                     GET_TOKEN_FOR_PARSER(OR);
                   }
{operator_and}     {
                     generalProcessing();
                     printToken("AND");
                     GET_TOKEN_FOR_PARSER(AND);
                   }
{operator_assign}  {
                     generalProcessing();
                     printToken("ASSIGN");
                     GET_TOKEN_FOR_PARSER(ASSIGN);
                   }
{operator_subrange} {
                     generalProcessing();
                     printToken("SUBRANGE");
                     GET_TOKEN_FOR_PARSER(SUBRANGE);
                   }

{white_space}      {
                     generalProcessing();
                   }

{begin_comment}    {
                     generalProcessing();
                     debugPrintInt("DEBUG: {begin_comment}: "
                                   "countCommentsNested(BEFORE)=",
                                   countCommentsNested);
                     countCommentsNested = 1;
                     debugPrintInt("DEBUG: {begin_comment}: "
                                   "countCommentsNested(AFTER)=",
                                   countCommentsNested);
                     lineNumberCommentBegin = glex_LineNumber;
                     BEGIN(COMMENT);
                   }

{end_comment}      {
                     generalProcessing();
                     printErrorCommentAndExit("Unclosed Comment");
                   }

{new_line}         {
                     generalProcessing();
                     newlineProcessing();
                   }

.                  {
                     generalProcessing();
                     if (yytext[0] == '\"') {
                       printErrorCommentAndExit("Unclosed Comment");
                     } else {
                       printErrorSymbolAndExit("Unknown Symbol", yytext);
                     }
                   }

<COMMENT>{begin_comment} {
                     generalProcessing();
                     debugPrintInt("DEBUG: <COMMENT>{begin_comment}: "
                                   "countCommentsNested(BEFORE)=",
                                   countCommentsNested);
                     if (countCommentsNested < 1) {
                       printErrorAndExit("internal logic error -- in "
                                         "processing comments");
                     }
                     countCommentsNested++;
                     debugPrintInt("DEBUG: <COMMENT>{begin_comment}: "
                                   "countCommentsNested(AFTER)=",
                                   countCommentsNested);
                   }
<COMMENT>{end_comment} {
                     generalProcessing();
                     debugPrintInt("DEBUG: <COMMENT>{end_comment}: "
                                   "countCommentsNested(BEFORE)=",
                                   countCommentsNested);
                     countCommentsNested--;
                     debugPrintInt("DEBUG: <COMMENT>{end_comment}: "
                                   "countCommentsNested(AFTER)=",
                                   countCommentsNested);
                     if (countCommentsNested == 0) {
                       BEGIN(INITIAL);
                     } else if (countCommentsNested < 0) {
                       printErrorCommentAndExit("Unclosed Comment");
                     }
                   }
<COMMENT>{new_line} {
                     generalProcessing();
                     debugPrint("DEBUG: <COMMENT>{new_line} called.");
                     newlineProcessing();
                   }
<COMMENT>.         {
                     generalProcessing();
                     debugPrintString("DEBUG: <COMMENT>.: "
                                      "yytext=",
                                      yytext);
                   }

%%

/******************************************************************************
///////////////////////////////////////////////////////////////////////////////
// user subroutine section
///////////////////////////////////////////////////////////////////////////////
******************************************************************************/


/******************************************************************************
///////////////////////////////////////////////////////////////////////////////
// yywrap()
///////////////////////////////////////////////////////////////////////////////
******************************************************************************/

#ifdef yywrap
  #undef yywrap
#endif
int yywrap() {
  if (countCommentsNested != 0) {
    printErrorCommentAndExit("Unclosed Comment");
  }
  return 1;
}

/******************************************************************************
///////////////////////////////////////////////////////////////////////////////
// the main program
///////////////////////////////////////////////////////////////////////////////
******************************************************************************/

/******************************************************************************
///////////////////////////////////////////////////////////////////////////////
// we may ignore to define the main program for lexer
///////////////////////////////////////////////////////////////////////////////
******************************************************************************/

/******************************************************************************
main() {
  yylex();
}
******************************************************************************/

/******************************************************************************
*******************************************************************************
** Following is not used at this moment.
*******************************************************************************
******************************************************************************/


/*

*/
