mirror of
https://github.com/postgres/postgres.git
synced 2025-05-21 00:02:53 -04:00
distinction between the external API (parser.h) and declarations that only need to be visible within the raw parser code (gramparse.h, which now is only included by parser.c, gram.y, scan.l, and keywords.c). This is in preparation for the upcoming change to a reentrant lexer, which will require referencing YYSTYPE in the declarations of base_yylex and filtered_base_yylex, hence gram.h will have to be included by gramparse.h. We don't want any more files than absolutely necessary to depend on gram.h, so some cleanup is called for.
190 lines
4.7 KiB
C
190 lines
4.7 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* parser.c
|
|
* Main entry point/driver for PostgreSQL grammar
|
|
*
|
|
* Note that the grammar is not allowed to perform any table access
|
|
* (since we need to be able to do basic parsing even while inside an
|
|
* aborted transaction). Therefore, the data structures returned by
|
|
* the grammar are "raw" parsetrees that still need to be analyzed by
|
|
* analyze.c and related files.
|
|
*
|
|
*
|
|
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
*
|
|
* IDENTIFICATION
|
|
* $PostgreSQL: pgsql/src/backend/parser/parser.c,v 1.79 2009/07/12 17:12:34 tgl Exp $
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
|
|
#include "parser/gramparse.h"
|
|
#include "parser/parser.h"
|
|
|
|
|
|
List *parsetree; /* result of parsing is left here */
|
|
|
|
static bool have_lookahead; /* is lookahead info valid? */
|
|
static int lookahead_token; /* one-token lookahead */
|
|
static YYSTYPE lookahead_yylval; /* yylval for lookahead token */
|
|
static YYLTYPE lookahead_yylloc; /* yylloc for lookahead token */
|
|
|
|
|
|
/*
|
|
* raw_parser
|
|
* Given a query in string form, do lexical and grammatical analysis.
|
|
*
|
|
* Returns a list of raw (un-analyzed) parse trees.
|
|
*/
|
|
List *
|
|
raw_parser(const char *str)
|
|
{
|
|
int yyresult;
|
|
|
|
parsetree = NIL; /* in case grammar forgets to set it */
|
|
have_lookahead = false;
|
|
|
|
scanner_init(str);
|
|
parser_init();
|
|
|
|
yyresult = base_yyparse();
|
|
|
|
scanner_finish();
|
|
|
|
if (yyresult) /* error */
|
|
return NIL;
|
|
|
|
return parsetree;
|
|
}
|
|
|
|
|
|
/*
|
|
* pg_parse_string_token - get the value represented by a string literal
|
|
*
|
|
* Given the textual form of a SQL string literal, produce the represented
|
|
* value as a palloc'd string. It is caller's responsibility that the
|
|
* passed string does represent one single string literal.
|
|
*
|
|
* We export this function to avoid having plpgsql depend on internal details
|
|
* of the core grammar (such as the token code assigned to SCONST). Note
|
|
* that since the scanner isn't presently re-entrant, this cannot be used
|
|
* during use of the main parser/scanner.
|
|
*/
|
|
char *
|
|
pg_parse_string_token(const char *token)
|
|
{
|
|
int ctoken;
|
|
|
|
scanner_init(token);
|
|
|
|
ctoken = base_yylex();
|
|
|
|
if (ctoken != SCONST) /* caller error */
|
|
elog(ERROR, "expected string constant, got token code %d", ctoken);
|
|
|
|
scanner_finish();
|
|
|
|
return base_yylval.str;
|
|
}
|
|
|
|
|
|
/*
|
|
* Intermediate filter between parser and base lexer (base_yylex in scan.l).
|
|
*
|
|
* The filter is needed because in some cases the standard SQL grammar
|
|
* requires more than one token lookahead. We reduce these cases to one-token
|
|
* lookahead by combining tokens here, in order to keep the grammar LALR(1).
|
|
*
|
|
* Using a filter is simpler than trying to recognize multiword tokens
|
|
* directly in scan.l, because we'd have to allow for comments between the
|
|
* words. Furthermore it's not clear how to do it without re-introducing
|
|
* scanner backtrack, which would cost more performance than this filter
|
|
* layer does.
|
|
*/
|
|
int
|
|
filtered_base_yylex(void)
|
|
{
|
|
int cur_token;
|
|
int next_token;
|
|
YYSTYPE cur_yylval;
|
|
YYLTYPE cur_yylloc;
|
|
|
|
/* Get next token --- we might already have it */
|
|
if (have_lookahead)
|
|
{
|
|
cur_token = lookahead_token;
|
|
base_yylval = lookahead_yylval;
|
|
base_yylloc = lookahead_yylloc;
|
|
have_lookahead = false;
|
|
}
|
|
else
|
|
cur_token = base_yylex();
|
|
|
|
/* Do we need to look ahead for a possible multiword token? */
|
|
switch (cur_token)
|
|
{
|
|
case NULLS_P:
|
|
|
|
/*
|
|
* NULLS FIRST and NULLS LAST must be reduced to one token
|
|
*/
|
|
cur_yylval = base_yylval;
|
|
cur_yylloc = base_yylloc;
|
|
next_token = base_yylex();
|
|
switch (next_token)
|
|
{
|
|
case FIRST_P:
|
|
cur_token = NULLS_FIRST;
|
|
break;
|
|
case LAST_P:
|
|
cur_token = NULLS_LAST;
|
|
break;
|
|
default:
|
|
/* save the lookahead token for next time */
|
|
lookahead_token = next_token;
|
|
lookahead_yylval = base_yylval;
|
|
lookahead_yylloc = base_yylloc;
|
|
have_lookahead = true;
|
|
/* and back up the output info to cur_token */
|
|
base_yylval = cur_yylval;
|
|
base_yylloc = cur_yylloc;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case WITH:
|
|
|
|
/*
|
|
* WITH TIME must be reduced to one token
|
|
*/
|
|
cur_yylval = base_yylval;
|
|
cur_yylloc = base_yylloc;
|
|
next_token = base_yylex();
|
|
switch (next_token)
|
|
{
|
|
case TIME:
|
|
cur_token = WITH_TIME;
|
|
break;
|
|
default:
|
|
/* save the lookahead token for next time */
|
|
lookahead_token = next_token;
|
|
lookahead_yylval = base_yylval;
|
|
lookahead_yylloc = base_yylloc;
|
|
have_lookahead = true;
|
|
/* and back up the output info to cur_token */
|
|
base_yylval = cur_yylval;
|
|
base_yylloc = cur_yylloc;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return cur_token;
|
|
}
|