1 /* 2 // 3 // Copyright (c) 2002-2010 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. 9 Based on ANSI C grammar, Lex specification: 10 http://www.lysator.liu.se/c/ANSI-C-grammar-l.html 11 12 IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_glslang_lexer.sh, 13 WHICH GENERATES THE GLSL ES LEXER (glslang_lex.cpp). 14 */ 15 16 %top{ 17 // 18 // Copyright (c) 2010 The ANGLE Project Authors. All rights reserved. 19 // Use of this source code is governed by a BSD-style license that can be 20 // found in the LICENSE file. 21 // 22 23 // This file is auto-generated by generate_glslang_lexer.sh. DO NOT EDIT! 24 } 25 26 %{ 27 #include "compiler/glslang.h" 28 #include "compiler/ParseHelper.h" 29 #include "compiler/util.h" 30 #include "glslang_tab.h" 31 32 /* windows only pragma */ 33 #ifdef _MSC_VER 34 #pragma warning(disable : 4102) 35 #endif 36 37 #define YY_USER_ACTION yylval->lex.line = yylineno; 38 #define YY_INPUT(buf, result, max_size) \ 39 result = string_input(buf, max_size, yyscanner); 40 41 static int string_input(char* buf, int max_size, yyscan_t yyscanner); 42 static int check_type(yyscan_t yyscanner); 43 static int reserved_word(yyscan_t yyscanner); 44 %} 45 46 %option noyywrap nounput never-interactive 47 %option yylineno reentrant bison-bridge 48 %option stack 49 %option extra-type="TParseContext*" 50 %x COMMENT FIELDS 51 52 D [0-9] 53 L [a-zA-Z_] 54 H [a-fA-F0-9] 55 E [Ee][+-]?{D}+ 56 O [0-7] 57 58 %% 59 60 %{ 61 TParseContext* context = yyextra; 62 %} 63 64 /* Single-line comments */ 65 "//"[^\n]* ; 66 67 /* Multi-line comments */ 68 "/*" { yy_push_state(COMMENT, yyscanner); } 69 <COMMENT>. | 70 <COMMENT>\n ; 71 <COMMENT>"*/" { yy_pop_state(yyscanner); } 72 73 "invariant" { return(INVARIANT); } 74 "highp" { return(HIGH_PRECISION); } 75 "mediump" { return(MEDIUM_PRECISION); } 76 "lowp" { return(LOW_PRECISION); } 77 "precision" { return(PRECISION); } 78 79 "attribute" { return(ATTRIBUTE); } 80 "const" { return(CONST_QUAL); } 81 "uniform" { return(UNIFORM); } 82 "varying" { return(VARYING); } 83 84 "break" { return(BREAK); } 85 "continue" { return(CONTINUE); } 86 "do" { return(DO); } 87 "for" { return(FOR); } 88 "while" { return(WHILE); } 89 90 "if" { return(IF); } 91 "else" { return(ELSE); } 92 93 "in" { return(IN_QUAL); } 94 "out" { return(OUT_QUAL); } 95 "inout" { return(INOUT_QUAL); } 96 97 "float" { context->lexAfterType = true; return(FLOAT_TYPE); } 98 "int" { context->lexAfterType = true; return(INT_TYPE); } 99 "void" { context->lexAfterType = true; return(VOID_TYPE); } 100 "bool" { context->lexAfterType = true; return(BOOL_TYPE); } 101 "true" { yylval->lex.b = true; return(BOOLCONSTANT); } 102 "false" { yylval->lex.b = false; return(BOOLCONSTANT); } 103 104 "discard" { return(DISCARD); } 105 "return" { return(RETURN); } 106 107 "mat2" { context->lexAfterType = true; return(MATRIX2); } 108 "mat3" { context->lexAfterType = true; return(MATRIX3); } 109 "mat4" { context->lexAfterType = true; return(MATRIX4); } 110 111 "vec2" { context->lexAfterType = true; return (VEC2); } 112 "vec3" { context->lexAfterType = true; return (VEC3); } 113 "vec4" { context->lexAfterType = true; return (VEC4); } 114 "ivec2" { context->lexAfterType = true; return (IVEC2); } 115 "ivec3" { context->lexAfterType = true; return (IVEC3); } 116 "ivec4" { context->lexAfterType = true; return (IVEC4); } 117 "bvec2" { context->lexAfterType = true; return (BVEC2); } 118 "bvec3" { context->lexAfterType = true; return (BVEC3); } 119 "bvec4" { context->lexAfterType = true; return (BVEC4); } 120 121 "sampler2D" { context->lexAfterType = true; return SAMPLER2D; } 122 "samplerCube" { context->lexAfterType = true; return SAMPLERCUBE; } 123 124 "struct" { context->lexAfterType = true; return(STRUCT); } 125 126 "asm" { return reserved_word(yyscanner); } 127 128 "class" { return reserved_word(yyscanner); } 129 "union" { return reserved_word(yyscanner); } 130 "enum" { return reserved_word(yyscanner); } 131 "typedef" { return reserved_word(yyscanner); } 132 "template" { return reserved_word(yyscanner); } 133 "this" { return reserved_word(yyscanner); } 134 "packed" { return reserved_word(yyscanner); } 135 136 "goto" { return reserved_word(yyscanner); } 137 "switch" { return reserved_word(yyscanner); } 138 "default" { return reserved_word(yyscanner); } 139 140 "inline" { return reserved_word(yyscanner); } 141 "noinline" { return reserved_word(yyscanner); } 142 "volatile" { return reserved_word(yyscanner); } 143 "public" { return reserved_word(yyscanner); } 144 "static" { return reserved_word(yyscanner); } 145 "extern" { return reserved_word(yyscanner); } 146 "external" { return reserved_word(yyscanner); } 147 "interface" { return reserved_word(yyscanner); } 148 149 "long" { return reserved_word(yyscanner); } 150 "short" { return reserved_word(yyscanner); } 151 "double" { return reserved_word(yyscanner); } 152 "half" { return reserved_word(yyscanner); } 153 "fixed" { return reserved_word(yyscanner); } 154 "unsigned" { return reserved_word(yyscanner); } 155 156 "input" { return reserved_word(yyscanner); } 157 "output" { return reserved_word(yyscanner); } 158 159 "hvec2" { return reserved_word(yyscanner); } 160 "hvec3" { return reserved_word(yyscanner); } 161 "hvec4" { return reserved_word(yyscanner); } 162 "fvec2" { return reserved_word(yyscanner); } 163 "fvec3" { return reserved_word(yyscanner); } 164 "fvec4" { return reserved_word(yyscanner); } 165 "dvec2" { return reserved_word(yyscanner); } 166 "dvec3" { return reserved_word(yyscanner); } 167 "dvec4" { return reserved_word(yyscanner); } 168 169 "sizeof" { return reserved_word(yyscanner); } 170 "cast" { return reserved_word(yyscanner); } 171 172 "namespace" { return reserved_word(yyscanner); } 173 "using" { return reserved_word(yyscanner); } 174 175 {L}({L}|{D})* { 176 yylval->lex.string = NewPoolTString(yytext); 177 return check_type(yyscanner); 178 } 179 180 0[xX]{H}+ { yylval->lex.i = strtol(yytext, 0, 0); return(INTCONSTANT); } 181 0{O}+ { yylval->lex.i = strtol(yytext, 0, 0); return(INTCONSTANT); } 182 0{D}+ { context->error(yylineno, "Invalid Octal number.", yytext, "", ""); context->recover(); return 0;} 183 {D}+ { yylval->lex.i = strtol(yytext, 0, 0); return(INTCONSTANT); } 184 185 {D}+{E} { yylval->lex.f = static_cast<float>(atof_dot(yytext)); return(FLOATCONSTANT); } 186 {D}+"."{D}*({E})? { yylval->lex.f = static_cast<float>(atof_dot(yytext)); return(FLOATCONSTANT); } 187 "."{D}+({E})? { yylval->lex.f = static_cast<float>(atof_dot(yytext)); return(FLOATCONSTANT); } 188 189 "+=" { return(ADD_ASSIGN); } 190 "-=" { return(SUB_ASSIGN); } 191 "*=" { return(MUL_ASSIGN); } 192 "/=" { return(DIV_ASSIGN); } 193 "%=" { return(MOD_ASSIGN); } 194 "<<=" { return(LEFT_ASSIGN); } 195 ">>=" { return(RIGHT_ASSIGN); } 196 "&=" { return(AND_ASSIGN); } 197 "^=" { return(XOR_ASSIGN); } 198 "|=" { return(OR_ASSIGN); } 199 200 "++" { return(INC_OP); } 201 "--" { return(DEC_OP); } 202 "&&" { return(AND_OP); } 203 "||" { return(OR_OP); } 204 "^^" { return(XOR_OP); } 205 "<=" { return(LE_OP); } 206 ">=" { return(GE_OP); } 207 "==" { return(EQ_OP); } 208 "!=" { return(NE_OP); } 209 "<<" { return(LEFT_OP); } 210 ">>" { return(RIGHT_OP); } 211 ";" { context->lexAfterType = false; return(SEMICOLON); } 212 ("{"|"<%") { context->lexAfterType = false; return(LEFT_BRACE); } 213 ("}"|"%>") { return(RIGHT_BRACE); } 214 "," { if (context->inTypeParen) context->lexAfterType = false; return(COMMA); } 215 ":" { return(COLON); } 216 "=" { context->lexAfterType = false; return(EQUAL); } 217 "(" { context->lexAfterType = false; context->inTypeParen = true; return(LEFT_PAREN); } 218 ")" { context->inTypeParen = false; return(RIGHT_PAREN); } 219 ("["|"<:") { return(LEFT_BRACKET); } 220 ("]"|":>") { return(RIGHT_BRACKET); } 221 "." { BEGIN(FIELDS); return(DOT); } 222 "!" { return(BANG); } 223 "-" { return(DASH); } 224 "~" { return(TILDE); } 225 "+" { return(PLUS); } 226 "*" { return(STAR); } 227 "/" { return(SLASH); } 228 "%" { return(PERCENT); } 229 "<" { return(LEFT_ANGLE); } 230 ">" { return(RIGHT_ANGLE); } 231 "|" { return(VERTICAL_BAR); } 232 "^" { return(CARET); } 233 "&" { return(AMPERSAND); } 234 "?" { return(QUESTION); } 235 236 <FIELDS>{L}({L}|{D})* { 237 BEGIN(INITIAL); 238 yylval->lex.string = NewPoolTString(yytext); 239 return FIELD_SELECTION; 240 } 241 <FIELDS>[ \t\v\f\r] {} 242 243 [ \t\v\n\f\r] { } 244 <*><<EOF>> { context->AfterEOF = true; yyterminate(); } 245 <*>. { context->warning(yylineno, "Unknown char", yytext, ""); return 0; } 246 247 %% 248 249 extern "C" { 250 // Preprocessor interface. 251 #include "compiler/preprocessor/preprocess.h" 252 253 #define SETUP_CONTEXT(pp) \ 254 TParseContext* context = (TParseContext*) pp->pC; \ 255 struct yyguts_t* yyg = (struct yyguts_t*) context->scanner; 256 257 // Preprocessor callbacks. 258 void CPPDebugLogMsg(const char *msg) 259 { 260 SETUP_CONTEXT(cpp); 261 context->infoSink.debug.message(EPrefixNone, msg); 262 } 263 264 void CPPWarningToInfoLog(const char *msg) 265 { 266 SETUP_CONTEXT(cpp); 267 context->warning(yylineno, msg, "", ""); 268 } 269 270 void CPPShInfoLogMsg(const char *msg) 271 { 272 SETUP_CONTEXT(cpp); 273 context->error(yylineno, msg, "", ""); 274 context->recover(); 275 } 276 277 void CPPErrorToInfoLog(char *msg) 278 { 279 SETUP_CONTEXT(cpp); 280 context->error(yylineno, msg, "", ""); 281 context->recover(); 282 } 283 284 void SetLineNumber(int line) 285 { 286 SETUP_CONTEXT(cpp); 287 int string = 0; 288 DecodeSourceLoc(yylineno, &string, NULL); 289 yylineno = EncodeSourceLoc(string, line); 290 } 291 292 void SetStringNumber(int string) 293 { 294 SETUP_CONTEXT(cpp); 295 int line = 0; 296 DecodeSourceLoc(yylineno, NULL, &line); 297 yylineno = EncodeSourceLoc(string, line); 298 } 299 300 int GetStringNumber() 301 { 302 SETUP_CONTEXT(cpp); 303 int string = 0; 304 DecodeSourceLoc(yylineno, &string, NULL); 305 return string; 306 } 307 308 int GetLineNumber() 309 { 310 SETUP_CONTEXT(cpp); 311 int line = 0; 312 DecodeSourceLoc(yylineno, NULL, &line); 313 return line; 314 } 315 316 void IncLineNumber() 317 { 318 SETUP_CONTEXT(cpp); 319 int string = 0, line = 0; 320 DecodeSourceLoc(yylineno, &string, &line); 321 yylineno = EncodeSourceLoc(string, ++line); 322 } 323 324 void DecLineNumber() 325 { 326 SETUP_CONTEXT(cpp); 327 int string = 0, line = 0; 328 DecodeSourceLoc(yylineno, &string, &line); 329 yylineno = EncodeSourceLoc(string, --line); 330 } 331 332 void HandlePragma(const char **tokens, int numTokens) 333 { 334 SETUP_CONTEXT(cpp); 335 if (!strcmp(tokens[0], "optimize")) { 336 if (numTokens != 4) { 337 CPPShInfoLogMsg("optimize pragma syntax is incorrect"); 338 return; 339 } 340 341 if (strcmp(tokens[1], "(")) { 342 CPPShInfoLogMsg("\"(\" expected after 'optimize' keyword"); 343 return; 344 } 345 346 if (!strcmp(tokens[2], "on")) 347 context->contextPragma.optimize = true; 348 else if (!strcmp(tokens[2], "off")) 349 context->contextPragma.optimize = false; 350 else { 351 CPPShInfoLogMsg("\"on\" or \"off\" expected after '(' for 'optimize' pragma"); 352 return; 353 } 354 355 if (strcmp(tokens[3], ")")) { 356 CPPShInfoLogMsg("\")\" expected to end 'optimize' pragma"); 357 return; 358 } 359 } else if (!strcmp(tokens[0], "debug")) { 360 if (numTokens != 4) { 361 CPPShInfoLogMsg("debug pragma syntax is incorrect"); 362 return; 363 } 364 365 if (strcmp(tokens[1], "(")) { 366 CPPShInfoLogMsg("\"(\" expected after 'debug' keyword"); 367 return; 368 } 369 370 if (!strcmp(tokens[2], "on")) 371 context->contextPragma.debug = true; 372 else if (!strcmp(tokens[2], "off")) 373 context->contextPragma.debug = false; 374 else { 375 CPPShInfoLogMsg("\"on\" or \"off\" expected after '(' for 'debug' pragma"); 376 return; 377 } 378 379 if (strcmp(tokens[3], ")")) { 380 CPPShInfoLogMsg("\")\" expected to end 'debug' pragma"); 381 return; 382 } 383 } else { 384 #ifdef PRAGMA_TABLE 385 // 386 // implementation specific pragma 387 // use ((TParseContext *)cpp->pC)->contextPragma.pragmaTable to store the information about pragma 388 // For now, just ignore the pragma that the implementation cannot recognize 389 // An Example of one such implementation for a pragma that has a syntax like 390 // #pragma pragmaname(pragmavalue) 391 // This implementation stores the current pragmavalue against the pragma name in pragmaTable. 392 // 393 if (numTokens == 4 && !strcmp(tokens[1], "(") && !strcmp(tokens[3], ")")) { 394 TPragmaTable& pragmaTable = ((TParseContext *)cpp->pC)->contextPragma.pragmaTable; 395 TPragmaTable::iterator iter; 396 iter = pragmaTable.find(TString(tokens[0])); 397 if (iter != pragmaTable.end()) { 398 iter->second = tokens[2]; 399 } else { 400 pragmaTable[ tokens[0] ] = tokens[2]; 401 } 402 } else if (numTokens >= 2) { 403 TPragmaTable& pragmaTable = ((TParseContext *)cpp->pC)->contextPragma.pragmaTable; 404 TPragmaTable::iterator iter; 405 iter = pragmaTable.find(TString(tokens[0])); 406 if (iter != pragmaTable.end()) { 407 iter->second = tokens[1]; 408 } else { 409 pragmaTable[ tokens[0] ] = tokens[1]; 410 } 411 } 412 #endif // PRAGMA_TABLE 413 } 414 } 415 416 void StoreStr(char *string) 417 { 418 SETUP_CONTEXT(cpp); 419 TString strSrc; 420 strSrc = TString(string); 421 422 context->HashErrMsg = context->HashErrMsg + " " + strSrc; 423 } 424 425 const char* GetStrfromTStr(void) 426 { 427 SETUP_CONTEXT(cpp); 428 cpp->ErrMsg = context->HashErrMsg.c_str(); 429 return cpp->ErrMsg; 430 } 431 432 void ResetTString(void) 433 { 434 SETUP_CONTEXT(cpp); 435 context->HashErrMsg = ""; 436 } 437 438 TBehavior GetBehavior(const char* behavior) 439 { 440 if (!strcmp("require", behavior)) 441 return EBhRequire; 442 else if (!strcmp("enable", behavior)) 443 return EBhEnable; 444 else if (!strcmp("disable", behavior)) 445 return EBhDisable; 446 else if (!strcmp("warn", behavior)) 447 return EBhWarn; 448 else { 449 CPPShInfoLogMsg((TString("behavior '") + behavior + "' is not supported").c_str()); 450 return EBhDisable; 451 } 452 } 453 454 void updateExtensionBehavior(const char* extName, const char* behavior) 455 { 456 SETUP_CONTEXT(cpp); 457 TBehavior behaviorVal = GetBehavior(behavior); 458 TMap<TString, TBehavior>:: iterator iter; 459 TString msg; 460 461 // special cased for all extension 462 if (!strcmp(extName, "all")) { 463 if (behaviorVal == EBhRequire || behaviorVal == EBhEnable) { 464 CPPShInfoLogMsg("extension 'all' cannot have 'require' or 'enable' behavior"); 465 return; 466 } else { 467 for (iter = context->extensionBehavior.begin(); iter != context->extensionBehavior.end(); ++iter) 468 iter->second = behaviorVal; 469 } 470 } else { 471 iter = context->extensionBehavior.find(TString(extName)); 472 if (iter == context->extensionBehavior.end()) { 473 switch (behaviorVal) { 474 case EBhRequire: 475 CPPShInfoLogMsg((TString("extension '") + extName + "' is not supported").c_str()); 476 break; 477 case EBhEnable: 478 case EBhWarn: 479 case EBhDisable: 480 msg = TString("extension '") + extName + "' is not supported"; 481 context->infoSink.info.message(EPrefixWarning, msg.c_str(), yylineno); 482 break; 483 } 484 return; 485 } else 486 iter->second = behaviorVal; 487 } 488 } 489 } // extern "C" 490 491 int string_input(char* buf, int max_size, yyscan_t yyscanner) { 492 int len; 493 494 if ((len = yylex_CPP(buf, max_size)) == 0) 495 return 0; 496 if (len >= max_size) 497 YY_FATAL_ERROR("input buffer overflow, can't enlarge buffer because scanner uses REJECT"); 498 499 buf[len] = ' '; 500 return len+1; 501 } 502 503 int check_type(yyscan_t yyscanner) { 504 struct yyguts_t* yyg = (struct yyguts_t*) yyscanner; 505 506 int token = IDENTIFIER; 507 TSymbol* symbol = yyextra->symbolTable.find(yytext); 508 if (yyextra->lexAfterType == false && symbol && symbol->isVariable()) { 509 TVariable* variable = static_cast<TVariable*>(symbol); 510 if (variable->isUserType()) { 511 yyextra->lexAfterType = true; 512 token = TYPE_NAME; 513 } 514 } 515 yylval->lex.symbol = symbol; 516 return token; 517 } 518 519 int reserved_word(yyscan_t yyscanner) { 520 struct yyguts_t* yyg = (struct yyguts_t*) yyscanner; 521 522 yyextra->error(yylineno, "Illegal use of reserved word", yytext, ""); 523 yyextra->recover(); 524 return 0; 525 } 526 527 void yyerror(TParseContext* context, const char* reason) { 528 struct yyguts_t* yyg = (struct yyguts_t*) context->scanner; 529 530 if (context->AfterEOF) { 531 context->error(yylineno, reason, "unexpected EOF", ""); 532 } else { 533 context->error(yylineno, reason, yytext, ""); 534 } 535 context->recover(); 536 } 537 538 int glslang_initialize(TParseContext* context) { 539 yyscan_t scanner = NULL; 540 if (yylex_init_extra(context, &scanner)) 541 return 1; 542 543 context->scanner = scanner; 544 return 0; 545 } 546 547 int glslang_finalize(TParseContext* context) { 548 yyscan_t scanner = context->scanner; 549 if (scanner == NULL) return 0; 550 551 context->scanner = NULL; 552 return yylex_destroy(scanner); 553 } 554 555 void glslang_scan(int count, const char* const string[], const int length[], 556 TParseContext* context) { 557 yyrestart(NULL, context->scanner); 558 yyset_lineno(EncodeSourceLoc(0, 1), context->scanner); 559 context->AfterEOF = false; 560 561 // Init preprocessor. 562 cpp->pC = context; 563 cpp->PaWhichStr = 0; 564 cpp->PaArgv = string; 565 cpp->PaArgc = count; 566 cpp->PaStrLen = length; 567 cpp->pastFirstStatement = 0; 568 ScanFromString(string[0]); 569 } 570 571