blob: e99d843b2d312096f9a0b83db5a46ae25edd8d60 [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
Jamie Madillb980c562018-11-27 11:34:27 -0500140} // namespace
Zhenyao Mod526f982014-05-13 14:51:19 -0700141
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)
Jamie Madillb980c562018-11-27 11:34:27 -0500157{}
alokp@chromium.org2c958ee2012-05-17 20:35:42 +0000158
Jamie Madillb980c562018-11-27 11:34:27 -0500159DirectiveParser::~DirectiveParser() {}
Jamie Madillacf2f3a2017-11-21 19:22:44 -0500160
Zhenyao Mod526f982014-05-13 14:51:19 -0700161void DirectiveParser::lex(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000162{
163 do
164 {
165 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000166
alokp@chromium.org432d6fc2012-06-27 22:13:21 +0000167 if (token->type == Token::PP_HASH)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000168 {
169 parseDirective(token);
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000170 mPastFirstStatement = true;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000171 }
Geoff Lang06e24a72015-04-27 14:48:59 -0400172 else if (!isEOD(token))
173 {
174 mSeenNonPreprocessorToken = true;
175 }
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000176
177 if (token->type == Token::LAST)
178 {
179 if (!mConditionalStack.empty())
180 {
Zhenyao Mod526f982014-05-13 14:51:19 -0700181 const ConditionalBlock &block = mConditionalStack.back();
Jamie Madillf832c9d2016-12-12 17:38:48 -0500182 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNTERMINATED, block.location,
183 block.type);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000184 }
185 break;
186 }
187
Jamie Madillf832c9d2016-12-12 17:38:48 -0500188 } while (skipping() || (token->type == '\n'));
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000189
190 mPastFirstStatement = true;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000191}
192
Zhenyao Mod526f982014-05-13 14:51:19 -0700193void DirectiveParser::parseDirective(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000194{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400195 ASSERT(token->type == Token::PP_HASH);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000196
197 mTokenizer->lex(token);
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000198 if (isEOD(token))
199 {
200 // Empty Directive.
201 return;
202 }
203
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000204 DirectiveType directive = getDirective(token);
205
206 // While in an excluded conditional block/group,
207 // we only parse conditional directives.
208 if (skipping() && !isConditionalDirective(directive))
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000209 {
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000210 skipUntilEOD(mTokenizer, token);
211 return;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000212 }
213
Jamie Madillf832c9d2016-12-12 17:38:48 -0500214 switch (directive)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000215 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500216 case DIRECTIVE_NONE:
217 mDiagnostics->report(Diagnostics::PP_DIRECTIVE_INVALID_NAME, token->location,
218 token->text);
219 skipUntilEOD(mTokenizer, token);
220 break;
221 case DIRECTIVE_DEFINE:
222 parseDefine(token);
223 break;
224 case DIRECTIVE_UNDEF:
225 parseUndef(token);
226 break;
227 case DIRECTIVE_IF:
228 parseIf(token);
229 break;
230 case DIRECTIVE_IFDEF:
231 parseIfdef(token);
232 break;
233 case DIRECTIVE_IFNDEF:
234 parseIfndef(token);
235 break;
236 case DIRECTIVE_ELSE:
237 parseElse(token);
238 break;
239 case DIRECTIVE_ELIF:
240 parseElif(token);
241 break;
242 case DIRECTIVE_ENDIF:
243 parseEndif(token);
244 break;
245 case DIRECTIVE_ERROR:
246 parseError(token);
247 break;
248 case DIRECTIVE_PRAGMA:
249 parsePragma(token);
250 break;
251 case DIRECTIVE_EXTENSION:
252 parseExtension(token);
253 break;
254 case DIRECTIVE_VERSION:
255 parseVersion(token);
256 break;
257 case DIRECTIVE_LINE:
258 parseLine(token);
259 break;
260 default:
261 UNREACHABLE();
262 break;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000263 }
264
265 skipUntilEOD(mTokenizer, token);
266 if (token->type == Token::LAST)
267 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500268 mDiagnostics->report(Diagnostics::PP_EOF_IN_DIRECTIVE, token->location, token->text);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000269 }
270}
271
Zhenyao Mod526f982014-05-13 14:51:19 -0700272void DirectiveParser::parseDefine(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000273{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400274 ASSERT(getDirective(token) == DIRECTIVE_DEFINE);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000275
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000276 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000277 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000278 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500279 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000280 return;
281 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000282 if (isMacroPredefined(token->text, *mMacroSet))
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000283 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500284 mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_REDEFINED, token->location,
285 token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000286 return;
287 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000288 if (isMacroNameReserved(token->text))
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000289 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500290 mDiagnostics->report(Diagnostics::PP_MACRO_NAME_RESERVED, token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000291 return;
292 }
Olli Etuaho2f6ddf32015-09-22 16:10:07 +0300293 // Using double underscores is allowed, but may result in unintended
294 // behavior, so a warning is issued. At the time of writing this was
295 // specified in ESSL 3.10, but the intent judging from Khronos
296 // discussions and dEQP tests was that double underscores should be
297 // allowed in earlier ESSL versions too.
298 if (hasDoubleUnderscores(token->text))
299 {
300 mDiagnostics->report(Diagnostics::PP_WARNING_MACRO_NAME_RESERVED, token->location,
301 token->text);
302 }
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000303
Olli Etuaho47c27e82017-01-17 15:29:35 +0000304 std::shared_ptr<Macro> macro = std::make_shared<Macro>();
305 macro->type = Macro::kTypeObj;
306 macro->name = token->text;
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000307
308 mTokenizer->lex(token);
309 if (token->type == '(' && !token->hasLeadingSpace())
310 {
311 // Function-like macro. Collect arguments.
Olli Etuaho47c27e82017-01-17 15:29:35 +0000312 macro->type = Macro::kTypeFunc;
Zhenyao Mod526f982014-05-13 14:51:19 -0700313 do
314 {
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000315 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000316 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000317 break;
Geoff Lang26be18d2015-04-27 14:05:57 -0400318
Olli Etuaho47c27e82017-01-17 15:29:35 +0000319 if (std::find(macro->parameters.begin(), macro->parameters.end(), token->text) !=
320 macro->parameters.end())
Geoff Lang26be18d2015-04-27 14:05:57 -0400321 {
322 mDiagnostics->report(Diagnostics::PP_MACRO_DUPLICATE_PARAMETER_NAMES,
323 token->location, token->text);
324 return;
325 }
326
Olli Etuaho47c27e82017-01-17 15:29:35 +0000327 macro->parameters.push_back(token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000328
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000329 mTokenizer->lex(token); // Get ','.
Jamie Madillf832c9d2016-12-12 17:38:48 -0500330 } while (token->type == ',');
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000331
332 if (token->type != ')')
333 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500334 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000335 return;
336 }
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000337 mTokenizer->lex(token); // Get ')'.
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000338 }
339
alokp@chromium.org7c884542012-05-24 19:13:03 +0000340 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000341 {
342 // Reset the token location because it is unnecessary in replacement
343 // list. Resetting it also allows us to reuse Token::equals() to
344 // compare macros.
345 token->location = SourceLocation();
Olli Etuaho47c27e82017-01-17 15:29:35 +0000346 macro->replacements.push_back(*token);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000347 mTokenizer->lex(token);
348 }
Olli Etuaho47c27e82017-01-17 15:29:35 +0000349 if (!macro->replacements.empty())
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000350 {
351 // Whitespace preceding the replacement list is not considered part of
352 // the replacement list for either form of macro.
Olli Etuaho47c27e82017-01-17 15:29:35 +0000353 macro->replacements.front().setHasLeadingSpace(false);
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000354 }
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000355
356 // Check for macro redefinition.
Olli Etuaho47c27e82017-01-17 15:29:35 +0000357 MacroSet::const_iterator iter = mMacroSet->find(macro->name);
358 if (iter != mMacroSet->end() && !macro->equals(*iter->second))
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000359 {
Olli Etuaho47c27e82017-01-17 15:29:35 +0000360 mDiagnostics->report(Diagnostics::PP_MACRO_REDEFINED, token->location, macro->name);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000361 return;
362 }
Olli Etuaho47c27e82017-01-17 15:29:35 +0000363 mMacroSet->insert(std::make_pair(macro->name, macro));
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000364}
365
Zhenyao Mod526f982014-05-13 14:51:19 -0700366void DirectiveParser::parseUndef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000367{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400368 ASSERT(getDirective(token) == DIRECTIVE_UNDEF);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000369
370 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000371 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000372 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500373 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000374 return;
375 }
376
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000377 MacroSet::iterator iter = mMacroSet->find(token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000378 if (iter != mMacroSet->end())
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000379 {
Olli Etuaho47c27e82017-01-17 15:29:35 +0000380 if (iter->second->predefined)
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000381 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500382 mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_UNDEFINED, token->location,
383 token->text);
Corentin Wallezd2f195b2016-09-19 15:53:33 -0400384 return;
385 }
Olli Etuaho47c27e82017-01-17 15:29:35 +0000386 else if (iter->second->expansionCount > 0)
Corentin Wallezd2f195b2016-09-19 15:53:33 -0400387 {
388 mDiagnostics->report(Diagnostics::PP_MACRO_UNDEFINED_WHILE_INVOKED, token->location,
389 token->text);
390 return;
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000391 }
392 else
393 {
394 mMacroSet->erase(iter);
395 }
396 }
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000397
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000398 mTokenizer->lex(token);
Geoff Langb819d252015-04-27 14:16:34 -0400399 if (!isEOD(token))
400 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500401 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
Geoff Langb819d252015-04-27 14:16:34 -0400402 skipUntilEOD(mTokenizer, token);
403 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000404}
405
Zhenyao Mod526f982014-05-13 14:51:19 -0700406void DirectiveParser::parseIf(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000407{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400408 ASSERT(getDirective(token) == DIRECTIVE_IF);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000409 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000410}
411
Zhenyao Mod526f982014-05-13 14:51:19 -0700412void DirectiveParser::parseIfdef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000413{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400414 ASSERT(getDirective(token) == DIRECTIVE_IFDEF);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000415 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000416}
417
Zhenyao Mod526f982014-05-13 14:51:19 -0700418void DirectiveParser::parseIfndef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000419{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400420 ASSERT(getDirective(token) == DIRECTIVE_IFNDEF);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000421 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000422}
423
Zhenyao Mod526f982014-05-13 14:51:19 -0700424void DirectiveParser::parseElse(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000425{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400426 ASSERT(getDirective(token) == DIRECTIVE_ELSE);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000427
428 if (mConditionalStack.empty())
429 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500430 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_WITHOUT_IF, token->location,
431 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000432 skipUntilEOD(mTokenizer, token);
433 return;
434 }
435
Zhenyao Mod526f982014-05-13 14:51:19 -0700436 ConditionalBlock &block = mConditionalStack.back();
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000437 if (block.skipBlock)
438 {
439 // No diagnostics. Just skip the whole line.
440 skipUntilEOD(mTokenizer, token);
441 return;
442 }
443 if (block.foundElseGroup)
444 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500445 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_AFTER_ELSE, token->location,
446 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000447 skipUntilEOD(mTokenizer, token);
448 return;
449 }
450
Jamie Madillf832c9d2016-12-12 17:38:48 -0500451 block.foundElseGroup = true;
452 block.skipGroup = block.foundValidGroup;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000453 block.foundValidGroup = true;
454
Geoff Lang95a423d2015-04-28 11:09:45 -0400455 // Check if there are extra tokens after #else.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000456 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000457 if (!isEOD(token))
458 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500459 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location,
460 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000461 skipUntilEOD(mTokenizer, token);
462 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000463}
464
Zhenyao Mod526f982014-05-13 14:51:19 -0700465void DirectiveParser::parseElif(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000466{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400467 ASSERT(getDirective(token) == DIRECTIVE_ELIF);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000468
469 if (mConditionalStack.empty())
470 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500471 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_WITHOUT_IF, token->location,
472 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000473 skipUntilEOD(mTokenizer, token);
474 return;
475 }
476
Zhenyao Mod526f982014-05-13 14:51:19 -0700477 ConditionalBlock &block = mConditionalStack.back();
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000478 if (block.skipBlock)
479 {
480 // No diagnostics. Just skip the whole line.
481 skipUntilEOD(mTokenizer, token);
482 return;
483 }
484 if (block.foundElseGroup)
485 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500486 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_AFTER_ELSE, token->location,
487 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000488 skipUntilEOD(mTokenizer, token);
489 return;
490 }
491 if (block.foundValidGroup)
492 {
493 // Do not parse the expression.
494 // Also be careful not to emit a diagnostic.
495 block.skipGroup = true;
496 skipUntilEOD(mTokenizer, token);
497 return;
498 }
499
Jamie Madillf832c9d2016-12-12 17:38:48 -0500500 int expression = parseExpressionIf(token);
501 block.skipGroup = expression == 0;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000502 block.foundValidGroup = expression != 0;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000503}
504
Zhenyao Mod526f982014-05-13 14:51:19 -0700505void DirectiveParser::parseEndif(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000506{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400507 ASSERT(getDirective(token) == DIRECTIVE_ENDIF);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000508
509 if (mConditionalStack.empty())
510 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500511 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ENDIF_WITHOUT_IF, token->location,
512 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000513 skipUntilEOD(mTokenizer, token);
514 return;
515 }
516
517 mConditionalStack.pop_back();
518
Geoff Lang95a423d2015-04-28 11:09:45 -0400519 // Check if there are tokens after #endif.
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::parseError(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000530{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400531 ASSERT(getDirective(token) == DIRECTIVE_ERROR);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000532
alokp@chromium.org2e818912012-06-29 21:26:03 +0000533 std::ostringstream stream;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000534 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000535 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org36124de82012-05-24 02:17:43 +0000536 {
537 stream << *token;
538 mTokenizer->lex(token);
539 }
540 mDirectiveHandler->handleError(token->location, stream.str());
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000541}
542
alokp@chromium.org36124de82012-05-24 02:17:43 +0000543// Parses pragma of form: #pragma name[(value)].
Zhenyao Mod526f982014-05-13 14:51:19 -0700544void DirectiveParser::parsePragma(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000545{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400546 ASSERT(getDirective(token) == DIRECTIVE_PRAGMA);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000547
548 enum State
549 {
550 PRAGMA_NAME,
551 LEFT_PAREN,
552 PRAGMA_VALUE,
553 RIGHT_PAREN
554 };
555
556 bool valid = true;
557 std::string name, value;
558 int state = PRAGMA_NAME;
559
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000560 mTokenizer->lex(token);
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700561 bool stdgl = token->text == "STDGL";
562 if (stdgl)
563 {
564 mTokenizer->lex(token);
565 }
alokp@chromium.org7c884542012-05-24 19:13:03 +0000566 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org36124de82012-05-24 02:17:43 +0000567 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500568 switch (state++)
alokp@chromium.org36124de82012-05-24 02:17:43 +0000569 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500570 case PRAGMA_NAME:
571 name = token->text;
572 valid = valid && (token->type == Token::IDENTIFIER);
573 break;
574 case LEFT_PAREN:
575 valid = valid && (token->type == '(');
576 break;
577 case PRAGMA_VALUE:
578 value = token->text;
579 valid = valid && (token->type == Token::IDENTIFIER);
580 break;
581 case RIGHT_PAREN:
582 valid = valid && (token->type == ')');
583 break;
584 default:
585 valid = false;
586 break;
alokp@chromium.org36124de82012-05-24 02:17:43 +0000587 }
588 mTokenizer->lex(token);
589 }
590
591 valid = valid && ((state == PRAGMA_NAME) || // Empty pragma.
592 (state == LEFT_PAREN) || // Without value.
593 (state == RIGHT_PAREN + 1)); // With value.
594 if (!valid)
595 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500596 mDiagnostics->report(Diagnostics::PP_UNRECOGNIZED_PRAGMA, token->location, name);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000597 }
598 else if (state > PRAGMA_NAME) // Do not notify for empty pragma.
599 {
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700600 mDirectiveHandler->handlePragma(token->location, name, value, stdgl);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000601 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000602}
603
Zhenyao Mod526f982014-05-13 14:51:19 -0700604void DirectiveParser::parseExtension(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000605{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400606 ASSERT(getDirective(token) == DIRECTIVE_EXTENSION);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000607
608 enum State
609 {
610 EXT_NAME,
611 COLON,
612 EXT_BEHAVIOR
613 };
614
615 bool valid = true;
616 std::string name, behavior;
617 int state = EXT_NAME;
618
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000619 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000620 while ((token->type != '\n') && (token->type != Token::LAST))
621 {
622 switch (state++)
623 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500624 case EXT_NAME:
625 if (valid && (token->type != Token::IDENTIFIER))
626 {
627 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_NAME, token->location,
628 token->text);
629 valid = false;
630 }
631 if (valid)
632 name = token->text;
633 break;
634 case COLON:
635 if (valid && (token->type != ':'))
636 {
637 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
638 token->text);
639 valid = false;
640 }
641 break;
642 case EXT_BEHAVIOR:
643 if (valid && (token->type != Token::IDENTIFIER))
644 {
645 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_BEHAVIOR,
646 token->location, token->text);
647 valid = false;
648 }
649 if (valid)
650 behavior = token->text;
651 break;
652 default:
653 if (valid)
654 {
655 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
656 token->text);
657 valid = false;
658 }
659 break;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000660 }
661 mTokenizer->lex(token);
662 }
663 if (valid && (state != EXT_BEHAVIOR + 1))
664 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500665 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_DIRECTIVE, token->location,
666 token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000667 valid = false;
668 }
Geoff Lang06e24a72015-04-27 14:48:59 -0400669 if (valid && mSeenNonPreprocessorToken)
670 {
Geoff Langb3a6a8f2015-06-23 16:10:14 -0400671 if (mShaderVersion >= 300)
672 {
673 mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL3,
674 token->location, token->text);
675 valid = false;
676 }
677 else
678 {
679 mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1,
680 token->location, token->text);
681 }
Geoff Lang06e24a72015-04-27 14:48:59 -0400682 }
alokp@chromium.org7c884542012-05-24 19:13:03 +0000683 if (valid)
684 mDirectiveHandler->handleExtension(token->location, name, behavior);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000685}
686
Zhenyao Mod526f982014-05-13 14:51:19 -0700687void DirectiveParser::parseVersion(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000688{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400689 ASSERT(getDirective(token) == DIRECTIVE_VERSION);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000690
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000691 if (mPastFirstStatement)
692 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500693 mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_STATEMENT, token->location,
694 token->text);
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000695 skipUntilEOD(mTokenizer, token);
696 return;
697 }
698
alokp@chromium.org7c884542012-05-24 19:13:03 +0000699 enum State
700 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000701 VERSION_NUMBER,
702 VERSION_PROFILE,
703 VERSION_ENDLINE
alokp@chromium.org7c884542012-05-24 19:13:03 +0000704 };
705
Jamie Madillf832c9d2016-12-12 17:38:48 -0500706 bool valid = true;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000707 int version = 0;
Jamie Madillf832c9d2016-12-12 17:38:48 -0500708 int state = VERSION_NUMBER;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000709
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000710 mTokenizer->lex(token);
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000711 while (valid && (token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org7c884542012-05-24 19:13:03 +0000712 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000713 switch (state)
alokp@chromium.org7c884542012-05-24 19:13:03 +0000714 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500715 case VERSION_NUMBER:
716 if (token->type != Token::CONST_INT)
717 {
718 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_NUMBER, token->location,
719 token->text);
720 valid = false;
721 }
722 if (valid && !token->iValue(&version))
723 {
724 mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW, token->location,
725 token->text);
726 valid = false;
727 }
728 if (valid)
729 {
730 state = (version < 300) ? VERSION_ENDLINE : VERSION_PROFILE;
731 }
732 break;
733 case VERSION_PROFILE:
734 if (token->type != Token::IDENTIFIER || token->text != "es")
735 {
736 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE, token->location,
737 token->text);
738 valid = false;
739 }
740 state = VERSION_ENDLINE;
741 break;
742 default:
743 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
744 token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000745 valid = false;
Jamie Madillf832c9d2016-12-12 17:38:48 -0500746 break;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000747 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000748
alokp@chromium.org7c884542012-05-24 19:13:03 +0000749 mTokenizer->lex(token);
750 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000751
752 if (valid && (state != VERSION_ENDLINE))
alokp@chromium.org7c884542012-05-24 19:13:03 +0000753 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500754 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE, token->location,
755 token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000756 valid = false;
757 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000758
Olli Etuahoc378cd82015-05-25 15:21:44 +0300759 if (valid && version >= 300 && token->location.line > 1)
760 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500761 mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_LINE_ESSL3, token->location,
762 token->text);
Olli Etuahoc378cd82015-05-25 15:21:44 +0300763 valid = false;
764 }
765
alokp@chromium.org7c884542012-05-24 19:13:03 +0000766 if (valid)
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000767 {
alokp@chromium.org7c884542012-05-24 19:13:03 +0000768 mDirectiveHandler->handleVersion(token->location, version);
Geoff Langb3a6a8f2015-06-23 16:10:14 -0400769 mShaderVersion = version;
Olli Etuaho6cb4c7f2015-08-13 11:27:17 +0300770 PredefineMacro(mMacroSet, "__VERSION__", version);
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000771 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000772}
773
Zhenyao Mod526f982014-05-13 14:51:19 -0700774void DirectiveParser::parseLine(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000775{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400776 ASSERT(getDirective(token) == DIRECTIVE_LINE);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000777
Jamie Madillf832c9d2016-12-12 17:38:48 -0500778 bool valid = true;
Olli Etuaho247374c2015-09-09 15:07:24 +0300779 bool parsedFileNumber = false;
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000780 int line = 0, file = 0;
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000781
Jamie Madillc3bef3e2018-10-03 07:35:09 -0400782 MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, mSettings, false);
Olli Etuaho247374c2015-09-09 15:07:24 +0300783
784 // Lex the first token after "#line" so we can check it for EOD.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000785 macroExpander.lex(token);
Olli Etuaho247374c2015-09-09 15:07:24 +0300786
787 if (isEOD(token))
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000788 {
Olli Etuaho247374c2015-09-09 15:07:24 +0300789 mDiagnostics->report(Diagnostics::PP_INVALID_LINE_DIRECTIVE, token->location, token->text);
790 valid = false;
791 }
792 else
793 {
794 ExpressionParser expressionParser(&macroExpander, mDiagnostics);
795 ExpressionParser::ErrorSettings errorSettings;
796
797 // See GLES3 section 12.42
798 errorSettings.integerLiteralsMustFit32BitSignedRange = true;
799
800 errorSettings.unexpectedIdentifier = Diagnostics::PP_INVALID_LINE_NUMBER;
801 // The first token was lexed earlier to check if it was EOD. Include
802 // the token in parsing for a second time by setting the
803 // parsePresetToken flag to true.
804 expressionParser.parse(token, &line, true, errorSettings, &valid);
805 if (!isEOD(token) && valid)
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000806 {
Olli Etuaho247374c2015-09-09 15:07:24 +0300807 errorSettings.unexpectedIdentifier = Diagnostics::PP_INVALID_FILE_NUMBER;
808 // After parsing the line expression expressionParser has also
809 // advanced to the first token of the file expression - this is the
810 // token that makes the parser reduce the "input" rule for the line
811 // expression and stop. So we're using parsePresetToken = true here
812 // as well.
813 expressionParser.parse(token, &file, true, errorSettings, &valid);
814 parsedFileNumber = true;
815 }
816 if (!isEOD(token))
817 {
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000818 if (valid)
819 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500820 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
821 token->text);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000822 valid = false;
823 }
Olli Etuaho247374c2015-09-09 15:07:24 +0300824 skipUntilEOD(mTokenizer, token);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000825 }
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000826 }
827
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000828 if (valid)
829 {
830 mTokenizer->setLineNumber(line);
Olli Etuaho247374c2015-09-09 15:07:24 +0300831 if (parsedFileNumber)
Zhenyao Mod526f982014-05-13 14:51:19 -0700832 mTokenizer->setFileNumber(file);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000833 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000834}
835
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000836bool DirectiveParser::skipping() const
837{
Zhenyao Mod526f982014-05-13 14:51:19 -0700838 if (mConditionalStack.empty())
839 return false;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000840
Jamie Madillf832c9d2016-12-12 17:38:48 -0500841 const ConditionalBlock &block = mConditionalStack.back();
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000842 return block.skipBlock || block.skipGroup;
843}
844
Zhenyao Mod526f982014-05-13 14:51:19 -0700845void DirectiveParser::parseConditionalIf(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000846{
847 ConditionalBlock block;
Jamie Madillf832c9d2016-12-12 17:38:48 -0500848 block.type = token->text;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000849 block.location = token->location;
850
851 if (skipping())
852 {
853 // This conditional block is inside another conditional group
854 // which is skipped. As a consequence this whole block is skipped.
855 // Be careful not to parse the conditional expression that might
856 // emit a diagnostic.
857 skipUntilEOD(mTokenizer, token);
858 block.skipBlock = true;
859 }
860 else
861 {
862 DirectiveType directive = getDirective(token);
863
864 int expression = 0;
865 switch (directive)
866 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500867 case DIRECTIVE_IF:
868 expression = parseExpressionIf(token);
869 break;
870 case DIRECTIVE_IFDEF:
871 expression = parseExpressionIfdef(token);
872 break;
873 case DIRECTIVE_IFNDEF:
874 expression = parseExpressionIfdef(token) == 0 ? 1 : 0;
875 break;
876 default:
877 UNREACHABLE();
878 break;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000879 }
Jamie Madillf832c9d2016-12-12 17:38:48 -0500880 block.skipGroup = expression == 0;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000881 block.foundValidGroup = expression != 0;
882 }
883 mConditionalStack.push_back(block);
884}
885
Zhenyao Mod526f982014-05-13 14:51:19 -0700886int DirectiveParser::parseExpressionIf(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000887{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400888 ASSERT((getDirective(token) == DIRECTIVE_IF) || (getDirective(token) == DIRECTIVE_ELIF));
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000889
Jamie Madillc3bef3e2018-10-03 07:35:09 -0400890 MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, mSettings, true);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000891 ExpressionParser expressionParser(&macroExpander, mDiagnostics);
892
893 int expression = 0;
Olli Etuaho247374c2015-09-09 15:07:24 +0300894 ExpressionParser::ErrorSettings errorSettings;
895 errorSettings.integerLiteralsMustFit32BitSignedRange = false;
Jamie Madillf832c9d2016-12-12 17:38:48 -0500896 errorSettings.unexpectedIdentifier = Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN;
Olli Etuaho247374c2015-09-09 15:07:24 +0300897
898 bool valid = true;
899 expressionParser.parse(token, &expression, false, errorSettings, &valid);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000900
Geoff Lang95a423d2015-04-28 11:09:45 -0400901 // Check if there are tokens after #if expression.
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000902 if (!isEOD(token))
903 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500904 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location,
905 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000906 skipUntilEOD(mTokenizer, token);
907 }
908
909 return expression;
910}
911
Zhenyao Mod526f982014-05-13 14:51:19 -0700912int DirectiveParser::parseExpressionIfdef(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000913{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400914 ASSERT((getDirective(token) == DIRECTIVE_IFDEF) || (getDirective(token) == DIRECTIVE_IFNDEF));
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000915
916 mTokenizer->lex(token);
917 if (token->type != Token::IDENTIFIER)
918 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500919 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000920 skipUntilEOD(mTokenizer, token);
921 return 0;
922 }
923
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000924 MacroSet::const_iterator iter = mMacroSet->find(token->text);
Jamie Madillf832c9d2016-12-12 17:38:48 -0500925 int expression = iter != mMacroSet->end() ? 1 : 0;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000926
Geoff Lang95a423d2015-04-28 11:09:45 -0400927 // Check if there are tokens after #ifdef expression.
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000928 mTokenizer->lex(token);
929 if (!isEOD(token))
930 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500931 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location,
932 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000933 skipUntilEOD(mTokenizer, token);
934 }
935 return expression;
936}
937
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000938} // namespace pp
Geoff Lang197d5292018-04-25 14:29:00 -0400939
940} // namespace angle