]> granicus.if.org Git - postgresql/blob - src/interfaces/ecpg/preproc/preproc.y
From: Michael Meskes <meskes@topsystem.de>
[postgresql] / src / interfaces / ecpg / preproc / preproc.y
1 /* Copyright comment */
2 %{
3 #include <stdio.h>
4 #include <string.h>
5 #include <stdlib.h>
6
7 #include "type.h"
8 #include "extern.h"
9
10 static void yyerror(char *);
11
12 /*
13  * Variables containing simple states.
14  */
15 int     debugging = 0;
16 static int      struct_level = 0;
17 static char     *do_str = NULL;
18 static int      do_length = 0;
19
20 /* temporarily store record members while creating the data structure */
21 struct ECPGrecord_member *record_member_list[128] = { NULL };
22
23 /*
24  * Handle the filename and line numbering.
25  */
26 char * input_filename = NULL;
27
28 static void
29 output_line_number()
30 {
31     if (input_filename)
32        fprintf(yyout, "\n#line %d \"%s\"\n", yylineno, input_filename);
33 }
34
35 /*
36  * store the whenever action here
37  */
38 static struct when when_error, when_nf;
39
40 static void
41 print_action(struct when *w)
42 {
43         switch (w->code)
44         {
45                 case W_CONTINUE: fprintf(yyout, "continue;");
46                                  break;
47                 case W_BREAK:    fprintf(yyout, "break;");
48                                  break;
49                 case W_SQLPRINT: fprintf(yyout, "sqlprint();");
50                                  break;
51                 case W_GOTO:     fprintf(yyout, "goto %s;", w->str);
52                                  break;
53                 case W_DO:       fprintf(yyout, "%s;", w->str);
54                                  break;
55                 case W_STOP:     fprintf(yyout, "exit (1);");
56                                  break;
57                 default:         fprintf(yyout, "{/* %d not implemented yet */}", w->code);
58                                  break;
59         }
60 }
61
62 static void
63 whenever_action()
64 {
65         if (when_nf.code != W_NOTHING)
66         {
67                 fprintf(yyout, "\nif (SQLCODE > 0) ");
68                 print_action(&when_nf);
69         }
70         if (when_error.code != W_NOTHING)
71         {
72                 fprintf(yyout, "\nif (SQLCODE < 0) ");
73                 print_action(&when_error);
74         }
75         output_line_number();
76 }
77
78 /*
79  * Handling of the variables.
80  */
81
82 /*
83  * brace level counter
84  */
85 int braces_open;
86
87 /* This is a linked list of the variable names and types. */
88 struct variable
89 {
90     char * name;
91     struct ECPGtype * type;
92     int brace_level;
93     struct variable * next;
94 };
95
96 static struct variable * allvariables = NULL;
97
98 static struct variable *
99 find_variable(char * name)
100 {
101     struct variable * p;
102
103     for (p = allvariables; p; p = p->next)
104     {
105         if (strcmp(p->name, name) == 0)
106             return p;
107     }
108
109     {
110         char * errorstring = (char *) malloc(strlen(name) + 100);
111
112         sprintf(errorstring, "The variable :%s is not declared.", name);
113
114         yyerror(errorstring);
115     }
116     return NULL;
117 }
118
119
120 static void
121 new_variable(const char * name, struct ECPGtype * type)
122 {
123     struct variable * p = (struct variable*) malloc(sizeof(struct variable));
124
125     p->name = strdup(name);
126     p->type = type;
127     p->brace_level = braces_open;
128
129     p->next = allvariables;
130     allvariables = p;
131 }
132
133 static void
134 remove_variables(int brace_level)
135 {
136     struct variable * p, *prev;
137
138     for (p = prev = allvariables; p; p = p ? p->next : NULL)
139     {
140         if (p->brace_level >= brace_level)
141         {
142             /* remove it */
143             if (p == allvariables)
144                 prev = allvariables = p->next;
145             else
146                 prev->next = p->next;
147
148             ECPGfree_type(p->type);
149             free(p->name);
150             free(p);
151             p = prev;
152         }
153         else
154             prev = p;
155     }
156 }
157
158
159 /*
160  * Here are the variables that need to be handled on every request.
161  * These are of two kinds: input and output.
162  * I will make two lists for them.
163  */
164 struct arguments {
165     struct variable * variable;
166     struct arguments * next;
167 };
168
169
170 static struct arguments * argsinsert = NULL;
171 static struct arguments * argsresult = NULL;
172
173 static void
174 reset_variables(void)
175 {
176     argsinsert = NULL;
177     argsresult = NULL;
178 }
179
180
181 /* Add a variable to a request. */
182 static void
183 add_variable(struct arguments ** list, struct variable * var)
184 {
185     struct arguments * p = (struct arguments *)malloc(sizeof(struct arguments));
186     p->variable = var;
187     p->next = *list;
188     *list = p;
189 }
190
191
192 /* Dump out a list of all the variable on this list.
193    This is a recursive function that works from the end of the list and
194    deletes the list as we go on.
195  */
196 static void
197 dump_variables(struct arguments * list)
198 {
199     if (list == NULL)
200     {
201         return;
202     }
203
204     /* The list is build up from the beginning so lets first dump the
205        end of the list:
206      */
207
208     dump_variables(list->next);
209
210     /* Then the current element. */
211     ECPGdump_a_type(yyout, list->variable->name, list->variable->type, NULL);
212
213     /* Then release the list element. */
214     free(list);
215 }
216 %}
217
218 %union {
219     int                         tagname;
220     struct ECPGtemp_type        type;
221     char *                      symbolname;
222     long                        indexsize;
223     enum ECPGttype              type_enum;
224     struct when                 action;
225 }
226
227 %token <tagname> SQL_START SQL_SEMI SQL_STRING SQL_INTO
228 %token <tagname> SQL_BEGIN SQL_END SQL_DECLARE SQL_SECTION SQL_INCLUDE 
229 %token <tagname> SQL_CONNECT SQL_OPEN SQL_EXECUTE SQL_IMMEDIATE
230 %token <tagname> SQL_COMMIT SQL_ROLLBACK SQL_RELEASE SQL_WORK SQL_WHENEVER
231 %token <tagname> SQL_SQLERROR SQL_NOT_FOUND SQL_CONTINUE
232 %token <tagname> SQL_DO SQL_GOTO SQL_SQLPRINT SQL_STOP
233
234 %token <tagname> S_SYMBOL S_LENGTH S_ANYTHING S_LABEL
235 %token <tagname> S_VARCHAR S_VARCHAR2
236 %token <tagname> S_EXTERN S_STATIC S_AUTO S_CONST S_REGISTER S_STRUCT
237 %token <tagname> S_UNSIGNED S_SIGNED
238 %token <tagname> S_LONG S_SHORT S_INT S_CHAR S_FLOAT S_DOUBLE S_BOOL
239 %token <tagname> '[' ']' ';' ',' '{' '}' '=' '*' '(' ')'
240
241 %type <type> type type_detailed varchar_type simple_type struct_type string_type
242 /* % type <type> array_type pointer_type */
243 %type <symbolname> symbol label
244 %type <tagname> maybe_storage_clause varchar_tag db_name
245 %type <type_enum> simple_tag char_tag
246 %type <indexsize> index length
247 %type <action> action
248 %type <tagname> canything sqlanything both_anything vartext commit_release
249
250 %%
251 prog : statements;
252
253 statements : /* empty */
254            | statements statement;
255
256 statement : sqldeclaration
257           | sqlinclude
258           | sqlconnect
259           | sqlopen
260           | sqlcommit
261           | sqlrollback
262           | sqlexecute
263           | sqlwhenever
264           | sqlstatement
265           | cthing
266           | blockstart
267           | blockend;
268
269 sqldeclaration : sql_startdeclare
270                  variable_declarations
271                  sql_enddeclare;
272
273 sql_startdeclare : SQL_START SQL_BEGIN SQL_DECLARE SQL_SECTION SQL_SEMI {
274     fprintf(yyout, "/* exec sql begin declare section */\n"); 
275     output_line_number();
276 }
277
278 sql_enddeclare : SQL_START SQL_END SQL_DECLARE SQL_SECTION SQL_SEMI {
279     fprintf(yyout,"/* exec sql end declare section */\n"); 
280     output_line_number();
281 }
282
283 variable_declarations : /* empty */
284                       | variable_declarations variable_declaration;
285
286 /* Here is where we can enter support for typedef. */
287 variable_declaration : type initializer ';'     { 
288     /* don't worry about our list when we're working on a struct */
289     if (struct_level == 0)
290     {
291         new_variable($<type>1.name, $<type>1.typ);
292         free((void *)$<type>1.name);
293     }
294     fprintf(yyout, ";"); 
295 }
296
297 initializer : /*empty */
298             | '=' {fwrite(yytext, yyleng, 1, yyout);} vartext;
299
300 vartext : /* empty */ {}
301         | vartext both_anything {
302         if (do_length == 0)
303                 fwrite(yytext, yyleng, 1, yyout);
304         else
305         {
306                 if (strlen(do_str) + yyleng + 1 >= do_length)
307                         do_str = mm_realloc(do_str, do_length += yyleng);
308
309                 strcat(do_str, yytext);
310         }
311 }
312
313 symbol : S_SYMBOL { 
314     char * name = (char *)malloc(yyleng + 1);
315
316     strncpy(name, yytext, yyleng);
317     name[yyleng] = '\0';
318
319     $<symbolname>$ = name;
320 }
321
322 type : maybe_storage_clause type_detailed { $<type>$ = $<type>2; };
323 type_detailed : varchar_type { $<type>$ = $<type>1; }
324               | simple_type { $<type>$ = $<type>1; }
325               | string_type { $<type>$ = $<type>1; }
326 /*            | array_type {$<type>$ = $<type>1; }
327               | pointer_type {$<type>$ = $<type>1; }*/
328               | struct_type {$<type>$ = $<type>1; };
329
330 varchar_type : varchar_tag symbol index {
331     if ($<indexsize>3 > 0L)
332         fprintf(yyout, "struct varchar_%s { int len; char arr[%ld]; } %s", $<symbolname>2, $<indexsize>3, $<symbolname>2);
333     else
334         fprintf(yyout, "struct varchar_%s { int len; char arr[]; } %s", $<symbolname>2, $<symbolname>2);
335     if (struct_level == 0)
336     {
337         $<type>$.name = $<symbolname>2;
338         $<type>$.typ = ECPGmake_varchar_type(ECPGt_varchar, $<indexsize>3);
339     }
340     else
341         ECPGmake_record_member($<symbolname>2, ECPGmake_varchar_type(ECPGt_varchar, $<indexsize>3), &(record_member_list[struct_level-1]));
342 }
343
344 varchar_tag : S_VARCHAR { $<tagname>$ = $<tagname>1; }
345             | S_VARCHAR2 { $<tagname>$ = $<tagname>1; };
346
347 simple_type : simple_tag symbol {
348     fprintf(yyout, "%s %s", ECPGtype_name($<type_enum>1), $<symbolname>2);
349     if (struct_level == 0)
350     {
351         $<type>$.name = $<symbolname>2;
352         $<type>$.typ = ECPGmake_simple_type($<type_enum>1, 1);
353     }
354     else
355         ECPGmake_record_member($<symbolname>2, ECPGmake_simple_type($<type_enum>1, 1), &(record_member_list[struct_level-1]));
356 }
357
358 string_type : char_tag symbol index {
359     if ($<indexsize>3 > 0L)
360             fprintf(yyout, "%s %s [%ld]", ECPGtype_name($<type_enum>1), $<symbolname>2, $<indexsize>3);
361     else
362             fprintf(yyout, "%s %s []", ECPGtype_name($<type_enum>1), $<symbolname>2);
363     if (struct_level == 0)
364     {
365         $<type>$.name = $<symbolname>2;
366         $<type>$.typ = ECPGmake_simple_type($<type_enum>1, $<indexsize>3);
367     }
368     else
369         ECPGmake_record_member($<symbolname>2, ECPGmake_simple_type($<type_enum>1, $<indexsize>3), &(record_member_list[struct_level-1]));
370 }
371         |       char_tag '*' symbol {
372     fprintf(yyout, "%s *%s", ECPGtype_name($<type_enum>1), $<symbolname>3);
373     if (struct_level == 0)
374     {
375         $<type>$.name = $<symbolname>3;
376         $<type>$.typ = ECPGmake_simple_type($<type_enum>1, 0);
377     }
378     else
379         ECPGmake_record_member($<symbolname>3, ECPGmake_simple_type($<type_enum>1, 0), &(record_member_list[struct_level-1]));
380 }
381         |       char_tag symbol {
382     fprintf(yyout, "%s %s", ECPGtype_name($<type_enum>1), $<symbolname>2);
383     if (struct_level == 0)
384     {
385         $<type>$.name = $<symbolname>2;
386         $<type>$.typ = ECPGmake_simple_type($<type_enum>1, 1);
387     }
388     else
389         ECPGmake_record_member($<symbolname>2, ECPGmake_simple_type($<type_enum>1, 1), &(record_member_list[struct_level-1]));
390 }
391
392 char_tag : S_CHAR { $<type_enum>$ = ECPGt_char; }
393            | S_UNSIGNED S_CHAR { $<type_enum>$ = ECPGt_unsigned_char; }
394
395 /*
396 array_type : simple_tag symbol index {
397     if ($<indexsize>3 > 0)
398             fprintf(yyout, "%s %s [%ld]", ECPGtype_name($<type_enum>1), $<symbolname>2, $<indexsize>3);
399     else
400             fprintf(yyout, "%s %s []", ECPGtype_name($<type_enum>1), $<symbolname>2);
401     if (struct_level == 0)
402     {
403         $<type>$.name = $<symbolname>2;
404         $<type>$.typ = ECPGmake_array_type(ECPGmake_simple_type($<type_enum>1), $<indexsize>3);
405     }
406     else
407         ECPGmake_record_member($<symbolname>2, ECPGmake_array_type(ECPGmake_simple_type($<type_enum>1), $<indexsize>3), &(record_member_list[struct_level-1]));
408 }
409
410 pointer_type : simple_tag '*' symbol {
411     fprintf(yyout, "%s * %s", ECPGtype_name($<type_enum>1), $<symbolname>3);
412     if (struct_level == 0)
413     {
414         $<type>$.name = $<symbolname>3;
415         $<type>$.typ = ECPGmake_array_type(ECPGmake_simple_type($<type_enum>1), 0);
416     }
417     else
418         ECPGmake_record_member($<symbolname>3, ECPGmake_array_type(ECPGmake_simple_type($<type_enum>1), 0), &(record_member_list[struct_level-1]));
419 }
420 */
421
422 s_struct : S_STRUCT symbol {
423     struct_level++;
424     fprintf(yyout, "struct %s {", $<symbolname>2);
425 }
426
427 struct_type : s_struct '{' variable_declarations '}' symbol {
428     struct_level--;
429     if (struct_level == 0)
430     {
431         $<type>$.name = $<symbolname>5;
432         $<type>$.typ = ECPGmake_record_type(record_member_list[struct_level]);
433     }
434     else
435         ECPGmake_record_member($<symbolname>5, ECPGmake_record_type(record_member_list[struct_level]), &(record_member_list[struct_level-1])); 
436     fprintf(yyout, "} %s", $<symbolname>5);
437     record_member_list[struct_level] = NULL;
438 }
439
440 simple_tag : S_SHORT { $<type_enum>$ = ECPGt_short; }
441            | S_UNSIGNED S_SHORT { $<type_enum>$ = ECPGt_unsigned_short; }
442            | S_INT { $<type_enum>$ = ECPGt_int; }
443            | S_UNSIGNED S_INT { $<type_enum>$ = ECPGt_unsigned_int; }
444            | S_LONG { $<type_enum>$ = ECPGt_long; }
445            | S_UNSIGNED S_LONG { $<type_enum>$ = ECPGt_unsigned_long; }
446            | S_FLOAT { $<type_enum>$ = ECPGt_float; }
447            | S_DOUBLE { $<type_enum>$ = ECPGt_double; }
448            | S_BOOL { $<type_enum>$ = ECPGt_bool; };
449
450 maybe_storage_clause : S_EXTERN { fwrite(yytext, yyleng, 1, yyout); }
451                        | S_STATIC { fwrite(yytext, yyleng, 1, yyout); }
452                        | S_SIGNED { fwrite(yytext, yyleng, 1, yyout); }
453                        | S_CONST { fwrite(yytext, yyleng, 1, yyout); }
454                        | S_REGISTER { fwrite(yytext, yyleng, 1, yyout); }
455                        | S_AUTO { fwrite(yytext, yyleng, 1, yyout); }
456                        | /* empty */ { };
457          
458 index : '[' length ']' { $<indexsize>$ = $<indexsize>2; }
459         | '[' ']' { $<indexsize>$ = 0L; }
460
461 length : S_LENGTH { $<indexsize>$ = atol(yytext); }
462
463 sqlinclude : SQL_START SQL_INCLUDE { fprintf(yyout, "#include \""); }
464         filename SQL_SEMI { fprintf(yyout, ".h\""); output_line_number(); };
465
466 filename : cthing
467          | filename cthing;
468
469 sqlconnect : SQL_START SQL_CONNECT { fprintf(yyout, "ECPGconnect("); }
470              db_name
471              SQL_SEMI { fprintf(yyout, ");"); whenever_action();}
472
473 db_name : SQL_STRING { fprintf(yyout, "\""); fwrite(yytext + 1, yyleng - 2, 1, yyout); fprintf(yyout, "\""); }
474         | ':' symbol { /* check if we have a char variable */
475                         struct variable *p = find_variable($<symbolname>2);
476                         enum ECPGttype typ = p->type->typ;
477
478                         /* if array see what's inside */
479                         if (typ == ECPGt_array)
480                                 typ = p->type->u.element->typ;
481
482                         if (typ != ECPGt_char && typ != ECPGt_unsigned_char)
483                                 yyerror("invalid datatype");
484
485                         fprintf(yyout, "%s", $<symbolname>2);
486         }
487
488 /* Open is an open cursor. Removed. */
489 sqlopen : SQL_START SQL_OPEN sqlgarbage SQL_SEMI { output_line_number(); };
490
491 sqlgarbage : /* Empty */
492            | sqlgarbage sqlanything;
493             
494
495 sqlcommit : SQL_START commit_release SQL_SEMI {
496     fprintf(yyout, "ECPGcommit(__LINE__);"); 
497     whenever_action();
498 }
499
500 commit_release : SQL_COMMIT
501                | SQL_COMMIT SQL_RELEASE
502                | SQL_COMMIT SQL_WORK SQL_RELEASE;
503
504 sqlrollback : SQL_START SQL_ROLLBACK SQL_SEMI {
505     fprintf(yyout, "ECPGrollback(__LINE__);");
506     whenever_action();
507 };
508
509 sqlexecute : SQL_START SQL_EXECUTE SQL_IMMEDIATE  ':' symbol  SQL_SEMI {  
510     fprintf(yyout, "ECPGdo(__LINE__, %s, ECPGt_EOIT, ECPGt_EORT );", $5);
511     whenever_action();
512 };
513
514 sqlwhenever : SQL_START SQL_WHENEVER SQL_SQLERROR {
515         fprintf(yyout, "/* exec sql whenever sqlerror ");
516 }       action SQL_SEMI{
517         when_error.code = $<action>5.code;
518         when_error.str = $<action>5.str;
519         fprintf(yyout, "; */\n");
520 }
521         | SQL_START SQL_WHENEVER SQL_NOT_FOUND {
522         fprintf(yyout, "/* exec sql whenever not found ");
523 }        action SQL_SEMI{
524         when_nf.code = $<action>5.code;
525         when_nf.str=$<action>5.str;
526         fprintf(yyout, "; */\n");
527 }
528
529 action : SQL_CONTINUE {
530         $<action>$.code = W_NOTHING;
531         $<action>$.str = NULL;
532         fprintf(yyout, "continue");
533 }
534        | SQL_SQLPRINT {
535         $<action>$.code = W_SQLPRINT;
536         $<action>$.str = NULL;
537         fprintf(yyout, "sqlprint");
538 }
539        | SQL_STOP {
540         $<action>$.code = W_STOP;
541         $<action>$.str = NULL;
542         fprintf(yyout, "stop");
543 }
544        | SQL_GOTO label {
545         $<action>$.code = W_GOTO;
546         $<action>$.str = $<symbolname>2;
547         fprintf(yyout, "goto %s", $<symbolname>2);
548 }
549        | SQL_GOTO symbol {
550         $<action>$.code = W_GOTO;
551         $<action>$.str = $<symbolname>2;
552         fprintf(yyout, "goto %s", $<symbolname>2);
553 }
554        | SQL_DO symbol '(' {
555         do_str = (char *) mm_alloc(do_length = strlen($<symbolname>2) + 4);
556         sprintf(do_str, "%s (", $<symbolname>2);
557 } vartext ')' {
558         do_str[strlen(do_str)+1]='\0';
559         do_str[strlen(do_str)]=')';
560         $<action>$.code = W_DO;
561         $<action>$.str = do_str;
562         fprintf(yyout, "do %s", do_str);
563         do_str = NULL;
564         do_length = 0;
565 }
566
567 label : S_LABEL {
568     char * name = (char *)malloc(yyleng + 1);
569
570     strncpy(name, yytext, yyleng);
571     name[yyleng] = '\0';
572
573     $<symbolname>$ = name;
574 }
575
576 sqlstatement : SQL_START { /* Reset stack */
577     reset_variables();
578     fprintf(yyout, "ECPGdo(__LINE__, \"");
579 } sqlstatement_words SQL_SEMI {  
580     /* Dump */
581     fprintf(yyout, "\", ");                
582     dump_variables(argsinsert);
583     fprintf(yyout, "ECPGt_EOIT, ");
584     dump_variables(argsresult);
585     fprintf(yyout, "ECPGt_EORT );");
586     whenever_action();
587 };
588
589 sqlstatement_words : sqlstatement_word
590                    | sqlstatement_words sqlstatement_word;
591         
592 sqlstatement_word : ':' symbol 
593                   {
594                       add_variable(&argsinsert, find_variable($2));
595                       fprintf(yyout, " ;; ");
596                   }
597                   | SQL_INTO into_list { }
598                   | sqlanything 
599                   { 
600                       fwrite(yytext, yyleng, 1, yyout);
601                       fwrite(" ", 1, 1, yyout);
602                   }
603                   | SQL_INTO sqlanything 
604                   {
605                       fprintf(yyout, " into ");
606                       fwrite(yytext, yyleng, 1, yyout);
607                       fwrite(" ", 1, 1, yyout);
608                   };
609
610 into_list : ':' symbol {
611     add_variable(&argsresult, find_variable($2)); 
612 }
613           | into_list ',' ':' symbol {
614     add_variable(&argsresult, find_variable($4)); 
615 };
616
617 cthing : canything {
618     fwrite(yytext, yyleng, 1, yyout);
619 }
620
621 canything : both_anything
622           | SQL_INTO
623           | ';';
624
625 sqlanything : both_anything;
626
627 both_anything : S_LENGTH | S_VARCHAR | S_VARCHAR2 
628           | S_LONG | S_SHORT | S_INT | S_CHAR | S_FLOAT | S_DOUBLE | S_BOOL 
629           | SQL_OPEN | SQL_CONNECT
630           | SQL_STRING
631           | SQL_BEGIN | SQL_END 
632           | SQL_DECLARE | SQL_SECTION 
633           | SQL_INCLUDE 
634           | S_SYMBOL | S_LABEL
635           | S_STATIC | S_EXTERN | S_AUTO | S_CONST | S_REGISTER | S_STRUCT
636           | '[' | ']' | ',' | '=' | '*' | '(' | ')'
637           | S_ANYTHING;
638
639 blockstart : '{' {
640     braces_open++;
641     fwrite(yytext, yyleng, 1, yyout);
642 }
643
644 blockend : '}' {
645     remove_variables(braces_open--);
646     fwrite(yytext, yyleng, 1, yyout);
647 }
648 %%
649
650 static void yyerror(char * error)
651 {
652     fprintf(stderr, "%s in line %d\n", error, yylineno);
653     exit(1);
654 }