~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/ThirdParty/ANGLE/src/compiler/preprocessor/new/DirectiveParser.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

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