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.
7
#include "DirectiveParser.h"
13
#include "Diagnostics.h"
14
#include "DirectiveHandler.h"
15
#include "ExpressionParser.h"
16
#include "MacroExpander.h"
18
#include "Tokenizer.h"
40
static DirectiveType getDirective(const pp::Token* token)
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");
56
if (token->type != pp::Token::IDENTIFIER)
57
return DIRECTIVE_NONE;
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)
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;
86
return DIRECTIVE_NONE;
89
static bool isConditionalDirective(DirectiveType directive)
95
case DIRECTIVE_IFNDEF:
105
// Returns true if the token represents End Of Directive.
106
static bool isEOD(const pp::Token* token)
108
return (token->type == '\n') || (token->type == pp::Token::LAST);
111
static void skipUntilEOD(pp::Lexer* lexer, pp::Token* token)
119
static bool isMacroNameReserved(const std::string& name)
121
// Names prefixed with "GL_" are reserved.
122
if (name.substr(0, 3) == "GL_")
125
// Names containing two consecutive underscores are reserved.
126
if (name.find("__") != std::string::npos)
132
static bool isMacroPredefined(const std::string& name,
133
const pp::MacroSet& macroSet)
135
pp::MacroSet::const_iterator iter = macroSet.find(name);
136
return iter != macroSet.end() ? iter->second.predefined : false;
142
class DefinedParser : public Lexer
145
DefinedParser(Lexer* lexer,
146
const MacroSet* macroSet,
147
Diagnostics* diagnostics) :
150
mDiagnostics(diagnostics)
155
virtual void lex(Token* token)
157
static const std::string kDefined("defined");
160
if (token->type != Token::IDENTIFIER)
162
if (token->value != kDefined)
167
if (token->type == '(')
173
if (token->type != Token::IDENTIFIER)
175
mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
176
token->location, token->value);
177
skipUntilEOD(mLexer, token);
180
MacroSet::const_iterator iter = mMacroSet->find(token->value);
181
std::string expression = iter != mMacroSet->end() ? "1" : "0";
186
if (token->type != ')')
188
mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
189
token->location, token->value);
190
skipUntilEOD(mLexer, token);
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;
203
const MacroSet* mMacroSet;
204
Diagnostics* mDiagnostics;
207
DirectiveParser::DirectiveParser(Tokenizer* tokenizer,
209
Diagnostics* diagnostics,
210
DirectiveHandler* directiveHandler) :
211
mTokenizer(tokenizer),
213
mDiagnostics(diagnostics),
214
mDirectiveHandler(directiveHandler)
218
void DirectiveParser::lex(Token* token)
222
mTokenizer->lex(token);
224
if (token->type == Token::PP_HASH)
226
parseDirective(token);
229
if (token->type == Token::LAST)
231
if (!mConditionalStack.empty())
233
const ConditionalBlock& block = mConditionalStack.back();
234
mDiagnostics->report(Diagnostics::CONDITIONAL_UNTERMINATED,
235
block.location, block.type);
240
} while (skipping() || (token->type == '\n'));
243
void DirectiveParser::parseDirective(Token* token)
245
assert(token->type == Token::PP_HASH);
247
mTokenizer->lex(token);
248
DirectiveType directive = getDirective(token);
250
// While in an excluded conditional block/group,
251
// we only parse conditional directives.
252
if (skipping() && !isConditionalDirective(directive))
254
skipUntilEOD(mTokenizer, token);
261
mDiagnostics->report(Diagnostics::DIRECTIVE_INVALID_NAME,
262
token->location, token->value);
263
skipUntilEOD(mTokenizer, token);
265
case DIRECTIVE_DEFINE:
268
case DIRECTIVE_UNDEF:
274
case DIRECTIVE_IFDEF:
277
case DIRECTIVE_IFNDEF:
286
case DIRECTIVE_ENDIF:
289
case DIRECTIVE_ERROR:
292
case DIRECTIVE_PRAGMA:
295
case DIRECTIVE_EXTENSION:
296
parseExtension(token);
298
case DIRECTIVE_VERSION:
309
skipUntilEOD(mTokenizer, token);
310
if (token->type == Token::LAST)
312
mDiagnostics->report(Diagnostics::EOF_IN_DIRECTIVE,
313
token->location, token->value);
317
void DirectiveParser::parseDefine(Token* token)
319
assert(getDirective(token) == DIRECTIVE_DEFINE);
321
mTokenizer->lex(token);
322
if (token->type != Token::IDENTIFIER)
324
mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
325
token->location, token->value);
328
if (isMacroPredefined(token->value, *mMacroSet))
330
mDiagnostics->report(Diagnostics::MACRO_PREDEFINED_REDEFINED,
331
token->location, token->value);
334
if (isMacroNameReserved(token->value))
336
mDiagnostics->report(Diagnostics::MACRO_NAME_RESERVED,
337
token->location, token->value);
342
macro.type = Macro::kTypeObj;
343
macro.name = token->value;
345
mTokenizer->lex(token);
346
if (token->type == '(' && !token->hasLeadingSpace())
348
// Function-like macro. Collect arguments.
349
macro.type = Macro::kTypeFunc;
351
mTokenizer->lex(token);
352
if (token->type != Token::IDENTIFIER)
354
macro.parameters.push_back(token->value);
356
mTokenizer->lex(token); // Get ','.
357
} while (token->type == ',');
359
if (token->type != ')')
361
mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
366
mTokenizer->lex(token); // Get ')'.
369
while ((token->type != '\n') && (token->type != Token::LAST))
371
// Reset the token location because it is unnecessary in replacement
372
// list. Resetting it also allows us to reuse Token::equals() to
374
token->location = SourceLocation();
375
macro.replacements.push_back(*token);
376
mTokenizer->lex(token);
378
if (!macro.replacements.empty())
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);
385
// Check for macro redefinition.
386
MacroSet::const_iterator iter = mMacroSet->find(macro.name);
387
if (iter != mMacroSet->end() && !macro.equals(iter->second))
389
mDiagnostics->report(Diagnostics::MACRO_REDEFINED,
394
mMacroSet->insert(std::make_pair(macro.name, macro));
397
void DirectiveParser::parseUndef(Token* token)
399
assert(getDirective(token) == DIRECTIVE_UNDEF);
401
mTokenizer->lex(token);
402
if (token->type != Token::IDENTIFIER)
404
mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
405
token->location, token->value);
409
MacroSet::iterator iter = mMacroSet->find(token->value);
410
if (iter != mMacroSet->end())
412
if (iter->second.predefined)
414
mDiagnostics->report(Diagnostics::MACRO_PREDEFINED_UNDEFINED,
415
token->location, token->value);
419
mMacroSet->erase(iter);
423
mTokenizer->lex(token);
426
void DirectiveParser::parseIf(Token* token)
428
assert(getDirective(token) == DIRECTIVE_IF);
429
parseConditionalIf(token);
432
void DirectiveParser::parseIfdef(Token* token)
434
assert(getDirective(token) == DIRECTIVE_IFDEF);
435
parseConditionalIf(token);
438
void DirectiveParser::parseIfndef(Token* token)
440
assert(getDirective(token) == DIRECTIVE_IFNDEF);
441
parseConditionalIf(token);
444
void DirectiveParser::parseElse(Token* token)
446
assert(getDirective(token) == DIRECTIVE_ELSE);
448
if (mConditionalStack.empty())
450
mDiagnostics->report(Diagnostics::CONDITIONAL_ELSE_WITHOUT_IF,
451
token->location, token->value);
452
skipUntilEOD(mTokenizer, token);
456
ConditionalBlock& block = mConditionalStack.back();
459
// No diagnostics. Just skip the whole line.
460
skipUntilEOD(mTokenizer, token);
463
if (block.foundElseGroup)
465
mDiagnostics->report(Diagnostics::CONDITIONAL_ELSE_AFTER_ELSE,
466
token->location, token->value);
467
skipUntilEOD(mTokenizer, token);
471
block.foundElseGroup = true;
472
block.skipGroup = block.foundValidGroup;
473
block.foundValidGroup = true;
475
// Warn if there are extra tokens after #else.
476
mTokenizer->lex(token);
479
mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,
480
token->location, token->value);
481
skipUntilEOD(mTokenizer, token);
485
void DirectiveParser::parseElif(Token* token)
487
assert(getDirective(token) == DIRECTIVE_ELIF);
489
if (mConditionalStack.empty())
491
mDiagnostics->report(Diagnostics::CONDITIONAL_ELIF_WITHOUT_IF,
492
token->location, token->value);
493
skipUntilEOD(mTokenizer, token);
497
ConditionalBlock& block = mConditionalStack.back();
500
// No diagnostics. Just skip the whole line.
501
skipUntilEOD(mTokenizer, token);
504
if (block.foundElseGroup)
506
mDiagnostics->report(Diagnostics::CONDITIONAL_ELIF_AFTER_ELSE,
507
token->location, token->value);
508
skipUntilEOD(mTokenizer, token);
511
if (block.foundValidGroup)
513
// Do not parse the expression.
514
// Also be careful not to emit a diagnostic.
515
block.skipGroup = true;
516
skipUntilEOD(mTokenizer, token);
520
int expression = parseExpressionIf(token);
521
block.skipGroup = expression == 0;
522
block.foundValidGroup = expression != 0;
525
void DirectiveParser::parseEndif(Token* token)
527
assert(getDirective(token) == DIRECTIVE_ENDIF);
529
if (mConditionalStack.empty())
531
mDiagnostics->report(Diagnostics::CONDITIONAL_ENDIF_WITHOUT_IF,
532
token->location, token->value);
533
skipUntilEOD(mTokenizer, token);
537
mConditionalStack.pop_back();
539
// Warn if there are tokens after #endif.
540
mTokenizer->lex(token);
543
mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,
544
token->location, token->value);
545
skipUntilEOD(mTokenizer, token);
549
void DirectiveParser::parseError(Token* token)
551
assert(getDirective(token) == DIRECTIVE_ERROR);
553
std::stringstream stream;
554
mTokenizer->lex(token);
555
while ((token->type != '\n') && (token->type != Token::LAST))
558
mTokenizer->lex(token);
560
mDirectiveHandler->handleError(token->location, stream.str());
563
// Parses pragma of form: #pragma name[(value)].
564
void DirectiveParser::parsePragma(Token* token)
566
assert(getDirective(token) == DIRECTIVE_PRAGMA);
577
std::string name, value;
578
int state = PRAGMA_NAME;
580
mTokenizer->lex(token);
581
while ((token->type != '\n') && (token->type != Token::LAST))
587
valid = valid && (token->type == Token::IDENTIFIER);
590
valid = valid && (token->type == '(');
593
value = token->value;
594
valid = valid && (token->type == Token::IDENTIFIER);
597
valid = valid && (token->type == ')');
603
mTokenizer->lex(token);
606
valid = valid && ((state == PRAGMA_NAME) || // Empty pragma.
607
(state == LEFT_PAREN) || // Without value.
608
(state == RIGHT_PAREN + 1)); // With value.
611
mDiagnostics->report(Diagnostics::UNRECOGNIZED_PRAGMA,
612
token->location, name);
614
else if (state > PRAGMA_NAME) // Do not notify for empty pragma.
616
mDirectiveHandler->handlePragma(token->location, name, value);
620
void DirectiveParser::parseExtension(Token* token)
622
assert(getDirective(token) == DIRECTIVE_EXTENSION);
632
std::string name, behavior;
633
int state = EXT_NAME;
635
mTokenizer->lex(token);
636
while ((token->type != '\n') && (token->type != Token::LAST))
641
if (valid && (token->type != Token::IDENTIFIER))
643
mDiagnostics->report(Diagnostics::INVALID_EXTENSION_NAME,
644
token->location, token->value);
647
if (valid) name = token->value;
650
if (valid && (token->type != ':'))
652
mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
653
token->location, token->value);
658
if (valid && (token->type != Token::IDENTIFIER))
660
mDiagnostics->report(Diagnostics::INVALID_EXTENSION_BEHAVIOR,
661
token->location, token->value);
664
if (valid) behavior = token->value;
669
mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
670
token->location, token->value);
675
mTokenizer->lex(token);
677
if (valid && (state != EXT_BEHAVIOR + 1))
679
mDiagnostics->report(Diagnostics::INVALID_EXTENSION_DIRECTIVE,
680
token->location, token->value);
684
mDirectiveHandler->handleExtension(token->location, name, behavior);
687
void DirectiveParser::parseVersion(Token* token)
689
assert(getDirective(token) == DIRECTIVE_VERSION);
698
int state = VERSION_NUMBER;
700
mTokenizer->lex(token);
701
while ((token->type != '\n') && (token->type != Token::LAST))
706
if (valid && (token->type != Token::CONST_INT))
708
mDiagnostics->report(Diagnostics::INVALID_VERSION_NUMBER,
709
token->location, token->value);
712
if (valid) version = atoi(token->value.c_str());
717
mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
718
token->location, token->value);
723
mTokenizer->lex(token);
725
if (valid && (state != VERSION_NUMBER + 1))
727
mDiagnostics->report(Diagnostics::INVALID_VERSION_DIRECTIVE,
728
token->location, token->value);
732
mDirectiveHandler->handleVersion(token->location, version);
735
void DirectiveParser::parseLine(Token* token)
737
assert(getDirective(token) == DIRECTIVE_LINE);
746
int line = 0, file = 0;
747
int state = LINE_NUMBER;
749
MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics);
750
macroExpander.lex(token);
751
while ((token->type != '\n') && (token->type != Token::LAST))
756
if (valid && (token->type != Token::CONST_INT))
758
mDiagnostics->report(Diagnostics::INVALID_LINE_NUMBER,
759
token->location, token->value);
762
if (valid) line = atoi(token->value.c_str());
765
if (valid && (token->type != Token::CONST_INT))
767
mDiagnostics->report(Diagnostics::INVALID_FILE_NUMBER,
768
token->location, token->value);
771
if (valid) file = atoi(token->value.c_str());
776
mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
777
token->location, token->value);
782
macroExpander.lex(token);
785
if (valid && (state != FILE_NUMBER) && (state != FILE_NUMBER + 1))
787
mDiagnostics->report(Diagnostics::INVALID_LINE_DIRECTIVE,
788
token->location, token->value);
793
mTokenizer->setLineNumber(line);
794
if (state == FILE_NUMBER + 1) mTokenizer->setFileNumber(file);
798
bool DirectiveParser::skipping() const
800
if (mConditionalStack.empty()) return false;
802
const ConditionalBlock& block = mConditionalStack.back();
803
return block.skipBlock || block.skipGroup;
806
void DirectiveParser::parseConditionalIf(Token* token)
808
ConditionalBlock block;
809
block.type = token->value;
810
block.location = token->location;
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;
823
DirectiveType directive = getDirective(token);
829
expression = parseExpressionIf(token);
831
case DIRECTIVE_IFDEF:
832
expression = parseExpressionIfdef(token);
834
case DIRECTIVE_IFNDEF:
835
expression = parseExpressionIfdef(token) == 0 ? 1 : 0;
841
block.skipGroup = expression == 0;
842
block.foundValidGroup = expression != 0;
844
mConditionalStack.push_back(block);
847
int DirectiveParser::parseExpressionIf(Token* token)
849
assert((getDirective(token) == DIRECTIVE_IF) ||
850
(getDirective(token) == DIRECTIVE_ELIF));
852
DefinedParser definedParser(mTokenizer, mMacroSet, mDiagnostics);
853
MacroExpander macroExpander(&definedParser, mMacroSet, mDiagnostics);
854
ExpressionParser expressionParser(¯oExpander, mDiagnostics);
857
macroExpander.lex(token);
858
expressionParser.parse(token, &expression);
860
// Warn if there are tokens after #if expression.
863
mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,
864
token->location, token->value);
865
skipUntilEOD(mTokenizer, token);
871
int DirectiveParser::parseExpressionIfdef(Token* token)
873
assert((getDirective(token) == DIRECTIVE_IFDEF) ||
874
(getDirective(token) == DIRECTIVE_IFNDEF));
876
mTokenizer->lex(token);
877
if (token->type != Token::IDENTIFIER)
879
mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
880
token->location, token->value);
881
skipUntilEOD(mTokenizer, token);
885
MacroSet::const_iterator iter = mMacroSet->find(token->value);
886
int expression = iter != mMacroSet->end() ? 1 : 0;
888
// Warn if there are tokens after #ifdef expression.
889
mTokenizer->lex(token);
892
mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,
893
token->location, token->value);
894
skipUntilEOD(mTokenizer, token);