2 /**********************************************************************
3 * scan.l - Scanner for the PL/pgSQL
7 * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/Attic/scan.l,v 1.22 2002/08/30 00:28:41 tgl Exp $
9 * This software is copyrighted by Jan Wieck - Hamburg.
11 * The author hereby grants permission to use, copy, modify,
12 * distribute, and license this software and its documentation
13 * for any purpose, provided that existing copyright notices are
14 * retained in all copies and that this notice is included
15 * verbatim in any distributions. No written agreement, license,
16 * or royalty fee is required for any of the authorized uses.
17 * Modifications to this software may be copyrighted by their
18 * author and need not follow the licensing terms described
19 * here, provided that the new terms are clearly indicated on
20 * the first page of each file where they apply.
22 * IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY
23 * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR
24 * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS
25 * SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN
26 * IF THE AUTHOR HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
29 * THE AUTHOR AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY
30 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
31 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
32 * PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON
33 * AN "AS IS" BASIS, AND THE AUTHOR AND DISTRIBUTORS HAVE NO
34 * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
35 * ENHANCEMENTS, OR MODIFICATIONS.
37 **********************************************************************/
43 static char *plpgsql_source;
44 static int plpgsql_bytes_left;
45 static int scanner_functype;
46 static int scanner_typereported;
47 static int pushback_token;
48 static bool have_pushback_token;
49 static int lookahead_token;
50 static bool have_lookahead_token;
52 int plpgsql_SpaceScanned = 0;
54 static void plpgsql_input(char *buf, int *result, int max);
56 #define YY_INPUT(buf,res,max) plpgsql_input(buf, &res, max)
60 %option never-interactive
65 %option case-insensitive
68 %x IN_STRING IN_COMMENT
71 letter [\200-\377_A-Za-z]
72 letter_or_digit [\200-\377_A-Za-z0-9]
74 quoted_ident (\"[^\"]*\")+
76 identifier ({letter}{letter_or_digit}*|{quoted_ident})
82 * Local variable in scanner to remember where
83 * a string or comment started
89 * Reset the state when entering the scanner
93 plpgsql_SpaceScanned = 0;
96 * On the first call to a new source report the
97 * functions type (T_FUNCTION or T_TRIGGER)
100 if (!scanner_typereported)
102 scanner_typereported = 1;
103 return scanner_functype;
110 := { return K_ASSIGN; }
111 = { return K_ASSIGN; }
112 \.\. { return K_DOTDOT; }
113 alias { return K_ALIAS; }
114 begin { return K_BEGIN; }
115 close { return K_CLOSE; }
116 constant { return K_CONSTANT; }
117 cursor { return K_CURSOR; }
118 debug { return K_DEBUG; }
119 declare { return K_DECLARE; }
120 default { return K_DEFAULT; }
121 diagnostics { return K_DIAGNOSTICS; }
122 else { return K_ELSE; }
123 elsif { return K_ELSIF; }
124 end { return K_END; }
125 exception { return K_EXCEPTION; }
126 execute { return K_EXECUTE; }
127 exit { return K_EXIT; }
128 fetch { return K_FETCH; }
129 for { return K_FOR; }
130 from { return K_FROM; }
131 get { return K_GET; }
134 info { return K_INFO; }
135 into { return K_INTO; }
137 log { return K_LOG; }
138 loop { return K_LOOP; }
139 next { return K_NEXT; }
140 not { return K_NOT; }
141 notice { return K_NOTICE; }
142 null { return K_NULL; }
143 open { return K_OPEN; }
144 perform { return K_PERFORM; }
145 raise { return K_RAISE; }
146 record { return K_RECORD; }
147 rename { return K_RENAME; }
148 result_oid { return K_RESULT_OID; }
149 return { return K_RETURN; }
150 reverse { return K_REVERSE; }
151 row_count { return K_ROW_COUNT; }
152 select { return K_SELECT; }
153 then { return K_THEN; }
155 type { return K_TYPE; }
156 warning { return K_WARNING; }
157 when { return K_WHEN; }
158 while { return K_WHILE; }
160 ^#option { return O_OPTION; }
161 dump { return O_DUMP; }
168 {identifier} { return plpgsql_parse_word(yytext); }
169 {identifier}{space}*\.{space}*{identifier} { return plpgsql_parse_dblword(yytext); }
170 {identifier}{space}*\.{space}*{identifier}{space}*\.{space}*{identifier} { return plpgsql_parse_tripword(yytext); }
171 {identifier}{space}*%TYPE { return plpgsql_parse_wordtype(yytext); }
172 {identifier}{space}*\.{space}*{identifier}{space}*%TYPE { return plpgsql_parse_dblwordtype(yytext); }
173 {identifier}{space}*%ROWTYPE { return plpgsql_parse_wordrowtype(yytext); }
175 \${digit}+ { return plpgsql_parse_word(yytext); }
176 \${digit}+{space}*\.{space}*{identifier} { return plpgsql_parse_dblword(yytext); }
177 \${digit}+{space}*\.{space}*{identifier}{space}*\.{space}*{identifier} { return plpgsql_parse_tripword(yytext); }
178 \${digit}+{space}*%TYPE { return plpgsql_parse_wordtype(yytext); }
179 \${digit}+{space}*\.{space}*{identifier}{space}*%TYPE { return plpgsql_parse_dblwordtype(yytext); }
180 \${digit}+{space}*%ROWTYPE { return plpgsql_parse_wordrowtype(yytext); }
182 {digit}+ { return T_NUMBER; }
185 plpgsql_error_lineno = yylineno;
186 elog(ERROR, "unterminated quoted identifier");
190 * Ignore whitespaces but remember this happened
193 {space}+ { plpgsql_SpaceScanned = 1; }
201 \/\* { start_lineno = yylineno;
204 <IN_COMMENT>\*\/ { BEGIN INITIAL; plpgsql_SpaceScanned = 1; }
207 <IN_COMMENT><<EOF>> {
208 plpgsql_error_lineno = start_lineno;
209 elog(ERROR, "unterminated comment");
213 * Collect anything inside of ''s and return one STRING
216 ' { start_lineno = yylineno;
221 <IN_STRING>'' { yymore(); }
222 <IN_STRING>' { BEGIN INITIAL;
226 plpgsql_error_lineno = start_lineno;
227 elog(ERROR, "unterminated string");
229 <IN_STRING>[^'\\]* { yymore(); }
232 * Any unmatched character is returned as is
235 . { return yytext[0]; }
241 plpgsql_input(char *buf, int *result, int max)
245 if (n > plpgsql_bytes_left)
246 n = plpgsql_bytes_left;
255 memcpy(buf, plpgsql_source, n);
257 plpgsql_bytes_left -= n;
261 * This is the yylex routine called from outside. It exists to provide
262 * a pushback facility, as well as to allow us to parse syntax that
263 * requires more than one token of lookahead.
270 if (have_pushback_token)
272 have_pushback_token = false;
273 cur_token = pushback_token;
275 else if (have_lookahead_token)
277 have_lookahead_token = false;
278 cur_token = lookahead_token;
283 /* Do we need to look ahead for a possible multiword token? */
286 /* RETURN NEXT must be reduced to a single token */
288 if (!have_lookahead_token)
290 lookahead_token = yylex();
291 have_lookahead_token = true;
293 if (lookahead_token == K_NEXT)
295 have_lookahead_token = false;
296 cur_token = K_RETURN_NEXT;
308 * Push back a single token to be re-read by next plpgsql_yylex() call.
311 plpgsql_push_back_token(int token)
313 if (have_pushback_token)
314 elog(ERROR, "plpgsql_push_back_token: can't push back multiple tokens");
315 pushback_token = token;
316 have_pushback_token = true;
321 * Initialize the scanner for new input.
324 plpgsql_setinput(char *source, int functype)
329 plpgsql_source = source;
332 * Hack: skip any initial newline, so that in the common coding layout
333 * CREATE FUNCTION ... AS '
335 * ' LANGUAGE 'plpgsql';
336 * we will think "line 1" is what the programmer thinks of as line 1.
339 if (*plpgsql_source == '\r')
341 if (*plpgsql_source == '\n')
344 plpgsql_bytes_left = strlen(plpgsql_source);
346 scanner_functype = functype;
347 scanner_typereported = 0;
349 have_pushback_token = false;
350 have_lookahead_token = false;