/* Copyright comment */ %{ #include #include #include #include "type.h" #include "extern.h" static void yyerror(char *); /* * Variables containing simple states. */ int debugging = 0; /* * Handle the filename and line numbering. */ char * input_filename = NULL; void output_line_number() { if (input_filename) fprintf(yyout, "\n#line %d \"%s\"\n", yylineno, input_filename); } /* * Handling of the variables. */ /* Since we don't want to keep track of where the functions end we just * have a list of functions that we search in, most reasently defined * function. This won't work if we use block scope for variables with the * same name but different types but in all other cases the c-compiler will * signal an error (hopefully). * * This list is leaked on program exit. This is because I don't think it is * important enough to spend the extra ten minutes to write the function that * deletes it. It would be another thing if I would have written in C++. */ /* This is a linked list of the variable names and types. */ struct variable { char * name; struct ECPGtype * type; struct variable * next; }; static struct variable * allvariables = NULL; struct variable * find_variable(char * name) { struct variable * p; for (p = allvariables; p; p = p->next) { if (strcmp(p->name, name) == 0) return p; } { char * errorstring = (char *) malloc(strlen(name) + 100); sprintf(errorstring, "The variable :%s is not declared.", name); yyerror(errorstring); } return NULL; } void new_variable(const char * name, struct ECPGtype * type) { struct variable * p = (struct variable*) malloc(sizeof(struct variable)); p->name = strdup(name); p->type = type; p->next = allvariables; allvariables = p; } /* * Here are the variables that need to be handled on every request. * These are of two kinds: input and output. * I will make two lists for them. */ struct arguments { struct variable * variable; struct arguments * next; }; static struct arguments * argsinsert = NULL; static struct arguments * argsresult = NULL; void reset_variables() { argsinsert = NULL; argsresult = NULL; } /* Add a variable to a request. */ void add_variable(struct arguments ** list, struct variable * var) { struct arguments * p = (struct arguments *)malloc(sizeof(struct arguments)); p->variable = var; p->next = *list; *list = p; } /* Dump out a list of all the variable on this list. This is a recursive function that works from the end of the list and deletes the list as we go on. */ void dump_variables(struct arguments * list) { if (list == NULL) { return; } /* The list is build up from the beginning so lets first dump the end of the list: */ dump_variables(list->next); /* Then the current element. */ ECPGdump_a_type(yyout, list->variable->name, list->variable->type); /* Then release the list element. */ free(list); } %} %union { int tagname; struct ECPGtemp_type type; char * symbolname; int indexsize; enum ECPGttype type_enum; } %token SQL_START SQL_SEMI SQL_STRING SQL_INTO %token SQL_BEGIN SQL_END SQL_DECLARE SQL_SECTION SQL_INCLUDE %token SQL_CONNECT SQL_OPEN %token SQL_COMMIT SQL_ROLLBACK %token S_SYMBOL S_LENGTH S_ANYTHING %token S_VARCHAR S_VARCHAR2 %token S_EXTERN S_STATIC %token S_UNSIGNED S_SIGNED %token S_LONG S_SHORT S_INT S_CHAR S_FLOAT S_DOUBLE S_BOOL %token '[' ']' ';' ',' %type type type_detailed varchar_type simple_type array_type %type symbol %type maybe_storage_clause varchar_tag %type simple_tag %type index length %type canything sqlanything both_anything %% prog : statements; statements : /* empty */ | statements statement; statement : sqldeclaration | sqlinclude | sqlconnect | sqlopen | sqlcommit | sqlrollback | sqlstatement | cthing; sqldeclaration : sql_startdeclare variable_declarations sql_enddeclare; sql_startdeclare : SQL_START SQL_BEGIN SQL_DECLARE SQL_SECTION SQL_SEMI { fprintf(yyout, "/* exec sql begin declare section */\n"); output_line_number(); }; sql_enddeclare : SQL_START SQL_END SQL_DECLARE SQL_SECTION SQL_SEMI { fprintf(yyout,"/* exec sql end declare section */\n"); output_line_number(); }; variable_declarations : /* empty */ | variable_declarations variable_declaration ; /* Here is where we can enter support for typedef. */ variable_declaration : type ';' { new_variable($1.name, $1.typ); free($1.name); fprintf(yyout, ";"); } symbol : S_SYMBOL { char * name = (char *)malloc(yyleng + 1); strncpy(name, yytext, yyleng); name[yyleng] = '\0'; $$ = name; } type : maybe_storage_clause type_detailed { $$ = $2; }; type_detailed : varchar_type { $$ = $1; } | simple_type { $$ = $1; } | array_type {$$ = $1; }; varchar_type : varchar_tag symbol index { fprintf(yyout, "struct varchar_%s { int len; char arr[%d]; } %s", $2, $3, $2); $$.name = $2; $$.typ = ECPGmake_varchar_type(ECPGt_varchar, $3); } varchar_tag : S_VARCHAR { $$ = $1; } | S_VARCHAR2 { $$ = $1; }; simple_type : simple_tag symbol { fprintf(yyout, "%s %s", ECPGtype_name($1), $2); $$.name = $2; $$.typ = ECPGmake_simple_type($1); } array_type : simple_tag symbol index { fprintf(yyout, "%s %s [%d]", ECPGtype_name($1), $2, $3); $$.name = $2; $$.typ = ECPGmake_array_type(ECPGmake_simple_type($1), $3); } simple_tag : S_CHAR { $$ = ECPGt_char; } | S_UNSIGNED S_CHAR { $$ = ECPGt_unsigned_char; } | S_SHORT { $$ = ECPGt_short; } | S_UNSIGNED S_SHORT { $$ = ECPGt_unsigned_short; } | S_INT { $$ = ECPGt_int; } | S_UNSIGNED S_INT { $$ = ECPGt_unsigned_int; } | S_LONG { $$ = ECPGt_long; } | S_UNSIGNED S_LONG { $$ = ECPGt_unsigned_long; } | S_FLOAT { $$ = ECPGt_float; } | S_DOUBLE { $$ = ECPGt_double; } | S_BOOL { $$ = ECPGt_bool; }; maybe_storage_clause : S_EXTERN { fwrite(yytext, yyleng, 1, yyout); } | S_STATIC { fwrite(yytext, yyleng, 1, yyout); } | /* empty */ { }; index : '[' length ']' { $$ = $2; }; length : S_LENGTH { $$ = atoi(yytext); } sqlinclude : SQL_START SQL_INCLUDE { fprintf(yyout, "#include \""); } filename SQL_SEMI { fprintf(yyout, ".h\""); output_line_number(); }; filename : cthing | filename cthing; sqlconnect : SQL_START SQL_CONNECT { fprintf(yyout, "ECPGconnect(\""); } SQL_STRING { fwrite(yytext + 1, yyleng - 2, 1, yyout); } SQL_SEMI { fprintf(yyout, "\");"); output_line_number(); }; /* Open is an open cursor. Removed. */ sqlopen : SQL_START SQL_OPEN sqlgarbage SQL_SEMI { output_line_number(); }; sqlgarbage : /* Empty */ | sqlgarbage sqlanything; sqlcommit : SQL_START SQL_COMMIT SQL_SEMI { fprintf(yyout, "ECPGcommit(__LINE__);"); output_line_number(); }; sqlrollback : SQL_START SQL_ROLLBACK SQL_SEMI { fprintf(yyout, "ECPGrollback(__LINE__);"); output_line_number(); }; sqlstatement : SQL_START { /* Reset stack */ reset_variables(); fprintf(yyout, "ECPGdo(__LINE__, \""); } sqlstatement_words SQL_SEMI { /* Dump */ fprintf(yyout, "\", "); dump_variables(argsinsert); fprintf(yyout, "ECPGt_EOIT, "); dump_variables(argsresult); fprintf(yyout, "ECPGt_EORT );"); output_line_number(); }; sqlstatement_words : sqlstatement_word | sqlstatement_words sqlstatement_word; sqlstatement_word : ':' symbol { add_variable(&argsinsert, find_variable($2)); fprintf(yyout, " ;; "); } | SQL_INTO into_list { } | sqlanything { fwrite(yytext, yyleng, 1, yyout); fwrite(" ", 1, 1, yyout); } | SQL_INTO sqlanything { fprintf(yyout, " into "); fwrite(yytext, yyleng, 1, yyout); fwrite(" ", 1, 1, yyout); }; into_list : ':' symbol { add_variable(&argsresult, find_variable($2)); } | into_list ',' ':' symbol{ add_variable(&argsresult, find_variable($4)); }; cthing : canything { fwrite(yytext, yyleng, 1, yyout); } canything : both_anything | SQL_INTO | ';'; sqlanything : both_anything; both_anything : S_LENGTH | S_VARCHAR | S_VARCHAR2 | S_LONG | S_SHORT | S_INT | S_CHAR | S_FLOAT | S_DOUBLE | SQL_OPEN | SQL_CONNECT | SQL_STRING | SQL_BEGIN | SQL_END | SQL_DECLARE | SQL_SECTION | SQL_INCLUDE | S_SYMBOL | '[' | ']' | ',' | S_ANYTHING; %% static void yyerror(char * error) { fprintf(stderr, "%s\n", error); exit(1); }