/* @(#)request.y	1.11	2/10/93 */
/*******************************************************************************

This code was written and designed by 
Andrew Gene HALL of I.N. Services Pty. Ltd., Scarborough WA, Australia,
for the 
University of Western Australia, Crawley WA, Australia.

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

%{
#include "diagmesg.h"
#include "sf_space.h"
#include "request_space.h"

/* local variables */
char		*request_string = NULL;
Request_Seq	**next_req = NULL;
extern Data_Item	*current_di;
int             request_line_count = 1;
char		*last_request_token = NULL;

#include "request_scanner.c"
/* request_scanner defines malloc so 
 * its important that it comes in before utilitys
 */
#include "utilitys.h"
#include "sf_search.h"
#include "operators.h"

/* /usr/include/string.h */
extern char *	strncat(/* char *s1, const char *s2, size_t n */);
extern char *	strpbrk(/* const char *s1, const char *s2 */);

/* redefine yylex */
#ifdef yylex
#undef yylex
#endif
#define yylex request_scanner

/* BOTCHES to help in compiling */
/* redefine yyparse */
#ifdef yyparse
#undef yyparse
#endif
#define yyparse	parse_request

#define yyerror	request_error

#ifdef YYDEBUG
#define xmalloc malloc
#endif 

extern char *re_comp(char *);
extern re_exec(char *);

/* end BOTCHES */

/* programming macros */
#define BUILD_COMPARISON_FN( d, f, l )                                         \
{                                                                              \
		   Malloc( Conditional_Request, d);                            \
		   d->tag = COMPARISON_FN;                                     \
		   d->cond.comparison_fn.function = f;                         \
		   d->cond.comparison_fn.left = l;                             \
		   d->cond.comparison_fn.right = current_di;                   \
} while(0)
#define BUILD_BINARY_FN( d, f, l, r)                                           \
{                                                                              \
		   Malloc( Conditional_Request, d);                            \
		   d->tag = BINARY_FN;                                         \
		   d->cond.binary_fn.function = f;                             \
		   d->cond.binary_fn.left = l;                                 \
		   d->cond.binary_fn.right = r;                                \
} while(0)

/* global variables */
extern Request_Seq	*requests;

%}

/* Yacc Declarations */
%start star_request

%union {
   char			*string;
   Request_Seq		*star_request_value;
   Conditional_Request	*conditional_request_value;
   Request		*request_value;
   Data_Item		*data_item_val;
   }

%token CLOSE_ROUND_BRACKET OPEN_ROUND_BRACKET REQUEST_STRING 
       NON_QUOTED_TEXT_STRING DOUBLE_QUOTED_TEXT_STRING 
       SINGLE_QUOTED_TEXT_STRING 
       IF_ ELSE_ UNKNOWN_ ENDIF_ SCOPE_DATA_ITEM_ SCOPE_LOOP_PACKET_
       SCOPE_LOOP_STRUCTURE_ SCOPE_SAVE_FRAME_ SCOPE_DATA_BLOCK_ SCOPE_FILE_ 
       ENDSCOPE_

/* lowest precedence */
%left UNION_
%left INTERSECTION_
%left ASCII_LESS_ ASCII_LESS_OR_EQUAL_ ASCII_GREATER_  ASCII_GREATER_OR_EQUAL_
      REAL_LESS_  REAL_LESS_OR_EQUAL_  REAL_GREATER_   REAL_GREATER_OR_EQUAL_ 
%left SUB_STRING_ NOT_SUB_STRING_
%left EQUAL_STRINGS_ NOT_EQUAL_STRINGS_ 
      REAL_EQUAL_    REAL_NOT_EQUAL_ 
%left COMPLEMENT_ ASSUME_TRUE_ REG_EXP_
/* highest precedence */

%type <star_request_value>		star_request sequence_of_requests
%type <request_value>			a_request
%type <conditional_request_value>	conditional_request 
%type <data_item_val>			data_item

/* Yacc Rules */
%%
star_request :
		{  
		   INFORM_MSG("Starting Interpreter for Request Language.");
		}
        | sequence_of_requests
		{
		   DEBUG_MSG("star_request : sequence_of_requests"); 
                   requests = $1;
		}
	;

a_request :
	  conditional_request
		{
		   DEBUG_MSG("a_request : conditional_request");
		   Malloc( Request, $$ );
		   $$->tag = CONDITIONAL;
		   $$->request.conditional = $1;
		}

	| IF_ conditional_request sequence_of_requests ENDIF_
		{
		   DEBUG_MSG("a_request : IF_ conditional_request sequence_of_requests ENDIF_");
		   Malloc( Request, $$ );
		   $$->tag = BRANCHING;
                   Malloc( Branching_Request, $$->request.branching );
		   $$->request.branching->condition = $2;
		   $$->request.branching->true_branch = $3;
		   $$->request.branching->false_branch = NULL;
		   $$->request.branching->unknown_branch = NULL;
		}

	| IF_ conditional_request sequence_of_requests ELSE_ sequence_of_requests ENDIF_
		{
		   DEBUG_MSG("a_request : IF_ conditional_request sequence_of_requests ELSE_ sequence_of_requests ENDIF_");
		   Malloc( Request, $$ );
		   $$->tag = BRANCHING;
                   Malloc( Branching_Request, $$->request.branching );
		   $$->request.branching->condition = $2;
		   $$->request.branching->true_branch = $3;
		   $$->request.branching->false_branch = $5;
		   $$->request.branching->unknown_branch = NULL;
		}
	| IF_ conditional_request sequence_of_requests ELSE_ sequence_of_requests UNKNOWN_ sequence_of_requests ENDIF_
		{
		   DEBUG_MSG("a_request : IF_ conditional_request sequence_of_requests ELSE_ sequence_of_requests UNKNOWN_ sequence_of_requests ENDIF_");
		   Malloc( Request, $$ );
		   $$->tag = BRANCHING;
                   Malloc( Branching_Request, $$->request.branching );
		   $$->request.branching->condition = $2;
		   $$->request.branching->true_branch = $3;
		   $$->request.branching->false_branch = $5;
		   $$->request.branching->unknown_branch = $7;
		}
	| IF_ conditional_request sequence_of_requests UNKNOWN_ sequence_of_requests ENDIF_
		{
		   DEBUG_MSG("a_request : IF_ conditional_request sequence_of_requests UNKNOWN_ sequence_of_requests ENDIF_");
		   Malloc( Request, $$ );
		   $$->tag = BRANCHING;
                   Malloc( Branching_Request, $$->request.branching );
		   $$->request.branching->condition = $2;
		   $$->request.branching->true_branch = $3;
		   $$->request.branching->false_branch = NULL;
		   $$->request.branching->unknown_branch = $5;
		}

	| SCOPE_DATA_ITEM_ sequence_of_requests ENDSCOPE_
		{
		   DEBUG_MSG("a_request : SCOPE_DATA_ITEM_ sequence_of_requests ENDSCOPE_");
		   Malloc( Request, $$ );
		   $$->tag = SCOPE;
                   Malloc( Scope_Request, $$->request.scope );
		   $$->request.scope->scope = SCOPE_DATA_ITEM;
		   $$->request.scope->reqs = $2;
		}

	| SCOPE_LOOP_PACKET_ sequence_of_requests ENDSCOPE_
		{
		   DEBUG_MSG("a_request : SCOPE_LOOP_PACKET_ sequence_of_requests ENDSCOPE_");
		   Malloc( Request, $$ );
		   $$->tag = SCOPE;
                   Malloc( Scope_Request, $$->request.scope );
		   $$->request.scope->scope = SCOPE_LOOP_PACKET;
		   $$->request.scope->reqs = $2;
		}

	| SCOPE_LOOP_STRUCTURE_ sequence_of_requests ENDSCOPE_
		{
		   DEBUG_MSG("a_request : SCOPE_LOOP_STRUCTURE_ sequence_of_requests ENDSCOPE_");
		   Malloc( Request, $$ );
		   $$->tag = SCOPE;
                   Malloc( Scope_Request, $$->request.scope );
		   $$->request.scope->scope = SCOPE_LOOP_STRUCTURE;
		   $$->request.scope->reqs = $2;
		}

	| SCOPE_SAVE_FRAME_ sequence_of_requests ENDSCOPE_
		{
		   DEBUG_MSG("a_request : SCOPE_SAVE_FRAME_ sequence_of_requests ENDSCOPE_");
		   Malloc( Request, $$ );
		   $$->tag = SCOPE;
                   Malloc( Scope_Request, $$->request.scope );
		   $$->request.scope->scope = SCOPE_SAVE_FRAME;
		   $$->request.scope->reqs = $2;
		}
	| SCOPE_DATA_BLOCK_ sequence_of_requests ENDSCOPE_
		{
		   DEBUG_MSG("a_request : SCOPE_DATA_BLOCK_ sequence_of_requests ENDSCOPE_");
		   Malloc( Request, $$ );
		   $$->tag = SCOPE;
                   Malloc( Scope_Request, $$->request.scope );
		   $$->request.scope->scope = SCOPE_DATA_BLOCK;
		   $$->request.scope->reqs = $2;
		}
	| SCOPE_FILE_ sequence_of_requests ENDSCOPE_
		{
		   DEBUG_MSG("a_request : SCOPE_FILE_ sequence_of_requests ENDSCOPE_");
		   Malloc( Request, $$ );
		   $$->tag = SCOPE;
                   Malloc( Scope_Request, $$->request.scope );
		   $$->request.scope->scope = SCOPE_FILE;
		   $$->request.scope->reqs = $2;
		}

	;

conditional_request :
	  OPEN_ROUND_BRACKET conditional_request CLOSE_ROUND_BRACKET
		{
		   DEBUG_MSG("conditional_request : ( conditional_request )");
		   $$ = $2;
		}

	| conditional_request UNION_ conditional_request
		{
		   DEBUG_MSG("conditional_request : conditional_request UNION_ conditional_request");
                   BUILD_BINARY_FN( $$, UNION, $1, $3);
		}

	| conditional_request INTERSECTION_ conditional_request
		{
		   DEBUG_MSG("conditional_request : conditional_request INTERSECTION_ conditional_request");
                   BUILD_BINARY_FN( $$, INTERSECTION, $1, $3 );
		}

	| conditional_request EQUAL_STRINGS_ data_item
		{
		   DEBUG_MSG("conditional_request : conditional_request EQUAL_STRINGS_ data_item");
                   BUILD_COMPARISON_FN( $$, EQUAL_STRINGS, $1 );
		}

	| conditional_request NOT_EQUAL_STRINGS_ data_item
		{
		   DEBUG_MSG("conditional_request : conditional_request NOT_EQUAL_STRINGS_ data_item");
                   BUILD_COMPARISON_FN( $$, NOT_EQUAL_STRINGS, $1 );
		}

	| conditional_request SUB_STRING_ data_item
		{
		   DEBUG_MSG("conditional_request : conditional_request SUB_STRING_ data_item");
                   BUILD_COMPARISON_FN( $$, SUB_STRING, $1 );
		}

	| conditional_request NOT_SUB_STRING_ data_item
		{
		   DEBUG_MSG("conditional_request : conditional_request NOT_SUB_STRING_ data_item");
                   BUILD_COMPARISON_FN( $$, NOT_SUB_STRING, $1 );
		}

	| conditional_request ASCII_LESS_ data_item
		{
		   DEBUG_MSG("conditional_request : conditional_request ASCII_LESS_ data_item");
                   BUILD_COMPARISON_FN( $$, ASCII_LESS, $1 );
		}

	| conditional_request ASCII_LESS_OR_EQUAL_ data_item
		{
		   DEBUG_MSG("conditional_request : conditional_request ASCII_LESS_OR_EQUAL data_item");
                   BUILD_COMPARISON_FN( $$, ASCII_LESS_OR_EQUAL, $1 );
		}

	| conditional_request ASCII_GREATER_ data_item
		{
		   DEBUG_MSG("conditional_request : conditional_request ASCII_GREATER data_item");
                   BUILD_COMPARISON_FN( $$, ASCII_GREATER, $1 );
		}

	| conditional_request ASCII_GREATER_OR_EQUAL_ data_item
		{
		   DEBUG_MSG("conditional_request : conditional_request ASCII_GREATER_OR_EQUAL data_item");
                   BUILD_COMPARISON_FN( $$, ASCII_GREATER_OR_EQUAL, $1 );
		}

	| conditional_request REAL_EQUAL_ data_item
		{
		   DEBUG_MSG("conditional_request : conditional_request REAL_EQUAL data_item");
                   BUILD_COMPARISON_FN( $$, REAL_EQUAL, $1 );
		}

	| conditional_request REAL_NOT_EQUAL_ data_item
		{
		   DEBUG_MSG("conditional_request : conditional_request REAL_NOT_EQUAL data_item");
                   BUILD_COMPARISON_FN( $$, REAL_NOT_EQUAL, $1 );
		}

	| conditional_request REAL_LESS_ data_item
		{
		   DEBUG_MSG("conditional_request : conditional_request REAL_LESS data_item");
                   BUILD_COMPARISON_FN( $$, REAL_LESS, $1 );
		}

	| conditional_request REAL_LESS_OR_EQUAL_ data_item
		{
		   DEBUG_MSG("conditional_request : conditional_request REAL_LESS_OR_EQUAL data_item");
                   BUILD_COMPARISON_FN( $$, REAL_LESS_OR_EQUAL, $1 );
		}

	| conditional_request REAL_GREATER_ data_item
		{
		   DEBUG_MSG("conditional_request : conditional_request REAL_GREATER data_item");
                   BUILD_COMPARISON_FN( $$, REAL_GREATER, $1 );
		}

	| conditional_request REAL_GREATER_OR_EQUAL_ data_item
		{
		   DEBUG_MSG("conditional_request : conditional_request REAL_GREATER_OR_EQUAL data_item");
                   BUILD_COMPARISON_FN( $$, REAL_GREATER_OR_EQUAL, $1 );
		}


	| COMPLEMENT_ conditional_request
		{
		   DEBUG_MSG("conditional_request : COMPLEMENT conditional_request");
		   Malloc( Conditional_Request, $$);
		   $$->tag = UNARY_FN;
		   $$->cond.unary_fn.function = COMPLEMENT;
		   $$->cond.unary_fn.right = $2;
		}

	| ASSUME_TRUE_ conditional_request
		{
		   DEBUG_MSG("conditional_request : ASSUME_TRUE_ conditional_request");
		   Malloc( Conditional_Request, $$);
		   $$->tag = UNARY_FN;
		   $$->cond.unary_fn.function = ASSUME_TRUE;
		   $$->cond.unary_fn.right = $2;
		}

	| REQUEST_STRING 
		{  
		   DEBUG_MSG("conditional_request : REQUEST_STRING");
		   Malloc( Conditional_Request, $$);
		   $$->tag = RE_STRING;
		   $$->cond.re_string = wildcard_to_re( request_string );
		}

	| REG_EXP_ OPEN_ROUND_BRACKET REQUEST_STRING CLOSE_ROUND_BRACKET  
		{  
		   DEBUG_MSG("conditional_request : reg_exp_");
		   Malloc( Conditional_Request, $$);
		   $$->tag = RE_STRING;
		   $$->cond.re_string = request_string;
		}
	;

data_item :
	  NON_QUOTED_TEXT_STRING
		{
                   DEBUG_MSG("data_item : NON_QUOTED_TEXT_STRING ");
		   $$ = current_di;
		}
	| DOUBLE_QUOTED_TEXT_STRING
		{
                   DEBUG_MSG("data_item : DOUBLE_QUOTED_TEXT_STRING ");
		   $$ = current_di;
		}
	| SINGLE_QUOTED_TEXT_STRING
		{
                   DEBUG_MSG("data_item : SINGLE_QUOTED_TEXT_STRING ");
		   $$ = current_di;
		}
	;

sequence_of_requests :
	  /* empty */
		{  
		   DEBUG_MSG("sequence_of_requests : empty"); 
		   $$ = NULL;
		}

        | sequence_of_requests a_request
		{  
		   register Request_Seq	*tmp;

		   DEBUG_MSG("sequence_of_requests : sequence_of_requests a_request"); 
		   Malloc( Request_Seq, tmp);
		   tmp->req = $2;
		   tmp->next = NULL;
		   if( $1 ) {
		      register Request_Seq	*t = $1;
		      while( t->next ) t = t->next;
		      $$ = $1;
		      t->next = tmp;
		   }
                   else 
		      $$ = tmp;
		}
	;
%%
yyerror(char *s)
{
  char  *t;
  int   i = YYTRANSLATE(yychar);

  /* assume 12 chars will be enough to print an int */
  t = (char *)malloc( (22 + 12 + 1) * sizeof(char));
  ERROR_MSG(sprintf( t, "Syntax Error in line: %-12d", request_line_count));
  free( t );
  t = (char *)malloc( (12 + strlen(yytname[i]) + 1) * sizeof(char));
  ERROR_MSG(sprintf( t, "Unexpected %s,", yytname[i]));
  ERROR_MSG(last_request_token);
  free( t );
}
