/******************************************************************************
// -*- YACC	-*-	 //	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 22 12:42:53 2003--DATERL
// Finalized date: DATEFL----DATEFR
// To do List:
// Change List:
// Notes:
// Functionalities should be implemented:
//
///////////////////////////////////////////////////////////////////////////////
******************************************************************************/

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

/*****************************************************************************
 /////////////////////////////////////////////////////////////////////////////
 //	datatype definitions
 /////////////////////////////////////////////////////////////////////////////
 *****************************************************************************/

%{
  #include <stdlib.h>
  #include "ast.h"
  #include "traverse.h"
  #include "verify.h"

  Program *myProgram = NULL;

  int yylex (void);
  void yyerror (char const *);
  extern int glex_LineNumber;

%}

%{
  #define ADD_TO_END(WHAT_TYPE,	DEST, SRC) \
  {	\
	WHAT_TYPE *ptr;	\
	ptr	= DEST;	\
	while (ptr->next) {	\
	  ptr =	ptr->next; \
	} \
	ptr->next =	SRC; \
  }

  #define CREATE_NEW(DEST, WHAT_TYPE) { \
	DEST = ((WHAT_TYPE	*) calloc(sizeof(WHAT_TYPE), 1)); \
      DEST->_lineno = glex_LineNumber; \
  }
%}

%union {
  int	 integerValue;
  double doubleValue;
  char* stringValue;
  DecList* DecListPtr;
  Dec* DecPtr;
  VarDec* VarDecPtr;
  ConstDec* ConstDecPtr;
  IDList* IDListPtr;
  DeclType* DeclTypePtr;
  ArrayDataType* ArrayDataTypePtr;
  BoundList* BoundListPtr;
  BoundInfo* BoundInfoPtr;
  Bound* BoundPtr;
  SubList* SubListPtr;
  Sub* SubPtr;
  SubHeading* SubHeadingPtr;
  SubParams* SubParamsPtr;
  ArgSetList* ArgSetListPtr;
  StmBlock* StmBlockPtr;
  StmList* StmListPtr;
  Stm* StmPtr;
  ExpList* ExpListPtr;
  Exp* ExpPtr;
  VarExp* VarExpPtr;
  LitExp* LitExpPtr;
  Program* ProgramPtr;
  SubCallExp *SubCallExpPtr;
  ID_Type *IDValuePtr;

}



%{

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

	#include <stdio.h>
	#include <string.h>
	/*
	#include "src3.tab.h"
	*/

	/*************************************************************************
	 /////////////////////////////////////////////////////////////////////////
	 //	extern variables
	 /////////////////////////////////////////////////////////////////////////
	 *************************************************************************/

	extern char* yytext;
	extern int glex_LineNumber;
	extern YYSTYPE yylval;

	extern int GLOBAL_progstart;
	extern char *GLOBAL_progname;

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

	#if	!defined(YACC_TO_PRINT_PARSER_DEBUG_MESSAGE)
		 #define YACC_TO_PRINT_PARSER_DEBUG_MESSAGE	0
	#endif
	#if	!defined(YACC_TO_PRINT_PARSER_ERROR_MESSAGE)
		 #define YACC_TO_PRINT_PARSER_ERROR_MESSAGE	1
	#endif
	#if	!defined(YACC_TO_PRINT_PARSER_OUTPUT)
		 #define YACC_TO_PRINT_PARSER_OUTPUT 0
	#endif

	/**************************************************************************
	///////////////////////////////////////////////////////////////////////////
	// control variables
	///////////////////////////////////////////////////////////////////////////
	**************************************************************************/
	int	yaccToPrintParserDebugMessage =	YACC_TO_PRINT_PARSER_DEBUG_MESSAGE;
	int	yaccToPrintParserErrorMessage =	YACC_TO_PRINT_PARSER_ERROR_MESSAGE;
	int	yaccToPrintParserOutput	= YACC_TO_PRINT_PARSER_OUTPUT;

	/**************************************************************************
	///////////////////////////////////////////////////////////////////////////
	// auxiliary subroutines
	///////////////////////////////////////////////////////////////////////////
	**************************************************************************/
	void parserDebugPrintExtra(int anInteger,
							   const char* message,
							   const char* extra_message) {
	  if (yaccToPrintParserDebugMessage) {
		printf("Parser DEBUG output: %s[%s]	%d",
			   message,
			   extra_message,
			   anInteger);
		printf("\n");
		/*printf("%d: %s at	'%s'\n", glex_LineNumber, msg, yytext);*/
	  }
	}
	void parserDebugPrint(const	char* message) {
	  if (yaccToPrintParserDebugMessage) {
		printf("Parser DEBUG output: %s", message);
		printf("\n");
	  }
	}
	void parserDebugPrintInt(const char* message, int number) {
	  if (yaccToPrintParserDebugMessage) {
		printf("Parser DEBUG output: %s[%d]", message, number);
		printf("\n");
	  }
	}
	void parserDebugPrintDefaultInteger(const char*	message) {
	  parserDebugPrintInt(message, yylval.integerValue);
	}
	void parserDebugPrintUnsignedInt(const char* message,
									 unsigned int number) {
	  if (yaccToPrintParserDebugMessage) {
		printf("Parser DEBUG output: %s[%u]", message, number);
		printf("\n");
	  }
	}
	void parserDebugPrintDefaultUnsignedInteger(const char*	message) {	  
	  parserDebugPrintUnsignedInt(message, yylval.integerValue);
	}
	void parserDebugPrintReal(const	char* message, double number) {
	  if (yaccToPrintParserDebugMessage) {
		printf("Parser DEBUG output: %s[%f]", message, number);
		printf("\n");
	  }
	}
	void parserDebugPrintDefaultReal(const char* message) {
	  parserDebugPrintReal(message,	yylval.doubleValue);
	}
	void parserDebugPrintString(const char*	message, const char* inString) {
	  if (yaccToPrintParserDebugMessage) {
		printf("Parser DEBUG output: %s[%s]", message, inString);
		printf("\n");
	  }
	}
	void parserDebugPrintDefaultString(const char* message)	{
	  parserDebugPrintString(message, yylval.stringValue);
	}

%}

/*****************************************************************************
 /////////////////////////////////////////////////////////////////////////////
 //	token definitions
 /////////////////////////////////////////////////////////////////////////////
 *****************************************************************************/

%token VAR INT REAL	STRING BOOL
%token ARRAY OF
%token KWBEGIN END
%token READ	WRITE WRITELN
%token IF THEN ELSE	WHILE DO RETURN
%token<IDValuePtr>	ID 
%token<integerValue> LITINT
%token<doubleValue>	LITREAL
%token<stringValue>	LITSTRING
%token NOT
%token LT GT EQ
%token MUL DIV MOD PLUS	MINUS
%token LBRACKET	RBRACKET LPAREN	RPAREN
%token COLON SEMI COMMA
%token NEQ LTE GTE
%token OR AND
%token ASSIGN SUBRANGE

%type <integerValue> basicType literalInteger
%type <doubleValue> literalReal
%type <stringValue> literalString
%type <IDValuePtr> programHeading
%type <ProgramPtr> startRule programBody 
%type <DecListPtr> nonEmptyDeclarationList declarationList 
%type <DecPtr> declaration 
%type <VarDecPtr> idsDeclaration variableDeclaration
%type <ConstDecPtr> constantDeclaration
%type <IDListPtr> idList
%type <DeclTypePtr> declType
%type <ArrayDataTypePtr> arrayType
%type <BoundListPtr> rangeInformation
%type <BoundInfoPtr> range
%type <BoundPtr> rangeObject
%type <SubListPtr> subroutineDeclarationList nonEmptySubroutineDeclarationList
%type <SubPtr> subroutineDeclaration
%type <SubHeadingPtr> subroutineHeading
%type <SubParamsPtr> argumentSet
%type <DeclTypePtr> returnDeclaration 
%type <ArgSetListPtr> argumentList
%type <StmBlockPtr> subroutineBody statementBlock statementBody
%type <StmListPtr> statementList nonEmptyStatementList
%type <StmPtr> statement
%type <ExpPtr> expression
%type <ExpListPtr> expressionList nonEmptyExpressionList
%type <SubCallExpPtr> functionCall
%type <VarExpPtr> variable
%type <LitExpPtr> literal



%left COMMA
%nonassoc ASSIGN
%left OR
%left AND
%left EQ NEQ LT	GT LTE GTE
%left PLUS MINUS
%left MUL DIV MOD
%nonassoc NOT
%nonassoc LBRACKET RBRACKET	LPAREN RPAREN

%start startRule

/*****************************************************************************
 /////////////////////////////////////////////////////////////////////////////
 //	rules section
 /////////////////////////////////////////////////////////////////////////////
 *****************************************************************************/

%%

/*****************************************************************************
 *****************************************************************************/

startRule:
	programHeading programBody END ID {
	  parserDebugPrintDefaultString("In	startRule");
	  $$ = $2;
	  GLOBAL_progname = $4->id; 
	  memcpy(&$$->idt, $1, sizeof(ID_Type));
	  myProgram = $$;
	  memcpy(&$$->end_idt, $4, sizeof(ID_Type));
	}
  ;

programBody:
	declarationList	subroutineDeclarationList statementBlock SEMI {
	  parserDebugPrint("In programBody");

	  CREATE_NEW($$, Program);
	  $$->decList =	$1;
	  $$->subList =	$2;
	  $$->stmBlock = $3;
	}
  ;

programHeading:
	ID SEMI	{
	  parserDebugPrintDefaultString("In	programHeading");
	  GLOBAL_progstart = glex_LineNumber; 
	  $$ = $1;
	}
  ;

/*****************************************************************************
 *****************************************************************************/

declarationList:
	/* A declarationList can be	empty */ {
	  parserDebugPrint("In declarationList:empty");

	  $$ = NULL;
	}
  |	nonEmptyDeclarationList	{
	  parserDebugPrint("In declarationList:nonEmptyDeclarationList");

	  $$ = $1;
	}
  ;

nonEmptyDeclarationList:
	declaration	{
	  parserDebugPrint("In nonEmptyDeclarationList:declaration");

	  CREATE_NEW($$, DecList);
	  $$->dec =	$1;
	  $$->next = NULL;
	}
  |	nonEmptyDeclarationList	SEMI declaration {
    DecList *e;
	  parserDebugPrint("In nonEmptyDeclarationList:nonEmptyDeclarationList");

	  CREATE_NEW(e, DecList);
	  e->dec = $3;
	  e->next =	NULL;
	  $$ = $1;
	  ADD_TO_END(DecList, $$, e);
	}
  ;

declaration:
	variableDeclaration	{
	  parserDebugPrint("In declaration:variableDeclaration");

	  CREATE_NEW($$, Dec);
	  $$->decType =	VAR_DEC;
	  $$->varDec = $1;
	  $$->constDec = NULL;
	}
  |	constantDeclaration	{
	  parserDebugPrint("In declaration:constantDeclaration");

	  CREATE_NEW($$, Dec);
	  $$->decType =	CONST_DEC;
	  $$->varDec = NULL;
	  $$->constDec = $1;
	}
  ;

variableDeclaration:
	VAR	idsDeclaration {
	  parserDebugPrint("In variableDeclaration");

	  $$ = $2;
	}
  ;

idsDeclaration:
	idList COLON declType {
	  parserDebugPrint("In idsDeclaration");

	  CREATE_NEW($$, VarDec);
	  $$->idList = $1;
	  $$->declType = $3;
	}
  ;

constantDeclaration:
	VAR	idList COLON literal {
	  parserDebugPrint("In constantDeclaration:literal");

	  CREATE_NEW($$, ConstDec);
	  $$->idList = $2;
	  $$->ConstDecType = CONST_LIT;
	  $$->litExp = $4;
	}
  |	VAR	idList COLON ID	{
	  parserDebugPrintDefaultString("In	constantDeclaration:ID");

	  CREATE_NEW($$, ConstDec);
	  $$->idList = $2;
	  $$->ConstDecType = CONST_ID;
	  memcpy(&$$->idt, $4, sizeof(ID_Type));
	}
  ;

idList:
	ID {
	  parserDebugPrintDefaultString("In	idList:ID");
	  
	  CREATE_NEW($$, IDList);
	  memcpy(&$$->idt, $1, sizeof(ID_Type));
	  $$->next = NULL;
	}
  |	idList COMMA ID	{
	  IDList *e;

	  parserDebugPrintDefaultString("In	idList:idList");

	  CREATE_NEW(e, IDList);
	  memcpy(&e->idt, $3, sizeof(ID_Type));
	  e->next =	NULL;

	  $$ = $1;

	  ADD_TO_END(IDList, $$, e);
	}
  ;

/*****************************************************************************
 *****************************************************************************/

declType:
	arrayType {
	  parserDebugPrint("In type:arrayType");

	  CREATE_NEW($$, DeclType);
	  $$->vardecType = ARRAY_VAR;
	  $$->arrayDataType	= $1;
	}
  |	basicType {
	  parserDebugPrint("In type:basicType");

	  CREATE_NEW($$, DeclType);
	  $$->vardecType = SINGLE_VAR;
	  $$->basicDataType	= $1;
	}
  ;

arrayType:
	ARRAY LBRACKET rangeInformation	RBRACKET OF	basicType {
	  parserDebugPrint("In arrayType");

	  CREATE_NEW($$, ArrayDataType);
	  $$->Type = $6;
	  $$->boundList	= $3;
	}
  ;

basicType:
	INT	{
	  parserDebugPrint("In basicType:INT");

	  $$ = TYPE_int;
	}
  |	REAL {
	  parserDebugPrint("In basicType:REAL");

	  $$ = TYPE_real;
	}
  |	STRING {
	  parserDebugPrint("In basicType:STRING");

	  $$ = TYPE_string;
	}
  |	BOOL {
	  parserDebugPrint("In basicType:BOOL");

	  $$ = TYPE_bool;
	}
  ;

rangeInformation:
	range {
	  parserDebugPrint("In rangeInformation:range");

	  CREATE_NEW($$, BoundList);
	  $$->next = NULL;
	  $$->bound	= $1;
	}
  |	rangeInformation COMMA range {
	  BoundList	*e;
	  parserDebugPrint("In rangeInformation:COMMA");

	  CREATE_NEW(e, BoundList);
	  e->bound = $3;
	  e->next =	NULL;
	  $$ = $1;
	  ADD_TO_END(BoundList,	$$,	e);
	}
  ;

range:
	rangeObject	{
	  parserDebugPrint("In range:rangeObject");

	  CREATE_NEW($$, BoundInfo);
	  CREATE_NEW($$->lower_bound, Bound);
	  $$->lower_bound->Type	= BOUND_VAL;
	  $$->lower_bound->Value = 0;
	  $$->upper_bound =	$1;
	  $$->upper_bound->partial = 1;
	  if ($$->upper_bound->Type == BOUND_VAL) {
	    $$->upper_bound->Value--;
	  }
	}
  |	rangeObject	SUBRANGE rangeObject {
	  parserDebugPrint("In range:SUBRANGE");

	  CREATE_NEW($$, BoundInfo);
	  $$->lower_bound =	$1;
	  $$->upper_bound =	$3;
	}
  ;

rangeObject:
	ID {
	  parserDebugPrint("In rangeObject:variable");

	  CREATE_NEW($$, Bound);
	  $$->Type = BOUND_ID;
	  memcpy(&$$->idt, $1, sizeof(ID_Type));
	}
  |	literalInteger {
	  parserDebugPrint("In rangeObject:literalInteger");

	  CREATE_NEW($$, Bound);
	  $$->Type = BOUND_VAL;
	  $$->Value	= $1;
	}
  ;

/*****************************************************************************
 *****************************************************************************/

subroutineDeclarationList:
	/* A subroutineList	can	be empty */	{
	  parserDebugPrint("In subroutineDeclarationList:empty");

	  $$ = NULL;
	}
  |	nonEmptySubroutineDeclarationList {
	  parserDebugPrint("In subroutineDeclarationList:"
					   "nonEmptySubroutineDeclarationList");

	  $$ = $1;
	}
  ;

nonEmptySubroutineDeclarationList:
	subroutineDeclaration {
	  parserDebugPrint("In nonEmptySubroutineDeclarationList:"
					   "subroutineDeclaration");

	  CREATE_NEW($$, SubList);
	  $$->subroutine = $1;
	  $$->next = NULL;
	}
  |	nonEmptySubroutineDeclarationList subroutineDeclaration	{
	  SubList *e;

	  parserDebugPrint("In nonEmptySubroutineDeclarationList:"
					   "nonEmptySubroutineDeclarationList");

	  CREATE_NEW(e, SubList);
	  e->subroutine	= $2;
	  e->next =	NULL;
	  $$ = $1;
	  ADD_TO_END(SubList, $$, e);
	}
  ;

subroutineDeclaration:
	subroutineHeading subroutineBody END ID	{
	  parserDebugPrintDefaultString("In	subroutineDeclaration");
	  CREATE_NEW($$, Sub);
	  $$->heading =	$1;
	  $$->body = $2;
	  memcpy(&$$->end_idt, $4, sizeof(ID_Type));
	}
  ;

subroutineHeading:
	ID LPAREN argumentSet RPAREN returnDeclaration SEMI	{
	  parserDebugPrintDefaultString("In	subroutineHeading");
	  CREATE_NEW($$, SubHeading);
	  memcpy(&$$->idt, $1, sizeof(ID_Type));
	  $$->subParams	= $3;
	  $$->return_type =	$5;
	}
  ;

argumentSet:
	/* An argumentSet can be empty */ {		
	  parserDebugPrint("In argumentSet:empty");

	  CREATE_NEW($$, SubParams);
	  $$->val_params = NULL;
	  $$->ref_params = NULL;
	}
  |	argumentList {
	  parserDebugPrint("In argumentSet:argumentList");

	  CREATE_NEW($$, SubParams);
	  $$->val_params = $1;
	  $$->ref_params = NULL;
	}
  |	VAR	argumentList {
	  parserDebugPrint("In argumentSet:VAR");

	  CREATE_NEW($$, SubParams);
	  $$->val_params = NULL;
	  $$->ref_params = $2;
	}
  |	argumentList SEMI VAR argumentList {
	  parserDebugPrint("In argumentSet:SEMI	VAR");

	  CREATE_NEW($$, SubParams);
	  $$->val_params = $1;
	  $$->ref_params = $4;
	}
  ;

returnDeclaration:
	COLON declType {
	  parserDebugPrint("In returnDeclaration:COLON");

	  $$ = $2;
	}
  ;

argumentList:
	idsDeclaration {
	  parserDebugPrint("In argumentList:idsDeclaration");

	  CREATE_NEW($$, ArgSetList);
	  $$->argset = $1;
	  $$->next = NULL;
	}
  |	argumentList SEMI idsDeclaration {
	  ArgSetList *e;

	  parserDebugPrint("In argumentList:argumentList");

	  CREATE_NEW(e, ArgSetList);
	  e->argset	= $3;
	  e->next =	NULL;
	  $$ = $1;
	  ADD_TO_END(ArgSetList, $$, e);
	}
  ;

subroutineBody:
	statementBlock SEMI	{
	  parserDebugPrint("In subroutineBody");

	  $$ = $1;
	}
  ;

/*****************************************************************************
 *****************************************************************************/

statementBlock:
	KWBEGIN	statementBody END {
	  parserDebugPrint("In statementBlock");

	  $$ = $2;
	}
  ;

/* The following rule will cause shift/reduce conflicts, thus we need to
   rewrite it as the version following it.
statementBody:
	declarationList	subroutineDeclarationList statementList	{
	  parserDebugPrint("In statementBody:default");

	}
  ;
*/

statementBody: /* As the commented implementation above,
				  if we	only allow one rule	-- the first one --	as
				  declarationList subroutineDeclarationList	statementList
				  then it will cause an	shift/reduce error.	Therefore,
				  we split the rule	into two in	order to avoid it.
			   */
	declarationList	statementList {
	  parserDebugPrint("In statementBody:default");

	  CREATE_NEW($$, StmBlock);
	  $$->decList =	$1;
	  $$->subList =	NULL;
	  $$->stmList =	$2;
	}
  |	declarationList	nonEmptySubroutineDeclarationList statementList	{
	  parserDebugPrint("In statementBody:"
					   "nonEmptySubroutineDeclarationList");

	  CREATE_NEW($$, StmBlock);
	  $$->decList =	$1;
	  $$->subList =	$2;
	  $$->stmList =	$3;
	}
  ;

statementList:
	/* A statementList can be empty	*/ {
	  parserDebugPrint("In statementList:empty");

	  $$ = NULL;
	}
  |	nonEmptyStatementList {
	  parserDebugPrint("In statementList:nonEmptyStatementList");

	  $$ = $1;
	}
  ;

nonEmptyStatementList:
	statement {
	  parserDebugPrint("In nonEmptyStatementList:statement");

	  CREATE_NEW($$, StmList);
	  $$->stm =	$1;
	  $$->next = NULL;
	}
  |	nonEmptyStatementList statement	{
	  StmList *e;
	  parserDebugPrint("In nonEmptyStatementList:nonEmptyStatementList");

	  CREATE_NEW(e, StmList);
	  e->stm = $2;
	  e->next =	NULL;

	  $$ = $1;
	  ADD_TO_END(StmList, $$, e);
	}
  ;

statement:
	variable ASSIGN	expression SEMI	{
	  parserDebugPrint("In statement:ASSIGN");

	  CREATE_NEW($$, Stm);
	  parserDebugPrint("OK1.\n");
	  $$->Type = STM_ASSIGN;
	  CREATE_NEW($$->assignStm, AssignStm);
	  $$->assignStm->var =	$1;
	  $$->assignStm->expr = $3;

	  parserDebugPrint("OK2.\n");
	}
  /* If	we allow a functionCall	to be an allowable statment, then it causes
	 a reduce/reduce conflict with subroutineHeading
  |	functionCall SEMI {
	  parserDebugPrint("In statement:functionCall");

	}
  */
  |	READ variable SEMI {
	  parserDebugPrint("In statement:READ");

	  CREATE_NEW($$, Stm);
	  $$->Type = STM_READ;
	  CREATE_NEW($$->read, ReadStm);
	  $$->read->var =	$2;
	}
  |	WRITE expressionList SEMI {
	  parserDebugPrint("In statement:WRITE");

	  CREATE_NEW($$, Stm);
	  $$->Type = STM_WRITE;
	  CREATE_NEW($$->write, WriteStm);
	  $$->write->list = $2;
	}
  |	IF expression THEN statementList END IF	SEMI {
	  parserDebugPrint("In statement:IF");

	  CREATE_NEW($$, Stm);
	  $$->Type = STM_IF_THEN;
	  CREATE_NEW($$->if_then, If_Then_Stm);
	  $$->if_then->condition	= $2;
	  $$->if_then->then_clause =	$4;
	}
  |	IF expression THEN statementList ELSE statementList	END	IF SEMI	{
	  parserDebugPrint("In statement:IFELSE");

	  CREATE_NEW($$, Stm);
	  $$->Type = STM_IF_THEN_ELSE;
	  CREATE_NEW($$->if_then_else, If_Then_Else_Stm);
	  $$->if_then_else->condition	= $2;
	  $$->if_then_else->then_clause =	$4;
	  $$->if_then_else->else_clause =	$6;
	}
  |	WHILE expression DO	statementList END WHILE	SEMI {
	  parserDebugPrint("In statement:WHILE");

	  CREATE_NEW($$, Stm);
	  $$->Type = STM_WHILE;
	  CREATE_NEW($$->whileStm, WhileStm);
	  $$->whileStm->condition	= $2;
	  $$->whileStm->body = $4;
	}
  |	RETURN expression SEMI {
	  parserDebugPrint("In statement:RETURN");

	  CREATE_NEW($$, Stm);
	  $$->Type = STM_RETURN;
	  CREATE_NEW($$->returnStm, ReturnStm);
	  $$->returnStm->expr = $2;
	}
  |	statementBlock SEMI	{
	  parserDebugPrint("In statement:statementBlock");

	  CREATE_NEW($$, Stm);
	  $$->Type = STM_BLOCK;
	  $$->stmBlock = $1;
	}
  ;

/*****************************************************************************
 *****************************************************************************/

expressionList:
	/* An expressionList can be	empty */ {
	  parserDebugPrint("In expressionList:empty");

	  $$ = NULL;
	}
  |	nonEmptyExpressionList {
	  parserDebugPrint("In expressionList:nonEmptyExpressionList");

	  $$ = $1;
	}
  ;

nonEmptyExpressionList:
	expression {
	  parserDebugPrint("In nonEmptyExpressionList:expression");

	  CREATE_NEW($$, ExpList);
	  $$->exp =	$1;
	  $$->next = NULL;
	}
  |	nonEmptyExpressionList COMMA expression	{
	  ExpList *e;
	  parserDebugPrint("In nonEmptyExpressionList:COMMA");


	  CREATE_NEW(e, ExpList);
	  e->exp = $3;
	  e->next =	NULL;

	  $$ = $1;
	  ADD_TO_END(ExpList, $$, e);
	}
  ;

expression:	/* An expression covers	all	kinds of expressions and in	SRC3
			   the most	comprehensive one is the logicalExpression */
	expression AND expression {
	  parserDebugPrint("In expression:AND");

	  CREATE_NEW($$, Exp);
	  $$->Type = LOGIC_EXP;
	  CREATE_NEW($$->logicExp, LogicExp);
	  $$->logicExp->x =	$1;
	  $$->logicExp->y =	$3;
	  $$->logicExp->op = _AND;
	}
  |	expression OR expression {
	  parserDebugPrint("In expression:OR");

	  CREATE_NEW($$, Exp);
	  $$->Type = LOGIC_EXP;	
	  CREATE_NEW($$->logicExp, LogicExp);
	  $$->logicExp->x =	$1;
	  $$->logicExp->y =	$3;
	  $$->logicExp->op = _OR;
	}
  |	NOT	expression {
	  parserDebugPrint("In expression:NOT");

	  CREATE_NEW($$, Exp);
	  $$->Type = LOGIC_EXP;
	  CREATE_NEW($$->logicExp, LogicExp);
	  $$->logicExp->x	= $2;
	  $$->logicExp->op = _NOT;
	}
  |	LPAREN expression RPAREN {
	  parserDebugPrint("In expression:LRPAREN");

	  CREATE_NEW($$, Exp);
	  $$->Type = NESTED_EXP;
	  $$->nestedExp	= $2;
	}
  |	expression GT expression {
	  parserDebugPrint("In expression:GT");

	  CREATE_NEW($$, Exp);
	  $$->Type = REL_EXP;
	  CREATE_NEW($$->relExp, RelExp);
	  $$->relExp->x	= $1;
	  $$->relExp->y	= $3;
	  $$->relExp->op = _GT;
	}
  |	expression GTE expression {
	  parserDebugPrint("In expression:GTE");

	  CREATE_NEW($$, Exp);
	  $$->Type = REL_EXP;
	  CREATE_NEW($$->relExp, RelExp);
	  $$->relExp->x	= $1;
	  $$->relExp->y	= $3;
	  $$->relExp->op = _GTE;
	}
  |	expression LT expression {
	  parserDebugPrint("In expression:LT");

	  CREATE_NEW($$, Exp);
	  $$->Type = REL_EXP;
	  CREATE_NEW($$->relExp, RelExp);
	  $$->relExp->x	= $1;
	  $$->relExp->y	= $3;
	  $$->relExp->op = _LT;
	}
  |	expression LTE expression {
	  parserDebugPrint("In expression:LTE");

	  CREATE_NEW($$, Exp);
	  $$->Type = REL_EXP;
	  CREATE_NEW($$->relExp, RelExp);
	  $$->relExp->x	= $1;
	  $$->relExp->y	= $3;
	  $$->relExp->op = _LTE;
	}
  |	expression EQ expression {
	  parserDebugPrint("In expression:EQ");

	  CREATE_NEW($$, Exp);
	  $$->Type = REL_EXP;
	  CREATE_NEW($$->relExp, RelExp);
	  $$->relExp->x	= $1;
	  $$->relExp->y	= $3;
	  $$->relExp->op = _EQ;
	}
  |	expression NEQ expression {
	  parserDebugPrint("In expression:NEQ");

	  CREATE_NEW($$, Exp);
	  $$->Type = REL_EXP;
	  CREATE_NEW($$->relExp, RelExp);
	  $$->relExp->x	= $1;
	  $$->relExp->y	= $3;
	  $$->relExp->op = _NEQ;
	}
  |	expression PLUS	expression {
	  parserDebugPrint("In expression:PLUS");

	  CREATE_NEW($$, Exp);
	  $$->Type = ARITH_EXP;
	  CREATE_NEW($$->arithExp, ArithExp);
	  $$->arithExp->x =	$1;
	  $$->arithExp->y =	$3;
	  $$->arithExp->op = _PLUS;
	}
  |	expression MINUS expression	{
	  parserDebugPrint("In expression:MINUS");

	  CREATE_NEW($$, Exp);
	  $$->Type = ARITH_EXP;
	  CREATE_NEW($$->arithExp, ArithExp);
	  $$->arithExp->x =	$1;
	  $$->arithExp->y =	$3;
	  $$->arithExp->op = _MINUS;
	}
  |	expression MUL expression {
	  parserDebugPrint("In expression:MUL");

	  CREATE_NEW($$, Exp);
	  $$->Type = ARITH_EXP;
	  CREATE_NEW($$->arithExp, ArithExp);
	  $$->arithExp->x =	$1;
	  $$->arithExp->y =	$3;
	  $$->arithExp->op = _MUL;
	}
  |	expression DIV expression {
	  parserDebugPrint("In expression:DIV");

	  CREATE_NEW($$, Exp);
	  $$->Type = ARITH_EXP;
	  CREATE_NEW($$->arithExp, ArithExp);
	  $$->arithExp->x =	$1;
	  $$->arithExp->y =	$3;
	  $$->arithExp->op = _DIV;
	}
  |	expression MOD expression {
	  parserDebugPrint("In expression:MOD");

	  CREATE_NEW($$, Exp);
	  $$->Type = ARITH_EXP;
	  CREATE_NEW($$->arithExp, ArithExp);
	  $$->arithExp->x =	$1;
	  $$->arithExp->y =	$3;
	  $$->arithExp->op = _REM;
	}
  |	functionCall {
	  parserDebugPrint("In expression:functionCall");

	  CREATE_NEW($$, Exp);
	  $$->Type = CALL_EXP;
	  $$->callExp =	$1;
	}
  |	variable {
	  parserDebugPrint("In operationObject:variable");

	  CREATE_NEW($$, Exp);
	  $$->Type = VAR_EXP;
	  $$->varExp = $1;
	}
  |	literal	{
	  parserDebugPrint("In operationObject:literal");

	  CREATE_NEW($$, Exp);
	  $$->Type = LIT_EXP;
	  $$->litExp = $1;
	}
  ;

functionCall:
	ID LPAREN expressionList RPAREN	{
	  parserDebugPrint("In functionCall");

	  CREATE_NEW($$, SubCallExp);
	  memcpy(&$$->idt, $1, sizeof(ID_Type));
	  $$->expList =	$3;
  }
  ;

variable:
	ID {
	  parserDebugPrintDefaultString("In	variable:ID");
	  CREATE_NEW($$, VarExp);
	  $$->Type = VAR_BASIC;
	  memcpy(&$$->idt, $1, sizeof(ID_Type));
	}
  |	ID LBRACKET	nonEmptyExpressionList RBRACKET	{
	  parserDebugPrint("In variable:ID LBRACKET	RBRACKET");

	  CREATE_NEW($$, VarExp);
	  $$->Type = VAR_ARRAY;
	  memcpy(&$$->idt, $1, sizeof(ID_Type));
	  $$->offsets =	$3;
	}
/*
  |	ID LBRACKET	nonEmptyOperationObjectList	RBRACKET {
	  parserDebugPrint("In variable:ID LBRACKET	RBRACKET");

	}
*/
  ;

/* This	rule was original designed for dereference array, but I	think
   it is too limited not to	allow expression for array dereferencing.
nonEmptyOperationObjectList:
	operationObject	{
	  parserDebugPrint("In nonEmptyOperationObjectList:operationObject");

	}
  |	nonEmptyOperationObjectList	COMMA operationObject {
	  parserDebugPrint("In nonEmptyOperationObjectList:"
					   "nonEmptyOperationObject");

	}
  ;
*/

literal:
	literalString {
	  parserDebugPrintDefaultString("In	literal:literalString");
	  CREATE_NEW($$, LitExp);
	  $$->Type = TYPE_string;
	  $$->litStr = $1;
	}
  |	literalInteger {
	  parserDebugPrint("In literalInteger:literalInteger");

	  CREATE_NEW($$, LitExp);
	  $$->Type = TYPE_int;
	  $$->litInt = $1;
	}
  |	literalReal	{
	  parserDebugPrint("In literalInteger:literalReal");

	  CREATE_NEW($$, LitExp);
	  $$->Type = TYPE_real;
	  $$->litReal =	$1;
	}
  ;

literalString:
	LITSTRING {
	  parserDebugPrintDefaultString("In	literalString");
	  $$ = strdup($1);
	}
  ;

literalInteger:
	LITINT {
	  parserDebugPrintDefaultInteger("In literalInteger:LITINT");
	  $$ = $1;
	}
  |	PLUS LITINT	{
	  parserDebugPrint("In literalInteger:PLUS LITINT");

	  $$ = $2;
	}
  |	MINUS LITINT {
	  parserDebugPrint("In literalInteger:MINUS	LITINT");

	  $$ = 0 - $2;
	}
  ;

literalReal:
	LITREAL	{
	  parserDebugPrintDefaultReal("In literalReal:LITREAL");
	  $$ = $1;
	}
  |	PLUS LITREAL {
	  parserDebugPrint("In literalReal:PLUS	LITREAL");

	  $$ = $2;
	}
  |	MINUS LITREAL {
	  parserDebugPrint("In literalReal:MINUS LITREAL");

	  $$ = 0 - $2;
	}
  ;

%%

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

void	yyerror(const char*	message) {
  parserDebugPrintExtra(glex_LineNumber, message, message);
  printf("Parse	Failed at line %d\n", glex_LineNumber);
  return ;
}

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

int main() {
  if (!yyparse()) {
    if (myProgram) {
	initVerify();
	traverse_Program(myProgram, "Program", 0);
    }
  }

  return 0;
}

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

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

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


/*
 */

