1 // 2 //Copyright (C) 2002-2005 3Dlabs Inc. Ltd. 3 //Copyright (C) 2013 LunarG, Inc. 4 //All rights reserved. 5 // 6 //Redistribution and use in source and binary forms, with or without 7 //modification, are permitted provided that the following conditions 8 //are met: 9 // 10 // Redistributions of source code must retain the above copyright 11 // notice, this list of conditions and the following disclaimer. 12 // 13 // Redistributions in binary form must reproduce the above 14 // copyright notice, this list of conditions and the following 15 // disclaimer in the documentation and/or other materials provided 16 // with the distribution. 17 // 18 // Neither the name of 3Dlabs Inc. Ltd. nor the names of its 19 // contributors may be used to endorse or promote products derived 20 // from this software without specific prior written permission. 21 // 22 //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 //"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 //LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25 //FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26 //COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 //INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 //BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30 //CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 //LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32 //ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 //POSSIBILITY OF SUCH DAMAGE. 34 // 35 /****************************************************************************\ 36 Copyright (c) 2002, NVIDIA Corporation. 37 38 NVIDIA Corporation("NVIDIA") supplies this software to you in 39 consideration of your agreement to the following terms, and your use, 40 installation, modification or redistribution of this NVIDIA software 41 constitutes acceptance of these terms. If you do not agree with these 42 terms, please do not use, install, modify or redistribute this NVIDIA 43 software. 44 45 In consideration of your agreement to abide by the following terms, and 46 subject to these terms, NVIDIA grants you a personal, non-exclusive 47 license, under NVIDIA's copyrights in this original NVIDIA software (the 48 "NVIDIA Software"), to use, reproduce, modify and redistribute the 49 NVIDIA Software, with or without modifications, in source and/or binary 50 forms; provided that if you redistribute the NVIDIA Software, you must 51 retain the copyright notice of NVIDIA, this notice and the following 52 text and disclaimers in all such redistributions of the NVIDIA Software. 53 Neither the name, trademarks, service marks nor logos of NVIDIA 54 Corporation may be used to endorse or promote products derived from the 55 NVIDIA Software without specific prior written permission from NVIDIA. 56 Except as expressly stated in this notice, no other rights or licenses 57 express or implied, are granted by NVIDIA herein, including but not 58 limited to any patent rights that may be infringed by your derivative 59 works or by other works in which the NVIDIA Software may be 60 incorporated. No hardware is licensed hereunder. 61 62 THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT 63 WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, 64 INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, 65 NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR 66 ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER 67 PRODUCTS. 68 69 IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, 70 INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 71 TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 72 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY 73 OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE 74 NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, 75 TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF 76 NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 77 \****************************************************************************/ 78 // 79 // cpp.c 80 // 81 82 #define _CRT_SECURE_NO_WARNINGS 83 84 #include <stdarg.h> 85 #include <stdio.h> 86 #include <sstream> 87 #include <stdlib.h> 88 #include <string.h> 89 #include <ctype.h> 90 91 #include "PpContext.h" 92 #include "PpTokens.h" 93 94 namespace glslang { 95 96 int TPpContext::InitCPP() 97 { 98 pool = mem_CreatePool(0, 0); 99 100 return 1; 101 } 102 103 // Handle #define 104 int TPpContext::CPPdefine(TPpToken* ppToken) 105 { 106 MacroSymbol mac; 107 Symbol *symb; 108 109 // get macro name 110 int token = scanToken(ppToken); 111 if (token != PpAtomIdentifier) { 112 parseContext.ppError(ppToken->loc, "must be followed by macro name", "#define", ""); 113 return token; 114 } 115 if (ppToken->loc.string >= 0) { 116 // We are in user code; check for reserved name use: 117 parseContext.reservedPpErrorCheck(ppToken->loc, ppToken->name, "#define"); 118 } 119 120 // save the original atom 121 const int defAtom = ppToken->atom; 122 123 // gather parameters to the macro, between (...) 124 token = scanToken(ppToken); 125 if (token == '(' && ! ppToken->space) { 126 int argc = 0; 127 int args[maxMacroArgs]; 128 do { 129 token = scanToken(ppToken); 130 if (argc == 0 && token == ')') 131 break; 132 if (token != PpAtomIdentifier) { 133 parseContext.ppError(ppToken->loc, "bad argument", "#define", ""); 134 135 return token; 136 } 137 // check for duplication of parameter name 138 bool duplicate = false; 139 for (int a = 0; a < argc; ++a) { 140 if (args[a] == ppToken->atom) { 141 parseContext.ppError(ppToken->loc, "duplicate macro parameter", "#define", ""); 142 duplicate = true; 143 break; 144 } 145 } 146 if (! duplicate) { 147 if (argc < maxMacroArgs) 148 args[argc++] = ppToken->atom; 149 else 150 parseContext.ppError(ppToken->loc, "too many macro parameters", "#define", ""); 151 } 152 token = scanToken(ppToken); 153 } while (token == ','); 154 if (token != ')') { 155 parseContext.ppError(ppToken->loc, "missing parenthesis", "#define", ""); 156 157 return token; 158 } 159 mac.argc = argc; 160 mac.args = (int*)mem_Alloc(pool, argc * sizeof(int)); 161 memcpy(mac.args, args, argc * sizeof(int)); 162 token = scanToken(ppToken); 163 } 164 165 // record the definition of the macro 166 TSourceLoc defineLoc = ppToken->loc; // because ppToken is going to go to the next line before we report errors 167 mac.body = new TokenStream; 168 while (token != '\n' && token != EndOfInput) { 169 RecordToken(mac.body, token, ppToken); 170 token = scanToken(ppToken); 171 if (token != '\n' && ppToken->space) 172 RecordToken(mac.body, ' ', ppToken); 173 } 174 175 // check for duplicate definition 176 symb = LookUpSymbol(defAtom); 177 if (symb) { 178 if (! symb->mac.undef) { 179 // Already defined -- need to make sure they are identical: 180 // "Two replacement lists are identical if and only if the preprocessing tokens in both have the same number, 181 // ordering, spelling, and white-space separation, where all white-space separations are considered identical." 182 if (symb->mac.argc != mac.argc) 183 parseContext.ppError(defineLoc, "Macro redefined; different number of arguments:", "#define", GetAtomString(defAtom)); 184 else { 185 for (int argc = 0; argc < mac.argc; argc++) { 186 if (symb->mac.args[argc] != mac.args[argc]) 187 parseContext.ppError(defineLoc, "Macro redefined; different argument names:", "#define", GetAtomString(defAtom)); 188 } 189 RewindTokenStream(symb->mac.body); 190 RewindTokenStream(mac.body); 191 int newToken; 192 do { 193 int oldToken; 194 TPpToken oldPpToken; 195 TPpToken newPpToken; 196 oldToken = ReadToken(symb->mac.body, &oldPpToken); 197 newToken = ReadToken(mac.body, &newPpToken); 198 if (oldToken != newToken || oldPpToken != newPpToken) { 199 parseContext.ppError(defineLoc, "Macro redefined; different substitutions:", "#define", GetAtomString(defAtom)); 200 break; 201 } 202 } while (newToken > 0); 203 } 204 } 205 } else 206 symb = AddSymbol(defAtom); 207 208 delete symb->mac.body; 209 symb->mac = mac; 210 211 return '\n'; 212 } 213 214 // Handle #undef 215 int TPpContext::CPPundef(TPpToken* ppToken) 216 { 217 int token = scanToken(ppToken); 218 Symbol *symb; 219 if (token != PpAtomIdentifier) { 220 parseContext.ppError(ppToken->loc, "must be followed by macro name", "#undef", ""); 221 222 return token; 223 } 224 225 parseContext.reservedPpErrorCheck(ppToken->loc, ppToken->name, "#undef"); 226 227 symb = LookUpSymbol(ppToken->atom); 228 if (symb) { 229 symb->mac.undef = 1; 230 } 231 token = scanToken(ppToken); 232 if (token != '\n') 233 parseContext.ppError(ppToken->loc, "can only be followed by a single macro name", "#undef", ""); 234 235 return token; 236 } 237 238 // Handle #else 239 /* Skip forward to appropriate spot. This is used both 240 ** to skip to a #endif after seeing an #else, AND to skip to a #else, 241 ** #elif, or #endif after a #if/#ifdef/#ifndef/#elif test was false. 242 */ 243 int TPpContext::CPPelse(int matchelse, TPpToken* ppToken) 244 { 245 int atom; 246 int depth = 0; 247 int token = scanToken(ppToken); 248 249 while (token != EndOfInput) { 250 if (token != '#') { 251 while (token != '\n' && token != EndOfInput) 252 token = scanToken(ppToken); 253 254 if (token == EndOfInput) 255 return token; 256 257 token = scanToken(ppToken); 258 continue; 259 } 260 261 if ((token = scanToken(ppToken)) != PpAtomIdentifier) 262 continue; 263 264 atom = ppToken->atom; 265 if (atom == PpAtomIf || atom == PpAtomIfdef || atom == PpAtomIfndef) { 266 depth++; 267 ifdepth++; 268 elsetracker++; 269 } else if (atom == PpAtomEndif) { 270 token = extraTokenCheck(atom, ppToken, scanToken(ppToken)); 271 elseSeen[elsetracker] = false; 272 --elsetracker; 273 if (depth == 0) { 274 // found the #endif we are looking for 275 if (ifdepth) 276 --ifdepth; 277 break; 278 } 279 --depth; 280 --ifdepth; 281 } else if (matchelse && depth == 0) { 282 if (atom == PpAtomElse) { 283 elseSeen[elsetracker] = true; 284 token = extraTokenCheck(atom, ppToken, scanToken(ppToken)); 285 // found the #else we are looking for 286 break; 287 } else if (atom == PpAtomElif) { 288 if (elseSeen[elsetracker]) 289 parseContext.ppError(ppToken->loc, "#elif after #else", "#elif", ""); 290 /* we decrement ifdepth here, because CPPif will increment 291 * it and we really want to leave it alone */ 292 if (ifdepth) { 293 --ifdepth; 294 elseSeen[elsetracker] = false; 295 --elsetracker; 296 } 297 298 return CPPif(ppToken); 299 } 300 } else if (atom == PpAtomElse) { 301 if (elseSeen[elsetracker]) 302 parseContext.ppError(ppToken->loc, "#else after #else", "#else", ""); 303 else 304 elseSeen[elsetracker] = true; 305 token = extraTokenCheck(atom, ppToken, scanToken(ppToken)); 306 } else if (atom == PpAtomElif) { 307 if (elseSeen[elsetracker]) 308 parseContext.ppError(ppToken->loc, "#elif after #else", "#elif", ""); 309 } 310 } 311 312 return token; 313 } 314 315 // Call when there should be no more tokens left on a line. 316 int TPpContext::extraTokenCheck(int atom, TPpToken* ppToken, int token) 317 { 318 if (token != '\n' && token != EndOfInput) { 319 static const char* message = "unexpected tokens following directive"; 320 321 const char* label; 322 if (atom == PpAtomElse) 323 label = "#else"; 324 else if (atom == PpAtomElif) 325 label = "#elif"; 326 else if (atom == PpAtomEndif) 327 label = "#endif"; 328 else if (atom == PpAtomIf) 329 label = "#if"; 330 else if (atom == PpAtomLine) 331 label = "#line"; 332 else 333 label = ""; 334 335 if (parseContext.relaxedErrors()) 336 parseContext.ppWarn(ppToken->loc, message, label, ""); 337 else 338 parseContext.ppError(ppToken->loc, message, label, ""); 339 340 while (token != '\n' && token != EndOfInput) 341 token = scanToken(ppToken); 342 } 343 344 return token; 345 } 346 347 enum eval_prec { 348 MIN_PRECEDENCE, 349 COND, LOGOR, LOGAND, OR, XOR, AND, EQUAL, RELATION, SHIFT, ADD, MUL, UNARY, 350 MAX_PRECEDENCE 351 }; 352 353 namespace { 354 355 int op_logor(int a, int b) { return a || b; } 356 int op_logand(int a, int b) { return a && b; } 357 int op_or(int a, int b) { return a | b; } 358 int op_xor(int a, int b) { return a ^ b; } 359 int op_and(int a, int b) { return a & b; } 360 int op_eq(int a, int b) { return a == b; } 361 int op_ne(int a, int b) { return a != b; } 362 int op_ge(int a, int b) { return a >= b; } 363 int op_le(int a, int b) { return a <= b; } 364 int op_gt(int a, int b) { return a > b; } 365 int op_lt(int a, int b) { return a < b; } 366 int op_shl(int a, int b) { return a << b; } 367 int op_shr(int a, int b) { return a >> b; } 368 int op_add(int a, int b) { return a + b; } 369 int op_sub(int a, int b) { return a - b; } 370 int op_mul(int a, int b) { return a * b; } 371 int op_div(int a, int b) { return a / b; } 372 int op_mod(int a, int b) { return a % b; } 373 int op_pos(int a) { return a; } 374 int op_neg(int a) { return -a; } 375 int op_cmpl(int a) { return ~a; } 376 int op_not(int a) { return !a; } 377 378 }; 379 380 struct TBinop { 381 int token, precedence, (*op)(int, int); 382 } binop[] = { 383 { PpAtomOr, LOGOR, op_logor }, 384 { PpAtomAnd, LOGAND, op_logand }, 385 { '|', OR, op_or }, 386 { '^', XOR, op_xor }, 387 { '&', AND, op_and }, 388 { PpAtomEQ, EQUAL, op_eq }, 389 { PpAtomNE, EQUAL, op_ne }, 390 { '>', RELATION, op_gt }, 391 { PpAtomGE, RELATION, op_ge }, 392 { '<', RELATION, op_lt }, 393 { PpAtomLE, RELATION, op_le }, 394 { PpAtomLeft, SHIFT, op_shl }, 395 { PpAtomRight, SHIFT, op_shr }, 396 { '+', ADD, op_add }, 397 { '-', ADD, op_sub }, 398 { '*', MUL, op_mul }, 399 { '/', MUL, op_div }, 400 { '%', MUL, op_mod }, 401 }; 402 403 struct TUnop { 404 int token, (*op)(int); 405 } unop[] = { 406 { '+', op_pos }, 407 { '-', op_neg }, 408 { '~', op_cmpl }, 409 { '!', op_not }, 410 }; 411 412 #define NUM_ELEMENTS(A) (sizeof(A) / sizeof(A[0])) 413 414 int TPpContext::eval(int token, int precedence, bool shortCircuit, int& res, bool& err, TPpToken* ppToken) 415 { 416 TSourceLoc loc = ppToken->loc; // because we sometimes read the newline before reporting the error 417 if (token == PpAtomIdentifier) { 418 if (ppToken->atom == PpAtomDefined) { 419 bool needclose = 0; 420 token = scanToken(ppToken); 421 if (token == '(') { 422 needclose = true; 423 token = scanToken(ppToken); 424 } 425 if (token != PpAtomIdentifier) { 426 parseContext.ppError(loc, "incorrect directive, expected identifier", "preprocessor evaluation", ""); 427 err = true; 428 res = 0; 429 430 return token; 431 } 432 Symbol* s = LookUpSymbol(ppToken->atom); 433 res = s ? ! s->mac.undef : 0; 434 token = scanToken(ppToken); 435 if (needclose) { 436 if (token != ')') { 437 parseContext.ppError(loc, "expected ')'", "preprocessor evaluation", ""); 438 err = true; 439 res = 0; 440 441 return token; 442 } 443 token = scanToken(ppToken); 444 } 445 } else { 446 token = evalToToken(token, shortCircuit, res, err, ppToken); 447 return eval(token, precedence, shortCircuit, res, err, ppToken); 448 } 449 } else if (token == PpAtomConstInt) { 450 res = ppToken->ival; 451 token = scanToken(ppToken); 452 } else if (token == '(') { 453 token = scanToken(ppToken); 454 token = eval(token, MIN_PRECEDENCE, shortCircuit, res, err, ppToken); 455 if (! err) { 456 if (token != ')') { 457 parseContext.ppError(loc, "expected ')'", "preprocessor evaluation", ""); 458 err = true; 459 res = 0; 460 461 return token; 462 } 463 token = scanToken(ppToken); 464 } 465 } else { 466 int op = NUM_ELEMENTS(unop) - 1; 467 for (; op >= 0; op--) { 468 if (unop[op].token == token) 469 break; 470 } 471 if (op >= 0) { 472 token = scanToken(ppToken); 473 token = eval(token, UNARY, shortCircuit, res, err, ppToken); 474 res = unop[op].op(res); 475 } else { 476 parseContext.ppError(loc, "bad expression", "preprocessor evaluation", ""); 477 err = true; 478 res = 0; 479 480 return token; 481 } 482 } 483 484 token = evalToToken(token, shortCircuit, res, err, ppToken); 485 486 // Perform evaluation of binary operation, if there is one, otherwise we are done. 487 while (! err) { 488 if (token == ')' || token == '\n') 489 break; 490 int op; 491 for (op = NUM_ELEMENTS(binop) - 1; op >= 0; op--) { 492 if (binop[op].token == token) 493 break; 494 } 495 if (op < 0 || binop[op].precedence <= precedence) 496 break; 497 int leftSide = res; 498 499 // Setup short-circuiting, needed for ES, unless already in a short circuit. 500 // (Once in a short-circuit, can't turn off again, until that whole subexpression is done. 501 if (! shortCircuit) { 502 if ((token == PpAtomOr && leftSide == 1) || 503 (token == PpAtomAnd && leftSide == 0)) 504 shortCircuit = true; 505 } 506 507 token = scanToken(ppToken); 508 token = eval(token, binop[op].precedence, shortCircuit, res, err, ppToken); 509 510 if (binop[op].op == op_div || binop[op].op == op_mod) { 511 if (res == 0) { 512 parseContext.ppError(loc, "division by 0", "preprocessor evaluation", ""); 513 res = 1; 514 } 515 } 516 res = binop[op].op(leftSide, res); 517 } 518 519 return token; 520 } 521 522 // Expand macros, skipping empty expansions, to get to the first real token in those expansions. 523 int TPpContext::evalToToken(int token, bool shortCircuit, int& res, bool& err, TPpToken* ppToken) 524 { 525 while (token == PpAtomIdentifier && ppToken->atom != PpAtomDefined) { 526 int macroReturn = MacroExpand(ppToken->atom, ppToken, true, false); 527 if (macroReturn == 0) { 528 parseContext.ppError(ppToken->loc, "can't evaluate expression", "preprocessor evaluation", ""); 529 err = true; 530 res = 0; 531 token = scanToken(ppToken); 532 break; 533 } 534 if (macroReturn == -1) { 535 if (! shortCircuit && parseContext.profile == EEsProfile) { 536 const char* message = "undefined macro in expression not allowed in es profile"; 537 if (parseContext.relaxedErrors()) 538 parseContext.ppWarn(ppToken->loc, message, "preprocessor evaluation", ppToken->name); 539 else 540 parseContext.ppError(ppToken->loc, message, "preprocessor evaluation", ppToken->name); 541 } 542 } 543 token = scanToken(ppToken); 544 } 545 546 return token; 547 } 548 549 // Handle #if 550 int TPpContext::CPPif(TPpToken* ppToken) 551 { 552 int token = scanToken(ppToken); 553 elsetracker++; 554 ifdepth++; 555 if (ifdepth > maxIfNesting) { 556 parseContext.ppError(ppToken->loc, "maximum nesting depth exceeded", "#if", ""); 557 return 0; 558 } 559 int res = 0; 560 bool err = false; 561 token = eval(token, MIN_PRECEDENCE, false, res, err, ppToken); 562 token = extraTokenCheck(PpAtomIf, ppToken, token); 563 if (!res && !err) 564 token = CPPelse(1, ppToken); 565 566 return token; 567 } 568 569 // Handle #ifdef 570 int TPpContext::CPPifdef(int defined, TPpToken* ppToken) 571 { 572 int token = scanToken(ppToken); 573 int name = ppToken->atom; 574 if (++ifdepth > maxIfNesting) { 575 parseContext.ppError(ppToken->loc, "maximum nesting depth exceeded", "#ifdef", ""); 576 return 0; 577 } 578 elsetracker++; 579 if (token != PpAtomIdentifier) { 580 if (defined) 581 parseContext.ppError(ppToken->loc, "must be followed by macro name", "#ifdef", ""); 582 else 583 parseContext.ppError(ppToken->loc, "must be followed by macro name", "#ifndef", ""); 584 } else { 585 Symbol *s = LookUpSymbol(name); 586 token = scanToken(ppToken); 587 if (token != '\n') { 588 parseContext.ppError(ppToken->loc, "unexpected tokens following #ifdef directive - expected a newline", "#ifdef", ""); 589 while (token != '\n' && token != EndOfInput) 590 token = scanToken(ppToken); 591 } 592 if (((s && !s->mac.undef) ? 1 : 0) != defined) 593 token = CPPelse(1, ppToken); 594 } 595 596 return token; 597 } 598 599 // Handle #include 600 int TPpContext::CPPinclude(TPpToken* ppToken) 601 { 602 const TSourceLoc directiveLoc = ppToken->loc; 603 int token = scanToken(ppToken); 604 if (token != PpAtomConstString) { 605 // TODO: handle angle brackets. 606 parseContext.ppError(directiveLoc, "must be followed by a file designation", "#include", ""); 607 } else { 608 // Make a copy of the name because it will be overwritten by the next token scan. 609 const std::string filename = ppToken->name; 610 token = scanToken(ppToken); 611 if (token != '\n' && token != EndOfInput) { 612 parseContext.ppError(ppToken->loc, "extra content after file designation", "#include", ""); 613 } else { 614 TShader::Includer::IncludeResult* res = includer.include(filename.c_str(), TShader::Includer::EIncludeRelative, currentSourceFile.c_str(), includeStack.size() + 1); 615 if (res && !res->file_name.empty()) { 616 if (res->file_data && res->file_length) { 617 const bool forNextLine = parseContext.lineDirectiveShouldSetNextLine(); 618 std::ostringstream prologue; 619 std::ostringstream epilogue; 620 prologue << "#line " << forNextLine << " " << "\"" << res->file_name << "\"\n"; 621 epilogue << (res->file_data[res->file_length - 1] == '\n'? "" : "\n") << "#line " << directiveLoc.line + forNextLine << " " << directiveLoc.getStringNameOrNum() << "\n"; 622 pushInput(new TokenizableIncludeFile(directiveLoc, prologue.str(), res, epilogue.str(), this)); 623 } 624 // At EOF, there's no "current" location anymore. 625 if (token != EndOfInput) parseContext.setCurrentColumn(0); 626 // Don't accidentally return EndOfInput, which will end all preprocessing. 627 return '\n'; 628 } else { 629 std::string message = 630 res ? std::string(res->file_data, res->file_length) 631 : std::string("Could not process include directive"); 632 parseContext.ppError(directiveLoc, message.c_str(), "#include", ""); 633 if (res) { 634 includer.releaseInclude(res); 635 } 636 } 637 } 638 } 639 return token; 640 } 641 642 // Handle #line 643 int TPpContext::CPPline(TPpToken* ppToken) 644 { 645 // "#line must have, after macro substitution, one of the following forms: 646 // "#line line 647 // "#line line source-string-number" 648 649 int token = scanToken(ppToken); 650 const TSourceLoc directiveLoc = ppToken->loc; 651 if (token == '\n') { 652 parseContext.ppError(ppToken->loc, "must by followed by an integral literal", "#line", ""); 653 return token; 654 } 655 656 int lineRes = 0; // Line number after macro expansion. 657 int lineToken = 0; 658 bool hasFile = false; 659 int fileRes = 0; // Source file number after macro expansion. 660 const char* sourceName = nullptr; // Optional source file name. 661 bool lineErr = false; 662 bool fileErr = false; 663 token = eval(token, MIN_PRECEDENCE, false, lineRes, lineErr, ppToken); 664 if (! lineErr) { 665 lineToken = lineRes; 666 if (token == '\n') 667 ++lineRes; 668 669 if (parseContext.lineDirectiveShouldSetNextLine()) 670 --lineRes; 671 parseContext.setCurrentLine(lineRes); 672 673 if (token != '\n') { 674 if (token == PpAtomConstString) { 675 parseContext.ppRequireExtensions(directiveLoc, 1, &E_GL_GOOGLE_cpp_style_line_directive, "filename-based #line"); 676 // We need to save a copy of the string instead of pointing 677 // to the name field of the token since the name field 678 // will likely be overwritten by the next token scan. 679 sourceName = GetAtomString(LookUpAddString(ppToken->name)); 680 parseContext.setCurrentSourceName(sourceName); 681 hasFile = true; 682 token = scanToken(ppToken); 683 } else { 684 token = eval(token, MIN_PRECEDENCE, false, fileRes, fileErr, ppToken); 685 if (! fileErr) { 686 parseContext.setCurrentString(fileRes); 687 hasFile = true; 688 } 689 } 690 } 691 } 692 if (!fileErr && !lineErr) { 693 parseContext.notifyLineDirective(directiveLoc.line, lineToken, hasFile, fileRes, sourceName); 694 } 695 token = extraTokenCheck(PpAtomLine, ppToken, token); 696 697 return token; 698 } 699 700 // Handle #error 701 int TPpContext::CPPerror(TPpToken* ppToken) 702 { 703 int token = scanToken(ppToken); 704 std::string message; 705 TSourceLoc loc = ppToken->loc; 706 707 while (token != '\n' && token != EndOfInput) { 708 if (token == PpAtomConstInt || token == PpAtomConstUint || 709 token == PpAtomConstInt64 || token == PpAtomConstUint64 || 710 token == PpAtomConstFloat || token == PpAtomConstDouble) { 711 message.append(ppToken->name); 712 } else if (token == PpAtomIdentifier || token == PpAtomConstString) { 713 message.append(ppToken->name); 714 } else { 715 message.append(GetAtomString(token)); 716 } 717 message.append(" "); 718 token = scanToken(ppToken); 719 } 720 parseContext.notifyErrorDirective(loc.line, message.c_str()); 721 //store this msg into the shader's information log..set the Compile Error flag!!!! 722 parseContext.ppError(loc, message.c_str(), "#error", ""); 723 724 return '\n'; 725 } 726 727 // Handle #pragma 728 int TPpContext::CPPpragma(TPpToken* ppToken) 729 { 730 char SrcStrName[2]; 731 TVector<TString> tokens; 732 733 TSourceLoc loc = ppToken->loc; // because we go to the next line before processing 734 int token = scanToken(ppToken); 735 while (token != '\n' && token != EndOfInput) { 736 switch (token) { 737 case PpAtomIdentifier: 738 case PpAtomConstInt: 739 case PpAtomConstUint: 740 case PpAtomConstInt64: 741 case PpAtomConstUint64: 742 case PpAtomConstFloat: 743 case PpAtomConstDouble: 744 tokens.push_back(ppToken->name); 745 break; 746 default: 747 SrcStrName[0] = (char)token; 748 SrcStrName[1] = '\0'; 749 tokens.push_back(SrcStrName); 750 } 751 token = scanToken(ppToken); 752 } 753 754 if (token == EndOfInput) 755 parseContext.ppError(loc, "directive must end with a newline", "#pragma", ""); 756 else 757 parseContext.handlePragma(loc, tokens); 758 759 return token; 760 } 761 762 // #version: This is just for error checking: the version and profile are decided before preprocessing starts 763 int TPpContext::CPPversion(TPpToken* ppToken) 764 { 765 int token = scanToken(ppToken); 766 767 if (errorOnVersion || versionSeen) 768 parseContext.ppError(ppToken->loc, "must occur first in shader", "#version", ""); 769 versionSeen = true; 770 771 if (token == '\n') { 772 parseContext.ppError(ppToken->loc, "must be followed by version number", "#version", ""); 773 774 return token; 775 } 776 777 if (token != PpAtomConstInt) 778 parseContext.ppError(ppToken->loc, "must be followed by version number", "#version", ""); 779 780 ppToken->ival = atoi(ppToken->name); 781 int versionNumber = ppToken->ival; 782 int line = ppToken->loc.line; 783 token = scanToken(ppToken); 784 785 if (token == '\n') { 786 parseContext.notifyVersion(line, versionNumber, nullptr); 787 return token; 788 } else { 789 if (ppToken->atom != PpAtomCore && 790 ppToken->atom != PpAtomCompatibility && 791 ppToken->atom != PpAtomEs) 792 parseContext.ppError(ppToken->loc, "bad profile name; use es, core, or compatibility", "#version", ""); 793 parseContext.notifyVersion(line, versionNumber, ppToken->name); 794 token = scanToken(ppToken); 795 796 if (token == '\n') 797 return token; 798 else 799 parseContext.ppError(ppToken->loc, "bad tokens following profile -- expected newline", "#version", ""); 800 } 801 802 return token; 803 } 804 805 // Handle #extension 806 int TPpContext::CPPextension(TPpToken* ppToken) 807 { 808 int line = ppToken->loc.line; 809 int token = scanToken(ppToken); 810 char extensionName[MaxTokenLength + 1]; 811 812 if (token=='\n') { 813 parseContext.ppError(ppToken->loc, "extension name not specified", "#extension", ""); 814 return token; 815 } 816 817 if (token != PpAtomIdentifier) 818 parseContext.ppError(ppToken->loc, "extension name expected", "#extension", ""); 819 820 assert(strlen(ppToken->name) <= MaxTokenLength); 821 strcpy(extensionName, ppToken->name); 822 823 token = scanToken(ppToken); 824 if (token != ':') { 825 parseContext.ppError(ppToken->loc, "':' missing after extension name", "#extension", ""); 826 return token; 827 } 828 829 token = scanToken(ppToken); 830 if (token != PpAtomIdentifier) { 831 parseContext.ppError(ppToken->loc, "behavior for extension not specified", "#extension", ""); 832 return token; 833 } 834 835 parseContext.updateExtensionBehavior(line, extensionName, ppToken->name); 836 parseContext.notifyExtensionDirective(line, extensionName, ppToken->name); 837 838 token = scanToken(ppToken); 839 if (token == '\n') 840 return token; 841 else 842 parseContext.ppError(ppToken->loc, "extra tokens -- expected newline", "#extension",""); 843 844 return token; 845 } 846 847 int TPpContext::readCPPline(TPpToken* ppToken) 848 { 849 int token = scanToken(ppToken); 850 851 if (token == PpAtomIdentifier) { 852 switch (ppToken->atom) { 853 case PpAtomDefine: 854 token = CPPdefine(ppToken); 855 break; 856 case PpAtomElse: 857 if (elsetracker[elseSeen]) 858 parseContext.ppError(ppToken->loc, "#else after #else", "#else", ""); 859 elsetracker[elseSeen] = true; 860 if (! ifdepth) 861 parseContext.ppError(ppToken->loc, "mismatched statements", "#else", ""); 862 token = extraTokenCheck(PpAtomElse, ppToken, scanToken(ppToken)); 863 token = CPPelse(0, ppToken); 864 break; 865 case PpAtomElif: 866 if (! ifdepth) 867 parseContext.ppError(ppToken->loc, "mismatched statements", "#elif", ""); 868 if (elseSeen[elsetracker]) 869 parseContext.ppError(ppToken->loc, "#elif after #else", "#elif", ""); 870 // this token is really a dont care, but we still need to eat the tokens 871 token = scanToken(ppToken); 872 while (token != '\n' && token != EndOfInput) 873 token = scanToken(ppToken); 874 token = CPPelse(0, ppToken); 875 break; 876 case PpAtomEndif: 877 if (! ifdepth) 878 parseContext.ppError(ppToken->loc, "mismatched statements", "#endif", ""); 879 else { 880 elseSeen[elsetracker] = false; 881 --elsetracker; 882 --ifdepth; 883 } 884 token = extraTokenCheck(PpAtomEndif, ppToken, scanToken(ppToken)); 885 break; 886 case PpAtomIf: 887 token = CPPif(ppToken); 888 break; 889 case PpAtomIfdef: 890 token = CPPifdef(1, ppToken); 891 break; 892 case PpAtomIfndef: 893 token = CPPifdef(0, ppToken); 894 break; 895 case PpAtomInclude: 896 parseContext.ppRequireExtensions(ppToken->loc, 1, &E_GL_GOOGLE_include_directive, "#include"); 897 token = CPPinclude(ppToken); 898 break; 899 case PpAtomLine: 900 token = CPPline(ppToken); 901 break; 902 case PpAtomPragma: 903 token = CPPpragma(ppToken); 904 break; 905 case PpAtomUndef: 906 token = CPPundef(ppToken); 907 break; 908 case PpAtomError: 909 token = CPPerror(ppToken); 910 break; 911 case PpAtomVersion: 912 token = CPPversion(ppToken); 913 break; 914 case PpAtomExtension: 915 token = CPPextension(ppToken); 916 break; 917 default: 918 parseContext.ppError(ppToken->loc, "invalid directive:", "#", ppToken->name); 919 break; 920 } 921 } else if (token != '\n' && token != EndOfInput) 922 parseContext.ppError(ppToken->loc, "invalid directive", "#", ""); 923 924 while (token != '\n' && token != EndOfInput) 925 token = scanToken(ppToken); 926 927 return token; 928 } 929 930 TPpContext::TokenStream* TPpContext::PrescanMacroArg(TokenStream* a, TPpToken* ppToken, bool newLineOkay) 931 { 932 int token; 933 TokenStream *n; 934 RewindTokenStream(a); 935 do { 936 token = ReadToken(a, ppToken); 937 if (token == PpAtomIdentifier && LookUpSymbol(ppToken->atom)) 938 break; 939 } while (token != EndOfInput); 940 941 if (token == EndOfInput) 942 return a; 943 944 n = new TokenStream; 945 pushInput(new tMarkerInput(this)); 946 pushTokenStreamInput(a); 947 while ((token = scanToken(ppToken)) != tMarkerInput::marker) { 948 if (token == PpAtomIdentifier && MacroExpand(ppToken->atom, ppToken, false, newLineOkay) != 0) 949 continue; 950 RecordToken(n, token, ppToken); 951 } 952 popInput(); 953 delete a; 954 955 return n; 956 } 957 958 // 959 // Return the next token for a macro expansion, handling macro args. 960 // 961 int TPpContext::tMacroInput::scan(TPpToken* ppToken) 962 { 963 int token; 964 do { 965 token = pp->ReadToken(mac->body, ppToken); 966 } while (token == ' '); // handle white space in macro 967 968 // TODO: preprocessor: properly handle whitespace (or lack of it) between tokens when expanding 969 if (token == PpAtomIdentifier) { 970 int i; 971 for (i = mac->argc - 1; i >= 0; i--) 972 if (mac->args[i] == ppToken->atom) 973 break; 974 if (i >= 0) { 975 pp->pushTokenStreamInput(args[i]); 976 977 return pp->scanToken(ppToken); 978 } 979 } 980 981 if (token == EndOfInput) 982 mac->busy = 0; 983 984 return token; 985 } 986 987 // return a textual zero, for scanning a macro that was never defined 988 int TPpContext::tZeroInput::scan(TPpToken* ppToken) 989 { 990 if (done) 991 return EndOfInput; 992 993 strcpy(ppToken->name, "0"); 994 ppToken->ival = 0; 995 ppToken->space = false; 996 done = true; 997 998 return PpAtomConstInt; 999 } 1000 1001 // 1002 // Check an identifier (atom) to see if it is a macro that should be expanded. 1003 // If it is, and defined, push a tInput that will produce the appropriate expansion 1004 // and return 1. 1005 // If it is, but undefined, and expandUndef is requested, push a tInput that will 1006 // expand to 0 and return -1. 1007 // Otherwise, return 0 to indicate no expansion, which is not necessarily an error. 1008 // 1009 int TPpContext::MacroExpand(int atom, TPpToken* ppToken, bool expandUndef, bool newLineOkay) 1010 { 1011 ppToken->space = false; 1012 switch (atom) { 1013 case PpAtomLineMacro: 1014 ppToken->ival = parseContext.getCurrentLoc().line; 1015 snprintf(ppToken->name, sizeof(ppToken->name), "%d", ppToken->ival); 1016 UngetToken(PpAtomConstInt, ppToken); 1017 return 1; 1018 1019 case PpAtomFileMacro: { 1020 if (parseContext.getCurrentLoc().name) 1021 parseContext.ppRequireExtensions(ppToken->loc, 1, &E_GL_GOOGLE_cpp_style_line_directive, "filename-based __FILE__"); 1022 ppToken->ival = parseContext.getCurrentLoc().string; 1023 snprintf(ppToken->name, sizeof(ppToken->name), "%s", ppToken->loc.getStringNameOrNum().c_str()); 1024 UngetToken(PpAtomConstInt, ppToken); 1025 return 1; 1026 } 1027 1028 case PpAtomVersionMacro: 1029 ppToken->ival = parseContext.version; 1030 snprintf(ppToken->name, sizeof(ppToken->name), "%d", ppToken->ival); 1031 UngetToken(PpAtomConstInt, ppToken); 1032 return 1; 1033 1034 default: 1035 break; 1036 } 1037 1038 Symbol *sym = LookUpSymbol(atom); 1039 int token; 1040 int depth = 0; 1041 1042 // no recursive expansions 1043 if (sym && sym->mac.busy) 1044 return 0; 1045 1046 // not expanding undefined macros 1047 if ((! sym || sym->mac.undef) && ! expandUndef) 1048 return 0; 1049 1050 // 0 is the value of an undefined macro 1051 if ((! sym || sym->mac.undef) && expandUndef) { 1052 pushInput(new tZeroInput(this)); 1053 return -1; 1054 } 1055 1056 tMacroInput *in = new tMacroInput(this); 1057 1058 TSourceLoc loc = ppToken->loc; // in case we go to the next line before discovering the error 1059 in->mac = &sym->mac; 1060 if (sym->mac.args) { 1061 token = scanToken(ppToken); 1062 if (newLineOkay) { 1063 while (token == '\n') 1064 token = scanToken(ppToken); 1065 } 1066 if (token != '(') { 1067 parseContext.ppError(loc, "expected '(' following", "macro expansion", GetAtomString(atom)); 1068 UngetToken(token, ppToken); 1069 ppToken->atom = atom; 1070 1071 delete in; 1072 return 0; 1073 } 1074 in->args.resize(in->mac->argc); 1075 for (int i = 0; i < in->mac->argc; i++) 1076 in->args[i] = new TokenStream; 1077 int arg = 0; 1078 bool tokenRecorded = false; 1079 do { 1080 depth = 0; 1081 while (1) { 1082 token = scanToken(ppToken); 1083 if (token == EndOfInput) { 1084 parseContext.ppError(loc, "End of input in macro", "macro expansion", GetAtomString(atom)); 1085 delete in; 1086 return 0; 1087 } 1088 if (token == '\n') { 1089 if (! newLineOkay) { 1090 parseContext.ppError(loc, "End of line in macro substitution:", "macro expansion", GetAtomString(atom)); 1091 delete in; 1092 return 0; 1093 } 1094 continue; 1095 } 1096 if (token == '#') { 1097 parseContext.ppError(ppToken->loc, "unexpected '#'", "macro expansion", GetAtomString(atom)); 1098 delete in; 1099 return 0; 1100 } 1101 if (in->mac->argc == 0 && token != ')') 1102 break; 1103 if (depth == 0 && (token == ',' || token == ')')) 1104 break; 1105 if (token == '(') 1106 depth++; 1107 if (token == ')') 1108 depth--; 1109 RecordToken(in->args[arg], token, ppToken); 1110 tokenRecorded = true; 1111 } 1112 if (token == ')') { 1113 if (in->mac->argc == 1 && tokenRecorded == 0) 1114 break; 1115 arg++; 1116 break; 1117 } 1118 arg++; 1119 } while (arg < in->mac->argc); 1120 1121 if (arg < in->mac->argc) 1122 parseContext.ppError(loc, "Too few args in Macro", "macro expansion", GetAtomString(atom)); 1123 else if (token != ')') { 1124 depth=0; 1125 while (token != EndOfInput && (depth > 0 || token != ')')) { 1126 if (token == ')') 1127 depth--; 1128 token = scanToken(ppToken); 1129 if (token == '(') 1130 depth++; 1131 } 1132 1133 if (token == EndOfInput) { 1134 parseContext.ppError(loc, "End of input in macro", "macro expansion", GetAtomString(atom)); 1135 delete in; 1136 return 0; 1137 } 1138 parseContext.ppError(loc, "Too many args in macro", "macro expansion", GetAtomString(atom)); 1139 } 1140 for (int i = 0; i < in->mac->argc; i++) 1141 in->args[i] = PrescanMacroArg(in->args[i], ppToken, newLineOkay); 1142 } 1143 1144 pushInput(in); 1145 sym->mac.busy = 1; 1146 RewindTokenStream(sym->mac.body); 1147 1148 return 1; 1149 } 1150 1151 } // end namespace glslang 1152