blob: a268c8007213d18d976c9e35666b79a4920123b0 [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
21namespace {
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000022enum DirectiveType
23{
24 DIRECTIVE_NONE,
25 DIRECTIVE_DEFINE,
26 DIRECTIVE_UNDEF,
27 DIRECTIVE_IF,
28 DIRECTIVE_IFDEF,
29 DIRECTIVE_IFNDEF,
30 DIRECTIVE_ELSE,
31 DIRECTIVE_ELIF,
32 DIRECTIVE_ENDIF,
33 DIRECTIVE_ERROR,
34 DIRECTIVE_PRAGMA,
35 DIRECTIVE_EXTENSION,
36 DIRECTIVE_VERSION,
37 DIRECTIVE_LINE
38};
alokp@chromium.org04d7d222012-05-16 19:24:07 +000039
Zhenyao Mod526f982014-05-13 14:51:19 -070040DirectiveType getDirective(const pp::Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000041{
Zhenyao Mob5e17752014-10-22 10:57:10 -070042 const char kDirectiveDefine[] = "define";
43 const char kDirectiveUndef[] = "undef";
44 const char kDirectiveIf[] = "if";
45 const char kDirectiveIfdef[] = "ifdef";
46 const char kDirectiveIfndef[] = "ifndef";
47 const char kDirectiveElse[] = "else";
48 const char kDirectiveElif[] = "elif";
49 const char kDirectiveEndif[] = "endif";
50 const char kDirectiveError[] = "error";
51 const char kDirectivePragma[] = "pragma";
52 const char kDirectiveExtension[] = "extension";
53 const char kDirectiveVersion[] = "version";
54 const char kDirectiveLine[] = "line";
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000055
56 if (token->type != pp::Token::IDENTIFIER)
57 return DIRECTIVE_NONE;
58
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +000059 if (token->text == kDirectiveDefine)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000060 return DIRECTIVE_DEFINE;
Zhenyao Mod526f982014-05-13 14:51:19 -070061 if (token->text == kDirectiveUndef)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000062 return DIRECTIVE_UNDEF;
Zhenyao Mod526f982014-05-13 14:51:19 -070063 if (token->text == kDirectiveIf)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000064 return DIRECTIVE_IF;
Zhenyao Mod526f982014-05-13 14:51:19 -070065 if (token->text == kDirectiveIfdef)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000066 return DIRECTIVE_IFDEF;
Zhenyao Mod526f982014-05-13 14:51:19 -070067 if (token->text == kDirectiveIfndef)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000068 return DIRECTIVE_IFNDEF;
Zhenyao Mod526f982014-05-13 14:51:19 -070069 if (token->text == kDirectiveElse)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000070 return DIRECTIVE_ELSE;
Zhenyao Mod526f982014-05-13 14:51:19 -070071 if (token->text == kDirectiveElif)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000072 return DIRECTIVE_ELIF;
Zhenyao Mod526f982014-05-13 14:51:19 -070073 if (token->text == kDirectiveEndif)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000074 return DIRECTIVE_ENDIF;
Zhenyao Mod526f982014-05-13 14:51:19 -070075 if (token->text == kDirectiveError)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000076 return DIRECTIVE_ERROR;
Zhenyao Mod526f982014-05-13 14:51:19 -070077 if (token->text == kDirectivePragma)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000078 return DIRECTIVE_PRAGMA;
Zhenyao Mod526f982014-05-13 14:51:19 -070079 if (token->text == kDirectiveExtension)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000080 return DIRECTIVE_EXTENSION;
Zhenyao Mod526f982014-05-13 14:51:19 -070081 if (token->text == kDirectiveVersion)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000082 return DIRECTIVE_VERSION;
Zhenyao Mod526f982014-05-13 14:51:19 -070083 if (token->text == kDirectiveLine)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000084 return DIRECTIVE_LINE;
85
86 return DIRECTIVE_NONE;
87}
88
Zhenyao Mod526f982014-05-13 14:51:19 -070089bool isConditionalDirective(DirectiveType directive)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000090{
91 switch (directive)
92 {
93 case DIRECTIVE_IF:
94 case DIRECTIVE_IFDEF:
95 case DIRECTIVE_IFNDEF:
96 case DIRECTIVE_ELSE:
97 case DIRECTIVE_ELIF:
98 case DIRECTIVE_ENDIF:
99 return true;
100 default:
101 return false;
102 }
103}
104
105// Returns true if the token represents End Of Directive.
Zhenyao Mod526f982014-05-13 14:51:19 -0700106bool isEOD(const pp::Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000107{
108 return (token->type == '\n') || (token->type == pp::Token::LAST);
109}
110
Zhenyao Mod526f982014-05-13 14:51:19 -0700111void skipUntilEOD(pp::Lexer *lexer, pp::Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000112{
113 while(!isEOD(token))
114 {
115 lexer->lex(token);
116 }
117}
118
Zhenyao Mod526f982014-05-13 14:51:19 -0700119bool isMacroNameReserved(const std::string &name)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000120{
Olli Etuaho4d675ca2016-03-07 14:48:49 +0200121 // Names prefixed with "GL_" and the name "defined" are reserved.
122 return name == "defined" || (name.substr(0, 3) == "GL_");
Olli Etuaho2f6ddf32015-09-22 16:10:07 +0300123}
Geoff Lang4c8cae62015-05-01 16:46:16 +0000124
Olli Etuaho2f6ddf32015-09-22 16:10:07 +0300125bool hasDoubleUnderscores(const std::string &name)
126{
127 return (name.find("__") != std::string::npos);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000128}
129
Zhenyao Mod526f982014-05-13 14:51:19 -0700130bool isMacroPredefined(const std::string &name,
131 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();
Shannon Woods7f2d7942013-11-19 15:07:58 -0500239 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNTERMINATED,
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000240 block.location, block.type);
241 }
242 break;
243 }
244
Zhenyao Mod526f982014-05-13 14:51:19 -0700245 }
246 while (skipping() || (token->type == '\n'));
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000247
248 mPastFirstStatement = true;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000249}
250
Zhenyao Mod526f982014-05-13 14:51:19 -0700251void DirectiveParser::parseDirective(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000252{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400253 ASSERT(token->type == Token::PP_HASH);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000254
255 mTokenizer->lex(token);
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000256 if (isEOD(token))
257 {
258 // Empty Directive.
259 return;
260 }
261
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000262 DirectiveType directive = getDirective(token);
263
264 // While in an excluded conditional block/group,
265 // we only parse conditional directives.
266 if (skipping() && !isConditionalDirective(directive))
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000267 {
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000268 skipUntilEOD(mTokenizer, token);
269 return;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000270 }
271
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000272 switch(directive)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000273 {
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000274 case DIRECTIVE_NONE:
Shannon Woods7f2d7942013-11-19 15:07:58 -0500275 mDiagnostics->report(Diagnostics::PP_DIRECTIVE_INVALID_NAME,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000276 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000277 skipUntilEOD(mTokenizer, token);
278 break;
279 case DIRECTIVE_DEFINE:
280 parseDefine(token);
281 break;
282 case DIRECTIVE_UNDEF:
283 parseUndef(token);
284 break;
285 case DIRECTIVE_IF:
286 parseIf(token);
287 break;
288 case DIRECTIVE_IFDEF:
289 parseIfdef(token);
290 break;
291 case DIRECTIVE_IFNDEF:
292 parseIfndef(token);
293 break;
294 case DIRECTIVE_ELSE:
295 parseElse(token);
296 break;
297 case DIRECTIVE_ELIF:
298 parseElif(token);
299 break;
300 case DIRECTIVE_ENDIF:
301 parseEndif(token);
302 break;
303 case DIRECTIVE_ERROR:
304 parseError(token);
305 break;
306 case DIRECTIVE_PRAGMA:
307 parsePragma(token);
308 break;
309 case DIRECTIVE_EXTENSION:
310 parseExtension(token);
311 break;
312 case DIRECTIVE_VERSION:
313 parseVersion(token);
314 break;
315 case DIRECTIVE_LINE:
316 parseLine(token);
317 break;
318 default:
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400319 UNREACHABLE();
320 break;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000321 }
322
323 skipUntilEOD(mTokenizer, token);
324 if (token->type == Token::LAST)
325 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500326 mDiagnostics->report(Diagnostics::PP_EOF_IN_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000327 token->location, token->text);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000328 }
329}
330
Zhenyao Mod526f982014-05-13 14:51:19 -0700331void DirectiveParser::parseDefine(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000332{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400333 ASSERT(getDirective(token) == DIRECTIVE_DEFINE);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000334
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000335 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000336 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000337 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500338 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000339 token->location, token->text);
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000340 return;
341 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000342 if (isMacroPredefined(token->text, *mMacroSet))
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000343 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500344 mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_REDEFINED,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000345 token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000346 return;
347 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000348 if (isMacroNameReserved(token->text))
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000349 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500350 mDiagnostics->report(Diagnostics::PP_MACRO_NAME_RESERVED,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000351 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
365 Macro macro;
366 macro.type = Macro::kTypeObj;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000367 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.
373 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
380 if (std::find(macro.parameters.begin(), macro.parameters.end(), token->text) != macro.parameters.end())
381 {
382 mDiagnostics->report(Diagnostics::PP_MACRO_DUPLICATE_PARAMETER_NAMES,
383 token->location, token->text);
384 return;
385 }
386
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000387 macro.parameters.push_back(token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000388
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000389 mTokenizer->lex(token); // Get ','.
Zhenyao Mod526f982014-05-13 14:51:19 -0700390 }
391 while (token->type == ',');
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000392
393 if (token->type != ')')
394 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500395 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000396 token->location,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000397 token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000398 return;
399 }
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000400 mTokenizer->lex(token); // Get ')'.
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000401 }
402
alokp@chromium.org7c884542012-05-24 19:13:03 +0000403 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000404 {
405 // Reset the token location because it is unnecessary in replacement
406 // list. Resetting it also allows us to reuse Token::equals() to
407 // compare macros.
408 token->location = SourceLocation();
409 macro.replacements.push_back(*token);
410 mTokenizer->lex(token);
411 }
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000412 if (!macro.replacements.empty())
413 {
414 // Whitespace preceding the replacement list is not considered part of
415 // the replacement list for either form of macro.
416 macro.replacements.front().setHasLeadingSpace(false);
417 }
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000418
419 // Check for macro redefinition.
420 MacroSet::const_iterator iter = mMacroSet->find(macro.name);
421 if (iter != mMacroSet->end() && !macro.equals(iter->second))
422 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500423 mDiagnostics->report(Diagnostics::PP_MACRO_REDEFINED,
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000424 token->location,
425 macro.name);
426 return;
427 }
428 mMacroSet->insert(std::make_pair(macro.name, macro));
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000429}
430
Zhenyao Mod526f982014-05-13 14:51:19 -0700431void DirectiveParser::parseUndef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000432{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400433 ASSERT(getDirective(token) == DIRECTIVE_UNDEF);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000434
435 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000436 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000437 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500438 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000439 token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000440 return;
441 }
442
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000443 MacroSet::iterator iter = mMacroSet->find(token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000444 if (iter != mMacroSet->end())
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000445 {
446 if (iter->second.predefined)
447 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500448 mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_UNDEFINED,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000449 token->location, token->text);
Corentin Wallezd2f195b2016-09-19 15:53:33 -0400450 return;
451 }
452 else if (iter->second.expansionCount > 0)
453 {
454 mDiagnostics->report(Diagnostics::PP_MACRO_UNDEFINED_WHILE_INVOKED, token->location,
455 token->text);
456 return;
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000457 }
458 else
459 {
460 mMacroSet->erase(iter);
461 }
462 }
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000463
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000464 mTokenizer->lex(token);
Geoff Langb819d252015-04-27 14:16:34 -0400465 if (!isEOD(token))
466 {
467 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
468 token->location, token->text);
469 skipUntilEOD(mTokenizer, token);
470 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000471}
472
Zhenyao Mod526f982014-05-13 14:51:19 -0700473void DirectiveParser::parseIf(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000474{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400475 ASSERT(getDirective(token) == DIRECTIVE_IF);
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::parseIfdef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000480{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400481 ASSERT(getDirective(token) == DIRECTIVE_IFDEF);
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::parseIfndef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000486{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400487 ASSERT(getDirective(token) == DIRECTIVE_IFNDEF);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000488 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000489}
490
Zhenyao Mod526f982014-05-13 14:51:19 -0700491void DirectiveParser::parseElse(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000492{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400493 ASSERT(getDirective(token) == DIRECTIVE_ELSE);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000494
495 if (mConditionalStack.empty())
496 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500497 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_WITHOUT_IF,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000498 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000499 skipUntilEOD(mTokenizer, token);
500 return;
501 }
502
Zhenyao Mod526f982014-05-13 14:51:19 -0700503 ConditionalBlock &block = mConditionalStack.back();
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000504 if (block.skipBlock)
505 {
506 // No diagnostics. Just skip the whole line.
507 skipUntilEOD(mTokenizer, token);
508 return;
509 }
510 if (block.foundElseGroup)
511 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500512 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_AFTER_ELSE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000513 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000514 skipUntilEOD(mTokenizer, token);
515 return;
516 }
517
518 block.foundElseGroup = true;
519 block.skipGroup = block.foundValidGroup;
520 block.foundValidGroup = true;
521
Geoff Lang95a423d2015-04-28 11:09:45 -0400522 // Check if there are extra tokens after #else.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000523 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000524 if (!isEOD(token))
525 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500526 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000527 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000528 skipUntilEOD(mTokenizer, token);
529 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000530}
531
Zhenyao Mod526f982014-05-13 14:51:19 -0700532void DirectiveParser::parseElif(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000533{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400534 ASSERT(getDirective(token) == DIRECTIVE_ELIF);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000535
536 if (mConditionalStack.empty())
537 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500538 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_WITHOUT_IF,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000539 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000540 skipUntilEOD(mTokenizer, token);
541 return;
542 }
543
Zhenyao Mod526f982014-05-13 14:51:19 -0700544 ConditionalBlock &block = mConditionalStack.back();
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000545 if (block.skipBlock)
546 {
547 // No diagnostics. Just skip the whole line.
548 skipUntilEOD(mTokenizer, token);
549 return;
550 }
551 if (block.foundElseGroup)
552 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500553 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_AFTER_ELSE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000554 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000555 skipUntilEOD(mTokenizer, token);
556 return;
557 }
558 if (block.foundValidGroup)
559 {
560 // Do not parse the expression.
561 // Also be careful not to emit a diagnostic.
562 block.skipGroup = true;
563 skipUntilEOD(mTokenizer, token);
564 return;
565 }
566
567 int expression = parseExpressionIf(token);
568 block.skipGroup = expression == 0;
569 block.foundValidGroup = expression != 0;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000570}
571
Zhenyao Mod526f982014-05-13 14:51:19 -0700572void DirectiveParser::parseEndif(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000573{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400574 ASSERT(getDirective(token) == DIRECTIVE_ENDIF);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000575
576 if (mConditionalStack.empty())
577 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500578 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ENDIF_WITHOUT_IF,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000579 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000580 skipUntilEOD(mTokenizer, token);
581 return;
582 }
583
584 mConditionalStack.pop_back();
585
Geoff Lang95a423d2015-04-28 11:09:45 -0400586 // Check if there are tokens after #endif.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000587 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000588 if (!isEOD(token))
589 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500590 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000591 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000592 skipUntilEOD(mTokenizer, token);
593 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000594}
595
Zhenyao Mod526f982014-05-13 14:51:19 -0700596void DirectiveParser::parseError(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000597{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400598 ASSERT(getDirective(token) == DIRECTIVE_ERROR);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000599
alokp@chromium.org2e818912012-06-29 21:26:03 +0000600 std::ostringstream stream;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000601 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000602 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org36124de82012-05-24 02:17:43 +0000603 {
604 stream << *token;
605 mTokenizer->lex(token);
606 }
607 mDirectiveHandler->handleError(token->location, stream.str());
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000608}
609
alokp@chromium.org36124de82012-05-24 02:17:43 +0000610// Parses pragma of form: #pragma name[(value)].
Zhenyao Mod526f982014-05-13 14:51:19 -0700611void DirectiveParser::parsePragma(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000612{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400613 ASSERT(getDirective(token) == DIRECTIVE_PRAGMA);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000614
615 enum State
616 {
617 PRAGMA_NAME,
618 LEFT_PAREN,
619 PRAGMA_VALUE,
620 RIGHT_PAREN
621 };
622
623 bool valid = true;
624 std::string name, value;
625 int state = PRAGMA_NAME;
626
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000627 mTokenizer->lex(token);
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700628 bool stdgl = token->text == "STDGL";
629 if (stdgl)
630 {
631 mTokenizer->lex(token);
632 }
alokp@chromium.org7c884542012-05-24 19:13:03 +0000633 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org36124de82012-05-24 02:17:43 +0000634 {
635 switch(state++)
636 {
637 case PRAGMA_NAME:
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000638 name = token->text;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000639 valid = valid && (token->type == Token::IDENTIFIER);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000640 break;
641 case LEFT_PAREN:
642 valid = valid && (token->type == '(');
643 break;
644 case PRAGMA_VALUE:
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000645 value = token->text;
Olli Etuaho391befe2015-08-12 16:30:38 +0300646 valid = valid && (token->type == Token::IDENTIFIER);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000647 break;
648 case RIGHT_PAREN:
649 valid = valid && (token->type == ')');
650 break;
651 default:
652 valid = false;
653 break;
654 }
655 mTokenizer->lex(token);
656 }
657
658 valid = valid && ((state == PRAGMA_NAME) || // Empty pragma.
659 (state == LEFT_PAREN) || // Without value.
660 (state == RIGHT_PAREN + 1)); // With value.
661 if (!valid)
662 {
Olli Etuaho391befe2015-08-12 16:30:38 +0300663 mDiagnostics->report(Diagnostics::PP_UNRECOGNIZED_PRAGMA,
alokp@chromium.org36124de82012-05-24 02:17:43 +0000664 token->location, name);
665 }
666 else if (state > PRAGMA_NAME) // Do not notify for empty pragma.
667 {
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700668 mDirectiveHandler->handlePragma(token->location, name, value, stdgl);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000669 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000670}
671
Zhenyao Mod526f982014-05-13 14:51:19 -0700672void DirectiveParser::parseExtension(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000673{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400674 ASSERT(getDirective(token) == DIRECTIVE_EXTENSION);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000675
676 enum State
677 {
678 EXT_NAME,
679 COLON,
680 EXT_BEHAVIOR
681 };
682
683 bool valid = true;
684 std::string name, behavior;
685 int state = EXT_NAME;
686
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000687 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000688 while ((token->type != '\n') && (token->type != Token::LAST))
689 {
690 switch (state++)
691 {
692 case EXT_NAME:
693 if (valid && (token->type != Token::IDENTIFIER))
694 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500695 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_NAME,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000696 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000697 valid = false;
698 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000699 if (valid) name = token->text;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000700 break;
701 case COLON:
702 if (valid && (token->type != ':'))
703 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500704 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000705 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000706 valid = false;
707 }
708 break;
709 case EXT_BEHAVIOR:
710 if (valid && (token->type != Token::IDENTIFIER))
711 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500712 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_BEHAVIOR,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000713 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000714 valid = false;
715 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000716 if (valid) behavior = token->text;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000717 break;
718 default:
719 if (valid)
720 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500721 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000722 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000723 valid = false;
724 }
725 break;
726 }
727 mTokenizer->lex(token);
728 }
729 if (valid && (state != EXT_BEHAVIOR + 1))
730 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500731 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000732 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000733 valid = false;
734 }
Geoff Lang06e24a72015-04-27 14:48:59 -0400735 if (valid && mSeenNonPreprocessorToken)
736 {
Geoff Langb3a6a8f2015-06-23 16:10:14 -0400737 if (mShaderVersion >= 300)
738 {
739 mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL3,
740 token->location, token->text);
741 valid = false;
742 }
743 else
744 {
745 mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1,
746 token->location, token->text);
747 }
Geoff Lang06e24a72015-04-27 14:48:59 -0400748 }
alokp@chromium.org7c884542012-05-24 19:13:03 +0000749 if (valid)
750 mDirectiveHandler->handleExtension(token->location, name, behavior);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000751}
752
Zhenyao Mod526f982014-05-13 14:51:19 -0700753void DirectiveParser::parseVersion(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000754{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400755 ASSERT(getDirective(token) == DIRECTIVE_VERSION);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000756
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000757 if (mPastFirstStatement)
758 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500759 mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_STATEMENT,
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000760 token->location, token->text);
761 skipUntilEOD(mTokenizer, token);
762 return;
763 }
764
alokp@chromium.org7c884542012-05-24 19:13:03 +0000765 enum State
766 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000767 VERSION_NUMBER,
768 VERSION_PROFILE,
769 VERSION_ENDLINE
alokp@chromium.org7c884542012-05-24 19:13:03 +0000770 };
771
772 bool valid = true;
773 int version = 0;
774 int state = VERSION_NUMBER;
775
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000776 mTokenizer->lex(token);
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000777 while (valid && (token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org7c884542012-05-24 19:13:03 +0000778 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000779 switch (state)
alokp@chromium.org7c884542012-05-24 19:13:03 +0000780 {
781 case VERSION_NUMBER:
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000782 if (token->type != Token::CONST_INT)
alokp@chromium.org7c884542012-05-24 19:13:03 +0000783 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500784 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_NUMBER,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000785 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000786 valid = false;
787 }
alokp@chromium.org2e818912012-06-29 21:26:03 +0000788 if (valid && !token->iValue(&version))
789 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500790 mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW,
alokp@chromium.org2e818912012-06-29 21:26:03 +0000791 token->location, token->text);
792 valid = false;
793 }
alokp@chromium.org7c884542012-05-24 19:13:03 +0000794 if (valid)
795 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000796 state = (version < 300) ? VERSION_ENDLINE : VERSION_PROFILE;
797 }
798 break;
799 case VERSION_PROFILE:
800 if (token->type != Token::IDENTIFIER || token->text != "es")
801 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500802 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000803 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000804 valid = false;
805 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000806 state = VERSION_ENDLINE;
807 break;
808 default:
Shannon Woods7f2d7942013-11-19 15:07:58 -0500809 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000810 token->location, token->text);
811 valid = false;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000812 break;
813 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000814
alokp@chromium.org7c884542012-05-24 19:13:03 +0000815 mTokenizer->lex(token);
816 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000817
818 if (valid && (state != VERSION_ENDLINE))
alokp@chromium.org7c884542012-05-24 19:13:03 +0000819 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500820 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000821 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000822 valid = false;
823 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000824
Olli Etuahoc378cd82015-05-25 15:21:44 +0300825 if (valid && version >= 300 && token->location.line > 1)
826 {
827 mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_LINE_ESSL3,
828 token->location, token->text);
829 valid = false;
830 }
831
alokp@chromium.org7c884542012-05-24 19:13:03 +0000832 if (valid)
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000833 {
alokp@chromium.org7c884542012-05-24 19:13:03 +0000834 mDirectiveHandler->handleVersion(token->location, version);
Geoff Langb3a6a8f2015-06-23 16:10:14 -0400835 mShaderVersion = version;
Olli Etuaho6cb4c7f2015-08-13 11:27:17 +0300836 PredefineMacro(mMacroSet, "__VERSION__", version);
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000837 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000838}
839
Zhenyao Mod526f982014-05-13 14:51:19 -0700840void DirectiveParser::parseLine(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000841{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400842 ASSERT(getDirective(token) == DIRECTIVE_LINE);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000843
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000844 bool valid = true;
Olli Etuaho247374c2015-09-09 15:07:24 +0300845 bool parsedFileNumber = false;
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000846 int line = 0, file = 0;
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000847
Olli Etuahof1cf5e62016-11-22 17:36:49 +0000848 MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, mMaxMacroExpansionDepth);
Olli Etuaho247374c2015-09-09 15:07:24 +0300849
850 // Lex the first token after "#line" so we can check it for EOD.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000851 macroExpander.lex(token);
Olli Etuaho247374c2015-09-09 15:07:24 +0300852
853 if (isEOD(token))
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000854 {
Olli Etuaho247374c2015-09-09 15:07:24 +0300855 mDiagnostics->report(Diagnostics::PP_INVALID_LINE_DIRECTIVE, token->location, token->text);
856 valid = false;
857 }
858 else
859 {
860 ExpressionParser expressionParser(&macroExpander, mDiagnostics);
861 ExpressionParser::ErrorSettings errorSettings;
862
863 // See GLES3 section 12.42
864 errorSettings.integerLiteralsMustFit32BitSignedRange = true;
865
866 errorSettings.unexpectedIdentifier = Diagnostics::PP_INVALID_LINE_NUMBER;
867 // The first token was lexed earlier to check if it was EOD. Include
868 // the token in parsing for a second time by setting the
869 // parsePresetToken flag to true.
870 expressionParser.parse(token, &line, true, errorSettings, &valid);
871 if (!isEOD(token) && valid)
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000872 {
Olli Etuaho247374c2015-09-09 15:07:24 +0300873 errorSettings.unexpectedIdentifier = Diagnostics::PP_INVALID_FILE_NUMBER;
874 // After parsing the line expression expressionParser has also
875 // advanced to the first token of the file expression - this is the
876 // token that makes the parser reduce the "input" rule for the line
877 // expression and stop. So we're using parsePresetToken = true here
878 // as well.
879 expressionParser.parse(token, &file, true, errorSettings, &valid);
880 parsedFileNumber = true;
881 }
882 if (!isEOD(token))
883 {
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000884 if (valid)
885 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500886 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000887 token->location, token->text);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000888 valid = false;
889 }
Olli Etuaho247374c2015-09-09 15:07:24 +0300890 skipUntilEOD(mTokenizer, token);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000891 }
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000892 }
893
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000894 if (valid)
895 {
896 mTokenizer->setLineNumber(line);
Olli Etuaho247374c2015-09-09 15:07:24 +0300897 if (parsedFileNumber)
Zhenyao Mod526f982014-05-13 14:51:19 -0700898 mTokenizer->setFileNumber(file);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000899 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000900}
901
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000902bool DirectiveParser::skipping() const
903{
Zhenyao Mod526f982014-05-13 14:51:19 -0700904 if (mConditionalStack.empty())
905 return false;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000906
907 const ConditionalBlock& block = mConditionalStack.back();
908 return block.skipBlock || block.skipGroup;
909}
910
Zhenyao Mod526f982014-05-13 14:51:19 -0700911void DirectiveParser::parseConditionalIf(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000912{
913 ConditionalBlock block;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000914 block.type = token->text;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000915 block.location = token->location;
916
917 if (skipping())
918 {
919 // This conditional block is inside another conditional group
920 // which is skipped. As a consequence this whole block is skipped.
921 // Be careful not to parse the conditional expression that might
922 // emit a diagnostic.
923 skipUntilEOD(mTokenizer, token);
924 block.skipBlock = true;
925 }
926 else
927 {
928 DirectiveType directive = getDirective(token);
929
930 int expression = 0;
931 switch (directive)
932 {
933 case DIRECTIVE_IF:
934 expression = parseExpressionIf(token);
935 break;
936 case DIRECTIVE_IFDEF:
937 expression = parseExpressionIfdef(token);
938 break;
939 case DIRECTIVE_IFNDEF:
940 expression = parseExpressionIfdef(token) == 0 ? 1 : 0;
941 break;
942 default:
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400943 UNREACHABLE();
944 break;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000945 }
946 block.skipGroup = expression == 0;
947 block.foundValidGroup = expression != 0;
948 }
949 mConditionalStack.push_back(block);
950}
951
Zhenyao Mod526f982014-05-13 14:51:19 -0700952int DirectiveParser::parseExpressionIf(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000953{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400954 ASSERT((getDirective(token) == DIRECTIVE_IF) || (getDirective(token) == DIRECTIVE_ELIF));
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000955
Olli Etuaho1b2f1622016-03-04 15:06:51 +0200956 DefinedParser definedParser(mTokenizer, mMacroSet, mDiagnostics);
Olli Etuahof1cf5e62016-11-22 17:36:49 +0000957 MacroExpander macroExpander(&definedParser, mMacroSet, mDiagnostics, mMaxMacroExpansionDepth);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000958 ExpressionParser expressionParser(&macroExpander, mDiagnostics);
959
960 int expression = 0;
Olli Etuaho247374c2015-09-09 15:07:24 +0300961 ExpressionParser::ErrorSettings errorSettings;
962 errorSettings.integerLiteralsMustFit32BitSignedRange = false;
963 errorSettings.unexpectedIdentifier = Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN;
964
965 bool valid = true;
966 expressionParser.parse(token, &expression, false, errorSettings, &valid);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000967
Geoff Lang95a423d2015-04-28 11:09:45 -0400968 // Check if there are tokens after #if expression.
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000969 if (!isEOD(token))
970 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500971 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000972 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000973 skipUntilEOD(mTokenizer, token);
974 }
975
976 return expression;
977}
978
Zhenyao Mod526f982014-05-13 14:51:19 -0700979int DirectiveParser::parseExpressionIfdef(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000980{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400981 ASSERT((getDirective(token) == DIRECTIVE_IFDEF) || (getDirective(token) == DIRECTIVE_IFNDEF));
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000982
983 mTokenizer->lex(token);
984 if (token->type != Token::IDENTIFIER)
985 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500986 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000987 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000988 skipUntilEOD(mTokenizer, token);
989 return 0;
990 }
991
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000992 MacroSet::const_iterator iter = mMacroSet->find(token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000993 int expression = iter != mMacroSet->end() ? 1 : 0;
994
Geoff Lang95a423d2015-04-28 11:09:45 -0400995 // Check if there are tokens after #ifdef expression.
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000996 mTokenizer->lex(token);
997 if (!isEOD(token))
998 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500999 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +00001000 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +00001001 skipUntilEOD(mTokenizer, token);
1002 }
1003 return expression;
1004}
1005
alokp@chromium.org04d7d222012-05-16 19:24:07 +00001006} // namespace pp