diff options
Diffstat (limited to 'src/backend/parser/scan.l')
-rw-r--r-- | src/backend/parser/scan.l | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/src/backend/parser/scan.l b/src/backend/parser/scan.l new file mode 100644 index 00000000000..d3b3b9a3f26 --- /dev/null +++ b/src/backend/parser/scan.l @@ -0,0 +1,255 @@ +%{ +/*------------------------------------------------------------------------- + * + * 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 */ + |