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