blob: 739cbd483a7c70ee30c0734f50b01f8ed5da0464 [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{
Zhenyao Mod526f982014-05-13 14:51:19 -0700144DirectiveParser::DirectiveParser(Tokenizer *tokenizer,
145 MacroSet *macroSet,
146 Diagnostics *diagnostics,
Olli Etuahof1cf5e62016-11-22 17:36:49 +0000147 DirectiveHandler *directiveHandler,
Jamie Madillc3bef3e2018-10-03 07:35:09 -0400148 const PreprocessorSettings &settings)
Zhenyao Mod526f982014-05-13 14:51:19 -0700149 : mPastFirstStatement(false),
Geoff Lang06e24a72015-04-27 14:48:59 -0400150 mSeenNonPreprocessorToken(false),
Zhenyao Mod526f982014-05-13 14:51:19 -0700151 mTokenizer(tokenizer),
152 mMacroSet(macroSet),
153 mDiagnostics(diagnostics),
Geoff Langb3a6a8f2015-06-23 16:10:14 -0400154 mDirectiveHandler(directiveHandler),
Olli Etuahof1cf5e62016-11-22 17:36:49 +0000155 mShaderVersion(100),
Jamie Madillc3bef3e2018-10-03 07:35:09 -0400156 mSettings(settings)
alokp@chromium.org2c958ee2012-05-17 20:35:42 +0000157{
158}
159
Jamie Madillacf2f3a2017-11-21 19:22:44 -0500160DirectiveParser::~DirectiveParser()
161{
162}
163
Zhenyao Mod526f982014-05-13 14:51:19 -0700164void DirectiveParser::lex(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000165{
166 do
167 {
168 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000169
alokp@chromium.org432d6fc2012-06-27 22:13:21 +0000170 if (token->type == Token::PP_HASH)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000171 {
172 parseDirective(token);
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000173 mPastFirstStatement = true;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000174 }
Geoff Lang06e24a72015-04-27 14:48:59 -0400175 else if (!isEOD(token))
176 {
177 mSeenNonPreprocessorToken = true;
178 }
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000179
180 if (token->type == Token::LAST)
181 {
182 if (!mConditionalStack.empty())
183 {
Zhenyao Mod526f982014-05-13 14:51:19 -0700184 const ConditionalBlock &block = mConditionalStack.back();
Jamie Madillf832c9d2016-12-12 17:38:48 -0500185 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNTERMINATED, block.location,
186 block.type);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000187 }
188 break;
189 }
190
Jamie Madillf832c9d2016-12-12 17:38:48 -0500191 } while (skipping() || (token->type == '\n'));
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000192
193 mPastFirstStatement = true;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000194}
195
Zhenyao Mod526f982014-05-13 14:51:19 -0700196void DirectiveParser::parseDirective(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000197{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400198 ASSERT(token->type == Token::PP_HASH);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000199
200 mTokenizer->lex(token);
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000201 if (isEOD(token))
202 {
203 // Empty Directive.
204 return;
205 }
206
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000207 DirectiveType directive = getDirective(token);
208
209 // While in an excluded conditional block/group,
210 // we only parse conditional directives.
211 if (skipping() && !isConditionalDirective(directive))
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000212 {
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000213 skipUntilEOD(mTokenizer, token);
214 return;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000215 }
216
Jamie Madillf832c9d2016-12-12 17:38:48 -0500217 switch (directive)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000218 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500219 case DIRECTIVE_NONE:
220 mDiagnostics->report(Diagnostics::PP_DIRECTIVE_INVALID_NAME, token->location,
221 token->text);
222 skipUntilEOD(mTokenizer, token);
223 break;
224 case DIRECTIVE_DEFINE:
225 parseDefine(token);
226 break;
227 case DIRECTIVE_UNDEF:
228 parseUndef(token);
229 break;
230 case DIRECTIVE_IF:
231 parseIf(token);
232 break;
233 case DIRECTIVE_IFDEF:
234 parseIfdef(token);
235 break;
236 case DIRECTIVE_IFNDEF:
237 parseIfndef(token);
238 break;
239 case DIRECTIVE_ELSE:
240 parseElse(token);
241 break;
242 case DIRECTIVE_ELIF:
243 parseElif(token);
244 break;
245 case DIRECTIVE_ENDIF:
246 parseEndif(token);
247 break;
248 case DIRECTIVE_ERROR:
249 parseError(token);
250 break;
251 case DIRECTIVE_PRAGMA:
252 parsePragma(token);
253 break;
254 case DIRECTIVE_EXTENSION:
255 parseExtension(token);
256 break;
257 case DIRECTIVE_VERSION:
258 parseVersion(token);
259 break;
260 case DIRECTIVE_LINE:
261 parseLine(token);
262 break;
263 default:
264 UNREACHABLE();
265 break;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000266 }
267
268 skipUntilEOD(mTokenizer, token);
269 if (token->type == Token::LAST)
270 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500271 mDiagnostics->report(Diagnostics::PP_EOF_IN_DIRECTIVE, token->location, token->text);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000272 }
273}
274
Zhenyao Mod526f982014-05-13 14:51:19 -0700275void DirectiveParser::parseDefine(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000276{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400277 ASSERT(getDirective(token) == DIRECTIVE_DEFINE);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000278
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000279 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000280 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000281 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500282 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000283 return;
284 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000285 if (isMacroPredefined(token->text, *mMacroSet))
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000286 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500287 mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_REDEFINED, token->location,
288 token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000289 return;
290 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000291 if (isMacroNameReserved(token->text))
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000292 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500293 mDiagnostics->report(Diagnostics::PP_MACRO_NAME_RESERVED, token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000294 return;
295 }
Olli Etuaho2f6ddf32015-09-22 16:10:07 +0300296 // Using double underscores is allowed, but may result in unintended
297 // behavior, so a warning is issued. At the time of writing this was
298 // specified in ESSL 3.10, but the intent judging from Khronos
299 // discussions and dEQP tests was that double underscores should be
300 // allowed in earlier ESSL versions too.
301 if (hasDoubleUnderscores(token->text))
302 {
303 mDiagnostics->report(Diagnostics::PP_WARNING_MACRO_NAME_RESERVED, token->location,
304 token->text);
305 }
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000306
Olli Etuaho47c27e82017-01-17 15:29:35 +0000307 std::shared_ptr<Macro> macro = std::make_shared<Macro>();
308 macro->type = Macro::kTypeObj;
309 macro->name = token->text;
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000310
311 mTokenizer->lex(token);
312 if (token->type == '(' && !token->hasLeadingSpace())
313 {
314 // Function-like macro. Collect arguments.
Olli Etuaho47c27e82017-01-17 15:29:35 +0000315 macro->type = Macro::kTypeFunc;
Zhenyao Mod526f982014-05-13 14:51:19 -0700316 do
317 {
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000318 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000319 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000320 break;
Geoff Lang26be18d2015-04-27 14:05:57 -0400321
Olli Etuaho47c27e82017-01-17 15:29:35 +0000322 if (std::find(macro->parameters.begin(), macro->parameters.end(), token->text) !=
323 macro->parameters.end())
Geoff Lang26be18d2015-04-27 14:05:57 -0400324 {
325 mDiagnostics->report(Diagnostics::PP_MACRO_DUPLICATE_PARAMETER_NAMES,
326 token->location, token->text);
327 return;
328 }
329
Olli Etuaho47c27e82017-01-17 15:29:35 +0000330 macro->parameters.push_back(token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000331
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000332 mTokenizer->lex(token); // Get ','.
Jamie Madillf832c9d2016-12-12 17:38:48 -0500333 } while (token->type == ',');
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000334
335 if (token->type != ')')
336 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500337 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000338 return;
339 }
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000340 mTokenizer->lex(token); // Get ')'.
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000341 }
342
alokp@chromium.org7c884542012-05-24 19:13:03 +0000343 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000344 {
345 // Reset the token location because it is unnecessary in replacement
346 // list. Resetting it also allows us to reuse Token::equals() to
347 // compare macros.
348 token->location = SourceLocation();
Olli Etuaho47c27e82017-01-17 15:29:35 +0000349 macro->replacements.push_back(*token);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000350 mTokenizer->lex(token);
351 }
Olli Etuaho47c27e82017-01-17 15:29:35 +0000352 if (!macro->replacements.empty())
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000353 {
354 // Whitespace preceding the replacement list is not considered part of
355 // the replacement list for either form of macro.
Olli Etuaho47c27e82017-01-17 15:29:35 +0000356 macro->replacements.front().setHasLeadingSpace(false);
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000357 }
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000358
359 // Check for macro redefinition.
Olli Etuaho47c27e82017-01-17 15:29:35 +0000360 MacroSet::const_iterator iter = mMacroSet->find(macro->name);
361 if (iter != mMacroSet->end() && !macro->equals(*iter->second))
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000362 {
Olli Etuaho47c27e82017-01-17 15:29:35 +0000363 mDiagnostics->report(Diagnostics::PP_MACRO_REDEFINED, token->location, macro->name);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000364 return;
365 }
Olli Etuaho47c27e82017-01-17 15:29:35 +0000366 mMacroSet->insert(std::make_pair(macro->name, macro));
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000367}
368
Zhenyao Mod526f982014-05-13 14:51:19 -0700369void DirectiveParser::parseUndef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000370{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400371 ASSERT(getDirective(token) == DIRECTIVE_UNDEF);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000372
373 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000374 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000375 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500376 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000377 return;
378 }
379
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000380 MacroSet::iterator iter = mMacroSet->find(token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000381 if (iter != mMacroSet->end())
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000382 {
Olli Etuaho47c27e82017-01-17 15:29:35 +0000383 if (iter->second->predefined)
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000384 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500385 mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_UNDEFINED, token->location,
386 token->text);
Corentin Wallezd2f195b2016-09-19 15:53:33 -0400387 return;
388 }
Olli Etuaho47c27e82017-01-17 15:29:35 +0000389 else if (iter->second->expansionCount > 0)
Corentin Wallezd2f195b2016-09-19 15:53:33 -0400390 {
391 mDiagnostics->report(Diagnostics::PP_MACRO_UNDEFINED_WHILE_INVOKED, token->location,
392 token->text);
393 return;
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000394 }
395 else
396 {
397 mMacroSet->erase(iter);
398 }
399 }
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000400
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000401 mTokenizer->lex(token);
Geoff Langb819d252015-04-27 14:16:34 -0400402 if (!isEOD(token))
403 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500404 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
Geoff Langb819d252015-04-27 14:16:34 -0400405 skipUntilEOD(mTokenizer, token);
406 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000407}
408
Zhenyao Mod526f982014-05-13 14:51:19 -0700409void DirectiveParser::parseIf(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000410{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400411 ASSERT(getDirective(token) == DIRECTIVE_IF);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000412 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000413}
414
Zhenyao Mod526f982014-05-13 14:51:19 -0700415void DirectiveParser::parseIfdef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000416{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400417 ASSERT(getDirective(token) == DIRECTIVE_IFDEF);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000418 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000419}
420
Zhenyao Mod526f982014-05-13 14:51:19 -0700421void DirectiveParser::parseIfndef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000422{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400423 ASSERT(getDirective(token) == DIRECTIVE_IFNDEF);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000424 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000425}
426
Zhenyao Mod526f982014-05-13 14:51:19 -0700427void DirectiveParser::parseElse(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000428{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400429 ASSERT(getDirective(token) == DIRECTIVE_ELSE);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000430
431 if (mConditionalStack.empty())
432 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500433 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_WITHOUT_IF, token->location,
434 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000435 skipUntilEOD(mTokenizer, token);
436 return;
437 }
438
Zhenyao Mod526f982014-05-13 14:51:19 -0700439 ConditionalBlock &block = mConditionalStack.back();
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000440 if (block.skipBlock)
441 {
442 // No diagnostics. Just skip the whole line.
443 skipUntilEOD(mTokenizer, token);
444 return;
445 }
446 if (block.foundElseGroup)
447 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500448 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_AFTER_ELSE, token->location,
449 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000450 skipUntilEOD(mTokenizer, token);
451 return;
452 }
453
Jamie Madillf832c9d2016-12-12 17:38:48 -0500454 block.foundElseGroup = true;
455 block.skipGroup = block.foundValidGroup;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000456 block.foundValidGroup = true;
457
Geoff Lang95a423d2015-04-28 11:09:45 -0400458 // Check if there are extra tokens after #else.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000459 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000460 if (!isEOD(token))
461 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500462 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location,
463 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000464 skipUntilEOD(mTokenizer, token);
465 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000466}
467
Zhenyao Mod526f982014-05-13 14:51:19 -0700468void DirectiveParser::parseElif(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000469{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400470 ASSERT(getDirective(token) == DIRECTIVE_ELIF);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000471
472 if (mConditionalStack.empty())
473 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500474 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_WITHOUT_IF, token->location,
475 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000476 skipUntilEOD(mTokenizer, token);
477 return;
478 }
479
Zhenyao Mod526f982014-05-13 14:51:19 -0700480 ConditionalBlock &block = mConditionalStack.back();
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000481 if (block.skipBlock)
482 {
483 // No diagnostics. Just skip the whole line.
484 skipUntilEOD(mTokenizer, token);
485 return;
486 }
487 if (block.foundElseGroup)
488 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500489 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_AFTER_ELSE, token->location,
490 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000491 skipUntilEOD(mTokenizer, token);
492 return;
493 }
494 if (block.foundValidGroup)
495 {
496 // Do not parse the expression.
497 // Also be careful not to emit a diagnostic.
498 block.skipGroup = true;
499 skipUntilEOD(mTokenizer, token);
500 return;
501 }
502
Jamie Madillf832c9d2016-12-12 17:38:48 -0500503 int expression = parseExpressionIf(token);
504 block.skipGroup = expression == 0;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000505 block.foundValidGroup = expression != 0;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000506}
507
Zhenyao Mod526f982014-05-13 14:51:19 -0700508void DirectiveParser::parseEndif(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000509{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400510 ASSERT(getDirective(token) == DIRECTIVE_ENDIF);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000511
512 if (mConditionalStack.empty())
513 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500514 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ENDIF_WITHOUT_IF, token->location,
515 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000516 skipUntilEOD(mTokenizer, token);
517 return;
518 }
519
520 mConditionalStack.pop_back();
521
Geoff Lang95a423d2015-04-28 11:09:45 -0400522 // Check if there are tokens after #endif.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000523 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000524 if (!isEOD(token))
525 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500526 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location,
527 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000528 skipUntilEOD(mTokenizer, token);
529 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000530}
531
Zhenyao Mod526f982014-05-13 14:51:19 -0700532void DirectiveParser::parseError(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000533{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400534 ASSERT(getDirective(token) == DIRECTIVE_ERROR);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000535
alokp@chromium.org2e818912012-06-29 21:26:03 +0000536 std::ostringstream stream;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000537 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000538 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org36124de82012-05-24 02:17:43 +0000539 {
540 stream << *token;
541 mTokenizer->lex(token);
542 }
543 mDirectiveHandler->handleError(token->location, stream.str());
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000544}
545
alokp@chromium.org36124de82012-05-24 02:17:43 +0000546// Parses pragma of form: #pragma name[(value)].
Zhenyao Mod526f982014-05-13 14:51:19 -0700547void DirectiveParser::parsePragma(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000548{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400549 ASSERT(getDirective(token) == DIRECTIVE_PRAGMA);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000550
551 enum State
552 {
553 PRAGMA_NAME,
554 LEFT_PAREN,
555 PRAGMA_VALUE,
556 RIGHT_PAREN
557 };
558
559 bool valid = true;
560 std::string name, value;
561 int state = PRAGMA_NAME;
562
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000563 mTokenizer->lex(token);
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700564 bool stdgl = token->text == "STDGL";
565 if (stdgl)
566 {
567 mTokenizer->lex(token);
568 }
alokp@chromium.org7c884542012-05-24 19:13:03 +0000569 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org36124de82012-05-24 02:17:43 +0000570 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500571 switch (state++)
alokp@chromium.org36124de82012-05-24 02:17:43 +0000572 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500573 case PRAGMA_NAME:
574 name = token->text;
575 valid = valid && (token->type == Token::IDENTIFIER);
576 break;
577 case LEFT_PAREN:
578 valid = valid && (token->type == '(');
579 break;
580 case PRAGMA_VALUE:
581 value = token->text;
582 valid = valid && (token->type == Token::IDENTIFIER);
583 break;
584 case RIGHT_PAREN:
585 valid = valid && (token->type == ')');
586 break;
587 default:
588 valid = false;
589 break;
alokp@chromium.org36124de82012-05-24 02:17:43 +0000590 }
591 mTokenizer->lex(token);
592 }
593
594 valid = valid && ((state == PRAGMA_NAME) || // Empty pragma.
595 (state == LEFT_PAREN) || // Without value.
596 (state == RIGHT_PAREN + 1)); // With value.
597 if (!valid)
598 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500599 mDiagnostics->report(Diagnostics::PP_UNRECOGNIZED_PRAGMA, token->location, name);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000600 }
601 else if (state > PRAGMA_NAME) // Do not notify for empty pragma.
602 {
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700603 mDirectiveHandler->handlePragma(token->location, name, value, stdgl);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000604 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000605}
606
Zhenyao Mod526f982014-05-13 14:51:19 -0700607void DirectiveParser::parseExtension(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000608{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400609 ASSERT(getDirective(token) == DIRECTIVE_EXTENSION);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000610
611 enum State
612 {
613 EXT_NAME,
614 COLON,
615 EXT_BEHAVIOR
616 };
617
618 bool valid = true;
619 std::string name, behavior;
620 int state = EXT_NAME;
621
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000622 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000623 while ((token->type != '\n') && (token->type != Token::LAST))
624 {
625 switch (state++)
626 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500627 case EXT_NAME:
628 if (valid && (token->type != Token::IDENTIFIER))
629 {
630 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_NAME, token->location,
631 token->text);
632 valid = false;
633 }
634 if (valid)
635 name = token->text;
636 break;
637 case COLON:
638 if (valid && (token->type != ':'))
639 {
640 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
641 token->text);
642 valid = false;
643 }
644 break;
645 case EXT_BEHAVIOR:
646 if (valid && (token->type != Token::IDENTIFIER))
647 {
648 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_BEHAVIOR,
649 token->location, token->text);
650 valid = false;
651 }
652 if (valid)
653 behavior = token->text;
654 break;
655 default:
656 if (valid)
657 {
658 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
659 token->text);
660 valid = false;
661 }
662 break;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000663 }
664 mTokenizer->lex(token);
665 }
666 if (valid && (state != EXT_BEHAVIOR + 1))
667 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500668 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_DIRECTIVE, token->location,
669 token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000670 valid = false;
671 }
Geoff Lang06e24a72015-04-27 14:48:59 -0400672 if (valid && mSeenNonPreprocessorToken)
673 {
Geoff Langb3a6a8f2015-06-23 16:10:14 -0400674 if (mShaderVersion >= 300)
675 {
676 mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL3,
677 token->location, token->text);
678 valid = false;
679 }
680 else
681 {
682 mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1,
683 token->location, token->text);
684 }
Geoff Lang06e24a72015-04-27 14:48:59 -0400685 }
alokp@chromium.org7c884542012-05-24 19:13:03 +0000686 if (valid)
687 mDirectiveHandler->handleExtension(token->location, name, behavior);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000688}
689
Zhenyao Mod526f982014-05-13 14:51:19 -0700690void DirectiveParser::parseVersion(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000691{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400692 ASSERT(getDirective(token) == DIRECTIVE_VERSION);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000693
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000694 if (mPastFirstStatement)
695 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500696 mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_STATEMENT, token->location,
697 token->text);
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000698 skipUntilEOD(mTokenizer, token);
699 return;
700 }
701
alokp@chromium.org7c884542012-05-24 19:13:03 +0000702 enum State
703 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000704 VERSION_NUMBER,
705 VERSION_PROFILE,
706 VERSION_ENDLINE
alokp@chromium.org7c884542012-05-24 19:13:03 +0000707 };
708
Jamie Madillf832c9d2016-12-12 17:38:48 -0500709 bool valid = true;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000710 int version = 0;
Jamie Madillf832c9d2016-12-12 17:38:48 -0500711 int state = VERSION_NUMBER;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000712
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000713 mTokenizer->lex(token);
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000714 while (valid && (token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org7c884542012-05-24 19:13:03 +0000715 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000716 switch (state)
alokp@chromium.org7c884542012-05-24 19:13:03 +0000717 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500718 case VERSION_NUMBER:
719 if (token->type != Token::CONST_INT)
720 {
721 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_NUMBER, token->location,
722 token->text);
723 valid = false;
724 }
725 if (valid && !token->iValue(&version))
726 {
727 mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW, token->location,
728 token->text);
729 valid = false;
730 }
731 if (valid)
732 {
733 state = (version < 300) ? VERSION_ENDLINE : VERSION_PROFILE;
734 }
735 break;
736 case VERSION_PROFILE:
737 if (token->type != Token::IDENTIFIER || token->text != "es")
738 {
739 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE, token->location,
740 token->text);
741 valid = false;
742 }
743 state = VERSION_ENDLINE;
744 break;
745 default:
746 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
747 token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000748 valid = false;
Jamie Madillf832c9d2016-12-12 17:38:48 -0500749 break;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000750 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000751
alokp@chromium.org7c884542012-05-24 19:13:03 +0000752 mTokenizer->lex(token);
753 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000754
755 if (valid && (state != VERSION_ENDLINE))
alokp@chromium.org7c884542012-05-24 19:13:03 +0000756 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500757 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE, token->location,
758 token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000759 valid = false;
760 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000761
Olli Etuahoc378cd82015-05-25 15:21:44 +0300762 if (valid && version >= 300 && token->location.line > 1)
763 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500764 mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_LINE_ESSL3, token->location,
765 token->text);
Olli Etuahoc378cd82015-05-25 15:21:44 +0300766 valid = false;
767 }
768
alokp@chromium.org7c884542012-05-24 19:13:03 +0000769 if (valid)
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000770 {
alokp@chromium.org7c884542012-05-24 19:13:03 +0000771 mDirectiveHandler->handleVersion(token->location, version);
Geoff Langb3a6a8f2015-06-23 16:10:14 -0400772 mShaderVersion = version;
Olli Etuaho6cb4c7f2015-08-13 11:27:17 +0300773 PredefineMacro(mMacroSet, "__VERSION__", version);
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000774 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000775}
776
Zhenyao Mod526f982014-05-13 14:51:19 -0700777void DirectiveParser::parseLine(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000778{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400779 ASSERT(getDirective(token) == DIRECTIVE_LINE);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000780
Jamie Madillf832c9d2016-12-12 17:38:48 -0500781 bool valid = true;
Olli Etuaho247374c2015-09-09 15:07:24 +0300782 bool parsedFileNumber = false;
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000783 int line = 0, file = 0;
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000784
Jamie Madillc3bef3e2018-10-03 07:35:09 -0400785 MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, mSettings, false);
Olli Etuaho247374c2015-09-09 15:07:24 +0300786
787 // Lex the first token after "#line" so we can check it for EOD.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000788 macroExpander.lex(token);
Olli Etuaho247374c2015-09-09 15:07:24 +0300789
790 if (isEOD(token))
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000791 {
Olli Etuaho247374c2015-09-09 15:07:24 +0300792 mDiagnostics->report(Diagnostics::PP_INVALID_LINE_DIRECTIVE, token->location, token->text);
793 valid = false;
794 }
795 else
796 {
797 ExpressionParser expressionParser(&macroExpander, mDiagnostics);
798 ExpressionParser::ErrorSettings errorSettings;
799
800 // See GLES3 section 12.42
801 errorSettings.integerLiteralsMustFit32BitSignedRange = true;
802
803 errorSettings.unexpectedIdentifier = Diagnostics::PP_INVALID_LINE_NUMBER;
804 // The first token was lexed earlier to check if it was EOD. Include
805 // the token in parsing for a second time by setting the
806 // parsePresetToken flag to true.
807 expressionParser.parse(token, &line, true, errorSettings, &valid);
808 if (!isEOD(token) && valid)
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000809 {
Olli Etuaho247374c2015-09-09 15:07:24 +0300810 errorSettings.unexpectedIdentifier = Diagnostics::PP_INVALID_FILE_NUMBER;
811 // After parsing the line expression expressionParser has also
812 // advanced to the first token of the file expression - this is the
813 // token that makes the parser reduce the "input" rule for the line
814 // expression and stop. So we're using parsePresetToken = true here
815 // as well.
816 expressionParser.parse(token, &file, true, errorSettings, &valid);
817 parsedFileNumber = true;
818 }
819 if (!isEOD(token))
820 {
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000821 if (valid)
822 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500823 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
824 token->text);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000825 valid = false;
826 }
Olli Etuaho247374c2015-09-09 15:07:24 +0300827 skipUntilEOD(mTokenizer, token);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000828 }
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000829 }
830
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000831 if (valid)
832 {
833 mTokenizer->setLineNumber(line);
Olli Etuaho247374c2015-09-09 15:07:24 +0300834 if (parsedFileNumber)
Zhenyao Mod526f982014-05-13 14:51:19 -0700835 mTokenizer->setFileNumber(file);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000836 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000837}
838
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000839bool DirectiveParser::skipping() const
840{
Zhenyao Mod526f982014-05-13 14:51:19 -0700841 if (mConditionalStack.empty())
842 return false;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000843
Jamie Madillf832c9d2016-12-12 17:38:48 -0500844 const ConditionalBlock &block = mConditionalStack.back();
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000845 return block.skipBlock || block.skipGroup;
846}
847
Zhenyao Mod526f982014-05-13 14:51:19 -0700848void DirectiveParser::parseConditionalIf(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000849{
850 ConditionalBlock block;
Jamie Madillf832c9d2016-12-12 17:38:48 -0500851 block.type = token->text;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000852 block.location = token->location;
853
854 if (skipping())
855 {
856 // This conditional block is inside another conditional group
857 // which is skipped. As a consequence this whole block is skipped.
858 // Be careful not to parse the conditional expression that might
859 // emit a diagnostic.
860 skipUntilEOD(mTokenizer, token);
861 block.skipBlock = true;
862 }
863 else
864 {
865 DirectiveType directive = getDirective(token);
866
867 int expression = 0;
868 switch (directive)
869 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500870 case DIRECTIVE_IF:
871 expression = parseExpressionIf(token);
872 break;
873 case DIRECTIVE_IFDEF:
874 expression = parseExpressionIfdef(token);
875 break;
876 case DIRECTIVE_IFNDEF:
877 expression = parseExpressionIfdef(token) == 0 ? 1 : 0;
878 break;
879 default:
880 UNREACHABLE();
881 break;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000882 }
Jamie Madillf832c9d2016-12-12 17:38:48 -0500883 block.skipGroup = expression == 0;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000884 block.foundValidGroup = expression != 0;
885 }
886 mConditionalStack.push_back(block);
887}
888
Zhenyao Mod526f982014-05-13 14:51:19 -0700889int DirectiveParser::parseExpressionIf(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000890{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400891 ASSERT((getDirective(token) == DIRECTIVE_IF) || (getDirective(token) == DIRECTIVE_ELIF));
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000892
Jamie Madillc3bef3e2018-10-03 07:35:09 -0400893 MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, mSettings, true);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000894 ExpressionParser expressionParser(&macroExpander, mDiagnostics);
895
896 int expression = 0;
Olli Etuaho247374c2015-09-09 15:07:24 +0300897 ExpressionParser::ErrorSettings errorSettings;
898 errorSettings.integerLiteralsMustFit32BitSignedRange = false;
Jamie Madillf832c9d2016-12-12 17:38:48 -0500899 errorSettings.unexpectedIdentifier = Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN;
Olli Etuaho247374c2015-09-09 15:07:24 +0300900
901 bool valid = true;
902 expressionParser.parse(token, &expression, false, errorSettings, &valid);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000903
Geoff Lang95a423d2015-04-28 11:09:45 -0400904 // Check if there are tokens after #if expression.
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000905 if (!isEOD(token))
906 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500907 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location,
908 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000909 skipUntilEOD(mTokenizer, token);
910 }
911
912 return expression;
913}
914
Zhenyao Mod526f982014-05-13 14:51:19 -0700915int DirectiveParser::parseExpressionIfdef(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000916{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400917 ASSERT((getDirective(token) == DIRECTIVE_IFDEF) || (getDirective(token) == DIRECTIVE_IFNDEF));
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000918
919 mTokenizer->lex(token);
920 if (token->type != Token::IDENTIFIER)
921 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500922 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000923 skipUntilEOD(mTokenizer, token);
924 return 0;
925 }
926
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000927 MacroSet::const_iterator iter = mMacroSet->find(token->text);
Jamie Madillf832c9d2016-12-12 17:38:48 -0500928 int expression = iter != mMacroSet->end() ? 1 : 0;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000929
Geoff Lang95a423d2015-04-28 11:09:45 -0400930 // Check if there are tokens after #ifdef expression.
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000931 mTokenizer->lex(token);
932 if (!isEOD(token))
933 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500934 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location,
935 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000936 skipUntilEOD(mTokenizer, token);
937 }
938 return expression;
939}
940
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000941} // namespace pp
Geoff Lang197d5292018-04-25 14:29:00 -0400942
943} // namespace angle