summaryrefslogtreecommitdiff
path: root/src/interfaces/ecpg/preproc
diff options
context:
space:
mode:
authorMarc G. Fournier <scrappy@hub.org>1998-02-10 16:44:17 +0000
committerMarc G. Fournier <scrappy@hub.org>1998-02-10 16:44:17 +0000
commit38201e21d0849a469e165085e4d12ac0969f5018 (patch)
treeb9e0e9db026ea6b3838f57025aebbca014f998f4 /src/interfaces/ecpg/preproc
parenta8313f9671c621852dbdf16b6f47e19ceda489ea (diff)
Erk, the whole directory structure changed on us here...
Diffstat (limited to 'src/interfaces/ecpg/preproc')
-rw-r--r--src/interfaces/ecpg/preproc/Makefile33
-rw-r--r--src/interfaces/ecpg/preproc/Makefile.in32
-rw-r--r--src/interfaces/ecpg/preproc/ecpg.c106
-rw-r--r--src/interfaces/ecpg/preproc/pgc.l116
-rw-r--r--src/interfaces/ecpg/preproc/preproc.y366
-rw-r--r--src/interfaces/ecpg/preproc/type.c286
-rw-r--r--src/interfaces/ecpg/preproc/type.h51
-rw-r--r--src/interfaces/ecpg/preproc/y.tab.h39
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;