/* File: aqlparse.y * Author: Stefan Wiesmann and Richard Durbin (wiesmann,rd@sanger.ac.uk) * and Fred Wobus (fw@sanger.ac.uk) * Copyright (C) J Thierry-Mieg and R Durbin, 1996 * ------------------------------------------------------------------- * Acedb is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * or see the on-line version at http://www.gnu.org/copyleft/gpl.txt * ------------------------------------------------------------------- * This file is part of the ACEDB genome database package, written by * Richard Durbin (MRC LMB, UK) rd@sanger.ac.uk, and * Jean Thierry-Mieg (CRBM du CNRS, France) mieg@kaa.cnrs-mop.fr * * SCCS: $Id: aqlparse.y,v 1.36 1999/11/09 12:17:24 fw Exp $ * Description: yacc grammar for AQL * Exported functions: * aqlParse() * HISTORY: * Last edited: Nov 9 10:47 1999 (fw) * * Sep 7 17:12 1999 (fw): substantial addition to the grammar - * 'basic_decl' can now be 'expr' for a much more * general kind of declaration * * May 3 11:25 1999 (fw): added 'class .""' notation * * Mar 2 10:07 1999 (fw): all identifiers referring to names in the database * can now be quoted. select a->"min" from a in class "class" * is now possible. All user chosen identifiers have to be non-keywords still. * * Feb 26 10:17 1999 (fw): merged bool_expr: into expr: so all boolean * evaluation is now just an expression value of type BOOL * * Aug 11 13:48 1998 (fw): introduction of a default row-variable locator for 'select all @t where :1 = "xx"' type queries. * * Aug 10 16:53 1998 (fw): made class() locFunc possible * * Jul 10 11:55 1998 (fw): SORT_QUALIFIER now sets ->op to ASC/DESC, rather than number * * Jul 9 10:23 1998 (fw): changed alias syntax from Id:(expr) to Id::expr * Created: Tue Oct 29 00:01:02 1996 (rd) *------------------------------------------------------------------- */ %{ #include "acedb.h" #include "aceio.h" #include "waql/aql_.h" /**************************************************************/ static mytime_t timeCreateFromString (char *dateString); /********* globals for this module - NOT threadsafe **********/ static AQL aql_L; /* current aql object to work with */ static int tokPos[1024]; /**************************************************************/ /* macros for creating new nodes, they should really used some standard interface, like aqlcheck.c:makeNewNode() */ /* create a node of type t */ #define zMake(t) AqlNode* z = halloc(sizeof(AqlNode),aql_L->query->handle); yyval.Ptr = z; z->type = t; z->vtype = '0' /* used to chain multiples of select_fields, sortfields or table_exprs together */ #define zzFinal(x) AqlNode* zz = (AqlNode*)x; yyval.Ptr = zz; while (zz->nxt) zz = zz->nxt /* used to chain local field dereferencer together, e.g. a->paper->author->name */ #define zzFinalMake(x,t) zzFinal(x); zz->nxt = (AqlNode*)halloc(sizeof(AqlNode),aql_L->query->handle); zz = zz->nxt; zz->type = t; zz->vtype = '0' #define posSet(x,t) (x)->pos = tokPos[t] /**************************************************************/ %} %union { char* String; int Int; float Float; int Command; void* Ptr; } %token Identifier %token Number %token FloatLiteral %token StringLiteral %token DateLiteral %token Comparator %token TableFunc %token LocatorFunc %token ExprFunc %token ExprExprFunc %token Ordering %token SELECT FROM WHERE ALL ORDER BY %token TRUEtok FALSEtok %token AS OBJECT EXISTS EXISTS_TAG CLASS %token ARROW ASSIGN DOUBLE_COLON IN %token NOW TODAY %token AND OR XOR %token UNION INTERSECT DIFF %left ';' %left ASSIGN %nonassoc ORDER BY %left UNION %left INTERSECT DIFF %left OR XOR %left AND %left NOT %left Comparator %left '+' '-' %left '*' '/' %left '%' %nonassoc UMINUS %nonassoc EXISTS %nonassoc EXISTS_TAG %% start: query { aql_L->query->root = $1; $$ = $1; } query: table_expr { $$ = $1; } | query ';' query { zzFinal($1); zz->nxt = $3; aql_L->query->root = $1; } | '@' Identifier ASSIGN table_expr { zMake(nTABLE_ASSIGN); z->left = $4; z->name = $2; $$ = z; posSet(z,ASSIGN); } | '$' Identifier ASSIGN expr { zMake(nVAR_ASSIGN); z->left = $4; z->name = $2; $$ = z; posSet(z,ASSIGN); } ; table_expr: safe_table { $$ = $1; } | SELECT fieldlist { zMake(nTABLE_SFW); z->right = $2; posSet(z,SELECT); } | SELECT fieldlist FROM fwlist { zMake(nTABLE_SFW); z->left = $4; z->right = $2; posSet(z,SELECT); } | SELECT ALL fwlist { zMake(nTABLE_SFW_ALL); z->left = $3; posSet(z,SELECT); } /* select all class XXX -or- * select all object(..) -or- * select all @table */ | SELECT ALL FROM fwlist { zMake(nTABLE_SFW_ALL); z->left = $4; posSet(z,SELECT); } | table_expr ORDER { zMake(nTABLE_ORDER); z->left = $1; z->op = oASC; posSet(z,ORDER); } | table_expr ORDER Ordering { zMake(nTABLE_ORDER); z->left = $1; z->op = $3; posSet(z,ORDER); } | table_expr ORDER BY sortlist { zMake(nTABLE_ORDER); z->left = $1; z->right = $4; $$ = z; posSet(z,ORDER); } | table_expr UNION table_expr { zMake(nTABLE_OP); z->op = oUNION; z->left = $1; z->right = $3; posSet(z,UNION); } | table_expr INTERSECT table_expr { zMake(nTABLE_OP); z->op = oINTERSECT; z->left = $1; z->right = $3; posSet(z,INTERSECT); } | table_expr DIFF table_expr { zMake(nTABLE_OP); z->op = oDIFF; z->left = $1; z->right = $3; posSet(z,DIFF); } ; safe_table: '(' table_expr ')' { $$ = $2; } | '@' Identifier { zMake(nTABLE_VAR); z->name = $2; posSet(z,'@'); } ; sortlist: sort_criterion { $$ = $1; } | sortlist ',' sort_criterion { zzFinal($1); zz->nxt = $3; } ; sort_criterion: ':' Identifier { zMake(nSORT_FIELD_NAME); z->name = $2; posSet(z,':'); } | ':' TableFunc { zMake(nSORT_FIELD_NAME); z->name = strnew(aqlOpTypeName($2), aql_L->query->handle); posSet(z,':'); } | ':' Number { zMake(nSORT_FIELD); z->number = $2; posSet(z,':'); } | ':' Identifier Ordering { zMake(nSORT_FIELD_NAME); z->name = $2; z->left = (AqlNode*)halloc(sizeof(AqlNode),aql_L->query->handle); z->left->type = nSORT_QUALIFIER; z->left->op = $3; posSet(z,':'); } | ':' Number Ordering { zMake(nSORT_FIELD); z->number = $2; z->left = (AqlNode*)halloc(sizeof(AqlNode),aql_L->query->handle); z->left->type = nSORT_QUALIFIER; z->left->op = $3; posSet(z,':'); } /* | ':' expr { zMake(nSORT_FIELD_EXPR); z->left = $2; posSet(z,':'); }*/ ; fieldlist: field { $$ = $1; } | fieldlist ',' field { zzFinal($1); zz->nxt = $3; } ; field: expr { zMake(nSELECT_FIELD); z->left = $1; } | Identifier DOUBLE_COLON expr { zMake(nSELECT_FIELD); z->name = $1; z->left = $3; posSet(z,DOUBLE_COLON); } ; fwlist: fw { $$ = $1; } | fwlist ',' fw { zzFinal($1); zz->nxt = $3; } ; fw: basic_decl { AqlNode *z = $1; z->name = "_DEF"; $$ = z; } | basic_decl WHERE expr { AqlNode *z = $1; z->name = "_DEF"; z->right = $3; $$ = z; } | Identifier IN basic_decl { AqlNode *z = $3; z->name = $1; $$ = z; } | Identifier IN basic_decl WHERE expr { AqlNode *z = $3; z->name = $1; z->right = $5; $$ = z; } | basic_decl AS Identifier { AqlNode *z = $1; z->name = $3; $$ = z; } | basic_decl AS Identifier WHERE expr { AqlNode *z = $1; z->name = $3; z->right = $5; $$ = z; } | basic_decl Identifier { AqlNode *z = $1; z->name = $2; $$ = z; } | basic_decl Identifier WHERE expr { AqlNode *z = $1; z->name = $2; z->right = $4; $$ = z; } ; basic_decl: expr { zMake(nFROM_LOC); z->left = $1; z->pos = z->left->pos; } | safe_table { zMake(nFROM_TABLE); z->left = $1; z->pos = z->left->pos; } | CLASS Identifier { zMake(nFROM_LOC); z->left = (AqlNode*)halloc(sizeof(AqlNode),aql_L->query->handle); z = z->left; z->type = nCLASS; z->name = $2; posSet(z,Identifier); } | CLASS Identifier '.' StringLiteral { zMake(nFROM_LOC); z->left = (AqlNode*)halloc(sizeof(AqlNode),aql_L->query->handle); z = z->left; z->type = nCLASS; z->name = $2; posSet(z,Identifier); z->nxt = (AqlNode*)halloc(sizeof(AqlNode),aql_L->query->handle); z->nxt->type = nTEXT; z->nxt->isValue = KNOWNVAL; z->nxt->value.s = $4; z->nxt->vtype = 's'; } | CLASS StringLiteral { zMake(nFROM_LOC); z->left = (AqlNode*)halloc(sizeof(AqlNode),aql_L->query->handle); z = z->left; z->type = nCLASS; z->name = $2; posSet(z,StringLiteral); } | CLASS StringLiteral '.' StringLiteral { zMake(nFROM_LOC); z->left = (AqlNode*)halloc(sizeof(AqlNode),aql_L->query->handle); z = z->left; z->type = nCLASS; z->name = $2; posSet(z,StringLiteral); z->nxt = (AqlNode*)halloc(sizeof(AqlNode),aql_L->query->handle); z->nxt->type = nTEXT; z->nxt->isValue = KNOWNVAL; z->nxt->value.s = $4; z->nxt->vtype = 's'; } ; locator: Identifier { zMake(nLOC_VAR); z->name = $1; posSet(z,Identifier); } | OBJECT '(' expr ',' expr ')' { zMake(nOBJECT); z->left = $3; z->right = $5; posSet(z,'('); } | locator ARROW Identifier { zzFinalMake($1,nLOC_FOLLOW_TAG_NAME); zz->name = $3; posSet(zz,ARROW); } | locator ARROW StringLiteral { zzFinalMake($1,nLOC_FOLLOW_TAG_NAME); zz->name = $3; posSet(zz,ARROW); } | locator ARROW Number { zzFinalMake($1,nLOC_FOLLOW_POS); zz->number = $3; posSet(zz,ARROW); } | locator '[' Identifier ']'{ zzFinalMake($1,nLOC_LOCAL_TAG_NAME); zz->name = $3; posSet(zz,'['); } | locator '[' StringLiteral ']'{ zzFinalMake($1,nLOC_LOCAL_TAG_NAME); zz->name = $3; posSet(zz,'['); } | locator '[' Number ']' { zzFinalMake($1,nLOC_LOCAL_POS); zz->number = $3; posSet(zz,'['); } | locator ':' Identifier { zzFinalMake($1,nLOC_LOCAL_FIELD_NAME); zz->name = $3; posSet(zz,':'); } | locator ':' StringLiteral { zzFinalMake($1,nLOC_LOCAL_FIELD_NAME); zz->name = $3; posSet(zz,':'); } | locator ':' Number { zzFinalMake($1,nLOC_LOCAL_FIELD); zz->number = $3; posSet(zz,':'); } | locator '.' CLASS { zzFinalMake($1,nLOC_METHOD); zz->name = $3; posSet(zz,'.'); /* by matching the keyword 'class' we can write loc.class as a valid method. All other * method names are matched by the Identifier rule below */ } | locator '.' Identifier { zzFinalMake($1,nLOC_METHOD); zz->name = $3; posSet(zz,'.'); } | ARROW Identifier { zMake(nLOC_VAR); z->name = "_DEF"; { zzFinalMake(z,nLOC_FOLLOW_TAG_NAME); zz->name = $2; posSet(zz,Identifier); }} | ARROW StringLiteral { zMake(nLOC_VAR); z->name = "_DEF"; { zzFinalMake(z,nLOC_FOLLOW_TAG_NAME); zz->name = $2; posSet(zz,StringLiteral); }} | ARROW Number { zMake(nLOC_VAR); z->name = "_DEF"; { zzFinalMake(z,nLOC_FOLLOW_POS); zz->number = $2; posSet(zz,Number); }} | '[' Identifier ']' { zMake(nLOC_VAR); z->name = "_DEF"; { zzFinalMake(z,nLOC_LOCAL_TAG_NAME); zz->name = $2; posSet(zz,Identifier); }} | '[' StringLiteral ']' { zMake(nLOC_VAR); z->name = "_DEF"; { zzFinalMake(z,nLOC_LOCAL_TAG_NAME); zz->name = $2; posSet(zz,StringLiteral); }} | '[' Number ']' { zMake(nLOC_VAR); z->name = "_DEF"; { zzFinalMake(z,nLOC_LOCAL_POS); zz->number = $2; posSet(zz,Number); }} | ':' Identifier { zMake(nLOC_VAR); z->name = "_DEF"; { zzFinalMake(z,nLOC_LOCAL_FIELD_NAME); zz->name = $2; posSet(zz,Identifier); }} | ':' Number { zMake(nLOC_VAR); z->name = "_DEF"; { zzFinalMake(z,nLOC_LOCAL_FIELD); zz->number = $2; posSet(zz,Number); }} | '.' CLASS { zMake(nLOC_VAR); z->name = "_DEF"; { zzFinalMake(z,nLOC_METHOD); zz->name = $2; posSet(zz,'.'); }} | '.' Identifier { zMake(nLOC_VAR); z->name = "_DEF"; { zzFinalMake(z,nLOC_METHOD); zz->name = $2; posSet(zz,'.'); }} | safe_table ':' Identifier { zMake(nLOC_TABLE_FIELD_NAME); z->left = $1; z->name = $3; posSet(z,':'); } | safe_table ':' Number { zMake(nLOC_TABLE_FIELD); z->left = $1; z->number = $3; posSet(z,':'); } ; expr: locator { $$ = $1; } | '$' Identifier { zMake(nVAR); z->name = $2; posSet(z,'$'); } | Number { zMake(nINT); z->value.i = $1; posSet(z,Number); } | FloatLiteral { zMake(nFLOAT); z->value.f = $1; posSet(z,FloatLiteral); } | StringLiteral { zMake(nTEXT); z->value.s = $1; posSet(z,StringLiteral); } | date { $$ = $1; } | TableFunc safe_table { zMake(nEXPR_TABLE_FUNC); z->op = $1; z->left = $2; posSet(z,'(');} | TableFunc safe_table ':' Number { zMake(nEXPR_TABLE_FUNC_FIELD); z->op = $1; z->left = $2; z->number = $4; posSet(z,':');} | TableFunc safe_table ':' Identifier { zMake(nEXPR_TABLE_FUNC_FIELD_NAME); z->op = $1; z->left = $2; z->name = $4; posSet(z,':');} | ExprExprFunc '(' expr ',' expr ')' { zMake(nEXPR_OP); z->op = $1; z->left = $3; z->right = $5; posSet(z,'('); } | ExprFunc '(' expr ')' { zMake(nEXPR_OP); z->op = $1; z->left = $3; posSet(z,'('); } | expr '+' expr { zMake(nEXPR_OP); z->op = oPLUS; z->left = $1; z->right = $3; posSet(z,'+'); } | expr '-' expr { zMake(nEXPR_OP); z->op = oMINUS; z->left = $1; z->right = $3; posSet(z,'-'); } | expr '*' expr { zMake(nEXPR_OP); z->op = oTIMES; z->left = $1; z->right = $3; posSet(z,'*'); } | expr '/' expr { zMake(nEXPR_OP); z->op = oDIVIDE; z->left = $1; z->right = $3; posSet(z,'/'); } | '-' expr %prec UMINUS { zMake(nEXPR_OP); z->op = oUMINUS; z->left = $2; posSet(z,'-'); } | expr '%' expr { zMake(nEXPR_OP); z->op = oMOD; z->left = $1; z->right = $3; posSet(z,'%'); } | TRUEtok { zMake(nBOOL); z->value.b = TRUE; posSet(z,TRUEtok); } | FALSEtok { zMake(nBOOL); z->value.b = FALSE; posSet(z,FALSEtok); } | EXISTS locator { zMake(nBOOL_EXISTS); z->left = $2; posSet(z,EXISTS); } | EXISTS_TAG locator { zMake(nBOOL_EXISTS_TAG); z->left = $2; posSet(z,EXISTS_TAG); } | EXISTS '(' locator ')' { zMake(nBOOL_EXISTS); z->left = $3; posSet(z,EXISTS); } | EXISTS_TAG '(' locator ')' { zMake(nBOOL_EXISTS_TAG); z->left = $3; posSet(z,EXISTS_TAG); } | expr Comparator expr { zMake(nBOOL_COMPARISON); z->op = $2; z->left = $1; z->right = $3; posSet(z,Comparator); } | NOT expr { zMake(nBOOL_NOT); z->left = $2; posSet(z,NOT); } | expr AND expr { zMake(nBOOL_OP); z->op = oAND; z->left = $1; z->right = $3; posSet(z,AND); } | expr OR expr { zMake(nBOOL_OP); z->op = oOR; z->left = $1; z->right = $3; posSet(z,OR); } | expr XOR expr { zMake(nBOOL_OP); z->op = oXOR; z->left = $1; z->right = $3; posSet(z,XOR); } | '(' expr ')' { $$ = $2; } ; date: NOW { zMake(nDATE); z->value.t = timeParse ("now"); posSet(z,NOW); } | TODAY { zMake(nDATE); z->value.t = timeParse ("today"); posSet(z,TODAY); } | DateLiteral { zMake(nDATE); z->value.t = timeCreateFromString ($1); posSet(z,DateLiteral); } ; %% /************ entry point: aqlParse() ***********************/ static char *lexString; static int lexPos; int yyparse (); void aqlParse (AQL aql) { #ifdef LINUX extern FILE *yyin; extern FILE *yyout; /* this will fool the flex generated lexer into thinking that we * have an input file stream. It avoids the default setting to 'stdin'. */ yyin = (FILE*)1; yyout = (FILE*)1; #endif aql_L = aql; /* make current object global to this file (not threadsafe)*/ lexString = strnew (aql_L->query->text, aql_L->query->handle); /* let the lexer work on a copy */ /* global char * pointer lexString is modified during parsing */ lexPos = 0; yyparse (); /* return code ignored - error handle by aqlError longjmp */ return; } /* aqlParse */ static mytime_t timeCreateFromString (char *dateString) { mytime_t returnTimeElement; returnTimeElement = timeParse (dateString); if (!returnTimeElement) aqlError (aql_L, 702, lexPos-1, "Bad date/time literal"); return returnTimeElement; } /***************** lex code ************************/ #include "lex.yy.c" /***************** end of file **********************/