2 /**********************************************************************
3 * scan.l - Scanner for the PL/pgSQL
7 * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/Attic/scan.l,v 1.24 2002/11/07 06:06:17 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 **********************************************************************/
42 static char *plpgsql_source;
43 static int plpgsql_bytes_left;
44 static int scanner_functype;
45 static int scanner_typereported;
46 static int pushback_token;
47 static bool have_pushback_token;
48 static int lookahead_token;
49 static bool have_lookahead_token;
51 int plpgsql_SpaceScanned = 0;
53 static void plpgsql_input(char *buf, int *result, int max);
55 #define YY_INPUT(buf,res,max) plpgsql_input(buf, &res, max)
59 %option never-interactive
64 %option case-insensitive
67 %x IN_STRING IN_COMMENT
70 letter [\200-\377_A-Za-z]
71 letter_or_digit [\200-\377_A-Za-z0-9]
73 quoted_ident (\"[^\"]*\")+
75 identifier ({letter}{letter_or_digit}*|{quoted_ident})
81 * Local variable in scanner to remember where
82 * a string or comment started
88 * Reset the state when entering the scanner
92 plpgsql_SpaceScanned = 0;
95 * On the first call to a new source report the
96 * functions type (T_FUNCTION or T_TRIGGER)
99 if (!scanner_typereported)
101 scanner_typereported = 1;
102 return scanner_functype;
109 := { return K_ASSIGN; }
110 = { return K_ASSIGN; }
111 \.\. { return K_DOTDOT; }
112 alias { return K_ALIAS; }
113 begin { return K_BEGIN; }
114 close { return K_CLOSE; }
115 constant { return K_CONSTANT; }
116 cursor { return K_CURSOR; }
117 debug { return K_DEBUG; }
118 declare { return K_DECLARE; }
119 default { return K_DEFAULT; }
120 diagnostics { return K_DIAGNOSTICS; }
121 else { return K_ELSE; }
122 elsif { return K_ELSIF; }
123 end { return K_END; }
124 exception { return K_EXCEPTION; }
125 execute { return K_EXECUTE; }
126 exit { return K_EXIT; }
127 fetch { return K_FETCH; }
128 for { return K_FOR; }
129 from { return K_FROM; }
130 get { return K_GET; }
133 info { return K_INFO; }
134 into { return K_INTO; }
136 log { return K_LOG; }
137 loop { return K_LOOP; }
138 next { return K_NEXT; }
139 not { return K_NOT; }
140 notice { return K_NOTICE; }
141 null { return K_NULL; }
142 open { return K_OPEN; }
143 perform { return K_PERFORM; }
144 raise { return K_RAISE; }
145 record { return K_RECORD; }
146 rename { return K_RENAME; }
147 result_oid { return K_RESULT_OID; }
148 return { return K_RETURN; }
149 reverse { return K_REVERSE; }
150 row_count { return K_ROW_COUNT; }
151 select { return K_SELECT; }
152 then { return K_THEN; }
154 type { return K_TYPE; }
155 warning { return K_WARNING; }
156 when { return K_WHEN; }
157 while { return K_WHILE; }
159 ^#option { return O_OPTION; }
160 dump { return O_DUMP; }
167 {identifier} { return plpgsql_parse_word(yytext); }
168 {identifier}{space}*\.{space}*{identifier} { return plpgsql_parse_dblword(yytext); }
169 {identifier}{space}*\.{space}*{identifier}{space}*\.{space}*{identifier} { return plpgsql_parse_tripword(yytext); }
170 {identifier}{space}*%TYPE { return plpgsql_parse_wordtype(yytext); }
171 {identifier}{space}*\.{space}*{identifier}{space}*%TYPE { return plpgsql_parse_dblwordtype(yytext); }
172 {identifier}{space}*\.{space}*{identifier}{space}*\.{space}*{identifier}{space}*%TYPE { return plpgsql_parse_tripwordtype(yytext); }
173 {identifier}{space}*%ROWTYPE { return plpgsql_parse_wordrowtype(yytext); }
174 {identifier}{space}*\.{space}*{identifier}{space}*%ROWTYPE { return plpgsql_parse_dblwordrowtype(yytext); }
176 \${digit}+ { return plpgsql_parse_word(yytext); }
177 \${digit}+{space}*\.{space}*{identifier} { return plpgsql_parse_dblword(yytext); }
178 \${digit}+{space}*\.{space}*{identifier}{space}*\.{space}*{identifier} { return plpgsql_parse_tripword(yytext); }
179 \${digit}+{space}*%TYPE { return plpgsql_parse_wordtype(yytext); }
180 \${digit}+{space}*\.{space}*{identifier}{space}*%TYPE { return plpgsql_parse_dblwordtype(yytext); }
181 \${digit}+{space}*\.{space}*{identifier}{space}*\.{space}*{identifier}{space}*%TYPE { return plpgsql_parse_tripwordtype(yytext); }
182 \${digit}+{space}*%ROWTYPE { return plpgsql_parse_wordrowtype(yytext); }
183 \${digit}+{space}*\.{space}*{identifier}{space}*%ROWTYPE { return plpgsql_parse_dblwordrowtype(yytext); }
185 {digit}+ { return T_NUMBER; }
188 plpgsql_error_lineno = yylineno;
189 elog(ERROR, "unterminated quoted identifier");
193 * Ignore whitespaces but remember this happened
196 {space}+ { plpgsql_SpaceScanned = 1; }
204 \/\* { start_lineno = yylineno;
207 <IN_COMMENT>\*\/ { BEGIN INITIAL; plpgsql_SpaceScanned = 1; }
210 <IN_COMMENT><<EOF>> {
211 plpgsql_error_lineno = start_lineno;
212 elog(ERROR, "unterminated comment");
216 * Collect anything inside of ''s and return one STRING
219 ' { start_lineno = yylineno;
224 <IN_STRING>'' { yymore(); }
225 <IN_STRING>' { BEGIN INITIAL;
229 plpgsql_error_lineno = start_lineno;
230 elog(ERROR, "unterminated string");
232 <IN_STRING>[^'\\]* { yymore(); }
235 * Any unmatched character is returned as is
238 . { return yytext[0]; }
244 plpgsql_input(char *buf, int *result, int max)
248 if (n > plpgsql_bytes_left)
249 n = plpgsql_bytes_left;
258 memcpy(buf, plpgsql_source, n);
260 plpgsql_bytes_left -= n;
264 * This is the yylex routine called from outside. It exists to provide
265 * a pushback facility, as well as to allow us to parse syntax that
266 * requires more than one token of lookahead.
273 if (have_pushback_token)
275 have_pushback_token = false;
276 cur_token = pushback_token;
278 else if (have_lookahead_token)
280 have_lookahead_token = false;
281 cur_token = lookahead_token;
286 /* Do we need to look ahead for a possible multiword token? */
289 /* RETURN NEXT must be reduced to a single token */
291 if (!have_lookahead_token)
293 lookahead_token = yylex();
294 have_lookahead_token = true;
296 if (lookahead_token == K_NEXT)
298 have_lookahead_token = false;
299 cur_token = K_RETURN_NEXT;
311 * Push back a single token to be re-read by next plpgsql_yylex() call.
314 plpgsql_push_back_token(int token)
316 if (have_pushback_token)
317 elog(ERROR, "plpgsql_push_back_token: can't push back multiple tokens");
318 pushback_token = token;
319 have_pushback_token = true;
324 * Initialize the scanner for new input.
327 plpgsql_setinput(char *source, int functype)
332 plpgsql_source = source;
335 * Hack: skip any initial newline, so that in the common coding layout
336 * CREATE FUNCTION ... AS '
338 * ' LANGUAGE 'plpgsql';
339 * we will think "line 1" is what the programmer thinks of as line 1.
342 if (*plpgsql_source == '\r')
344 if (*plpgsql_source == '\n')
347 plpgsql_bytes_left = strlen(plpgsql_source);
349 scanner_functype = functype;
350 scanner_typereported = 0;
352 have_pushback_token = false;
353 have_lookahead_token = false;