]> granicus.if.org Git - postgresql/blob - src/interfaces/ecpg/preproc/preproc.y
670ea9b8c6a5283a6828b74c2554293afdc1e41e
[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
18 /* temporarily store record members while creating the data structure */
19 struct ECPGrecord_member *record_member_list[128] = { NULL };
20
21 /*
22  * Handle the filename and line numbering.
23  */
24 char * input_filename = NULL;
25
26 void
27 output_line_number()
28 {
29     if (input_filename)
30        fprintf(yyout, "\n#line %d \"%s\"\n", yylineno, input_filename);
31 }
32
33 /*
34  * Handling of the variables.
35  */
36
37 /*
38  * brace level counter
39  */
40 int braces_open;
41
42 /* This is a linked list of the variable names and types. */
43 struct variable
44 {
45     char * name;
46     struct ECPGtype * type;
47     int brace_level;
48     struct variable * next;
49 };
50
51 static struct variable * allvariables = NULL;
52
53 static struct variable *
54 find_variable(char * name)
55 {
56     struct variable * p;
57
58     for (p = allvariables; p; p = p->next)
59     {
60         if (strcmp(p->name, name) == 0)
61             return p;
62     }
63
64     {
65         char * errorstring = (char *) malloc(strlen(name) + 100);
66
67         sprintf(errorstring, "The variable :%s is not declared.", name);
68
69         yyerror(errorstring);
70     }
71     return NULL;
72 }
73
74
75 static void
76 new_variable(const char * name, struct ECPGtype * type)
77 {
78     struct variable * p = (struct variable*) malloc(sizeof(struct variable));
79
80     p->name = strdup(name);
81     p->type = type;
82     p->brace_level = braces_open;
83
84     p->next = allvariables;
85     allvariables = p;
86 }
87
88 static void
89 remove_variables(int brace_level)
90 {
91     struct variable * p, *prev;
92
93     for (p = prev = allvariables; p; p = p ? p->next : NULL)
94     {
95         if (p->brace_level >= brace_level)
96         {
97             /* remove it */
98             if (p == allvariables)
99                 prev = allvariables = p->next;
100             else
101                 prev->next = p->next;
102
103             ECPGfree_type(p->type);
104             free(p->name);
105             free(p);
106             p = prev;
107         }
108         else
109             prev = p;
110     }
111 }
112
113
114 /*
115  * Here are the variables that need to be handled on every request.
116  * These are of two kinds: input and output.
117  * I will make two lists for them.
118  */
119 struct arguments {
120     struct variable * variable;
121     struct arguments * next;
122 };
123
124
125 static struct arguments * argsinsert = NULL;
126 static struct arguments * argsresult = NULL;
127
128 void
129 reset_variables()
130 {
131     argsinsert = NULL;
132     argsresult = NULL;
133 }
134
135
136 /* Add a variable to a request. */
137 void
138 add_variable(struct arguments ** list, struct variable * var)
139 {
140     struct arguments * p = (struct arguments *)malloc(sizeof(struct arguments));
141     p->variable = var;
142     p->next = *list;
143     *list = p;
144 }
145
146
147 /* Dump out a list of all the variable on this list.
148    This is a recursive function that works from the end of the list and
149    deletes the list as we go on.
150  */
151 void
152 dump_variables(struct arguments * list)
153 {
154     if (list == NULL)
155     {
156         return;
157     }
158
159     /* The list is build up from the beginning so lets first dump the
160        end of the list:
161      */
162
163     dump_variables(list->next);
164
165     /* Then the current element. */
166     ECPGdump_a_type(yyout, list->variable->name, list->variable->type, NULL);
167
168     /* Then release the list element. */
169     free(list);
170 }
171 %}
172
173 %union {
174     int                         tagname;
175     struct ECPGtemp_type        type;
176     char *                      symbolname;
177     int                         indexsize;
178     enum ECPGttype              type_enum;
179 }
180
181 %token <tagname> SQL_START SQL_SEMI SQL_STRING SQL_INTO
182 %token <tagname> SQL_BEGIN SQL_END SQL_DECLARE SQL_SECTION SQL_INCLUDE 
183 %token <tagname> SQL_CONNECT SQL_OPEN SQL_EXECUTE SQL_IMMEDIATE
184 %token <tagname> SQL_COMMIT SQL_ROLLBACK SQL_RELEASE SQL_WORK
185
186 %token <tagname> S_SYMBOL S_LENGTH S_ANYTHING
187 %token <tagname> S_VARCHAR S_VARCHAR2
188 %token <tagname> S_EXTERN S_STATIC S_AUTO S_CONST S_REGISTER S_STRUCT
189 %token <tagname> S_UNSIGNED S_SIGNED
190 %token <tagname> S_LONG S_SHORT S_INT S_CHAR S_FLOAT S_DOUBLE S_BOOL
191 %token <tagname> '[' ']' ';' ',' '{' '}' '=' '*'
192
193 %type <type> type type_detailed varchar_type simple_type array_type struct_type
194 %type <symbolname> symbol
195 %type <tagname> maybe_storage_clause varchar_tag db_name
196 %type <type_enum> simple_tag
197 %type <indexsize> index length
198 %type <tagname> canything sqlanything both_anything vartext commit_release
199
200
201 %%
202 prog : statements;
203
204 statements : /* empty */
205            | statements statement;
206
207 statement : sqldeclaration
208           | sqlinclude
209           | sqlconnect
210           | sqlopen
211           | sqlcommit
212           | sqlrollback
213           | sqlexecute
214           | sqlstatement
215           | cthing
216           | blockstart
217           | blockend;
218
219 sqldeclaration : sql_startdeclare
220                  variable_declarations
221                  sql_enddeclare;
222
223 sql_startdeclare : SQL_START SQL_BEGIN SQL_DECLARE SQL_SECTION SQL_SEMI {
224     fprintf(yyout, "/* exec sql begin declare section */\n"); 
225     output_line_number();
226 }
227
228 sql_enddeclare : SQL_START SQL_END SQL_DECLARE SQL_SECTION SQL_SEMI {
229     fprintf(yyout,"/* exec sql end declare section */\n"); 
230     output_line_number();
231 }
232
233 variable_declarations : /* empty */
234                       | variable_declarations variable_declaration;
235
236 /* Here is where we can enter support for typedef. */
237 variable_declaration : type initializer ';'     { 
238     /* don't worry about our list when we're working on a struct */
239     if (struct_level == 0)
240     {
241         new_variable($<type>1.name, $<type>1.typ);
242         free($<type>1.name);
243     }
244     fprintf(yyout, ";"); 
245 }
246
247 initializer : /*empty */
248             | '=' {fwrite(yytext, yyleng, 1, yyout);} vartext;
249
250 vartext : both_anything {fwrite(yytext, yyleng, 1, yyout);}
251         | vartext both_anything {fwrite(yytext, yyleng, 1, yyout);}
252
253 symbol : S_SYMBOL { 
254     char * name = (char *)malloc(yyleng + 1);
255
256     strncpy(name, yytext, yyleng);
257     name[yyleng] = '\0';
258
259     $<symbolname>$ = name;
260 }
261
262 type : maybe_storage_clause type_detailed { $<type>$ = $<type>2; };
263 type_detailed : varchar_type { $<type>$ = $<type>1; }
264               | simple_type { $<type>$ = $<type>1; }
265               | array_type {$<type>$ = $<type>1; }
266               | pointer_type {$<type>$ = $<type>1; }
267               | struct_type {$<type>$ = $<type>1; };
268
269 varchar_type : varchar_tag symbol index {
270     if ($<indexsize>3 > 0)
271         fprintf(yyout, "struct varchar_%s { int len; char arr[%d]; } %s", $<symbolname>2, $<indexsize>3, $<symbolname>2);
272     else
273         fprintf(yyout, "struct varchar_%s { int len; char arr[%d]; } %s", $<symbolname>2, $<indexsize>3, $<symbolname>2);
274     if (struct_level == 0)
275     {
276         $<type>$.name = $<symbolname>2;
277         $<type>$.typ = ECPGmake_varchar_type(ECPGt_varchar, $<indexsize>3);
278     }
279     else
280         ECPGmake_record_member($<symbolname>2, ECPGmake_varchar_type(ECPGt_varchar, $<indexsize>3), &(record_member_list[struct_level-1]));
281 }
282
283 varchar_tag : S_VARCHAR { $<tagname>$ = $<tagname>1; }
284             | S_VARCHAR2 { $<tagname>$ = $<tagname>1; };
285
286 simple_type : simple_tag symbol {
287     fprintf(yyout, "%s %s", ECPGtype_name($<type_enum>1), $<symbolname>2);
288     if (struct_level == 0)
289     {
290         $<type>$.name = $<symbolname>2;
291         $<type>$.typ = ECPGmake_simple_type($<type_enum>1);
292     }
293     else
294         ECPGmake_record_member($<symbolname>2, ECPGmake_simple_type($<type_enum>1), &(record_member_list[struct_level-1]));
295 }
296
297 array_type : simple_tag symbol index {
298     if ($<indexsize>3 > 0)
299             fprintf(yyout, "%s %s [%d]", ECPGtype_name($<type_enum>1), $<symbolname>2, $<indexsize>3);
300     else
301             fprintf(yyout, "%s %s []", ECPGtype_name($<type_enum>1), $<symbolname>2);
302     if (struct_level == 0)
303     {
304         $<type>$.name = $<symbolname>2;
305         $<type>$.typ = ECPGmake_array_type(ECPGmake_simple_type($<type_enum>1), $<indexsize>3);
306     }
307     else
308         ECPGmake_record_member($<symbolname>2, ECPGmake_array_type(ECPGmake_simple_type($<type_enum>1), $<indexsize>3), &(record_member_list[struct_level-1]));
309 }
310
311 pointer_type : simple_tag '*' symbol {
312     fprintf(yyout, "%s * %s", ECPGtype_name($<type_enum>1), $<symbolname>3);
313     if (struct_level == 0)
314     {
315         $<type>$.name = $<symbolname>3;
316         $<type>$.typ = ECPGmake_array_type(ECPGmake_simple_type($<type_enum>1), 0);
317     }
318     else
319         ECPGmake_record_member($<symbolname>3, ECPGmake_array_type(ECPGmake_simple_type($<type_enum>1), 0), &(record_member_list[struct_level-1]));
320 }
321
322 s_struct : S_STRUCT symbol {
323     struct_level++;
324     fprintf(yyout, "struct %s {", $<symbolname>2);
325 }
326
327 struct_type : s_struct '{' variable_declarations '}' symbol {
328     struct_level--;
329     if (struct_level == 0)
330     {
331         $<type>$.name = $<symbolname>5;
332         $<type>$.typ = ECPGmake_record_type(record_member_list[struct_level]);
333     }
334     else
335         ECPGmake_record_member($<symbolname>5, ECPGmake_record_type(record_member_list[struct_level]), &(record_member_list[struct_level-1])); 
336     fprintf(yyout, "} %s", $<symbolname>5);
337     record_member_list[struct_level] = NULL;
338 }
339
340 simple_tag : S_CHAR { $<type_enum>$ = ECPGt_char; }
341            | S_UNSIGNED S_CHAR { $<type_enum>$ = ECPGt_unsigned_char; }
342            | S_SHORT { $<type_enum>$ = ECPGt_short; }
343            | S_UNSIGNED S_SHORT { $<type_enum>$ = ECPGt_unsigned_short; }
344            | S_INT { $<type_enum>$ = ECPGt_int; }
345            | S_UNSIGNED S_INT { $<type_enum>$ = ECPGt_unsigned_int; }
346            | S_LONG { $<type_enum>$ = ECPGt_long; }
347            | S_UNSIGNED S_LONG { $<type_enum>$ = ECPGt_unsigned_long; }
348            | S_FLOAT { $<type_enum>$ = ECPGt_float; }
349            | S_DOUBLE { $<type_enum>$ = ECPGt_double; }
350            | S_BOOL { $<type_enum>$ = ECPGt_bool; };
351
352 maybe_storage_clause : S_EXTERN { fwrite(yytext, yyleng, 1, yyout); }
353                        | S_STATIC { fwrite(yytext, yyleng, 1, yyout); }
354                        | S_CONST { fwrite(yytext, yyleng, 1, yyout); }
355                        | S_REGISTER { fwrite(yytext, yyleng, 1, yyout); }
356                        | S_AUTO { fwrite(yytext, yyleng, 1, yyout); }
357                        | /* empty */ { };
358          
359 index : '[' length ']' { $<indexsize>$ = $<indexsize>2; }
360         | '[' ']' { $<indexsize>$ = 0; }
361
362 length : S_LENGTH { $<indexsize>$ = atoi(yytext); }
363
364 sqlinclude : SQL_START SQL_INCLUDE { fprintf(yyout, "#include \""); }
365         filename SQL_SEMI { fprintf(yyout, ".h\""); output_line_number(); };
366
367 filename : cthing
368          | filename cthing;
369
370 sqlconnect : SQL_START SQL_CONNECT { fprintf(yyout, "ECPGconnect("); }
371              db_name
372              SQL_SEMI { fprintf(yyout, ");"); output_line_number();}
373
374 db_name : SQL_STRING { fprintf(yyout, "\""); fwrite(yytext + 1, yyleng - 2, 1, yyout); fprintf(yyout, "\""); }
375         | ':' symbol { /* check if we have a char variabnle */
376                         struct variable *p = find_variable($<symbolname>2);
377                         enum ECPGttype typ = p->type->typ;
378
379                         /* if array see what's inside */
380                         if (typ == ECPGt_array)
381                                 typ = p->type->u.element->typ;
382
383                         if (typ != ECPGt_char && typ != ECPGt_unsigned_char)
384                                 yyerror("invalid datatype");
385
386                         fprintf(yyout, "%s", $<symbolname>2);
387         }
388
389 /* Open is an open cursor. Removed. */
390 sqlopen : SQL_START SQL_OPEN sqlgarbage SQL_SEMI { output_line_number(); };
391
392 sqlgarbage : /* Empty */
393            | sqlgarbage sqlanything;
394             
395
396 sqlcommit : SQL_START commit_release SQL_SEMI {
397     fprintf(yyout, "ECPGcommit(__LINE__);"); 
398     output_line_number();
399 }
400
401 commit_release : SQL_COMMIT
402                | SQL_COMMIT SQL_RELEASE
403                | SQL_COMMIT SQL_WORK SQL_RELEASE;
404
405 sqlrollback : SQL_START SQL_ROLLBACK SQL_SEMI {
406     fprintf(yyout, "ECPGrollback(__LINE__);");
407     output_line_number();
408 };
409
410 sqlexecute : SQL_START { /* Reset stack */
411     reset_variables();
412     fprintf(yyout, "ECPGdo(__LINE__, \"");
413 } SQL_EXECUTE SQL_IMMEDIATE sqlstatement_words SQL_SEMI {  
414     /* Dump */
415     fprintf(yyout, "\", ");                
416     dump_variables(argsinsert);
417     fprintf(yyout, "ECPGt_EOIT, ");
418     dump_variables(argsresult);
419     fprintf(yyout, "ECPGt_EORT );");
420     output_line_number();
421 };
422
423 sqlstatement : SQL_START { /* Reset stack */
424     reset_variables();
425     fprintf(yyout, "ECPGdo(__LINE__, \"");
426 } sqlstatement_words SQL_SEMI {  
427     /* Dump */
428     fprintf(yyout, "\", ");                
429     dump_variables(argsinsert);
430     fprintf(yyout, "ECPGt_EOIT, ");
431     dump_variables(argsresult);
432     fprintf(yyout, "ECPGt_EORT );");
433     output_line_number();
434 };
435
436 sqlstatement_words : sqlstatement_word
437                    | sqlstatement_words sqlstatement_word;
438         
439 sqlstatement_word : ':' symbol 
440                   {
441                       add_variable(&argsinsert, find_variable($2));
442                       fprintf(yyout, " ;; ");
443                   }
444                   | SQL_INTO into_list { }
445                   | sqlanything 
446                   { 
447                       fwrite(yytext, yyleng, 1, yyout);
448                       fwrite(" ", 1, 1, yyout);
449                   }
450                   | SQL_INTO sqlanything 
451                   {
452                       fprintf(yyout, " into ");
453                       fwrite(yytext, yyleng, 1, yyout);
454                       fwrite(" ", 1, 1, yyout);
455                   };
456
457 into_list : ':' symbol {
458     add_variable(&argsresult, find_variable($2)); 
459 }
460           | into_list ',' ':' symbol{
461     add_variable(&argsresult, find_variable($4)); 
462 };
463
464 cthing : canything {
465     fwrite(yytext, yyleng, 1, yyout);
466 }
467
468 canything : both_anything
469           | SQL_INTO
470           | ';';
471
472 sqlanything : both_anything;
473
474 both_anything : S_LENGTH | S_VARCHAR | S_VARCHAR2 
475           | S_LONG | S_SHORT | S_INT | S_CHAR | S_FLOAT | S_DOUBLE | S_BOOL 
476           | SQL_OPEN | SQL_CONNECT
477           | SQL_STRING
478           | SQL_BEGIN | SQL_END 
479           | SQL_DECLARE | SQL_SECTION 
480           | SQL_INCLUDE 
481           | S_SYMBOL
482           | S_STATIC | S_EXTERN | S_AUTO | S_CONST | S_REGISTER | S_STRUCT
483           | '[' | ']' | ',' | '=' | '*'
484           | S_ANYTHING;
485
486 blockstart : '{' {
487     braces_open++;
488     fwrite(yytext, yyleng, 1, yyout);
489 }
490
491 blockend : '}' {
492     remove_variables(braces_open--);
493     fwrite(yytext, yyleng, 1, yyout);
494 }
495 %%
496 static void yyerror(char * error)
497 {
498     fprintf(stderr, "%s\n", error);
499     exit(1);
500 }