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
16This file contains the Lex specification for GLSL ES preprocessor.
17Based on Microsoft Visual Studio 2010 Preprocessor Grammar:
18http://msdn.microsoft.com/en-us/library/2scxys89.aspx
19
20IF 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
65typedef std::string YYSTYPE;
66typedef 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
106NEWLINE     \n|\r|\r\n
107IDENTIFIER  [_a-zA-Z][_a-zA-Z0-9]*
108PUNCTUATOR  [][<>(){}.+-/*%^|&~=!:;,?]
109
110DECIMAL_CONSTANT      [1-9][0-9]*[uU]?
111OCTAL_CONSTANT        0[0-7]*[uU]?
112HEXADECIMAL_CONSTANT  0[xX][0-9a-fA-F]+[uU]?
113
114DIGIT                [0-9]
115EXPONENT_PART        [eE][+-]?{DIGIT}+
116FRACTIONAL_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
313namespace pp {
314
315Tokenizer::Tokenizer(Diagnostics *diagnostics) : mHandle(nullptr), mMaxTokenSize(1024)
316{
317    mContext.diagnostics = diagnostics;
318}
319
320Tokenizer::~Tokenizer()
321{
322    destroyScanner();
323}
324
325bool 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
334void Tokenizer::setFileNumber(int file)
335{
336    // We use column number as file number.
337    // See macro yyfileno.
338    yyset_column(file, mHandle);
339}
340
341void Tokenizer::setLineNumber(int line)
342{
343    yyset_lineno(line, mHandle);
344}
345
346void Tokenizer::setMaxTokenSize(size_t maxTokenSize)
347{
348    mMaxTokenSize = maxTokenSize;
349}
350
351void 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
381bool 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
390void Tokenizer::destroyScanner()
391{
392    if (mHandle == nullptr)
393        return;
394
395    yylex_destroy(mHandle);
396    mHandle = nullptr;
397}
398
399}  // namespace pp
400
401