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.
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
12
IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN scripts/run_code_generation.py
16
// GENERATED FILE - DO NOT EDIT.
17
// Generated by generate_parser.py from preprocessor.l
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.
24
// Lexer for the OpenGL shading language preprocessor.
30
#pragma warning(disable: 4005)
33
#include "compiler/preprocessor/Tokenizer.h"
35
#include "compiler/preprocessor/DiagnosticsBase.h"
36
#include "compiler/preprocessor/Token.h"
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)
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"
52
// Flex isn't semi-colon clean.
53
#pragma clang diagnostic ignored "-Wextra-semi-stmt"
54
#pragma clang diagnostic ignored "-Wunreachable-code"
57
// Workaround for flex using the register keyword, deprecated in C++11.
59
#if __cplusplus > 199711L
64
typedef std::string YYSTYPE;
65
typedef angle::pp::SourceLocation YYLTYPE;
67
// Use the unused yycolumn variable to track file (string) number.
68
#define yyfileno yycolumn
70
#define YY_USER_INIT \
74
yyextra->leadingSpace = false; \
75
yyextra->lineStart = true; \
79
#define YY_USER_ACTION \
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))) \
87
scanLoc->cIndex -= input->length(scanLoc->sIndex++); \
88
++yyfileno; yylineno = 1; \
90
yylloc->file = yyfileno; \
91
yylloc->line = yylineno; \
92
scanLoc->cIndex += yyleng; \
95
#define YY_INPUT(buf, result, maxSize) \
96
result = yyextra->input.read(buf, maxSize, &yylineno);
100
%option noyywrap nounput never-interactive
101
%option reentrant bison-bridge bison-locations
103
%option extra-type="angle::pp::Tokenizer::Context*"
107
IDENTIFIER [_a-zA-Z][_a-zA-Z0-9]*
108
PUNCTUATOR [][<>(){}.+-/*%^|&~=!:;,?]
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]?
115
EXPONENT_PART [eE][+-]?{DIGIT}+
116
FRACTIONAL_CONSTANT ({DIGIT}*"."{DIGIT}+)|({DIGIT}+".")
124
/* Line breaks are just counted - not returned. */
125
/* The comment is replaced by a single space. */
126
"/*" { BEGIN(COMMENT); }
130
if (yylineno == INT_MAX)
132
*yylval = "Integer overflow on line number";
133
return angle::pp::Token::GOT_ERROR;
138
yyextra->leadingSpace = true;
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;
149
yylval->assign(yytext, yyleng);
150
return angle::pp::Token::IDENTIFIER;
153
({DECIMAL_CONSTANT}[uU]?)|({OCTAL_CONSTANT}[uU]?)|({HEXADECIMAL_CONSTANT}[uU]?) {
154
yylval->assign(yytext, yyleng);
155
return angle::pp::Token::CONST_INT;
158
({DIGIT}+{EXPONENT_PART}[fF]?)|({FRACTIONAL_CONSTANT}{EXPONENT_PART}?[fF]?) {
159
yylval->assign(yytext, yyleng);
160
return angle::pp::Token::CONST_FLOAT;
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;
171
yylval->assign(yytext, yyleng);
172
return angle::pp::Token::OP_INC;
175
yylval->assign(yytext, yyleng);
176
return angle::pp::Token::OP_DEC;
179
yylval->assign(yytext, yyleng);
180
return angle::pp::Token::OP_LEFT;
183
yylval->assign(yytext, yyleng);
184
return angle::pp::Token::OP_RIGHT;
187
yylval->assign(yytext, yyleng);
188
return angle::pp::Token::OP_LE;
191
yylval->assign(yytext, yyleng);
192
return angle::pp::Token::OP_GE;
195
yylval->assign(yytext, yyleng);
196
return angle::pp::Token::OP_EQ;
199
yylval->assign(yytext, yyleng);
200
return angle::pp::Token::OP_NE;
203
yylval->assign(yytext, yyleng);
204
return angle::pp::Token::OP_AND;
207
yylval->assign(yytext, yyleng);
208
return angle::pp::Token::OP_XOR;
211
yylval->assign(yytext, yyleng);
212
return angle::pp::Token::OP_OR;
215
yylval->assign(yytext, yyleng);
216
return angle::pp::Token::OP_ADD_ASSIGN;
219
yylval->assign(yytext, yyleng);
220
return angle::pp::Token::OP_SUB_ASSIGN;
223
yylval->assign(yytext, yyleng);
224
return angle::pp::Token::OP_MUL_ASSIGN;
227
yylval->assign(yytext, yyleng);
228
return angle::pp::Token::OP_DIV_ASSIGN;
231
yylval->assign(yytext, yyleng);
232
return angle::pp::Token::OP_MOD_ASSIGN;
235
yylval->assign(yytext, yyleng);
236
return angle::pp::Token::OP_LEFT_ASSIGN;
239
yylval->assign(yytext, yyleng);
240
return angle::pp::Token::OP_RIGHT_ASSIGN;
243
yylval->assign(yytext, yyleng);
244
return angle::pp::Token::OP_AND_ASSIGN;
247
yylval->assign(yytext, yyleng);
248
return angle::pp::Token::OP_XOR_ASSIGN;
251
yylval->assign(yytext, yyleng);
252
return angle::pp::Token::OP_OR_ASSIGN;
256
yylval->assign(1, yytext[0]);
260
[ \t\v\f]+ { yyextra->leadingSpace = true; }
263
if (yylineno == INT_MAX)
265
*yylval = "Integer overflow on line number";
266
return angle::pp::Token::GOT_ERROR;
269
yylval->assign(1, '\n');
274
yylval->assign(1, yytext[0]);
275
return angle::pp::Token::PP_OTHER;
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)
286
// We can only reach here if there are empty strings at the
288
scanLoc->sIndex = sIndexMax; scanLoc->cIndex = 0;
289
// FIXME: this is not 64-bit clean.
290
yyfileno = static_cast<int>(sIndexMax); yylineno = 1;
292
yylloc->file = yyfileno;
293
yylloc->line = yylineno;
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");
302
else if (YY_START == COMMENT)
304
yyextra->diagnostics->report(angle::pp::Diagnostics::PP_EOF_IN_COMMENT,
305
angle::pp::SourceLocation(yyfileno, yylineno),
306
"EOF while in a comment");
317
Tokenizer::Tokenizer(Diagnostics *diagnostics) : mHandle(nullptr), mMaxTokenSize(256)
319
mContext.diagnostics = diagnostics;
322
Tokenizer::~Tokenizer()
327
bool Tokenizer::init(size_t count, const char * const string[], const int length[])
329
if ((count > 0) && (string == 0))
332
mContext.input = Input(count, string, length);
333
return initScanner();
336
void Tokenizer::setFileNumber(int file)
338
// We use column number as file number.
339
// See macro yyfileno.
340
yyset_column(file, mHandle);
343
void Tokenizer::setLineNumber(int line)
345
yyset_lineno(line, mHandle);
348
void Tokenizer::setMaxTokenSize(size_t maxTokenSize)
350
mMaxTokenSize = maxTokenSize;
353
void Tokenizer::lex(Token *token)
355
int tokenType = yylex(&token->text, &token->location, mHandle);
357
if (tokenType == Token::GOT_ERROR)
359
mContext.diagnostics->report(Diagnostics::PP_TOKENIZER_ERROR, token->location, token->text);
360
token->type = Token::LAST;
364
token->type = tokenType;
367
if (token->text.size() > mMaxTokenSize)
369
mContext.diagnostics->report(Diagnostics::PP_TOKEN_TOO_LONG,
370
token->location, token->text);
371
token->text.erase(mMaxTokenSize);
376
token->setAtStartOfLine(mContext.lineStart);
377
mContext.lineStart = token->type == '\n';
379
token->setHasLeadingSpace(mContext.leadingSpace);
380
mContext.leadingSpace = false;
383
bool Tokenizer::initScanner()
385
if ((mHandle == nullptr) && yylex_init_extra(&mContext, &mHandle))
388
yyrestart(0, mHandle);
392
void Tokenizer::destroyScanner()
394
if (mHandle == nullptr)
397
yylex_destroy(mHandle);