blob: 9eb044ec024027302627dbe8b0105b4571dca4df [file] [log] [blame]
Nicolas Capens0bac2852016-05-07 06:09:58 -04001// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "DirectiveParser.h"
16
Alexis Hetue13238e2017-12-15 18:01:07 -050017#include <algorithm>
Nicolas Capens0bac2852016-05-07 06:09:58 -040018#include <cassert>
19#include <cstdlib>
20#include <sstream>
21
Alexis Hetue13238e2017-12-15 18:01:07 -050022#include "DiagnosticsBase.h"
23#include "DirectiveHandlerBase.h"
Nicolas Capens0bac2852016-05-07 06:09:58 -040024#include "ExpressionParser.h"
25#include "MacroExpander.h"
26#include "Token.h"
27#include "Tokenizer.h"
28
29namespace {
30enum DirectiveType
31{
32 DIRECTIVE_NONE,
33 DIRECTIVE_DEFINE,
34 DIRECTIVE_UNDEF,
35 DIRECTIVE_IF,
36 DIRECTIVE_IFDEF,
37 DIRECTIVE_IFNDEF,
38 DIRECTIVE_ELSE,
39 DIRECTIVE_ELIF,
40 DIRECTIVE_ENDIF,
41 DIRECTIVE_ERROR,
42 DIRECTIVE_PRAGMA,
43 DIRECTIVE_EXTENSION,
44 DIRECTIVE_VERSION,
45 DIRECTIVE_LINE
46};
47} // namespace
48
Alexis Hetue13238e2017-12-15 18:01:07 -050049static DirectiveType getDirective(const pp::Token *token)
Nicolas Capens0bac2852016-05-07 06:09:58 -040050{
51 static const std::string kDirectiveDefine("define");
52 static const std::string kDirectiveUndef("undef");
53 static const std::string kDirectiveIf("if");
54 static const std::string kDirectiveIfdef("ifdef");
55 static const std::string kDirectiveIfndef("ifndef");
56 static const std::string kDirectiveElse("else");
57 static const std::string kDirectiveElif("elif");
58 static const std::string kDirectiveEndif("endif");
59 static const std::string kDirectiveError("error");
60 static const std::string kDirectivePragma("pragma");
61 static const std::string kDirectiveExtension("extension");
62 static const std::string kDirectiveVersion("version");
63 static const std::string kDirectiveLine("line");
64
65 if (token->type != pp::Token::IDENTIFIER)
66 return DIRECTIVE_NONE;
67
68 if (token->text == kDirectiveDefine)
69 return DIRECTIVE_DEFINE;
70 else if (token->text == kDirectiveUndef)
71 return DIRECTIVE_UNDEF;
72 else if (token->text == kDirectiveIf)
73 return DIRECTIVE_IF;
74 else if (token->text == kDirectiveIfdef)
75 return DIRECTIVE_IFDEF;
76 else if (token->text == kDirectiveIfndef)
77 return DIRECTIVE_IFNDEF;
78 else if (token->text == kDirectiveElse)
79 return DIRECTIVE_ELSE;
80 else if (token->text == kDirectiveElif)
81 return DIRECTIVE_ELIF;
82 else if (token->text == kDirectiveEndif)
83 return DIRECTIVE_ENDIF;
84 else if (token->text == kDirectiveError)
85 return DIRECTIVE_ERROR;
86 else if (token->text == kDirectivePragma)
87 return DIRECTIVE_PRAGMA;
88 else if (token->text == kDirectiveExtension)
89 return DIRECTIVE_EXTENSION;
90 else if (token->text == kDirectiveVersion)
91 return DIRECTIVE_VERSION;
92 else if (token->text == kDirectiveLine)
93 return DIRECTIVE_LINE;
94
95 return DIRECTIVE_NONE;
96}
97
98static bool isConditionalDirective(DirectiveType directive)
99{
100 switch (directive)
101 {
102 case DIRECTIVE_IF:
103 case DIRECTIVE_IFDEF:
104 case DIRECTIVE_IFNDEF:
105 case DIRECTIVE_ELSE:
106 case DIRECTIVE_ELIF:
107 case DIRECTIVE_ENDIF:
108 return true;
109 default:
110 return false;
111 }
112}
113
114// Returns true if the token represents End Of Directive.
Alexis Hetue13238e2017-12-15 18:01:07 -0500115static bool isEOD(const pp::Token *token)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400116{
117 return (token->type == '\n') || (token->type == pp::Token::LAST);
118}
119
Alexis Hetue13238e2017-12-15 18:01:07 -0500120static void skipUntilEOD(pp::Lexer *lexer, pp::Token *token)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400121{
122 while(!isEOD(token))
123 {
124 lexer->lex(token);
125 }
126}
127
128static bool isMacroNameReserved(const std::string& name)
129{
130 // Names prefixed with "GL_" are reserved.
Alexis Hetue13238e2017-12-15 18:01:07 -0500131 return (name.substr(0, 3) == "GL_");
132}
Nicolas Capens0bac2852016-05-07 06:09:58 -0400133
Alexis Hetue13238e2017-12-15 18:01:07 -0500134bool hasDoubleUnderscores(const std::string &name)
135{
136 return (name.find("__") != std::string::npos);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400137}
138
139static bool isMacroPredefined(const std::string& name,
140 const pp::MacroSet& macroSet)
141{
142 pp::MacroSet::const_iterator iter = macroSet.find(name);
Alexis Hetue13238e2017-12-15 18:01:07 -0500143 return iter != macroSet.end() ? iter->second->predefined : false;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400144}
145
146namespace pp
147{
148
Alexis Hetue13238e2017-12-15 18:01:07 -0500149class DefinedParser : public Lexer
150{
151public:
152 DefinedParser(Lexer *lexer, const MacroSet *macroSet, Diagnostics *diagnostics)
153 : mLexer(lexer), mMacroSet(macroSet), mDiagnostics(diagnostics)
154 {
155 }
156
157protected:
158 void lex(Token *token) override
159 {
160 const char kDefined[] = "defined";
161
162 mLexer->lex(token);
163 if (token->type != Token::IDENTIFIER)
164 return;
165 if (token->text != kDefined)
166 return;
167
168 bool paren = false;
169 mLexer->lex(token);
170 if (token->type == '(')
171 {
172 paren = true;
173 mLexer->lex(token);
174 }
175
176 if (token->type != Token::IDENTIFIER)
177 {
178 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
179 skipUntilEOD(mLexer, token);
180 return;
181 }
182 MacroSet::const_iterator iter = mMacroSet->find(token->text);
183 std::string expression = iter != mMacroSet->end() ? "1" : "0";
184
185 if (paren)
186 {
187 mLexer->lex(token);
188 if (token->type != ')')
189 {
190 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
191 token->location, token->text);
192 skipUntilEOD(mLexer, token);
193 return;
194 }
195 }
196
197 // We have a valid defined operator.
198 // Convert the current token into a CONST_INT token.
199 token->type = Token::CONST_INT;
200 token->text = expression;
201 }
202
203private:
204 Lexer *mLexer;
205 const MacroSet *mMacroSet;
206 Diagnostics *mDiagnostics;
207};
208
209DirectiveParser::DirectiveParser(Tokenizer *tokenizer,
210 MacroSet *macroSet,
211 Diagnostics *diagnostics,
212 DirectiveHandler *directiveHandler,
213 int maxMacroExpansionDepth)
214 : mPastFirstStatement(false),
215 mSeenNonPreprocessorToken(false),
216 mTokenizer(tokenizer),
217 mMacroSet(macroSet),
218 mDiagnostics(diagnostics),
219 mDirectiveHandler(directiveHandler),
220 mShaderVersion(100),
221 mMaxMacroExpansionDepth(maxMacroExpansionDepth)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400222{
223}
224
Alexis Hetue13238e2017-12-15 18:01:07 -0500225DirectiveParser::~DirectiveParser()
226{
227}
228
229void DirectiveParser::lex(Token *token)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400230{
231 do
232 {
233 mTokenizer->lex(token);
234
235 if (token->type == Token::PP_HASH)
236 {
237 parseDirective(token);
238 mPastFirstStatement = true;
239 }
Alexis Hetue13238e2017-12-15 18:01:07 -0500240 else if (!isEOD(token))
241 {
242 mSeenNonPreprocessorToken = true;
243 }
Nicolas Capens0bac2852016-05-07 06:09:58 -0400244
245 if (token->type == Token::LAST)
246 {
247 if (!mConditionalStack.empty())
248 {
Alexis Hetue13238e2017-12-15 18:01:07 -0500249 const ConditionalBlock &block = mConditionalStack.back();
250 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNTERMINATED,
Nicolas Capens0bac2852016-05-07 06:09:58 -0400251 block.location, block.type);
252 }
253 break;
254 }
255
256 } while (skipping() || (token->type == '\n'));
257
258 mPastFirstStatement = true;
259}
260
Alexis Hetue13238e2017-12-15 18:01:07 -0500261void DirectiveParser::parseDirective(Token *token)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400262{
263 assert(token->type == Token::PP_HASH);
264
265 mTokenizer->lex(token);
266 if (isEOD(token))
267 {
268 // Empty Directive.
269 return;
270 }
271
272 DirectiveType directive = getDirective(token);
273
274 // While in an excluded conditional block/group,
275 // we only parse conditional directives.
276 if (skipping() && !isConditionalDirective(directive))
277 {
278 skipUntilEOD(mTokenizer, token);
279 return;
280 }
281
282 switch(directive)
283 {
284 case DIRECTIVE_NONE:
Alexis Hetue13238e2017-12-15 18:01:07 -0500285 mDiagnostics->report(Diagnostics::PP_DIRECTIVE_INVALID_NAME,
Nicolas Capens0bac2852016-05-07 06:09:58 -0400286 token->location, token->text);
287 skipUntilEOD(mTokenizer, token);
288 break;
289 case DIRECTIVE_DEFINE:
290 parseDefine(token);
291 break;
292 case DIRECTIVE_UNDEF:
293 parseUndef(token);
294 break;
295 case DIRECTIVE_IF:
296 parseIf(token);
297 break;
298 case DIRECTIVE_IFDEF:
299 parseIfdef(token);
300 break;
301 case DIRECTIVE_IFNDEF:
302 parseIfndef(token);
303 break;
304 case DIRECTIVE_ELSE:
305 parseElse(token);
306 break;
307 case DIRECTIVE_ELIF:
308 parseElif(token);
309 break;
310 case DIRECTIVE_ENDIF:
311 parseEndif(token);
312 break;
313 case DIRECTIVE_ERROR:
314 parseError(token);
315 break;
316 case DIRECTIVE_PRAGMA:
317 parsePragma(token);
318 break;
319 case DIRECTIVE_EXTENSION:
320 parseExtension(token);
321 break;
322 case DIRECTIVE_VERSION:
323 parseVersion(token);
324 break;
325 case DIRECTIVE_LINE:
326 parseLine(token);
327 break;
328 default:
329 assert(false);
330 break;
331 }
332
333 skipUntilEOD(mTokenizer, token);
334 if (token->type == Token::LAST)
335 {
Alexis Hetue13238e2017-12-15 18:01:07 -0500336 mDiagnostics->report(Diagnostics::PP_EOF_IN_DIRECTIVE,
Nicolas Capens0bac2852016-05-07 06:09:58 -0400337 token->location, token->text);
338 }
339}
340
Alexis Hetue13238e2017-12-15 18:01:07 -0500341void DirectiveParser::parseDefine(Token *token)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400342{
343 assert(getDirective(token) == DIRECTIVE_DEFINE);
344
345 mTokenizer->lex(token);
346 if (token->type != Token::IDENTIFIER)
347 {
Alexis Hetue13238e2017-12-15 18:01:07 -0500348 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
Nicolas Capens0bac2852016-05-07 06:09:58 -0400349 token->location, token->text);
350 return;
351 }
352 if (isMacroPredefined(token->text, *mMacroSet))
353 {
Alexis Hetue13238e2017-12-15 18:01:07 -0500354 mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_REDEFINED,
Nicolas Capens0bac2852016-05-07 06:09:58 -0400355 token->location, token->text);
356 return;
357 }
358 if (isMacroNameReserved(token->text))
359 {
Alexis Hetue13238e2017-12-15 18:01:07 -0500360 mDiagnostics->report(Diagnostics::PP_MACRO_NAME_RESERVED,
Nicolas Capens0bac2852016-05-07 06:09:58 -0400361 token->location, token->text);
362 return;
363 }
Alexis Hetue13238e2017-12-15 18:01:07 -0500364 // Using double underscores is allowed, but may result in unintended
365 // behavior, so a warning is issued. At the time of writing this was
366 // specified in ESSL 3.10, but the intent judging from Khronos
367 // discussions and dEQP tests was that double underscores should be
368 // allowed in earlier ESSL versions too.
369 if (hasDoubleUnderscores(token->text))
370 {
371 mDiagnostics->report(Diagnostics::PP_WARNING_MACRO_NAME_RESERVED, token->location,
372 token->text);
373 }
Nicolas Capens0bac2852016-05-07 06:09:58 -0400374
Alexis Hetue13238e2017-12-15 18:01:07 -0500375 std::shared_ptr<Macro> macro = std::make_shared<Macro>();
376 macro->type = Macro::kTypeObj;
377 macro->name = token->text;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400378
379 mTokenizer->lex(token);
380 if (token->type == '(' && !token->hasLeadingSpace())
381 {
382 // Function-like macro. Collect arguments.
Alexis Hetue13238e2017-12-15 18:01:07 -0500383 macro->type = Macro::kTypeFunc;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400384 do {
385 mTokenizer->lex(token);
386 if (token->type != Token::IDENTIFIER)
387 break;
388
Alexis Hetue13238e2017-12-15 18:01:07 -0500389 if (std::find(macro->parameters.begin(), macro->parameters.end(), token->text) != macro->parameters.end())
Nicolas Capens0bac2852016-05-07 06:09:58 -0400390 {
Alexis Hetue13238e2017-12-15 18:01:07 -0500391 mDiagnostics->report(Diagnostics::PP_MACRO_DUPLICATE_PARAMETER_NAMES,
Nicolas Capens0bac2852016-05-07 06:09:58 -0400392 token->location, token->text);
393 return;
394 }
395
Alexis Hetue13238e2017-12-15 18:01:07 -0500396 macro->parameters.push_back(token->text);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400397
398 mTokenizer->lex(token); // Get ','.
399 } while (token->type == ',');
400
401 if (token->type != ')')
402 {
Alexis Hetue13238e2017-12-15 18:01:07 -0500403 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
Nicolas Capens0bac2852016-05-07 06:09:58 -0400404 token->location,
405 token->text);
406 return;
407 }
408 mTokenizer->lex(token); // Get ')'.
409 }
410
411 while ((token->type != '\n') && (token->type != Token::LAST))
412 {
413 // Reset the token location because it is unnecessary in replacement
414 // list. Resetting it also allows us to reuse Token::equals() to
415 // compare macros.
416 token->location = SourceLocation();
Alexis Hetue13238e2017-12-15 18:01:07 -0500417 macro->replacements.push_back(*token);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400418 mTokenizer->lex(token);
419 }
Alexis Hetue13238e2017-12-15 18:01:07 -0500420 if (!macro->replacements.empty())
Nicolas Capens0bac2852016-05-07 06:09:58 -0400421 {
422 // Whitespace preceding the replacement list is not considered part of
423 // the replacement list for either form of macro.
Alexis Hetue13238e2017-12-15 18:01:07 -0500424 macro->replacements.front().setHasLeadingSpace(false);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400425 }
426
427 // Check for macro redefinition.
Alexis Hetue13238e2017-12-15 18:01:07 -0500428 MacroSet::const_iterator iter = mMacroSet->find(macro->name);
429 if (iter != mMacroSet->end() && !macro->equals(*iter->second))
Nicolas Capens0bac2852016-05-07 06:09:58 -0400430 {
Alexis Hetue13238e2017-12-15 18:01:07 -0500431 mDiagnostics->report(Diagnostics::PP_MACRO_REDEFINED, token->location, macro->name);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400432 return;
433 }
Alexis Hetue13238e2017-12-15 18:01:07 -0500434 mMacroSet->insert(std::make_pair(macro->name, macro));
Nicolas Capens0bac2852016-05-07 06:09:58 -0400435}
436
Alexis Hetue13238e2017-12-15 18:01:07 -0500437void DirectiveParser::parseUndef(Token *token)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400438{
439 assert(getDirective(token) == DIRECTIVE_UNDEF);
440
441 mTokenizer->lex(token);
442 if (token->type != Token::IDENTIFIER)
443 {
Alexis Hetue13238e2017-12-15 18:01:07 -0500444 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
Nicolas Capens0bac2852016-05-07 06:09:58 -0400445 token->location, token->text);
446 return;
447 }
448
449 MacroSet::iterator iter = mMacroSet->find(token->text);
450 if (iter != mMacroSet->end())
451 {
Alexis Hetue13238e2017-12-15 18:01:07 -0500452 if (iter->second->predefined)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400453 {
Alexis Hetue13238e2017-12-15 18:01:07 -0500454 mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_UNDEFINED,
Nicolas Capens0bac2852016-05-07 06:09:58 -0400455 token->location, token->text);
Alexis Hetue13238e2017-12-15 18:01:07 -0500456 return;
457 }
458 else if (iter->second->expansionCount > 0)
459 {
460 mDiagnostics->report(Diagnostics::PP_MACRO_UNDEFINED_WHILE_INVOKED,
461 token->location, token->text);
462 return;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400463 }
464 else
465 {
466 mMacroSet->erase(iter);
467 }
468 }
469
470 mTokenizer->lex(token);
Alexis Hetue13238e2017-12-15 18:01:07 -0500471 if (!isEOD(token))
472 {
473 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
474 skipUntilEOD(mTokenizer, token);
475 }
Nicolas Capens0bac2852016-05-07 06:09:58 -0400476}
477
Alexis Hetue13238e2017-12-15 18:01:07 -0500478void DirectiveParser::parseIf(Token *token)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400479{
480 assert(getDirective(token) == DIRECTIVE_IF);
481 parseConditionalIf(token);
482}
483
Alexis Hetue13238e2017-12-15 18:01:07 -0500484void DirectiveParser::parseIfdef(Token *token)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400485{
486 assert(getDirective(token) == DIRECTIVE_IFDEF);
487 parseConditionalIf(token);
488}
489
Alexis Hetue13238e2017-12-15 18:01:07 -0500490void DirectiveParser::parseIfndef(Token *token)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400491{
492 assert(getDirective(token) == DIRECTIVE_IFNDEF);
493 parseConditionalIf(token);
494}
495
Alexis Hetue13238e2017-12-15 18:01:07 -0500496void DirectiveParser::parseElse(Token *token)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400497{
498 assert(getDirective(token) == DIRECTIVE_ELSE);
499
500 if (mConditionalStack.empty())
501 {
Alexis Hetue13238e2017-12-15 18:01:07 -0500502 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_WITHOUT_IF,
Nicolas Capens0bac2852016-05-07 06:09:58 -0400503 token->location, token->text);
504 skipUntilEOD(mTokenizer, token);
505 return;
506 }
507
Alexis Hetue13238e2017-12-15 18:01:07 -0500508 ConditionalBlock &block = mConditionalStack.back();
Nicolas Capens0bac2852016-05-07 06:09:58 -0400509 if (block.skipBlock)
510 {
511 // No diagnostics. Just skip the whole line.
512 skipUntilEOD(mTokenizer, token);
513 return;
514 }
515 if (block.foundElseGroup)
516 {
Alexis Hetue13238e2017-12-15 18:01:07 -0500517 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_AFTER_ELSE,
Nicolas Capens0bac2852016-05-07 06:09:58 -0400518 token->location, token->text);
519 skipUntilEOD(mTokenizer, token);
520 return;
521 }
522
523 block.foundElseGroup = true;
524 block.skipGroup = block.foundValidGroup;
525 block.foundValidGroup = true;
526
527 // Check if there are extra tokens after #else.
528 mTokenizer->lex(token);
529 if (!isEOD(token))
530 {
Alexis Hetue13238e2017-12-15 18:01:07 -0500531 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
Nicolas Capens0bac2852016-05-07 06:09:58 -0400532 token->location, token->text);
533 skipUntilEOD(mTokenizer, token);
534 }
535}
536
Alexis Hetue13238e2017-12-15 18:01:07 -0500537void DirectiveParser::parseElif(Token *token)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400538{
539 assert(getDirective(token) == DIRECTIVE_ELIF);
540
541 if (mConditionalStack.empty())
542 {
Alexis Hetue13238e2017-12-15 18:01:07 -0500543 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_WITHOUT_IF,
Nicolas Capens0bac2852016-05-07 06:09:58 -0400544 token->location, token->text);
545 skipUntilEOD(mTokenizer, token);
546 return;
547 }
548
Alexis Hetue13238e2017-12-15 18:01:07 -0500549 ConditionalBlock &block = mConditionalStack.back();
Nicolas Capens0bac2852016-05-07 06:09:58 -0400550 if (block.skipBlock)
551 {
552 // No diagnostics. Just skip the whole line.
553 skipUntilEOD(mTokenizer, token);
554 return;
555 }
556 if (block.foundElseGroup)
557 {
Alexis Hetue13238e2017-12-15 18:01:07 -0500558 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_AFTER_ELSE,
Nicolas Capens0bac2852016-05-07 06:09:58 -0400559 token->location, token->text);
560 skipUntilEOD(mTokenizer, token);
561 return;
562 }
563 if (block.foundValidGroup)
564 {
565 // Do not parse the expression.
566 // Also be careful not to emit a diagnostic.
567 block.skipGroup = true;
568 skipUntilEOD(mTokenizer, token);
569 return;
570 }
571
572 int expression = parseExpressionIf(token);
573 block.skipGroup = expression == 0;
574 block.foundValidGroup = expression != 0;
575}
576
Alexis Hetue13238e2017-12-15 18:01:07 -0500577void DirectiveParser::parseEndif(Token *token)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400578{
579 assert(getDirective(token) == DIRECTIVE_ENDIF);
580
581 if (mConditionalStack.empty())
582 {
Alexis Hetue13238e2017-12-15 18:01:07 -0500583 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ENDIF_WITHOUT_IF,
Nicolas Capens0bac2852016-05-07 06:09:58 -0400584 token->location, token->text);
585 skipUntilEOD(mTokenizer, token);
586 return;
587 }
588
589 mConditionalStack.pop_back();
590
591 // Check if there are tokens after #endif.
592 mTokenizer->lex(token);
593 if (!isEOD(token))
594 {
Alexis Hetue13238e2017-12-15 18:01:07 -0500595 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
Nicolas Capens0bac2852016-05-07 06:09:58 -0400596 token->location, token->text);
597 skipUntilEOD(mTokenizer, token);
598 }
599}
600
Alexis Hetue13238e2017-12-15 18:01:07 -0500601void DirectiveParser::parseError(Token *token)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400602{
603 assert(getDirective(token) == DIRECTIVE_ERROR);
604
605 std::ostringstream stream;
606 mTokenizer->lex(token);
607 while ((token->type != '\n') && (token->type != Token::LAST))
608 {
609 stream << *token;
610 mTokenizer->lex(token);
611 }
612 mDirectiveHandler->handleError(token->location, stream.str());
613}
614
615// Parses pragma of form: #pragma name[(value)].
Alexis Hetue13238e2017-12-15 18:01:07 -0500616void DirectiveParser::parsePragma(Token *token)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400617{
618 assert(getDirective(token) == DIRECTIVE_PRAGMA);
619
620 enum State
621 {
622 PRAGMA_NAME,
623 LEFT_PAREN,
624 PRAGMA_VALUE,
625 RIGHT_PAREN
626 };
627
628 bool valid = true;
629 std::string name, value;
630 int state = PRAGMA_NAME;
631
632 mTokenizer->lex(token);
Alexis Hetue13238e2017-12-15 18:01:07 -0500633 bool stdgl = token->text == "STDGL";
634 if (stdgl)
635 {
636 mTokenizer->lex(token);
637 }
Nicolas Capens0bac2852016-05-07 06:09:58 -0400638 while ((token->type != '\n') && (token->type != Token::LAST))
639 {
640 switch(state++)
641 {
642 case PRAGMA_NAME:
643 name = token->text;
644 valid = valid && (token->type == Token::IDENTIFIER);
645 break;
646 case LEFT_PAREN:
647 valid = valid && (token->type == '(');
648 break;
649 case PRAGMA_VALUE:
650 value = token->text;
651 valid = valid && (token->type == Token::IDENTIFIER);
652 break;
653 case RIGHT_PAREN:
654 valid = valid && (token->type == ')');
655 break;
656 default:
657 valid = false;
658 break;
659 }
660 mTokenizer->lex(token);
661 }
662
663 valid = valid && ((state == PRAGMA_NAME) || // Empty pragma.
664 (state == LEFT_PAREN) || // Without value.
665 (state == RIGHT_PAREN + 1)); // With value.
666 if (!valid)
667 {
Alexis Hetue13238e2017-12-15 18:01:07 -0500668 mDiagnostics->report(Diagnostics::PP_UNRECOGNIZED_PRAGMA, token->location, name);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400669 }
670 else if (state > PRAGMA_NAME) // Do not notify for empty pragma.
671 {
Alexis Hetue13238e2017-12-15 18:01:07 -0500672 mDirectiveHandler->handlePragma(token->location, name, value, stdgl);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400673 }
674}
675
Alexis Hetue13238e2017-12-15 18:01:07 -0500676void DirectiveParser::parseExtension(Token *token)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400677{
678 assert(getDirective(token) == DIRECTIVE_EXTENSION);
679
680 enum State
681 {
682 EXT_NAME,
683 COLON,
684 EXT_BEHAVIOR
685 };
686
687 bool valid = true;
688 std::string name, behavior;
689 int state = EXT_NAME;
690
691 mTokenizer->lex(token);
692 while ((token->type != '\n') && (token->type != Token::LAST))
693 {
694 switch (state++)
695 {
Alexis Hetue13238e2017-12-15 18:01:07 -0500696 case EXT_NAME:
697 if (valid && (token->type != Token::IDENTIFIER))
698 {
699 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_NAME, token->location,
700 token->text);
701 valid = false;
702 }
703 if (valid)
704 name = token->text;
705 break;
706 case COLON:
707 if (valid && (token->type != ':'))
708 {
709 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
710 token->text);
711 valid = false;
712 }
713 break;
714 case EXT_BEHAVIOR:
715 if (valid && (token->type != Token::IDENTIFIER))
716 {
717 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_BEHAVIOR,
718 token->location, token->text);
719 valid = false;
720 }
721 if (valid)
722 behavior = token->text;
723 break;
724 default:
725 if (valid)
726 {
727 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
728 token->text);
729 valid = false;
730 }
731 break;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400732 }
733 mTokenizer->lex(token);
734 }
735 if (valid && (state != EXT_BEHAVIOR + 1))
736 {
Alexis Hetue13238e2017-12-15 18:01:07 -0500737 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_DIRECTIVE, token->location,
738 token->text);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400739 valid = false;
740 }
Alexis Hetue13238e2017-12-15 18:01:07 -0500741 if (valid && mSeenNonPreprocessorToken)
742 {
743 if (mShaderVersion >= 300)
744 {
745 mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL3,
746 token->location, token->text);
747 valid = false;
748 }
749 else
750 {
751 mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1,
752 token->location, token->text);
753 }
754 }
Nicolas Capens0bac2852016-05-07 06:09:58 -0400755 if (valid)
756 mDirectiveHandler->handleExtension(token->location, name, behavior);
757}
758
Alexis Hetue13238e2017-12-15 18:01:07 -0500759void DirectiveParser::parseVersion(Token *token)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400760{
761 assert(getDirective(token) == DIRECTIVE_VERSION);
762
763 if (mPastFirstStatement)
764 {
Alexis Hetue13238e2017-12-15 18:01:07 -0500765 mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_STATEMENT, token->location,
766 token->text);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400767 skipUntilEOD(mTokenizer, token);
768 return;
769 }
770
771 enum State
772 {
773 VERSION_NUMBER,
774 VERSION_PROFILE,
775 VERSION_ENDLINE
776 };
777
778 bool valid = true;
779 int version = 0;
780 int state = VERSION_NUMBER;
781
782 mTokenizer->lex(token);
783 while (valid && (token->type != '\n') && (token->type != Token::LAST))
784 {
785 switch (state)
786 {
787 case VERSION_NUMBER:
788 if (token->type != Token::CONST_INT)
789 {
Alexis Hetue13238e2017-12-15 18:01:07 -0500790 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_NUMBER,
Nicolas Capens0bac2852016-05-07 06:09:58 -0400791 token->location, token->text);
792 valid = false;
793 }
794 if (valid && !token->iValue(&version))
795 {
Alexis Hetue13238e2017-12-15 18:01:07 -0500796 mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW,
Nicolas Capens0bac2852016-05-07 06:09:58 -0400797 token->location, token->text);
798 valid = false;
799 }
800 if (valid)
801 {
802 state = (version < 300) ? VERSION_ENDLINE : VERSION_PROFILE;
803 }
804 break;
805 case VERSION_PROFILE:
806 if (token->type != Token::IDENTIFIER || token->text != "es")
807 {
Alexis Hetue13238e2017-12-15 18:01:07 -0500808 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE,
Nicolas Capens0bac2852016-05-07 06:09:58 -0400809 token->location, token->text);
810 valid = false;
811 }
812 state = VERSION_ENDLINE;
813 break;
814 default:
Alexis Hetue13238e2017-12-15 18:01:07 -0500815 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
Nicolas Capens0bac2852016-05-07 06:09:58 -0400816 token->location, token->text);
817 valid = false;
818 break;
819 }
820
821 mTokenizer->lex(token);
822 }
823
824 if (valid && (state != VERSION_ENDLINE))
825 {
Alexis Hetue13238e2017-12-15 18:01:07 -0500826 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE,
Nicolas Capens0bac2852016-05-07 06:09:58 -0400827 token->location, token->text);
828 valid = false;
829 }
830
Alexis Hetue13238e2017-12-15 18:01:07 -0500831 if (valid && version >= 300 && token->location.line > 1)
832 {
833 mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_LINE_ESSL3, token->location,
834 token->text);
835 valid = false;
836 }
837
Nicolas Capens0bac2852016-05-07 06:09:58 -0400838 if (valid)
839 {
840 mDirectiveHandler->handleVersion(token->location, version);
Alexis Hetue13238e2017-12-15 18:01:07 -0500841 mShaderVersion = version;
842 PredefineMacro(mMacroSet, "__VERSION__", version);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400843 }
844}
845
Alexis Hetue13238e2017-12-15 18:01:07 -0500846void DirectiveParser::parseLine(Token *token)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400847{
848 assert(getDirective(token) == DIRECTIVE_LINE);
849
Nicolas Capens0bac2852016-05-07 06:09:58 -0400850 bool valid = true;
Alexis Hetue13238e2017-12-15 18:01:07 -0500851 bool parsedFileNumber = false;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400852 int line = 0, file = 0;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400853
Alexis Hetue13238e2017-12-15 18:01:07 -0500854 MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, false, mMaxMacroExpansionDepth);
855
856 // Lex the first token after "#line" so we can check it for EOD.
Nicolas Capens0bac2852016-05-07 06:09:58 -0400857 macroExpander.lex(token);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400858
Alexis Hetue13238e2017-12-15 18:01:07 -0500859 if (isEOD(token))
Nicolas Capens0bac2852016-05-07 06:09:58 -0400860 {
Alexis Hetue13238e2017-12-15 18:01:07 -0500861 mDiagnostics->report(Diagnostics::PP_INVALID_LINE_DIRECTIVE, token->location, token->text);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400862 valid = false;
863 }
Alexis Hetue13238e2017-12-15 18:01:07 -0500864 else
865 {
866 ExpressionParser expressionParser(&macroExpander, mDiagnostics);
867 ExpressionParser::ErrorSettings errorSettings;
868
869 // See GLES3 section 12.42
870 errorSettings.integerLiteralsMustFit32BitSignedRange = true;
871
872 errorSettings.unexpectedIdentifier = Diagnostics::PP_INVALID_LINE_NUMBER;
873 // The first token was lexed earlier to check if it was EOD. Include
874 // the token in parsing for a second time by setting the
875 // parsePresetToken flag to true.
876 expressionParser.parse(token, &line, true, errorSettings, &valid);
877 if (!isEOD(token) && valid)
878 {
879 errorSettings.unexpectedIdentifier = Diagnostics::PP_INVALID_FILE_NUMBER;
880 // After parsing the line expression expressionParser has also
881 // advanced to the first token of the file expression - this is the
882 // token that makes the parser reduce the "input" rule for the line
883 // expression and stop. So we're using parsePresetToken = true here
884 // as well.
885 expressionParser.parse(token, &file, true, errorSettings, &valid);
886 parsedFileNumber = true;
887 }
888 if (!isEOD(token))
889 {
890 if (valid)
891 {
892 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
893 token->location, token->text);
894 valid = false;
895 }
896 skipUntilEOD(mTokenizer, token);
897 }
898 }
899
Nicolas Capens0bac2852016-05-07 06:09:58 -0400900 if (valid)
901 {
902 mTokenizer->setLineNumber(line);
Alexis Hetue13238e2017-12-15 18:01:07 -0500903 if (parsedFileNumber)
904 mTokenizer->setFileNumber(file);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400905 }
906}
907
908bool DirectiveParser::skipping() const
909{
Alexis Hetue13238e2017-12-15 18:01:07 -0500910 if (mConditionalStack.empty())
911 return false;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400912
Alexis Hetue13238e2017-12-15 18:01:07 -0500913 const ConditionalBlock &block = mConditionalStack.back();
Nicolas Capens0bac2852016-05-07 06:09:58 -0400914 return block.skipBlock || block.skipGroup;
915}
916
Alexis Hetue13238e2017-12-15 18:01:07 -0500917void DirectiveParser::parseConditionalIf(Token *token)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400918{
919 ConditionalBlock block;
920 block.type = token->text;
921 block.location = token->location;
922
923 if (skipping())
924 {
925 // This conditional block is inside another conditional group
926 // which is skipped. As a consequence this whole block is skipped.
927 // Be careful not to parse the conditional expression that might
928 // emit a diagnostic.
929 skipUntilEOD(mTokenizer, token);
930 block.skipBlock = true;
931 }
932 else
933 {
934 DirectiveType directive = getDirective(token);
935
936 int expression = 0;
937 switch (directive)
938 {
939 case DIRECTIVE_IF:
940 expression = parseExpressionIf(token);
941 break;
942 case DIRECTIVE_IFDEF:
943 expression = parseExpressionIfdef(token);
944 break;
945 case DIRECTIVE_IFNDEF:
946 expression = parseExpressionIfdef(token) == 0 ? 1 : 0;
947 break;
948 default:
949 assert(false);
950 break;
951 }
952 block.skipGroup = expression == 0;
953 block.foundValidGroup = expression != 0;
954 }
955 mConditionalStack.push_back(block);
956}
957
Alexis Hetue13238e2017-12-15 18:01:07 -0500958int DirectiveParser::parseExpressionIf(Token *token)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400959{
Alexis Hetue13238e2017-12-15 18:01:07 -0500960 assert((getDirective(token) == DIRECTIVE_IF) || (getDirective(token) == DIRECTIVE_ELIF));
Nicolas Capens0bac2852016-05-07 06:09:58 -0400961
Alexis Hetue13238e2017-12-15 18:01:07 -0500962 DefinedParser definedParser(mTokenizer, mMacroSet, mDiagnostics);
963 MacroExpander macroExpander(&definedParser, mMacroSet, mDiagnostics, true, mMaxMacroExpansionDepth);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400964 ExpressionParser expressionParser(&macroExpander, mDiagnostics);
965
966 int expression = 0;
Alexis Hetue13238e2017-12-15 18:01:07 -0500967 ExpressionParser::ErrorSettings errorSettings;
968 errorSettings.integerLiteralsMustFit32BitSignedRange = false;
969 errorSettings.unexpectedIdentifier = Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN;
970
971 bool valid = true;
972 expressionParser.parse(token, &expression, false, errorSettings, &valid);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400973
974 // Check if there are tokens after #if expression.
975 if (!isEOD(token))
976 {
Alexis Hetue13238e2017-12-15 18:01:07 -0500977 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
Nicolas Capens0bac2852016-05-07 06:09:58 -0400978 token->location, token->text);
979 skipUntilEOD(mTokenizer, token);
980 }
981
982 return expression;
983}
984
985int DirectiveParser::parseExpressionIfdef(Token* token)
986{
987 assert((getDirective(token) == DIRECTIVE_IFDEF) ||
988 (getDirective(token) == DIRECTIVE_IFNDEF));
989
990 mTokenizer->lex(token);
991 if (token->type != Token::IDENTIFIER)
992 {
Alexis Hetue13238e2017-12-15 18:01:07 -0500993 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
Nicolas Capens0bac2852016-05-07 06:09:58 -0400994 token->location, token->text);
995 skipUntilEOD(mTokenizer, token);
996 return 0;
997 }
998
999 MacroSet::const_iterator iter = mMacroSet->find(token->text);
1000 int expression = iter != mMacroSet->end() ? 1 : 0;
1001
1002 // Check if there are tokens after #ifdef expression.
1003 mTokenizer->lex(token);
1004 if (!isEOD(token))
1005 {
Alexis Hetue13238e2017-12-15 18:01:07 -05001006 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
Nicolas Capens0bac2852016-05-07 06:09:58 -04001007 token->location, token->text);
1008 skipUntilEOD(mTokenizer, token);
1009 }
1010 return expression;
1011}
1012
1013} // namespace pp