blob: f6c576399081c9d96f80cc63924cc0d56c3d2d14 [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
Jamie Madillf832c9d2016-12-12 17:38:48 -050021namespace
22{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000023enum DirectiveType
24{
25 DIRECTIVE_NONE,
26 DIRECTIVE_DEFINE,
27 DIRECTIVE_UNDEF,
28 DIRECTIVE_IF,
29 DIRECTIVE_IFDEF,
30 DIRECTIVE_IFNDEF,
31 DIRECTIVE_ELSE,
32 DIRECTIVE_ELIF,
33 DIRECTIVE_ENDIF,
34 DIRECTIVE_ERROR,
35 DIRECTIVE_PRAGMA,
36 DIRECTIVE_EXTENSION,
37 DIRECTIVE_VERSION,
38 DIRECTIVE_LINE
39};
alokp@chromium.org04d7d222012-05-16 19:24:07 +000040
Zhenyao Mod526f982014-05-13 14:51:19 -070041DirectiveType getDirective(const pp::Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000042{
Jamie Madillf832c9d2016-12-12 17:38:48 -050043 const char kDirectiveDefine[] = "define";
44 const char kDirectiveUndef[] = "undef";
45 const char kDirectiveIf[] = "if";
46 const char kDirectiveIfdef[] = "ifdef";
47 const char kDirectiveIfndef[] = "ifndef";
48 const char kDirectiveElse[] = "else";
49 const char kDirectiveElif[] = "elif";
50 const char kDirectiveEndif[] = "endif";
51 const char kDirectiveError[] = "error";
52 const char kDirectivePragma[] = "pragma";
Zhenyao Mob5e17752014-10-22 10:57:10 -070053 const char kDirectiveExtension[] = "extension";
Jamie Madillf832c9d2016-12-12 17:38:48 -050054 const char kDirectiveVersion[] = "version";
55 const char kDirectiveLine[] = "line";
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000056
57 if (token->type != pp::Token::IDENTIFIER)
58 return DIRECTIVE_NONE;
59
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +000060 if (token->text == kDirectiveDefine)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000061 return DIRECTIVE_DEFINE;
Zhenyao Mod526f982014-05-13 14:51:19 -070062 if (token->text == kDirectiveUndef)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000063 return DIRECTIVE_UNDEF;
Zhenyao Mod526f982014-05-13 14:51:19 -070064 if (token->text == kDirectiveIf)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000065 return DIRECTIVE_IF;
Zhenyao Mod526f982014-05-13 14:51:19 -070066 if (token->text == kDirectiveIfdef)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000067 return DIRECTIVE_IFDEF;
Zhenyao Mod526f982014-05-13 14:51:19 -070068 if (token->text == kDirectiveIfndef)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000069 return DIRECTIVE_IFNDEF;
Zhenyao Mod526f982014-05-13 14:51:19 -070070 if (token->text == kDirectiveElse)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000071 return DIRECTIVE_ELSE;
Zhenyao Mod526f982014-05-13 14:51:19 -070072 if (token->text == kDirectiveElif)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000073 return DIRECTIVE_ELIF;
Zhenyao Mod526f982014-05-13 14:51:19 -070074 if (token->text == kDirectiveEndif)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000075 return DIRECTIVE_ENDIF;
Zhenyao Mod526f982014-05-13 14:51:19 -070076 if (token->text == kDirectiveError)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000077 return DIRECTIVE_ERROR;
Zhenyao Mod526f982014-05-13 14:51:19 -070078 if (token->text == kDirectivePragma)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000079 return DIRECTIVE_PRAGMA;
Zhenyao Mod526f982014-05-13 14:51:19 -070080 if (token->text == kDirectiveExtension)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000081 return DIRECTIVE_EXTENSION;
Zhenyao Mod526f982014-05-13 14:51:19 -070082 if (token->text == kDirectiveVersion)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000083 return DIRECTIVE_VERSION;
Zhenyao Mod526f982014-05-13 14:51:19 -070084 if (token->text == kDirectiveLine)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000085 return DIRECTIVE_LINE;
86
87 return DIRECTIVE_NONE;
88}
89
Zhenyao Mod526f982014-05-13 14:51:19 -070090bool isConditionalDirective(DirectiveType directive)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000091{
92 switch (directive)
93 {
Jamie Madillf832c9d2016-12-12 17:38:48 -050094 case DIRECTIVE_IF:
95 case DIRECTIVE_IFDEF:
96 case DIRECTIVE_IFNDEF:
97 case DIRECTIVE_ELSE:
98 case DIRECTIVE_ELIF:
99 case DIRECTIVE_ENDIF:
100 return true;
101 default:
102 return false;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000103 }
104}
105
106// Returns true if the token represents End Of Directive.
Zhenyao Mod526f982014-05-13 14:51:19 -0700107bool isEOD(const pp::Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000108{
109 return (token->type == '\n') || (token->type == pp::Token::LAST);
110}
111
Zhenyao Mod526f982014-05-13 14:51:19 -0700112void skipUntilEOD(pp::Lexer *lexer, pp::Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000113{
Jamie Madillf832c9d2016-12-12 17:38:48 -0500114 while (!isEOD(token))
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000115 {
116 lexer->lex(token);
117 }
118}
119
Zhenyao Mod526f982014-05-13 14:51:19 -0700120bool isMacroNameReserved(const std::string &name)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000121{
Olli Etuaho4d675ca2016-03-07 14:48:49 +0200122 // Names prefixed with "GL_" and the name "defined" are reserved.
123 return name == "defined" || (name.substr(0, 3) == "GL_");
Olli Etuaho2f6ddf32015-09-22 16:10:07 +0300124}
Geoff Lang4c8cae62015-05-01 16:46:16 +0000125
Olli Etuaho2f6ddf32015-09-22 16:10:07 +0300126bool hasDoubleUnderscores(const std::string &name)
127{
128 return (name.find("__") != std::string::npos);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000129}
130
Jamie Madillf832c9d2016-12-12 17:38:48 -0500131bool isMacroPredefined(const std::string &name, const pp::MacroSet &macroSet)
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000132{
133 pp::MacroSet::const_iterator iter = macroSet.find(name);
Olli Etuaho47c27e82017-01-17 15:29:35 +0000134 return iter != macroSet.end() ? iter->second->predefined : false;
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000135}
136
Zhenyao Mod526f982014-05-13 14:51:19 -0700137} // namespace anonymous
138
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000139namespace pp
140{
141
Olli Etuaho1b2f1622016-03-04 15:06:51 +0200142class DefinedParser : public Lexer
143{
144 public:
145 DefinedParser(Lexer *lexer, const MacroSet *macroSet, Diagnostics *diagnostics)
146 : mLexer(lexer), mMacroSet(macroSet), mDiagnostics(diagnostics)
147 {
148 }
149
150 protected:
151 void lex(Token *token) override
152 {
153 const char kDefined[] = "defined";
154
155 mLexer->lex(token);
156 if (token->type != Token::IDENTIFIER)
157 return;
158 if (token->text != kDefined)
159 return;
160
161 bool paren = false;
162 mLexer->lex(token);
163 if (token->type == '(')
164 {
165 paren = true;
166 mLexer->lex(token);
167 }
168
169 if (token->type != Token::IDENTIFIER)
170 {
171 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
172 skipUntilEOD(mLexer, token);
173 return;
174 }
175 MacroSet::const_iterator iter = mMacroSet->find(token->text);
176 std::string expression = iter != mMacroSet->end() ? "1" : "0";
177
178 if (paren)
179 {
180 mLexer->lex(token);
181 if (token->type != ')')
182 {
183 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
184 token->text);
185 skipUntilEOD(mLexer, token);
186 return;
187 }
188 }
189
190 // We have a valid defined operator.
191 // Convert the current token into a CONST_INT token.
192 token->type = Token::CONST_INT;
193 token->text = expression;
194 }
195
196 private:
197 Lexer *mLexer;
198 const MacroSet *mMacroSet;
199 Diagnostics *mDiagnostics;
200};
201
Zhenyao Mod526f982014-05-13 14:51:19 -0700202DirectiveParser::DirectiveParser(Tokenizer *tokenizer,
203 MacroSet *macroSet,
204 Diagnostics *diagnostics,
Olli Etuahof1cf5e62016-11-22 17:36:49 +0000205 DirectiveHandler *directiveHandler,
206 int maxMacroExpansionDepth)
Zhenyao Mod526f982014-05-13 14:51:19 -0700207 : mPastFirstStatement(false),
Geoff Lang06e24a72015-04-27 14:48:59 -0400208 mSeenNonPreprocessorToken(false),
Zhenyao Mod526f982014-05-13 14:51:19 -0700209 mTokenizer(tokenizer),
210 mMacroSet(macroSet),
211 mDiagnostics(diagnostics),
Geoff Langb3a6a8f2015-06-23 16:10:14 -0400212 mDirectiveHandler(directiveHandler),
Olli Etuahof1cf5e62016-11-22 17:36:49 +0000213 mShaderVersion(100),
214 mMaxMacroExpansionDepth(maxMacroExpansionDepth)
alokp@chromium.org2c958ee2012-05-17 20:35:42 +0000215{
216}
217
Jamie Madillacf2f3a2017-11-21 19:22:44 -0500218DirectiveParser::~DirectiveParser()
219{
220}
221
Zhenyao Mod526f982014-05-13 14:51:19 -0700222void DirectiveParser::lex(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000223{
224 do
225 {
226 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000227
alokp@chromium.org432d6fc2012-06-27 22:13:21 +0000228 if (token->type == Token::PP_HASH)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000229 {
230 parseDirective(token);
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000231 mPastFirstStatement = true;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000232 }
Geoff Lang06e24a72015-04-27 14:48:59 -0400233 else if (!isEOD(token))
234 {
235 mSeenNonPreprocessorToken = true;
236 }
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000237
238 if (token->type == Token::LAST)
239 {
240 if (!mConditionalStack.empty())
241 {
Zhenyao Mod526f982014-05-13 14:51:19 -0700242 const ConditionalBlock &block = mConditionalStack.back();
Jamie Madillf832c9d2016-12-12 17:38:48 -0500243 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNTERMINATED, block.location,
244 block.type);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000245 }
246 break;
247 }
248
Jamie Madillf832c9d2016-12-12 17:38:48 -0500249 } while (skipping() || (token->type == '\n'));
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000250
251 mPastFirstStatement = true;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000252}
253
Zhenyao Mod526f982014-05-13 14:51:19 -0700254void DirectiveParser::parseDirective(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000255{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400256 ASSERT(token->type == Token::PP_HASH);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000257
258 mTokenizer->lex(token);
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000259 if (isEOD(token))
260 {
261 // Empty Directive.
262 return;
263 }
264
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000265 DirectiveType directive = getDirective(token);
266
267 // While in an excluded conditional block/group,
268 // we only parse conditional directives.
269 if (skipping() && !isConditionalDirective(directive))
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000270 {
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000271 skipUntilEOD(mTokenizer, token);
272 return;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000273 }
274
Jamie Madillf832c9d2016-12-12 17:38:48 -0500275 switch (directive)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000276 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500277 case DIRECTIVE_NONE:
278 mDiagnostics->report(Diagnostics::PP_DIRECTIVE_INVALID_NAME, token->location,
279 token->text);
280 skipUntilEOD(mTokenizer, token);
281 break;
282 case DIRECTIVE_DEFINE:
283 parseDefine(token);
284 break;
285 case DIRECTIVE_UNDEF:
286 parseUndef(token);
287 break;
288 case DIRECTIVE_IF:
289 parseIf(token);
290 break;
291 case DIRECTIVE_IFDEF:
292 parseIfdef(token);
293 break;
294 case DIRECTIVE_IFNDEF:
295 parseIfndef(token);
296 break;
297 case DIRECTIVE_ELSE:
298 parseElse(token);
299 break;
300 case DIRECTIVE_ELIF:
301 parseElif(token);
302 break;
303 case DIRECTIVE_ENDIF:
304 parseEndif(token);
305 break;
306 case DIRECTIVE_ERROR:
307 parseError(token);
308 break;
309 case DIRECTIVE_PRAGMA:
310 parsePragma(token);
311 break;
312 case DIRECTIVE_EXTENSION:
313 parseExtension(token);
314 break;
315 case DIRECTIVE_VERSION:
316 parseVersion(token);
317 break;
318 case DIRECTIVE_LINE:
319 parseLine(token);
320 break;
321 default:
322 UNREACHABLE();
323 break;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000324 }
325
326 skipUntilEOD(mTokenizer, token);
327 if (token->type == Token::LAST)
328 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500329 mDiagnostics->report(Diagnostics::PP_EOF_IN_DIRECTIVE, token->location, token->text);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000330 }
331}
332
Zhenyao Mod526f982014-05-13 14:51:19 -0700333void DirectiveParser::parseDefine(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000334{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400335 ASSERT(getDirective(token) == DIRECTIVE_DEFINE);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000336
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000337 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000338 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000339 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500340 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000341 return;
342 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000343 if (isMacroPredefined(token->text, *mMacroSet))
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000344 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500345 mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_REDEFINED, token->location,
346 token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000347 return;
348 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000349 if (isMacroNameReserved(token->text))
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000350 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500351 mDiagnostics->report(Diagnostics::PP_MACRO_NAME_RESERVED, token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000352 return;
353 }
Olli Etuaho2f6ddf32015-09-22 16:10:07 +0300354 // Using double underscores is allowed, but may result in unintended
355 // behavior, so a warning is issued. At the time of writing this was
356 // specified in ESSL 3.10, but the intent judging from Khronos
357 // discussions and dEQP tests was that double underscores should be
358 // allowed in earlier ESSL versions too.
359 if (hasDoubleUnderscores(token->text))
360 {
361 mDiagnostics->report(Diagnostics::PP_WARNING_MACRO_NAME_RESERVED, token->location,
362 token->text);
363 }
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000364
Olli Etuaho47c27e82017-01-17 15:29:35 +0000365 std::shared_ptr<Macro> macro = std::make_shared<Macro>();
366 macro->type = Macro::kTypeObj;
367 macro->name = token->text;
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000368
369 mTokenizer->lex(token);
370 if (token->type == '(' && !token->hasLeadingSpace())
371 {
372 // Function-like macro. Collect arguments.
Olli Etuaho47c27e82017-01-17 15:29:35 +0000373 macro->type = Macro::kTypeFunc;
Zhenyao Mod526f982014-05-13 14:51:19 -0700374 do
375 {
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000376 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000377 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000378 break;
Geoff Lang26be18d2015-04-27 14:05:57 -0400379
Olli Etuaho47c27e82017-01-17 15:29:35 +0000380 if (std::find(macro->parameters.begin(), macro->parameters.end(), token->text) !=
381 macro->parameters.end())
Geoff Lang26be18d2015-04-27 14:05:57 -0400382 {
383 mDiagnostics->report(Diagnostics::PP_MACRO_DUPLICATE_PARAMETER_NAMES,
384 token->location, token->text);
385 return;
386 }
387
Olli Etuaho47c27e82017-01-17 15:29:35 +0000388 macro->parameters.push_back(token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000389
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000390 mTokenizer->lex(token); // Get ','.
Jamie Madillf832c9d2016-12-12 17:38:48 -0500391 } while (token->type == ',');
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000392
393 if (token->type != ')')
394 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500395 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000396 return;
397 }
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000398 mTokenizer->lex(token); // Get ')'.
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000399 }
400
alokp@chromium.org7c884542012-05-24 19:13:03 +0000401 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000402 {
403 // Reset the token location because it is unnecessary in replacement
404 // list. Resetting it also allows us to reuse Token::equals() to
405 // compare macros.
406 token->location = SourceLocation();
Olli Etuaho47c27e82017-01-17 15:29:35 +0000407 macro->replacements.push_back(*token);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000408 mTokenizer->lex(token);
409 }
Olli Etuaho47c27e82017-01-17 15:29:35 +0000410 if (!macro->replacements.empty())
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000411 {
412 // Whitespace preceding the replacement list is not considered part of
413 // the replacement list for either form of macro.
Olli Etuaho47c27e82017-01-17 15:29:35 +0000414 macro->replacements.front().setHasLeadingSpace(false);
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000415 }
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000416
417 // Check for macro redefinition.
Olli Etuaho47c27e82017-01-17 15:29:35 +0000418 MacroSet::const_iterator iter = mMacroSet->find(macro->name);
419 if (iter != mMacroSet->end() && !macro->equals(*iter->second))
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000420 {
Olli Etuaho47c27e82017-01-17 15:29:35 +0000421 mDiagnostics->report(Diagnostics::PP_MACRO_REDEFINED, token->location, macro->name);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000422 return;
423 }
Olli Etuaho47c27e82017-01-17 15:29:35 +0000424 mMacroSet->insert(std::make_pair(macro->name, macro));
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000425}
426
Zhenyao Mod526f982014-05-13 14:51:19 -0700427void DirectiveParser::parseUndef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000428{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400429 ASSERT(getDirective(token) == DIRECTIVE_UNDEF);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000430
431 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000432 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000433 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500434 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000435 return;
436 }
437
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000438 MacroSet::iterator iter = mMacroSet->find(token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000439 if (iter != mMacroSet->end())
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000440 {
Olli Etuaho47c27e82017-01-17 15:29:35 +0000441 if (iter->second->predefined)
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000442 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500443 mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_UNDEFINED, token->location,
444 token->text);
Corentin Wallezd2f195b2016-09-19 15:53:33 -0400445 return;
446 }
Olli Etuaho47c27e82017-01-17 15:29:35 +0000447 else if (iter->second->expansionCount > 0)
Corentin Wallezd2f195b2016-09-19 15:53:33 -0400448 {
449 mDiagnostics->report(Diagnostics::PP_MACRO_UNDEFINED_WHILE_INVOKED, token->location,
450 token->text);
451 return;
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000452 }
453 else
454 {
455 mMacroSet->erase(iter);
456 }
457 }
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000458
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000459 mTokenizer->lex(token);
Geoff Langb819d252015-04-27 14:16:34 -0400460 if (!isEOD(token))
461 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500462 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
Geoff Langb819d252015-04-27 14:16:34 -0400463 skipUntilEOD(mTokenizer, token);
464 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000465}
466
Zhenyao Mod526f982014-05-13 14:51:19 -0700467void DirectiveParser::parseIf(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000468{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400469 ASSERT(getDirective(token) == DIRECTIVE_IF);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000470 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000471}
472
Zhenyao Mod526f982014-05-13 14:51:19 -0700473void DirectiveParser::parseIfdef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000474{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400475 ASSERT(getDirective(token) == DIRECTIVE_IFDEF);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000476 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000477}
478
Zhenyao Mod526f982014-05-13 14:51:19 -0700479void DirectiveParser::parseIfndef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000480{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400481 ASSERT(getDirective(token) == DIRECTIVE_IFNDEF);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000482 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000483}
484
Zhenyao Mod526f982014-05-13 14:51:19 -0700485void DirectiveParser::parseElse(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000486{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400487 ASSERT(getDirective(token) == DIRECTIVE_ELSE);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000488
489 if (mConditionalStack.empty())
490 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500491 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_WITHOUT_IF, token->location,
492 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000493 skipUntilEOD(mTokenizer, token);
494 return;
495 }
496
Zhenyao Mod526f982014-05-13 14:51:19 -0700497 ConditionalBlock &block = mConditionalStack.back();
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000498 if (block.skipBlock)
499 {
500 // No diagnostics. Just skip the whole line.
501 skipUntilEOD(mTokenizer, token);
502 return;
503 }
504 if (block.foundElseGroup)
505 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500506 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_AFTER_ELSE, token->location,
507 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000508 skipUntilEOD(mTokenizer, token);
509 return;
510 }
511
Jamie Madillf832c9d2016-12-12 17:38:48 -0500512 block.foundElseGroup = true;
513 block.skipGroup = block.foundValidGroup;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000514 block.foundValidGroup = true;
515
Geoff Lang95a423d2015-04-28 11:09:45 -0400516 // Check if there are extra tokens after #else.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000517 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000518 if (!isEOD(token))
519 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500520 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location,
521 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000522 skipUntilEOD(mTokenizer, token);
523 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000524}
525
Zhenyao Mod526f982014-05-13 14:51:19 -0700526void DirectiveParser::parseElif(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000527{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400528 ASSERT(getDirective(token) == DIRECTIVE_ELIF);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000529
530 if (mConditionalStack.empty())
531 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500532 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_WITHOUT_IF, token->location,
533 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000534 skipUntilEOD(mTokenizer, token);
535 return;
536 }
537
Zhenyao Mod526f982014-05-13 14:51:19 -0700538 ConditionalBlock &block = mConditionalStack.back();
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000539 if (block.skipBlock)
540 {
541 // No diagnostics. Just skip the whole line.
542 skipUntilEOD(mTokenizer, token);
543 return;
544 }
545 if (block.foundElseGroup)
546 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500547 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_AFTER_ELSE, token->location,
548 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000549 skipUntilEOD(mTokenizer, token);
550 return;
551 }
552 if (block.foundValidGroup)
553 {
554 // Do not parse the expression.
555 // Also be careful not to emit a diagnostic.
556 block.skipGroup = true;
557 skipUntilEOD(mTokenizer, token);
558 return;
559 }
560
Jamie Madillf832c9d2016-12-12 17:38:48 -0500561 int expression = parseExpressionIf(token);
562 block.skipGroup = expression == 0;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000563 block.foundValidGroup = expression != 0;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000564}
565
Zhenyao Mod526f982014-05-13 14:51:19 -0700566void DirectiveParser::parseEndif(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000567{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400568 ASSERT(getDirective(token) == DIRECTIVE_ENDIF);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000569
570 if (mConditionalStack.empty())
571 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500572 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ENDIF_WITHOUT_IF, token->location,
573 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000574 skipUntilEOD(mTokenizer, token);
575 return;
576 }
577
578 mConditionalStack.pop_back();
579
Geoff Lang95a423d2015-04-28 11:09:45 -0400580 // Check if there are tokens after #endif.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000581 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000582 if (!isEOD(token))
583 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500584 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location,
585 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000586 skipUntilEOD(mTokenizer, token);
587 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000588}
589
Zhenyao Mod526f982014-05-13 14:51:19 -0700590void DirectiveParser::parseError(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000591{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400592 ASSERT(getDirective(token) == DIRECTIVE_ERROR);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000593
alokp@chromium.org2e818912012-06-29 21:26:03 +0000594 std::ostringstream stream;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000595 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000596 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org36124de82012-05-24 02:17:43 +0000597 {
598 stream << *token;
599 mTokenizer->lex(token);
600 }
601 mDirectiveHandler->handleError(token->location, stream.str());
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000602}
603
alokp@chromium.org36124de82012-05-24 02:17:43 +0000604// Parses pragma of form: #pragma name[(value)].
Zhenyao Mod526f982014-05-13 14:51:19 -0700605void DirectiveParser::parsePragma(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000606{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400607 ASSERT(getDirective(token) == DIRECTIVE_PRAGMA);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000608
609 enum State
610 {
611 PRAGMA_NAME,
612 LEFT_PAREN,
613 PRAGMA_VALUE,
614 RIGHT_PAREN
615 };
616
617 bool valid = true;
618 std::string name, value;
619 int state = PRAGMA_NAME;
620
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000621 mTokenizer->lex(token);
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700622 bool stdgl = token->text == "STDGL";
623 if (stdgl)
624 {
625 mTokenizer->lex(token);
626 }
alokp@chromium.org7c884542012-05-24 19:13:03 +0000627 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org36124de82012-05-24 02:17:43 +0000628 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500629 switch (state++)
alokp@chromium.org36124de82012-05-24 02:17:43 +0000630 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500631 case PRAGMA_NAME:
632 name = token->text;
633 valid = valid && (token->type == Token::IDENTIFIER);
634 break;
635 case LEFT_PAREN:
636 valid = valid && (token->type == '(');
637 break;
638 case PRAGMA_VALUE:
639 value = token->text;
640 valid = valid && (token->type == Token::IDENTIFIER);
641 break;
642 case RIGHT_PAREN:
643 valid = valid && (token->type == ')');
644 break;
645 default:
646 valid = false;
647 break;
alokp@chromium.org36124de82012-05-24 02:17:43 +0000648 }
649 mTokenizer->lex(token);
650 }
651
652 valid = valid && ((state == PRAGMA_NAME) || // Empty pragma.
653 (state == LEFT_PAREN) || // Without value.
654 (state == RIGHT_PAREN + 1)); // With value.
655 if (!valid)
656 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500657 mDiagnostics->report(Diagnostics::PP_UNRECOGNIZED_PRAGMA, token->location, name);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000658 }
659 else if (state > PRAGMA_NAME) // Do not notify for empty pragma.
660 {
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700661 mDirectiveHandler->handlePragma(token->location, name, value, stdgl);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000662 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000663}
664
Zhenyao Mod526f982014-05-13 14:51:19 -0700665void DirectiveParser::parseExtension(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000666{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400667 ASSERT(getDirective(token) == DIRECTIVE_EXTENSION);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000668
669 enum State
670 {
671 EXT_NAME,
672 COLON,
673 EXT_BEHAVIOR
674 };
675
676 bool valid = true;
677 std::string name, behavior;
678 int state = EXT_NAME;
679
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000680 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000681 while ((token->type != '\n') && (token->type != Token::LAST))
682 {
683 switch (state++)
684 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500685 case EXT_NAME:
686 if (valid && (token->type != Token::IDENTIFIER))
687 {
688 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_NAME, token->location,
689 token->text);
690 valid = false;
691 }
692 if (valid)
693 name = token->text;
694 break;
695 case COLON:
696 if (valid && (token->type != ':'))
697 {
698 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
699 token->text);
700 valid = false;
701 }
702 break;
703 case EXT_BEHAVIOR:
704 if (valid && (token->type != Token::IDENTIFIER))
705 {
706 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_BEHAVIOR,
707 token->location, token->text);
708 valid = false;
709 }
710 if (valid)
711 behavior = token->text;
712 break;
713 default:
714 if (valid)
715 {
716 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
717 token->text);
718 valid = false;
719 }
720 break;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000721 }
722 mTokenizer->lex(token);
723 }
724 if (valid && (state != EXT_BEHAVIOR + 1))
725 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500726 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_DIRECTIVE, token->location,
727 token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000728 valid = false;
729 }
Geoff Lang06e24a72015-04-27 14:48:59 -0400730 if (valid && mSeenNonPreprocessorToken)
731 {
Geoff Langb3a6a8f2015-06-23 16:10:14 -0400732 if (mShaderVersion >= 300)
733 {
734 mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL3,
735 token->location, token->text);
736 valid = false;
737 }
738 else
739 {
740 mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1,
741 token->location, token->text);
742 }
Geoff Lang06e24a72015-04-27 14:48:59 -0400743 }
alokp@chromium.org7c884542012-05-24 19:13:03 +0000744 if (valid)
745 mDirectiveHandler->handleExtension(token->location, name, behavior);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000746}
747
Zhenyao Mod526f982014-05-13 14:51:19 -0700748void DirectiveParser::parseVersion(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000749{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400750 ASSERT(getDirective(token) == DIRECTIVE_VERSION);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000751
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000752 if (mPastFirstStatement)
753 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500754 mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_STATEMENT, token->location,
755 token->text);
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000756 skipUntilEOD(mTokenizer, token);
757 return;
758 }
759
alokp@chromium.org7c884542012-05-24 19:13:03 +0000760 enum State
761 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000762 VERSION_NUMBER,
763 VERSION_PROFILE,
764 VERSION_ENDLINE
alokp@chromium.org7c884542012-05-24 19:13:03 +0000765 };
766
Jamie Madillf832c9d2016-12-12 17:38:48 -0500767 bool valid = true;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000768 int version = 0;
Jamie Madillf832c9d2016-12-12 17:38:48 -0500769 int state = VERSION_NUMBER;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000770
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000771 mTokenizer->lex(token);
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000772 while (valid && (token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org7c884542012-05-24 19:13:03 +0000773 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000774 switch (state)
alokp@chromium.org7c884542012-05-24 19:13:03 +0000775 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500776 case VERSION_NUMBER:
777 if (token->type != Token::CONST_INT)
778 {
779 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_NUMBER, token->location,
780 token->text);
781 valid = false;
782 }
783 if (valid && !token->iValue(&version))
784 {
785 mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW, token->location,
786 token->text);
787 valid = false;
788 }
789 if (valid)
790 {
791 state = (version < 300) ? VERSION_ENDLINE : VERSION_PROFILE;
792 }
793 break;
794 case VERSION_PROFILE:
795 if (token->type != Token::IDENTIFIER || token->text != "es")
796 {
797 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE, token->location,
798 token->text);
799 valid = false;
800 }
801 state = VERSION_ENDLINE;
802 break;
803 default:
804 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
805 token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000806 valid = false;
Jamie Madillf832c9d2016-12-12 17:38:48 -0500807 break;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000808 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000809
alokp@chromium.org7c884542012-05-24 19:13:03 +0000810 mTokenizer->lex(token);
811 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000812
813 if (valid && (state != VERSION_ENDLINE))
alokp@chromium.org7c884542012-05-24 19:13:03 +0000814 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500815 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE, token->location,
816 token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000817 valid = false;
818 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000819
Olli Etuahoc378cd82015-05-25 15:21:44 +0300820 if (valid && version >= 300 && token->location.line > 1)
821 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500822 mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_LINE_ESSL3, token->location,
823 token->text);
Olli Etuahoc378cd82015-05-25 15:21:44 +0300824 valid = false;
825 }
826
alokp@chromium.org7c884542012-05-24 19:13:03 +0000827 if (valid)
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000828 {
alokp@chromium.org7c884542012-05-24 19:13:03 +0000829 mDirectiveHandler->handleVersion(token->location, version);
Geoff Langb3a6a8f2015-06-23 16:10:14 -0400830 mShaderVersion = version;
Olli Etuaho6cb4c7f2015-08-13 11:27:17 +0300831 PredefineMacro(mMacroSet, "__VERSION__", version);
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000832 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000833}
834
Zhenyao Mod526f982014-05-13 14:51:19 -0700835void DirectiveParser::parseLine(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000836{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400837 ASSERT(getDirective(token) == DIRECTIVE_LINE);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000838
Jamie Madillf832c9d2016-12-12 17:38:48 -0500839 bool valid = true;
Olli Etuaho247374c2015-09-09 15:07:24 +0300840 bool parsedFileNumber = false;
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000841 int line = 0, file = 0;
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000842
Olli Etuahof1cf5e62016-11-22 17:36:49 +0000843 MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, mMaxMacroExpansionDepth);
Olli Etuaho247374c2015-09-09 15:07:24 +0300844
845 // Lex the first token after "#line" so we can check it for EOD.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000846 macroExpander.lex(token);
Olli Etuaho247374c2015-09-09 15:07:24 +0300847
848 if (isEOD(token))
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000849 {
Olli Etuaho247374c2015-09-09 15:07:24 +0300850 mDiagnostics->report(Diagnostics::PP_INVALID_LINE_DIRECTIVE, token->location, token->text);
851 valid = false;
852 }
853 else
854 {
855 ExpressionParser expressionParser(&macroExpander, mDiagnostics);
856 ExpressionParser::ErrorSettings errorSettings;
857
858 // See GLES3 section 12.42
859 errorSettings.integerLiteralsMustFit32BitSignedRange = true;
860
861 errorSettings.unexpectedIdentifier = Diagnostics::PP_INVALID_LINE_NUMBER;
862 // The first token was lexed earlier to check if it was EOD. Include
863 // the token in parsing for a second time by setting the
864 // parsePresetToken flag to true.
865 expressionParser.parse(token, &line, true, errorSettings, &valid);
866 if (!isEOD(token) && valid)
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000867 {
Olli Etuaho247374c2015-09-09 15:07:24 +0300868 errorSettings.unexpectedIdentifier = Diagnostics::PP_INVALID_FILE_NUMBER;
869 // After parsing the line expression expressionParser has also
870 // advanced to the first token of the file expression - this is the
871 // token that makes the parser reduce the "input" rule for the line
872 // expression and stop. So we're using parsePresetToken = true here
873 // as well.
874 expressionParser.parse(token, &file, true, errorSettings, &valid);
875 parsedFileNumber = true;
876 }
877 if (!isEOD(token))
878 {
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000879 if (valid)
880 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500881 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
882 token->text);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000883 valid = false;
884 }
Olli Etuaho247374c2015-09-09 15:07:24 +0300885 skipUntilEOD(mTokenizer, token);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000886 }
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000887 }
888
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000889 if (valid)
890 {
891 mTokenizer->setLineNumber(line);
Olli Etuaho247374c2015-09-09 15:07:24 +0300892 if (parsedFileNumber)
Zhenyao Mod526f982014-05-13 14:51:19 -0700893 mTokenizer->setFileNumber(file);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000894 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000895}
896
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000897bool DirectiveParser::skipping() const
898{
Zhenyao Mod526f982014-05-13 14:51:19 -0700899 if (mConditionalStack.empty())
900 return false;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000901
Jamie Madillf832c9d2016-12-12 17:38:48 -0500902 const ConditionalBlock &block = mConditionalStack.back();
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000903 return block.skipBlock || block.skipGroup;
904}
905
Zhenyao Mod526f982014-05-13 14:51:19 -0700906void DirectiveParser::parseConditionalIf(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000907{
908 ConditionalBlock block;
Jamie Madillf832c9d2016-12-12 17:38:48 -0500909 block.type = token->text;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000910 block.location = token->location;
911
912 if (skipping())
913 {
914 // This conditional block is inside another conditional group
915 // which is skipped. As a consequence this whole block is skipped.
916 // Be careful not to parse the conditional expression that might
917 // emit a diagnostic.
918 skipUntilEOD(mTokenizer, token);
919 block.skipBlock = true;
920 }
921 else
922 {
923 DirectiveType directive = getDirective(token);
924
925 int expression = 0;
926 switch (directive)
927 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500928 case DIRECTIVE_IF:
929 expression = parseExpressionIf(token);
930 break;
931 case DIRECTIVE_IFDEF:
932 expression = parseExpressionIfdef(token);
933 break;
934 case DIRECTIVE_IFNDEF:
935 expression = parseExpressionIfdef(token) == 0 ? 1 : 0;
936 break;
937 default:
938 UNREACHABLE();
939 break;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000940 }
Jamie Madillf832c9d2016-12-12 17:38:48 -0500941 block.skipGroup = expression == 0;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000942 block.foundValidGroup = expression != 0;
943 }
944 mConditionalStack.push_back(block);
945}
946
Zhenyao Mod526f982014-05-13 14:51:19 -0700947int DirectiveParser::parseExpressionIf(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000948{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400949 ASSERT((getDirective(token) == DIRECTIVE_IF) || (getDirective(token) == DIRECTIVE_ELIF));
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000950
Olli Etuaho1b2f1622016-03-04 15:06:51 +0200951 DefinedParser definedParser(mTokenizer, mMacroSet, mDiagnostics);
Olli Etuahof1cf5e62016-11-22 17:36:49 +0000952 MacroExpander macroExpander(&definedParser, mMacroSet, mDiagnostics, mMaxMacroExpansionDepth);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000953 ExpressionParser expressionParser(&macroExpander, mDiagnostics);
954
955 int expression = 0;
Olli Etuaho247374c2015-09-09 15:07:24 +0300956 ExpressionParser::ErrorSettings errorSettings;
957 errorSettings.integerLiteralsMustFit32BitSignedRange = false;
Jamie Madillf832c9d2016-12-12 17:38:48 -0500958 errorSettings.unexpectedIdentifier = Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN;
Olli Etuaho247374c2015-09-09 15:07:24 +0300959
960 bool valid = true;
961 expressionParser.parse(token, &expression, false, errorSettings, &valid);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000962
Geoff Lang95a423d2015-04-28 11:09:45 -0400963 // Check if there are tokens after #if expression.
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000964 if (!isEOD(token))
965 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500966 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location,
967 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000968 skipUntilEOD(mTokenizer, token);
969 }
970
971 return expression;
972}
973
Zhenyao Mod526f982014-05-13 14:51:19 -0700974int DirectiveParser::parseExpressionIfdef(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000975{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400976 ASSERT((getDirective(token) == DIRECTIVE_IFDEF) || (getDirective(token) == DIRECTIVE_IFNDEF));
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000977
978 mTokenizer->lex(token);
979 if (token->type != Token::IDENTIFIER)
980 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500981 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000982 skipUntilEOD(mTokenizer, token);
983 return 0;
984 }
985
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000986 MacroSet::const_iterator iter = mMacroSet->find(token->text);
Jamie Madillf832c9d2016-12-12 17:38:48 -0500987 int expression = iter != mMacroSet->end() ? 1 : 0;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000988
Geoff Lang95a423d2015-04-28 11:09:45 -0400989 // Check if there are tokens after #ifdef expression.
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000990 mTokenizer->lex(token);
991 if (!isEOD(token))
992 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500993 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location,
994 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000995 skipUntilEOD(mTokenizer, token);
996 }
997 return expression;
998}
999
alokp@chromium.org04d7d222012-05-16 19:24:07 +00001000} // namespace pp