blob: 643f73bd97a895dbcdd2b7a2fbf4173951f166c9 [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,
205 DirectiveHandler *directiveHandler)
206 : mPastFirstStatement(false),
Geoff Lang06e24a72015-04-27 14:48:59 -0400207 mSeenNonPreprocessorToken(false),
Zhenyao Mod526f982014-05-13 14:51:19 -0700208 mTokenizer(tokenizer),
209 mMacroSet(macroSet),
210 mDiagnostics(diagnostics),
Geoff Langb3a6a8f2015-06-23 16:10:14 -0400211 mDirectiveHandler(directiveHandler),
212 mShaderVersion(100)
alokp@chromium.org2c958ee2012-05-17 20:35:42 +0000213{
214}
215
Zhenyao Mod526f982014-05-13 14:51:19 -0700216void DirectiveParser::lex(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000217{
218 do
219 {
220 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000221
alokp@chromium.org432d6fc2012-06-27 22:13:21 +0000222 if (token->type == Token::PP_HASH)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000223 {
224 parseDirective(token);
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000225 mPastFirstStatement = true;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000226 }
Geoff Lang06e24a72015-04-27 14:48:59 -0400227 else if (!isEOD(token))
228 {
229 mSeenNonPreprocessorToken = true;
230 }
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000231
232 if (token->type == Token::LAST)
233 {
234 if (!mConditionalStack.empty())
235 {
Zhenyao Mod526f982014-05-13 14:51:19 -0700236 const ConditionalBlock &block = mConditionalStack.back();
Shannon Woods7f2d7942013-11-19 15:07:58 -0500237 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNTERMINATED,
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000238 block.location, block.type);
239 }
240 break;
241 }
242
Zhenyao Mod526f982014-05-13 14:51:19 -0700243 }
244 while (skipping() || (token->type == '\n'));
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000245
246 mPastFirstStatement = true;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000247}
248
Zhenyao Mod526f982014-05-13 14:51:19 -0700249void DirectiveParser::parseDirective(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000250{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400251 ASSERT(token->type == Token::PP_HASH);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000252
253 mTokenizer->lex(token);
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000254 if (isEOD(token))
255 {
256 // Empty Directive.
257 return;
258 }
259
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000260 DirectiveType directive = getDirective(token);
261
262 // While in an excluded conditional block/group,
263 // we only parse conditional directives.
264 if (skipping() && !isConditionalDirective(directive))
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000265 {
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000266 skipUntilEOD(mTokenizer, token);
267 return;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000268 }
269
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000270 switch(directive)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000271 {
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000272 case DIRECTIVE_NONE:
Shannon Woods7f2d7942013-11-19 15:07:58 -0500273 mDiagnostics->report(Diagnostics::PP_DIRECTIVE_INVALID_NAME,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000274 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000275 skipUntilEOD(mTokenizer, token);
276 break;
277 case DIRECTIVE_DEFINE:
278 parseDefine(token);
279 break;
280 case DIRECTIVE_UNDEF:
281 parseUndef(token);
282 break;
283 case DIRECTIVE_IF:
284 parseIf(token);
285 break;
286 case DIRECTIVE_IFDEF:
287 parseIfdef(token);
288 break;
289 case DIRECTIVE_IFNDEF:
290 parseIfndef(token);
291 break;
292 case DIRECTIVE_ELSE:
293 parseElse(token);
294 break;
295 case DIRECTIVE_ELIF:
296 parseElif(token);
297 break;
298 case DIRECTIVE_ENDIF:
299 parseEndif(token);
300 break;
301 case DIRECTIVE_ERROR:
302 parseError(token);
303 break;
304 case DIRECTIVE_PRAGMA:
305 parsePragma(token);
306 break;
307 case DIRECTIVE_EXTENSION:
308 parseExtension(token);
309 break;
310 case DIRECTIVE_VERSION:
311 parseVersion(token);
312 break;
313 case DIRECTIVE_LINE:
314 parseLine(token);
315 break;
316 default:
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400317 UNREACHABLE();
318 break;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000319 }
320
321 skipUntilEOD(mTokenizer, token);
322 if (token->type == Token::LAST)
323 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500324 mDiagnostics->report(Diagnostics::PP_EOF_IN_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000325 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 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500336 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000337 token->location, token->text);
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000338 return;
339 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000340 if (isMacroPredefined(token->text, *mMacroSet))
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000341 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500342 mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_REDEFINED,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000343 token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000344 return;
345 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000346 if (isMacroNameReserved(token->text))
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000347 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500348 mDiagnostics->report(Diagnostics::PP_MACRO_NAME_RESERVED,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000349 token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000350 return;
351 }
Olli Etuaho2f6ddf32015-09-22 16:10:07 +0300352 // Using double underscores is allowed, but may result in unintended
353 // behavior, so a warning is issued. At the time of writing this was
354 // specified in ESSL 3.10, but the intent judging from Khronos
355 // discussions and dEQP tests was that double underscores should be
356 // allowed in earlier ESSL versions too.
357 if (hasDoubleUnderscores(token->text))
358 {
359 mDiagnostics->report(Diagnostics::PP_WARNING_MACRO_NAME_RESERVED, token->location,
360 token->text);
361 }
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000362
363 Macro macro;
364 macro.type = Macro::kTypeObj;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000365 macro.name = token->text;
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000366
367 mTokenizer->lex(token);
368 if (token->type == '(' && !token->hasLeadingSpace())
369 {
370 // Function-like macro. Collect arguments.
371 macro.type = Macro::kTypeFunc;
Zhenyao Mod526f982014-05-13 14:51:19 -0700372 do
373 {
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000374 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000375 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000376 break;
Geoff Lang26be18d2015-04-27 14:05:57 -0400377
378 if (std::find(macro.parameters.begin(), macro.parameters.end(), token->text) != macro.parameters.end())
379 {
380 mDiagnostics->report(Diagnostics::PP_MACRO_DUPLICATE_PARAMETER_NAMES,
381 token->location, token->text);
382 return;
383 }
384
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000385 macro.parameters.push_back(token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000386
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000387 mTokenizer->lex(token); // Get ','.
Zhenyao Mod526f982014-05-13 14:51:19 -0700388 }
389 while (token->type == ',');
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000390
391 if (token->type != ')')
392 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500393 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000394 token->location,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000395 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();
407 macro.replacements.push_back(*token);
408 mTokenizer->lex(token);
409 }
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000410 if (!macro.replacements.empty())
411 {
412 // Whitespace preceding the replacement list is not considered part of
413 // the replacement list for either form of macro.
414 macro.replacements.front().setHasLeadingSpace(false);
415 }
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000416
417 // Check for macro redefinition.
418 MacroSet::const_iterator iter = mMacroSet->find(macro.name);
419 if (iter != mMacroSet->end() && !macro.equals(iter->second))
420 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500421 mDiagnostics->report(Diagnostics::PP_MACRO_REDEFINED,
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000422 token->location,
423 macro.name);
424 return;
425 }
426 mMacroSet->insert(std::make_pair(macro.name, macro));
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000427}
428
Zhenyao Mod526f982014-05-13 14:51:19 -0700429void DirectiveParser::parseUndef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000430{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400431 ASSERT(getDirective(token) == DIRECTIVE_UNDEF);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000432
433 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000434 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000435 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500436 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000437 token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000438 return;
439 }
440
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000441 MacroSet::iterator iter = mMacroSet->find(token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000442 if (iter != mMacroSet->end())
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000443 {
444 if (iter->second.predefined)
445 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500446 mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_UNDEFINED,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000447 token->location, token->text);
Corentin Wallezd2f195b2016-09-19 15:53:33 -0400448 return;
449 }
450 else if (iter->second.expansionCount > 0)
451 {
452 mDiagnostics->report(Diagnostics::PP_MACRO_UNDEFINED_WHILE_INVOKED, token->location,
453 token->text);
454 return;
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000455 }
456 else
457 {
458 mMacroSet->erase(iter);
459 }
460 }
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000461
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000462 mTokenizer->lex(token);
Geoff Langb819d252015-04-27 14:16:34 -0400463 if (!isEOD(token))
464 {
465 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
466 token->location, token->text);
467 skipUntilEOD(mTokenizer, token);
468 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000469}
470
Zhenyao Mod526f982014-05-13 14:51:19 -0700471void DirectiveParser::parseIf(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000472{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400473 ASSERT(getDirective(token) == DIRECTIVE_IF);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000474 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000475}
476
Zhenyao Mod526f982014-05-13 14:51:19 -0700477void DirectiveParser::parseIfdef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000478{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400479 ASSERT(getDirective(token) == DIRECTIVE_IFDEF);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000480 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000481}
482
Zhenyao Mod526f982014-05-13 14:51:19 -0700483void DirectiveParser::parseIfndef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000484{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400485 ASSERT(getDirective(token) == DIRECTIVE_IFNDEF);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000486 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000487}
488
Zhenyao Mod526f982014-05-13 14:51:19 -0700489void DirectiveParser::parseElse(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000490{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400491 ASSERT(getDirective(token) == DIRECTIVE_ELSE);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000492
493 if (mConditionalStack.empty())
494 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500495 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_WITHOUT_IF,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000496 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000497 skipUntilEOD(mTokenizer, token);
498 return;
499 }
500
Zhenyao Mod526f982014-05-13 14:51:19 -0700501 ConditionalBlock &block = mConditionalStack.back();
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000502 if (block.skipBlock)
503 {
504 // No diagnostics. Just skip the whole line.
505 skipUntilEOD(mTokenizer, token);
506 return;
507 }
508 if (block.foundElseGroup)
509 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500510 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_AFTER_ELSE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000511 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000512 skipUntilEOD(mTokenizer, token);
513 return;
514 }
515
516 block.foundElseGroup = true;
517 block.skipGroup = block.foundValidGroup;
518 block.foundValidGroup = true;
519
Geoff Lang95a423d2015-04-28 11:09:45 -0400520 // Check if there are extra tokens after #else.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000521 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000522 if (!isEOD(token))
523 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500524 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000525 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000526 skipUntilEOD(mTokenizer, token);
527 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000528}
529
Zhenyao Mod526f982014-05-13 14:51:19 -0700530void DirectiveParser::parseElif(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000531{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400532 ASSERT(getDirective(token) == DIRECTIVE_ELIF);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000533
534 if (mConditionalStack.empty())
535 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500536 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_WITHOUT_IF,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000537 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000538 skipUntilEOD(mTokenizer, token);
539 return;
540 }
541
Zhenyao Mod526f982014-05-13 14:51:19 -0700542 ConditionalBlock &block = mConditionalStack.back();
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000543 if (block.skipBlock)
544 {
545 // No diagnostics. Just skip the whole line.
546 skipUntilEOD(mTokenizer, token);
547 return;
548 }
549 if (block.foundElseGroup)
550 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500551 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_AFTER_ELSE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000552 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000553 skipUntilEOD(mTokenizer, token);
554 return;
555 }
556 if (block.foundValidGroup)
557 {
558 // Do not parse the expression.
559 // Also be careful not to emit a diagnostic.
560 block.skipGroup = true;
561 skipUntilEOD(mTokenizer, token);
562 return;
563 }
564
565 int expression = parseExpressionIf(token);
566 block.skipGroup = expression == 0;
567 block.foundValidGroup = expression != 0;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000568}
569
Zhenyao Mod526f982014-05-13 14:51:19 -0700570void DirectiveParser::parseEndif(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000571{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400572 ASSERT(getDirective(token) == DIRECTIVE_ENDIF);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000573
574 if (mConditionalStack.empty())
575 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500576 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ENDIF_WITHOUT_IF,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000577 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000578 skipUntilEOD(mTokenizer, token);
579 return;
580 }
581
582 mConditionalStack.pop_back();
583
Geoff Lang95a423d2015-04-28 11:09:45 -0400584 // Check if there are tokens after #endif.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000585 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000586 if (!isEOD(token))
587 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500588 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000589 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000590 skipUntilEOD(mTokenizer, token);
591 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000592}
593
Zhenyao Mod526f982014-05-13 14:51:19 -0700594void DirectiveParser::parseError(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000595{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400596 ASSERT(getDirective(token) == DIRECTIVE_ERROR);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000597
alokp@chromium.org2e818912012-06-29 21:26:03 +0000598 std::ostringstream stream;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000599 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000600 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org36124de82012-05-24 02:17:43 +0000601 {
602 stream << *token;
603 mTokenizer->lex(token);
604 }
605 mDirectiveHandler->handleError(token->location, stream.str());
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000606}
607
alokp@chromium.org36124de82012-05-24 02:17:43 +0000608// Parses pragma of form: #pragma name[(value)].
Zhenyao Mod526f982014-05-13 14:51:19 -0700609void DirectiveParser::parsePragma(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000610{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400611 ASSERT(getDirective(token) == DIRECTIVE_PRAGMA);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000612
613 enum State
614 {
615 PRAGMA_NAME,
616 LEFT_PAREN,
617 PRAGMA_VALUE,
618 RIGHT_PAREN
619 };
620
621 bool valid = true;
622 std::string name, value;
623 int state = PRAGMA_NAME;
624
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000625 mTokenizer->lex(token);
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700626 bool stdgl = token->text == "STDGL";
627 if (stdgl)
628 {
629 mTokenizer->lex(token);
630 }
alokp@chromium.org7c884542012-05-24 19:13:03 +0000631 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org36124de82012-05-24 02:17:43 +0000632 {
633 switch(state++)
634 {
635 case PRAGMA_NAME:
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000636 name = token->text;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000637 valid = valid && (token->type == Token::IDENTIFIER);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000638 break;
639 case LEFT_PAREN:
640 valid = valid && (token->type == '(');
641 break;
642 case PRAGMA_VALUE:
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000643 value = token->text;
Olli Etuaho391befe2015-08-12 16:30:38 +0300644 valid = valid && (token->type == Token::IDENTIFIER);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000645 break;
646 case RIGHT_PAREN:
647 valid = valid && (token->type == ')');
648 break;
649 default:
650 valid = false;
651 break;
652 }
653 mTokenizer->lex(token);
654 }
655
656 valid = valid && ((state == PRAGMA_NAME) || // Empty pragma.
657 (state == LEFT_PAREN) || // Without value.
658 (state == RIGHT_PAREN + 1)); // With value.
659 if (!valid)
660 {
Olli Etuaho391befe2015-08-12 16:30:38 +0300661 mDiagnostics->report(Diagnostics::PP_UNRECOGNIZED_PRAGMA,
alokp@chromium.org36124de82012-05-24 02:17:43 +0000662 token->location, name);
663 }
664 else if (state > PRAGMA_NAME) // Do not notify for empty pragma.
665 {
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700666 mDirectiveHandler->handlePragma(token->location, name, value, stdgl);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000667 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000668}
669
Zhenyao Mod526f982014-05-13 14:51:19 -0700670void DirectiveParser::parseExtension(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000671{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400672 ASSERT(getDirective(token) == DIRECTIVE_EXTENSION);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000673
674 enum State
675 {
676 EXT_NAME,
677 COLON,
678 EXT_BEHAVIOR
679 };
680
681 bool valid = true;
682 std::string name, behavior;
683 int state = EXT_NAME;
684
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000685 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000686 while ((token->type != '\n') && (token->type != Token::LAST))
687 {
688 switch (state++)
689 {
690 case EXT_NAME:
691 if (valid && (token->type != Token::IDENTIFIER))
692 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500693 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_NAME,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000694 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000695 valid = false;
696 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000697 if (valid) name = token->text;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000698 break;
699 case COLON:
700 if (valid && (token->type != ':'))
701 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500702 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000703 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000704 valid = false;
705 }
706 break;
707 case EXT_BEHAVIOR:
708 if (valid && (token->type != Token::IDENTIFIER))
709 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500710 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_BEHAVIOR,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000711 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000712 valid = false;
713 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000714 if (valid) behavior = token->text;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000715 break;
716 default:
717 if (valid)
718 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500719 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000720 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000721 valid = false;
722 }
723 break;
724 }
725 mTokenizer->lex(token);
726 }
727 if (valid && (state != EXT_BEHAVIOR + 1))
728 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500729 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000730 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000731 valid = false;
732 }
Geoff Lang06e24a72015-04-27 14:48:59 -0400733 if (valid && mSeenNonPreprocessorToken)
734 {
Geoff Langb3a6a8f2015-06-23 16:10:14 -0400735 if (mShaderVersion >= 300)
736 {
737 mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL3,
738 token->location, token->text);
739 valid = false;
740 }
741 else
742 {
743 mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1,
744 token->location, token->text);
745 }
Geoff Lang06e24a72015-04-27 14:48:59 -0400746 }
alokp@chromium.org7c884542012-05-24 19:13:03 +0000747 if (valid)
748 mDirectiveHandler->handleExtension(token->location, name, behavior);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000749}
750
Zhenyao Mod526f982014-05-13 14:51:19 -0700751void DirectiveParser::parseVersion(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000752{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400753 ASSERT(getDirective(token) == DIRECTIVE_VERSION);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000754
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000755 if (mPastFirstStatement)
756 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500757 mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_STATEMENT,
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000758 token->location, token->text);
759 skipUntilEOD(mTokenizer, token);
760 return;
761 }
762
alokp@chromium.org7c884542012-05-24 19:13:03 +0000763 enum State
764 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000765 VERSION_NUMBER,
766 VERSION_PROFILE,
767 VERSION_ENDLINE
alokp@chromium.org7c884542012-05-24 19:13:03 +0000768 };
769
770 bool valid = true;
771 int version = 0;
772 int state = VERSION_NUMBER;
773
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000774 mTokenizer->lex(token);
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000775 while (valid && (token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org7c884542012-05-24 19:13:03 +0000776 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000777 switch (state)
alokp@chromium.org7c884542012-05-24 19:13:03 +0000778 {
779 case VERSION_NUMBER:
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000780 if (token->type != Token::CONST_INT)
alokp@chromium.org7c884542012-05-24 19:13:03 +0000781 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500782 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_NUMBER,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000783 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000784 valid = false;
785 }
alokp@chromium.org2e818912012-06-29 21:26:03 +0000786 if (valid && !token->iValue(&version))
787 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500788 mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW,
alokp@chromium.org2e818912012-06-29 21:26:03 +0000789 token->location, token->text);
790 valid = false;
791 }
alokp@chromium.org7c884542012-05-24 19:13:03 +0000792 if (valid)
793 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000794 state = (version < 300) ? VERSION_ENDLINE : VERSION_PROFILE;
795 }
796 break;
797 case VERSION_PROFILE:
798 if (token->type != Token::IDENTIFIER || token->text != "es")
799 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500800 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000801 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000802 valid = false;
803 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000804 state = VERSION_ENDLINE;
805 break;
806 default:
Shannon Woods7f2d7942013-11-19 15:07:58 -0500807 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000808 token->location, token->text);
809 valid = false;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000810 break;
811 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000812
alokp@chromium.org7c884542012-05-24 19:13:03 +0000813 mTokenizer->lex(token);
814 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000815
816 if (valid && (state != VERSION_ENDLINE))
alokp@chromium.org7c884542012-05-24 19:13:03 +0000817 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500818 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000819 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000820 valid = false;
821 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000822
Olli Etuahoc378cd82015-05-25 15:21:44 +0300823 if (valid && version >= 300 && token->location.line > 1)
824 {
825 mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_LINE_ESSL3,
826 token->location, token->text);
827 valid = false;
828 }
829
alokp@chromium.org7c884542012-05-24 19:13:03 +0000830 if (valid)
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000831 {
alokp@chromium.org7c884542012-05-24 19:13:03 +0000832 mDirectiveHandler->handleVersion(token->location, version);
Geoff Langb3a6a8f2015-06-23 16:10:14 -0400833 mShaderVersion = version;
Olli Etuaho6cb4c7f2015-08-13 11:27:17 +0300834 PredefineMacro(mMacroSet, "__VERSION__", version);
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000835 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000836}
837
Zhenyao Mod526f982014-05-13 14:51:19 -0700838void DirectiveParser::parseLine(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000839{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400840 ASSERT(getDirective(token) == DIRECTIVE_LINE);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000841
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000842 bool valid = true;
Olli Etuaho247374c2015-09-09 15:07:24 +0300843 bool parsedFileNumber = false;
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000844 int line = 0, file = 0;
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000845
Olli Etuaho1b2f1622016-03-04 15:06:51 +0200846 MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics);
Olli Etuaho247374c2015-09-09 15:07:24 +0300847
848 // Lex the first token after "#line" so we can check it for EOD.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000849 macroExpander.lex(token);
Olli Etuaho247374c2015-09-09 15:07:24 +0300850
851 if (isEOD(token))
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000852 {
Olli Etuaho247374c2015-09-09 15:07:24 +0300853 mDiagnostics->report(Diagnostics::PP_INVALID_LINE_DIRECTIVE, token->location, token->text);
854 valid = false;
855 }
856 else
857 {
858 ExpressionParser expressionParser(&macroExpander, mDiagnostics);
859 ExpressionParser::ErrorSettings errorSettings;
860
861 // See GLES3 section 12.42
862 errorSettings.integerLiteralsMustFit32BitSignedRange = true;
863
864 errorSettings.unexpectedIdentifier = Diagnostics::PP_INVALID_LINE_NUMBER;
865 // The first token was lexed earlier to check if it was EOD. Include
866 // the token in parsing for a second time by setting the
867 // parsePresetToken flag to true.
868 expressionParser.parse(token, &line, true, errorSettings, &valid);
869 if (!isEOD(token) && valid)
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000870 {
Olli Etuaho247374c2015-09-09 15:07:24 +0300871 errorSettings.unexpectedIdentifier = Diagnostics::PP_INVALID_FILE_NUMBER;
872 // After parsing the line expression expressionParser has also
873 // advanced to the first token of the file expression - this is the
874 // token that makes the parser reduce the "input" rule for the line
875 // expression and stop. So we're using parsePresetToken = true here
876 // as well.
877 expressionParser.parse(token, &file, true, errorSettings, &valid);
878 parsedFileNumber = true;
879 }
880 if (!isEOD(token))
881 {
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000882 if (valid)
883 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500884 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000885 token->location, token->text);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000886 valid = false;
887 }
Olli Etuaho247374c2015-09-09 15:07:24 +0300888 skipUntilEOD(mTokenizer, token);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000889 }
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000890 }
891
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000892 if (valid)
893 {
894 mTokenizer->setLineNumber(line);
Olli Etuaho247374c2015-09-09 15:07:24 +0300895 if (parsedFileNumber)
Zhenyao Mod526f982014-05-13 14:51:19 -0700896 mTokenizer->setFileNumber(file);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000897 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000898}
899
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000900bool DirectiveParser::skipping() const
901{
Zhenyao Mod526f982014-05-13 14:51:19 -0700902 if (mConditionalStack.empty())
903 return false;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000904
905 const ConditionalBlock& block = mConditionalStack.back();
906 return block.skipBlock || block.skipGroup;
907}
908
Zhenyao Mod526f982014-05-13 14:51:19 -0700909void DirectiveParser::parseConditionalIf(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000910{
911 ConditionalBlock block;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000912 block.type = token->text;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000913 block.location = token->location;
914
915 if (skipping())
916 {
917 // This conditional block is inside another conditional group
918 // which is skipped. As a consequence this whole block is skipped.
919 // Be careful not to parse the conditional expression that might
920 // emit a diagnostic.
921 skipUntilEOD(mTokenizer, token);
922 block.skipBlock = true;
923 }
924 else
925 {
926 DirectiveType directive = getDirective(token);
927
928 int expression = 0;
929 switch (directive)
930 {
931 case DIRECTIVE_IF:
932 expression = parseExpressionIf(token);
933 break;
934 case DIRECTIVE_IFDEF:
935 expression = parseExpressionIfdef(token);
936 break;
937 case DIRECTIVE_IFNDEF:
938 expression = parseExpressionIfdef(token) == 0 ? 1 : 0;
939 break;
940 default:
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400941 UNREACHABLE();
942 break;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000943 }
944 block.skipGroup = expression == 0;
945 block.foundValidGroup = expression != 0;
946 }
947 mConditionalStack.push_back(block);
948}
949
Zhenyao Mod526f982014-05-13 14:51:19 -0700950int DirectiveParser::parseExpressionIf(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000951{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400952 ASSERT((getDirective(token) == DIRECTIVE_IF) || (getDirective(token) == DIRECTIVE_ELIF));
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000953
Olli Etuaho1b2f1622016-03-04 15:06:51 +0200954 DefinedParser definedParser(mTokenizer, mMacroSet, mDiagnostics);
955 MacroExpander macroExpander(&definedParser, mMacroSet, mDiagnostics);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000956 ExpressionParser expressionParser(&macroExpander, mDiagnostics);
957
958 int expression = 0;
Olli Etuaho247374c2015-09-09 15:07:24 +0300959 ExpressionParser::ErrorSettings errorSettings;
960 errorSettings.integerLiteralsMustFit32BitSignedRange = false;
961 errorSettings.unexpectedIdentifier = Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN;
962
963 bool valid = true;
964 expressionParser.parse(token, &expression, false, errorSettings, &valid);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000965
Geoff Lang95a423d2015-04-28 11:09:45 -0400966 // Check if there are tokens after #if expression.
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000967 if (!isEOD(token))
968 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500969 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000970 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000971 skipUntilEOD(mTokenizer, token);
972 }
973
974 return expression;
975}
976
Zhenyao Mod526f982014-05-13 14:51:19 -0700977int DirectiveParser::parseExpressionIfdef(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000978{
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400979 ASSERT((getDirective(token) == DIRECTIVE_IFDEF) || (getDirective(token) == DIRECTIVE_IFNDEF));
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000980
981 mTokenizer->lex(token);
982 if (token->type != Token::IDENTIFIER)
983 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500984 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000985 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000986 skipUntilEOD(mTokenizer, token);
987 return 0;
988 }
989
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000990 MacroSet::const_iterator iter = mMacroSet->find(token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000991 int expression = iter != mMacroSet->end() ? 1 : 0;
992
Geoff Lang95a423d2015-04-28 11:09:45 -0400993 // Check if there are tokens after #ifdef expression.
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000994 mTokenizer->lex(token);
995 if (!isEOD(token))
996 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500997 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000998 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000999 skipUntilEOD(mTokenizer, token);
1000 }
1001 return expression;
1002}
1003
alokp@chromium.org04d7d222012-05-16 19:24:07 +00001004} // namespace pp