mirror of
https://github.com/postgres/postgres.git
synced 2025-11-29 00:04:28 -05:00
365 lines
9.2 KiB
Plaintext
365 lines
9.2 KiB
Plaintext
/* Copyright comment */
|
|
%{
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#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 <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;
|
|
|
|
%%
|
|
static void yyerror(char * error)
|
|
{
|
|
fprintf(stderr, "%s\n", error);
|
|
exit(1);
|
|
}
|