blob: aceb3b2b2e4d79b6ca3c6490cee4b184485cb916 [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
7#include "DirectiveParser.h"
8
Geoff Lang26be18d2015-04-27 14:05:57 -04009#include <algorithm>
alokp@chromium.org04d7d222012-05-16 19:24:07 +000010#include <cassert>
alokp@chromium.org51b96852012-05-30 20:25:05 +000011#include <cstdlib>
alokp@chromium.org36124de82012-05-24 02:17:43 +000012#include <sstream>
alokp@chromium.org04d7d222012-05-16 19:24:07 +000013
daniel@transgaming.comb3077d02013-01-11 04:12:09 +000014#include "DiagnosticsBase.h"
15#include "DirectiveHandlerBase.h"
alokp@chromium.org04d7d222012-05-16 19:24:07 +000016#include "ExpressionParser.h"
17#include "MacroExpander.h"
18#include "Token.h"
19#include "Tokenizer.h"
20
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{
alokp@chromium.org432d6fc2012-06-27 22:13:21 +0000251 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:
317 assert(false);
318 break;
319 }
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{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000331 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{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000431 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);
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 {
458 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
459 token->location, token->text);
460 skipUntilEOD(mTokenizer, token);
461 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000462}
463
Zhenyao Mod526f982014-05-13 14:51:19 -0700464void DirectiveParser::parseIf(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000465{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000466 assert(getDirective(token) == DIRECTIVE_IF);
467 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000468}
469
Zhenyao Mod526f982014-05-13 14:51:19 -0700470void DirectiveParser::parseIfdef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000471{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000472 assert(getDirective(token) == DIRECTIVE_IFDEF);
473 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000474}
475
Zhenyao Mod526f982014-05-13 14:51:19 -0700476void DirectiveParser::parseIfndef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000477{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000478 assert(getDirective(token) == DIRECTIVE_IFNDEF);
479 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000480}
481
Zhenyao Mod526f982014-05-13 14:51:19 -0700482void DirectiveParser::parseElse(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000483{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000484 assert(getDirective(token) == DIRECTIVE_ELSE);
485
486 if (mConditionalStack.empty())
487 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500488 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_WITHOUT_IF,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000489 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000490 skipUntilEOD(mTokenizer, token);
491 return;
492 }
493
Zhenyao Mod526f982014-05-13 14:51:19 -0700494 ConditionalBlock &block = mConditionalStack.back();
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000495 if (block.skipBlock)
496 {
497 // No diagnostics. Just skip the whole line.
498 skipUntilEOD(mTokenizer, token);
499 return;
500 }
501 if (block.foundElseGroup)
502 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500503 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_AFTER_ELSE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000504 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000505 skipUntilEOD(mTokenizer, token);
506 return;
507 }
508
509 block.foundElseGroup = true;
510 block.skipGroup = block.foundValidGroup;
511 block.foundValidGroup = true;
512
Geoff Lang95a423d2015-04-28 11:09:45 -0400513 // Check if there are extra tokens after #else.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000514 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000515 if (!isEOD(token))
516 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500517 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000518 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000519 skipUntilEOD(mTokenizer, token);
520 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000521}
522
Zhenyao Mod526f982014-05-13 14:51:19 -0700523void DirectiveParser::parseElif(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000524{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000525 assert(getDirective(token) == DIRECTIVE_ELIF);
526
527 if (mConditionalStack.empty())
528 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500529 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_WITHOUT_IF,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000530 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000531 skipUntilEOD(mTokenizer, token);
532 return;
533 }
534
Zhenyao Mod526f982014-05-13 14:51:19 -0700535 ConditionalBlock &block = mConditionalStack.back();
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000536 if (block.skipBlock)
537 {
538 // No diagnostics. Just skip the whole line.
539 skipUntilEOD(mTokenizer, token);
540 return;
541 }
542 if (block.foundElseGroup)
543 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500544 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_AFTER_ELSE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000545 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000546 skipUntilEOD(mTokenizer, token);
547 return;
548 }
549 if (block.foundValidGroup)
550 {
551 // Do not parse the expression.
552 // Also be careful not to emit a diagnostic.
553 block.skipGroup = true;
554 skipUntilEOD(mTokenizer, token);
555 return;
556 }
557
558 int expression = parseExpressionIf(token);
559 block.skipGroup = expression == 0;
560 block.foundValidGroup = expression != 0;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000561}
562
Zhenyao Mod526f982014-05-13 14:51:19 -0700563void DirectiveParser::parseEndif(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000564{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000565 assert(getDirective(token) == DIRECTIVE_ENDIF);
566
567 if (mConditionalStack.empty())
568 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500569 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ENDIF_WITHOUT_IF,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000570 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000571 skipUntilEOD(mTokenizer, token);
572 return;
573 }
574
575 mConditionalStack.pop_back();
576
Geoff Lang95a423d2015-04-28 11:09:45 -0400577 // Check if there are tokens after #endif.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000578 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000579 if (!isEOD(token))
580 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500581 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000582 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000583 skipUntilEOD(mTokenizer, token);
584 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000585}
586
Zhenyao Mod526f982014-05-13 14:51:19 -0700587void DirectiveParser::parseError(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000588{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000589 assert(getDirective(token) == DIRECTIVE_ERROR);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000590
alokp@chromium.org2e818912012-06-29 21:26:03 +0000591 std::ostringstream stream;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000592 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000593 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org36124de82012-05-24 02:17:43 +0000594 {
595 stream << *token;
596 mTokenizer->lex(token);
597 }
598 mDirectiveHandler->handleError(token->location, stream.str());
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000599}
600
alokp@chromium.org36124de82012-05-24 02:17:43 +0000601// Parses pragma of form: #pragma name[(value)].
Zhenyao Mod526f982014-05-13 14:51:19 -0700602void DirectiveParser::parsePragma(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000603{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000604 assert(getDirective(token) == DIRECTIVE_PRAGMA);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000605
606 enum State
607 {
608 PRAGMA_NAME,
609 LEFT_PAREN,
610 PRAGMA_VALUE,
611 RIGHT_PAREN
612 };
613
614 bool valid = true;
615 std::string name, value;
616 int state = PRAGMA_NAME;
617
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000618 mTokenizer->lex(token);
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700619 bool stdgl = token->text == "STDGL";
620 if (stdgl)
621 {
622 mTokenizer->lex(token);
623 }
alokp@chromium.org7c884542012-05-24 19:13:03 +0000624 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org36124de82012-05-24 02:17:43 +0000625 {
626 switch(state++)
627 {
628 case PRAGMA_NAME:
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000629 name = token->text;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000630 valid = valid && (token->type == Token::IDENTIFIER);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000631 break;
632 case LEFT_PAREN:
633 valid = valid && (token->type == '(');
634 break;
635 case PRAGMA_VALUE:
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000636 value = token->text;
Olli Etuaho391befe2015-08-12 16:30:38 +0300637 valid = valid && (token->type == Token::IDENTIFIER);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000638 break;
639 case RIGHT_PAREN:
640 valid = valid && (token->type == ')');
641 break;
642 default:
643 valid = false;
644 break;
645 }
646 mTokenizer->lex(token);
647 }
648
649 valid = valid && ((state == PRAGMA_NAME) || // Empty pragma.
650 (state == LEFT_PAREN) || // Without value.
651 (state == RIGHT_PAREN + 1)); // With value.
652 if (!valid)
653 {
Olli Etuaho391befe2015-08-12 16:30:38 +0300654 mDiagnostics->report(Diagnostics::PP_UNRECOGNIZED_PRAGMA,
alokp@chromium.org36124de82012-05-24 02:17:43 +0000655 token->location, name);
656 }
657 else if (state > PRAGMA_NAME) // Do not notify for empty pragma.
658 {
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700659 mDirectiveHandler->handlePragma(token->location, name, value, stdgl);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000660 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000661}
662
Zhenyao Mod526f982014-05-13 14:51:19 -0700663void DirectiveParser::parseExtension(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000664{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000665 assert(getDirective(token) == DIRECTIVE_EXTENSION);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000666
667 enum State
668 {
669 EXT_NAME,
670 COLON,
671 EXT_BEHAVIOR
672 };
673
674 bool valid = true;
675 std::string name, behavior;
676 int state = EXT_NAME;
677
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000678 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000679 while ((token->type != '\n') && (token->type != Token::LAST))
680 {
681 switch (state++)
682 {
683 case EXT_NAME:
684 if (valid && (token->type != Token::IDENTIFIER))
685 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500686 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_NAME,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000687 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000688 valid = false;
689 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000690 if (valid) name = token->text;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000691 break;
692 case COLON:
693 if (valid && (token->type != ':'))
694 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500695 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
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 }
699 break;
700 case EXT_BEHAVIOR:
701 if (valid && (token->type != Token::IDENTIFIER))
702 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500703 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_BEHAVIOR,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000704 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000705 valid = false;
706 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000707 if (valid) behavior = token->text;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000708 break;
709 default:
710 if (valid)
711 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500712 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
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 }
716 break;
717 }
718 mTokenizer->lex(token);
719 }
720 if (valid && (state != EXT_BEHAVIOR + 1))
721 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500722 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000723 token->location, 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{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000746 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 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500750 mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_STATEMENT,
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000751 token->location, token->text);
752 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
763 bool valid = true;
764 int version = 0;
765 int state = VERSION_NUMBER;
766
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 {
772 case VERSION_NUMBER:
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000773 if (token->type != Token::CONST_INT)
alokp@chromium.org7c884542012-05-24 19:13:03 +0000774 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500775 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_NUMBER,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000776 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000777 valid = false;
778 }
alokp@chromium.org2e818912012-06-29 21:26:03 +0000779 if (valid && !token->iValue(&version))
780 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500781 mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW,
alokp@chromium.org2e818912012-06-29 21:26:03 +0000782 token->location, token->text);
783 valid = false;
784 }
alokp@chromium.org7c884542012-05-24 19:13:03 +0000785 if (valid)
786 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000787 state = (version < 300) ? VERSION_ENDLINE : VERSION_PROFILE;
788 }
789 break;
790 case VERSION_PROFILE:
791 if (token->type != Token::IDENTIFIER || token->text != "es")
792 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500793 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000794 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000795 valid = false;
796 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000797 state = VERSION_ENDLINE;
798 break;
799 default:
Shannon Woods7f2d7942013-11-19 15:07:58 -0500800 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000801 token->location, token->text);
802 valid = false;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000803 break;
804 }
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 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500811 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000812 token->location, 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 {
818 mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_LINE_ESSL3,
819 token->location, token->text);
820 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{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000833 assert(getDirective(token) == DIRECTIVE_LINE);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000834
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000835 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 Etuaho1b2f1622016-03-04 15:06:51 +0200839 MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics);
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 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500877 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000878 token->location, 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
898 const ConditionalBlock& block = mConditionalStack.back();
899 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;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000905 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 {
924 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 assert(false);
935 break;
936 }
937 block.skipGroup = expression == 0;
938 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{
945 assert((getDirective(token) == DIRECTIVE_IF) ||
946 (getDirective(token) == DIRECTIVE_ELIF));
947
Olli Etuaho1b2f1622016-03-04 15:06:51 +0200948 DefinedParser definedParser(mTokenizer, mMacroSet, mDiagnostics);
949 MacroExpander macroExpander(&definedParser, mMacroSet, mDiagnostics);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000950 ExpressionParser expressionParser(&macroExpander, mDiagnostics);
951
952 int expression = 0;
Olli Etuaho247374c2015-09-09 15:07:24 +0300953 ExpressionParser::ErrorSettings errorSettings;
954 errorSettings.integerLiteralsMustFit32BitSignedRange = false;
955 errorSettings.unexpectedIdentifier = Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN;
956
957 bool valid = true;
958 expressionParser.parse(token, &expression, false, errorSettings, &valid);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000959
Geoff Lang95a423d2015-04-28 11:09:45 -0400960 // Check if there are tokens after #if expression.
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000961 if (!isEOD(token))
962 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500963 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000964 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000965 skipUntilEOD(mTokenizer, token);
966 }
967
968 return expression;
969}
970
Zhenyao Mod526f982014-05-13 14:51:19 -0700971int DirectiveParser::parseExpressionIfdef(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000972{
973 assert((getDirective(token) == DIRECTIVE_IFDEF) ||
974 (getDirective(token) == DIRECTIVE_IFNDEF));
975
976 mTokenizer->lex(token);
977 if (token->type != Token::IDENTIFIER)
978 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500979 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000980 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000981 skipUntilEOD(mTokenizer, token);
982 return 0;
983 }
984
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000985 MacroSet::const_iterator iter = mMacroSet->find(token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000986 int expression = iter != mMacroSet->end() ? 1 : 0;
987
Geoff Lang95a423d2015-04-28 11:09:45 -0400988 // Check if there are tokens after #ifdef expression.
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000989 mTokenizer->lex(token);
990 if (!isEOD(token))
991 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500992 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000993 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000994 skipUntilEOD(mTokenizer, token);
995 }
996 return expression;
997}
998
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000999} // namespace pp