blob: c1f202f57c17d79ec6e0b5cf740441924d981cb7 [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
Zhenyao Mod526f982014-05-13 14:51:19 -0700142DirectiveParser::DirectiveParser(Tokenizer *tokenizer,
143 MacroSet *macroSet,
144 Diagnostics *diagnostics,
145 DirectiveHandler *directiveHandler)
146 : mPastFirstStatement(false),
Geoff Lang06e24a72015-04-27 14:48:59 -0400147 mSeenNonPreprocessorToken(false),
Zhenyao Mod526f982014-05-13 14:51:19 -0700148 mTokenizer(tokenizer),
149 mMacroSet(macroSet),
150 mDiagnostics(diagnostics),
Geoff Langb3a6a8f2015-06-23 16:10:14 -0400151 mDirectiveHandler(directiveHandler),
152 mShaderVersion(100)
alokp@chromium.org2c958ee2012-05-17 20:35:42 +0000153{
154}
155
Zhenyao Mod526f982014-05-13 14:51:19 -0700156void DirectiveParser::lex(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000157{
158 do
159 {
160 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000161
alokp@chromium.org432d6fc2012-06-27 22:13:21 +0000162 if (token->type == Token::PP_HASH)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000163 {
164 parseDirective(token);
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000165 mPastFirstStatement = true;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000166 }
Geoff Lang06e24a72015-04-27 14:48:59 -0400167 else if (!isEOD(token))
168 {
169 mSeenNonPreprocessorToken = true;
170 }
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000171
172 if (token->type == Token::LAST)
173 {
174 if (!mConditionalStack.empty())
175 {
Zhenyao Mod526f982014-05-13 14:51:19 -0700176 const ConditionalBlock &block = mConditionalStack.back();
Shannon Woods7f2d7942013-11-19 15:07:58 -0500177 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNTERMINATED,
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000178 block.location, block.type);
179 }
180 break;
181 }
182
Zhenyao Mod526f982014-05-13 14:51:19 -0700183 }
184 while (skipping() || (token->type == '\n'));
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000185
186 mPastFirstStatement = true;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000187}
188
Zhenyao Mod526f982014-05-13 14:51:19 -0700189void DirectiveParser::parseDirective(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000190{
alokp@chromium.org432d6fc2012-06-27 22:13:21 +0000191 assert(token->type == Token::PP_HASH);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000192
193 mTokenizer->lex(token);
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000194 if (isEOD(token))
195 {
196 // Empty Directive.
197 return;
198 }
199
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000200 DirectiveType directive = getDirective(token);
201
202 // While in an excluded conditional block/group,
203 // we only parse conditional directives.
204 if (skipping() && !isConditionalDirective(directive))
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000205 {
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000206 skipUntilEOD(mTokenizer, token);
207 return;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000208 }
209
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000210 switch(directive)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000211 {
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000212 case DIRECTIVE_NONE:
Shannon Woods7f2d7942013-11-19 15:07:58 -0500213 mDiagnostics->report(Diagnostics::PP_DIRECTIVE_INVALID_NAME,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000214 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000215 skipUntilEOD(mTokenizer, token);
216 break;
217 case DIRECTIVE_DEFINE:
218 parseDefine(token);
219 break;
220 case DIRECTIVE_UNDEF:
221 parseUndef(token);
222 break;
223 case DIRECTIVE_IF:
224 parseIf(token);
225 break;
226 case DIRECTIVE_IFDEF:
227 parseIfdef(token);
228 break;
229 case DIRECTIVE_IFNDEF:
230 parseIfndef(token);
231 break;
232 case DIRECTIVE_ELSE:
233 parseElse(token);
234 break;
235 case DIRECTIVE_ELIF:
236 parseElif(token);
237 break;
238 case DIRECTIVE_ENDIF:
239 parseEndif(token);
240 break;
241 case DIRECTIVE_ERROR:
242 parseError(token);
243 break;
244 case DIRECTIVE_PRAGMA:
245 parsePragma(token);
246 break;
247 case DIRECTIVE_EXTENSION:
248 parseExtension(token);
249 break;
250 case DIRECTIVE_VERSION:
251 parseVersion(token);
252 break;
253 case DIRECTIVE_LINE:
254 parseLine(token);
255 break;
256 default:
257 assert(false);
258 break;
259 }
260
261 skipUntilEOD(mTokenizer, token);
262 if (token->type == Token::LAST)
263 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500264 mDiagnostics->report(Diagnostics::PP_EOF_IN_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000265 token->location, token->text);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000266 }
267}
268
Zhenyao Mod526f982014-05-13 14:51:19 -0700269void DirectiveParser::parseDefine(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000270{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000271 assert(getDirective(token) == DIRECTIVE_DEFINE);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000272
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000273 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000274 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000275 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500276 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000277 token->location, token->text);
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000278 return;
279 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000280 if (isMacroPredefined(token->text, *mMacroSet))
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000281 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500282 mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_REDEFINED,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000283 token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000284 return;
285 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000286 if (isMacroNameReserved(token->text))
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000287 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500288 mDiagnostics->report(Diagnostics::PP_MACRO_NAME_RESERVED,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000289 token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000290 return;
291 }
Olli Etuaho2f6ddf32015-09-22 16:10:07 +0300292 // Using double underscores is allowed, but may result in unintended
293 // behavior, so a warning is issued. At the time of writing this was
294 // specified in ESSL 3.10, but the intent judging from Khronos
295 // discussions and dEQP tests was that double underscores should be
296 // allowed in earlier ESSL versions too.
297 if (hasDoubleUnderscores(token->text))
298 {
299 mDiagnostics->report(Diagnostics::PP_WARNING_MACRO_NAME_RESERVED, token->location,
300 token->text);
301 }
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000302
303 Macro macro;
304 macro.type = Macro::kTypeObj;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000305 macro.name = token->text;
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000306
307 mTokenizer->lex(token);
308 if (token->type == '(' && !token->hasLeadingSpace())
309 {
310 // Function-like macro. Collect arguments.
311 macro.type = Macro::kTypeFunc;
Zhenyao Mod526f982014-05-13 14:51:19 -0700312 do
313 {
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000314 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000315 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000316 break;
Geoff Lang26be18d2015-04-27 14:05:57 -0400317
318 if (std::find(macro.parameters.begin(), macro.parameters.end(), token->text) != macro.parameters.end())
319 {
320 mDiagnostics->report(Diagnostics::PP_MACRO_DUPLICATE_PARAMETER_NAMES,
321 token->location, token->text);
322 return;
323 }
324
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000325 macro.parameters.push_back(token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000326
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000327 mTokenizer->lex(token); // Get ','.
Zhenyao Mod526f982014-05-13 14:51:19 -0700328 }
329 while (token->type == ',');
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000330
331 if (token->type != ')')
332 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500333 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000334 token->location,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000335 token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000336 return;
337 }
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000338 mTokenizer->lex(token); // Get ')'.
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000339 }
340
alokp@chromium.org7c884542012-05-24 19:13:03 +0000341 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000342 {
343 // Reset the token location because it is unnecessary in replacement
344 // list. Resetting it also allows us to reuse Token::equals() to
345 // compare macros.
346 token->location = SourceLocation();
347 macro.replacements.push_back(*token);
348 mTokenizer->lex(token);
349 }
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000350 if (!macro.replacements.empty())
351 {
352 // Whitespace preceding the replacement list is not considered part of
353 // the replacement list for either form of macro.
354 macro.replacements.front().setHasLeadingSpace(false);
355 }
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000356
357 // Check for macro redefinition.
358 MacroSet::const_iterator iter = mMacroSet->find(macro.name);
359 if (iter != mMacroSet->end() && !macro.equals(iter->second))
360 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500361 mDiagnostics->report(Diagnostics::PP_MACRO_REDEFINED,
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000362 token->location,
363 macro.name);
364 return;
365 }
366 mMacroSet->insert(std::make_pair(macro.name, macro));
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000367}
368
Zhenyao Mod526f982014-05-13 14:51:19 -0700369void DirectiveParser::parseUndef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000370{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000371 assert(getDirective(token) == DIRECTIVE_UNDEF);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000372
373 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000374 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000375 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500376 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000377 token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000378 return;
379 }
380
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000381 MacroSet::iterator iter = mMacroSet->find(token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000382 if (iter != mMacroSet->end())
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000383 {
384 if (iter->second.predefined)
385 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500386 mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_UNDEFINED,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000387 token->location, token->text);
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000388 }
389 else
390 {
391 mMacroSet->erase(iter);
392 }
393 }
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000394
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000395 mTokenizer->lex(token);
Geoff Langb819d252015-04-27 14:16:34 -0400396 if (!isEOD(token))
397 {
398 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
399 token->location, token->text);
400 skipUntilEOD(mTokenizer, token);
401 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000402}
403
Zhenyao Mod526f982014-05-13 14:51:19 -0700404void DirectiveParser::parseIf(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000405{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000406 assert(getDirective(token) == DIRECTIVE_IF);
407 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000408}
409
Zhenyao Mod526f982014-05-13 14:51:19 -0700410void DirectiveParser::parseIfdef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000411{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000412 assert(getDirective(token) == DIRECTIVE_IFDEF);
413 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000414}
415
Zhenyao Mod526f982014-05-13 14:51:19 -0700416void DirectiveParser::parseIfndef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000417{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000418 assert(getDirective(token) == DIRECTIVE_IFNDEF);
419 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000420}
421
Zhenyao Mod526f982014-05-13 14:51:19 -0700422void DirectiveParser::parseElse(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000423{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000424 assert(getDirective(token) == DIRECTIVE_ELSE);
425
426 if (mConditionalStack.empty())
427 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500428 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_WITHOUT_IF,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000429 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000430 skipUntilEOD(mTokenizer, token);
431 return;
432 }
433
Zhenyao Mod526f982014-05-13 14:51:19 -0700434 ConditionalBlock &block = mConditionalStack.back();
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000435 if (block.skipBlock)
436 {
437 // No diagnostics. Just skip the whole line.
438 skipUntilEOD(mTokenizer, token);
439 return;
440 }
441 if (block.foundElseGroup)
442 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500443 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_AFTER_ELSE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000444 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000445 skipUntilEOD(mTokenizer, token);
446 return;
447 }
448
449 block.foundElseGroup = true;
450 block.skipGroup = block.foundValidGroup;
451 block.foundValidGroup = true;
452
Geoff Lang95a423d2015-04-28 11:09:45 -0400453 // Check if there are extra tokens after #else.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000454 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000455 if (!isEOD(token))
456 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500457 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000458 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000459 skipUntilEOD(mTokenizer, token);
460 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000461}
462
Zhenyao Mod526f982014-05-13 14:51:19 -0700463void DirectiveParser::parseElif(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000464{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000465 assert(getDirective(token) == DIRECTIVE_ELIF);
466
467 if (mConditionalStack.empty())
468 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500469 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_WITHOUT_IF,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000470 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000471 skipUntilEOD(mTokenizer, token);
472 return;
473 }
474
Zhenyao Mod526f982014-05-13 14:51:19 -0700475 ConditionalBlock &block = mConditionalStack.back();
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000476 if (block.skipBlock)
477 {
478 // No diagnostics. Just skip the whole line.
479 skipUntilEOD(mTokenizer, token);
480 return;
481 }
482 if (block.foundElseGroup)
483 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500484 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_AFTER_ELSE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000485 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000486 skipUntilEOD(mTokenizer, token);
487 return;
488 }
489 if (block.foundValidGroup)
490 {
491 // Do not parse the expression.
492 // Also be careful not to emit a diagnostic.
493 block.skipGroup = true;
494 skipUntilEOD(mTokenizer, token);
495 return;
496 }
497
498 int expression = parseExpressionIf(token);
499 block.skipGroup = expression == 0;
500 block.foundValidGroup = expression != 0;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000501}
502
Zhenyao Mod526f982014-05-13 14:51:19 -0700503void DirectiveParser::parseEndif(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000504{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000505 assert(getDirective(token) == DIRECTIVE_ENDIF);
506
507 if (mConditionalStack.empty())
508 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500509 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ENDIF_WITHOUT_IF,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000510 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000511 skipUntilEOD(mTokenizer, token);
512 return;
513 }
514
515 mConditionalStack.pop_back();
516
Geoff Lang95a423d2015-04-28 11:09:45 -0400517 // Check if there are tokens after #endif.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000518 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000519 if (!isEOD(token))
520 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500521 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000522 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000523 skipUntilEOD(mTokenizer, token);
524 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000525}
526
Zhenyao Mod526f982014-05-13 14:51:19 -0700527void DirectiveParser::parseError(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000528{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000529 assert(getDirective(token) == DIRECTIVE_ERROR);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000530
alokp@chromium.org2e818912012-06-29 21:26:03 +0000531 std::ostringstream stream;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000532 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000533 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org36124de82012-05-24 02:17:43 +0000534 {
535 stream << *token;
536 mTokenizer->lex(token);
537 }
538 mDirectiveHandler->handleError(token->location, stream.str());
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000539}
540
alokp@chromium.org36124de82012-05-24 02:17:43 +0000541// Parses pragma of form: #pragma name[(value)].
Zhenyao Mod526f982014-05-13 14:51:19 -0700542void DirectiveParser::parsePragma(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000543{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000544 assert(getDirective(token) == DIRECTIVE_PRAGMA);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000545
546 enum State
547 {
548 PRAGMA_NAME,
549 LEFT_PAREN,
550 PRAGMA_VALUE,
551 RIGHT_PAREN
552 };
553
554 bool valid = true;
555 std::string name, value;
556 int state = PRAGMA_NAME;
557
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000558 mTokenizer->lex(token);
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700559 bool stdgl = token->text == "STDGL";
560 if (stdgl)
561 {
562 mTokenizer->lex(token);
563 }
alokp@chromium.org7c884542012-05-24 19:13:03 +0000564 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org36124de82012-05-24 02:17:43 +0000565 {
566 switch(state++)
567 {
568 case PRAGMA_NAME:
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000569 name = token->text;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000570 valid = valid && (token->type == Token::IDENTIFIER);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000571 break;
572 case LEFT_PAREN:
573 valid = valid && (token->type == '(');
574 break;
575 case PRAGMA_VALUE:
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000576 value = token->text;
Olli Etuaho391befe2015-08-12 16:30:38 +0300577 valid = valid && (token->type == Token::IDENTIFIER);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000578 break;
579 case RIGHT_PAREN:
580 valid = valid && (token->type == ')');
581 break;
582 default:
583 valid = false;
584 break;
585 }
586 mTokenizer->lex(token);
587 }
588
589 valid = valid && ((state == PRAGMA_NAME) || // Empty pragma.
590 (state == LEFT_PAREN) || // Without value.
591 (state == RIGHT_PAREN + 1)); // With value.
592 if (!valid)
593 {
Olli Etuaho391befe2015-08-12 16:30:38 +0300594 mDiagnostics->report(Diagnostics::PP_UNRECOGNIZED_PRAGMA,
alokp@chromium.org36124de82012-05-24 02:17:43 +0000595 token->location, name);
596 }
597 else if (state > PRAGMA_NAME) // Do not notify for empty pragma.
598 {
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700599 mDirectiveHandler->handlePragma(token->location, name, value, stdgl);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000600 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000601}
602
Zhenyao Mod526f982014-05-13 14:51:19 -0700603void DirectiveParser::parseExtension(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000604{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000605 assert(getDirective(token) == DIRECTIVE_EXTENSION);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000606
607 enum State
608 {
609 EXT_NAME,
610 COLON,
611 EXT_BEHAVIOR
612 };
613
614 bool valid = true;
615 std::string name, behavior;
616 int state = EXT_NAME;
617
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000618 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000619 while ((token->type != '\n') && (token->type != Token::LAST))
620 {
621 switch (state++)
622 {
623 case EXT_NAME:
624 if (valid && (token->type != Token::IDENTIFIER))
625 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500626 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_NAME,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000627 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000628 valid = false;
629 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000630 if (valid) name = token->text;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000631 break;
632 case COLON:
633 if (valid && (token->type != ':'))
634 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500635 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000636 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000637 valid = false;
638 }
639 break;
640 case EXT_BEHAVIOR:
641 if (valid && (token->type != Token::IDENTIFIER))
642 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500643 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_BEHAVIOR,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000644 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000645 valid = false;
646 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000647 if (valid) behavior = token->text;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000648 break;
649 default:
650 if (valid)
651 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500652 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000653 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000654 valid = false;
655 }
656 break;
657 }
658 mTokenizer->lex(token);
659 }
660 if (valid && (state != EXT_BEHAVIOR + 1))
661 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500662 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000663 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000664 valid = false;
665 }
Geoff Lang06e24a72015-04-27 14:48:59 -0400666 if (valid && mSeenNonPreprocessorToken)
667 {
Geoff Langb3a6a8f2015-06-23 16:10:14 -0400668 if (mShaderVersion >= 300)
669 {
670 mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL3,
671 token->location, token->text);
672 valid = false;
673 }
674 else
675 {
676 mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1,
677 token->location, token->text);
678 }
Geoff Lang06e24a72015-04-27 14:48:59 -0400679 }
alokp@chromium.org7c884542012-05-24 19:13:03 +0000680 if (valid)
681 mDirectiveHandler->handleExtension(token->location, name, behavior);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000682}
683
Zhenyao Mod526f982014-05-13 14:51:19 -0700684void DirectiveParser::parseVersion(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000685{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000686 assert(getDirective(token) == DIRECTIVE_VERSION);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000687
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000688 if (mPastFirstStatement)
689 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500690 mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_STATEMENT,
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000691 token->location, token->text);
692 skipUntilEOD(mTokenizer, token);
693 return;
694 }
695
alokp@chromium.org7c884542012-05-24 19:13:03 +0000696 enum State
697 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000698 VERSION_NUMBER,
699 VERSION_PROFILE,
700 VERSION_ENDLINE
alokp@chromium.org7c884542012-05-24 19:13:03 +0000701 };
702
703 bool valid = true;
704 int version = 0;
705 int state = VERSION_NUMBER;
706
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000707 mTokenizer->lex(token);
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000708 while (valid && (token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org7c884542012-05-24 19:13:03 +0000709 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000710 switch (state)
alokp@chromium.org7c884542012-05-24 19:13:03 +0000711 {
712 case VERSION_NUMBER:
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000713 if (token->type != Token::CONST_INT)
alokp@chromium.org7c884542012-05-24 19:13:03 +0000714 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500715 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_NUMBER,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000716 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000717 valid = false;
718 }
alokp@chromium.org2e818912012-06-29 21:26:03 +0000719 if (valid && !token->iValue(&version))
720 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500721 mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW,
alokp@chromium.org2e818912012-06-29 21:26:03 +0000722 token->location, token->text);
723 valid = false;
724 }
alokp@chromium.org7c884542012-05-24 19:13:03 +0000725 if (valid)
726 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000727 state = (version < 300) ? VERSION_ENDLINE : VERSION_PROFILE;
728 }
729 break;
730 case VERSION_PROFILE:
731 if (token->type != Token::IDENTIFIER || token->text != "es")
732 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500733 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000734 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000735 valid = false;
736 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000737 state = VERSION_ENDLINE;
738 break;
739 default:
Shannon Woods7f2d7942013-11-19 15:07:58 -0500740 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000741 token->location, token->text);
742 valid = false;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000743 break;
744 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000745
alokp@chromium.org7c884542012-05-24 19:13:03 +0000746 mTokenizer->lex(token);
747 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000748
749 if (valid && (state != VERSION_ENDLINE))
alokp@chromium.org7c884542012-05-24 19:13:03 +0000750 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500751 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000752 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000753 valid = false;
754 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000755
Olli Etuahoc378cd82015-05-25 15:21:44 +0300756 if (valid && version >= 300 && token->location.line > 1)
757 {
758 mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_LINE_ESSL3,
759 token->location, token->text);
760 valid = false;
761 }
762
alokp@chromium.org7c884542012-05-24 19:13:03 +0000763 if (valid)
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000764 {
alokp@chromium.org7c884542012-05-24 19:13:03 +0000765 mDirectiveHandler->handleVersion(token->location, version);
Geoff Langb3a6a8f2015-06-23 16:10:14 -0400766 mShaderVersion = version;
Olli Etuaho6cb4c7f2015-08-13 11:27:17 +0300767 PredefineMacro(mMacroSet, "__VERSION__", version);
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000768 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000769}
770
Zhenyao Mod526f982014-05-13 14:51:19 -0700771void DirectiveParser::parseLine(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000772{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000773 assert(getDirective(token) == DIRECTIVE_LINE);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000774
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000775 bool valid = true;
Olli Etuaho247374c2015-09-09 15:07:24 +0300776 bool parsedFileNumber = false;
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000777 int line = 0, file = 0;
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000778
Olli Etuaho261f5372015-09-18 10:34:31 +0300779 MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, false);
Olli Etuaho247374c2015-09-09 15:07:24 +0300780
781 // Lex the first token after "#line" so we can check it for EOD.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000782 macroExpander.lex(token);
Olli Etuaho247374c2015-09-09 15:07:24 +0300783
784 if (isEOD(token))
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000785 {
Olli Etuaho247374c2015-09-09 15:07:24 +0300786 mDiagnostics->report(Diagnostics::PP_INVALID_LINE_DIRECTIVE, token->location, token->text);
787 valid = false;
788 }
789 else
790 {
791 ExpressionParser expressionParser(&macroExpander, mDiagnostics);
792 ExpressionParser::ErrorSettings errorSettings;
793
794 // See GLES3 section 12.42
795 errorSettings.integerLiteralsMustFit32BitSignedRange = true;
796
797 errorSettings.unexpectedIdentifier = Diagnostics::PP_INVALID_LINE_NUMBER;
798 // The first token was lexed earlier to check if it was EOD. Include
799 // the token in parsing for a second time by setting the
800 // parsePresetToken flag to true.
801 expressionParser.parse(token, &line, true, errorSettings, &valid);
802 if (!isEOD(token) && valid)
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000803 {
Olli Etuaho247374c2015-09-09 15:07:24 +0300804 errorSettings.unexpectedIdentifier = Diagnostics::PP_INVALID_FILE_NUMBER;
805 // After parsing the line expression expressionParser has also
806 // advanced to the first token of the file expression - this is the
807 // token that makes the parser reduce the "input" rule for the line
808 // expression and stop. So we're using parsePresetToken = true here
809 // as well.
810 expressionParser.parse(token, &file, true, errorSettings, &valid);
811 parsedFileNumber = true;
812 }
813 if (!isEOD(token))
814 {
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000815 if (valid)
816 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500817 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000818 token->location, token->text);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000819 valid = false;
820 }
Olli Etuaho247374c2015-09-09 15:07:24 +0300821 skipUntilEOD(mTokenizer, token);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000822 }
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000823 }
824
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000825 if (valid)
826 {
827 mTokenizer->setLineNumber(line);
Olli Etuaho247374c2015-09-09 15:07:24 +0300828 if (parsedFileNumber)
Zhenyao Mod526f982014-05-13 14:51:19 -0700829 mTokenizer->setFileNumber(file);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000830 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000831}
832
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000833bool DirectiveParser::skipping() const
834{
Zhenyao Mod526f982014-05-13 14:51:19 -0700835 if (mConditionalStack.empty())
836 return false;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000837
838 const ConditionalBlock& block = mConditionalStack.back();
839 return block.skipBlock || block.skipGroup;
840}
841
Zhenyao Mod526f982014-05-13 14:51:19 -0700842void DirectiveParser::parseConditionalIf(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000843{
844 ConditionalBlock block;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000845 block.type = token->text;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000846 block.location = token->location;
847
848 if (skipping())
849 {
850 // This conditional block is inside another conditional group
851 // which is skipped. As a consequence this whole block is skipped.
852 // Be careful not to parse the conditional expression that might
853 // emit a diagnostic.
854 skipUntilEOD(mTokenizer, token);
855 block.skipBlock = true;
856 }
857 else
858 {
859 DirectiveType directive = getDirective(token);
860
861 int expression = 0;
862 switch (directive)
863 {
864 case DIRECTIVE_IF:
865 expression = parseExpressionIf(token);
866 break;
867 case DIRECTIVE_IFDEF:
868 expression = parseExpressionIfdef(token);
869 break;
870 case DIRECTIVE_IFNDEF:
871 expression = parseExpressionIfdef(token) == 0 ? 1 : 0;
872 break;
873 default:
874 assert(false);
875 break;
876 }
877 block.skipGroup = expression == 0;
878 block.foundValidGroup = expression != 0;
879 }
880 mConditionalStack.push_back(block);
881}
882
Zhenyao Mod526f982014-05-13 14:51:19 -0700883int DirectiveParser::parseExpressionIf(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000884{
885 assert((getDirective(token) == DIRECTIVE_IF) ||
886 (getDirective(token) == DIRECTIVE_ELIF));
887
Olli Etuaho261f5372015-09-18 10:34:31 +0300888 MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, true);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000889 ExpressionParser expressionParser(&macroExpander, mDiagnostics);
890
891 int expression = 0;
Olli Etuaho247374c2015-09-09 15:07:24 +0300892 ExpressionParser::ErrorSettings errorSettings;
893 errorSettings.integerLiteralsMustFit32BitSignedRange = false;
894 errorSettings.unexpectedIdentifier = Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN;
895
896 bool valid = true;
897 expressionParser.parse(token, &expression, false, errorSettings, &valid);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000898
Geoff Lang95a423d2015-04-28 11:09:45 -0400899 // Check if there are tokens after #if expression.
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000900 if (!isEOD(token))
901 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500902 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000903 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000904 skipUntilEOD(mTokenizer, token);
905 }
906
907 return expression;
908}
909
Zhenyao Mod526f982014-05-13 14:51:19 -0700910int DirectiveParser::parseExpressionIfdef(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000911{
912 assert((getDirective(token) == DIRECTIVE_IFDEF) ||
913 (getDirective(token) == DIRECTIVE_IFNDEF));
914
915 mTokenizer->lex(token);
916 if (token->type != Token::IDENTIFIER)
917 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500918 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000919 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000920 skipUntilEOD(mTokenizer, token);
921 return 0;
922 }
923
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000924 MacroSet::const_iterator iter = mMacroSet->find(token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000925 int expression = iter != mMacroSet->end() ? 1 : 0;
926
Geoff Lang95a423d2015-04-28 11:09:45 -0400927 // Check if there are tokens after #ifdef expression.
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000928 mTokenizer->lex(token);
929 if (!isEOD(token))
930 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500931 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000932 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000933 skipUntilEOD(mTokenizer, token);
934 }
935 return expression;
936}
937
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000938} // namespace pp