Parser.cpp 208 KB
Newer Older
con's avatar
con committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include "Parser.h"
#include "Token.h"
#include "Lexer.h"
#include "Control.h"
#include "AST.h"
#include "Literals.h"
27
#include "ObjectiveCTypeQualifiers.h"
28
#include "QtContextKeywords.h"
29
30
31
32

#include <unordered_map>
#include <utility>

33
#include <string>
Roberto Raggi's avatar
Roberto Raggi committed
34
#include <cstdio> // for putchar
35

36
#if defined(_MSC_VER) && (_MSC_VER < 1800)
Tobias Hunger's avatar
Tobias Hunger committed
37
#    define va_copy(dst, src) ((dst) = (src))
38
39
#elif defined(__INTEL_COMPILER) && !defined(va_copy)
#    define va_copy __va_copy
Tobias Hunger's avatar
Tobias Hunger committed
40
41
#endif

Roberto Raggi's avatar
Roberto Raggi committed
42
#define CPLUSPLUS_NO_DEBUG_RULE
43
#define MAX_EXPRESSION_DEPTH 100
44
#define MAX_STATEMENT_DEPTH 100
Roberto Raggi's avatar
Roberto Raggi committed
45

46
47
using namespace CPlusPlus;

Roberto Raggi's avatar
Roberto Raggi committed
48
49
50
namespace {

class DebugRule {
51
public:
Roberto Raggi's avatar
Roberto Raggi committed
52
53
    static int depth;

54
    DebugRule(const char *name, const char *spell, unsigned idx, bool blocked)
Roberto Raggi's avatar
Roberto Raggi committed
55
    {
56
        for (int i = 0; i <= depth; ++i)
57
          fputc('-', stderr);
Roberto Raggi's avatar
Roberto Raggi committed
58
59

        ++depth;
60
        fprintf(stderr, " %s, ahead: '%s' (%u) - block-errors: %d\n", name, spell, idx, blocked);
Roberto Raggi's avatar
Roberto Raggi committed
61
    }
Roberto Raggi's avatar
Roberto Raggi committed
62
63
64
65
66
67
68

    ~DebugRule()
    { --depth; }
};

int DebugRule::depth = 0;

69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
inline bool lookAtAssignmentOperator(int tokenKind)
{
    switch (tokenKind) {
    case T_EQUAL:
    case T_AMPER_EQUAL:
    case T_CARET_EQUAL:
    case T_SLASH_EQUAL:
    case T_GREATER_GREATER_EQUAL:
    case T_LESS_LESS_EQUAL:
    case T_MINUS_EQUAL:
    case T_PERCENT_EQUAL:
    case T_PIPE_EQUAL:
    case T_PLUS_EQUAL:
    case T_STAR_EQUAL:
    case T_TILDE_EQUAL:
        return true;
    default:
        return false;
    } // switch
}

90
namespace Prec {
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
enum {
    Unknown         = 0,
    Comma           = 1,
    Assignment      = 2,
    Conditional     = 3,
    LogicalOr       = 4,
    LogicalAnd      = 5,
    InclusiveOr     = 6,
    ExclusiveOr     = 7,
    And             = 8,
    Equality        = 9,
    Relational      = 10,
    Shift           = 11,
    Additive        = 12,
    Multiplicative  = 13,
    PointerToMember = 14
};
108
} // namespace Precedece
109

110
111
inline int precedence(int tokenKind, bool templateArguments)
{
112
113
    // ### this will/might need some tuning for C++0x
    // (see: [temp.names]p3)
114
    if (templateArguments && (tokenKind == T_GREATER || tokenKind == T_GREATER_GREATER))
115
116
        return -1;

117
    if (lookAtAssignmentOperator(tokenKind))
118
        return Prec::Assignment;
119

120
    switch (tokenKind) {
121
122
123
124
125
126
127
    case T_COMMA:           return Prec::Comma;
    case T_QUESTION:        return Prec::Conditional;
    case T_PIPE_PIPE:       return Prec::LogicalOr;
    case T_AMPER_AMPER:     return Prec::LogicalAnd;
    case T_PIPE:            return Prec::InclusiveOr;
    case T_CARET:           return Prec::ExclusiveOr;
    case T_AMPER:           return Prec::And;
128
    case T_EQUAL_EQUAL:
129
    case T_EXCLAIM_EQUAL:   return Prec::Equality;
130
131
132
    case T_GREATER:
    case T_LESS:
    case T_LESS_EQUAL:
133
    case T_GREATER_EQUAL:   return Prec::Relational;
134
    case T_LESS_LESS:
135
    case T_GREATER_GREATER: return Prec::ExclusiveOr;
136
    case T_PLUS:
137
    case T_MINUS:           return Prec::Additive;
138
139
    case T_STAR:
    case T_SLASH:
140
    case T_PERCENT:         return Prec::Multiplicative;
141
    case T_ARROW_STAR:
142
143
    case T_DOT_STAR:        return Prec::PointerToMember;
    default:                return Prec::Unknown;
144
145
146
    }
}

147
inline bool isBinaryOperator(int tokenKind)
148
149
150
151
152
153
154
{ return precedence(tokenKind, false) != Prec::Unknown; }

inline bool isRightAssociative(int tokenKind)
{
    const int prec = precedence(tokenKind, false);
    return prec == Prec::Conditional || prec == Prec::Assignment;
}
155

Roberto Raggi's avatar
Roberto Raggi committed
156
157
} // end of anonymous namespace

158
159
160
161
162
163
164
165
166
167
class Parser::ASTCache
{
    ASTCache(const ASTCache &other);
    void operator =(const ASTCache &other);

public:
    enum ASTKind {
        Expression,
        ExpressionList,
        ParameterDeclarationClause,
168
        TemplateId,
169
170
171
172
173
174
175
        TypeId
    };

public:
    ASTCache() {}

    void insert(ASTKind astKind, unsigned tokenIndexBeforeParsing,
176
                AST *resultingAST, unsigned resultingTokenIndex, bool resultingReturnValue)
177
178
    {
        const auto key = std::make_pair(astKind, tokenIndexBeforeParsing);
179
180
181
182
183
184

        ParseFunctionResult result;
        result.resultingAST = resultingAST;
        result.resultingTokenIndex = resultingTokenIndex;
        result.returnValue = resultingReturnValue;
        const auto keyValue = std::make_pair(key, result);
185
186
187
188
        _cache.insert(keyValue);
    }

    AST *find(ASTKind astKind, unsigned tokenIndex,
189
              unsigned *resultingTokenIndex, bool *foundInCache, bool *returnValue) const
190
191
192
193
194
195
196
197
    {
        const auto key = std::make_pair(astKind, tokenIndex);
        const auto it = _cache.find(key);
        if (it == _cache.end()) {
            *foundInCache = false;
            return 0;
        } else {
            *foundInCache = true;
198
199
200
            *resultingTokenIndex = it->second.resultingTokenIndex;
            *returnValue = it->second.returnValue;
            return it->second.resultingAST;
201
202
203
204
205
206
207
208
209
210
211
212
213
214
        }
    }

    void clear()
    {
        _cache.clear();
    }

private:
    struct KeyHasher {
        size_t operator()(const std::pair<int, unsigned> &key) const
        { return std::hash<int>()(key.first) ^ std::hash<unsigned>()(key.second); }
    };

215
216
217
218
219
220
    struct ParseFunctionResult {
        AST *resultingAST;
        unsigned resultingTokenIndex;
        bool returnValue;
    };

221
    typedef std::pair<int, unsigned> ASTKindAndTokenIndex;
222
    std::unordered_map<ASTKindAndTokenIndex, ParseFunctionResult, KeyHasher> _cache;
223
224
};

Roberto Raggi's avatar
Roberto Raggi committed
225
#ifndef CPLUSPLUS_NO_DEBUG_RULE
226
#  define DEBUG_THIS_RULE() DebugRule __debug_rule__(__func__, tok().spell(), cursor(), _translationUnit->blockErrors())
227
228
229
230
231
232
233
234
235
inline void debugPrintCheckCache(bool goodCase)
{
    for (int i = 0; i <= DebugRule::depth - 1; ++i)
        fputc('-', stderr);
    if (goodCase)
        fprintf(stderr, " CACHE: Re-using AST from Cache.\n");
    else
        fprintf(stderr, " CACHE: Already tried to parse this, skipping.\n");
}
Roberto Raggi's avatar
Roberto Raggi committed
236
237
#else
#  define DEBUG_THIS_RULE() do {} while (0)
238
inline void debugPrintCheckCache(bool) {}
Roberto Raggi's avatar
Roberto Raggi committed
239
240
#endif

241
#define CHECK_CACHE(ASTKind, ASTType) \
242
243
    do { \
        bool foundInCache; \
244
245
246
247
        unsigned newTokenIndex; \
        bool returnValue; \
        if (AST *ast = _astCache->find(ASTKind, cursor(), \
                                       &newTokenIndex, &foundInCache, &returnValue)) { \
248
249
250
            debugPrintCheckCache(true); \
            node = (ASTType *) ast; \
            _tokenIndex = newTokenIndex; \
251
            return returnValue; \
252
253
        } else if (foundInCache) { \
            debugPrintCheckCache(false); \
254
            return returnValue; \
255
256
257
        } \
    } while (0)

258
#define PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, minPrecedence) { \
259
260
261
262
    if (LA() == T_THROW) { \
        if (!parseThrowExpression(node)) \
            return false; \
    } else if (!parseCastExpression(node)) \
263
264
265
266
267
268
        return false; \
    \
    parseExpressionWithOperatorPrecedence(node, minPrecedence); \
    return true; \
}

269
Parser::Parser(TranslationUnit *unit)
con's avatar
con committed
270
    : _translationUnit(unit),
271
272
273
      _control(unit->control()),
      _pool(unit->memoryPool()),
      _languageFeatures(unit->languageFeatures()),
con's avatar
con committed
274
275
      _tokenIndex(1),
      _templateArguments(0),
Roberto Raggi's avatar
Roberto Raggi committed
276
      _inFunctionBody(false),
277
      _inExpressionStatement(false),
278
      _expressionDepth(0),
279
280
281
      _statementDepth(0),
      _astCache(new ASTCache),
      _expressionStatementAstCache(new ASTCache)
con's avatar
con committed
282
283
284
{ }

Parser::~Parser()
285
286
287
288
{
    delete _expressionStatementAstCache;
    delete _astCache;
}
con's avatar
con committed
289
290
291
292
293
294
295
296

bool Parser::switchTemplateArguments(bool templateArguments)
{
    bool previousTemplateArguments = _templateArguments;
    _templateArguments = templateArguments;
    return previousTemplateArguments;
}

297
298
299
300
301
bool Parser::maybeSplitGreaterGreaterToken(int n)
{
    return _translationUnit->maybeSplitGreaterGreaterToken(_tokenIndex + n - 1);
}

con's avatar
con committed
302
303
304
305
306
307
308
309
310
311
312
313
bool Parser::skipUntil(int token)
{
    while (int tk = LA()) {
        if (tk == token)
            return true;

        consumeToken();
    }

    return false;
}

314
void Parser::skipUntilDeclaration()
con's avatar
con committed
315
{
316
317
318
319
    for (; ; consumeToken()) {
        switch (LA()) {
        case T_EOF_SYMBOL:

320
321
322
        // end of a block
        case T_RBRACE:

323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
        // names
        case T_IDENTIFIER:
        case T_COLON_COLON:
        case T_TILDE:
        case T_OPERATOR:

        // empty declaration
        case T_SEMICOLON:

        // member specification
        case T_USING:
        case T_TEMPLATE:
        case T_PUBLIC:
        case T_PROTECTED:
        case T_PRIVATE:
        case T_Q_SIGNALS:
        case T_Q_SLOTS:
340
        case T_Q_PROPERTY:
341
        case T_Q_PRIVATE_PROPERTY:
342
343
        case T_Q_ENUMS:
        case T_Q_FLAGS:
344
        case T_Q_INTERFACES:
345
346
347
348
349

        // Qt function specifiers
        case T_Q_SIGNAL:
        case T_Q_SLOT:
        case T_Q_INVOKABLE:
350
351
352
353

        // declarations
        case T_ENUM:
        case T_NAMESPACE:
354
355
        case T_INLINE:
        case T_STATIC_ASSERT:
356
357
        case T_ASM:
        case T_EXPORT:
358
359
360
361
362
        case T_AT_CLASS:
        case T_AT_INTERFACE:
        case T_AT_PROTOCOL:
        case T_AT_IMPLEMENTATION:
        case T_AT_END:
363
364
365
366
367
368
369
            return;

        default:
            if (lookAtBuiltinTypeSpecifier() || lookAtClassKey() ||
                lookAtFunctionSpecifier() || lookAtStorageClassSpecifier())
                return;
        } // switch
370
    }
con's avatar
con committed
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
}

bool Parser::skipUntilStatement()
{
    while (int tk = LA()) {
        switch (tk) {
            case T_SEMICOLON:
            case T_LBRACE:
            case T_RBRACE:
            case T_CONST:
            case T_VOLATILE:
            case T_IDENTIFIER:
            case T_CASE:
            case T_DEFAULT:
            case T_IF:
            case T_SWITCH:
            case T_WHILE:
            case T_DO:
            case T_FOR:
            case T_BREAK:
            case T_CONTINUE:
            case T_RETURN:
            case T_GOTO:
            case T_TRY:
            case T_CATCH:
            case T_THROW:
            case T_CHAR:
398
399
            case T_CHAR16_T:
            case T_CHAR32_T:
con's avatar
con committed
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
            case T_WCHAR_T:
            case T_BOOL:
            case T_SHORT:
            case T_INT:
            case T_LONG:
            case T_SIGNED:
            case T_UNSIGNED:
            case T_FLOAT:
            case T_DOUBLE:
            case T_VOID:
            case T_CLASS:
            case T_STRUCT:
            case T_UNION:
            case T_ENUM:
            case T_COLON_COLON:
            case T_TEMPLATE:
            case T_USING:
                return true;

419
            case T_AT_TRY:
420
            case T_AT_SYNCHRONIZED:
421
            case T_AT_THROW:
422
                if (_languageFeatures.objCEnabled)
423
                    return true;
424

con's avatar
con committed
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
            default:
                consumeToken();
        }
    }

    return false;
}

bool Parser::skip(int l, int r)
{
    int count = 0;

    while (int tk = LA()) {
        if (tk == l)
            ++count;
        else if (tk == r)
            --count;
        else if (l != T_LBRACE && (tk == T_LBRACE ||
                                   tk == T_RBRACE ||
                                   tk == T_SEMICOLON))
            return false;

        if (count == 0)
            return true;

        consumeToken();
    }

    return false;
}

456
457
458
459
460
461
462
463
464
465
466
467
int Parser::find(int token, int stopAt)
{
    for (int i = 1; ; ++i) {
        const int tk = LA(i);
        if (!tk || tk == stopAt)
            return 0;
        if (tk == token)
            return i;
    }
    return 0;
}

con's avatar
con committed
468
469
470
471
472
473
void Parser::match(int kind, unsigned *token)
{
    if (LA() == kind)
        *token = consumeToken();
    else {
        *token = 0;
474
        error(_tokenIndex, "expected token `%s' got `%s'",
Orgad Shaneh's avatar
Orgad Shaneh committed
475
              Token::name(kind), tok().spell());
con's avatar
con committed
476
477
478
479
480
    }
}

bool Parser::parseClassOrNamespaceName(NameAST *&node)
{
Roberto Raggi's avatar
Roberto Raggi committed
481
    DEBUG_THIS_RULE();
482
    if (LA() == T_IDENTIFIER && (LA(2) == T_COLON_COLON || LA(2) == T_LESS)) {
con's avatar
con committed
483
484
        unsigned identifier_token = cursor();

485
486
487
488
489
490
491
492
        if (LA(2) == T_LESS) {
            bool blocked = blockErrors(true);
            if (parseTemplateId(node) && LA() == T_COLON_COLON) {
                blockErrors(blocked);
                return true;
            }
            blockErrors(blocked);
        }
con's avatar
con committed
493
494
495
496
497
498
499
500
501
502
503

        rewind(identifier_token);

        if (LA(2) == T_COLON_COLON) {
            SimpleNameAST *ast = new (_pool) SimpleNameAST;
            ast->identifier_token = consumeToken();
            node = ast;
            return true;
        }
    } else if (LA() == T_TEMPLATE) {
        unsigned template_token = consumeToken();
504
        if (parseTemplateId(node, template_token) && LA() == T_COLON_COLON)
con's avatar
con committed
505
506
507
508
509
510
            return true;
        rewind(template_token);
    }
    return false;
}

511
bool Parser::parseTemplateId(NameAST *&node, unsigned template_token)
con's avatar
con committed
512
{
Roberto Raggi's avatar
Roberto Raggi committed
513
    DEBUG_THIS_RULE();
514
    CHECK_CACHE(ASTCache::TemplateId, NameAST);
515
516
517

    const unsigned start = cursor();

con's avatar
con committed
518
519
    if (LA() == T_IDENTIFIER && LA(2) == T_LESS) {
        TemplateIdAST *ast = new (_pool) TemplateIdAST;
520
        ast->template_token = template_token;
con's avatar
con committed
521
522
        ast->identifier_token = consumeToken();
        ast->less_token = consumeToken();
523
        if (maybeSplitGreaterGreaterToken() || LA() == T_GREATER || parseTemplateArgumentList(
Roberto Raggi's avatar
Roberto Raggi committed
524
                ast->template_argument_list)) {
525
            if (maybeSplitGreaterGreaterToken() || LA() == T_GREATER) {
con's avatar
con committed
526
527
                ast->greater_token = consumeToken();
                node = ast;
528
529
530
                const bool result = true;
                _astCache->insert(ASTCache::TemplateId, start, node, cursor(), result);
                return result;
con's avatar
con committed
531
532
533
            }
        }
    }
534

535
536
    const bool result = false;
    _astCache->insert(ASTCache::TemplateId, start, 0, cursor(), result);
537
    rewind(start);
538
    return result;
con's avatar
con committed
539
540
}

Roberto Raggi's avatar
Roberto Raggi committed
541
bool Parser::parseNestedNameSpecifier(NestedNameSpecifierListAST *&node,
con's avatar
con committed
542
543
                                      bool /*acceptTemplateId*/)
{
Roberto Raggi's avatar
Roberto Raggi committed
544
    DEBUG_THIS_RULE();
Roberto Raggi's avatar
Roberto Raggi committed
545
    NestedNameSpecifierListAST **nested_name_specifier = &node;
con's avatar
con committed
546
    NameAST *class_or_namespace_name = 0;
Roberto Raggi's avatar
Roberto Raggi committed
547
    if (parseClassOrNamespaceName(class_or_namespace_name) && LA() == T_COLON_COLON) {
con's avatar
con committed
548
549
        unsigned scope_token = consumeToken();

Roberto Raggi's avatar
Roberto Raggi committed
550
551
552
553
554
        NestedNameSpecifierAST *name = new (_pool) NestedNameSpecifierAST;
        name->class_or_namespace_name = class_or_namespace_name;
        name->scope_token = scope_token;

        *nested_name_specifier = new (_pool) NestedNameSpecifierListAST(name);
con's avatar
con committed
555
556
        nested_name_specifier = &(*nested_name_specifier)->next;

Roberto Raggi's avatar
Roberto Raggi committed
557
        while (parseClassOrNamespaceName(class_or_namespace_name) && LA() == T_COLON_COLON) {
con's avatar
con committed
558
            scope_token = consumeToken();
Roberto Raggi's avatar
Roberto Raggi committed
559
560
561
562
563
564

            name = new (_pool) NestedNameSpecifierAST;
            name->class_or_namespace_name = class_or_namespace_name;
            name->scope_token = scope_token;

            *nested_name_specifier = new (_pool) NestedNameSpecifierListAST(name);
con's avatar
con committed
565
566
567
568
569
570
571
572
573
574
575
576
            nested_name_specifier = &(*nested_name_specifier)->next;
        }

        // ### ugly hack
        rewind(scope_token);
        consumeToken();
        return true;
    }

    return false;
}

Roberto Raggi's avatar
Roberto Raggi committed
577
bool Parser::parseNestedNameSpecifierOpt(NestedNameSpecifierListAST *&name, bool acceptTemplateId)
con's avatar
con committed
578
{
Roberto Raggi's avatar
Roberto Raggi committed
579
    DEBUG_THIS_RULE();
con's avatar
con committed
580
581
582
583
584
585
586
587
    unsigned start = cursor();
    if (! parseNestedNameSpecifier(name, acceptTemplateId))
        rewind(start);
    return true;
}

bool Parser::parseName(NameAST *&node, bool acceptTemplateId)
{
Roberto Raggi's avatar
Roberto Raggi committed
588
    DEBUG_THIS_RULE();
589
    unsigned global_scope_token = 0;
590
591
592
593
594
595
596
597
598
599
600
601

    switch (LA()) {
    case T_COLON_COLON:
    case T_IDENTIFIER:
    case T_TILDE: // destructor-name-id
    case T_OPERATOR: // operator-name-id
    case T_TEMPLATE: // template introduced template-id
      break;
    default:
      return false;
    }

con's avatar
con committed
602
603
604
    if (LA() == T_COLON_COLON)
        global_scope_token = consumeToken();

Roberto Raggi's avatar
Roberto Raggi committed
605
    NestedNameSpecifierListAST *nested_name_specifier = 0;
con's avatar
con committed
606
607
608
609
610
611
612
613
614
615
616
617
618
    parseNestedNameSpecifierOpt(nested_name_specifier,
                                /*acceptTemplateId=*/ true);

    NameAST *unqualified_name = 0;
    if (parseUnqualifiedName(unqualified_name,
                             /*acceptTemplateId=*/ acceptTemplateId || nested_name_specifier != 0)) {
        if (! global_scope_token && ! nested_name_specifier) {
            node = unqualified_name;
            return true;
        }

        QualifiedNameAST *ast = new (_pool) QualifiedNameAST;
        ast->global_scope_token = global_scope_token;
Roberto Raggi's avatar
Roberto Raggi committed
619
        ast->nested_name_specifier_list = nested_name_specifier;
con's avatar
con committed
620
621
622
623
624
625
626
627
628
629
        ast->unqualified_name = unqualified_name;
        node = ast;
        return true;
    }

    return false;
}

bool Parser::parseTranslationUnit(TranslationUnitAST *&node)
{
Roberto Raggi's avatar
Roberto Raggi committed
630
    DEBUG_THIS_RULE();
con's avatar
con committed
631
    TranslationUnitAST *ast = new (_pool) TranslationUnitAST;
Roberto Raggi's avatar
Roberto Raggi committed
632
    DeclarationListAST **decl = &ast->declaration_list;
con's avatar
con committed
633
634
635
636

    while (LA()) {
        unsigned start_declaration = cursor();

Roberto Raggi's avatar
Roberto Raggi committed
637
638
639
640
        DeclarationAST *declaration = 0;

        if (parseDeclaration(declaration)) {
            *decl = new (_pool) DeclarationListAST;
641
            (*decl)->value = declaration;
Roberto Raggi's avatar
Roberto Raggi committed
642
            decl = &(*decl)->next;
con's avatar
con committed
643
        } else {
644
            error(start_declaration, "expected a declaration");
con's avatar
con committed
645
            rewind(start_declaration + 1);
646
            skipUntilDeclaration();
con's avatar
con committed
647
        }
Roberto Raggi's avatar
Roberto Raggi committed
648

649
650

        if (TopLevelDeclarationProcessor *processor = _control->topLevelDeclarationProcessor()) {
651
            if (!processor->processDeclaration(declaration))
652
653
654
                break;
        }

Roberto Raggi's avatar
Roberto Raggi committed
655
        _templateArgumentList.clear();
con's avatar
con committed
656
657
658
659
660
661
662
663
    }

    node = ast;
    return true;
}

bool Parser::parseEmptyDeclaration(DeclarationAST *&node)
{
Roberto Raggi's avatar
Roberto Raggi committed
664
    DEBUG_THIS_RULE();
con's avatar
con committed
665
666
667
668
669
670
671
672
673
674
675
    if (LA() == T_SEMICOLON) {
        EmptyDeclarationAST *ast = new (_pool) EmptyDeclarationAST;
        ast->semicolon_token = consumeToken();
        node = ast;
        return true;
    }
    return false;
}

bool Parser::parseDeclaration(DeclarationAST *&node)
{
Roberto Raggi's avatar
Roberto Raggi committed
676
    DEBUG_THIS_RULE();
con's avatar
con committed
677
678
679
680
681
682
683
684
685
686
687
688
689
    switch (LA()) {
    case T_SEMICOLON:
        return parseEmptyDeclaration(node);

    case T_NAMESPACE:
        return parseNamespace(node);

    case T_USING:
        return parseUsing(node);

    case T_ASM:
        return parseAsmDefinition(node);

690

con's avatar
con committed
691
692
693
694
    case T_TEMPLATE:
    case T_EXPORT:
        return parseTemplateDeclaration(node);

Roberto Raggi's avatar
Roberto Raggi committed
695
    // ObjcC++
696
697
    case T_AT_CLASS:
        return parseObjCClassForwardDeclaration(node);
698

699
700
    case T_AT_INTERFACE:
        return parseObjCInterface(node);
701

702
703
    case T_AT_PROTOCOL:
        return parseObjCProtocol(node);
704

705
706
    case T_AT_IMPLEMENTATION:
        return parseObjCImplementation(node);
707

708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
    case T_Q_DECLARE_INTERFACE:
    {
        consumeToken();
        unsigned lparen_token = 0;
        match(T_LPAREN, &lparen_token);
        NameAST *name = 0;
        parseName(name);
        unsigned comma_token = 0;
        match(T_COMMA, &comma_token);
        unsigned string_literal = 0;
        match(T_STRING_LITERAL, &string_literal);
        unsigned rparen_token = 0;
        match(T_RPAREN, &rparen_token);
    }   return true;

723
724
    case T_AT_END:
        // TODO: should this be done here, or higher-up?
725
        error(cursor(), "skip stray token `%s'", tok().spell());
726
727
        consumeToken();
        break;
728

729
    case T_INLINE:
730
        if (_languageFeatures.cxx11Enabled && LA(2) == T_NAMESPACE)
731
            return parseNamespace(node);
732
733
734
        return parseSimpleDeclaration(node);

    case T_STATIC_ASSERT:
735
        if (_languageFeatures.cxx11Enabled)
736
737
            return parseStaticAssertDeclaration(node);
        return parseSimpleDeclaration(node);
738

Roberto Raggi's avatar
Roberto Raggi committed
739
    default: {
740
        if (_languageFeatures.objCEnabled && LA() == T___ATTRIBUTE__) {
Roberto Raggi's avatar
Roberto Raggi committed
741
            const unsigned start = cursor();
Roberto Raggi's avatar
Roberto Raggi committed
742
            SpecifierListAST *attributes = 0, **attr = &attributes;
743
            while (parseGnuAttributeSpecifier(*attr))
Roberto Raggi's avatar
Roberto Raggi committed
744
                attr = &(*attr)->next;
745
746
747
748
749
750
            if (LA() == T_AT_INTERFACE)
                return parseObjCInterface(node, attributes);
            else if (LA() == T_AT_PROTOCOL)
                return parseObjCProtocol(node, attributes);
            else if (LA() == T_AT_PROPERTY)
                return parseObjCPropertyDeclaration(node, attributes);
Roberto Raggi's avatar
Roberto Raggi committed
751
752
            rewind(start);
        }
753

con's avatar
con committed
754
755
756
757
758
759
        if (LA() == T_EXTERN && LA(2) == T_TEMPLATE)
            return parseTemplateDeclaration(node);
        else if (LA() == T_EXTERN && LA(2) == T_STRING_LITERAL)
            return parseLinkageSpecification(node);
        else
            return parseSimpleDeclaration(node);
Roberto Raggi's avatar
Roberto Raggi committed
760
761
    }   break; // default

con's avatar
con committed
762
    } // end switch
Roberto Raggi's avatar
Roberto Raggi committed
763
764

    return false;
con's avatar
con committed
765
766
767
768
}

bool Parser::parseLinkageSpecification(DeclarationAST *&node)
{
Roberto Raggi's avatar
Roberto Raggi committed
769
    DEBUG_THIS_RULE();
con's avatar
con committed
770
771
772
    if (LA() == T_EXTERN && LA(2) == T_STRING_LITERAL) {
        LinkageSpecificationAST *ast = new (_pool) LinkageSpecificationAST;
        ast->extern_token = consumeToken();
Roberto Raggi's avatar
cleanup    
Roberto Raggi committed
773
        ast->extern_type_token = consumeToken();
con's avatar
con committed
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788

        if (LA() == T_LBRACE)
            parseLinkageBody(ast->declaration);
        else
            parseDeclaration(ast->declaration);

        node = ast;
        return true;
    }

    return false;
}

bool Parser::parseLinkageBody(DeclarationAST *&node)
{
Roberto Raggi's avatar
Roberto Raggi committed
789
    DEBUG_THIS_RULE();
con's avatar
con committed
790
791
792
    if (LA() == T_LBRACE) {
        LinkageBodyAST *ast = new (_pool) LinkageBodyAST;
        ast->lbrace_token = consumeToken();
Roberto Raggi's avatar
Roberto Raggi committed
793
        DeclarationListAST **declaration_ptr = &ast->declaration_list;
con's avatar
con committed
794
795
796
797
798
799

        while (int tk = LA()) {
            if (tk == T_RBRACE)
                break;

            unsigned start_declaration = cursor();
Roberto Raggi's avatar
Roberto Raggi committed
800
801
802
            DeclarationAST *declaration = 0;
            if (parseDeclaration(declaration)) {
                *declaration_ptr = new (_pool) DeclarationListAST;
803
                (*declaration_ptr)->value = declaration;
Roberto Raggi's avatar
Roberto Raggi committed
804
                declaration_ptr = &(*declaration_ptr)->next;
con's avatar
con committed
805
            } else {
806
                error(start_declaration, "expected a declaration");
con's avatar
con committed
807
                rewind(start_declaration + 1);
808
                skipUntilDeclaration();
con's avatar
con committed
809
            }
Roberto Raggi's avatar
Roberto Raggi committed
810
811

            _templateArgumentList.clear();
con's avatar
con committed
812
813
814
815
816
817
818
819
        }
        match(T_RBRACE, &ast->rbrace_token);
        node = ast;
        return true;
    }
    return false;
}

820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
bool Parser::parseStaticAssertDeclaration(DeclarationAST *&node)
{
    DEBUG_THIS_RULE();
    if (LA() != T_STATIC_ASSERT)
        return false;

    StaticAssertDeclarationAST *ast = new (_pool) StaticAssertDeclarationAST;
    ast->static_assert_token = consumeToken();
    match(T_LPAREN, &ast->lparen_token);
    parseConstantExpression(ast->expression);
    match(T_COMMA, &ast->comma_token);
    parseStringLiteral(ast->string_literal);
    match(T_RPAREN, &ast->rparen_token);
    match(T_SEMICOLON, &ast->semicolon_token);

    node = ast;
    return true;
}

con's avatar
con committed
839
840
841
// ### rename parseNamespaceAliarOrDeclaration?
bool Parser::parseNamespace(DeclarationAST *&node)
{
Roberto Raggi's avatar
Roberto Raggi committed
842
    DEBUG_THIS_RULE();
843
    if (LA() != T_NAMESPACE && !(_languageFeatures.cxx11Enabled && LA() == T_INLINE && LA(2) == T_NAMESPACE))
con's avatar
con committed
844
845
        return false;

846
    unsigned inline_token = 0;
847
    if (_languageFeatures.cxx11Enabled && LA() == T_INLINE)
848
849
        inline_token = consumeToken();

con's avatar
con committed
850
851
852
    unsigned namespace_token = consumeToken();

    if (LA() == T_IDENTIFIER && LA(2) == T_EQUAL) {
853
854
        if (inline_token)
            warning(inline_token, "namespace alias cannot be inline");
con's avatar
con committed
855
856
857
        NamespaceAliasDefinitionAST *ast =
                new (_pool) NamespaceAliasDefinitionAST;
        ast->namespace_token = namespace_token;
Roberto Raggi's avatar
cleanup    
Roberto Raggi committed
858
        ast->namespace_name_token = consumeToken();
con's avatar
con committed
859
860
861
862
863
864
865
866
        ast->equal_token = consumeToken();
        parseName(ast->name);
        match(T_SEMICOLON, &ast->semicolon_token);
        node = ast;
        return true;
    }

    NamespaceAST *ast = new (_pool) NamespaceAST;
867
    ast->inline_token = inline_token;
con's avatar
con committed
868
869
870
    ast->namespace_token = namespace_token;
    if (LA() == T_IDENTIFIER)
        ast->identifier_token = consumeToken();
871
    parseOptionalAttributeSpecifierSequence(ast->attribute_list);
872
    if (LA() == T_LBRACE) {
con's avatar
con committed
873
        parseLinkageBody(ast->linkage_body);
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
    } else { // attempt to do error recovery
        unsigned pos = cursor();
        for (;LA() != T_EOF_SYMBOL; consumeToken()) {
            switch (LA()) {
            case T_IDENTIFIER:
            case T_POUND:
            case T_POUND_POUND:
            case T___ATTRIBUTE__:
            case T_LPAREN:
            case T_RPAREN:
            case T_DEFAULT:
            case T_PUBLIC:
            case T_PRIVATE:
            case T_PROTECTED:
                continue;
            }
            if (tok().isLiteral())
                continue;
            break;
        }
        if (LA() == T_LBRACE && parseLinkageBody(ast->linkage_body))
            warning(pos, "expected '{' before '%s'", _translationUnit->tokenAt(pos).spell());
        else
            rewind(pos);
    }
con's avatar
con committed
899
900
901
902
903
904
    node = ast;
    return true;
}

bool Parser::parseUsing(DeclarationAST *&node)
{
Roberto Raggi's avatar
Roberto Raggi committed
905
    DEBUG_THIS_RULE();
con's avatar
con committed
906
907
908
909
910
911
    if (LA() != T_USING)
        return false;

    if (LA(2) == T_NAMESPACE)
        return parseUsingDirective(node);

912
    if (_languageFeatures.cxx11Enabled && LA(2) == T_IDENTIFIER && parseAliasDeclaration(node))
913
914
        return true;

con's avatar
con committed
915
916
917
918
919
920
921
922
923
924
925
926
927
928
    UsingAST *ast = new (_pool) UsingAST;
    ast->using_token = consumeToken();

    if (LA() == T_TYPENAME)
        ast->typename_token = consumeToken();

    parseName(ast->name);
    match(T_SEMICOLON, &ast->semicolon_token);
    node = ast;
    return true;
}

bool Parser::parseUsingDirective(DeclarationAST *&node)
{
Roberto Raggi's avatar
Roberto Raggi committed
929
    DEBUG_THIS_RULE();
con's avatar
con committed
930
931
932
933
934
    if (LA() == T_USING && LA(2) == T_NAMESPACE) {
        UsingDirectiveAST *ast = new (_pool) UsingDirectiveAST;
        ast->using_token = consumeToken();
        ast->namespace_token = consumeToken();
        if (! parseName(ast->name))
935
936
            warning(cursor(), "expected `namespace name' before `%s'",
                    tok().spell());
con's avatar
con committed
937
938
939
940
941
942
943
        match(T_SEMICOLON, &ast->semicolon_token);
        node = ast;
        return true;
    }
    return false;
}

944
945
946
947
948
949
950
951
952
953
954
955
// alias-declaration = 'using' identifier attribute-specifier-seq(opt) '=' type-id ';'
bool Parser::parseAliasDeclaration(DeclarationAST *&node)
{
    DEBUG_THIS_RULE();
    if (LA() != T_USING || LA(2) != T_IDENTIFIER)
        return false;

    if (!find(T_EQUAL, T_SEMICOLON))
        return false;

    AliasDeclarationAST *alias = new (_pool) AliasDeclarationAST;
    alias->using_token = consumeToken();
956
957
958
    SimpleNameAST *name = new (_pool) SimpleNameAST;
    name->identifier_token = consumeToken();
    alias->name = name;
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976

    // ### attributes!
    while (LA() != T_EQUAL)
        consumeToken();

    alias->equal_token = consumeToken();

    ExpressionAST *expr = 0;
    parseTypeId(expr);
    if (expr)
        alias->typeId = expr->asTypeId();

    match(T_SEMICOLON, &alias->semicolon_token);

    node = alias;
    return true;
}

con's avatar
con committed
977
978
bool Parser::parseConversionFunctionId(NameAST *&node)
{
Roberto Raggi's avatar
Roberto Raggi committed
979
    DEBUG_THIS_RULE();
con's avatar
con committed
980
981
982
    if (LA() != T_OPERATOR)
        return false;
    unsigned operator_token = consumeToken();
Roberto Raggi's avatar
Roberto Raggi committed
983
    SpecifierListAST *type_specifier = 0;
984
    if (! parseTypeSpecifier(type_specifier))
con's avatar
con committed
985
        return false;
Roberto Raggi's avatar
Roberto Raggi committed
986
    PtrOperatorListAST *ptr_operators = 0, **ptr_operators_tail = &ptr_operators;
con's avatar
con committed
987
988
989
990
991
    while (parsePtrOperator(*ptr_operators_tail))
        ptr_operators_tail = &(*ptr_operators_tail)->next;

    ConversionFunctionIdAST *ast = new (_pool) ConversionFunctionIdAST;
    ast->operator_token = operator_token;
Roberto Raggi's avatar
Roberto Raggi committed
992
993
    ast->type_specifier_list = type_specifier;
    ast->ptr_operator_list = ptr_operators;
con's avatar
con committed
994
995
996
997
998
999
    node = ast;
    return true;
}

bool Parser::parseOperatorFunctionId(NameAST *&node)
{
Roberto Raggi's avatar
Roberto Raggi committed
1000
    DEBUG_THIS_RULE();
con's avatar
con committed
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
    if (LA() != T_OPERATOR)
        return false;
    unsigned operator_token = consumeToken();

    OperatorAST *op = 0;
    if (! parseOperator(op))
        return false;

    OperatorFunctionIdAST *ast = new (_pool) OperatorFunctionIdAST;
    ast->operator_token = operator_token;
    ast->op = op;
    node = ast;
    return true;
}

1016
1017
Parser::TemplateArgumentListEntry *Parser::templateArgumentListEntry(unsigned tokenIndex)
{
Roberto Raggi's avatar
Roberto Raggi committed
1018
1019
1020
    std::map<unsigned, TemplateArgumentListEntry>::iterator it =_templateArgumentList.find(tokenIndex);
    if (it != _templateArgumentList.end())
        return &it->second;
1021
1022
1023
1024

    return 0;
}

Roberto Raggi's avatar
Roberto Raggi committed
1025
bool Parser::parseTemplateArgumentList(ExpressionListAST *&node)
con's avatar
con committed
1026
{
1027
1028
    DEBUG_THIS_RULE();

1029
1030
    if (TemplateArgumentListEntry *entry = templateArgumentListEntry(cursor())) {
        rewind(entry->cursor);
Roberto Raggi's avatar
Roberto Raggi committed
1031
1032
        node = entry->ast;
        return entry->ast != 0;
1033
1034
1035
1036
    }

    unsigned start = cursor();

Roberto Raggi's avatar
Roberto Raggi committed
1037
    ExpressionListAST **template_argument_ptr = &node;
con's avatar
con committed
1038
    ExpressionAST *template_argument = 0;
1039
    const bool cxx11Enabled = _languageFeatures.cxx11Enabled;
con's avatar
con committed
1040
    if (parseTemplateArgument(template_argument)) {
Roberto Raggi's avatar
Roberto Raggi committed
1041
        *template_argument_ptr = new (_pool) ExpressionListAST;
1042
        (*template_argument_ptr)->value = template_argument;
con's avatar
con committed
1043
        template_argument_ptr = &(*template_argument_ptr)->next;
1044

1045
        if (cxx11Enabled && LA() == T_DOT_DOT_DOT)
1046
1047
            consumeToken(); // ### store this token in the AST

con's avatar
con committed
1048
        while (LA() == T_COMMA) {
1049
            consumeToken(); // consume T_COMMA
con's avatar
con committed
1050
1051

            if (parseTemplateArgument(template_argument)) {
Roberto Raggi's avatar
Roberto Raggi committed
1052
                *template_argument_ptr = new (_pool) ExpressionListAST;
1053
                (*template_argument_ptr)->value = template_argument;
con's avatar
con committed
1054
                template_argument_ptr = &(*template_argument_ptr)->next;
1055

1056
                if (cxx11Enabled && LA() == T_DOT_DOT_DOT)
1057
                    consumeToken(); // ### store this token in the AST
con's avatar
con committed
1058
1059
            }
        }
1060

1061
1062
        if (_pool != _translationUnit->memoryPool()) {
            MemoryPool *pool = _translationUnit->memoryPool();
Roberto Raggi's avatar
Roberto Raggi committed
1063
1064
            ExpressionListAST *template_argument_list = node;
            for (ExpressionListAST *iter = template_argument_list, **ast_iter = &node;
1065
                 iter; iter = iter->next, ast_iter = &(*ast_iter)->next)
Roberto Raggi's avatar
Roberto Raggi committed
1066
                *ast_iter = new (pool) ExpressionListAST((iter->value) ? iter->value->clone(pool) : 0);
1067
1068
        }

1069
        _templateArgumentList.insert(std::make_pair(start, TemplateArgumentListEntry(start, cursor(), node)));
con's avatar
con committed
1070
1071
        return true;
    }
1072

1073
    _templateArgumentList.insert(std::make_pair(start, TemplateArgumentListEntry(start, cursor(), 0)));
con's avatar
con committed
1074
1075
1076
1077
1078
    return false;
}

bool Parser::parseAsmDefinition(DeclarationAST *&node)
{
Roberto Raggi's avatar
Roberto Raggi committed
1079
    DEBUG_THIS_RULE();
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
    if (LA() != T_ASM)
        return false;

    AsmDefinitionAST *ast = new (_pool) AsmDefinitionAST;
    ast->asm_token = consumeToken();

    if (LA() == T_VOLATILE)
        ast->volatile_token = consumeToken();

    match(T_LPAREN, &ast->lparen_token);
    unsigned string_literal_token = 0;
    match(T_STRING_LITERAL, &string_literal_token);
    while (LA() == T_STRING_LITERAL) {
        consumeToken();
    }
    if (LA() == T_COLON) {
        consumeToken(); // skip T_COLON
        parseAsmOperandList();
        if (LA() == T_COLON) {
            consumeToken();
            parseAsmOperandList();
            if (LA() == T_COLON) {
                consumeToken();
                parseAsmClobberList();
            }
        } else if (LA() == T_COLON_COLON) {
            consumeToken();
            parseAsmClobberList();
        }
    } else if (LA() == T_COLON_COLON) {
        consumeToken();
1111
        parseAsmOperandList();
1112

1113
1114
1115
1116
        if (LA() == T_COLON) {
          consumeToken();
          parseAsmClobberList();
        }
1117
1118
1119
1120
1121
1122
1123
1124
1125
    }
    match(T_RPAREN, &ast->rparen_token);
    match(T_SEMICOLON, &ast->semicolon_token);
    node = ast;
    return true;
}

bool Parser::parseAsmOperandList()
{
Roberto Raggi's avatar
Roberto Raggi committed
1126
    DEBUG_THIS_RULE();
1127
1128
1129
    if (LA() != T_STRING_LITERAL)
        return true;

1130
1131
1132
1133
    if (parseAsmOperand()) {
        while (LA() == T_COMMA) {
            consumeToken();
            parseAsmOperand();
con's avatar
con committed
1134
1135
1136
        }
        return true;
    }
1137

con's avatar
con committed
1138
1139
1140
    return false;
}

1141
1142
bool Parser::parseAsmOperand()
{
Roberto Raggi's avatar
Roberto Raggi committed
1143
    DEBUG_THIS_RULE();
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
    unsigned string_literal_token = 0;
    match(T_STRING_LITERAL, &string_literal_token);

    if (LA() == T_LBRACKET) {
        /*unsigned lbracket_token = */ consumeToken();
        match(T_STRING_LITERAL, &string_literal_token);
        unsigned rbracket_token = 0;
        match(T_RBRACKET, &rbracket_token);
    }

    unsigned lparen_token = 0, rparen_token = 0;
    match(T_LPAREN, &lparen_token);
    ExpressionAST *expression = 0;
    parseExpression(expression);
    match(T_RPAREN, &rparen_token);
    return true;
}

bool Parser::parseAsmClobberList()
{
Roberto Raggi's avatar
Roberto Raggi committed
1164
    DEBUG_THIS_RULE();
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
    if (LA() != T_STRING_LITERAL)
        return false;

    unsigned string_literal_token = consumeToken();

    while (LA() == T_COMMA) {
        consumeToken();
        match(T_STRING_LITERAL, &string_literal_token);
    }

    return true;
}

con's avatar
con committed
1178
1179
bool Parser::parseTemplateDeclaration(DeclarationAST *&node)
{
Roberto Raggi's avatar
Roberto Raggi committed
1180
    DEBUG_THIS_RULE();
con's avatar
con committed
1181
1182
1183
1184
1185
1186
    if (! (LA(1) == T_TEMPLATE || ((LA(1) == T_EXPORT || LA(1) == T_EXTERN)
            && LA(2) == T_TEMPLATE)))
        return false;

    TemplateDeclarationAST *ast = new (_pool) TemplateDeclarationAST;

1187
    if (LA() == T_EXPORT || LA() == T_EXTERN)
con's avatar
con committed
1188
1189
1190
1191
1192
1193
        ast->export_token = consumeToken();

    ast->template_token = consumeToken();

    if (LA() == T_LESS) {
        ast->less_token = consumeToken();
1194
        if (maybeSplitGreaterGreaterToken() || LA() == T_GREATER || parseTemplateParameterList(ast->template_parameter_list))
con's avatar
con committed
1195
1196
1197
            match(T_GREATER, &ast->greater_token);
    }

1198
    while (LA()) {
1199
1200
1201
1202
1203
1204
        unsigned start_declaration = cursor();

        ast->declaration = 0;
        if (parseDeclaration(ast->declaration))
            break;

1205
        error(start_declaration, "expected a declaration");
1206
1207
        rewind(start_declaration + 1);
        skipUntilDeclaration();
1208
    }
1209

con's avatar
con committed
1210
1211
1212
1213
1214
1215
    node = ast;
    return true;
}

bool Parser::parseOperator(OperatorAST *&node) // ### FIXME
{
Roberto Raggi's avatar
Roberto Raggi committed
1216
    DEBUG_THIS_RULE();
con's avatar
con committed
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
    OperatorAST *ast = new (_pool) OperatorAST;

    switch (LA()) {
    case T_NEW:
    case T_DELETE: {
        ast->op_token = consumeToken();
        if (LA() == T_LBRACKET) {
            ast->open_token = consumeToken();
            match(T_RBRACKET, &ast->close_token);
        }
    } break;

    case T_PLUS:
    case T_MINUS:
    case T_STAR:
    case T_SLASH:
    case T_PERCENT:
    case T_CARET:
    case T_AMPER:
    case T_PIPE:
    case T_TILDE:
    case T_EXCLAIM:
    case T_LESS:
    case T_GREATER:
    case T_COMMA:
    case T_AMPER_EQUAL:
    case T_CARET_EQUAL:
    case T_SLASH_EQUAL:
    case T_EQUAL:
    case T_EQUAL_EQUAL:
    case T_EXCLAIM_EQUAL:
    case T_GREATER_EQUAL:
    case T_GREATER_GREATER_EQUAL:
    case T_LESS_EQUAL:
    case T_LESS_LESS_EQUAL:
    case T_MINUS_EQUAL:
    case T_PERCENT_EQUAL:
    case T_PIPE_EQUAL:
    case T_PLUS_EQUAL:
    case T_STAR_EQUAL:
    case T_TILDE_EQUAL:
    case T_LESS_LESS:
    case T_GREATER_GREATER:
    case T_AMPER_AMPER:
    case T_PIPE_PIPE:
    case T_PLUS_PLUS:
    case T_MINUS_MINUS:
    case T_ARROW_STAR:
    case T_DOT_STAR:
    case T_ARROW:
        ast->op_token = consumeToken();
        break;

    default:
        if (LA() == T_LPAREN && LA(2) == T_RPAREN) {
            ast->op_token = ast->open_token = consumeToken();
            ast->close_token = consumeToken();
        } else if (LA() == T_LBRACKET && LA(2) == T_RBRACKET) {
            ast->op_token = ast->open_token = consumeToken();
            ast->close_token = consumeToken();
1277
1278
1279
1280
1281
1282
1283
1284
        } else if (_languageFeatures.cxx11Enabled &&
                   LA() == T_STRING_LITERAL && LA(2) == T_IDENTIFIER &&
                   !tok().f.userDefinedLiteral && tok().string->size() == 0 &&
                   tok(2).identifier->size() > 1 && tok(2).identifier->chars()[0] == '_') {
            // C++11 user-defined literal operator, e.g.:
            // int operator"" _abc123(const char *str, size_t size) { ... }
            ast->op_token = consumeToken();
            consumeToken(); // consume literal operator identifier
con's avatar
con committed
1285
1286
1287
1288
1289
1290
1291
1292
1293
        } else {
            return false;
        }
    }

    node = ast;
    return true;
}

Roberto Raggi's avatar
Roberto Raggi committed
1294
bool Parser::parseCvQualifiers(SpecifierListAST *&node)
con's avatar
con committed
1295
{
Roberto Raggi's avatar
Roberto Raggi committed
1296