/********************************************************************************
*
* File: oql.y
* Title: The oql parser; it generates Expr terms
* Programmer: Leonidas Fegaras, UTA
* Date: 2/21/97
*
********************************************************************************/

%{
#include <stream.h>
#include <string.h>
#include "external.h"

static int lineno = 1;
#include "oql.yy.c"

const Expr NONE = variable("NONE");
const Expr SET = variable("set");
const Expr BAG = variable("bag");
const Expr LIST = variable("list");


static list<Expr>* table_constraints = Nil;

static Expr current_attribute;

query ( Expr e);

class_def ( Expr e);

yyerror (char *s) {
  cout << s << " (line: " << lineno << ")" << " Token: " << yytext << "\n";
};

%}
%union {
	int		Tint;
	Expr		Texp;
	list<Expr>*	Texps;
}

%token ID NUM LSTRING PLUS TIMES DIV MINUS
       SEMI EOF EQ LT GT LE NE GE IF THEN ELSE
       DOT TRUE FALSE BAR COMPOSE LARROW ASSIGN LP RP
       LB RB LSB RSB COMMA AND OR IN DARROW CONCAT SORT
       LOWEST LOW HIGHEST SARROW COLON SELECT WHERE DISTINCT INTERSECT
       FROM FOR ALL EXISTS GROUP BY WITH CLASS EXTENT STRUCT UNION
       ENUM KEY KEYS RELATIONSHIP ATTRIBUTE INVERSE INTERFACE DIRECTIVES

%type <Tint> num
%type <Texp> start exp wherexp name class subtype attribute type key path
%type <Texps> expl explist tuples ranges range keys names typedecls parameters attributes dirlist

%left LOWEST
%left LOW
%left IN
%nonassoc WHERE
%left COLON
%nonassoc IF
%nonassoc ASSIGN
%right OR
%right AND
%left LP LB
%left EQ LT GT LE GE NE
%left PLUS MINUS
%left TIMES DIV CONCAT INTERSECT UNION
%right SARROW DARROW
%nonassoc ID TRUE FALSE NUM LSTRING
%nonassoc BAR
%left COMMA
%left DOT
%left HIGHEST

%%

start :   item SEMI			{}
	| start item SEMI		{}
	;
item:	  exp				{ query($1); }
	| type name ASSIGN exp		{ query(function(variable("define"),Cons($1,Cons($2,Cons($4,Nil))))); }
	| type name			{ query(function(variable("define"),Cons($1,Cons($2,Cons(variable("null"),Nil))))); }
	| class				{ class_def($1); }
	| DIRECTIVES EQ LSB dirlist RSB	{}
	;
name:	  ID				{ $$ = variable(new string(yytext)); }
	;
num:	  NUM				{ $$ = atoi(yytext); }
	;
exp : num				{ $$ = integer($1); }
    | TRUE				{ $$ = variable("true"); }
    | FALSE				{ $$ = variable("false"); }
    | name				{ $$ = $1; }
    | LSTRING				{ yytext[strlen(yytext)-1]='\0';
					  $$ = estring(new string(yytext+1)); }
    | LP exp RP				{ $$ = $2; }
    | IF exp THEN exp ELSE exp %prec LOWEST
					{ $$ = function(variable("if"),Cons($2,Cons($4,Cons($6,Nil)))); }
    | exp DOT name			{ $$ = function(variable("project"),Cons($1,Cons($3,Nil))); }
    | exp DOT name LP explist RP	{ $$ = function(variable("method"),Cons($3,Cons($1,$5))); }
    | exp EQ exp			{ $$ = function(variable("eq"),Cons($1,Cons($3,Nil))); }
    | exp LT exp			{ $$ = function(variable("lt"),Cons($1,Cons($3,Nil))); }
    | exp GT exp			{ $$ = function(variable("gt"),Cons($1,Cons($3,Nil))); }
    | exp LE exp			{ $$ = function(variable("le"),Cons($1,Cons($3,Nil))); }
    | exp NE exp			{ $$ = function(variable("ne"),Cons($1,Cons($3,Nil))); }
    | exp GE exp			{ $$ = function(variable("ge"),Cons($1,Cons($3,Nil))); }
    | exp PLUS exp			{ $$ = function(variable("plus"),Cons($1,Cons($3,Nil))); }
    | exp MINUS exp			{ $$ = function(variable("minus"),Cons($1,Cons($3,Nil))); }
    | exp TIMES exp			{ $$ = function(variable("times"),Cons($1,Cons($3,Nil))); }
    | exp DIV exp			{ $$ = function(variable("div"),Cons($1,Cons($3,Nil))); }
    | exp OR exp			{ $$ = function(variable("or"),Cons($1,Cons($3,Nil))); }
    | exp AND exp			{ $$ = function(variable("and"),Cons($1,Cons($3,Nil))); }
    | exp LB exp RB			{ yyerror("Vectors are not supported"); }
    | name LP explist RP		{ $$ = function($1,$3); }
    | STRUCT LP tuples RP		{ $$ = function(variable("struct"),$3->reverse()); }
    | SELECT exp FROM range wherexp	{ $$ = function(variable("compr"),Cons(BAG,Cons($2,Append($4,Cons($5,Nil))))); }
    | SELECT DISTINCT exp FROM range wherexp
					{ $$ = function(variable("compr"),Cons(SET,Cons($3,Append($5,Cons($6,Nil))))); }
    | exp IN exp			{ $$ = function(variable("member"),Cons($1,Cons($3,Nil))); }
    | exp INTERSECT exp			{ $$ = function(variable("intersect"),Cons($1,Cons($3,Nil))); }
    | exp UNION exp			{ $$ = function(variable("union"),Cons($1,Cons($3,Nil))); }
    | FOR ALL name IN exp COLON exp	{ $$ = function(variable("forall"),Cons($3,Cons($5,Cons($7,Nil)))); }
    | EXISTS name IN exp COLON exp	{ $$ = function(variable("exists"),Cons($2,Cons($4,Cons($6,Nil)))); }
    | GROUP name IN exp BY LP tuples RP	{ $$ = function(variable("group"),Cons($2,Cons($4,Cons(NONE,$7)))); }
    | GROUP name IN exp BY LP tuples RP WITH LP tuples RP
					{ $$ = function(variable("group"),
						Cons($2,Cons($4,Cons(function(variable("struct"),$11),$7)))); }
    | SORT name IN exp BY LP explist RP	{ $$ = function(variable("sort"),Cons($2,Cons($4,$7))); }
    | SORT name IN exp BY name		{ $$ = function(variable("sort"),Cons($2,Cons($4,Cons($6,Nil)))); }
    | LP name RP exp	%prec HIGHEST	{ $$ = $4; }
    | exp ASSIGN exp			{ $$ = function(variable("update"),Cons($1,Cons($3,Nil))); }
    ;
wherexp : /* empty */			{ $$ = function(variable("and"),Nil); }
	| WHERE exp			{ $$ = $2; }
	;
expl:     expl COMMA exp		{ $$ = Cons($3,$1); }
	| exp				{ $$ = Cons($1,Nil); }
	;
explist:  /* empty */			{ $$ = Nil; }
	| expl				{ $$ = $1->reverse(); }
	;
ranges: ranges COMMA name IN exp	{ $$ = Cons(function(variable("iterate"),Cons($3,Cons($5,Nil))),$1); }
      | name IN exp			{ $$ = Cons(function(variable("iterate"),Cons($1,Cons($3,Nil))),Nil); }
      ;
range:  ranges				{ $$ = $1->reverse(); }
	;
tuples:   tuples COMMA name COLON exp	{ $$ = Cons(function(variable("bind"),Cons($3,Cons($5,Nil))),$1); }
	| name COLON exp		{ $$ = Cons(function(variable("bind"),Cons($1,Cons($3,Nil))),Nil); }
	;
class:	  INTERFACE name subtype LP keys RP LSB attributes RSB
		{ $$ = function(variable("interface"),Cons($2,Cons($3,Cons(function(variable("info"),$5),$8->reverse())))); }
	;
subtype:  /* empty */			{ $$ = NONE; }
	| COLON name			{ $$ = $2; }
	;
attributes: attribute SEMI		{ $$ = Cons($1,Nil); }
	| attributes attribute SEMI	{ $$ = Cons($2,$1); }
	;
attribute: ATTRIBUTE type name		{ $$ = function(variable("attribute"),Cons($3,Cons($2,Nil))); }
	| RELATIONSHIP type name INVERSE name COLON COLON name
		{ $$ = function(variable("relationship"),Cons($3,Cons($2,Cons($5,Cons($8,Nil))))); }
	| type name LP RP exp		{ $$ = function(variable("method"),Cons($2,Cons($5,Cons($1,Nil)))); }
	| type name LP parameters RP exp { $$ = function(variable("method"),Cons($2,Cons($6,Cons($1,$4)))); }
	;
type:	  name LT type GT		{ $$ = function($1,Cons($3,Nil)); }
	| name				{ $$ = $1; }
	| ENUM name LSB names RSB	{ $$ = function(variable("enum"),$4->reverse()); }
	| ENUM LSB names RSB		{ $$ = function(variable("enum"),$3->reverse()); }
	| STRUCT name LSB typedecls RSB	{ $$ = function(variable("struct"),$4->reverse()); }
	| STRUCT LSB typedecls RSB	{ $$ = function(variable("struct"),$3->reverse()); }
	;
typedecls: type name SEMI		{ $$ = Cons(function(variable("bind"),Cons($2,Cons($1,Nil))),Nil); }
	| typedecls type name SEMI	{ $$ = Cons(function(variable("bind"),Cons($3,Cons($2,Nil))),$1); }
	;
parameters: type name			{ $$ = Cons(function(variable("bind"),Cons($2,Cons($1,Nil))),Nil); }
	| parameters COMMA type name	{ $$ = Cons(function(variable("bind"),Cons($4,Cons($3,Nil))),$1); }
	;
key:	  EXTENT name			{ $$ = function(variable("extent"),Cons($2,Nil)); }
	| KEY name			{ $$ = function(variable("key"),Cons($2,Nil)); }
	| KEYS LP names LP		{ $$ = function(variable("key"),$3); }
	;
keys:	  key				{ $$ = Cons($1,Nil); }
	| keys key			{ $$ = Cons($2,$1); }
	;
names:	  name				{ $$ = Cons($1,Nil); }
	| names COMMA name		{ $$ = Cons($3,$1); }
	;
dirlist:  dirlist COMMA name LP path RP	{ $$ = Cons(function($3,Cons($5,Nil)),$1); }
	| dirlist COMMA name LP path COMMA exp RP
					{ $$ = Cons(function($3,Cons($5,Cons($7,Nil))),$1); }
        | name LP path RP		{ $$ = Cons(function($1,Cons($3,Nil)),Nil); }
        | name LP path COMMA exp RP	{ $$ = Cons(function($1,Cons($3,Cons($5,Nil))),Nil); }
	;
path:	  path DOT name			{ $$ = function(variable("project"),Cons($1,Cons($3,Nil))); }
	| name DOT name			{ $$ = function(variable("project"),Cons($1,Cons($3,Nil))); }
	;
%%

parse_sql () {
  lineno = 1;
  yyparse();
};
