1//
2// Copyright (c) 2011-2013 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7#include "DirectiveParser.h"
8
9#include <cassert>
10#include <cstdlib>
11#include <sstream>
12
13#include "DiagnosticsBase.h"
14#include "DirectiveHandlerBase.h"
15#include "ExpressionParser.h"
16#include "MacroExpander.h"
17#include "Token.h"
18#include "Tokenizer.h"
19
20namespace {
21enum DirectiveType
22{
23    DIRECTIVE_NONE,
24    DIRECTIVE_DEFINE,
25    DIRECTIVE_UNDEF,
26    DIRECTIVE_IF,
27    DIRECTIVE_IFDEF,
28    DIRECTIVE_IFNDEF,
29    DIRECTIVE_ELSE,
30    DIRECTIVE_ELIF,
31    DIRECTIVE_ENDIF,
32    DIRECTIVE_ERROR,
33    DIRECTIVE_PRAGMA,
34    DIRECTIVE_EXTENSION,
35    DIRECTIVE_VERSION,
36    DIRECTIVE_LINE
37};
38
39DirectiveType getDirective(const pp::Token *token)
40{
41    static const std::string kDirectiveDefine("define");
42    static const std::string kDirectiveUndef("undef");
43    static const std::string kDirectiveIf("if");
44    static const std::string kDirectiveIfdef("ifdef");
45    static const std::string kDirectiveIfndef("ifndef");
46    static const std::string kDirectiveElse("else");
47    static const std::string kDirectiveElif("elif");
48    static const std::string kDirectiveEndif("endif");
49    static const std::string kDirectiveError("error");
50    static const std::string kDirectivePragma("pragma");
51    static const std::string kDirectiveExtension("extension");
52    static const std::string kDirectiveVersion("version");
53    static const std::string kDirectiveLine("line");
54
55    if (token->type != pp::Token::IDENTIFIER)
56        return DIRECTIVE_NONE;
57
58    if (token->text == kDirectiveDefine)
59        return DIRECTIVE_DEFINE;
60    if (token->text == kDirectiveUndef)
61        return DIRECTIVE_UNDEF;
62    if (token->text == kDirectiveIf)
63        return DIRECTIVE_IF;
64    if (token->text == kDirectiveIfdef)
65        return DIRECTIVE_IFDEF;
66    if (token->text == kDirectiveIfndef)
67        return DIRECTIVE_IFNDEF;
68    if (token->text == kDirectiveElse)
69        return DIRECTIVE_ELSE;
70    if (token->text == kDirectiveElif)
71        return DIRECTIVE_ELIF;
72    if (token->text == kDirectiveEndif)
73        return DIRECTIVE_ENDIF;
74    if (token->text == kDirectiveError)
75        return DIRECTIVE_ERROR;
76    if (token->text == kDirectivePragma)
77        return DIRECTIVE_PRAGMA;
78    if (token->text == kDirectiveExtension)
79        return DIRECTIVE_EXTENSION;
80    if (token->text == kDirectiveVersion)
81        return DIRECTIVE_VERSION;
82    if (token->text == kDirectiveLine)
83        return DIRECTIVE_LINE;
84
85    return DIRECTIVE_NONE;
86}
87
88bool isConditionalDirective(DirectiveType directive)
89{
90    switch (directive)
91    {
92      case DIRECTIVE_IF:
93      case DIRECTIVE_IFDEF:
94      case DIRECTIVE_IFNDEF:
95      case DIRECTIVE_ELSE:
96      case DIRECTIVE_ELIF:
97      case DIRECTIVE_ENDIF:
98        return true;
99      default:
100        return false;
101    }
102}
103
104// Returns true if the token represents End Of Directive.
105bool isEOD(const pp::Token *token)
106{
107    return (token->type == '\n') || (token->type == pp::Token::LAST);
108}
109
110void skipUntilEOD(pp::Lexer *lexer, pp::Token *token)
111{
112    while(!isEOD(token))
113    {
114        lexer->lex(token);
115    }
116}
117
118bool isMacroNameReserved(const std::string &name)
119{
120    // Names prefixed with "GL_" are reserved.
121    if (name.substr(0, 3) == "GL_")
122        return true;
123
124    // Names containing two consecutive underscores are reserved.
125    if (name.find("__") != std::string::npos)
126        return true;
127
128    return false;
129}
130
131bool isMacroPredefined(const std::string &name,
132                       const pp::MacroSet &macroSet)
133{
134    pp::MacroSet::const_iterator iter = macroSet.find(name);
135    return iter != macroSet.end() ? iter->second.predefined : false;
136}
137
138}  // namespace anonymous
139
140namespace pp
141{
142
143class DefinedParser : public Lexer
144{
145  public:
146    DefinedParser(Lexer *lexer,
147                  const MacroSet *macroSet,
148                  Diagnostics *diagnostics)
149        : mLexer(lexer),
150          mMacroSet(macroSet),
151          mDiagnostics(diagnostics)
152    {
153    }
154
155  protected:
156    virtual void lex(Token *token)
157    {
158        static const std::string kDefined("defined");
159
160        mLexer->lex(token);
161        if (token->type != Token::IDENTIFIER)
162            return;
163        if (token->text != kDefined)
164            return;
165
166        bool paren = false;
167        mLexer->lex(token);
168        if (token->type == '(')
169        {
170            paren = true;
171            mLexer->lex(token);
172        }
173
174        if (token->type != Token::IDENTIFIER)
175        {
176            mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
177                                 token->location, token->text);
178            skipUntilEOD(mLexer, token);
179            return;
180        }
181        MacroSet::const_iterator iter = mMacroSet->find(token->text);
182        std::string expression = iter != mMacroSet->end() ? "1" : "0";
183
184        if (paren)
185        {
186            mLexer->lex(token);
187            if (token->type != ')')
188            {
189                mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
190                                     token->location, token->text);
191                skipUntilEOD(mLexer, token);
192                return;
193            }
194        }
195
196        // We have a valid defined operator.
197        // Convert the current token into a CONST_INT token.
198        token->type = Token::CONST_INT;
199        token->text = expression;
200    }
201
202  private:
203    Lexer *mLexer;
204    const MacroSet *mMacroSet;
205    Diagnostics *mDiagnostics;
206};
207
208DirectiveParser::DirectiveParser(Tokenizer *tokenizer,
209                                 MacroSet *macroSet,
210                                 Diagnostics *diagnostics,
211                                 DirectiveHandler *directiveHandler)
212    : mPastFirstStatement(false),
213      mTokenizer(tokenizer),
214      mMacroSet(macroSet),
215      mDiagnostics(diagnostics),
216      mDirectiveHandler(directiveHandler)
217{
218}
219
220void DirectiveParser::lex(Token *token)
221{
222    do
223    {
224        mTokenizer->lex(token);
225
226        if (token->type == Token::PP_HASH)
227        {
228            parseDirective(token);
229            mPastFirstStatement = true;
230        }
231
232        if (token->type == Token::LAST)
233        {
234            if (!mConditionalStack.empty())
235            {
236                const ConditionalBlock &block = mConditionalStack.back();
237                mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNTERMINATED,
238                                     block.location, block.type);
239            }
240            break;
241        }
242
243    }
244    while (skipping() || (token->type == '\n'));
245
246    mPastFirstStatement = true;
247}
248
249void DirectiveParser::parseDirective(Token *token)
250{
251    assert(token->type == Token::PP_HASH);
252
253    mTokenizer->lex(token);
254    if (isEOD(token))
255    {
256        // Empty Directive.
257        return;
258    }
259
260    DirectiveType directive = getDirective(token);
261
262    // While in an excluded conditional block/group,
263    // we only parse conditional directives.
264    if (skipping() && !isConditionalDirective(directive))
265    {
266        skipUntilEOD(mTokenizer, token);
267        return;
268    }
269
270    switch(directive)
271    {
272      case DIRECTIVE_NONE:
273        mDiagnostics->report(Diagnostics::PP_DIRECTIVE_INVALID_NAME,
274                             token->location, token->text);
275        skipUntilEOD(mTokenizer, token);
276        break;
277      case DIRECTIVE_DEFINE:
278        parseDefine(token);
279        break;
280      case DIRECTIVE_UNDEF:
281        parseUndef(token);
282        break;
283      case DIRECTIVE_IF:
284        parseIf(token);
285        break;
286      case DIRECTIVE_IFDEF:
287        parseIfdef(token);
288        break;
289      case DIRECTIVE_IFNDEF:
290        parseIfndef(token);
291        break;
292      case DIRECTIVE_ELSE:
293        parseElse(token);
294        break;
295      case DIRECTIVE_ELIF:
296        parseElif(token);
297        break;
298      case DIRECTIVE_ENDIF:
299        parseEndif(token);
300        break;
301      case DIRECTIVE_ERROR:
302        parseError(token);
303        break;
304      case DIRECTIVE_PRAGMA:
305        parsePragma(token);
306        break;
307      case DIRECTIVE_EXTENSION:
308        parseExtension(token);
309        break;
310      case DIRECTIVE_VERSION:
311        parseVersion(token);
312        break;
313      case DIRECTIVE_LINE:
314        parseLine(token);
315        break;
316      default:
317        assert(false);
318        break;
319    }
320
321    skipUntilEOD(mTokenizer, token);
322    if (token->type == Token::LAST)
323    {
324        mDiagnostics->report(Diagnostics::PP_EOF_IN_DIRECTIVE,
325                             token->location, token->text);
326    }
327}
328
329void DirectiveParser::parseDefine(Token *token)
330{
331    assert(getDirective(token) == DIRECTIVE_DEFINE);
332
333    mTokenizer->lex(token);
334    if (token->type != Token::IDENTIFIER)
335    {
336        mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
337                             token->location, token->text);
338        return;
339    }
340    if (isMacroPredefined(token->text, *mMacroSet))
341    {
342        mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_REDEFINED,
343                             token->location, token->text);
344        return;
345    }
346    if (isMacroNameReserved(token->text))
347    {
348        mDiagnostics->report(Diagnostics::PP_MACRO_NAME_RESERVED,
349                             token->location, token->text);
350        return;
351    }
352
353    Macro macro;
354    macro.type = Macro::kTypeObj;
355    macro.name = token->text;
356
357    mTokenizer->lex(token);
358    if (token->type == '(' && !token->hasLeadingSpace())
359    {
360        // Function-like macro. Collect arguments.
361        macro.type = Macro::kTypeFunc;
362        do
363        {
364            mTokenizer->lex(token);
365            if (token->type != Token::IDENTIFIER)
366                break;
367            macro.parameters.push_back(token->text);
368
369            mTokenizer->lex(token);  // Get ','.
370        }
371        while (token->type == ',');
372
373        if (token->type != ')')
374        {
375            mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
376                                 token->location,
377                                 token->text);
378            return;
379        }
380        mTokenizer->lex(token);  // Get ')'.
381    }
382
383    while ((token->type != '\n') && (token->type != Token::LAST))
384    {
385        // Reset the token location because it is unnecessary in replacement
386        // list. Resetting it also allows us to reuse Token::equals() to
387        // compare macros.
388        token->location = SourceLocation();
389        macro.replacements.push_back(*token);
390        mTokenizer->lex(token);
391    }
392    if (!macro.replacements.empty())
393    {
394        // Whitespace preceding the replacement list is not considered part of
395        // the replacement list for either form of macro.
396        macro.replacements.front().setHasLeadingSpace(false);
397    }
398
399    // Check for macro redefinition.
400    MacroSet::const_iterator iter = mMacroSet->find(macro.name);
401    if (iter != mMacroSet->end() && !macro.equals(iter->second))
402    {
403        mDiagnostics->report(Diagnostics::PP_MACRO_REDEFINED,
404                             token->location,
405                             macro.name);
406        return;
407    }
408    mMacroSet->insert(std::make_pair(macro.name, macro));
409}
410
411void DirectiveParser::parseUndef(Token *token)
412{
413    assert(getDirective(token) == DIRECTIVE_UNDEF);
414
415    mTokenizer->lex(token);
416    if (token->type != Token::IDENTIFIER)
417    {
418        mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
419                             token->location, token->text);
420        return;
421    }
422
423    MacroSet::iterator iter = mMacroSet->find(token->text);
424    if (iter != mMacroSet->end())
425    {
426        if (iter->second.predefined)
427        {
428            mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_UNDEFINED,
429                                 token->location, token->text);
430        }
431        else
432        {
433            mMacroSet->erase(iter);
434        }
435    }
436
437    mTokenizer->lex(token);
438}
439
440void DirectiveParser::parseIf(Token *token)
441{
442    assert(getDirective(token) == DIRECTIVE_IF);
443    parseConditionalIf(token);
444}
445
446void DirectiveParser::parseIfdef(Token *token)
447{
448    assert(getDirective(token) == DIRECTIVE_IFDEF);
449    parseConditionalIf(token);
450}
451
452void DirectiveParser::parseIfndef(Token *token)
453{
454    assert(getDirective(token) == DIRECTIVE_IFNDEF);
455    parseConditionalIf(token);
456}
457
458void DirectiveParser::parseElse(Token *token)
459{
460    assert(getDirective(token) == DIRECTIVE_ELSE);
461
462    if (mConditionalStack.empty())
463    {
464        mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_WITHOUT_IF,
465                             token->location, token->text);
466        skipUntilEOD(mTokenizer, token);
467        return;
468    }
469
470    ConditionalBlock &block = mConditionalStack.back();
471    if (block.skipBlock)
472    {
473        // No diagnostics. Just skip the whole line.
474        skipUntilEOD(mTokenizer, token);
475        return;
476    }
477    if (block.foundElseGroup)
478    {
479        mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_AFTER_ELSE,
480                             token->location, token->text);
481        skipUntilEOD(mTokenizer, token);
482        return;
483    }
484
485    block.foundElseGroup = true;
486    block.skipGroup = block.foundValidGroup;
487    block.foundValidGroup = true;
488
489    // Warn if there are extra tokens after #else.
490    mTokenizer->lex(token);
491    if (!isEOD(token))
492    {
493        mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
494                             token->location, token->text);
495        skipUntilEOD(mTokenizer, token);
496    }
497}
498
499void DirectiveParser::parseElif(Token *token)
500{
501    assert(getDirective(token) == DIRECTIVE_ELIF);
502
503    if (mConditionalStack.empty())
504    {
505        mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_WITHOUT_IF,
506                             token->location, token->text);
507        skipUntilEOD(mTokenizer, token);
508        return;
509    }
510
511    ConditionalBlock &block = mConditionalStack.back();
512    if (block.skipBlock)
513    {
514        // No diagnostics. Just skip the whole line.
515        skipUntilEOD(mTokenizer, token);
516        return;
517    }
518    if (block.foundElseGroup)
519    {
520        mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_AFTER_ELSE,
521                             token->location, token->text);
522        skipUntilEOD(mTokenizer, token);
523        return;
524    }
525    if (block.foundValidGroup)
526    {
527        // Do not parse the expression.
528        // Also be careful not to emit a diagnostic.
529        block.skipGroup = true;
530        skipUntilEOD(mTokenizer, token);
531        return;
532    }
533
534    int expression = parseExpressionIf(token);
535    block.skipGroup = expression == 0;
536    block.foundValidGroup = expression != 0;
537}
538
539void DirectiveParser::parseEndif(Token *token)
540{
541    assert(getDirective(token) == DIRECTIVE_ENDIF);
542
543    if (mConditionalStack.empty())
544    {
545        mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ENDIF_WITHOUT_IF,
546                             token->location, token->text);
547        skipUntilEOD(mTokenizer, token);
548        return;
549    }
550
551    mConditionalStack.pop_back();
552
553    // Warn if there are tokens after #endif.
554    mTokenizer->lex(token);
555    if (!isEOD(token))
556    {
557        mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
558                             token->location, token->text);
559        skipUntilEOD(mTokenizer, token);
560    }
561}
562
563void DirectiveParser::parseError(Token *token)
564{
565    assert(getDirective(token) == DIRECTIVE_ERROR);
566
567    std::ostringstream stream;
568    mTokenizer->lex(token);
569    while ((token->type != '\n') && (token->type != Token::LAST))
570    {
571        stream << *token;
572        mTokenizer->lex(token);
573    }
574    mDirectiveHandler->handleError(token->location, stream.str());
575}
576
577// Parses pragma of form: #pragma name[(value)].
578void DirectiveParser::parsePragma(Token *token)
579{
580    assert(getDirective(token) == DIRECTIVE_PRAGMA);
581
582    enum State
583    {
584        PRAGMA_NAME,
585        LEFT_PAREN,
586        PRAGMA_VALUE,
587        RIGHT_PAREN
588    };
589
590    bool valid = true;
591    std::string name, value;
592    int state = PRAGMA_NAME;
593
594    mTokenizer->lex(token);
595    while ((token->type != '\n') && (token->type != Token::LAST))
596    {
597        switch(state++)
598        {
599          case PRAGMA_NAME:
600            name = token->text;
601            valid = valid && (token->type == Token::IDENTIFIER);
602            break;
603          case LEFT_PAREN:
604            valid = valid && (token->type == '(');
605            break;
606          case PRAGMA_VALUE:
607            value = token->text;
608            valid = valid && (token->type == Token::IDENTIFIER);
609            break;
610          case RIGHT_PAREN:
611            valid = valid && (token->type == ')');
612            break;
613          default:
614            valid = false;
615            break;
616        }
617        mTokenizer->lex(token);
618    }
619
620    valid = valid && ((state == PRAGMA_NAME) ||     // Empty pragma.
621                      (state == LEFT_PAREN) ||      // Without value.
622                      (state == RIGHT_PAREN + 1));  // With value.
623    if (!valid)
624    {
625        mDiagnostics->report(Diagnostics::PP_UNRECOGNIZED_PRAGMA,
626                             token->location, name);
627    }
628    else if (state > PRAGMA_NAME)  // Do not notify for empty pragma.
629    {
630        mDirectiveHandler->handlePragma(token->location, name, value);
631    }
632}
633
634void DirectiveParser::parseExtension(Token *token)
635{
636    assert(getDirective(token) == DIRECTIVE_EXTENSION);
637
638    enum State
639    {
640        EXT_NAME,
641        COLON,
642        EXT_BEHAVIOR
643    };
644
645    bool valid = true;
646    std::string name, behavior;
647    int state = EXT_NAME;
648
649    mTokenizer->lex(token);
650    while ((token->type != '\n') && (token->type != Token::LAST))
651    {
652        switch (state++)
653        {
654          case EXT_NAME:
655            if (valid && (token->type != Token::IDENTIFIER))
656            {
657                mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_NAME,
658                                     token->location, token->text);
659                valid = false;
660            }
661            if (valid) name = token->text;
662            break;
663          case COLON:
664            if (valid && (token->type != ':'))
665            {
666                mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
667                                     token->location, token->text);
668                valid = false;
669            }
670            break;
671          case EXT_BEHAVIOR:
672            if (valid && (token->type != Token::IDENTIFIER))
673            {
674                mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_BEHAVIOR,
675                                     token->location, token->text);
676                valid = false;
677            }
678            if (valid) behavior = token->text;
679            break;
680          default:
681            if (valid)
682            {
683                mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
684                                     token->location, token->text);
685                valid = false;
686            }
687            break;
688        }
689        mTokenizer->lex(token);
690    }
691    if (valid && (state != EXT_BEHAVIOR + 1))
692    {
693        mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_DIRECTIVE,
694                             token->location, token->text);
695        valid = false;
696    }
697    if (valid)
698        mDirectiveHandler->handleExtension(token->location, name, behavior);
699}
700
701void DirectiveParser::parseVersion(Token *token)
702{
703    assert(getDirective(token) == DIRECTIVE_VERSION);
704
705    if (mPastFirstStatement)
706    {
707        mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_STATEMENT,
708                             token->location, token->text);
709        skipUntilEOD(mTokenizer, token);
710        return;
711    }
712
713    enum State
714    {
715        VERSION_NUMBER,
716        VERSION_PROFILE,
717        VERSION_ENDLINE
718    };
719
720    bool valid = true;
721    int version = 0;
722    int state = VERSION_NUMBER;
723
724    mTokenizer->lex(token);
725    while (valid && (token->type != '\n') && (token->type != Token::LAST))
726    {
727        switch (state)
728        {
729          case VERSION_NUMBER:
730            if (token->type != Token::CONST_INT)
731            {
732                mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_NUMBER,
733                                     token->location, token->text);
734                valid = false;
735            }
736            if (valid && !token->iValue(&version))
737            {
738                mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW,
739                                     token->location, token->text);
740                valid = false;
741            }
742            if (valid)
743            {
744                state = (version < 300) ? VERSION_ENDLINE : VERSION_PROFILE;
745            }
746            break;
747          case VERSION_PROFILE:
748            if (token->type != Token::IDENTIFIER || token->text != "es")
749            {
750                mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE,
751                                     token->location, token->text);
752                valid = false;
753            }
754            state = VERSION_ENDLINE;
755            break;
756          default:
757            mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
758                                 token->location, token->text);
759            valid = false;
760            break;
761        }
762
763        mTokenizer->lex(token);
764    }
765
766    if (valid && (state != VERSION_ENDLINE))
767    {
768        mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE,
769                             token->location, token->text);
770        valid = false;
771    }
772
773    if (valid)
774    {
775        mDirectiveHandler->handleVersion(token->location, version);
776    }
777}
778
779void DirectiveParser::parseLine(Token *token)
780{
781    assert(getDirective(token) == DIRECTIVE_LINE);
782
783    enum State
784    {
785        LINE_NUMBER,
786        FILE_NUMBER
787    };
788
789    bool valid = true;
790    int line = 0, file = 0;
791    int state = LINE_NUMBER;
792
793    MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics);
794    macroExpander.lex(token);
795    while ((token->type != '\n') && (token->type != Token::LAST))
796    {
797        switch (state++)
798        {
799          case LINE_NUMBER:
800            if (valid && (token->type != Token::CONST_INT))
801            {
802                mDiagnostics->report(Diagnostics::PP_INVALID_LINE_NUMBER,
803                                     token->location, token->text);
804                valid = false;
805            }
806            if (valid && !token->iValue(&line))
807            {
808                mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW,
809                                     token->location, token->text);
810                valid = false;
811            }
812            break;
813          case FILE_NUMBER:
814            if (valid && (token->type != Token::CONST_INT))
815            {
816                mDiagnostics->report(Diagnostics::PP_INVALID_FILE_NUMBER,
817                                     token->location, token->text);
818                valid = false;
819            }
820            if (valid && !token->iValue(&file))
821            {
822                mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW,
823                                     token->location, token->text);
824                valid = false;
825            }
826            break;
827          default:
828            if (valid)
829            {
830                mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
831                                     token->location, token->text);
832                valid = false;
833            }
834            break;
835        }
836        macroExpander.lex(token);
837    }
838
839    if (valid && (state != FILE_NUMBER) && (state != FILE_NUMBER + 1))
840    {
841        mDiagnostics->report(Diagnostics::PP_INVALID_LINE_DIRECTIVE,
842                             token->location, token->text);
843        valid = false;
844    }
845    if (valid)
846    {
847        mTokenizer->setLineNumber(line);
848        if (state == FILE_NUMBER + 1)
849            mTokenizer->setFileNumber(file);
850    }
851}
852
853bool DirectiveParser::skipping() const
854{
855    if (mConditionalStack.empty())
856        return false;
857
858    const ConditionalBlock& block = mConditionalStack.back();
859    return block.skipBlock || block.skipGroup;
860}
861
862void DirectiveParser::parseConditionalIf(Token *token)
863{
864    ConditionalBlock block;
865    block.type = token->text;
866    block.location = token->location;
867
868    if (skipping())
869    {
870        // This conditional block is inside another conditional group
871        // which is skipped. As a consequence this whole block is skipped.
872        // Be careful not to parse the conditional expression that might
873        // emit a diagnostic.
874        skipUntilEOD(mTokenizer, token);
875        block.skipBlock = true;
876    }
877    else
878    {
879        DirectiveType directive = getDirective(token);
880
881        int expression = 0;
882        switch (directive)
883        {
884          case DIRECTIVE_IF:
885            expression = parseExpressionIf(token);
886            break;
887          case DIRECTIVE_IFDEF:
888            expression = parseExpressionIfdef(token);
889            break;
890          case DIRECTIVE_IFNDEF:
891            expression = parseExpressionIfdef(token) == 0 ? 1 : 0;
892            break;
893          default:
894            assert(false);
895            break;
896        }
897        block.skipGroup = expression == 0;
898        block.foundValidGroup = expression != 0;
899    }
900    mConditionalStack.push_back(block);
901}
902
903int DirectiveParser::parseExpressionIf(Token *token)
904{
905    assert((getDirective(token) == DIRECTIVE_IF) ||
906           (getDirective(token) == DIRECTIVE_ELIF));
907
908    DefinedParser definedParser(mTokenizer, mMacroSet, mDiagnostics);
909    MacroExpander macroExpander(&definedParser, mMacroSet, mDiagnostics);
910    ExpressionParser expressionParser(&macroExpander, mDiagnostics);
911
912    int expression = 0;
913    macroExpander.lex(token);
914    expressionParser.parse(token, &expression);
915
916    // Warn if there are tokens after #if expression.
917    if (!isEOD(token))
918    {
919        mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
920                             token->location, token->text);
921        skipUntilEOD(mTokenizer, token);
922    }
923
924    return expression;
925}
926
927int DirectiveParser::parseExpressionIfdef(Token *token)
928{
929    assert((getDirective(token) == DIRECTIVE_IFDEF) ||
930           (getDirective(token) == DIRECTIVE_IFNDEF));
931
932    mTokenizer->lex(token);
933    if (token->type != Token::IDENTIFIER)
934    {
935        mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
936                             token->location, token->text);
937        skipUntilEOD(mTokenizer, token);
938        return 0;
939    }
940
941    MacroSet::const_iterator iter = mMacroSet->find(token->text);
942    int expression = iter != mMacroSet->end() ? 1 : 0;
943
944    // Warn if there are tokens after #ifdef expression.
945    mTokenizer->lex(token);
946    if (!isEOD(token))
947    {
948        mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
949                             token->location, token->text);
950        skipUntilEOD(mTokenizer, token);
951    }
952    return expression;
953}
954
955}  // namespace pp
956