• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 // Copyright 2016 The SwiftShader Authors. All Rights Reserved.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //    http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 
16 This file contains the Lex specification for GLSL ES preprocessor.
17 Based on Microsoft Visual Studio 2010 Preprocessor Grammar:
18 http://msdn.microsoft.com/en-us/library/2scxys89.aspx
19 
20 IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh.
21 */
22 
23 %top{
24 // Copyright 2016 The SwiftShader Authors. All Rights Reserved.
25 //
26 // Licensed under the Apache License, Version 2.0 (the "License");
27 // you may not use this file except in compliance with the License.
28 // You may obtain a copy of the License at
29 //
30 //    http://www.apache.org/licenses/LICENSE-2.0
31 //
32 // Unless required by applicable law or agreed to in writing, software
33 // distributed under the License is distributed on an "AS IS" BASIS,
34 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
35 // See the License for the specific language governing permissions and
36 // limitations under the License.
37 
38 // This file is auto-generated by generate_parser.sh. DO NOT EDIT!
39 }
40 
41 %{
42 #if defined(_MSC_VER)
43 #pragma warning(disable: 4005)
44 #endif
45 
46 #include "Tokenizer.h"
47 
48 #include "DiagnosticsBase.h"
49 #include "Token.h"
50 
51 #if defined(__GNUC__)
52 // Triggered by the auto-generated yy_fatal_error function.
53 #pragma GCC diagnostic ignored "-Wmissing-noreturn"
54 #elif defined(_MSC_VER)
55 #pragma warning(disable: 4244)
56 #endif
57 
58 // Workaround for flex using the register keyword, deprecated in C++11.
59 #ifdef __cplusplus
60 #if __cplusplus > 199711L
61 #define register
62 #endif
63 #endif
64 
65 typedef std::string YYSTYPE;
66 typedef pp::SourceLocation YYLTYPE;
67 
68 // Use the unused yycolumn variable to track file (string) number.
69 #define yyfileno yycolumn
70 
71 #define YY_USER_INIT                   \
72     do {                               \
73         yyfileno = 0;                  \
74         yylineno = 1;                  \
75         yyextra->leadingSpace = false; \
76         yyextra->lineStart = true;     \
77     } while(0);
78 
79 #define YY_USER_ACTION                                              \
80     do                                                              \
81     {                                                               \
82         pp::Input* input = &yyextra->input;                         \
83         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="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 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 ? pp::Token::PP_HASH : pp::Token::PP_OTHER;
146 }
147 
148 {IDENTIFIER} {
149     yylval->assign(yytext, yyleng);
150     return pp::Token::IDENTIFIER;
151 }
152 
153 ({DECIMAL_CONSTANT}[uU]?)|({OCTAL_CONSTANT}[uU]?)|({HEXADECIMAL_CONSTANT}[uU]?) {
154     yylval->assign(yytext, yyleng);
155     return pp::Token::CONST_INT;
156 }
157 
158 ({DIGIT}+{EXPONENT_PART}[fF]?)|({FRACTIONAL_CONSTANT}{EXPONENT_PART}?[fF]?) {
159     yylval->assign(yytext, yyleng);
160     return 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 pp::Token::PP_NUMBER;
168 }
169 
170 "++" {
171     yylval->assign(yytext, yyleng);
172     return pp::Token::OP_INC;
173 }
174 "--" {
175     yylval->assign(yytext, yyleng);
176     return pp::Token::OP_DEC;
177 }
178 "<<" {
179     yylval->assign(yytext, yyleng);
180     return pp::Token::OP_LEFT;
181 }
182 ">>" {
183     yylval->assign(yytext, yyleng);
184     return pp::Token::OP_RIGHT;
185 }
186 "<=" {
187     yylval->assign(yytext, yyleng);
188     return pp::Token::OP_LE;
189 }
190 ">=" {
191     yylval->assign(yytext, yyleng);
192     return pp::Token::OP_GE;
193 }
194 "==" {
195     yylval->assign(yytext, yyleng);
196     return pp::Token::OP_EQ;
197 }
198 "!=" {
199     yylval->assign(yytext, yyleng);
200     return pp::Token::OP_NE;
201 }
202 "&&" {
203     yylval->assign(yytext, yyleng);
204     return pp::Token::OP_AND;
205 }
206 "^^" {
207     yylval->assign(yytext, yyleng);
208     return pp::Token::OP_XOR;
209 }
210 "||" {
211     yylval->assign(yytext, yyleng);
212     return pp::Token::OP_OR;
213 }
214 "+=" {
215     yylval->assign(yytext, yyleng);
216     return pp::Token::OP_ADD_ASSIGN;
217 }
218 "-=" {
219     yylval->assign(yytext, yyleng);
220     return pp::Token::OP_SUB_ASSIGN;
221 }
222 "*=" {
223     yylval->assign(yytext, yyleng);
224     return pp::Token::OP_MUL_ASSIGN;
225 }
226 "/=" {
227     yylval->assign(yytext, yyleng);
228     return pp::Token::OP_DIV_ASSIGN;
229 }
230 "%=" {
231     yylval->assign(yytext, yyleng);
232     return pp::Token::OP_MOD_ASSIGN;
233 }
234 "<<=" {
235     yylval->assign(yytext, yyleng);
236     return pp::Token::OP_LEFT_ASSIGN;
237 }
238 ">>=" {
239     yylval->assign(yytext, yyleng);
240     return pp::Token::OP_RIGHT_ASSIGN;
241 }
242 "&=" {
243     yylval->assign(yytext, yyleng);
244     return pp::Token::OP_AND_ASSIGN;
245 }
246 "^=" {
247     yylval->assign(yytext, yyleng);
248     return pp::Token::OP_XOR_ASSIGN;
249 }
250 "|=" {
251     yylval->assign(yytext, yyleng);
252     return 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 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 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     pp::Input* input = &yyextra->input;
282     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(pp::Diagnostics::PP_TOKENIZER_ERROR,
299                 pp::SourceLocation(yyfileno, yylineno),
300                 "Integer overflow on line number");
301     }
302     else if (YY_START == COMMENT)
303     {
304         yyextra->diagnostics->report(pp::Diagnostics::PP_EOF_IN_COMMENT,
305                                      pp::SourceLocation(yyfileno, yylineno),
306                                      "EOF while in a comment");
307     }
308     yyterminate();
309 }
310 
311 %%
312 
313 namespace pp {
314 
315 Tokenizer::Tokenizer(Diagnostics *diagnostics) : mHandle(nullptr), mMaxTokenSize(1024)
316 {
317     mContext.diagnostics = diagnostics;
318 }
319 
320 Tokenizer::~Tokenizer()
321 {
322     destroyScanner();
323 }
324 
325 bool Tokenizer::init(size_t count, const char * const string[], const int length[])
326 {
327     if ((count > 0) && (string == 0))
328         return false;
329 
330     mContext.input = Input(count, string, length);
331     return initScanner();
332 }
333 
334 void Tokenizer::setFileNumber(int file)
335 {
336     // We use column number as file number.
337     // See macro yyfileno.
338     yyset_column(file, mHandle);
339 }
340 
341 void Tokenizer::setLineNumber(int line)
342 {
343     yyset_lineno(line, mHandle);
344 }
345 
346 void Tokenizer::setMaxTokenSize(size_t maxTokenSize)
347 {
348     mMaxTokenSize = maxTokenSize;
349 }
350 
351 void Tokenizer::lex(Token *token)
352 {
353     int tokenType = yylex(&token->text, &token->location, mHandle);
354 
355     if (tokenType == Token::GOT_ERROR)
356     {
357         mContext.diagnostics->report(Diagnostics::PP_TOKENIZER_ERROR, token->location, token->text);
358         token->type = Token::LAST;
359     }
360     else
361     {
362         token->type = tokenType;
363     }
364 
365     if (token->text.size() > mMaxTokenSize)
366     {
367         mContext.diagnostics->report(Diagnostics::PP_TOKEN_TOO_LONG,
368                                      token->location, token->text);
369         token->text.erase(mMaxTokenSize);
370     }
371 
372     token->flags = 0;
373 
374     token->setAtStartOfLine(mContext.lineStart);
375     mContext.lineStart = token->type == '\n';
376 
377     token->setHasLeadingSpace(mContext.leadingSpace);
378     mContext.leadingSpace = false;
379 }
380 
381 bool Tokenizer::initScanner()
382 {
383     if ((mHandle == nullptr) && yylex_init_extra(&mContext, &mHandle))
384         return false;
385 
386     yyrestart(0, mHandle);
387     return true;
388 }
389 
390 void Tokenizer::destroyScanner()
391 {
392     if (mHandle == nullptr)
393         return;
394 
395     yylex_destroy(mHandle);
396     mHandle = nullptr;
397 }
398 
399 }  // namespace pp
400 
401