/* ** GRAMMAR.Y -- Equel 6.2 grammar ** ** Yacc grammar and semantic rules for Quel ** embedded in C. ** ** The grammar is organized in the following manner: ** a) control structure ** b) quel statments ** c) equel statements ** d) declaration and use of C vars ** e) special objects ** f) expressions ** g) keywords ** h) noise words and punctuation ** Within a single classification, major objects are ordered ** alphabetically, and minor objects under the major ones they ** are in. ** ** Side Effects: ** performs the translation of an Equel program into ** a C program with calls on the Equel run-time ** support ** ** Files: ** constants.h -- for manifest constants ** globals.h -- for global variables ** tokens.y -- for operator, keyword tables ** .../fileio.h -- for FILE stuff for globals.h ** ** Diagnostics: ** Several self-explanatory diagnostics. ** ** History: ** 5/31/78 -- (marc) rewritten based on the previous ** equel grammar by jim ford, as well as ** rick berman's quel parser, and suggestions ** from everyone. ** 8/27/78 -- (marc) modified to include structure ** variables and definitions ** 1/13/79 -- (marc) modified to include qrymod statements ** ** NOTE: ** There are two shift/reduce conflicts associated ** with the non-terminals "[o_]gen_while". It is resolved ** correctly by yacc. */ /* QUEL keywords */ %token APPEND COPY CREATE DEFINE %token DELETE DESTROY HELP INDEX %token MODIFY PRINT INTEGRITY RANGE %token REPLACE RETRIEVE SAVE UNIQUE %token PERMIT VIEW /* special embedded QUEL commands */ %token INGRES EXIT PARAM /* C variable usages */ %token TYPE ALLOC STRUCT STRUCT_VAR /* QUEL noise words */ %token ALL BY FROM IN %token INTO IS OF ON %token ONTO TO WHERE UNTIL %token AT /* constants */ %token NAME SCONST I2CONST I4CONST %token F8CONST C_CODE /* punctuation */ %token COMMA LPAREN RPAREN PERIOD %token QUOTE BGNCMNT ENDCMNT LBRACE %token RBRACE LBRKT RBRKT NONREF %token SEMICOL POINTER COLON /* operator classes */ %token UOP %token BOP %token BDOP %token EOP %token LBOP LUOP %token FOP FBOP %token AOP /* define ascending precedence for operators */ %left LBOP %left LUOP %left BOP LBRKT %left UOP %nonassoc unaryop %{ /* STANDARD SCANNER & PARSER GLOBALS */ # include "constants.h" # include "../fileio.h" # include "globals.h" %} %% %{ register struct cvar *cvarp; %} /* * Program Control Structure */ program: program statement = { /* for each "statement", free the symbol space * used by that query (lookahed space must not * be freed), and catch up on output lines */ symspfree(); equate_lines(); } | ; ; statement: startquel quel_statement = { w_sync(); /* the purpose of the actions for startquel * and this action is to make each query * a single compound C statement (if (x) "{query}") */ w_op("}"); } | startquel equel_statement = { end_quote(); w_op("}"); } | c_code | declaration | error ; startquel: = w_op("{"); ; /* * C_CODE is a token returned by the lexical analyzer * when it recognizes that the following line is not * equel code. On the NEXT call to the lexical analyzer, * the code will be copied from the source to the output file. */ c_code: C_CODE | beginblock = Block_level =+ 1; | endblock = { if (Block_level == 0) yyserror("extra '}'", $1); else if ((Block_level =- 1) == 0) { freecvar(&C_locals); freecvar(&F_locals); } } ; /* the %prec is to resolve conflicts with the { after a * "tupret". */ beginblock: LBRACE %prec LBOP = w_op($1->d_elm); ; endblock: RBRACE = w_op($1->d_elm); ; quel_statement: append | copy | create | delete | destroy | help | index | integrity | modify | permit | print | range | replace | retrieve | save | view ; /* commands particular to Equel */ equel_statement:append_p | copy_p | create_p | exit | ingres | replace_p | retrieve_p | tupret | view_p ; /* * QUEL statements */ append: append_key apclause tlclause qualclause ; apclause: apkword id ; copy: copy_key id lparen ctl rparen cp_kword filename | copy_key id lparen rparen cp_kword filename ; filename: sconst | id ; create: create_key id lparen ctl rparen ; delete: delete_key delclause qualclause ; delclause: delnoise id ; destroy: destroy_key idlist | destroy_key integ_permit id int_list_all ; integ_permit: integ_key | permit_key ; int_list_all: int_list | all ; help: help_key | help_key all | help_key hlist | help_key int_perm_view idlist ; hlist: hparam | hlist comma hparam ; hparam: id | sconst ; int_perm_view: integ_permit | view_key ; index: index_key id is id lparen idlist rparen ; integrity: define_key integ_key integnoise id isnoise qual ; modify: modify_key id to id on modkeylist density | modify_key id to id ; modkeylist: modkey | modkeylist comma modkey ; modkey: id | id colon id ; density: where modfill | ; ; modfill: id is mod_var | modfill comma id is mod_var ; /* mod_var can be an integer constant or var, or a string var * or a quel name */ mod_var: I2CONST = w_con(I2CONST, $1->d_elm); | c_variable = { if ($1) { if (!Cvarp) w_key($1->d_elm); else if (Fieldp && Fieldp->c_type == opINT || Cvarp->c_type == opINT) w_var(Cv_display, opINT); else if (Fieldp && Fieldp->c_type == opSTRING || Cvarp->c_type == opSTRING) w_var(Cv_display, opIDSTRING); else yyserror("in MODIFY, qual var must be in or string", $1); } else yyserror("bad modify qualification", 0); free_display(Cv_display); Cvarp = Fieldp = 0; } ; permit: def_perm permit_list on_of_to id perm_tl perm_who perm_term perm_time perm_day qualclause ; def_perm: define_key permit_key ; permit_list: permlistelm | permit_list comma permlistelm ; permlistelm: RETRIEVE = w_key($1->d_elm); | APPEND = w_key($1->d_elm); | DELETE = w_key($1->d_elm); | REPLACE = w_key($1->d_elm); | all ; on_of_to: on | of | to ; perm_tl: lparen idlist rparen | ; ; perm_who: to id | all | ; ; perm_term: at id | at all | ; ; perm_time: from integer colon integer to integer colon integer | ; ; perm_day: on id to id | ; ; print: print_key idlist ; range: range_of id is id ; replace: replace_key repclause tlclause qualclause ; repclause: repkword id ; retrieve: retrieve_key resclause tlclause qualclause ; resclause: retkword id ; save: save_key id until date ; date: id integer integer ; view: define_key view_key id tlclause qualclause ; /* * Statements Particular to Equel */ append_p: append_p_key apclause param_tl qualclause ; copy_p: copy_p_key id param_tl fr_in_id filename ; fr_in_id: cp_kword | c_variable = { if ($1 && Cvarp) { if (Fieldp && Fieldp->c_type != opSTRING || !Fieldp && Cvarp->c_type != opSTRING) yyserror("string var expected for from/into in COPY", $1); else w_var(Cv_display, opIDSTRING); } else yyserror("into/from expected in COPY", $1); free_display(Cv_display); Fieldp = Cvarp = 0; } ; create_p: create_p_key id param_tl ; exit: EXIT = { Opflag = mdEXIT; w_new("IIexit();"); } ; ingres: ingres_key param_list = w_op(");"); ; param_list: param = w_op("0"); | param param_list ; param: id = w_op(","); | SCONST = { w_string($1->d_elm, 0); w_op(","); } ; replace_p: replace_p_key repclause param_tl qualclause ; retrieve_p: retrieve_p_key resclause param_tl qualclause ; tupret: tupret_keyw xc_code = w_flush(); | tupret_p o_xc_code = w_flush(); ; tupret_keyw: retrieve_key unique c_tlclause qualclause = { w_new("IIsetup();"); w_sync(); } ; unique: UNIQUE = { Opflag = mdTUPRET; w_key($1->d_elm); } | = Opflag = mdTUPRET; ; c_tlclause: lparen c_tlist rparen ; c_tlist: c_tlelm | c_tlelm comma c_tlist ; c_tlelm: reduc cvar is_key afcn ; reduc: = Opflag = mdCTLELM; ; xc_code: LBRACE gen_while c_code RBRACE %prec LBRACE = w_op("}"); | gen_while %prec LBOP = w_op("}"); ; gen_while: = { w_new("while(IIn_get("); w_file(); w_op(")){"); w_ret(); free_ret(); w_op("if(IIerrtest())continue;"); equate_lines(); } ; o_xc_code: LBRACE o_gen_while c_code RBRACE %prec LBRACE = w_op("}"); | o_gen_while %prec LBOP = w_op("}"); ; o_gen_while: = { w_new("while(IIgettup("); w_file(); w_op(")){"); equate_lines(); } ; tupret_p: tupret_p_key unique param_tl qualclause = { w_new("IIsetup();"); w_sync(); } ; view_p: PARAM define_key view_key id param_tl qualclause ; /* * Declarations and use of C variables */ declaration: decl_specifer declarator_list SEMICOL = { w_op($3->d_elm); Type_spec = 0; } | decl_specifer SEMICOL = { w_op($2->d_elm); Type_spec = 0; } ; decl_specifer: type_specifier | sc_specifier | type_specifier sc_specifier | sc_specifier type_specifier | struct_dec = { Struct_flag = 0; Type_spec = opSTRUCT; } | sc_specifier struct_dec = { Struct_flag = 0; Type_spec = opSTRUCT; } ; sc_specifier: ALLOC = { Opflag = mdDECL; w_key($1->d_elm); /* in case the default "int" should be assumed, * the Type_spec is set up for it, if a previous * type hasn't been given */ if (!Type_spec) Type_spec = opINT; } ; type_specifier: TYPE = { Opflag = mdDECL; w_key($1->d_elm); Type_spec = Opcode; } ; struct_dec: struct_name field_declaration | struct_name | struct_key field_declaration ; struct_name: struct_key NAME = w_key($2->d_elm); ; field_declaration: lbrace field_seq RBRACE = { w_op($3->d_elm); Type_spec = $3; } ; field_seq: field_seq field | ; ; field: type_specifier declarator_list SEMICOL = { w_op($3->d_elm); Type_spec = 0; } | C_CODE ; declarator_list: cvar_dec | declarator_list comma cvar_dec ; cvar_dec: cvarx = { if (Type_spec == opSTRING) Indir_level =- 1; if (Struct_flag) decl_field($1->d_elm, Type_spec, Indir_level, Block_level); else decl_cvar($1->d_elm, Type_spec, Indir_level, Block_level); free_display(Cv_display); Indir_level = Field_indir = 0; Fieldp = Cvarp = 0; } ; c_variable: cvarx = { $$ = $1; if (Cvarp && Cvarp->c_indir != Indir_level) { yyserror("bad indirection on a C variable", $1); $$ = 0; } Indir_level = Field_indir = 0; } | NONREF NAME = { enter_display(Cv_display, salloc($1->d_elm)); Cvarp = Fieldp = 0; $$ = $2; } | NONREF STRUCT_VAR = { enter_display(Cv_display, salloc($1->d_elm)); Cvarp = Fieldp = 0; $$ = $2; } | struct_var = { if (!Fieldp) { yyserror("undeclared field", $1); $$ = $0; } else if (Fieldp->c_indir != Field_indir) { yyserror("bad indirection on a structure's field", $1); $$ = 0; } if (Cvarp->c_indir != Indir_level) { yysemerr("bad indirection a structure variable", Cvarp->c_indir); $$ = 0; } Indir_level = Field_indir = 0; } ; struct_var: ptr struct_var %prec unaryop = { if ($1->d_elm [1] == '*') Field_indir =+ 1; Field_indir =+ 1; $$ = $2; } | struct_var arraysub %prec LBRKT = Field_indir =+ 1; | str_var_key selector_part ; str_var_key: STRUCT_VAR = { Cvarp = getcvar($1->d_elm); enter_display(Cv_display, $1->d_elm); } ; selector_part: arraysub selector_part = { Indir_level =+ 1; $$ = $2; } | select_op NAME = { enter_display(Cv_display, $2->d_elm); Fieldp = getfield($2->d_elm); $$ = $2; } ; select_op: PERIOD = enter_display(Cv_display, $1->d_elm); | POINTER = { enter_display(Cv_display, $1->d_elm); Indir_level =+ 1; } ; /* use of a C variable */ cvar: c_variable = { if ($1) { if (!Fieldp && ! Cvarp) { if (!Field_indir && !Indir_level && (sequal($1->d_elm, "dba") || sequal($1->d_elm, "usercode"))) /* constant operator COP */ w_key($1->d_elm); else yyserror("C var expected", $1); } else if (Opflag == mdCTLELM) { w_con(NAME, Fieldp ? Fieldp->c_id: Cvarp->c_id); enter_ret(Cv_display, Fieldp ? Fieldp->c_type: Cvarp->c_type); } else w_var(Cv_display, Fieldp ? Fieldp->c_type: Cvarp->c_type); } free_display(Cv_display); Fieldp = Cvarp = 0; Indir_level = Field_indir = 0; } cvarx: NAME = { if (Opflag == mdDECL) w_con(NAME, $1->d_elm); else { Cvarp = getcvar($1->d_elm); enter_display(Cv_display, salloc($1->d_elm)); } } | ptr cvarx %prec unaryop = { if ($1->d_elm [1] == '*') Indir_level =+ 1; Indir_level =+ 1; $$ = $2; } | cvarx arraysub %prec LBRKT = { Indir_level =+ 1; } ; ptr: BOP = { if (!sequal($1->d_elm, "*") && !sequal($1->d_elm, "**")) yyserror(Opflag == mdDECL ? "invalid operator in declaration": "invalid operator in C variable", $1); if (Opflag == mdDECL) w_op($1->d_elm); else enter_display(Cv_display, salloc($1->d_elm)); } ; arraysub: LBRKT = { if (Opflag == mdDECL) eat_display(0, '[', ']'); else eat_display(Cv_display, '[', ']'); } ; /* * Special Objects used throughout grammar */ id: c_variable = { if ($1) { if (Cvarp) { if (Fieldp && Fieldp->c_type != opSTRING || !Fieldp && Cvarp->c_type != opSTRING) yyserror("string var expected", $1); else if (Opflag == mdFILENAME) w_var(Cv_display, opSTRING); else if (Opflag == mdINGRES) w_display(Cv_display); else w_var(Cv_display, opIDSTRING); } else if (Opflag == mdINGRES) w_string($1->d_elm, 0); else if (Opflag == mdFILENAME) yyserror("file for a COPY must be a string or string variable", $1); else w_key($1->d_elm); } free_display(Cv_display); Fieldp = Cvarp = 0; } ; idlist: id | idlist comma id ; integer: I2CONST = w_con(I2CONST, $1->d_elm); | c_variable = { if ($1) { if (Cvarp) if (Fieldp && Fieldp->c_type == opINT || Cvarp->c_type == opINT) w_var(Cv_display, opINT); else yyserror("integer variable required", $1); else yyserror("integer variable required", $1); } free_display(Cv_display); } ; int_list: integer | int_list comma integer ; param_tl: LPAREN = { w_op("("); end_quote(); if (Opflag == mdTUPRET) w_key("IIw_left"); else w_key("IIw_right"); eat_display(0, '(', ')'); w_op(";"); begin_quote(); w_op(")"); } ; qualclause: where qual | where c_variable = { if (!$2 || !Cvarp) yyserror("C var (string) expected", $2); else if (Fieldp && Fieldp->c_type == opSTRING || Cvarp->c_type == opSTRING) { w_key(""); /* put out blank after * "where" */ end_quote(); w_op("IIwrite("); w_display(Cv_display); w_op(");"); } else yyserror("var must be string valued for qualification", $2); free_display(Cv_display); Cvarp = Fieldp = 0; } | ; ; qual: lparen qual rparen | luop qual %prec LUOP | qual lbop qual %prec LBOP | clause | ; ; clause: afcn rop afcn | afcn rop afcn bdop afcn ; ctl: id is id | ctl comma id is id ; sconst: SCONST = w_con(SCONST, $1->d_elm); ; tlclause: lparen tlist rparen ; tlist: tlelm | tlelm comma tlist ; tlelm: id is_key afcn | attrib ; /* * Expressions */ afcn: aggrfcn | aggr | attribfcn | afcn bop afcn %prec BOP | lparen afcn rparen | uop afcn %prec unaryop | fop lparen afcn rparen | fbop lparen afcn comma afcn rparen ; aggr: aop lparen afcn qualclause rparen ; aggrfcn: aop lparen afcn by aseq qualclause rparen ; attribfcn: I2CONST = w_con(I2CONST, $1->d_elm); | I4CONST = w_con(I4CONST, $1->d_elm); | F8CONST = w_con(F8CONST, $1->d_elm); | SCONST = w_con(SCONST, $1->d_elm); | cvar | attrib ; aseq: aseq comma afcn | afcn ; attrib: id period id | id period all= { if (Opflag != mdVIEW && Opflag != mdRETRIEVE && Opflag != mdAPPEND) yyserror( "'all' applied to this range variable illegal in this kind of statement", $1); } ; lbop: LBOP = w_key($1->d_elm); ; luop: LUOP = w_key($1->d_elm); ; bdop: BDOP = w_op($1->d_elm); ; rop: EOP = w_op($1->d_elm); | BDOP = w_op($1->d_elm); | IS = w_op("="); ; uop: UOP = w_op($1->d_elm); ; fop: FOP = w_key($1->d_elm); ; fbop: FBOP = w_key($1->d_elm); ; bop: BOP = w_op($1->d_elm); | UOP = w_op($1->d_elm); ; by: BY = w_key($1->d_elm); ; aop: AOP = w_key($1->d_elm); ; /* * Keywords */ append_p_key: PARAM APPEND = { begin_quote(); w_key($2->d_elm); Opflag = mdAPPEND; } ; append_key: APPEND = { Opflag = mdAPPEND; begin_quote(); w_key($1->d_elm); } ; copy_key: COPY = { Opflag = mdCOPY; begin_quote(); w_key($1->d_elm); } ; copy_p_key: PARAM COPY = { Opflag = mdCOPY; begin_quote(); w_key($2->d_elm); } ; cp_kword: INTO = { w_key($1->d_elm); Opflag = mdFILENAME; } | FROM = { w_key($1->d_elm); Opflag = mdFILENAME; } ; create_key: CREATE = { Opflag = mdCREATE; begin_quote(); w_key($1->d_elm); } ; create_p_key: PARAM CREATE = { Opflag = mdCREATE; begin_quote(); w_key($2->d_elm); } ; define_key: DEFINE = { Opflag = mdDEFINE; begin_quote(); w_key($1->d_elm); } ; delete_key: DELETE = { Opflag = mdDELETE; begin_quote(); w_key($1->d_elm); } ; destroy_key: DESTROY = { Opflag = mdDESTROY; begin_quote(); w_key($1->d_elm); } ; help_key: HELP = { Opflag = mdHELP; begin_quote(); w_key($1->d_elm); } ; index_key: INDEX ON = { Opflag = mdINDEX; begin_quote(); w_key($1->d_elm); w_key($2->d_elm); } ; ingres_key: INGRES = { Opflag = mdINGRES; w_new("IIingres("); } ; integ_key: INTEGRITY= { if (Opflag == mdDEFINE) Opflag = mdINTEGRITY; w_key($1->d_elm); } ; is_key: IS = { if (Opflag == mdCTLELM) Opflag = mdTUPRET; w_op("="); } | BY = w_key($1->d_elm); ; modify_key: MODIFY = { Opflag = mdMODIFY; begin_quote(); w_key($1->d_elm); } ; permit_key: PERMIT= { if (Opflag == mdDEFINE) Opflag = mdINTEGRITY; w_key($1->d_elm); } ; print_key: PRINT = { Opflag = mdPRINT; begin_quote(); w_key($1->d_elm); } ; range_of: RANGE OF = { Opflag = mdRANGE; begin_quote(); w_key($1->d_elm); w_key($2->d_elm); } ; replace_key: REPLACE = { Opflag = mdREPLACE; begin_quote(); w_key($1->d_elm); } ; replace_p_key: PARAM REPLACE = { begin_quote(); Opflag = mdREPLACE; w_key($2->d_elm); } ; retrieve_key: RETRIEVE = { Opflag = mdRETRIEVE; begin_quote(); w_key($1->d_elm); } ; retrieve_p_key: PARAM RETRIEVE = { Opflag = mdRETRIEVE; begin_quote(); w_key($2->d_elm); } ; save_key: SAVE = { Opflag = mdSAVE; begin_quote(); w_key($1->d_elm); } ; struct_key: STRUCT = { Opflag = mdDECL; Struct_flag = 1; w_key($1->d_elm); } ; tupret_p_key: PARAM RETRIEVE = { begin_quote(); w_key($2->d_elm); Opflag = mdTUPRET; } ; view_key: VIEW= { if (Opflag == mdDEFINE) Opflag = mdVIEW; w_key($1->d_elm); } ; /* * Noise words and punctuation */ all: ALL= w_key($1->d_elm); ; apkword: INTO | ONTO | TO | ON | ; ; at: AT = w_key($1->d_elm); ; colon: COLON = w_op($1->d_elm); ; comma: COMMA = w_op($1->d_elm); ; delnoise: IN | ON | FROM | ; ; from: FROM = w_key($1->d_elm); ; integnoise: ON | ONTO | IN | OF ; is: IS = w_op("="); ; isnoise: IS | ; ; lbrace: LBRACE = w_op($1->d_elm); ; lparen: LPAREN = w_op($1->d_elm); ; of: OF= w_key($1->d_elm); ; on: ON = w_key($1->d_elm); ; period: PERIOD = w_op($1->d_elm); ; repkword: INTO | IN | ON | ; ; rparen: RPAREN = w_op($1->d_elm); ; to: TO = w_key($1->d_elm); ; retkword: INTO | TO | ; ; until: UNTIL = w_key($1->d_elm); ; where: WHERE = w_key($1->d_elm); ; %% # include "tokens.y"