mirror of https://github.com/postgres/postgres
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
256 lines
6.2 KiB
256 lines
6.2 KiB
![]()
30 years ago
|
%{
|
||
|
/*-------------------------------------------------------------------------
|
||
|
*
|
||
|
* scan.l--
|
||
|
* lexical scanner for POSTGRES
|
||
|
*
|
||
|
* Copyright (c) 1994, Regents of the University of California
|
||
|
*
|
||
|
*
|
||
|
* IDENTIFICATION
|
||
|
* $Header: /cvsroot/pgsql/src/backend/parser/scan.l,v 1.1.1.1 1996/07/09 06:21:41 scrappy Exp $
|
||
|
*
|
||
|
*-------------------------------------------------------------------------
|
||
|
*/
|
||
|
#include <ctype.h>
|
||
|
#ifndef WIN32
|
||
|
#include <unistd.h>
|
||
|
#endif /* WIN32 */
|
||
|
#ifndef __linux__
|
||
|
#include <math.h>
|
||
|
#else
|
||
|
#include <stdlib.h>
|
||
|
#endif /* __linux__ */
|
||
|
#include <string.h>
|
||
|
|
||
|
#include "postgres.h"
|
||
|
#include "miscadmin.h"
|
||
|
#include "nodes/pg_list.h"
|
||
|
#include "nodes/parsenodes.h"
|
||
|
#include "parser/keywords.h"
|
||
|
#include "parser/scansup.h"
|
||
|
#include "parse.h"
|
||
|
#include "utils/elog.h"
|
||
|
#include "utils/palloc.h"
|
||
|
|
||
|
extern char *parseString;
|
||
|
extern char *parseCh;
|
||
|
|
||
|
/* some versions of lex define this as a macro */
|
||
|
#if defined(yywrap)
|
||
|
#undef yywrap
|
||
|
#endif /* yywrap */
|
||
|
|
||
|
#if defined(FLEX_SCANNER)
|
||
|
/* MAX_PARSE_BUFFER is defined in miscadmin.h */
|
||
|
#define YYLMAX MAX_PARSE_BUFFER
|
||
|
extern int myinput(char* buf, int max);
|
||
|
#undef YY_INPUT
|
||
|
#define YY_INPUT(buf,result,max) {result = myinput(buf,max);}
|
||
|
#else
|
||
|
#undef input
|
||
|
int input();
|
||
|
#undef unput
|
||
|
void unput(char);
|
||
|
#endif /* FLEX_SCANNER */
|
||
|
|
||
|
extern YYSTYPE yylval;
|
||
|
%}
|
||
|
|
||
|
digit [0-9]
|
||
|
letter [_A-Za-z]
|
||
|
letter_or_digit [_A-Za-z0-9]
|
||
|
|
||
|
identifier {letter}{letter_or_digit}*
|
||
|
|
||
|
self [,()\[\].;$\:\+\-\*\/\<\>\=\|]
|
||
|
op_and_self [\~\!\@\#\%\^\&\|\`\?\$\:\+\-\*\/\<\>\=]
|
||
|
op_only [\~\!\@\#\%\^\&\`\?]
|
||
|
|
||
|
operator ({op_and_self}{op_and_self}+)|{op_only}+
|
||
|
/* we used to allow double-quoted strings, but SQL doesn't */
|
||
|
/* so we won't either*/
|
||
|
quote '
|
||
|
|
||
|
integer -?{digit}+
|
||
|
real -?{digit}+\.{digit}+([Ee][-+]?{digit}+)?
|
||
|
|
||
|
param \${integer}
|
||
|
|
||
|
comment "--".*\n
|
||
|
|
||
|
space [ \t\n\f]
|
||
|
other .
|
||
|
|
||
|
%%
|
||
|
{comment} { /* ignore */ }
|
||
|
|
||
|
"::" { return TYPECAST; }
|
||
|
|
||
|
{self} { return (yytext[0]); }
|
||
|
|
||
|
{operator} {
|
||
|
yylval.str = pstrdup((char*)yytext);
|
||
|
return (Op);
|
||
|
}
|
||
|
{param} { yylval.ival = atoi((char*)&yytext[1]);
|
||
|
return (PARAM);
|
||
|
}
|
||
|
{integer} {
|
||
|
yylval.ival = atoi((char*)yytext);
|
||
|
return (ICONST);
|
||
|
}
|
||
|
{real} {
|
||
|
yylval.dval = atof((char*)yytext);
|
||
|
return (FCONST);
|
||
|
}
|
||
|
{quote} {
|
||
|
char literal[MAX_PARSE_BUFFER];
|
||
|
int i = 0;
|
||
|
int c = 0;
|
||
|
/* quote_seen can be either \ or ' because
|
||
|
we handle both cases of \' and '' for
|
||
|
quoting quotes*/
|
||
|
int quote_seen = 0;
|
||
|
|
||
|
while (i < MAX_PARSE_BUFFER - 1) {
|
||
|
c = input();
|
||
|
if (quote_seen != 0) {
|
||
|
if (quote_seen == '\'' &&
|
||
|
c != '\'') {
|
||
|
/* a non-quote follows a single quote */
|
||
|
/* so we've hit the end of the literal */
|
||
|
if (c != '\0' && c != EOF)
|
||
|
unput(c); /* put back the extra char we read*/
|
||
|
i = i - 1;
|
||
|
break; /* break out of the while loop */
|
||
|
}
|
||
|
/* if we reach here, we're still in */
|
||
|
/* the string literal */
|
||
|
literal[i++] = c;
|
||
|
quote_seen = 0;
|
||
|
continue;
|
||
|
}
|
||
|
if (c == '\0' || c == EOF) {
|
||
|
elog(WARN,"unterminated quoted string literal");
|
||
|
/* not reached */
|
||
|
}
|
||
|
literal[i++] = c;
|
||
|
if (c == '\'' || c == '\\')
|
||
|
quote_seen = c;
|
||
|
}
|
||
|
if ( i == MAX_PARSE_BUFFER - 1) {
|
||
|
elog (WARN, "unterminated quote string. parse buffer of %d chars exceeded", MAX_PARSE_BUFFER);
|
||
|
/* not reached */
|
||
|
}
|
||
|
literal[i] = '\0';
|
||
|
yylval.str = pstrdup(scanstr(literal));
|
||
|
return (SCONST);
|
||
|
}
|
||
|
{identifier} {
|
||
|
ScanKeyword *keyword;
|
||
|
|
||
|
keyword = ScanKeywordLookup((char*)yytext);
|
||
|
if (keyword != NULL) {
|
||
|
return (keyword->value);
|
||
|
} else {
|
||
|
yylval.str = pstrdup((char*)yytext);
|
||
|
return (IDENT);
|
||
|
}
|
||
|
}
|
||
|
{space} { /* ignore */ }
|
||
|
|
||
|
{other} { return (yytext[0]); }
|
||
|
|
||
|
%%
|
||
|
|
||
|
void yyerror(char message[])
|
||
|
{
|
||
|
elog(WARN, "parser: %s at or near \"%s\"\n", message, yytext);
|
||
|
}
|
||
|
|
||
|
int yywrap()
|
||
|
{
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
init_io:
|
||
|
called by postgres before any actual parsing is done
|
||
|
*/
|
||
|
void
|
||
|
init_io()
|
||
|
{
|
||
|
/* it's important to set this to NULL
|
||
|
because input()/myinput() checks the non-nullness of parseCh
|
||
|
to know when to pass the string to lex/flex */
|
||
|
parseCh = NULL;
|
||
|
#if defined(FLEX_SCANNER)
|
||
|
if (YY_CURRENT_BUFFER)
|
||
|
yy_flush_buffer(YY_CURRENT_BUFFER);
|
||
|
#endif /* FLEX_SCANNER */
|
||
|
BEGIN INITIAL;
|
||
|
}
|
||
|
|
||
|
|
||
|
#if !defined(FLEX_SCANNER)
|
||
|
/* get lex input from a string instead of from stdin */
|
||
|
int
|
||
|
input()
|
||
|
{
|
||
|
if (parseCh == NULL) {
|
||
|
parseCh = parseString;
|
||
|
return(*parseCh++);
|
||
|
} else if (*parseCh == '\0') {
|
||
|
return(0);
|
||
|
} else {
|
||
|
return(*parseCh++);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* undo lex input from a string instead of from stdin */
|
||
|
void
|
||
|
unput(char c)
|
||
|
{
|
||
|
if (parseCh == NULL) {
|
||
|
elog(FATAL, "Unput() failed.\n");
|
||
|
} else if (c != 0) {
|
||
|
*--parseCh = c;
|
||
|
}
|
||
|
}
|
||
|
#endif /* !defined(FLEX_SCANNER) */
|
||
|
|
||
|
#ifdef FLEX_SCANNER
|
||
|
/* input routine for flex to read input from a string instead of a file */
|
||
|
int
|
||
|
myinput(char* buf, int max)
|
||
|
{
|
||
|
int len, copylen;
|
||
|
|
||
|
if (parseCh == NULL) {
|
||
|
len = strlen(parseString);
|
||
|
if (len >= max)
|
||
|
copylen = max - 1;
|
||
|
else
|
||
|
copylen = len;
|
||
|
if (copylen > 0)
|
||
|
memcpy(buf, parseString, copylen);
|
||
|
buf[copylen] = '\0';
|
||
|
parseCh = parseString;
|
||
|
return copylen;
|
||
|
} else {
|
||
|
return 0; /* end of string */
|
||
|
}
|
||
|
}
|
||
|
|
||
|
char*
|
||
|
CurScan(void)
|
||
|
{
|
||
|
/*
|
||
|
return (InputFrag ? InputFrag : parseCh) +
|
||
|
(yy_c_buf_p - &yy_current_buffer->yy_ch_buf[yy_n_chars]);
|
||
|
*/
|
||
|
}
|
||
|
#endif /* FLEX_SCANNER */
|
||
|
|