PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
parser.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * parser.c
4  * Main entry point/driver for PostgreSQL grammar
5  *
6  * This should match src/backend/parser/parser.c, except that we do not
7  * need to bother with re-entrant interfaces.
8  *
9  *
10  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
11  * Portions Copyright (c) 1994, Regents of the University of California
12  *
13  * IDENTIFICATION
14  * src/interfaces/ecpg/preproc/parser.c
15  *
16  *-------------------------------------------------------------------------
17  */
18 
19 #include "postgres_fe.h"
20 
21 #include "extern.h"
22 #include "preproc.h"
23 
24 
25 static bool have_lookahead; /* is lookahead info valid? */
26 static int lookahead_token; /* one-token lookahead */
27 static YYSTYPE lookahead_yylval; /* yylval for lookahead token */
28 static YYLTYPE lookahead_yylloc; /* yylloc for lookahead token */
29 static char *lookahead_yytext; /* start current token */
30 static char *lookahead_end; /* end of current token */
31 static char lookahead_hold_char; /* to be put back at *lookahead_end */
32 
33 
34 /*
35  * Intermediate filter between parser and base lexer (base_yylex in scan.l).
36  *
37  * This filter is needed because in some cases the standard SQL grammar
38  * requires more than one token lookahead. We reduce these cases to one-token
39  * lookahead by replacing tokens here, in order to keep the grammar LALR(1).
40  *
41  * Using a filter is simpler than trying to recognize multiword tokens
42  * directly in scan.l, because we'd have to allow for comments between the
43  * words. Furthermore it's not clear how to do that without re-introducing
44  * scanner backtrack, which would cost more performance than this filter
45  * layer does.
46  */
47 int
49 {
50  int cur_token;
51  int next_token;
52  int cur_token_length;
53  YYSTYPE cur_yylval;
54  YYLTYPE cur_yylloc;
55  char *cur_yytext;
56 
57  /* Get next token --- we might already have it */
58  if (have_lookahead)
59  {
60  cur_token = lookahead_token;
61  base_yylval = lookahead_yylval;
62  base_yylloc = lookahead_yylloc;
65  have_lookahead = false;
66  }
67  else
68  cur_token = base_yylex();
69 
70  /*
71  * If this token isn't one that requires lookahead, just return it. If it
72  * does, determine the token length. (We could get that via strlen(), but
73  * since we have such a small set of possibilities, hardwiring seems
74  * feasible and more efficient.)
75  */
76  switch (cur_token)
77  {
78  case NOT:
79  cur_token_length = 3;
80  break;
81  case NULLS_P:
82  cur_token_length = 5;
83  break;
84  case WITH:
85  cur_token_length = 4;
86  break;
87  default:
88  return cur_token;
89  }
90 
91  /*
92  * Identify end+1 of current token. base_yylex() has temporarily stored a
93  * '\0' here, and will undo that when we call it again. We need to redo
94  * it to fully revert the lookahead call for error reporting purposes.
95  */
96  lookahead_end = base_yytext + cur_token_length;
97  Assert(*lookahead_end == '\0');
98 
99  /* Save and restore lexer output variables around the call */
100  cur_yylval = base_yylval;
101  cur_yylloc = base_yylloc;
102  cur_yytext = base_yytext;
103 
104  /* Get next token, saving outputs into lookahead variables */
105  next_token = base_yylex();
106 
108  lookahead_yylval = base_yylval;
109  lookahead_yylloc = base_yylloc;
111 
112  base_yylval = cur_yylval;
113  base_yylloc = cur_yylloc;
114  base_yytext = cur_yytext;
115 
116  /* Now revert the un-truncation of the current token */
118  *lookahead_end = '\0';
119 
120  have_lookahead = true;
121 
122  /* Replace cur_token if needed, based on lookahead */
123  switch (cur_token)
124  {
125  case NOT:
126  /* Replace NOT by NOT_LA if it's followed by BETWEEN, IN, etc */
127  switch (next_token)
128  {
129  case BETWEEN:
130  case IN_P:
131  case LIKE:
132  case ILIKE:
133  case SIMILAR:
134  cur_token = NOT_LA;
135  break;
136  }
137  break;
138 
139  case NULLS_P:
140  /* Replace NULLS_P by NULLS_LA if it's followed by FIRST or LAST */
141  switch (next_token)
142  {
143  case FIRST_P:
144  case LAST_P:
145  cur_token = NULLS_LA;
146  break;
147  }
148  break;
149 
150  case WITH:
151  /* Replace WITH by WITH_LA if it's followed by TIME or ORDINALITY */
152  switch (next_token)
153  {
154  case TIME:
155  case ORDINALITY:
156  cur_token = WITH_LA;
157  break;
158  }
159  break;
160  }
161 
162  return cur_token;
163 }
static char lookahead_hold_char
Definition: parser.c:31
static bool have_lookahead
Definition: parser.c:25
static char * lookahead_end
Definition: parser.c:30
static bool next_token(char **lineptr, char *buf, int bufsz, bool *initial_quote, bool *terminating_comma, int elevel, char **err_msg)
Definition: hba.c:194
static char * lookahead_yytext
Definition: parser.c:29
#define YYLTYPE
Definition: scanner.h:44
int base_yylex(YYSTYPE *lvalp, YYLTYPE *llocp, core_yyscan_t yyscanner)
Definition: parser.c:83
int filtered_base_yylex(void)
Definition: parser.c:48
static YYLTYPE lookahead_yylloc
Definition: parser.c:28
#define Assert(condition)
Definition: c.h:670
char * base_yytext
static int lookahead_token
Definition: parser.c:26
static YYSTYPE lookahead_yylval
Definition: parser.c:27