blob: 0731a41d136d7fc9a25e9ea47d93ab6038dee8ee [file] [log] [blame]
alokp@chromium.org04d7d222012-05-16 19:24:07 +00001//
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +00002// Copyright (c) 2011-2013 The ANGLE Project Authors. All rights reserved.
alokp@chromium.org04d7d222012-05-16 19:24:07 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
Corentin Wallez054f7ed2016-09-20 17:15:59 -04007#include "compiler/preprocessor/DirectiveParser.h"
alokp@chromium.org04d7d222012-05-16 19:24:07 +00008
Geoff Lang26be18d2015-04-27 14:05:57 -04009#include <algorithm>
alokp@chromium.org51b96852012-05-30 20:25:05 +000010#include <cstdlib>
alokp@chromium.org36124de82012-05-24 02:17:43 +000011#include <sstream>
alokp@chromium.org04d7d222012-05-16 19:24:07 +000012
Corentin Wallez054f7ed2016-09-20 17:15:59 -040013#include "common/debug.h"
14#include "compiler/preprocessor/DiagnosticsBase.h"
15#include "compiler/preprocessor/DirectiveHandlerBase.h"
16#include "compiler/preprocessor/ExpressionParser.h"
17#include "compiler/preprocessor/MacroExpander.h"
18#include "compiler/preprocessor/Token.h"
19#include "compiler/preprocessor/Tokenizer.h"
alokp@chromium.org04d7d222012-05-16 19:24:07 +000020
Geoff Lang197d5292018-04-25 14:29:00 -040021namespace angle
22{
23
Jamie Madillf832c9d2016-12-12 17:38:48 -050024namespace
25{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000026enum DirectiveType
27{
28 DIRECTIVE_NONE,
29 DIRECTIVE_DEFINE,
30 DIRECTIVE_UNDEF,
31 DIRECTIVE_IF,
32 DIRECTIVE_IFDEF,
33 DIRECTIVE_IFNDEF,
34 DIRECTIVE_ELSE,
35 DIRECTIVE_ELIF,
36 DIRECTIVE_ENDIF,
37 DIRECTIVE_ERROR,
38 DIRECTIVE_PRAGMA,
39 DIRECTIVE_EXTENSION,
40 DIRECTIVE_VERSION,
41 DIRECTIVE_LINE
42};
alokp@chromium.org04d7d222012-05-16 19:24:07 +000043
Zhenyao Mod526f982014-05-13 14:51:19 -070044DirectiveType getDirective(const pp::Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000045{
Jamie Madillf832c9d2016-12-12 17:38:48 -050046 const char kDirectiveDefine[] = "define";
47 const char kDirectiveUndef[] = "undef";
48 const char kDirectiveIf[] = "if";
49 const char kDirectiveIfdef[] = "ifdef";
50 const char kDirectiveIfndef[] = "ifndef";
51 const char kDirectiveElse[] = "else";
52 const char kDirectiveElif[] = "elif";
53 const char kDirectiveEndif[] = "endif";
54 const char kDirectiveError[] = "error";
55 const char kDirectivePragma[] = "pragma";
Zhenyao Mob5e17752014-10-22 10:57:10 -070056 const char kDirectiveExtension[] = "extension";
Jamie Madillf832c9d2016-12-12 17:38:48 -050057 const char kDirectiveVersion[] = "version";
58 const char kDirectiveLine[] = "line";
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000059
60 if (token->type != pp::Token::IDENTIFIER)
61 return DIRECTIVE_NONE;
62
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +000063 if (token->text == kDirectiveDefine)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000064 return DIRECTIVE_DEFINE;
Zhenyao Mod526f982014-05-13 14:51:19 -070065 if (token->text == kDirectiveUndef)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000066 return DIRECTIVE_UNDEF;
Zhenyao Mod526f982014-05-13 14:51:19 -070067 if (token->text == kDirectiveIf)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000068 return DIRECTIVE_IF;
Zhenyao Mod526f982014-05-13 14:51:19 -070069 if (token->text == kDirectiveIfdef)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000070 return DIRECTIVE_IFDEF;
Zhenyao Mod526f982014-05-13 14:51:19 -070071 if (token->text == kDirectiveIfndef)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000072 return DIRECTIVE_IFNDEF;
Zhenyao Mod526f982014-05-13 14:51:19 -070073 if (token->text == kDirectiveElse)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000074 return DIRECTIVE_ELSE;
Zhenyao Mod526f982014-05-13 14:51:19 -070075 if (token->text == kDirectiveElif)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000076 return DIRECTIVE_ELIF;
Zhenyao Mod526f982014-05-13 14:51:19 -070077 if (token->text == kDirectiveEndif)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000078 return DIRECTIVE_ENDIF;
Zhenyao Mod526f982014-05-13 14:51:19 -070079 if (token->text == kDirectiveError)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000080 return DIRECTIVE_ERROR;
Zhenyao Mod526f982014-05-13 14:51:19 -070081 if (token->text == kDirectivePragma)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000082 return DIRECTIVE_PRAGMA;
Zhenyao Mod526f982014-05-13 14:51:19 -070083 if (token->text == kDirectiveExtension)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000084 return DIRECTIVE_EXTENSION;
Zhenyao Mod526f982014-05-13 14:51:19 -070085 if (token->text == kDirectiveVersion)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000086 return DIRECTIVE_VERSION;
Zhenyao Mod526f982014-05-13 14:51:19 -070087 if (token->text == kDirectiveLine)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000088 return DIRECTIVE_LINE;
89
90 return DIRECTIVE_NONE;
91}
92
Zhenyao Mod526f982014-05-13 14:51:19 -070093bool isConditionalDirective(DirectiveType directive)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000094{
95 switch (directive)
96 {
Jamie Madillf832c9d2016-12-12 17:38:48 -050097 case DIRECTIVE_IF:
98 case DIRECTIVE_IFDEF:
99 case DIRECTIVE_IFNDEF:
100 case DIRECTIVE_ELSE:
101 case DIRECTIVE_ELIF:
102 case DIRECTIVE_ENDIF:
103 return true;
104 default:
105 return false;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000106 }
107}
108
109// Returns true if the token represents End Of Directive.
Zhenyao Mod526f982014-05-13 14:51:19 -0700110bool isEOD(const pp::Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000111{
112 return (token->type == '\n') || (token->type == pp::Token::LAST);
113}
114
Zhenyao Mod526f982014-05-13 14:51:19 -0700115void skipUntilEOD(pp::Lexer *lexer, pp::Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000116{
Jamie Madillf832c9d2016-12-12 17:38:48 -0500117 while (!isEOD(token))
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000118 {
119 lexer->lex(token);
120 }
121}
122
Zhenyao Mod526f982014-05-13 14:51:19 -0700123bool isMacroNameReserved(const std::string &name)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000124{
Olli Etuaho4d675ca2016-03-07 14:48:49 +0200125 // Names prefixed with "GL_" and the name "defined" are reserved.
126 return name == "defined" || (name.substr(0, 3) == "GL_");
Olli Etuaho2f6ddf32015-09-22 16:10:07 +0300127}
Geoff Lang4c8cae62015-05-01 16:46:16 +0000128
Olli Etuaho2f6ddf32015-09-22 16:10:07 +0300129bool hasDoubleUnderscores(const std::string &name)
130{
131 return (name.find("__") != std::string::npos);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000132}
133
Jamie Madillf832c9d2016-12-12 17:38:48 -0500134bool isMacroPredefined(const std::string &name, const pp::MacroSet &macroSet)
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000135{
136 pp::MacroSet::const_iterator iter = macroSet.find(name);
Olli Etuaho47c27e82017-01-17 15:29:35 +0000137 return iter != macroSet.end() ? iter->second->predefined : false;
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000138}
139
Zhenyao Mod526f982014-05-13 14:51:19 -0700140} // namespace anonymous
141
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000142namespace pp
143{
144
Olli Etuaho1b2f1622016-03-04 15:06:51 +0200145class DefinedParser : public Lexer
146{
147 public:
148 DefinedParser(Lexer *lexer, const MacroSet *macroSet, Diagnostics *diagnostics)
149 : mLexer(lexer), mMacroSet(macroSet), mDiagnostics(diagnostics)
150 {
151 }
152
153 protected:
154 void lex(Token *token) override
155 {
156 const char kDefined[] = "defined";
157
158 mLexer->lex(token);
159 if (token->type != Token::IDENTIFIER)
160 return;
161 if (token->text != kDefined)
162 return;
163
164 bool paren = false;
165 mLexer->lex(token);
166 if (token->type == '(')
167 {
168 paren = true;
169 mLexer->lex(token);
170 }
171
172 if (token->type != Token::IDENTIFIER)
173 {
174 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
175 skipUntilEOD(mLexer, token);
176 return;
177 }
178 MacroSet::const_iterator iter = mMacroSet->find(token->text);
179 std::string expression = iter != mMacroSet->end() ? "1" : "0";
180
181 if (paren)
182 {
183 mLexer->lex(token);
184 if (token->type != ')')
185 {
186 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
187 token->text);
188 skipUntilEOD(mLexer, token);
189 return;
190 }
191 }
192
193 // We have a valid defined operator.
194 // Convert the current token into a CONST_INT token.
195 token->type = Token::CONST_INT;
196 token->text = expression;
197 }
198
199 private:
200 Lexer *mLexer;
201 const MacroSet *mMacroSet;
202 Diagnostics *mDiagnostics;
203};
204
Zhenyao Mod526f982014-05-13 14:51:19 -0700205DirectiveParser::DirectiveParser(Tokenizer *tokenizer,
206 MacroSet *macroSet,
207 Diagnostics *diagnostics,
Olli Etuahof1cf5e62016-11-22 17:36:49 +0000208 DirectiveHandler *directiveHandler,
209 int maxMacroExpansionDepth)
Zhenyao Mod526f982014-05-13 14:51:19 -0700210 : mPastFirstStatement(false),
Geoff Lang06e24a72015-04-27 14:48:59 -0400211 mSeenNonPreprocessorToken(false),
Zhenyao Mod526f982014-05-13 14:51:19 -0700212 mTokenizer(tokenizer),
213 mMacroSet(macroSet),
214 mDiagnostics(diagnostics),
Geoff Langb3a6a8f2015-06-23 16:10:14 -0400215 mDirectiveHandler(directiveHandler),
Olli Etuahof1cf5e62016-11-22 17:36:49 +0000216 mShaderVersion(100),
217 mMaxMacroExpansionDepth(maxMacroExpansionDepth)
alokp@chromium.org2c958ee2012-05-17 20:35:42 +0000218{
219}
220
Jamie Madillacf2f3a2017-11-21 19:22:44 -0500221DirectiveParser::~DirectiveParser()
222{
223}
224
Zhenyao Mod526f982014-05-13 14:51:19 -0700225void DirectiveParser::lex(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000226{
227 do
228 {
229 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000230
alokp@chromium.org432d6fc2012-06-27 22:13:21 +0000231 if (token->type == Token::PP_HASH)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000232 {
233 parseDirective(token);
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000234 mPastFirstStatement = true;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000235 }
Geoff Lang06e24a72015-04-27 14:48:59 -0400236 else if (!isEOD(token))
237 {
238 mSeenNonPreprocessorToken = true;
239 }
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000240
241 if (token->type == Token::LAST)
242 {
243 if (!mConditionalStack.empty())
244 {
Zhenyao Mod526f982014-05-13 14:51:19 -0700245 const ConditionalBlock &block = mConditionalStack.back();
Jamie Madillf832c9d2016-12-12 17:38:48 -0500246 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNTERMINATED, block.location,
247 block.type);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000248 }
249 break;
250 }
251
Jamie Madillf832c9d2016-12-12 17:38:48 -0500252 } while (skipping() || (token->type == '\n'));
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000253
254 mPastFirstStatement = true;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000255}
256
Zhenyao Mod526f982014-05-13 14:51:19 -0700257void DirectiveParser::parseDirective(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000258{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400259 ASSERT(token->type == Token::PP_HASH);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000260
261 mTokenizer->lex(token);
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000262 if (isEOD(token))
263 {
264 // Empty Directive.
265 return;
266 }
267
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000268 DirectiveType directive = getDirective(token);
269
270 // While in an excluded conditional block/group,
271 // we only parse conditional directives.
272 if (skipping() && !isConditionalDirective(directive))
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000273 {
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000274 skipUntilEOD(mTokenizer, token);
275 return;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000276 }
277
Jamie Madillf832c9d2016-12-12 17:38:48 -0500278 switch (directive)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000279 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500280 case DIRECTIVE_NONE:
281 mDiagnostics->report(Diagnostics::PP_DIRECTIVE_INVALID_NAME, token->location,
282 token->text);
283 skipUntilEOD(mTokenizer, token);
284 break;
285 case DIRECTIVE_DEFINE:
286 parseDefine(token);
287 break;
288 case DIRECTIVE_UNDEF:
289 parseUndef(token);
290 break;
291 case DIRECTIVE_IF:
292 parseIf(token);
293 break;
294 case DIRECTIVE_IFDEF:
295 parseIfdef(token);
296 break;
297 case DIRECTIVE_IFNDEF:
298 parseIfndef(token);
299 break;
300 case DIRECTIVE_ELSE:
301 parseElse(token);
302 break;
303 case DIRECTIVE_ELIF:
304 parseElif(token);
305 break;
306 case DIRECTIVE_ENDIF:
307 parseEndif(token);
308 break;
309 case DIRECTIVE_ERROR:
310 parseError(token);
311 break;
312 case DIRECTIVE_PRAGMA:
313 parsePragma(token);
314 break;
315 case DIRECTIVE_EXTENSION:
316 parseExtension(token);
317 break;
318 case DIRECTIVE_VERSION:
319 parseVersion(token);
320 break;
321 case DIRECTIVE_LINE:
322 parseLine(token);
323 break;
324 default:
325 UNREACHABLE();
326 break;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000327 }
328
329 skipUntilEOD(mTokenizer, token);
330 if (token->type == Token::LAST)
331 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500332 mDiagnostics->report(Diagnostics::PP_EOF_IN_DIRECTIVE, token->location, token->text);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000333 }
334}
335
Zhenyao Mod526f982014-05-13 14:51:19 -0700336void DirectiveParser::parseDefine(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000337{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400338 ASSERT(getDirective(token) == DIRECTIVE_DEFINE);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000339
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000340 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000341 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000342 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500343 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000344 return;
345 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000346 if (isMacroPredefined(token->text, *mMacroSet))
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000347 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500348 mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_REDEFINED, token->location,
349 token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000350 return;
351 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000352 if (isMacroNameReserved(token->text))
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000353 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500354 mDiagnostics->report(Diagnostics::PP_MACRO_NAME_RESERVED, token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000355 return;
356 }
Olli Etuaho2f6ddf32015-09-22 16:10:07 +0300357 // Using double underscores is allowed, but may result in unintended
358 // behavior, so a warning is issued. At the time of writing this was
359 // specified in ESSL 3.10, but the intent judging from Khronos
360 // discussions and dEQP tests was that double underscores should be
361 // allowed in earlier ESSL versions too.
362 if (hasDoubleUnderscores(token->text))
363 {
364 mDiagnostics->report(Diagnostics::PP_WARNING_MACRO_NAME_RESERVED, token->location,
365 token->text);
366 }
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000367
Olli Etuaho47c27e82017-01-17 15:29:35 +0000368 std::shared_ptr<Macro> macro = std::make_shared<Macro>();
369 macro->type = Macro::kTypeObj;
370 macro->name = token->text;
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000371
372 mTokenizer->lex(token);
373 if (token->type == '(' && !token->hasLeadingSpace())
374 {
375 // Function-like macro. Collect arguments.
Olli Etuaho47c27e82017-01-17 15:29:35 +0000376 macro->type = Macro::kTypeFunc;
Zhenyao Mod526f982014-05-13 14:51:19 -0700377 do
378 {
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000379 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000380 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000381 break;
Geoff Lang26be18d2015-04-27 14:05:57 -0400382
Olli Etuaho47c27e82017-01-17 15:29:35 +0000383 if (std::find(macro->parameters.begin(), macro->parameters.end(), token->text) !=
384 macro->parameters.end())
Geoff Lang26be18d2015-04-27 14:05:57 -0400385 {
386 mDiagnostics->report(Diagnostics::PP_MACRO_DUPLICATE_PARAMETER_NAMES,
387 token->location, token->text);
388 return;
389 }
390
Olli Etuaho47c27e82017-01-17 15:29:35 +0000391 macro->parameters.push_back(token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000392
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000393 mTokenizer->lex(token); // Get ','.
Jamie Madillf832c9d2016-12-12 17:38:48 -0500394 } while (token->type == ',');
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000395
396 if (token->type != ')')
397 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500398 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000399 return;
400 }
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000401 mTokenizer->lex(token); // Get ')'.
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000402 }
403
alokp@chromium.org7c884542012-05-24 19:13:03 +0000404 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000405 {
406 // Reset the token location because it is unnecessary in replacement
407 // list. Resetting it also allows us to reuse Token::equals() to
408 // compare macros.
409 token->location = SourceLocation();
Olli Etuaho47c27e82017-01-17 15:29:35 +0000410 macro->replacements.push_back(*token);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000411 mTokenizer->lex(token);
412 }
Olli Etuaho47c27e82017-01-17 15:29:35 +0000413 if (!macro->replacements.empty())
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000414 {
415 // Whitespace preceding the replacement list is not considered part of
416 // the replacement list for either form of macro.
Olli Etuaho47c27e82017-01-17 15:29:35 +0000417 macro->replacements.front().setHasLeadingSpace(false);
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000418 }
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000419
420 // Check for macro redefinition.
Olli Etuaho47c27e82017-01-17 15:29:35 +0000421 MacroSet::const_iterator iter = mMacroSet->find(macro->name);
422 if (iter != mMacroSet->end() && !macro->equals(*iter->second))
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000423 {
Olli Etuaho47c27e82017-01-17 15:29:35 +0000424 mDiagnostics->report(Diagnostics::PP_MACRO_REDEFINED, token->location, macro->name);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000425 return;
426 }
Olli Etuaho47c27e82017-01-17 15:29:35 +0000427 mMacroSet->insert(std::make_pair(macro->name, macro));
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000428}
429
Zhenyao Mod526f982014-05-13 14:51:19 -0700430void DirectiveParser::parseUndef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000431{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400432 ASSERT(getDirective(token) == DIRECTIVE_UNDEF);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000433
434 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000435 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000436 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500437 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000438 return;
439 }
440
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000441 MacroSet::iterator iter = mMacroSet->find(token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000442 if (iter != mMacroSet->end())
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000443 {
Olli Etuaho47c27e82017-01-17 15:29:35 +0000444 if (iter->second->predefined)
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000445 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500446 mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_UNDEFINED, token->location,
447 token->text);
Corentin Wallezd2f195b2016-09-19 15:53:33 -0400448 return;
449 }
Olli Etuaho47c27e82017-01-17 15:29:35 +0000450 else if (iter->second->expansionCount > 0)
Corentin Wallezd2f195b2016-09-19 15:53:33 -0400451 {
452 mDiagnostics->report(Diagnostics::PP_MACRO_UNDEFINED_WHILE_INVOKED, token->location,
453 token->text);
454 return;
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000455 }
456 else
457 {
458 mMacroSet->erase(iter);
459 }
460 }
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000461
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000462 mTokenizer->lex(token);
Geoff Langb819d252015-04-27 14:16:34 -0400463 if (!isEOD(token))
464 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500465 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
Geoff Langb819d252015-04-27 14:16:34 -0400466 skipUntilEOD(mTokenizer, token);
467 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000468}
469
Zhenyao Mod526f982014-05-13 14:51:19 -0700470void DirectiveParser::parseIf(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000471{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400472 ASSERT(getDirective(token) == DIRECTIVE_IF);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000473 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000474}
475
Zhenyao Mod526f982014-05-13 14:51:19 -0700476void DirectiveParser::parseIfdef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000477{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400478 ASSERT(getDirective(token) == DIRECTIVE_IFDEF);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000479 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000480}
481
Zhenyao Mod526f982014-05-13 14:51:19 -0700482void DirectiveParser::parseIfndef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000483{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400484 ASSERT(getDirective(token) == DIRECTIVE_IFNDEF);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000485 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000486}
487
Zhenyao Mod526f982014-05-13 14:51:19 -0700488void DirectiveParser::parseElse(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000489{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400490 ASSERT(getDirective(token) == DIRECTIVE_ELSE);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000491
492 if (mConditionalStack.empty())
493 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500494 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_WITHOUT_IF, token->location,
495 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000496 skipUntilEOD(mTokenizer, token);
497 return;
498 }
499
Zhenyao Mod526f982014-05-13 14:51:19 -0700500 ConditionalBlock &block = mConditionalStack.back();
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000501 if (block.skipBlock)
502 {
503 // No diagnostics. Just skip the whole line.
504 skipUntilEOD(mTokenizer, token);
505 return;
506 }
507 if (block.foundElseGroup)
508 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500509 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_AFTER_ELSE, token->location,
510 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000511 skipUntilEOD(mTokenizer, token);
512 return;
513 }
514
Jamie Madillf832c9d2016-12-12 17:38:48 -0500515 block.foundElseGroup = true;
516 block.skipGroup = block.foundValidGroup;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000517 block.foundValidGroup = true;
518
Geoff Lang95a423d2015-04-28 11:09:45 -0400519 // Check if there are extra tokens after #else.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000520 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000521 if (!isEOD(token))
522 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500523 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location,
524 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000525 skipUntilEOD(mTokenizer, token);
526 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000527}
528
Zhenyao Mod526f982014-05-13 14:51:19 -0700529void DirectiveParser::parseElif(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000530{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400531 ASSERT(getDirective(token) == DIRECTIVE_ELIF);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000532
533 if (mConditionalStack.empty())
534 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500535 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_WITHOUT_IF, token->location,
536 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000537 skipUntilEOD(mTokenizer, token);
538 return;
539 }
540
Zhenyao Mod526f982014-05-13 14:51:19 -0700541 ConditionalBlock &block = mConditionalStack.back();
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000542 if (block.skipBlock)
543 {
544 // No diagnostics. Just skip the whole line.
545 skipUntilEOD(mTokenizer, token);
546 return;
547 }
548 if (block.foundElseGroup)
549 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500550 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_AFTER_ELSE, token->location,
551 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000552 skipUntilEOD(mTokenizer, token);
553 return;
554 }
555 if (block.foundValidGroup)
556 {
557 // Do not parse the expression.
558 // Also be careful not to emit a diagnostic.
559 block.skipGroup = true;
560 skipUntilEOD(mTokenizer, token);
561 return;
562 }
563
Jamie Madillf832c9d2016-12-12 17:38:48 -0500564 int expression = parseExpressionIf(token);
565 block.skipGroup = expression == 0;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000566 block.foundValidGroup = expression != 0;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000567}
568
Zhenyao Mod526f982014-05-13 14:51:19 -0700569void DirectiveParser::parseEndif(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000570{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400571 ASSERT(getDirective(token) == DIRECTIVE_ENDIF);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000572
573 if (mConditionalStack.empty())
574 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500575 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ENDIF_WITHOUT_IF, token->location,
576 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000577 skipUntilEOD(mTokenizer, token);
578 return;
579 }
580
581 mConditionalStack.pop_back();
582
Geoff Lang95a423d2015-04-28 11:09:45 -0400583 // Check if there are tokens after #endif.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000584 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000585 if (!isEOD(token))
586 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500587 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location,
588 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000589 skipUntilEOD(mTokenizer, token);
590 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000591}
592
Zhenyao Mod526f982014-05-13 14:51:19 -0700593void DirectiveParser::parseError(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000594{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400595 ASSERT(getDirective(token) == DIRECTIVE_ERROR);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000596
alokp@chromium.org2e818912012-06-29 21:26:03 +0000597 std::ostringstream stream;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000598 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000599 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org36124de82012-05-24 02:17:43 +0000600 {
601 stream << *token;
602 mTokenizer->lex(token);
603 }
604 mDirectiveHandler->handleError(token->location, stream.str());
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000605}
606
alokp@chromium.org36124de82012-05-24 02:17:43 +0000607// Parses pragma of form: #pragma name[(value)].
Zhenyao Mod526f982014-05-13 14:51:19 -0700608void DirectiveParser::parsePragma(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000609{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400610 ASSERT(getDirective(token) == DIRECTIVE_PRAGMA);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000611
612 enum State
613 {
614 PRAGMA_NAME,
615 LEFT_PAREN,
616 PRAGMA_VALUE,
617 RIGHT_PAREN
618 };
619
620 bool valid = true;
621 std::string name, value;
622 int state = PRAGMA_NAME;
623
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000624 mTokenizer->lex(token);
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700625 bool stdgl = token->text == "STDGL";
626 if (stdgl)
627 {
628 mTokenizer->lex(token);
629 }
alokp@chromium.org7c884542012-05-24 19:13:03 +0000630 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org36124de82012-05-24 02:17:43 +0000631 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500632 switch (state++)
alokp@chromium.org36124de82012-05-24 02:17:43 +0000633 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500634 case PRAGMA_NAME:
635 name = token->text;
636 valid = valid && (token->type == Token::IDENTIFIER);
637 break;
638 case LEFT_PAREN:
639 valid = valid && (token->type == '(');
640 break;
641 case PRAGMA_VALUE:
642 value = token->text;
643 valid = valid && (token->type == Token::IDENTIFIER);
644 break;
645 case RIGHT_PAREN:
646 valid = valid && (token->type == ')');
647 break;
648 default:
649 valid = false;
650 break;
alokp@chromium.org36124de82012-05-24 02:17:43 +0000651 }
652 mTokenizer->lex(token);
653 }
654
655 valid = valid && ((state == PRAGMA_NAME) || // Empty pragma.
656 (state == LEFT_PAREN) || // Without value.
657 (state == RIGHT_PAREN + 1)); // With value.
658 if (!valid)
659 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500660 mDiagnostics->report(Diagnostics::PP_UNRECOGNIZED_PRAGMA, token->location, name);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000661 }
662 else if (state > PRAGMA_NAME) // Do not notify for empty pragma.
663 {
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700664 mDirectiveHandler->handlePragma(token->location, name, value, stdgl);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000665 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000666}
667
Zhenyao Mod526f982014-05-13 14:51:19 -0700668void DirectiveParser::parseExtension(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000669{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400670 ASSERT(getDirective(token) == DIRECTIVE_EXTENSION);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000671
672 enum State
673 {
674 EXT_NAME,
675 COLON,
676 EXT_BEHAVIOR
677 };
678
679 bool valid = true;
680 std::string name, behavior;
681 int state = EXT_NAME;
682
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000683 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000684 while ((token->type != '\n') && (token->type != Token::LAST))
685 {
686 switch (state++)
687 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500688 case EXT_NAME:
689 if (valid && (token->type != Token::IDENTIFIER))
690 {
691 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_NAME, token->location,
692 token->text);
693 valid = false;
694 }
695 if (valid)
696 name = token->text;
697 break;
698 case COLON:
699 if (valid && (token->type != ':'))
700 {
701 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
702 token->text);
703 valid = false;
704 }
705 break;
706 case EXT_BEHAVIOR:
707 if (valid && (token->type != Token::IDENTIFIER))
708 {
709 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_BEHAVIOR,
710 token->location, token->text);
711 valid = false;
712 }
713 if (valid)
714 behavior = token->text;
715 break;
716 default:
717 if (valid)
718 {
719 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
720 token->text);
721 valid = false;
722 }
723 break;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000724 }
725 mTokenizer->lex(token);
726 }
727 if (valid && (state != EXT_BEHAVIOR + 1))
728 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500729 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_DIRECTIVE, token->location,
730 token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000731 valid = false;
732 }
Geoff Lang06e24a72015-04-27 14:48:59 -0400733 if (valid && mSeenNonPreprocessorToken)
734 {
Geoff Langb3a6a8f2015-06-23 16:10:14 -0400735 if (mShaderVersion >= 300)
736 {
737 mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL3,
738 token->location, token->text);
739 valid = false;
740 }
741 else
742 {
743 mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1,
744 token->location, token->text);
745 }
Geoff Lang06e24a72015-04-27 14:48:59 -0400746 }
alokp@chromium.org7c884542012-05-24 19:13:03 +0000747 if (valid)
748 mDirectiveHandler->handleExtension(token->location, name, behavior);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000749}
750
Zhenyao Mod526f982014-05-13 14:51:19 -0700751void DirectiveParser::parseVersion(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000752{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400753 ASSERT(getDirective(token) == DIRECTIVE_VERSION);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000754
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000755 if (mPastFirstStatement)
756 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500757 mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_STATEMENT, token->location,
758 token->text);
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000759 skipUntilEOD(mTokenizer, token);
760 return;
761 }
762
alokp@chromium.org7c884542012-05-24 19:13:03 +0000763 enum State
764 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000765 VERSION_NUMBER,
766 VERSION_PROFILE,
767 VERSION_ENDLINE
alokp@chromium.org7c884542012-05-24 19:13:03 +0000768 };
769
Jamie Madillf832c9d2016-12-12 17:38:48 -0500770 bool valid = true;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000771 int version = 0;
Jamie Madillf832c9d2016-12-12 17:38:48 -0500772 int state = VERSION_NUMBER;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000773
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000774 mTokenizer->lex(token);
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000775 while (valid && (token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org7c884542012-05-24 19:13:03 +0000776 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000777 switch (state)
alokp@chromium.org7c884542012-05-24 19:13:03 +0000778 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500779 case VERSION_NUMBER:
780 if (token->type != Token::CONST_INT)
781 {
782 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_NUMBER, token->location,
783 token->text);
784 valid = false;
785 }
786 if (valid && !token->iValue(&version))
787 {
788 mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW, token->location,
789 token->text);
790 valid = false;
791 }
792 if (valid)
793 {
794 state = (version < 300) ? VERSION_ENDLINE : VERSION_PROFILE;
795 }
796 break;
797 case VERSION_PROFILE:
798 if (token->type != Token::IDENTIFIER || token->text != "es")
799 {
800 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE, token->location,
801 token->text);
802 valid = false;
803 }
804 state = VERSION_ENDLINE;
805 break;
806 default:
807 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
808 token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000809 valid = false;
Jamie Madillf832c9d2016-12-12 17:38:48 -0500810 break;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000811 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000812
alokp@chromium.org7c884542012-05-24 19:13:03 +0000813 mTokenizer->lex(token);
814 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000815
816 if (valid && (state != VERSION_ENDLINE))
alokp@chromium.org7c884542012-05-24 19:13:03 +0000817 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500818 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE, token->location,
819 token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000820 valid = false;
821 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000822
Olli Etuahoc378cd82015-05-25 15:21:44 +0300823 if (valid && version >= 300 && token->location.line > 1)
824 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500825 mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_LINE_ESSL3, token->location,
826 token->text);
Olli Etuahoc378cd82015-05-25 15:21:44 +0300827 valid = false;
828 }
829
alokp@chromium.org7c884542012-05-24 19:13:03 +0000830 if (valid)
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000831 {
alokp@chromium.org7c884542012-05-24 19:13:03 +0000832 mDirectiveHandler->handleVersion(token->location, version);
Geoff Langb3a6a8f2015-06-23 16:10:14 -0400833 mShaderVersion = version;
Olli Etuaho6cb4c7f2015-08-13 11:27:17 +0300834 PredefineMacro(mMacroSet, "__VERSION__", version);
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000835 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000836}
837
Zhenyao Mod526f982014-05-13 14:51:19 -0700838void DirectiveParser::parseLine(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000839{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400840 ASSERT(getDirective(token) == DIRECTIVE_LINE);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000841
Jamie Madillf832c9d2016-12-12 17:38:48 -0500842 bool valid = true;
Olli Etuaho247374c2015-09-09 15:07:24 +0300843 bool parsedFileNumber = false;
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000844 int line = 0, file = 0;
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000845
Olli Etuahof1cf5e62016-11-22 17:36:49 +0000846 MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, mMaxMacroExpansionDepth);
Olli Etuaho247374c2015-09-09 15:07:24 +0300847
848 // Lex the first token after "#line" so we can check it for EOD.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000849 macroExpander.lex(token);
Olli Etuaho247374c2015-09-09 15:07:24 +0300850
851 if (isEOD(token))
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000852 {
Olli Etuaho247374c2015-09-09 15:07:24 +0300853 mDiagnostics->report(Diagnostics::PP_INVALID_LINE_DIRECTIVE, token->location, token->text);
854 valid = false;
855 }
856 else
857 {
858 ExpressionParser expressionParser(&macroExpander, mDiagnostics);
859 ExpressionParser::ErrorSettings errorSettings;
860
861 // See GLES3 section 12.42
862 errorSettings.integerLiteralsMustFit32BitSignedRange = true;
863
864 errorSettings.unexpectedIdentifier = Diagnostics::PP_INVALID_LINE_NUMBER;
865 // The first token was lexed earlier to check if it was EOD. Include
866 // the token in parsing for a second time by setting the
867 // parsePresetToken flag to true.
868 expressionParser.parse(token, &line, true, errorSettings, &valid);
869 if (!isEOD(token) && valid)
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000870 {
Olli Etuaho247374c2015-09-09 15:07:24 +0300871 errorSettings.unexpectedIdentifier = Diagnostics::PP_INVALID_FILE_NUMBER;
872 // After parsing the line expression expressionParser has also
873 // advanced to the first token of the file expression - this is the
874 // token that makes the parser reduce the "input" rule for the line
875 // expression and stop. So we're using parsePresetToken = true here
876 // as well.
877 expressionParser.parse(token, &file, true, errorSettings, &valid);
878 parsedFileNumber = true;
879 }
880 if (!isEOD(token))
881 {
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000882 if (valid)
883 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500884 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
885 token->text);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000886 valid = false;
887 }
Olli Etuaho247374c2015-09-09 15:07:24 +0300888 skipUntilEOD(mTokenizer, token);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000889 }
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000890 }
891
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000892 if (valid)
893 {
894 mTokenizer->setLineNumber(line);
Olli Etuaho247374c2015-09-09 15:07:24 +0300895 if (parsedFileNumber)
Zhenyao Mod526f982014-05-13 14:51:19 -0700896 mTokenizer->setFileNumber(file);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000897 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000898}
899
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000900bool DirectiveParser::skipping() const
901{
Zhenyao Mod526f982014-05-13 14:51:19 -0700902 if (mConditionalStack.empty())
903 return false;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000904
Jamie Madillf832c9d2016-12-12 17:38:48 -0500905 const ConditionalBlock &block = mConditionalStack.back();
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000906 return block.skipBlock || block.skipGroup;
907}
908
Zhenyao Mod526f982014-05-13 14:51:19 -0700909void DirectiveParser::parseConditionalIf(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000910{
911 ConditionalBlock block;
Jamie Madillf832c9d2016-12-12 17:38:48 -0500912 block.type = token->text;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000913 block.location = token->location;
914
915 if (skipping())
916 {
917 // This conditional block is inside another conditional group
918 // which is skipped. As a consequence this whole block is skipped.
919 // Be careful not to parse the conditional expression that might
920 // emit a diagnostic.
921 skipUntilEOD(mTokenizer, token);
922 block.skipBlock = true;
923 }
924 else
925 {
926 DirectiveType directive = getDirective(token);
927
928 int expression = 0;
929 switch (directive)
930 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500931 case DIRECTIVE_IF:
932 expression = parseExpressionIf(token);
933 break;
934 case DIRECTIVE_IFDEF:
935 expression = parseExpressionIfdef(token);
936 break;
937 case DIRECTIVE_IFNDEF:
938 expression = parseExpressionIfdef(token) == 0 ? 1 : 0;
939 break;
940 default:
941 UNREACHABLE();
942 break;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000943 }
Jamie Madillf832c9d2016-12-12 17:38:48 -0500944 block.skipGroup = expression == 0;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000945 block.foundValidGroup = expression != 0;
946 }
947 mConditionalStack.push_back(block);
948}
949
Zhenyao Mod526f982014-05-13 14:51:19 -0700950int DirectiveParser::parseExpressionIf(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000951{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400952 ASSERT((getDirective(token) == DIRECTIVE_IF) || (getDirective(token) == DIRECTIVE_ELIF));
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000953
Olli Etuaho1b2f1622016-03-04 15:06:51 +0200954 DefinedParser definedParser(mTokenizer, mMacroSet, mDiagnostics);
Olli Etuahof1cf5e62016-11-22 17:36:49 +0000955 MacroExpander macroExpander(&definedParser, mMacroSet, mDiagnostics, mMaxMacroExpansionDepth);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000956 ExpressionParser expressionParser(&macroExpander, mDiagnostics);
957
958 int expression = 0;
Olli Etuaho247374c2015-09-09 15:07:24 +0300959 ExpressionParser::ErrorSettings errorSettings;
960 errorSettings.integerLiteralsMustFit32BitSignedRange = false;
Jamie Madillf832c9d2016-12-12 17:38:48 -0500961 errorSettings.unexpectedIdentifier = Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN;
Olli Etuaho247374c2015-09-09 15:07:24 +0300962
963 bool valid = true;
964 expressionParser.parse(token, &expression, false, errorSettings, &valid);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000965
Geoff Lang95a423d2015-04-28 11:09:45 -0400966 // Check if there are tokens after #if expression.
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000967 if (!isEOD(token))
968 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500969 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location,
970 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000971 skipUntilEOD(mTokenizer, token);
972 }
973
974 return expression;
975}
976
Zhenyao Mod526f982014-05-13 14:51:19 -0700977int DirectiveParser::parseExpressionIfdef(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000978{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400979 ASSERT((getDirective(token) == DIRECTIVE_IFDEF) || (getDirective(token) == DIRECTIVE_IFNDEF));
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000980
981 mTokenizer->lex(token);
982 if (token->type != Token::IDENTIFIER)
983 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500984 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000985 skipUntilEOD(mTokenizer, token);
986 return 0;
987 }
988
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000989 MacroSet::const_iterator iter = mMacroSet->find(token->text);
Jamie Madillf832c9d2016-12-12 17:38:48 -0500990 int expression = iter != mMacroSet->end() ? 1 : 0;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000991
Geoff Lang95a423d2015-04-28 11:09:45 -0400992 // Check if there are tokens after #ifdef expression.
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000993 mTokenizer->lex(token);
994 if (!isEOD(token))
995 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500996 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location,
997 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000998 skipUntilEOD(mTokenizer, token);
999 }
1000 return expression;
1001}
1002
alokp@chromium.org04d7d222012-05-16 19:24:07 +00001003} // namespace pp
Geoff Lang197d5292018-04-25 14:29:00 -04001004
1005} // namespace angle