glsl/glcpp: Drop extra, final newline from most output
[mesa.git] / src / glsl / glcpp / glcpp-lex.l
1 %{
2 /*
3 * Copyright © 2010 Intel Corporation
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24
25 #include <stdio.h>
26 #include <string.h>
27 #include <ctype.h>
28
29 #include "glcpp.h"
30 #include "glcpp-parse.h"
31
32 /* Flex annoyingly generates some functions without making them
33 * static. Let's declare them here. */
34 int glcpp_get_column (yyscan_t yyscanner);
35 void glcpp_set_column (int column_no , yyscan_t yyscanner);
36
37 #ifdef _MSC_VER
38 #define YY_NO_UNISTD_H
39 #endif
40
41 #define YY_NO_INPUT
42
43 #define YY_USER_ACTION \
44 do { \
45 if (parser->has_new_line_number) \
46 yylineno = parser->new_line_number; \
47 if (parser->has_new_source_number) \
48 yylloc->source = parser->new_source_number; \
49 yylloc->first_column = yycolumn + 1; \
50 yylloc->first_line = yylloc->last_line = yylineno; \
51 yycolumn += yyleng; \
52 yylloc->last_column = yycolumn + 1; \
53 parser->has_new_line_number = 0; \
54 parser->has_new_source_number = 0; \
55 } while(0);
56
57 #define YY_USER_INIT \
58 do { \
59 yylineno = 1; \
60 yycolumn = 1; \
61 yylloc->source = 0; \
62 } while(0)
63
64 #define RETURN_TOKEN(token) \
65 do { \
66 if (token == NEWLINE) \
67 parser->last_token_was_newline = 1; \
68 else \
69 parser->last_token_was_newline = 0; \
70 return (token); \
71 } while(0)
72
73 %}
74
75 %option bison-bridge bison-locations reentrant noyywrap
76 %option extra-type="glcpp_parser_t *"
77 %option prefix="glcpp_"
78 %option stack
79 %option never-interactive
80
81 %x DONE COMMENT UNREACHABLE SKIP DEFINE NEWLINE_CATCHUP
82
83 SPACE [[:space:]]
84 NONSPACE [^[:space:]]
85 NEWLINE [\n]
86 HSPACE [ \t]
87 HASH ^{HSPACE}*#{HSPACE}*
88 IDENTIFIER [_a-zA-Z][_a-zA-Z0-9]*
89 PP_NUMBER [.]?[0-9]([._a-zA-Z0-9]|[eEpP][-+])*
90 PUNCTUATION [][(){}.&*~!/%<>^|;,=+-]
91
92 /* The OTHER class is simply a catch-all for things that the CPP
93 parser just doesn't care about. Since flex regular expressions that
94 match longer strings take priority over those matching shorter
95 strings, we have to be careful to avoid OTHER matching and hiding
96 something that CPP does care about. So we simply exclude all
97 characters that appear in any other expressions. */
98
99 OTHER [^][_#[:space:]#a-zA-Z0-9(){}.&*~!/%<>^|;,=+-]
100
101 DIGITS [0-9][0-9]*
102 DECIMAL_INTEGER [1-9][0-9]*[uU]?
103 OCTAL_INTEGER 0[0-7]*[uU]?
104 HEXADECIMAL_INTEGER 0[xX][0-9a-fA-F]+[uU]?
105
106 %%
107
108 glcpp_parser_t *parser = yyextra;
109
110 /* When we lex a multi-line comment, we replace it (as
111 * specified) with a single space. But if the comment spanned
112 * multiple lines, then subsequent parsing stages will not
113 * count correct line numbers. To avoid this problem we keep
114 * track of all newlines that were commented out by a
115 * multi-line comment, and we emit a NEWLINE token for each at
116 * the next legal opportunity, (which is when the lexer would
117 * be emitting a NEWLINE token anyway).
118 */
119 if (YY_START == NEWLINE_CATCHUP) {
120 if (parser->commented_newlines)
121 parser->commented_newlines--;
122 if (parser->commented_newlines == 0)
123 BEGIN INITIAL;
124 RETURN_TOKEN (NEWLINE);
125 }
126
127 /* The handling of the SKIP vs INITIAL start states requires
128 * some special handling. Typically, a lexer would change
129 * start states with statements like "BEGIN SKIP" within the
130 * lexer rules. We can't get away with that here, since we
131 * need the parser to actually evaluate expressions for
132 * directives like "#if".
133 *
134 * So, here, in code that will be executed on every call to
135 * the lexer,and before any rules, we examine the skip_stack
136 * as set by the parser to know whether to change from INITIAL
137 * to SKIP or from SKIP back to INITIAL.
138 *
139 * Three cases cause us to switch out of the SKIP state and
140 * back to the INITIAL state:
141 *
142 * 1. The top of the skip_stack is of type SKIP_NO_SKIP
143 * This means we're still evaluating some #if
144 * hierarchy, but we're on a branch of it where
145 * content should not be skipped (such as "#if 1" or
146 * "#else" or so).
147 *
148 * 2. The skip_stack is NULL meaning that we've reached
149 * the last #endif.
150 *
151 * 3. The lexing_directive bit is set. This indicates that we are
152 * lexing a pre-processor directive, (such as #if, #elif, or
153 * #else). For the #if and #elif directives we always need to
154 * parse the conditions, (even if otherwise within an #if
155 * 0). And for #else, we want to be able to generate an error
156 * if any garbage follows #else.
157 */
158 if (YY_START == INITIAL || YY_START == SKIP) {
159 if (parser->lexing_directive ||
160 parser->skip_stack == NULL ||
161 parser->skip_stack->type == SKIP_NO_SKIP)
162 {
163 BEGIN INITIAL;
164 } else {
165 BEGIN SKIP;
166 }
167 }
168
169 /* Single-line comments */
170 "//"[^\n]* {
171 }
172
173 /* Multi-line comments */
174 <DEFINE,INITIAL>"/*" { yy_push_state(COMMENT, yyscanner); }
175 <COMMENT>[^*\n]*
176 <COMMENT>[^*\n]*\n { yylineno++; yycolumn = 0; parser->commented_newlines++; }
177 <COMMENT>"*"+[^*/\n]*
178 <COMMENT>"*"+[^*/\n]*\n { yylineno++; yycolumn = 0; parser->commented_newlines++; }
179 <COMMENT>"*"+"/" {
180 yy_pop_state(yyscanner);
181 if (yyextra->space_tokens)
182 RETURN_TOKEN (SPACE);
183 }
184
185 {HASH}version{HSPACE}+ {
186 yylval->str = ralloc_strdup (yyextra, yytext);
187 yyextra->space_tokens = 0;
188 RETURN_TOKEN (HASH_VERSION);
189 }
190
191 /* glcpp doesn't handle #extension, #version, or #pragma directives.
192 * Simply pass them through to the main compiler's lexer/parser. */
193 {HASH}(extension|pragma)[^\n]* {
194 yylval->str = ralloc_strdup (yyextra, yytext);
195 yylineno++;
196 yycolumn = 0;
197 RETURN_TOKEN (OTHER);
198 }
199
200 {HASH}line{HSPACE}+ {
201 RETURN_TOKEN (HASH_LINE);
202 }
203
204 <SKIP,INITIAL>{
205 {HASH}ifdef {
206 yyextra->lexing_directive = 1;
207 yyextra->space_tokens = 0;
208 RETURN_TOKEN (HASH_IFDEF);
209 }
210
211 {HASH}ifndef {
212 yyextra->lexing_directive = 1;
213 yyextra->space_tokens = 0;
214 RETURN_TOKEN (HASH_IFNDEF);
215 }
216
217 {HASH}if/[^_a-zA-Z0-9] {
218 yyextra->lexing_directive = 1;
219 yyextra->space_tokens = 0;
220 RETURN_TOKEN (HASH_IF);
221 }
222
223 {HASH}elif/[^_a-zA-Z0-9] {
224 yyextra->lexing_directive = 1;
225 yyextra->space_tokens = 0;
226 RETURN_TOKEN (HASH_ELIF);
227 }
228
229 {HASH}else {
230 yyextra->space_tokens = 0;
231 RETURN_TOKEN (HASH_ELSE);
232 }
233
234 {HASH}endif {
235 yyextra->space_tokens = 0;
236 RETURN_TOKEN (HASH_ENDIF);
237 }
238 }
239
240 <SKIP>[^\n] {
241 }
242
243 {HASH}error.* {
244 char *p;
245 for (p = yytext; !isalpha(p[0]); p++); /* skip " # " */
246 p += 5; /* skip "error" */
247 glcpp_error(yylloc, yyextra, "#error%s", p);
248 }
249
250 /* After we see a "#define" we enter the <DEFINE> start state
251 * for the lexer. Within <DEFINE> we are looking for the first
252 * identifier and specifically checking whether the identifier
253 * is followed by a '(' or not, (to lex either a
254 * FUNC_IDENTIFIER or an OBJ_IDENITIFIER token).
255 *
256 * While in the <DEFINE> state we also need to explicitly
257 * handle a few other things that may appear before the
258 * identifier:
259 *
260 * * Comments, (handled above with the main support for
261 * comments).
262 *
263 * * Whitespace (simply ignored)
264 *
265 * * Anything else, (not an identifier, not a comment,
266 * and not whitespace). This will generate an error.
267 */
268 {HASH}define{HSPACE}+ {
269 yyextra->space_tokens = 0;
270 yy_push_state(DEFINE, yyscanner);
271 RETURN_TOKEN (HASH_DEFINE);
272 }
273
274 /* An identifier immediately followed by '(' */
275 <DEFINE>{IDENTIFIER}/"(" {
276 yy_pop_state(yyscanner);
277 yylval->str = ralloc_strdup (yyextra, yytext);
278 RETURN_TOKEN (FUNC_IDENTIFIER);
279 }
280
281 /* An identifier not immediately followed by '(' */
282 <DEFINE>{IDENTIFIER} {
283 yy_pop_state(yyscanner);
284 yylval->str = ralloc_strdup (yyextra, yytext);
285 RETURN_TOKEN (OBJ_IDENTIFIER);
286 }
287
288 /* Whitespace */
289 <DEFINE>{HSPACE}+ {
290 /* Just ignore it. Nothing to do here. */
291 }
292
293 /* '/' not followed by '*', so not a comment. This is an error. */
294 <DEFINE>[/][^*]{NONSPACE}* {
295 BEGIN INITIAL;
296 glcpp_error(yylloc, yyextra, "#define followed by a non-identifier: %s", yytext);
297 RETURN_TOKEN (INTEGER_STRING);
298 }
299
300 /* A character that can't start an identifier, comment, or
301 * space. This is an error. */
302 <DEFINE>[^_a-zA-Z/[:space:]]{NONSPACE}* {
303 BEGIN INITIAL;
304 glcpp_error(yylloc, yyextra, "#define followed by a non-identifier: %s", yytext);
305 RETURN_TOKEN (INTEGER_STRING);
306 }
307
308 {HASH}undef {
309 yyextra->space_tokens = 0;
310 RETURN_TOKEN (HASH_UNDEF);
311 }
312
313 {HASH} {
314 yyextra->space_tokens = 0;
315 RETURN_TOKEN (HASH);
316 }
317
318 {DECIMAL_INTEGER} {
319 yylval->str = ralloc_strdup (yyextra, yytext);
320 RETURN_TOKEN (INTEGER_STRING);
321 }
322
323 {OCTAL_INTEGER} {
324 yylval->str = ralloc_strdup (yyextra, yytext);
325 RETURN_TOKEN (INTEGER_STRING);
326 }
327
328 {HEXADECIMAL_INTEGER} {
329 yylval->str = ralloc_strdup (yyextra, yytext);
330 RETURN_TOKEN (INTEGER_STRING);
331 }
332
333 "<<" {
334 RETURN_TOKEN (LEFT_SHIFT);
335 }
336
337 ">>" {
338 RETURN_TOKEN (RIGHT_SHIFT);
339 }
340
341 "<=" {
342 RETURN_TOKEN (LESS_OR_EQUAL);
343 }
344
345 ">=" {
346 RETURN_TOKEN (GREATER_OR_EQUAL);
347 }
348
349 "==" {
350 RETURN_TOKEN (EQUAL);
351 }
352
353 "!=" {
354 RETURN_TOKEN (NOT_EQUAL);
355 }
356
357 "&&" {
358 RETURN_TOKEN (AND);
359 }
360
361 "||" {
362 RETURN_TOKEN (OR);
363 }
364
365 "##" {
366 if (parser->is_gles)
367 glcpp_error(yylloc, yyextra, "Token pasting (##) is illegal in GLES");
368 RETURN_TOKEN (PASTE);
369 }
370
371 "defined" {
372 RETURN_TOKEN (DEFINED);
373 }
374
375 {IDENTIFIER} {
376 yylval->str = ralloc_strdup (yyextra, yytext);
377 RETURN_TOKEN (IDENTIFIER);
378 }
379
380 {PP_NUMBER} {
381 yylval->str = ralloc_strdup (yyextra, yytext);
382 RETURN_TOKEN (OTHER);
383 }
384
385 {PUNCTUATION} {
386 RETURN_TOKEN (yytext[0]);
387 }
388
389 {OTHER}+ {
390 yylval->str = ralloc_strdup (yyextra, yytext);
391 RETURN_TOKEN (OTHER);
392 }
393
394 {HSPACE} {
395 if (yyextra->space_tokens) {
396 RETURN_TOKEN (SPACE);
397 }
398 }
399
400 <SKIP,INITIAL>\n {
401 if (parser->commented_newlines) {
402 BEGIN NEWLINE_CATCHUP;
403 }
404 yyextra->space_tokens = 1;
405 yyextra->lexing_directive = 0;
406 yylineno++;
407 yycolumn = 0;
408 RETURN_TOKEN (NEWLINE);
409 }
410
411 <INITIAL,COMMENT,DEFINE><<EOF>> {
412 if (YY_START == COMMENT)
413 glcpp_error(yylloc, yyextra, "Unterminated comment");
414 if (YY_START == DEFINE)
415 glcpp_error(yylloc, yyextra, "#define without macro name");
416 BEGIN DONE; /* Don't keep matching this rule forever. */
417 yyextra->lexing_directive = 0;
418 if (! parser->last_token_was_newline)
419 RETURN_TOKEN (NEWLINE);
420 }
421
422 /* We don't actually use the UNREACHABLE start condition. We
423 only have this action here so that we can pretend to call some
424 generated functions, (to avoid "defined but not used"
425 warnings. */
426 <UNREACHABLE>. {
427 unput('.');
428 yy_top_state(yyextra);
429 }
430
431 %%
432
433 void
434 glcpp_lex_set_source_string(glcpp_parser_t *parser, const char *shader)
435 {
436 yy_scan_string(shader, parser->scanner);
437 }