• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 //
3 // Copyright 2002 The ANGLE Project Authors. All rights reserved.
4 // Use of this source code is governed by a BSD-style license that can be
5 // found in the LICENSE file.
6 //
7 
8 This file contains the Lex specification for GLSL ES preprocessor.
9 Based on Microsoft Visual Studio 2010 Preprocessor Grammar:
10 http://msdn.microsoft.com/en-us/library/2scxys89.aspx
11 
12 IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN scripts/run_code_generation.py
13 */
14 
15 %top{
16 // GENERATED FILE - DO NOT EDIT.
17 // Generated by generate_parser.py from preprocessor.l
18 //
19 // Copyright 2019 The ANGLE Project Authors. All rights reserved.
20 // Use of this source code is governed by a BSD-style license that can be
21 // found in the LICENSE file.
22 //
23 // preprocessor.l:
24 //   Lexer for the OpenGL shading language preprocessor.
25 
26 }
27 
28 %{
29 #if defined(_MSC_VER)
30 #pragma warning(disable: 4005)
31 #endif
32 
33 #include "compiler/preprocessor/Tokenizer.h"
34 
35 #include "compiler/preprocessor/DiagnosticsBase.h"
36 #include "compiler/preprocessor/Token.h"
37 
38 #if defined(__GNUC__)
39 // Triggered by the auto-generated yy_fatal_error function.
40 #pragma GCC diagnostic ignored "-Wmissing-noreturn"
41 #elif defined(_MSC_VER)
42 #pragma warning(disable: 4244)
43 #endif
44 #if defined(__clang__)
45 // Flex uses `/*FALLTHROUGH*/` instead of dedicated statements.
46 #pragma clang diagnostic ignored "-Wimplicit-fallthrough"
47 #if defined(__APPLE__)
48 // Older clang versions don't have -Wextra-semi-stmt, and detecting Apple clang versions is
49 // difficult because they use different yet overlapping version numbers vs. regular clang.
50 #pragma clang diagnostic ignored "-Wunknown-warning-option"
51 #endif
52 // Flex isn't semi-colon clean.
53 #pragma clang diagnostic ignored "-Wextra-semi-stmt"
54 #pragma clang diagnostic ignored "-Wunreachable-code"
55 #endif
56 
57 // Workaround for flex using the register keyword, deprecated in C++11.
58 #ifdef __cplusplus
59 #if __cplusplus > 199711L
60 #define register
61 #endif
62 #endif
63 
64 typedef std::string YYSTYPE;
65 typedef angle::pp::SourceLocation YYLTYPE;
66 
67 // Use the unused yycolumn variable to track file (string) number.
68 #define yyfileno yycolumn
69 
70 #define YY_USER_INIT                   \
71     do {                               \
72         yyfileno = 0;                  \
73         yylineno = 1;                  \
74         yyextra->leadingSpace = false; \
75         yyextra->lineStart = true;     \
76     } while(0);
77 
78 #define YY_NO_INPUT
79 #define YY_USER_ACTION                                              \
80     do                                                              \
81     {                                                               \
82         angle::pp::Input* input = &yyextra->input;                  \
83         angle::pp::Input::Location* scanLoc = &yyextra->scanLoc;    \
84         while ((scanLoc->sIndex < input->count()) &&                \
85                (scanLoc->cIndex >= input->length(scanLoc->sIndex))) \
86         {                                                           \
87             scanLoc->cIndex -= input->length(scanLoc->sIndex++);    \
88             ++yyfileno; yylineno = 1;                               \
89         }                                                           \
90         yylloc->file = yyfileno;                                    \
91         yylloc->line = yylineno;                                    \
92         scanLoc->cIndex += yyleng;                                  \
93     } while(0);
94 
95 #define YY_INPUT(buf, result, maxSize) \
96     result = yyextra->input.read(buf, maxSize, &yylineno);
97 
98 %}
99 
100 %option noyywrap nounput never-interactive
101 %option reentrant bison-bridge bison-locations
102 %option prefix="pp"
103 %option extra-type="angle::pp::Tokenizer::Context*"
104 %x COMMENT
105 
106 NEWLINE     \n|\r|\r\n
107 IDENTIFIER  [_a-zA-Z][_a-zA-Z0-9]*
108 PUNCTUATOR  [][<>(){}.+-/*%^|&~=!:;,?]
109 
110 DECIMAL_CONSTANT      [1-9][0-9]*[uU]?
111 OCTAL_CONSTANT        0[0-7]*[uU]?
112 HEXADECIMAL_CONSTANT  0[xX][0-9a-fA-F]+[uU]?
113 
114 DIGIT                [0-9]
115 EXPONENT_PART        [eE][+-]?{DIGIT}+
116 FRACTIONAL_CONSTANT  ({DIGIT}*"."{DIGIT}+)|({DIGIT}+".")
117 
118 %%
119 
120     /* Line comment */
121 "//"[^\r\n]*
122 
123     /* Block comment */
124     /* Line breaks are just counted - not returned. */
125     /* The comment is replaced by a single space. */
126 "/*" { BEGIN(COMMENT); }
127 <COMMENT>[^*\r\n]+
128 <COMMENT>"*"
129 <COMMENT>{NEWLINE} {
130     if (yylineno == INT_MAX)
131     {
132         *yylval = "Integer overflow on line number";
133         return angle::pp::Token::GOT_ERROR;
134     }
135     ++yylineno;
136 }
137 <COMMENT>"*/" {
138     yyextra->leadingSpace = true;
139     BEGIN(INITIAL);
140 }
141 
142 # {
143     // # is only valid at start of line for preprocessor directives.
144     yylval->assign(1, yytext[0]);
145     return yyextra->lineStart ? angle::pp::Token::PP_HASH : angle::pp::Token::PP_OTHER;
146 }
147 
148 {IDENTIFIER} {
149     yylval->assign(yytext, yyleng);
150     return angle::pp::Token::IDENTIFIER;
151 }
152 
153 ({DECIMAL_CONSTANT}[uU]?)|({OCTAL_CONSTANT}[uU]?)|({HEXADECIMAL_CONSTANT}[uU]?) {
154     yylval->assign(yytext, yyleng);
155     return angle::pp::Token::CONST_INT;
156 }
157 
158 ({DIGIT}+{EXPONENT_PART}[fF]?)|({FRACTIONAL_CONSTANT}{EXPONENT_PART}?[fF]?) {
159     yylval->assign(yytext, yyleng);
160     return angle::pp::Token::CONST_FLOAT;
161 }
162 
163     /* Anything that starts with a {DIGIT} or .{DIGIT} must be a number. */
164     /* Rule to catch all invalid integers and floats. */
165 ({DIGIT}+[_a-zA-Z0-9.]*)|("."{DIGIT}+[_a-zA-Z0-9.]*) {
166     yylval->assign(yytext, yyleng);
167     return angle::pp::Token::PP_NUMBER;
168 }
169 
170 "++" {
171     yylval->assign(yytext, yyleng);
172     return angle::pp::Token::OP_INC;
173 }
174 "--" {
175     yylval->assign(yytext, yyleng);
176     return angle::pp::Token::OP_DEC;
177 }
178 "<<" {
179     yylval->assign(yytext, yyleng);
180     return angle::pp::Token::OP_LEFT;
181 }
182 ">>" {
183     yylval->assign(yytext, yyleng);
184     return angle::pp::Token::OP_RIGHT;
185 }
186 "<=" {
187     yylval->assign(yytext, yyleng);
188     return angle::pp::Token::OP_LE;
189 }
190 ">=" {
191     yylval->assign(yytext, yyleng);
192     return angle::pp::Token::OP_GE;
193 }
194 "==" {
195     yylval->assign(yytext, yyleng);
196     return angle::pp::Token::OP_EQ;
197 }
198 "!=" {
199     yylval->assign(yytext, yyleng);
200     return angle::pp::Token::OP_NE;
201 }
202 "&&" {
203     yylval->assign(yytext, yyleng);
204     return angle::pp::Token::OP_AND;
205 }
206 "^^" {
207     yylval->assign(yytext, yyleng);
208     return angle::pp::Token::OP_XOR;
209 }
210 "||" {
211     yylval->assign(yytext, yyleng);
212     return angle::pp::Token::OP_OR;
213 }
214 "+=" {
215     yylval->assign(yytext, yyleng);
216     return angle::pp::Token::OP_ADD_ASSIGN;
217 }
218 "-=" {
219     yylval->assign(yytext, yyleng);
220     return angle::pp::Token::OP_SUB_ASSIGN;
221 }
222 "*=" {
223     yylval->assign(yytext, yyleng);
224     return angle::pp::Token::OP_MUL_ASSIGN;
225 }
226 "/=" {
227     yylval->assign(yytext, yyleng);
228     return angle::pp::Token::OP_DIV_ASSIGN;
229 }
230 "%=" {
231     yylval->assign(yytext, yyleng);
232     return angle::pp::Token::OP_MOD_ASSIGN;
233 }
234 "<<=" {
235     yylval->assign(yytext, yyleng);
236     return angle::pp::Token::OP_LEFT_ASSIGN;
237 }
238 ">>=" {
239     yylval->assign(yytext, yyleng);
240     return angle::pp::Token::OP_RIGHT_ASSIGN;
241 }
242 "&=" {
243     yylval->assign(yytext, yyleng);
244     return angle::pp::Token::OP_AND_ASSIGN;
245 }
246 "^=" {
247     yylval->assign(yytext, yyleng);
248     return angle::pp::Token::OP_XOR_ASSIGN;
249 }
250 "|=" {
251     yylval->assign(yytext, yyleng);
252     return angle::pp::Token::OP_OR_ASSIGN;
253 }
254 
255 {PUNCTUATOR} {
256     yylval->assign(1, yytext[0]);
257     return yytext[0];
258 }
259 
260 [ \t\v\f]+   { yyextra->leadingSpace = true; }
261 
262 {NEWLINE} {
263     if (yylineno == INT_MAX)
264     {
265         *yylval = "Integer overflow on line number";
266         return angle::pp::Token::GOT_ERROR;
267     }
268     ++yylineno;
269     yylval->assign(1, '\n');
270     return '\n';
271 }
272 
273 . {
274     yylval->assign(1, yytext[0]);
275     return angle::pp::Token::PP_OTHER;
276 }
277 
278 <*><<EOF>> {
279     // YY_USER_ACTION is not invoked for handling EOF.
280     // Set the location for EOF token manually.
281     angle::pp::Input* input = &yyextra->input;
282     angle::pp::Input::Location* scanLoc = &yyextra->scanLoc;
283     yy_size_t sIndexMax = input->count() ? input->count() - 1 : 0;
284     if (scanLoc->sIndex != sIndexMax)
285     {
286         // We can only reach here if there are empty strings at the
287         // end of the input.
288         scanLoc->sIndex = sIndexMax; scanLoc->cIndex = 0;
289         // FIXME: this is not 64-bit clean.
290         yyfileno = static_cast<int>(sIndexMax); yylineno = 1;
291     }
292     yylloc->file = yyfileno;
293     yylloc->line = yylineno;
294     yylval->clear();
295 
296     // Line number overflows fake EOFs to exit early, check for this case.
297     if (yylineno == INT_MAX) {
298         yyextra->diagnostics->report(angle::pp::Diagnostics::PP_TOKENIZER_ERROR,
299                 angle::pp::SourceLocation(yyfileno, yylineno),
300                 "Integer overflow on line number");
301     }
302     else if (YY_START == COMMENT)
303     {
304         yyextra->diagnostics->report(angle::pp::Diagnostics::PP_EOF_IN_COMMENT,
305                                      angle::pp::SourceLocation(yyfileno, yylineno),
306                                      "EOF while in a comment");
307     }
308     yyterminate();
309 }
310 
311 %%
312 
313 namespace angle {
314 
315 namespace pp {
316 
317 Tokenizer::Tokenizer(Diagnostics *diagnostics) : mHandle(nullptr), mMaxTokenSize(256)
318 {
319     mContext.diagnostics = diagnostics;
320 }
321 
322 Tokenizer::~Tokenizer()
323 {
324     destroyScanner();
325 }
326 
327 bool Tokenizer::init(size_t count, const char * const string[], const int length[])
328 {
329     if ((count > 0) && (string == 0))
330         return false;
331 
332     mContext.input = Input(count, string, length);
333     return initScanner();
334 }
335 
336 void Tokenizer::setFileNumber(int file)
337 {
338     // We use column number as file number.
339     // See macro yyfileno.
340     yyset_column(file, mHandle);
341 }
342 
343 void Tokenizer::setLineNumber(int line)
344 {
345     yyset_lineno(line, mHandle);
346 }
347 
348 void Tokenizer::setMaxTokenSize(size_t maxTokenSize)
349 {
350     mMaxTokenSize = maxTokenSize;
351 }
352 
353 void Tokenizer::lex(Token *token)
354 {
355     int tokenType = yylex(&token->text, &token->location, mHandle);
356 
357     if (tokenType == Token::GOT_ERROR)
358     {
359         mContext.diagnostics->report(Diagnostics::PP_TOKENIZER_ERROR, token->location, token->text);
360         token->type = Token::LAST;
361     }
362     else
363     {
364         token->type = tokenType;
365     }
366 
367     if (token->text.size() > mMaxTokenSize)
368     {
369         mContext.diagnostics->report(Diagnostics::PP_TOKEN_TOO_LONG,
370                                      token->location, token->text);
371         token->text.erase(mMaxTokenSize);
372     }
373 
374     token->flags = 0;
375 
376     token->setAtStartOfLine(mContext.lineStart);
377     mContext.lineStart = token->type == '\n';
378 
379     token->setHasLeadingSpace(mContext.leadingSpace);
380     mContext.leadingSpace = false;
381 }
382 
383 bool Tokenizer::initScanner()
384 {
385     if ((mHandle == nullptr) && yylex_init_extra(&mContext, &mHandle))
386         return false;
387 
388     yyrestart(0, mHandle);
389     return true;
390 }
391 
392 void Tokenizer::destroyScanner()
393 {
394     if (mHandle == nullptr)
395         return;
396 
397     yylex_destroy(mHandle);
398     mHandle = nullptr;
399 }
400 
401 }  // namespace pp
402 
403 } // namespace angle
404 
405