diff options
author | Marc G. Fournier <scrappy@hub.org> | 1998-02-10 16:44:17 +0000 |
---|---|---|
committer | Marc G. Fournier <scrappy@hub.org> | 1998-02-10 16:44:17 +0000 |
commit | 38201e21d0849a469e165085e4d12ac0969f5018 (patch) | |
tree | b9e0e9db026ea6b3838f57025aebbca014f998f4 /src/interfaces/ecpg/preproc | |
parent | a8313f9671c621852dbdf16b6f47e19ceda489ea (diff) |
Erk, the whole directory structure changed on us here...
Diffstat (limited to 'src/interfaces/ecpg/preproc')
-rw-r--r-- | src/interfaces/ecpg/preproc/Makefile | 33 | ||||
-rw-r--r-- | src/interfaces/ecpg/preproc/Makefile.in | 32 | ||||
-rw-r--r-- | src/interfaces/ecpg/preproc/ecpg.c | 106 | ||||
-rw-r--r-- | src/interfaces/ecpg/preproc/pgc.l | 116 | ||||
-rw-r--r-- | src/interfaces/ecpg/preproc/preproc.y | 366 | ||||
-rw-r--r-- | src/interfaces/ecpg/preproc/type.c | 286 | ||||
-rw-r--r-- | src/interfaces/ecpg/preproc/type.h | 51 | ||||
-rw-r--r-- | src/interfaces/ecpg/preproc/y.tab.h | 39 |
8 files changed, 1029 insertions, 0 deletions
diff --git a/src/interfaces/ecpg/preproc/Makefile b/src/interfaces/ecpg/preproc/Makefile new file mode 100644 index 00000000000..8cc8b7cb3aa --- /dev/null +++ b/src/interfaces/ecpg/preproc/Makefile @@ -0,0 +1,33 @@ +# Generated automatically from Makefile.in by configure. +SRCDIR= ../../.. +include $(SRCDIR)/Makefile.global + +CC=gcc +LEX=flex +LEXLIB=-lfl +YACC=/usr/bin/bison +YFLAGS=-y -d + +CFLAGS=-I../include -O2 -g -Wall + +all:: ecpg + +clean: + rm -f *.o core a.out ecpg preproc.tab.h y.tab.c *~ + +install: all + install -c -m 755 ecpg $(BINDIR) + +uninstall: + rm -f $(BINDIR)/ecpg + +# Rule that really do something. +ecpg: y.tab.o pgc.o type.o ecpg.o + $(CC) -g -O2 -Wall -o ecpg y.tab.o pgc.o type.o ecpg.o -L../lib -lecpg $(LEXLIB) + +y.tab.h y.tab.c: preproc.y + $(YACC) $(YFLAGS) $< + +y.tab.o : y.tab.h ../include/ecpgtype.h +type.o : ../include/ecpgtype.h +pgc.o : ../include/ecpgtype.h diff --git a/src/interfaces/ecpg/preproc/Makefile.in b/src/interfaces/ecpg/preproc/Makefile.in new file mode 100644 index 00000000000..f3cb049e8c3 --- /dev/null +++ b/src/interfaces/ecpg/preproc/Makefile.in @@ -0,0 +1,32 @@ +SRCDIR= ../../.. +include $(SRCDIR)/Makefile.global + +CC=@CC@ +LEX=@LEX@ +LEXLIB=@LEXLIB@ +YACC=@YACC@ +YFLAGS=@YFLAGS@ + +CFLAGS=-I../include -O2 -g -Wall + +all:: ecpg + +clean: + rm -f *.o core a.out ecpg preproc.tab.h y.tab.c *~ + +install: all + install -c -m 755 ecpg $(BINDIR) + +uninstall: + rm -f $(BINDIR)/ecpg + +# Rule that really do something. +ecpg: y.tab.o pgc.o type.o ecpg.o + $(CC) -g -O2 -Wall -o ecpg y.tab.o pgc.o type.o ecpg.o -L../lib -lecpg $(LEXLIB) + +y.tab.h y.tab.c: preproc.y + $(YACC) $(YFLAGS) $< + +y.tab.o : y.tab.h ../include/ecpgtype.h +type.o : ../include/ecpgtype.h +pgc.o : ../include/ecpgtype.h diff --git a/src/interfaces/ecpg/preproc/ecpg.c b/src/interfaces/ecpg/preproc/ecpg.c new file mode 100644 index 00000000000..08f4a395250 --- /dev/null +++ b/src/interfaces/ecpg/preproc/ecpg.c @@ -0,0 +1,106 @@ +/* New main for ecpg, the PostgreSQL embedded SQL precompiler. */ +/* (C) Michael Meskes <meskes@debian.org> Feb 5th, 1998 */ +/* Placed under the same copyright as PostgresSQL */ + +#include <stdio.h> +#include <getopt.h> +#include <stdlib.h> +#include <strings.h> + +extern void lex_init(void); +extern FILE *yyin, *yyout; +extern char * input_filename; +extern int yyparse(void); + +static void +usage(char *progname) +{ + fprintf(stderr, "Usage: %s: [ -o outout file name] file1 [file2] ...\n", progname); +} + +int +main(int argc, char *const argv[]) +{ + char c, + out_option = 0; + int fnr; + + while ((c = getopt(argc, argv, "o:")) != EOF) + { + switch (c) + { + case 'o': + yyout = fopen(optarg, "w"); + if (yyout == NULL) + perror(optarg); + else + out_option = 1; + break; + default: + usage(argv[0]); + } + } + + /* after the options there must not be anything but filenames */ + for (fnr = optind; fnr < argc; fnr++) + { + char *filename, + *ptr2ext; + + filename = malloc(strlen(argv[fnr]) + 2); + if (filename == NULL) + { + perror("malloc"); + continue; + } + + strcpy(filename, argv[fnr]); + + ptr2ext = strrchr(filename, '.'); + /* no extension or extension not equal .pgc */ + if (ptr2ext == NULL || strcmp(ptr2ext, ".pgc") != 0) + { + ptr2ext = filename + strlen(filename); + ptr2ext[0] = '.'; + } + + /* make extension = .c */ + ptr2ext[1] = 'c'; + ptr2ext[2] = '\0'; + + if (out_option == 0) /* calculate the output name */ + { + yyout = fopen(filename, "w"); + if (yyout == NULL) + { + perror(filename); + free(filename); + continue; + } + } + + yyin = fopen(input_filename = argv[fnr], "r"); + if (yyin == NULL) + { + perror(argv[fnr]); + } + else + { + /* initialize lex */ + lex_init(); + + /* we need two includes everytime */ + fprintf(yyout, "/* These two include files are added by the preprocessor */\n#include <ecpgtype.h>\n#include <ecpglib.h>\n"); + + /* and parse the source */ + yyparse(); + + fclose(yyin); + if (out_option == 0) + fclose(yyout); + } + + free(filename); + } + return (0); +} diff --git a/src/interfaces/ecpg/preproc/pgc.l b/src/interfaces/ecpg/preproc/pgc.l new file mode 100644 index 00000000000..7ab3c5764f2 --- /dev/null +++ b/src/interfaces/ecpg/preproc/pgc.l @@ -0,0 +1,116 @@ +/* Copyright comment! */ +%{ +#include "type.h" +#include "y.tab.h" + +extern int debugging; + +#define dbg(arg) if (debugging) fprintf(stderr, "DEBUG, %d: %s\n", yylineno, #arg); +%} +%option yylineno +%s C SQL +ccomment \/\*([^*]|\*[^/]|\*\*[^/])*\*\/ +ws ([ \t\n][ \t\n]*|{ccomment})* +letter [A-Za-z_] +digit [0-9] +length {digit}+ +symbol {letter}({letter}|{digit})* +string '[^']*' + +exec [eE][xX][eE][cC] +sql [sS][qQ][lL] +varchar [vV][aA][rR][cC][hH][aA][rR] +varchar2 [vV][aA][rR][cC][hH][aA][rR]2 +into [iI][nN][tT][oO] +begin [bB][eE][gG][iI][nN] +end [eE][nN][dD] +declare [dD][eE][cC][lL][aA][rR][eE] +section [sS][eE][cC][tT][iI][oO][nN] +include [iI][nN][cC][lL][uU][dD][eE] +connect [cC][oO][nN][nN][eE][cC][tT] +open [oO][pP][eE][nN] +commit [cC][oO][mM][mM][iI][tT] +rollback [rR][oO][lL][lL][bB][aA][cC][kK] +%% +<C>{exec}{ws}{sql} { BEGIN SQL; dbg(SQL_START); return SQL_START; } +<SQL>";" { BEGIN C; dbg(SQL_SEMI); return SQL_SEMI; } +<SQL>{begin} { dbg(SQL_BEGIN); return SQL_BEGIN; } +<SQL>{end} { dbg(SQL_END); return SQL_END; } +<SQL>{declare} { dbg(SQL_DECLARE); return SQL_DECLARE; } +<SQL>{section} { dbg(SQL_SECTION); return SQL_SECTION; } +<SQL>{include} { dbg(SQL_INCLUDE); return SQL_INCLUDE; } +<SQL>{connect} { dbg(SQL_CONNECT); return SQL_CONNECT; } +<SQL>{open} { dbg(SQL_OPEN); return SQL_OPEN; } +<SQL>{commit} { dbg(SQL_COMMIT); return SQL_COMMIT; } +<SQL>{rollback} { dbg(SQL_ROLLBACK); return SQL_ROLLBACK; } + +<SQL>{into} { dbg(SQL_INTO); return SQL_INTO; } + +{length} { dbg(S_LENGTH); return S_LENGTH; } + +{varchar} { dbg(S_VARCHAR); return S_VARCHAR; } +{varchar2} { dbg(S_VARCHAR2); return S_VARCHAR2; } +long { dbg(S_LONG); return S_LONG; } +short { dbg(S_SHORT); return S_SHORT; } +int { dbg(S_INT); return S_INT; } +char { dbg(S_CHAR); return S_CHAR; } +float { dbg(S_FLOAT); return S_FLOAT; } +double { dbg(S_DOUBLE); return S_DOUBLE; } +bool { dbg(S_BOOL); return S_BOOL; } + +{string} { dbg(SQL_STRING); return SQL_STRING; } +<SQL>{ws} ; +{symbol} { dbg(S_SYMBOL); return S_SYMBOL; } + +<SQL>"!<" { dbg(S_SYMBOL); return S_SYMBOL; } +<SQL>"!>" { dbg(S_SYMBOL); return S_SYMBOL; } +<SQL>"!^" { dbg(S_SYMBOL); return S_SYMBOL; } +<SQL>"!|" { dbg(S_SYMBOL); return S_SYMBOL; } +<SQL>"!~" { dbg(S_SYMBOL); return S_SYMBOL; } +<SQL>"!~*" { dbg(S_SYMBOL); return S_SYMBOL; } +<SQL>"#<" { dbg(S_SYMBOL); return S_SYMBOL; } +<SQL>"#<=" { dbg(S_SYMBOL); return S_SYMBOL; } +<SQL>"#<>" { dbg(S_SYMBOL); return S_SYMBOL; } +<SQL>"#=" { dbg(S_SYMBOL); return S_SYMBOL; } +<SQL>"#>" { dbg(S_SYMBOL); return S_SYMBOL; } +<SQL>"#>=" { dbg(S_SYMBOL); return S_SYMBOL; } +<SQL>"&&" { dbg(S_SYMBOL); return S_SYMBOL; } +<SQL>"&<" { dbg(S_SYMBOL); return S_SYMBOL; } +<SQL>"&>" { dbg(S_SYMBOL); return S_SYMBOL; } +<SQL>"<<" { dbg(S_SYMBOL); return S_SYMBOL; } +<SQL>"<=" { dbg(S_SYMBOL); return S_SYMBOL; } +<SQL>"<===>" { dbg(S_SYMBOL); return S_SYMBOL; } +<SQL>"<>" { dbg(S_SYMBOL); return S_SYMBOL; } +<SQL>"<?>" { dbg(S_SYMBOL); return S_SYMBOL; } +<SQL>"===>" { dbg(S_SYMBOL); return S_SYMBOL; } +<SQL>"===`" { dbg(S_SYMBOL); return S_SYMBOL; } +<SQL>"=|=" { dbg(S_SYMBOL); return S_SYMBOL; } +<SQL>">=" { dbg(S_SYMBOL); return S_SYMBOL; } +<SQL>">>" { dbg(S_SYMBOL); return S_SYMBOL; } +<SQL>"@@" { dbg(S_SYMBOL); return S_SYMBOL; } +<SQL>"|/" { dbg(S_SYMBOL); return S_SYMBOL; } +<SQL>"||/" { dbg(S_SYMBOL); return S_SYMBOL; } +<SQL>"~*" { dbg(S_SYMBOL); return S_SYMBOL; } +<SQL>"~=" { dbg(S_SYMBOL); return S_SYMBOL; } + +"[" { dbg([); return '['; } +"]" { dbg(]); return ']'; } +";" { dbg(;); return ';'; } +"," { dbg(komma); return ','; } + +<SQL>":" { dbg(:); return ':'; } + +{ws} { ECHO; } +. { dbg(.); return S_ANYTHING; } +%% +void +lex_init(void) +{ + BEGIN C; +} + +int yywrap(void) +{ + return 1; +} + diff --git a/src/interfaces/ecpg/preproc/preproc.y b/src/interfaces/ecpg/preproc/preproc.y new file mode 100644 index 00000000000..b5a30c0d196 --- /dev/null +++ b/src/interfaces/ecpg/preproc/preproc.y @@ -0,0 +1,366 @@ +/* Copyright comment */ +%{ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "type.h" + +void yyerror(char *); +extern FILE * yyout; +extern char * yytext; +extern int yylineno; +extern int yyleng; + +/* + * 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 variabel :%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 is 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 <tagname> SQL_START SQL_SEMI SQL_STRING SQL_INTO +%token <tagname> SQL_BEGIN SQL_END SQL_DECLARE SQL_SECTION SQL_INCLUDE +%token <tagname> SQL_CONNECT SQL_OPEN +%token <tagname> SQL_COMMIT SQL_ROLLBACK + +%token <tagname> S_SYMBOL S_LENGTH S_ANYTHING +%token <tagname> S_VARCHAR S_VARCHAR2 +%token <tagname> S_EXTERN S_STATIC +%token <tagname> S_UNSIGNED S_SIGNED +%token <tagname> S_LONG S_SHORT S_INT S_CHAR S_FLOAT S_DOUBLE S_BOOL +%token <tagname> '[' ']' ';' ',' + +%type <type> type type_detailed varchar_type simple_type array_type +%type <symbolname> symbol +%type <tagname> maybe_storage_clause varchar_tag +%type <type_enum> simple_tag +%type <indexsize> index length +%type <tagname> 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($<type>1.name, $<type>1.typ); + free($<type>1.name); + fprintf(yyout, ";"); +} + +symbol : S_SYMBOL { + char * name = (char *)malloc(yyleng + 1); + + strncpy(name, yytext, yyleng); + name[yyleng] = '\0'; + + $<symbolname>$ = name; +} + +type : maybe_storage_clause type_detailed { $<type>$ = $<type>2; }; +type_detailed : varchar_type { $<type>$ = $<type>1; } + | simple_type { $<type>$ = $<type>1; } + | array_type {$<type>$ = $<type>1; }; + +varchar_type : varchar_tag symbol index { + fprintf(yyout, "struct varchar_%s { int len; char arr[%d]; } %s", $<symbolname>2, $<indexsize>3, $<symbolname>2); + $<type>$.name = $<symbolname>2; + $<type>$.typ = ECPGmake_varchar_type(ECPGt_varchar, $<indexsize>3); +} + +varchar_tag : S_VARCHAR { $<tagname>$ = $<tagname>1; } + | S_VARCHAR2 { $<tagname>$ = $<tagname>1; }; + +simple_type : simple_tag symbol { + fprintf(yyout, "%s %s", ECPGtype_name($<type_enum>1), $<symbolname>2); + $<type>$.name = $<symbolname>2; + $<type>$.typ = ECPGmake_simple_type($<type_enum>1); +} + +array_type : simple_tag symbol index { + fprintf(yyout, "%s %s [%d]", ECPGtype_name($<type_enum>1), $<symbolname>2, $<indexsize>3); + $<type>$.name = $<symbolname>2; + $<type>$.typ = ECPGmake_array_type(ECPGmake_simple_type($<type_enum>1), $<indexsize>3); +} + +simple_tag : S_CHAR { $<type_enum>$ = ECPGt_char; } + | S_UNSIGNED S_CHAR { $<type_enum>$ = ECPGt_unsigned_char; } + | S_SHORT { $<type_enum>$ = ECPGt_short; } + | S_UNSIGNED S_SHORT { $<type_enum>$ = ECPGt_unsigned_short; } + | S_INT { $<type_enum>$ = ECPGt_int; } + | S_UNSIGNED S_INT { $<type_enum>$ = ECPGt_unsigned_int; } + | S_LONG { $<type_enum>$ = ECPGt_long; } + | S_UNSIGNED S_LONG { $<type_enum>$ = ECPGt_unsigned_long; } + | S_FLOAT { $<type_enum>$ = ECPGt_float; } + | S_DOUBLE { $<type_enum>$ = ECPGt_double; } + | S_BOOL { $<type_enum>$ = ECPGt_bool; }; + +maybe_storage_clause : S_EXTERN { fwrite(yytext, yyleng, 1, yyout); } + | S_STATIC { fwrite(yytext, yyleng, 1, yyout); } + | /* empty */ { }; + +index : '[' length ']' { + $<indexsize>$ = $<indexsize>2; +}; + +length : S_LENGTH { $<indexsize>$ = 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; + +%% +void yyerror(char * error) +{ + fprintf(stderr, "%s\n", error); + exit(1); +} diff --git a/src/interfaces/ecpg/preproc/type.c b/src/interfaces/ecpg/preproc/type.c new file mode 100644 index 00000000000..e3ee2f003ab --- /dev/null +++ b/src/interfaces/ecpg/preproc/type.c @@ -0,0 +1,286 @@ +#include <stdio.h> +#include <string.h> + +#include "type.h" + +/* Constructors + Yes, I mostly write c++-code + */ + +/* The NAME argument is copied. The type argument is preserved as a pointer. */ +struct ECPGrecord_member * +ECPGmake_record_member(char * name, struct ECPGtype * type) +{ + struct ECPGrecord_member * ne = + (struct ECPGrecord_member *)malloc(sizeof(struct ECPGrecord_member)); + + ne->name = strdup(name); + ne->typ = type; + + return ne; +} + +struct ECPGtype * +ECPGmake_simple_type(enum ECPGttype typ) +{ + struct ECPGtype * ne = (struct ECPGtype *)malloc(sizeof(struct ECPGtype)); + + ne->typ = typ; + ne->size = 0; + ne->u.element = 0; + + return ne; +} + +struct ECPGtype * +ECPGmake_varchar_type(enum ECPGttype typ, unsigned short siz) +{ + struct ECPGtype * ne = ECPGmake_simple_type(typ); + + ne->size = siz; + + return ne; +} + +struct ECPGtype * +ECPGmake_array_type(struct ECPGtype * typ, unsigned short siz) +{ + struct ECPGtype * ne = ECPGmake_simple_type(ECPGt_array); + + ne->size = siz; + ne->u.element = typ; + + return ne; +} + +struct ECPGtype * +ECPGmake_record_type(struct ECPGrecord_member * rm[]) +{ + struct ECPGtype * ne = ECPGmake_simple_type(ECPGt_record); + + ne->u.members = rm; + + return ne; +} + + +/* Dump a type. + The type is dumped as: + type-tag <comma> - enum ECPGttype + reference-to-variable <comma> - void * + size <comma> - short size of this field (if varchar) + arrsize <comma> - short number of elements in the arr + offset <comma> - short offset to the next element + Where: + type-tag is one of the simple types or varchar. + reference-to-variable can be a reference to a struct element. + arrsize is the size of the array in case of array fetches. Otherwise 0. + size is the maxsize in case it is a varchar. Otherwise it is the size of + the variable (required to do array fetches of records). + */ +void ECPGdump_a_simple(FILE * o, const char * name, enum ECPGttype typ, + short varcharsize, + unsigned short arrsiz, const char * siz); +void ECPGdump_a_record(FILE * o, const char * name, unsigned short arrsiz, + struct ECPGtype * typ, const char * offset); + + +void +ECPGdump_a_type(FILE * o, const char * name, struct ECPGtype * typ) +{ + if (IS_SIMPLE_TYPE(typ->typ)) + { + ECPGdump_a_simple(o, name, typ->typ, typ->size, 0, 0); + } + else if (typ->typ == ECPGt_array) + { + if (IS_SIMPLE_TYPE(typ->u.element->typ)) + ECPGdump_a_simple(o, name, typ->u.element->typ, + typ->u.element->size, typ->size, 0); + else if (typ->u.element->typ == ECPGt_array) + { + abort(); /* Array of array, */ + } + else if (typ->u.element->typ == ECPGt_record) + { + /* Array of records. */ + ECPGdump_a_record(o, name, typ->size, typ->u.element, 0); + } + else + { + abort(); + } + } + else if (typ->typ == ECPGt_record) + { + ECPGdump_a_record(o, name, 0, typ, 0); + } + else + { + abort(); + } +} + + +/* If siz is NULL, then the offset is 0, if not use siz as a + string, it represents the offset needed if we are in an array of records. */ +void +ECPGdump_a_simple(FILE * o, const char * name, enum ECPGttype typ, + short varcharsize, + unsigned short arrsiz, + const char * siz) +{ + switch (typ) + { + case ECPGt_char: + fprintf(o, "\n\tECPGt_char,&%s,0,%d,%s, ", name, arrsiz, + siz == NULL ? "sizeof(char)" : siz); + break; + case ECPGt_unsigned_char: + fprintf(o, "\n\tECPGt_unsigned_char,&%s,0,%d,%s, ", name, arrsiz, + siz == NULL ? "sizeof(unsigned char)" : siz); + break; + case ECPGt_short: + fprintf(o, "\n\tECPGt_short,&%s,0,%d,%s, ", name, arrsiz, + siz == NULL ? "sizeof(short)" : siz); + break; + case ECPGt_unsigned_short: + fprintf(o, + "\n\tECPGt_unsigned_short,&%s,0,%d,%s, ", name, arrsiz, + siz == NULL ? "sizeof(unsigned short)" : siz); + break; + case ECPGt_int: + fprintf(o, "\n\tECPGt_int,&%s,0,%d,%s, ", name, arrsiz, + siz == NULL ? "sizeof(int)" : siz); + break; + case ECPGt_unsigned_int: + fprintf(o, "\n\tECPGt_unsigned_int,&%s,0,%d,%s, ", name, arrsiz, + siz == NULL ? "sizeof(unsigned int)" : siz); + break; + case ECPGt_long: + fprintf(o, "\n\tECPGt_long,&%s,0,%d,%s, ", name, arrsiz, + siz == NULL ? "sizeof(long)" : siz); + break; + case ECPGt_unsigned_long: + fprintf(o, "\n\tECPGt_unsigned_int,&%s,0,%d,%s, ", name, arrsiz, + siz == NULL ? "sizeof(unsigned int)" : siz); + break; + case ECPGt_float: + fprintf(o, "\n\tECPGt_float,&%s,0,%d,%s, ", name, arrsiz, + siz == NULL ? "sizeof(float)" : siz); + break; + case ECPGt_double: + fprintf(o, "\n\tECPGt_double,&%s,0,%d,%s, ", name, arrsiz, + siz == NULL ? "sizeof(double)" : siz); + break; + case ECPGt_bool: + fprintf(o, "\n\tECPGt_bool,&%s,0,%d,%s, ", name, arrsiz, + siz == NULL ? "sizeof(bool)" : siz); + break; + case ECPGt_varchar: + case ECPGt_varchar2: + if (siz == NULL) + fprintf(o, "\n\tECPGt_varchar,&%s,%d,%d,sizeof(struct varchar_%s), ", + name, + varcharsize, + arrsiz, name); + else + fprintf(o, "\n\tECPGt_varchar,&%s,%d,%d,%s, ", + name, + varcharsize, + arrsiz, siz); + break; + default: + abort(); + } +} + + +/* Penetrate a record and dump the contents. */ +void +ECPGdump_a_record(FILE * o, + const char * name, unsigned short arrsiz, + struct ECPGtype * typ, const char * offsetarg) +{ + /* If offset is NULL, then this is the first recursive level. If not then + we are in a record in a record and the offset is used as offset. + */ + struct ECPGrecord_member ** p; + char obuf[BUFSIZ]; + char buf[BUFSIZ]; + const char * offset; + + if (offsetarg == NULL) + { + sprintf(obuf, "sizeof(%s)", name); + offset = obuf; + } + else + { + offset = offsetarg; + } + + for (p = typ->u.members; *p; p++) + { + if (IS_SIMPLE_TYPE((*p)->typ->typ)) + { + sprintf(buf, "%s.%s", name, (*p)->name); + ECPGdump_a_simple(o, buf, (*p)->typ->typ, (*p)->typ->size, + arrsiz, offset); + } + else if ((*p)->typ->typ == ECPGt_array) + { + int i; + + for (i = 0; i < (*p)->typ->size; i++) + { + if (IS_SIMPLE_TYPE((*p)->typ->u.element->typ)) + { + sprintf(buf, "%s.%s[%d]", name, (*p)->name, i); + ECPGdump_a_simple(o, buf, (*p)->typ->typ, (*p)->typ->size, + arrsiz, offset); + } + else if((*p)->typ->u.element->typ == ECPGt_array) + { + /* Array within an array. NOT implemented yet. */ + abort(); + } + else if ((*p)->typ->u.element->typ == ECPGt_record) + { + /* Record within array within record. NOT implemented yet. */ + abort(); + } + else + { + /* Unknown type */ + abort(); + } + } + } + else if ((*p)->typ->typ == ECPGt_record) + { + /* Record within a record */ + sprintf(buf, "%s.%s", name, (*p)->name); + ECPGdump_a_record(o, buf, arrsiz, (*p)->typ, offset); + } + else + { + /* Unknown type */ + abort(); + } + } +} + + +/* Freeing is not really that important. Since we throw away the process + anyway. Lets implement that last! */ + +void +ECPGfree_record_member(struct ECPGrecord_member * rm) +{ +} + +void +ECPGfree_type(struct ECPGtype * typ) +{ +} diff --git a/src/interfaces/ecpg/preproc/type.h b/src/interfaces/ecpg/preproc/type.h new file mode 100644 index 00000000000..6726683bd58 --- /dev/null +++ b/src/interfaces/ecpg/preproc/type.h @@ -0,0 +1,51 @@ +#include <ecpgtype.h> + +struct ECPGtype; +struct ECPGrecord_member { + char * name; + struct ECPGtype * typ; +}; +struct ECPGtype { + enum ECPGttype typ; + unsigned short size; /* For array it is the number of elements. + * For varchar it is the maxsize of the area. + */ + union { + struct ECPGtype * element; /* For an array this is the type of the + * element */ + + struct ECPGrecord_member ** members; + /* A pointer to an array of members. */ + } u; +}; + +/* Everything is malloced. */ +struct ECPGrecord_member * ECPGmake_record_member(char *, struct ECPGtype *); +struct ECPGtype * ECPGmake_simple_type(enum ECPGttype); +struct ECPGtype * ECPGmake_varchar_type(enum ECPGttype, unsigned short); +struct ECPGtype * ECPGmake_array_type(struct ECPGtype *, unsigned short); +struct ECPGtype * ECPGmake_record_type(struct ECPGrecord_member *[]); + +/* Frees a type. */ +void ECPGfree_record_member(struct ECPGrecord_member *); +void ECPGfree_type(struct ECPGtype *); + +/* Dump a type. + The type is dumped as: + type-tag <comma> reference-to-variable <comma> arrsize <comma> size <comma> + Where: + type-tag is one of the simple types or varchar. + reference-to-variable can be a reference to a struct element. + arrsize is the size of the array in case of array fetches. Otherwise 0. + size is the maxsize in case it is a varchar. Otherwise it is the size of + the variable (required to do array fetches of records). + */ +void ECPGdump_a_type(FILE *, const char * name, struct ECPGtype *); + +/* A simple struct to keep a variable and its type. */ +struct ECPGtemp_type { + struct ECPGtype * typ; + const char * name; +}; + +extern const char * ECPGtype_name(enum ECPGttype typ); diff --git a/src/interfaces/ecpg/preproc/y.tab.h b/src/interfaces/ecpg/preproc/y.tab.h new file mode 100644 index 00000000000..b2fadd683bf --- /dev/null +++ b/src/interfaces/ecpg/preproc/y.tab.h @@ -0,0 +1,39 @@ +typedef union { + int tagname; + struct ECPGtemp_type type; + char * symbolname; + int indexsize; + enum ECPGttype type_enum; +} YYSTYPE; +#define SQL_START 258 +#define SQL_SEMI 259 +#define SQL_STRING 260 +#define SQL_INTO 261 +#define SQL_BEGIN 262 +#define SQL_END 263 +#define SQL_DECLARE 264 +#define SQL_SECTION 265 +#define SQL_INCLUDE 266 +#define SQL_CONNECT 267 +#define SQL_OPEN 268 +#define SQL_COMMIT 269 +#define SQL_ROLLBACK 270 +#define S_SYMBOL 271 +#define S_LENGTH 272 +#define S_ANYTHING 273 +#define S_VARCHAR 274 +#define S_VARCHAR2 275 +#define S_EXTERN 276 +#define S_STATIC 277 +#define S_UNSIGNED 278 +#define S_SIGNED 279 +#define S_LONG 280 +#define S_SHORT 281 +#define S_INT 282 +#define S_CHAR 283 +#define S_FLOAT 284 +#define S_DOUBLE 285 +#define S_BOOL 286 + + +extern YYSTYPE yylval; |