blob: b366a32c88cedfe5e78fbbc1298b83e3e6ec9dcf [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);
134 return iter != macroSet.end() ? iter->second.predefined : false;
135}
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
Zhenyao Mod526f982014-05-13 14:51:19 -0700218void DirectiveParser::lex(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000219{
220 do
221 {
222 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000223
alokp@chromium.org432d6fc2012-06-27 22:13:21 +0000224 if (token->type == Token::PP_HASH)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000225 {
226 parseDirective(token);
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000227 mPastFirstStatement = true;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000228 }
Geoff Lang06e24a72015-04-27 14:48:59 -0400229 else if (!isEOD(token))
230 {
231 mSeenNonPreprocessorToken = true;
232 }
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000233
234 if (token->type == Token::LAST)
235 {
236 if (!mConditionalStack.empty())
237 {
Zhenyao Mod526f982014-05-13 14:51:19 -0700238 const ConditionalBlock &block = mConditionalStack.back();
Jamie Madillf832c9d2016-12-12 17:38:48 -0500239 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNTERMINATED, block.location,
240 block.type);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000241 }
242 break;
243 }
244
Jamie Madillf832c9d2016-12-12 17:38:48 -0500245 } while (skipping() || (token->type == '\n'));
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000246
247 mPastFirstStatement = true;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000248}
249
Zhenyao Mod526f982014-05-13 14:51:19 -0700250void DirectiveParser::parseDirective(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000251{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400252 ASSERT(token->type == Token::PP_HASH);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000253
254 mTokenizer->lex(token);
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000255 if (isEOD(token))
256 {
257 // Empty Directive.
258 return;
259 }
260
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000261 DirectiveType directive = getDirective(token);
262
263 // While in an excluded conditional block/group,
264 // we only parse conditional directives.
265 if (skipping() && !isConditionalDirective(directive))
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000266 {
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000267 skipUntilEOD(mTokenizer, token);
268 return;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000269 }
270
Jamie Madillf832c9d2016-12-12 17:38:48 -0500271 switch (directive)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000272 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500273 case DIRECTIVE_NONE:
274 mDiagnostics->report(Diagnostics::PP_DIRECTIVE_INVALID_NAME, token->location,
275 token->text);
276 skipUntilEOD(mTokenizer, token);
277 break;
278 case DIRECTIVE_DEFINE:
279 parseDefine(token);
280 break;
281 case DIRECTIVE_UNDEF:
282 parseUndef(token);
283 break;
284 case DIRECTIVE_IF:
285 parseIf(token);
286 break;
287 case DIRECTIVE_IFDEF:
288 parseIfdef(token);
289 break;
290 case DIRECTIVE_IFNDEF:
291 parseIfndef(token);
292 break;
293 case DIRECTIVE_ELSE:
294 parseElse(token);
295 break;
296 case DIRECTIVE_ELIF:
297 parseElif(token);
298 break;
299 case DIRECTIVE_ENDIF:
300 parseEndif(token);
301 break;
302 case DIRECTIVE_ERROR:
303 parseError(token);
304 break;
305 case DIRECTIVE_PRAGMA:
306 parsePragma(token);
307 break;
308 case DIRECTIVE_EXTENSION:
309 parseExtension(token);
310 break;
311 case DIRECTIVE_VERSION:
312 parseVersion(token);
313 break;
314 case DIRECTIVE_LINE:
315 parseLine(token);
316 break;
317 default:
318 UNREACHABLE();
319 break;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000320 }
321
322 skipUntilEOD(mTokenizer, token);
323 if (token->type == Token::LAST)
324 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500325 mDiagnostics->report(Diagnostics::PP_EOF_IN_DIRECTIVE, token->location, token->text);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000326 }
327}
328
Zhenyao Mod526f982014-05-13 14:51:19 -0700329void DirectiveParser::parseDefine(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000330{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400331 ASSERT(getDirective(token) == DIRECTIVE_DEFINE);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000332
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000333 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000334 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000335 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500336 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000337 return;
338 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000339 if (isMacroPredefined(token->text, *mMacroSet))
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000340 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500341 mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_REDEFINED, token->location,
342 token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000343 return;
344 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000345 if (isMacroNameReserved(token->text))
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000346 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500347 mDiagnostics->report(Diagnostics::PP_MACRO_NAME_RESERVED, token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000348 return;
349 }
Olli Etuaho2f6ddf32015-09-22 16:10:07 +0300350 // Using double underscores is allowed, but may result in unintended
351 // behavior, so a warning is issued. At the time of writing this was
352 // specified in ESSL 3.10, but the intent judging from Khronos
353 // discussions and dEQP tests was that double underscores should be
354 // allowed in earlier ESSL versions too.
355 if (hasDoubleUnderscores(token->text))
356 {
357 mDiagnostics->report(Diagnostics::PP_WARNING_MACRO_NAME_RESERVED, token->location,
358 token->text);
359 }
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000360
361 Macro macro;
362 macro.type = Macro::kTypeObj;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000363 macro.name = token->text;
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000364
365 mTokenizer->lex(token);
366 if (token->type == '(' && !token->hasLeadingSpace())
367 {
368 // Function-like macro. Collect arguments.
369 macro.type = Macro::kTypeFunc;
Zhenyao Mod526f982014-05-13 14:51:19 -0700370 do
371 {
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000372 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000373 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000374 break;
Geoff Lang26be18d2015-04-27 14:05:57 -0400375
Jamie Madillf832c9d2016-12-12 17:38:48 -0500376 if (std::find(macro.parameters.begin(), macro.parameters.end(), token->text) !=
377 macro.parameters.end())
Geoff Lang26be18d2015-04-27 14:05:57 -0400378 {
379 mDiagnostics->report(Diagnostics::PP_MACRO_DUPLICATE_PARAMETER_NAMES,
380 token->location, token->text);
381 return;
382 }
383
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000384 macro.parameters.push_back(token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000385
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000386 mTokenizer->lex(token); // Get ','.
Jamie Madillf832c9d2016-12-12 17:38:48 -0500387 } while (token->type == ',');
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000388
389 if (token->type != ')')
390 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500391 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000392 return;
393 }
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000394 mTokenizer->lex(token); // Get ')'.
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000395 }
396
alokp@chromium.org7c884542012-05-24 19:13:03 +0000397 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000398 {
399 // Reset the token location because it is unnecessary in replacement
400 // list. Resetting it also allows us to reuse Token::equals() to
401 // compare macros.
402 token->location = SourceLocation();
403 macro.replacements.push_back(*token);
404 mTokenizer->lex(token);
405 }
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000406 if (!macro.replacements.empty())
407 {
408 // Whitespace preceding the replacement list is not considered part of
409 // the replacement list for either form of macro.
410 macro.replacements.front().setHasLeadingSpace(false);
411 }
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000412
413 // Check for macro redefinition.
414 MacroSet::const_iterator iter = mMacroSet->find(macro.name);
415 if (iter != mMacroSet->end() && !macro.equals(iter->second))
416 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500417 mDiagnostics->report(Diagnostics::PP_MACRO_REDEFINED, token->location, macro.name);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000418 return;
419 }
420 mMacroSet->insert(std::make_pair(macro.name, macro));
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000421}
422
Zhenyao Mod526f982014-05-13 14:51:19 -0700423void DirectiveParser::parseUndef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000424{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400425 ASSERT(getDirective(token) == DIRECTIVE_UNDEF);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000426
427 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000428 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000429 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500430 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000431 return;
432 }
433
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000434 MacroSet::iterator iter = mMacroSet->find(token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000435 if (iter != mMacroSet->end())
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000436 {
437 if (iter->second.predefined)
438 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500439 mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_UNDEFINED, token->location,
440 token->text);
Corentin Wallezd2f195b2016-09-19 15:53:33 -0400441 return;
442 }
443 else if (iter->second.expansionCount > 0)
444 {
445 mDiagnostics->report(Diagnostics::PP_MACRO_UNDEFINED_WHILE_INVOKED, token->location,
446 token->text);
447 return;
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000448 }
449 else
450 {
451 mMacroSet->erase(iter);
452 }
453 }
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000454
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000455 mTokenizer->lex(token);
Geoff Langb819d252015-04-27 14:16:34 -0400456 if (!isEOD(token))
457 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500458 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
Geoff Langb819d252015-04-27 14:16:34 -0400459 skipUntilEOD(mTokenizer, token);
460 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000461}
462
Zhenyao Mod526f982014-05-13 14:51:19 -0700463void DirectiveParser::parseIf(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000464{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400465 ASSERT(getDirective(token) == DIRECTIVE_IF);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000466 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000467}
468
Zhenyao Mod526f982014-05-13 14:51:19 -0700469void DirectiveParser::parseIfdef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000470{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400471 ASSERT(getDirective(token) == DIRECTIVE_IFDEF);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000472 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000473}
474
Zhenyao Mod526f982014-05-13 14:51:19 -0700475void DirectiveParser::parseIfndef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000476{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400477 ASSERT(getDirective(token) == DIRECTIVE_IFNDEF);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000478 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000479}
480
Zhenyao Mod526f982014-05-13 14:51:19 -0700481void DirectiveParser::parseElse(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000482{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400483 ASSERT(getDirective(token) == DIRECTIVE_ELSE);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000484
485 if (mConditionalStack.empty())
486 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500487 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_WITHOUT_IF, token->location,
488 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000489 skipUntilEOD(mTokenizer, token);
490 return;
491 }
492
Zhenyao Mod526f982014-05-13 14:51:19 -0700493 ConditionalBlock &block = mConditionalStack.back();
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000494 if (block.skipBlock)
495 {
496 // No diagnostics. Just skip the whole line.
497 skipUntilEOD(mTokenizer, token);
498 return;
499 }
500 if (block.foundElseGroup)
501 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500502 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_AFTER_ELSE, token->location,
503 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000504 skipUntilEOD(mTokenizer, token);
505 return;
506 }
507
Jamie Madillf832c9d2016-12-12 17:38:48 -0500508 block.foundElseGroup = true;
509 block.skipGroup = block.foundValidGroup;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000510 block.foundValidGroup = true;
511
Geoff Lang95a423d2015-04-28 11:09:45 -0400512 // Check if there are extra tokens after #else.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000513 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000514 if (!isEOD(token))
515 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500516 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location,
517 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000518 skipUntilEOD(mTokenizer, token);
519 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000520}
521
Zhenyao Mod526f982014-05-13 14:51:19 -0700522void DirectiveParser::parseElif(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000523{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400524 ASSERT(getDirective(token) == DIRECTIVE_ELIF);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000525
526 if (mConditionalStack.empty())
527 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500528 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_WITHOUT_IF, token->location,
529 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000530 skipUntilEOD(mTokenizer, token);
531 return;
532 }
533
Zhenyao Mod526f982014-05-13 14:51:19 -0700534 ConditionalBlock &block = mConditionalStack.back();
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000535 if (block.skipBlock)
536 {
537 // No diagnostics. Just skip the whole line.
538 skipUntilEOD(mTokenizer, token);
539 return;
540 }
541 if (block.foundElseGroup)
542 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500543 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_AFTER_ELSE, token->location,
544 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000545 skipUntilEOD(mTokenizer, token);
546 return;
547 }
548 if (block.foundValidGroup)
549 {
550 // Do not parse the expression.
551 // Also be careful not to emit a diagnostic.
552 block.skipGroup = true;
553 skipUntilEOD(mTokenizer, token);
554 return;
555 }
556
Jamie Madillf832c9d2016-12-12 17:38:48 -0500557 int expression = parseExpressionIf(token);
558 block.skipGroup = expression == 0;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000559 block.foundValidGroup = expression != 0;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000560}
561
Zhenyao Mod526f982014-05-13 14:51:19 -0700562void DirectiveParser::parseEndif(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000563{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400564 ASSERT(getDirective(token) == DIRECTIVE_ENDIF);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000565
566 if (mConditionalStack.empty())
567 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500568 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ENDIF_WITHOUT_IF, token->location,
569 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000570 skipUntilEOD(mTokenizer, token);
571 return;
572 }
573
574 mConditionalStack.pop_back();
575
Geoff Lang95a423d2015-04-28 11:09:45 -0400576 // Check if there are tokens after #endif.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000577 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000578 if (!isEOD(token))
579 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500580 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location,
581 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000582 skipUntilEOD(mTokenizer, token);
583 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000584}
585
Zhenyao Mod526f982014-05-13 14:51:19 -0700586void DirectiveParser::parseError(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000587{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400588 ASSERT(getDirective(token) == DIRECTIVE_ERROR);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000589
alokp@chromium.org2e818912012-06-29 21:26:03 +0000590 std::ostringstream stream;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000591 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000592 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org36124de82012-05-24 02:17:43 +0000593 {
594 stream << *token;
595 mTokenizer->lex(token);
596 }
597 mDirectiveHandler->handleError(token->location, stream.str());
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000598}
599
alokp@chromium.org36124de82012-05-24 02:17:43 +0000600// Parses pragma of form: #pragma name[(value)].
Zhenyao Mod526f982014-05-13 14:51:19 -0700601void DirectiveParser::parsePragma(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000602{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400603 ASSERT(getDirective(token) == DIRECTIVE_PRAGMA);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000604
605 enum State
606 {
607 PRAGMA_NAME,
608 LEFT_PAREN,
609 PRAGMA_VALUE,
610 RIGHT_PAREN
611 };
612
613 bool valid = true;
614 std::string name, value;
615 int state = PRAGMA_NAME;
616
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000617 mTokenizer->lex(token);
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700618 bool stdgl = token->text == "STDGL";
619 if (stdgl)
620 {
621 mTokenizer->lex(token);
622 }
alokp@chromium.org7c884542012-05-24 19:13:03 +0000623 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org36124de82012-05-24 02:17:43 +0000624 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500625 switch (state++)
alokp@chromium.org36124de82012-05-24 02:17:43 +0000626 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500627 case PRAGMA_NAME:
628 name = token->text;
629 valid = valid && (token->type == Token::IDENTIFIER);
630 break;
631 case LEFT_PAREN:
632 valid = valid && (token->type == '(');
633 break;
634 case PRAGMA_VALUE:
635 value = token->text;
636 valid = valid && (token->type == Token::IDENTIFIER);
637 break;
638 case RIGHT_PAREN:
639 valid = valid && (token->type == ')');
640 break;
641 default:
642 valid = false;
643 break;
alokp@chromium.org36124de82012-05-24 02:17:43 +0000644 }
645 mTokenizer->lex(token);
646 }
647
648 valid = valid && ((state == PRAGMA_NAME) || // Empty pragma.
649 (state == LEFT_PAREN) || // Without value.
650 (state == RIGHT_PAREN + 1)); // With value.
651 if (!valid)
652 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500653 mDiagnostics->report(Diagnostics::PP_UNRECOGNIZED_PRAGMA, token->location, name);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000654 }
655 else if (state > PRAGMA_NAME) // Do not notify for empty pragma.
656 {
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700657 mDirectiveHandler->handlePragma(token->location, name, value, stdgl);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000658 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000659}
660
Zhenyao Mod526f982014-05-13 14:51:19 -0700661void DirectiveParser::parseExtension(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000662{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400663 ASSERT(getDirective(token) == DIRECTIVE_EXTENSION);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000664
665 enum State
666 {
667 EXT_NAME,
668 COLON,
669 EXT_BEHAVIOR
670 };
671
672 bool valid = true;
673 std::string name, behavior;
674 int state = EXT_NAME;
675
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000676 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000677 while ((token->type != '\n') && (token->type != Token::LAST))
678 {
679 switch (state++)
680 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500681 case EXT_NAME:
682 if (valid && (token->type != Token::IDENTIFIER))
683 {
684 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_NAME, token->location,
685 token->text);
686 valid = false;
687 }
688 if (valid)
689 name = token->text;
690 break;
691 case COLON:
692 if (valid && (token->type != ':'))
693 {
694 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
695 token->text);
696 valid = false;
697 }
698 break;
699 case EXT_BEHAVIOR:
700 if (valid && (token->type != Token::IDENTIFIER))
701 {
702 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_BEHAVIOR,
703 token->location, token->text);
704 valid = false;
705 }
706 if (valid)
707 behavior = token->text;
708 break;
709 default:
710 if (valid)
711 {
712 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
713 token->text);
714 valid = false;
715 }
716 break;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000717 }
718 mTokenizer->lex(token);
719 }
720 if (valid && (state != EXT_BEHAVIOR + 1))
721 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500722 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_DIRECTIVE, token->location,
723 token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000724 valid = false;
725 }
Geoff Lang06e24a72015-04-27 14:48:59 -0400726 if (valid && mSeenNonPreprocessorToken)
727 {
Geoff Langb3a6a8f2015-06-23 16:10:14 -0400728 if (mShaderVersion >= 300)
729 {
730 mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL3,
731 token->location, token->text);
732 valid = false;
733 }
734 else
735 {
736 mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1,
737 token->location, token->text);
738 }
Geoff Lang06e24a72015-04-27 14:48:59 -0400739 }
alokp@chromium.org7c884542012-05-24 19:13:03 +0000740 if (valid)
741 mDirectiveHandler->handleExtension(token->location, name, behavior);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000742}
743
Zhenyao Mod526f982014-05-13 14:51:19 -0700744void DirectiveParser::parseVersion(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000745{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400746 ASSERT(getDirective(token) == DIRECTIVE_VERSION);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000747
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000748 if (mPastFirstStatement)
749 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500750 mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_STATEMENT, token->location,
751 token->text);
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000752 skipUntilEOD(mTokenizer, token);
753 return;
754 }
755
alokp@chromium.org7c884542012-05-24 19:13:03 +0000756 enum State
757 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000758 VERSION_NUMBER,
759 VERSION_PROFILE,
760 VERSION_ENDLINE
alokp@chromium.org7c884542012-05-24 19:13:03 +0000761 };
762
Jamie Madillf832c9d2016-12-12 17:38:48 -0500763 bool valid = true;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000764 int version = 0;
Jamie Madillf832c9d2016-12-12 17:38:48 -0500765 int state = VERSION_NUMBER;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000766
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000767 mTokenizer->lex(token);
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000768 while (valid && (token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org7c884542012-05-24 19:13:03 +0000769 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000770 switch (state)
alokp@chromium.org7c884542012-05-24 19:13:03 +0000771 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500772 case VERSION_NUMBER:
773 if (token->type != Token::CONST_INT)
774 {
775 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_NUMBER, token->location,
776 token->text);
777 valid = false;
778 }
779 if (valid && !token->iValue(&version))
780 {
781 mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW, token->location,
782 token->text);
783 valid = false;
784 }
785 if (valid)
786 {
787 state = (version < 300) ? VERSION_ENDLINE : VERSION_PROFILE;
788 }
789 break;
790 case VERSION_PROFILE:
791 if (token->type != Token::IDENTIFIER || token->text != "es")
792 {
793 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE, token->location,
794 token->text);
795 valid = false;
796 }
797 state = VERSION_ENDLINE;
798 break;
799 default:
800 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
801 token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000802 valid = false;
Jamie Madillf832c9d2016-12-12 17:38:48 -0500803 break;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000804 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000805
alokp@chromium.org7c884542012-05-24 19:13:03 +0000806 mTokenizer->lex(token);
807 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000808
809 if (valid && (state != VERSION_ENDLINE))
alokp@chromium.org7c884542012-05-24 19:13:03 +0000810 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500811 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE, token->location,
812 token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000813 valid = false;
814 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000815
Olli Etuahoc378cd82015-05-25 15:21:44 +0300816 if (valid && version >= 300 && token->location.line > 1)
817 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500818 mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_LINE_ESSL3, token->location,
819 token->text);
Olli Etuahoc378cd82015-05-25 15:21:44 +0300820 valid = false;
821 }
822
alokp@chromium.org7c884542012-05-24 19:13:03 +0000823 if (valid)
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000824 {
alokp@chromium.org7c884542012-05-24 19:13:03 +0000825 mDirectiveHandler->handleVersion(token->location, version);
Geoff Langb3a6a8f2015-06-23 16:10:14 -0400826 mShaderVersion = version;
Olli Etuaho6cb4c7f2015-08-13 11:27:17 +0300827 PredefineMacro(mMacroSet, "__VERSION__", version);
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000828 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000829}
830
Zhenyao Mod526f982014-05-13 14:51:19 -0700831void DirectiveParser::parseLine(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000832{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400833 ASSERT(getDirective(token) == DIRECTIVE_LINE);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000834
Jamie Madillf832c9d2016-12-12 17:38:48 -0500835 bool valid = true;
Olli Etuaho247374c2015-09-09 15:07:24 +0300836 bool parsedFileNumber = false;
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000837 int line = 0, file = 0;
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000838
Olli Etuahof1cf5e62016-11-22 17:36:49 +0000839 MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, mMaxMacroExpansionDepth);
Olli Etuaho247374c2015-09-09 15:07:24 +0300840
841 // Lex the first token after "#line" so we can check it for EOD.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000842 macroExpander.lex(token);
Olli Etuaho247374c2015-09-09 15:07:24 +0300843
844 if (isEOD(token))
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000845 {
Olli Etuaho247374c2015-09-09 15:07:24 +0300846 mDiagnostics->report(Diagnostics::PP_INVALID_LINE_DIRECTIVE, token->location, token->text);
847 valid = false;
848 }
849 else
850 {
851 ExpressionParser expressionParser(&macroExpander, mDiagnostics);
852 ExpressionParser::ErrorSettings errorSettings;
853
854 // See GLES3 section 12.42
855 errorSettings.integerLiteralsMustFit32BitSignedRange = true;
856
857 errorSettings.unexpectedIdentifier = Diagnostics::PP_INVALID_LINE_NUMBER;
858 // The first token was lexed earlier to check if it was EOD. Include
859 // the token in parsing for a second time by setting the
860 // parsePresetToken flag to true.
861 expressionParser.parse(token, &line, true, errorSettings, &valid);
862 if (!isEOD(token) && valid)
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000863 {
Olli Etuaho247374c2015-09-09 15:07:24 +0300864 errorSettings.unexpectedIdentifier = Diagnostics::PP_INVALID_FILE_NUMBER;
865 // After parsing the line expression expressionParser has also
866 // advanced to the first token of the file expression - this is the
867 // token that makes the parser reduce the "input" rule for the line
868 // expression and stop. So we're using parsePresetToken = true here
869 // as well.
870 expressionParser.parse(token, &file, true, errorSettings, &valid);
871 parsedFileNumber = true;
872 }
873 if (!isEOD(token))
874 {
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000875 if (valid)
876 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500877 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
878 token->text);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000879 valid = false;
880 }
Olli Etuaho247374c2015-09-09 15:07:24 +0300881 skipUntilEOD(mTokenizer, token);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000882 }
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000883 }
884
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000885 if (valid)
886 {
887 mTokenizer->setLineNumber(line);
Olli Etuaho247374c2015-09-09 15:07:24 +0300888 if (parsedFileNumber)
Zhenyao Mod526f982014-05-13 14:51:19 -0700889 mTokenizer->setFileNumber(file);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000890 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000891}
892
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000893bool DirectiveParser::skipping() const
894{
Zhenyao Mod526f982014-05-13 14:51:19 -0700895 if (mConditionalStack.empty())
896 return false;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000897
Jamie Madillf832c9d2016-12-12 17:38:48 -0500898 const ConditionalBlock &block = mConditionalStack.back();
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000899 return block.skipBlock || block.skipGroup;
900}
901
Zhenyao Mod526f982014-05-13 14:51:19 -0700902void DirectiveParser::parseConditionalIf(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000903{
904 ConditionalBlock block;
Jamie Madillf832c9d2016-12-12 17:38:48 -0500905 block.type = token->text;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000906 block.location = token->location;
907
908 if (skipping())
909 {
910 // This conditional block is inside another conditional group
911 // which is skipped. As a consequence this whole block is skipped.
912 // Be careful not to parse the conditional expression that might
913 // emit a diagnostic.
914 skipUntilEOD(mTokenizer, token);
915 block.skipBlock = true;
916 }
917 else
918 {
919 DirectiveType directive = getDirective(token);
920
921 int expression = 0;
922 switch (directive)
923 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500924 case DIRECTIVE_IF:
925 expression = parseExpressionIf(token);
926 break;
927 case DIRECTIVE_IFDEF:
928 expression = parseExpressionIfdef(token);
929 break;
930 case DIRECTIVE_IFNDEF:
931 expression = parseExpressionIfdef(token) == 0 ? 1 : 0;
932 break;
933 default:
934 UNREACHABLE();
935 break;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000936 }
Jamie Madillf832c9d2016-12-12 17:38:48 -0500937 block.skipGroup = expression == 0;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000938 block.foundValidGroup = expression != 0;
939 }
940 mConditionalStack.push_back(block);
941}
942
Zhenyao Mod526f982014-05-13 14:51:19 -0700943int DirectiveParser::parseExpressionIf(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000944{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400945 ASSERT((getDirective(token) == DIRECTIVE_IF) || (getDirective(token) == DIRECTIVE_ELIF));
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000946
Olli Etuaho1b2f1622016-03-04 15:06:51 +0200947 DefinedParser definedParser(mTokenizer, mMacroSet, mDiagnostics);
Olli Etuahof1cf5e62016-11-22 17:36:49 +0000948 MacroExpander macroExpander(&definedParser, mMacroSet, mDiagnostics, mMaxMacroExpansionDepth);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000949 ExpressionParser expressionParser(&macroExpander, mDiagnostics);
950
951 int expression = 0;
Olli Etuaho247374c2015-09-09 15:07:24 +0300952 ExpressionParser::ErrorSettings errorSettings;
953 errorSettings.integerLiteralsMustFit32BitSignedRange = false;
Jamie Madillf832c9d2016-12-12 17:38:48 -0500954 errorSettings.unexpectedIdentifier = Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN;
Olli Etuaho247374c2015-09-09 15:07:24 +0300955
956 bool valid = true;
957 expressionParser.parse(token, &expression, false, errorSettings, &valid);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000958
Geoff Lang95a423d2015-04-28 11:09:45 -0400959 // Check if there are tokens after #if expression.
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000960 if (!isEOD(token))
961 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500962 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location,
963 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000964 skipUntilEOD(mTokenizer, token);
965 }
966
967 return expression;
968}
969
Zhenyao Mod526f982014-05-13 14:51:19 -0700970int DirectiveParser::parseExpressionIfdef(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000971{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400972 ASSERT((getDirective(token) == DIRECTIVE_IFDEF) || (getDirective(token) == DIRECTIVE_IFNDEF));
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000973
974 mTokenizer->lex(token);
975 if (token->type != Token::IDENTIFIER)
976 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500977 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000978 skipUntilEOD(mTokenizer, token);
979 return 0;
980 }
981
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000982 MacroSet::const_iterator iter = mMacroSet->find(token->text);
Jamie Madillf832c9d2016-12-12 17:38:48 -0500983 int expression = iter != mMacroSet->end() ? 1 : 0;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000984
Geoff Lang95a423d2015-04-28 11:09:45 -0400985 // Check if there are tokens after #ifdef expression.
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000986 mTokenizer->lex(token);
987 if (!isEOD(token))
988 {
Jamie Madillf832c9d2016-12-12 17:38:48 -0500989 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location,
990 token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000991 skipUntilEOD(mTokenizer, token);
992 }
993 return expression;
994}
995
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000996} // namespace pp