Home | History | Annotate | Download | only in preprocessor
      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