mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-09-30 11:51:18 +02:00
7500a961f1
+ Thu Apr 23 09:27:16 CEST 1998 + + - Also allow call in whenever statement with the same functionality + as do. + + Thu Apr 23 12:29:28 CEST 1998 + + - Also rewrote variable declaration part. It is now possible to + declare more than one variable per line. + - Set version to 2.1.0 + + Fri Apr 24 13:50:15 CEST 1998 + + - Fixed some bugs. + - Set version to 2.1.1
541 lines
12 KiB
Plaintext
541 lines
12 KiB
Plaintext
/* This is a modified version of src/backend/parser/scan.l */
|
|
%{
|
|
#include "config.h"
|
|
|
|
#include <ctype.h>
|
|
#include <sys/types.h>
|
|
#include <limits.h>
|
|
#if defined(HAVE_STRING_H)
|
|
#include <string.h>
|
|
#else
|
|
#include <strings.h>
|
|
#endif
|
|
#include <errno.h>
|
|
|
|
#include "postgres.h"
|
|
#include "miscadmin.h"
|
|
#include "nodes/pg_list.h"
|
|
#include "nodes/parsenodes.h"
|
|
#include "parser/gramparse.h"
|
|
#include "parser/scansup.h"
|
|
#include "type.h"
|
|
#include "y.tab.h"
|
|
#include "utils/builtins.h"
|
|
|
|
#include "extern.h"
|
|
|
|
/* some versions of lex define this as a macro */
|
|
#if defined(yywrap)
|
|
#undef yywrap
|
|
#endif /* yywrap */
|
|
|
|
int debugging = 0;
|
|
extern YYSTYPE yylval;
|
|
int llen;
|
|
char literal[MAX_PARSE_BUFFER];
|
|
|
|
struct _yy_buffer { YY_BUFFER_STATE buffer;
|
|
long lineno;
|
|
char * filename;
|
|
struct _yy_buffer * next;
|
|
} *yy_buffer = NULL;
|
|
|
|
%}
|
|
%option yylineno
|
|
%s C SQL incl
|
|
/* OK, here is a short description of lex/flex rules behavior.
|
|
* The longest pattern which matches an input string is always chosen.
|
|
* For equal-length patterns, the first occurring in the rules list is chosen.
|
|
* INITIAL is the starting condition, to which all non-conditional rules apply.
|
|
* When in an exclusive condition, only those rules defined for that condition apply.
|
|
*
|
|
* Exclusive states change parsing rules while the state is active.
|
|
* There are exclusive states for quoted strings, extended comments,
|
|
* and to eliminate parsing troubles for numeric strings.
|
|
* Exclusive states:
|
|
* <xb> binary numeric string - thomas 1997-11-16
|
|
* <xc> extended C-style comments - tgl 1997-07-12
|
|
* <xd> delimited identifiers (double-quoted identifiers) - tgl 1997-10-27
|
|
* <xh> hexadecimal numeric string - thomas 1997-11-16
|
|
* <xm> numeric strings with embedded minus sign - tgl 1997-09-05
|
|
* <xq> quoted strings - tgl 1997-07-30
|
|
*
|
|
* The "extended comment" syntax closely resembles allowable operator syntax.
|
|
* So, when in condition <xc>, only strings which would terminate the
|
|
* "extended comment" trigger any action other than "ignore".
|
|
* Be sure to match _any_ candidate comment, including those with appended
|
|
* operator-like symbols. - thomas 1997-07-14
|
|
*/
|
|
|
|
%x xb
|
|
%x xc
|
|
%x xd
|
|
%x xdc
|
|
%x xh
|
|
%x xm
|
|
%x xq
|
|
|
|
/* Binary number
|
|
*/
|
|
xbstart [bB]{quote}
|
|
xbstop {quote}
|
|
xbinside [^']*
|
|
xbcat {quote}{space}*\n{space}*{quote}
|
|
|
|
/* Hexadecimal number
|
|
*/
|
|
xhstart [xX]{quote}
|
|
xhstop {quote}
|
|
xhinside [^']*
|
|
xhcat {quote}{space}*\n{space}*{quote}
|
|
|
|
/* Extended quote
|
|
* xqdouble implements SQL92 embedded quote
|
|
* xqcat allows strings to cross input lines
|
|
*/
|
|
quote '
|
|
xqstart {quote}
|
|
xqstop {quote}
|
|
xqdouble {quote}{quote}
|
|
xqinside [^\\']*
|
|
xqembedded "\\'"
|
|
xqliteral [\\](.|\n)
|
|
xqcat {quote}{space}*\n{space}*{quote}
|
|
|
|
/* Delimited quote
|
|
* Allows embedded spaces and other special characters into identifiers.
|
|
*/
|
|
dquote \"
|
|
xdstart {dquote}
|
|
xdstop {dquote}
|
|
xdinside [^"]*
|
|
|
|
/* Comments
|
|
* Ignored by the scanner and parser.
|
|
*/
|
|
xcline [\/][\*].*[\*][\/]{space}*\n*
|
|
xcstart [\/][\*]{op_and_self}*
|
|
xcstop {op_and_self}*[\*][\/]({space}*|\n)
|
|
xcinside [^*]*
|
|
xcstar [^/]
|
|
|
|
digit [0-9]
|
|
number [-+.0-9Ee]
|
|
letter [\200-\377_A-Za-z]
|
|
letter_or_digit [\200-\377_A-Za-z0-9]
|
|
|
|
identifier {letter}{letter_or_digit}*
|
|
|
|
typecast "::"
|
|
|
|
self [,()\[\].$\:\+\-\*\/\<\>\=\|]
|
|
op_and_self [\~\!\@\#\%\^\&\|\`\?\$\:\+\-\*\/\<\>\=]
|
|
operator {op_and_self}+
|
|
|
|
xminteger {integer}/-
|
|
xmreal {real}/{space}*-{digit}
|
|
xmstop -
|
|
|
|
integer -?{digit}+
|
|
real -?{digit}+\.{digit}+([Ee][-+]?{digit}+)?
|
|
|
|
param \${integer}
|
|
|
|
comment ("--"|"//").*\n
|
|
|
|
space [ \t\n\f]
|
|
other .
|
|
|
|
/* some stuff needed for ecpg */
|
|
ccomment \/\*([^*]|\*[^/]|\*\*[^/])*\*\/
|
|
exec [eE][xX][eE][cC]
|
|
include [iI][nN][cC][lL][uU][dD][eE]
|
|
sql [sS][qQ][lL]
|
|
|
|
/* DO NOT PUT ANY COMMENTS IN THE FOLLOWING SECTION.
|
|
* AT&T lex does not properly handle C-style comments in this second lex block.
|
|
* So, put comments here. tgl - 1997-09-08
|
|
*
|
|
* Quoted strings must allow some special characters such as single-quote
|
|
* and newline.
|
|
* Embedded single-quotes are implemented both in the SQL/92-standard
|
|
* style of two adjacent single quotes "''" and in the Postgres/Java style
|
|
* of escaped-quote "\'".
|
|
* Other embedded escaped characters are matched explicitly and the leading
|
|
* backslash is dropped from the string. - thomas 1997-09-24
|
|
*/
|
|
|
|
%%
|
|
<SQL>{comment} { /* ignore */ }
|
|
|
|
<SQL>{xcline} { /* ignore */ }
|
|
|
|
<xc>{xcstar} |
|
|
<SQL>{xcstart} { BEGIN(xc); }
|
|
|
|
<xc>{xcstop} { BEGIN(SQL); }
|
|
|
|
<xc>{xcinside} { /* ignore */ }
|
|
|
|
<SQL>{xbstart} {
|
|
BEGIN(xb);
|
|
llen = 0;
|
|
*literal = '\0';
|
|
}
|
|
<xb>{xbstop} {
|
|
char* endptr;
|
|
|
|
BEGIN(SQL);
|
|
errno = 0;
|
|
yylval.ival = strtol((char *)literal,&endptr,2);
|
|
if (*endptr != '\0' || errno == ERANGE)
|
|
yyerror("ERROR: Bad binary integer input!");
|
|
return (ICONST);
|
|
}
|
|
<xh>{xhinside} |
|
|
<xb>{xbinside} {
|
|
if ((llen+yyleng) > (MAX_PARSE_BUFFER - 1))
|
|
yyerror("ERROR: quoted string parse buffer exceeded");
|
|
memcpy(literal+llen, yytext, yyleng+1);
|
|
llen += yyleng;
|
|
}
|
|
<xh>{xhcat} |
|
|
<xb>{xbcat} {
|
|
}
|
|
|
|
<SQL>{xhstart} {
|
|
BEGIN(xh);
|
|
llen = 0;
|
|
*literal = '\0';
|
|
}
|
|
<xh>{xhstop} {
|
|
char* endptr;
|
|
|
|
BEGIN(SQL);
|
|
errno = 0;
|
|
yylval.ival = strtol((char *)literal,&endptr,16);
|
|
if (*endptr != '\0' || errno == ERANGE)
|
|
yyerror("ERROR: Bad hexadecimal integer input");
|
|
return (ICONST);
|
|
}
|
|
|
|
<SQL>{xqstart} {
|
|
BEGIN(xq);
|
|
llen = 0;
|
|
*literal = '\0';
|
|
}
|
|
<xq>{xqstop} {
|
|
BEGIN(SQL);
|
|
yylval.str = strdup(scanstr(literal));
|
|
return (SCONST);
|
|
}
|
|
<xq>{xqdouble} |
|
|
<xq>{xqinside} {
|
|
if ((llen+yyleng) > (MAX_PARSE_BUFFER - 1))
|
|
yyerror("ERROR: quoted string parse buffer exceeded");
|
|
memcpy(literal+llen, yytext, yyleng+1);
|
|
llen += yyleng;
|
|
}
|
|
<xq>{xqembedded} {
|
|
if ((llen+yyleng-1) > (MAX_PARSE_BUFFER - 1))
|
|
yyerror("ERROR: quoted string parse buffer exceeded");
|
|
memcpy(literal+llen, yytext, yyleng+1);
|
|
*(literal+llen) = '\'';
|
|
llen += yyleng;
|
|
}
|
|
|
|
<xq>{xqliteral} {
|
|
if ((llen+yyleng-1) > (MAX_PARSE_BUFFER - 1))
|
|
yyerror("ERROR: quoted string parse buffer exceeded");
|
|
memcpy(literal+llen, yytext, yyleng+1);
|
|
llen += yyleng;
|
|
}
|
|
<xq>{xqcat} {
|
|
}
|
|
|
|
|
|
<SQL>{xdstart} {
|
|
BEGIN(xd);
|
|
llen = 0;
|
|
*literal = '\0';
|
|
}
|
|
<xd>{xdstop} {
|
|
BEGIN(SQL);
|
|
yylval.str = strdup(literal);
|
|
return (CSTRING);
|
|
}
|
|
<xd>{xdinside} {
|
|
if ((llen+yyleng) > (MAX_PARSE_BUFFER - 1))
|
|
yyerror("ERROR: quoted string parse buffer exceeded");
|
|
memcpy(literal+llen, yytext, yyleng+1);
|
|
llen += yyleng;
|
|
}
|
|
<C>{xdstart} {
|
|
BEGIN(xdc);
|
|
llen = 0;
|
|
*literal = '\0';
|
|
}
|
|
<xdc>{xdstop} {
|
|
BEGIN(C);
|
|
yylval.str = strdup(literal);
|
|
return (CSTRING);
|
|
}
|
|
<xdc>{xdinside} {
|
|
if ((llen+yyleng) > (MAX_PARSE_BUFFER - 1))
|
|
yyerror("ERROR: quoted string parse buffer exceeded");
|
|
memcpy(literal+llen, yytext, yyleng+1);
|
|
llen += yyleng;
|
|
}
|
|
|
|
<xm>{space}* { /* ignore */ }
|
|
<xm>{xmstop} {
|
|
BEGIN(SQL);
|
|
return (yytext[0]);
|
|
}
|
|
|
|
|
|
<SQL>{typecast} { return TYPECAST; }
|
|
|
|
<SQL>{self}/-[\.0-9] {
|
|
return (yytext[0]);
|
|
}
|
|
<SQL>{self} { return (yytext[0]); }
|
|
<SQL>{operator}/-[\.0-9] {
|
|
yylval.str = strdup((char*)yytext);
|
|
return (Op);
|
|
}
|
|
<SQL>{operator} {
|
|
if (strcmp((char*)yytext,"!=") == 0)
|
|
yylval.str = strdup("<>"); /* compatability */
|
|
else
|
|
yylval.str = strdup((char*)yytext);
|
|
return (Op);
|
|
}
|
|
<SQL>{param} {
|
|
yylval.ival = atoi((char*)&yytext[1]);
|
|
return (PARAM);
|
|
}
|
|
|
|
<SQL>{identifier}/{space}*-{number} {
|
|
int i;
|
|
ScanKeyword *keyword;
|
|
|
|
BEGIN(xm);
|
|
for(i = 0; yytext[i]; i++)
|
|
if (isupper(yytext[i]))
|
|
yytext[i] = tolower(yytext[i]);
|
|
|
|
keyword = ScanKeywordLookup((char*)yytext);
|
|
if (keyword != NULL) {
|
|
return (keyword->value);
|
|
}
|
|
else
|
|
{
|
|
keyword = ScanECPGKeywordLookup((char*)yytext);
|
|
if (keyword != NULL) {
|
|
return (keyword->value);
|
|
}
|
|
else
|
|
{
|
|
yylval.str = strdup((char*)yytext);
|
|
return (IDENT);
|
|
}
|
|
}
|
|
}
|
|
{integer}/{space}*-{number} {
|
|
char* endptr;
|
|
|
|
BEGIN(xm);
|
|
errno = 0;
|
|
yylval.ival = strtol((char *)yytext,&endptr,10);
|
|
if (*endptr != '\0' || errno == ERANGE)
|
|
{
|
|
errno = 0;
|
|
yylval.dval = strtod(((char *)yytext),&endptr);
|
|
if (*endptr != '\0' || errno == ERANGE)
|
|
yyerror("ERROR: Bad integer input");
|
|
yyerror("WARNING: Integer input is out of range; promoted to float");
|
|
return (FCONST);
|
|
}
|
|
return (ICONST);
|
|
}
|
|
{real}/{space}*-{number} {
|
|
char* endptr;
|
|
|
|
BEGIN(xm);
|
|
errno = 0;
|
|
yylval.dval = strtod(((char *)yytext),&endptr);
|
|
if (*endptr != '\0' || errno == ERANGE)
|
|
yyerror("ERROR: Bad float8 input");
|
|
return (FCONST);
|
|
}
|
|
{integer} {
|
|
char* endptr;
|
|
|
|
errno = 0;
|
|
yylval.ival = strtol((char *)yytext,&endptr,10);
|
|
if (*endptr != '\0' || errno == ERANGE)
|
|
{
|
|
errno = 0;
|
|
yylval.dval = strtod(((char *)yytext),&endptr);
|
|
if (*endptr != '\0' || errno == ERANGE)
|
|
yyerror("ERROR: Bad integer input");
|
|
yyerror("WARNING: Integer input is out of range; promoted to float");
|
|
return (FCONST);
|
|
}
|
|
return (ICONST);
|
|
}
|
|
{real} {
|
|
char* endptr;
|
|
|
|
errno = 0;
|
|
yylval.dval = strtod((char *)yytext,&endptr);
|
|
if (*endptr != '\0' || errno == ERANGE)
|
|
yyerror("ERROR: Bad float input");
|
|
return (FCONST);
|
|
}
|
|
|
|
<SQL>:{identifier} {
|
|
yylval.str = strdup((char*)yytext+1);
|
|
return(CVARIABLE);
|
|
}
|
|
<SQL>{identifier} {
|
|
int i;
|
|
ScanKeyword *keyword;
|
|
|
|
for(i = 0; yytext[i]; i++)
|
|
if (isupper(yytext[i]))
|
|
yytext[i] = tolower(yytext[i]);
|
|
|
|
keyword = ScanKeywordLookup((char*)yytext);
|
|
if (keyword != NULL) {
|
|
return (keyword->value);
|
|
}
|
|
else
|
|
{
|
|
keyword = ScanECPGKeywordLookup((char*)yytext);
|
|
if (keyword != NULL) {
|
|
return (keyword->value);
|
|
}
|
|
else
|
|
{
|
|
yylval.str = strdup((char*)yytext);
|
|
return (IDENT);
|
|
}
|
|
}
|
|
}
|
|
<SQL>{space} { /* ignore */ }
|
|
<SQL>";" { BEGIN C; return SQL_SEMI; }
|
|
<SQL>{other} { return (yytext[0]); }
|
|
|
|
<C>{exec}{space}{sql} { BEGIN SQL; return SQL_START; }
|
|
<C>{identifier} {
|
|
ScanKeyword *keyword;
|
|
|
|
keyword = ScanCKeywordLookup((char*)yytext);
|
|
if (keyword != NULL) {
|
|
return (keyword->value);
|
|
}
|
|
else
|
|
{
|
|
yylval.str = strdup((char*)yytext);
|
|
return (IDENT);
|
|
}
|
|
}
|
|
<C>";" { return(';'); }
|
|
<C>"," { return(','); }
|
|
<C>"*" { return('*'); }
|
|
<C>{space} { ECHO; }
|
|
<C>\{ { return('{'); }
|
|
<C>\} { return('}'); }
|
|
<C>\[ { return('['); }
|
|
<C>\] { return(']'); }
|
|
<C>\= { return('='); }
|
|
<C>{other} { return (S_ANYTHING); }
|
|
<C>{exec}{space}{sql}{space}{include} { BEGIN(incl); }
|
|
<incl>{space} /* eat the whitespace */
|
|
<incl>[^ \t\n]+ { /* got the include file name */
|
|
struct _yy_buffer *yb;
|
|
struct _include_path *ip;
|
|
char inc_file[PATH_MAX];
|
|
|
|
yb = mm_alloc(sizeof(struct _yy_buffer));
|
|
|
|
yb->buffer = YY_CURRENT_BUFFER;
|
|
yb->lineno = yylineno;
|
|
yb->filename = input_filename;
|
|
yb->next = yy_buffer;
|
|
|
|
yy_buffer = yb;
|
|
|
|
if (yytext[strlen(yytext) - 1] == ';')
|
|
yytext[strlen(yytext) - 1] = '\0';
|
|
|
|
yyin = NULL;
|
|
for (ip = include_paths; yyin == NULL && ip != NULL; ip = ip->next)
|
|
{
|
|
if (strlen(ip->path) + strlen(yytext) + 3 > PATH_MAX)
|
|
{
|
|
fprintf(stderr, "Error: Path %s/%s is too long in line %d, skipping.\n", ip->path, yytext, yylineno);
|
|
continue;
|
|
}
|
|
sprintf (inc_file, "%s/%s", ip->path, yytext);
|
|
yyin = fopen( inc_file, "r" );
|
|
if (!yyin)
|
|
{
|
|
if (strcmp(inc_file + strlen(inc_file) - 2, ".h"))
|
|
{
|
|
strcat(inc_file, ".h");
|
|
yyin = fopen( inc_file, "r" );
|
|
}
|
|
|
|
}
|
|
}
|
|
if (!yyin)
|
|
{
|
|
fprintf(stderr, "Error: Cannot open include file %s in line %d\n", yytext, yylineno);
|
|
exit(1);
|
|
}
|
|
|
|
input_filename = strdup(inc_file);
|
|
yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE ));
|
|
yylineno = 0;
|
|
|
|
BEGIN C;
|
|
}
|
|
<incl>";" { BEGIN C; }
|
|
<<EOF>> { if (yy_buffer == NULL)
|
|
yyterminate();
|
|
else
|
|
{
|
|
struct _yy_buffer *yb = yy_buffer;
|
|
|
|
if (yyin != NULL)
|
|
fclose(yyin);
|
|
|
|
yy_delete_buffer( YY_CURRENT_BUFFER );
|
|
yy_switch_to_buffer(yy_buffer->buffer);
|
|
|
|
yylineno = yy_buffer->lineno;
|
|
|
|
free(input_filename);
|
|
input_filename = yy_buffer->filename;
|
|
|
|
yy_buffer = yy_buffer->next;
|
|
free(yb);
|
|
}
|
|
}
|
|
|
|
%%
|
|
void
|
|
lex_init(void)
|
|
{
|
|
braces_open = 0;
|
|
BEGIN C;
|
|
}
|
|
|
|
int yywrap(void)
|
|
{
|
|
return 1;
|
|
}
|