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