/******************************************************************** OQL grammer analyzer (conformant to ODMG 2.0 OQL) The material is provided as-is, with no warrenty of any kind. Author: Dirk Olbertz, Fraunhofer ISST Contact:Deutsche Telekom, Technologiezentrum, D-64307 Darmstadt Fraunhofer ISST, Postfach 520 130, D-44207 Dortmund http://www.isst.fhg.de, mailto:Weissenberg@do.isst.fhg.de Date: 98/03/16 Decription: This file parses ODMG 2.0 OQL, but without generation of a syntax tree. It is based on the BNF for ODMG-93 OQL and the new ODMG 2.0 standard provided by the ODMG. Modified by Leonidas Fegaras, 10/1/98 *********************************************************************/ %{ #include "gc_cpp.h" #include #include #include "basic.h" #define YYMAXDEPTH 20000 #define YYINITDEPTH 1000 int parser_line = 1; int parser_column = 0; int parser_state = 0; int yylex(); extern ofstream mout; extern ofstream fout; extern int suspended_stream_number; int yyerror ( char* text ); Expr OQL_query; extern bool interpreterp; /* the symbol table is a stack of scopes */ void new_scope(); void close_scope(); void new_variable_scope(); int close_variable_scope(); void warning_ODMG93 ( char* text ) { cout << "Warning: '" << text << "' is only supported in ODMG-93." << endl; cout << "Line: " << parser_line << ", Column: " << parser_column << endl; }; /* remove quotes and double-quotes from string */ char* fix_string ( char* x ) { int n = strlen(x); char* s = new char[n-2]; int j = 0; for(int i = 0; i* r ) { return function(variable(s),r); }; Expr L ( char* s, Expr x1, list* r ) { return function(variable(s),Cons(x1,r)); }; Expr L ( char* s, Expr x1, Expr x2, list* r ) { return function(variable(s),Cons(x1,Cons(x2,r))); }; Expr F ( char* s, Expr x1 ) { return function(variable(s),Cons(x1,Nil)); }; Expr F ( char* s, Expr x1, Expr x2 ) { return function(variable(s),Cons(x1,Cons(x2,Nil))); }; Expr F ( char* s, Expr x1, Expr x2, Expr x3 ) { return function(variable(s),Cons(x1,Cons(x2,Cons(x3,Nil)))); }; Expr F ( char* s, Expr x1, Expr x2, Expr x3, Expr x4 ) { return function(variable(s),Cons(x1,Cons(x2,Cons(x3,Cons(x4,Nil))))); }; Expr F ( char* s, Expr x1, Expr x2, Expr x3, Expr x4, Expr x5 ) { return function(variable(s),Cons(x1,Cons(x2,Cons(x3,Cons(x4,Cons(x5,Nil)))))); }; %} %start program %token DEFINE AS NIL TRUE FALSE LRPAR RRPAR PLUS %token MINUS MULT DIV MOD ABS DOUBLEVERT LIKE %token EQUAL NOTEQUAL GREATER LESS GREATEREQUAL LESSEQUAL %token NOT AND OR STRUCT SET BAG LIST ARRAY %token REPAR LEPAR DOT FIRST LAST ALL IN EXISTS %token UNIQUE SOME ANY COUNT SUM MIN MAX AVG SELECT %token DISTINCT FROM WHERE GROUP BY HAVING ORDER %token ASC DESC INTERSECT UNION EXCEPT LISTTOSET ELEMENT %token FLATTEN SEMI DOUBLEDOT TWODOT KOMMA ALL FOR %token ESCAPE CTOKEN LSPAR RSPAR INSERT CREATE INDEX ON DROP %token PRINT STATISTICS DELETE INSERT MODULE IMPORT EACH DO ASSIGN %token BEGINT COMMIT ABORT INITIALIZE CLEANUP COLLECT CASE OF END %token DEFAULT OPTIONS IFT THENT ELSET ENDTAG PERSISTENT ANY_TAG STAR_TAG %token string_literal float_literal integer_literal %token identifier %union { char* StringType; long Integer; float Float; char* Tstring; Expr Texp; list* Texps; } %type integer_literal %type identifier string_literal comparison_operator %type float_literal %type Id epsilon define_query query query_optDISTINCT query_optWHERE query_optGROUP query_optHAVING query_optORDER quantifier projection variable_declaration sort_criterion oql destination ODL_type method_name %type id_list named_query_list opt_query_list query_list projection_attributes projection_list variable_declaration_list partition_attributes sort_criterion_list tags cases options signature xml_attributes xml_attrs %left LOWEST %left FROM %nonassoc WHERE %left GROUP %left HAVING %left ORDER %left TWODOT DOUBLEDOT %nonassoc THENT ELSET ENDTAG %left OR %left AND EXISTS FOR ALL %left IN %left LRPAR RRPAR %left EQUAL NOTEQUAL LIKE %nonassoc LESS GREATER LESSEQUAL GREATEREQUAL SOME ANY %left PLUS MINUS DOUBLEVERT %left UNION EXCEPT %left MULT DIV MOD %left INTERSECT %left NOT %left LEPAR REPAR %left KOMMA %left DOT STAR_TAG ANY_TAG %left HIGHEST %% epsilon : /* empty */ { $$ = none;} ; Id: identifier { $$ = variable($1); } ; /*-------------------------------------------------- --------------------------------------------------*/ program : C_plus_plus_code | program C_plus_plus_code ; ctoken_list : CTOKEN | ctoken_list CTOKEN ; C_plus_plus_code : ESCAPE { c_code = false; new_variable_scope(); } oql SEMI { if (interpreterp) OQL_query = $3; else process($3); c_code = true; close_variable_scope(); if (!interpreterp) mout << "\n#line " << parser_line << endl; } | error SEMI { yyclearin; yyerrok; } | LSPAR { mout << "{"; new_scope(); } program RSPAR { mout << "}"; close_scope(); } | CTOKEN | SEMI { mout << ";"; } ; foreach_body: ctoken_list { mout << "; };"; } | ESCAPE { c_code = false; } oql { process($3); c_code = true; mout << " };"; } | LSPAR { mout << "{"; new_scope(); } program RSPAR { mout << " }; };"; close_scope(); } ; ODL_type : Id { $$ = $1; } | SET LESS ODL_type GREATER { $$ = F("set",$3); } | BAG LESS ODL_type GREATER { $$ = F("bag",$3); } | LIST LESS ODL_type GREATER { $$ = F("list",$3); } ; oql : define_query { $$ = $1; } | MODULE Id { $$ = F("module",$2); } | IMPORT Id { $$ = F("import",$2); } | Id DOUBLEDOT ODL_type { $$ = F("type",$3,$1); } | Id ASSIGN query { $$ = F("assign",$1,$3); } | destination ASSIGN query { $$ = F("update",$1,$3); } | destination INSERT query { $$ = F("insert",$1,$3); } | destination DELETE query { $$ = F("delete",$1,$3); } | Id DELETE query { $$ = F("delete",$1,$3); } | FOR EACH Id IN { new_scope(); } query DO { process(F("foreach",$3,$6)); c_code = true; } foreach_body { $$ = variable("none"); c_code = false; close_scope(); } | PRINT query { $$ = F("print",$2,integer(2)); } | PRINT query integer_literal { $$ = F("print",$2,integer($3)); } | CREATE INDEX Id ON Id LRPAR id_list RRPAR { $$ = L("create_index",$3,$5,$7->reverse()); } | DROP INDEX Id { $$ = F("drop_index",$3); } | COLLECT STATISTICS { $$ = F("collect",variable("statistics")); } | PRINT STATISTICS { $$ = F("print",variable("statistics")); } | BEGINT { $$ = variable("begin"); } | COMMIT { $$ = variable("commit"); } | ABORT { $$ = variable("abort"); } | INITIALIZE { $$ = L("initialize",Nil); } | CLEANUP { $$ = variable("cleanup"); } | OPTIONS options { $$ = L("options",$2); } ; destination : query DOT Id { $$ = F("project",$1,$3); } ; options : Id EQUAL integer_literal { $$ = Cons(F("bind",$1,integer($3)),Nil); } | options KOMMA Id EQUAL integer_literal{ $$ = Cons(F("bind",$3,integer($5)),$1); } ; /*------------------------------------------------------------ ::= DEFINE Id [( [Id {,Id}])] AS query ------------------------------------------------------------*/ define_query : DEFINE method_name AS query { $$ = F("define",$2,L("params",Nil),$4); } | DEFINE method_name LRPAR RRPAR AS query { $$ = F("define",$2,L("params",Nil),$6); } | DEFINE method_name LRPAR id_list RRPAR AS query { $$ = F("define",$2,L("params",$4->reverse()),$7); } | DEFINE method_name LRPAR RRPAR DOUBLEDOT ODL_type AS query { $$ = F("function",$2,L("params",Nil),$6,$8); } | DEFINE method_name LRPAR signature RRPAR DOUBLEDOT ODL_type AS query { $$ = F("function",$2,L("params",$4->reverse()),$7,$9); } ; method_name : Id { $$ = $1; } | Id DOUBLEDOT DOUBLEDOT Id { $$ = F("method",$1,$4); } ; signature : Id DOUBLEDOT ODL_type { $$ = Cons(F("bind",$1,$3),Nil); } | signature KOMMA Id DOUBLEDOT ODL_type { $$ = Cons(F("bind",$3,$5),$1); } ; id_list : Id { $$ = Cons($1,Nil); } | id_list KOMMA Id { $$ = Cons($3,$1); } ; /*------------------------------------------------------------ Basic ::= NIL ::= TRUE ::= FALSE ::= integer_literal ::= float_literal ::= string_literal ::= Id ::= ( query ) ------------------------------------------------------------*/ query : NIL { $$ = variable("nil"); } | TRUE { $$ = variable("true"); } | FALSE { $$ = variable("false"); } | integer_literal { $$ = integer($1); } | float_literal { $$ = real($1); } | string_literal { $$ = estring(fix_string($1)); } | Id { $$ = $1; } | LRPAR query RRPAR { $$ = $2; } ; /*------------------------------------------------------------ Simple Expression ::= query + query ::= query - query ::= query * query ::= query / query ::= - query ::= query MOD query ::= ABS( query ) ::= query || query ------------------------------------------------------------*/ query : query PLUS query { $$ = F("plus",$1,$3); } | query MINUS query { $$ = F("minus",$1,$3); } | query MULT query { $$ = F("times",$1,$3); } | query DIV query { $$ = F("div",$1,$3); } | MINUS query { $$ = F("minus",$2); } | query MOD query { $$ = F("mod",$1,$3); } | ABS LRPAR query RRPAR { $$ = F("abs",$3); } | query DOUBLEVERT query { $$ = F("concat",$1,$3); } ; /*------------------------------------------------------------ Comparison ::= query = query ::= query != query ::= query > query ::= query < query ::= query >= query ::= query <= query ::= query LIKE string_literal ------------------------------------------------------------*/ query : query EQUAL query { $$ = F("eq",$1,$3); } | query NOTEQUAL query { $$ = F("neq",$1,$3); } | query GREATER query { $$ = F("gt",$1,$3); } | query LESS query { $$ = F("lt",$1,$3); } | query GREATEREQUAL query { $$ = F("geq",$1,$3); } | query LESSEQUAL query { $$ = F("leq",$1,$3); } | query LIKE string_literal { $$ = F("like",$1,estring(fix_string($3))); } | IFT query THENT query ELSET query { $$ = F("if",$2,$4,$6); } ; /*------------------------------------------------------------ Boolean Expression ::= NOT query ::= query AND query ::= query OR query ------------------------------------------------------------*/ query : NOT query { $$ = F("not",$2); } | query AND query { $$ = F("and",$1,$3); } | query OR query { $$ = F("or",$1,$3); } ; /*------------------------------------------------------------ Constructor ::= Id ( [query] ) ::= Id ( Id : query {, Id : query} ) ::= STRUCT ( Id : query {, Id : query} ) ::= SET ( [query {, query} ] ) ::= BAG ( [query {, query} ] ) ::= LIST ( [query {, query} ] ) ::= ( query, query {, query} ) ::= [LIST] ( query .. query) ::= ARRAY ( [query {, query} ] ) ::= UNION ( Id : query ) ------------------------------------------------------------*/ query : Id LRPAR named_query_list RRPAR { $$ = L("construct",$1,$3->reverse()); } | PERSISTENT Id LRPAR named_query_list RRPAR { $$ = L("persistent_construct",$2,$4->reverse()); } | STRUCT LRPAR named_query_list RRPAR { $$ = L("struct",$3->reverse()); } | STRUCT LRPAR RRPAR { $$ = L("struct",Nil); } | SET LRPAR opt_query_list RRPAR { $$ = L("set",$3); } | BAG LRPAR opt_query_list RRPAR { $$ = L("bag",$3); } | LIST LRPAR opt_query_list RRPAR { $$ = L("list",$3); } /* The following rule produces 34 reduce/reduce conflicts ! | LRPAR query KOMMA query opt_query_list RRPAR */ | LIST LRPAR query TWODOT query RRPAR { $$ = F("list",F("dots",$3,$5)); } | LRPAR query TWODOT query RRPAR { $$ = F("dots",$2,$4); } | ARRAY LRPAR opt_query_list RRPAR { $$ = L("array",$3); } ; named_query_list : Id DOUBLEDOT query { $$ = Cons(F("bind",$1,$3),Nil); } | named_query_list KOMMA Id DOUBLEDOT query { $$ = Cons(F("bind",$3,$5),$1); } ; query_list : query { $$ = Cons($1,Nil); } | query_list KOMMA query { $$ = Cons($3,$1); } ; opt_query_list : epsilon { $$ = Nil; } | query_list { $$ = $1->reverse(); } ; /*------------------------------------------------------------ Accessor ::= query DOT Id ::= query DOT Id( query {,query} ) ::= * query ::= query [ query ] // *not* optional ! ::= query [query:query] // *not* optional ! ::= first( query ) ::= last( query ) ::= Id( [query {, query}] ) ::= CASE query OF {, { Id : } query } [ , DEFAULT : query ] END ------------------------------------------------------------*/ query : query DOT Id { $$ = F("project",$1,$3); } | query STAR_TAG { $$ = F("project",$1,variable("STAR")); } | query ANY_TAG { $$ = F("project",$1,variable("ANY")); } | query DOT Id LRPAR opt_query_list RRPAR { $$ = L("method",$1,$3,$5->reverse()); } | MULT query { $$ = F("deref",$2); } | query LEPAR query REPAR { $$ = F("vector_access",$1,$3); } | query LEPAR query DOUBLEDOT query REPAR { $$ = F("vector_range",$1,$3,$5); } | FIRST LRPAR query RRPAR { $$ = F("first",$3); } | LAST LRPAR query RRPAR { $$ = F("last",$3); } | Id LRPAR opt_query_list RRPAR { $$ = L("call",$1,$3); } | CASE query OF cases KOMMA DEFAULT DOUBLEDOT query END { $$ = L("cases",$2,F("case",$8,variable("default")),$4); } | CASE query OF cases END { $$ = L("cases",$2,$4); } | DOUBLEDOT integer_literal { $$ = F("LDBobject",integer($2)); } ; cases : tags query { $$ = Cons(L("case",$2,$1),Nil); } | cases KOMMA tags query { $$ = Cons(L("case",$4,$3),$1); } ; tags : Id DOUBLEDOT { $$ = Cons($1,Nil); } | tags Id DOUBLEDOT { $$ = Cons($2,$1); } ; /*------------------------------------------------------------ Collection Expression ::= FOR ALL Id IN query : query ::= EXISTS Id IN query : query ::= EXISTS ( query ) ::= UNIQUE ( query ) ::= query IN query ::= query comparison_operator quantifier query ::= COUNT ( query ) ::= COUNT ( * ) ::= SUM ( query ) ::= MIN ( query ) ::= MAX ( query ) ::= AVG ( query ) ------------------------------------------------------------*/ query : FOR ALL Id IN query DOUBLEDOT query { $$ = F("forall",$3,$5,$7); } | EXISTS Id IN query DOUBLEDOT query { $$ = F("exists",$2,$4,$6); } | EXISTS LRPAR query RRPAR { $$ = F("exists",$3); } | UNIQUE LRPAR query RRPAR { $$ = F("unique",$3); } | query IN query { $$ = F("member",$1,$3); } | query comparison_operator quantifier query { $$ = F($2,$1,$3,$4); } | COUNT LRPAR query RRPAR { $$ = F("count",$3); } | COUNT LRPAR MULT RRPAR { $$ = F("count",variable("all")); } | SUM LRPAR query RRPAR { $$ = F("sum",$3); } | MIN LRPAR query RRPAR { $$ = F("min",$3); } | MAX LRPAR query RRPAR { $$ = F("max",$3); } | AVG LRPAR query RRPAR { $$ = F("avg",$3); } ; /*------------------------------------------------------------ XML stuff ------------------------------------------------------------*/ query : LESS Id xml_attributes GREATER opt_query_list ENDTAG Id GREATER { if ($2->eq($7)) $$ = L("xml_tag",$2,L("attributes",$3),$5); else yyerror("end-tag name does not match with the begin-tag name"); } | query DOT MULT { $$ = F("project_star",$1); } ; xml_attrs : Id EQUAL string_literal { $$ = Cons(F("bind",$1,estring(fix_string($3))),Nil); } | xml_attrs Id EQUAL string_literal { $$ = Cons(F("bind",$2,estring(fix_string($4))),$1); } ; xml_attributes : xml_attrs { $$ = $1; } | { $$ = Nil; } ; /*------------------------------------------------------------------------- Select Expression ::= SELECT [ DISTINCT ] projection_attributes FROM variable_declaration {, variable_declaration } [ WHERE query ] [ GROUP BY partition_attributes ] [ HAVING query ] [ ORDER BY sort_criterion {, sort_criterion} ] ::= projection {, projection} ::= * ::= query ::= Id : query ::= query AS Id ::= query [[AS] Id] ::= projection {, projection} ::= query [ordering] ::= ASC ::= DESC -------------------------------------------------------------------------*/ query : SELECT query_optDISTINCT projection_attributes FROM variable_declaration_list query_optWHERE query_optGROUP query_optHAVING query_optORDER { $$ = function(variable("select"),Cons($2,Cons(L("project",$3), Cons(L("from",$5),Cons($6,Cons($7,Cons($8,Cons($9,Nil)))))))); } ; query_optDISTINCT : epsilon { $$ = variable("bag"); } | DISTINCT { $$ = variable("set"); } | LIST { $$ = variable("list"); } ; projection_attributes : projection_list { $$ = $1->reverse(); } | MULT { $$ = Cons(variable("all"),Nil); } ; projection_list : projection { $$ = Cons($1,Nil); } | projection_list KOMMA projection { $$ = Cons($3,$1); } ; projection : query { $$ = $1; } | Id DOUBLEDOT query { $$ = F("bind",$1,$3); } | query AS Id { $$ = F("bind",$3,$1); } ; variable_declaration_list : variable_declaration { $$ = Cons($1,Nil); } | variable_declaration KOMMA variable_declaration_list { $$ = Cons($1,$3); } ; variable_declaration : query { if (!$1->variablep()) yyerror("wrong from-clause"); $$ = F("iterate",variable($1->name()),$1); } | query Id { $$ = F("iterate",$2,$1); } | query AS Id { $$ = F("iterate",$3,$1); } | Id IN query { $$ = F("iterate",$1,$3); } ; query_optWHERE : epsilon { $$ = variable("true"); } | WHERE query { $$ = $2; } ; query_optGROUP : epsilon { $$ = L("groupby",Nil); } | GROUP BY partition_attributes { $$ = L("groupby",$3); } ; partition_attributes : projection_list { $$ = $1->reverse(); } ; query_optHAVING : epsilon { $$ = variable("true"); } | HAVING query { $$ = $2; } ; query_optORDER : epsilon { $$ = L("order",Nil); } | ORDER BY sort_criterion_list { $$ = L("order",$3->reverse()); } ; sort_criterion_list : sort_criterion { $$ = Cons($1,Nil); } | sort_criterion_list KOMMA sort_criterion { $$ = Cons($3,$1); } ; sort_criterion : query { $$ = $1; } | query ASC { $$ = $1; } | query DESC { $$ = F("desc",$1); } ; /*------------------------------------------------------------------------- Set Expression ::= query INTERSECT query ::= query UNION query ::= query EXCEPT query -------------------------------------------------------------------------*/ query : query INTERSECT query { $$ = F("intersect",$1,$3); } | query UNION query { $$ = F("union",$1,$3); } | query EXCEPT query { $$ = F("except",$1,$3); } ; /*------------------------------------------------------------------------- Conversion ::= LISTTOSET ( query ) ::= ELEMENT ( query ) ::= DISTINCT ( query ) ::= FLATTEN ( query ) ::= ( Id ) query -------------------------------------------------------------------------*/ query : LISTTOSET LRPAR query RRPAR { $$ = F("listtoset",$3); } | ELEMENT LRPAR query RRPAR { $$ = F("element",$3); } | DISTINCT LRPAR query RRPAR { $$ = F("distinct",$3); } | FLATTEN LRPAR query RRPAR { $$ = F("flatten",$3); } /* | LRPAR Id RRPAR query %prec HIGHEST { $$ = F("coerce",$2,$4); } */ ; comparison_operator : EQUAL { $$ = "eq"; } | NOTEQUAL { $$ = "neq"; } | GREATER { $$ = "gt"; } | LESS { $$ = "lt"; } | GREATEREQUAL { $$ = "geq"; } | LESSEQUAL { $$ = "leq"; } ; quantifier : SOME { $$ = variable("some"); } | ANY { $$ = variable("any"); } | ALL { $$ = variable("all"); } ; %% int ctoken ( int token ); void ctext (); #include "oql.yy.cc" int ctoken ( int token ) { if (c_code) { mout << yytext; return CTOKEN; } else return token; }; void ctext () { if (c_code || strcmp(yytext,"\n")==0) mout << yytext; }; int yyerror ( char* text ) { eout << "*** " << text << " near the token " << yytext << " (line: " << parser_line << ", column: " << parser_column << ")\n"; yyclearin; throw odmg_error_class(eout.str()); }; void parse_oql () { parser_line = 1; parser_column = 0; parser_state = 0; yyparse(); };