blob: 44cd6ba2ee94754f9053cc3299feed56f24d6a22 [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{
Geoff Lang942e3622015-04-30 11:00:01 -0400121 // Names prefixed with "GL_" are reserved.
Geoff Lang4c8cae62015-05-01 16:46:16 +0000122 if (name.substr(0, 3) == "GL_")
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000123 return true;
Geoff Lang4c8cae62015-05-01 16:46:16 +0000124
125 // Names containing two consecutive underscores are reserved.
126 if (name.find("__") != std::string::npos)
127 return true;
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000128
129 return false;
130}
131
Zhenyao Mod526f982014-05-13 14:51:19 -0700132bool isMacroPredefined(const std::string &name,
133 const pp::MacroSet &macroSet)
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000134{
135 pp::MacroSet::const_iterator iter = macroSet.find(name);
136 return iter != macroSet.end() ? iter->second.predefined : false;
137}
138
Zhenyao Mod526f982014-05-13 14:51:19 -0700139} // namespace anonymous
140
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000141namespace pp
142{
143
144class DefinedParser : public Lexer
145{
146 public:
Zhenyao Mod526f982014-05-13 14:51:19 -0700147 DefinedParser(Lexer *lexer,
148 const MacroSet *macroSet,
149 Diagnostics *diagnostics)
150 : mLexer(lexer),
151 mMacroSet(macroSet),
152 mDiagnostics(diagnostics)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000153 {
154 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000155
156 protected:
Zhenyao Mod526f982014-05-13 14:51:19 -0700157 virtual void lex(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000158 {
Zhenyao Mob5e17752014-10-22 10:57:10 -0700159 const char kDefined[] = "defined";
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000160
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000161 mLexer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000162 if (token->type != Token::IDENTIFIER)
163 return;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000164 if (token->text != kDefined)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000165 return;
166
167 bool paren = false;
168 mLexer->lex(token);
169 if (token->type == '(')
170 {
171 paren = true;
172 mLexer->lex(token);
173 }
174
175 if (token->type != Token::IDENTIFIER)
176 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500177 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000178 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000179 skipUntilEOD(mLexer, token);
180 return;
181 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000182 MacroSet::const_iterator iter = mMacroSet->find(token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000183 std::string expression = iter != mMacroSet->end() ? "1" : "0";
184
185 if (paren)
186 {
187 mLexer->lex(token);
188 if (token->type != ')')
189 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500190 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000191 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000192 skipUntilEOD(mLexer, token);
193 return;
194 }
195 }
196
197 // We have a valid defined operator.
198 // Convert the current token into a CONST_INT token.
199 token->type = Token::CONST_INT;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000200 token->text = expression;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000201 }
202
203 private:
Zhenyao Mod526f982014-05-13 14:51:19 -0700204 Lexer *mLexer;
205 const MacroSet *mMacroSet;
206 Diagnostics *mDiagnostics;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000207};
208
Zhenyao Mod526f982014-05-13 14:51:19 -0700209DirectiveParser::DirectiveParser(Tokenizer *tokenizer,
210 MacroSet *macroSet,
211 Diagnostics *diagnostics,
212 DirectiveHandler *directiveHandler)
213 : mPastFirstStatement(false),
Geoff Lang06e24a72015-04-27 14:48:59 -0400214 mSeenNonPreprocessorToken(false),
Zhenyao Mod526f982014-05-13 14:51:19 -0700215 mTokenizer(tokenizer),
216 mMacroSet(macroSet),
217 mDiagnostics(diagnostics),
Geoff Langb3a6a8f2015-06-23 16:10:14 -0400218 mDirectiveHandler(directiveHandler),
219 mShaderVersion(100)
alokp@chromium.org2c958ee2012-05-17 20:35:42 +0000220{
221}
222
Zhenyao Mod526f982014-05-13 14:51:19 -0700223void DirectiveParser::lex(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000224{
225 do
226 {
227 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000228
alokp@chromium.org432d6fc2012-06-27 22:13:21 +0000229 if (token->type == Token::PP_HASH)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000230 {
231 parseDirective(token);
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000232 mPastFirstStatement = true;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000233 }
Geoff Lang06e24a72015-04-27 14:48:59 -0400234 else if (!isEOD(token))
235 {
236 mSeenNonPreprocessorToken = true;
237 }
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000238
239 if (token->type == Token::LAST)
240 {
241 if (!mConditionalStack.empty())
242 {
Zhenyao Mod526f982014-05-13 14:51:19 -0700243 const ConditionalBlock &block = mConditionalStack.back();
Shannon Woods7f2d7942013-11-19 15:07:58 -0500244 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNTERMINATED,
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000245 block.location, block.type);
246 }
247 break;
248 }
249
Zhenyao Mod526f982014-05-13 14:51:19 -0700250 }
251 while (skipping() || (token->type == '\n'));
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000252
253 mPastFirstStatement = true;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000254}
255
Zhenyao Mod526f982014-05-13 14:51:19 -0700256void DirectiveParser::parseDirective(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000257{
alokp@chromium.org432d6fc2012-06-27 22:13:21 +0000258 assert(token->type == Token::PP_HASH);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000259
260 mTokenizer->lex(token);
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000261 if (isEOD(token))
262 {
263 // Empty Directive.
264 return;
265 }
266
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000267 DirectiveType directive = getDirective(token);
268
269 // While in an excluded conditional block/group,
270 // we only parse conditional directives.
271 if (skipping() && !isConditionalDirective(directive))
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000272 {
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000273 skipUntilEOD(mTokenizer, token);
274 return;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000275 }
276
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000277 switch(directive)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000278 {
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000279 case DIRECTIVE_NONE:
Shannon Woods7f2d7942013-11-19 15:07:58 -0500280 mDiagnostics->report(Diagnostics::PP_DIRECTIVE_INVALID_NAME,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000281 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000282 skipUntilEOD(mTokenizer, token);
283 break;
284 case DIRECTIVE_DEFINE:
285 parseDefine(token);
286 break;
287 case DIRECTIVE_UNDEF:
288 parseUndef(token);
289 break;
290 case DIRECTIVE_IF:
291 parseIf(token);
292 break;
293 case DIRECTIVE_IFDEF:
294 parseIfdef(token);
295 break;
296 case DIRECTIVE_IFNDEF:
297 parseIfndef(token);
298 break;
299 case DIRECTIVE_ELSE:
300 parseElse(token);
301 break;
302 case DIRECTIVE_ELIF:
303 parseElif(token);
304 break;
305 case DIRECTIVE_ENDIF:
306 parseEndif(token);
307 break;
308 case DIRECTIVE_ERROR:
309 parseError(token);
310 break;
311 case DIRECTIVE_PRAGMA:
312 parsePragma(token);
313 break;
314 case DIRECTIVE_EXTENSION:
315 parseExtension(token);
316 break;
317 case DIRECTIVE_VERSION:
318 parseVersion(token);
319 break;
320 case DIRECTIVE_LINE:
321 parseLine(token);
322 break;
323 default:
324 assert(false);
325 break;
326 }
327
328 skipUntilEOD(mTokenizer, token);
329 if (token->type == Token::LAST)
330 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500331 mDiagnostics->report(Diagnostics::PP_EOF_IN_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000332 token->location, token->text);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000333 }
334}
335
Zhenyao Mod526f982014-05-13 14:51:19 -0700336void DirectiveParser::parseDefine(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000337{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000338 assert(getDirective(token) == DIRECTIVE_DEFINE);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000339
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000340 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000341 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000342 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500343 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000344 token->location, token->text);
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000345 return;
346 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000347 if (isMacroPredefined(token->text, *mMacroSet))
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000348 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500349 mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_REDEFINED,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000350 token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000351 return;
352 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000353 if (isMacroNameReserved(token->text))
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000354 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500355 mDiagnostics->report(Diagnostics::PP_MACRO_NAME_RESERVED,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000356 token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000357 return;
358 }
359
360 Macro macro;
361 macro.type = Macro::kTypeObj;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000362 macro.name = token->text;
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000363
364 mTokenizer->lex(token);
365 if (token->type == '(' && !token->hasLeadingSpace())
366 {
367 // Function-like macro. Collect arguments.
368 macro.type = Macro::kTypeFunc;
Zhenyao Mod526f982014-05-13 14:51:19 -0700369 do
370 {
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000371 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000372 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000373 break;
Geoff Lang26be18d2015-04-27 14:05:57 -0400374
375 if (std::find(macro.parameters.begin(), macro.parameters.end(), token->text) != macro.parameters.end())
376 {
377 mDiagnostics->report(Diagnostics::PP_MACRO_DUPLICATE_PARAMETER_NAMES,
378 token->location, token->text);
379 return;
380 }
381
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000382 macro.parameters.push_back(token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000383
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000384 mTokenizer->lex(token); // Get ','.
Zhenyao Mod526f982014-05-13 14:51:19 -0700385 }
386 while (token->type == ',');
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000387
388 if (token->type != ')')
389 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500390 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000391 token->location,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000392 token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000393 return;
394 }
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000395 mTokenizer->lex(token); // Get ')'.
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000396 }
397
alokp@chromium.org7c884542012-05-24 19:13:03 +0000398 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000399 {
400 // Reset the token location because it is unnecessary in replacement
401 // list. Resetting it also allows us to reuse Token::equals() to
402 // compare macros.
403 token->location = SourceLocation();
404 macro.replacements.push_back(*token);
405 mTokenizer->lex(token);
406 }
alokp@chromium.org7fc38dd2012-06-14 18:23:23 +0000407 if (!macro.replacements.empty())
408 {
409 // Whitespace preceding the replacement list is not considered part of
410 // the replacement list for either form of macro.
411 macro.replacements.front().setHasLeadingSpace(false);
412 }
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000413
414 // Check for macro redefinition.
415 MacroSet::const_iterator iter = mMacroSet->find(macro.name);
416 if (iter != mMacroSet->end() && !macro.equals(iter->second))
417 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500418 mDiagnostics->report(Diagnostics::PP_MACRO_REDEFINED,
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000419 token->location,
420 macro.name);
421 return;
422 }
423 mMacroSet->insert(std::make_pair(macro.name, macro));
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000424}
425
Zhenyao Mod526f982014-05-13 14:51:19 -0700426void DirectiveParser::parseUndef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000427{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000428 assert(getDirective(token) == DIRECTIVE_UNDEF);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000429
430 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000431 if (token->type != Token::IDENTIFIER)
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000432 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500433 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000434 token->location, token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000435 return;
436 }
437
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000438 MacroSet::iterator iter = mMacroSet->find(token->text);
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000439 if (iter != mMacroSet->end())
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000440 {
441 if (iter->second.predefined)
442 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500443 mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_UNDEFINED,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000444 token->location, token->text);
alokp@chromium.orgf3cdb462012-06-19 18:39:48 +0000445 }
446 else
447 {
448 mMacroSet->erase(iter);
449 }
450 }
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000451
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000452 mTokenizer->lex(token);
Geoff Langb819d252015-04-27 14:16:34 -0400453 if (!isEOD(token))
454 {
455 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
456 token->location, token->text);
457 skipUntilEOD(mTokenizer, token);
458 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000459}
460
Zhenyao Mod526f982014-05-13 14:51:19 -0700461void DirectiveParser::parseIf(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000462{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000463 assert(getDirective(token) == DIRECTIVE_IF);
464 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000465}
466
Zhenyao Mod526f982014-05-13 14:51:19 -0700467void DirectiveParser::parseIfdef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000468{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000469 assert(getDirective(token) == DIRECTIVE_IFDEF);
470 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000471}
472
Zhenyao Mod526f982014-05-13 14:51:19 -0700473void DirectiveParser::parseIfndef(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000474{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000475 assert(getDirective(token) == DIRECTIVE_IFNDEF);
476 parseConditionalIf(token);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000477}
478
Zhenyao Mod526f982014-05-13 14:51:19 -0700479void DirectiveParser::parseElse(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000480{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000481 assert(getDirective(token) == DIRECTIVE_ELSE);
482
483 if (mConditionalStack.empty())
484 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500485 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_WITHOUT_IF,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000486 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000487 skipUntilEOD(mTokenizer, token);
488 return;
489 }
490
Zhenyao Mod526f982014-05-13 14:51:19 -0700491 ConditionalBlock &block = mConditionalStack.back();
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000492 if (block.skipBlock)
493 {
494 // No diagnostics. Just skip the whole line.
495 skipUntilEOD(mTokenizer, token);
496 return;
497 }
498 if (block.foundElseGroup)
499 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500500 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_AFTER_ELSE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000501 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000502 skipUntilEOD(mTokenizer, token);
503 return;
504 }
505
506 block.foundElseGroup = true;
507 block.skipGroup = block.foundValidGroup;
508 block.foundValidGroup = true;
509
Geoff Lang95a423d2015-04-28 11:09:45 -0400510 // Check if there are extra tokens after #else.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000511 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000512 if (!isEOD(token))
513 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500514 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000515 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000516 skipUntilEOD(mTokenizer, token);
517 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000518}
519
Zhenyao Mod526f982014-05-13 14:51:19 -0700520void DirectiveParser::parseElif(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000521{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000522 assert(getDirective(token) == DIRECTIVE_ELIF);
523
524 if (mConditionalStack.empty())
525 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500526 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_WITHOUT_IF,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000527 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000528 skipUntilEOD(mTokenizer, token);
529 return;
530 }
531
Zhenyao Mod526f982014-05-13 14:51:19 -0700532 ConditionalBlock &block = mConditionalStack.back();
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000533 if (block.skipBlock)
534 {
535 // No diagnostics. Just skip the whole line.
536 skipUntilEOD(mTokenizer, token);
537 return;
538 }
539 if (block.foundElseGroup)
540 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500541 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_AFTER_ELSE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000542 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000543 skipUntilEOD(mTokenizer, token);
544 return;
545 }
546 if (block.foundValidGroup)
547 {
548 // Do not parse the expression.
549 // Also be careful not to emit a diagnostic.
550 block.skipGroup = true;
551 skipUntilEOD(mTokenizer, token);
552 return;
553 }
554
555 int expression = parseExpressionIf(token);
556 block.skipGroup = expression == 0;
557 block.foundValidGroup = expression != 0;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000558}
559
Zhenyao Mod526f982014-05-13 14:51:19 -0700560void DirectiveParser::parseEndif(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000561{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000562 assert(getDirective(token) == DIRECTIVE_ENDIF);
563
564 if (mConditionalStack.empty())
565 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500566 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ENDIF_WITHOUT_IF,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000567 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000568 skipUntilEOD(mTokenizer, token);
569 return;
570 }
571
572 mConditionalStack.pop_back();
573
Geoff Lang95a423d2015-04-28 11:09:45 -0400574 // Check if there are tokens after #endif.
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000575 mTokenizer->lex(token);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000576 if (!isEOD(token))
577 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500578 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000579 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000580 skipUntilEOD(mTokenizer, token);
581 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000582}
583
Zhenyao Mod526f982014-05-13 14:51:19 -0700584void DirectiveParser::parseError(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000585{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000586 assert(getDirective(token) == DIRECTIVE_ERROR);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000587
alokp@chromium.org2e818912012-06-29 21:26:03 +0000588 std::ostringstream stream;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000589 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000590 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org36124de82012-05-24 02:17:43 +0000591 {
592 stream << *token;
593 mTokenizer->lex(token);
594 }
595 mDirectiveHandler->handleError(token->location, stream.str());
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000596}
597
alokp@chromium.org36124de82012-05-24 02:17:43 +0000598// Parses pragma of form: #pragma name[(value)].
Zhenyao Mod526f982014-05-13 14:51:19 -0700599void DirectiveParser::parsePragma(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000600{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000601 assert(getDirective(token) == DIRECTIVE_PRAGMA);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000602
603 enum State
604 {
605 PRAGMA_NAME,
606 LEFT_PAREN,
607 PRAGMA_VALUE,
608 RIGHT_PAREN
609 };
610
611 bool valid = true;
612 std::string name, value;
613 int state = PRAGMA_NAME;
614
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000615 mTokenizer->lex(token);
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700616 bool stdgl = token->text == "STDGL";
617 if (stdgl)
618 {
619 mTokenizer->lex(token);
620 }
alokp@chromium.org7c884542012-05-24 19:13:03 +0000621 while ((token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org36124de82012-05-24 02:17:43 +0000622 {
623 switch(state++)
624 {
625 case PRAGMA_NAME:
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000626 name = token->text;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000627 valid = valid && (token->type == Token::IDENTIFIER);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000628 break;
629 case LEFT_PAREN:
630 valid = valid && (token->type == '(');
631 break;
632 case PRAGMA_VALUE:
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000633 value = token->text;
Olli Etuaho391befe2015-08-12 16:30:38 +0300634 valid = valid && (token->type == Token::IDENTIFIER);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000635 break;
636 case RIGHT_PAREN:
637 valid = valid && (token->type == ')');
638 break;
639 default:
640 valid = false;
641 break;
642 }
643 mTokenizer->lex(token);
644 }
645
646 valid = valid && ((state == PRAGMA_NAME) || // Empty pragma.
647 (state == LEFT_PAREN) || // Without value.
648 (state == RIGHT_PAREN + 1)); // With value.
649 if (!valid)
650 {
Olli Etuaho391befe2015-08-12 16:30:38 +0300651 mDiagnostics->report(Diagnostics::PP_UNRECOGNIZED_PRAGMA,
alokp@chromium.org36124de82012-05-24 02:17:43 +0000652 token->location, name);
653 }
654 else if (state > PRAGMA_NAME) // Do not notify for empty pragma.
655 {
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700656 mDirectiveHandler->handlePragma(token->location, name, value, stdgl);
alokp@chromium.org36124de82012-05-24 02:17:43 +0000657 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000658}
659
Zhenyao Mod526f982014-05-13 14:51:19 -0700660void DirectiveParser::parseExtension(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000661{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000662 assert(getDirective(token) == DIRECTIVE_EXTENSION);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000663
664 enum State
665 {
666 EXT_NAME,
667 COLON,
668 EXT_BEHAVIOR
669 };
670
671 bool valid = true;
672 std::string name, behavior;
673 int state = EXT_NAME;
674
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000675 mTokenizer->lex(token);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000676 while ((token->type != '\n') && (token->type != Token::LAST))
677 {
678 switch (state++)
679 {
680 case EXT_NAME:
681 if (valid && (token->type != Token::IDENTIFIER))
682 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500683 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_NAME,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000684 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000685 valid = false;
686 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000687 if (valid) name = token->text;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000688 break;
689 case COLON:
690 if (valid && (token->type != ':'))
691 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500692 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000693 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000694 valid = false;
695 }
696 break;
697 case EXT_BEHAVIOR:
698 if (valid && (token->type != Token::IDENTIFIER))
699 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500700 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_BEHAVIOR,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000701 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000702 valid = false;
703 }
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000704 if (valid) behavior = token->text;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000705 break;
706 default:
707 if (valid)
708 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500709 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000710 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000711 valid = false;
712 }
713 break;
714 }
715 mTokenizer->lex(token);
716 }
717 if (valid && (state != EXT_BEHAVIOR + 1))
718 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500719 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_DIRECTIVE,
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 }
Geoff Lang06e24a72015-04-27 14:48:59 -0400723 if (valid && mSeenNonPreprocessorToken)
724 {
Geoff Langb3a6a8f2015-06-23 16:10:14 -0400725 if (mShaderVersion >= 300)
726 {
727 mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL3,
728 token->location, token->text);
729 valid = false;
730 }
731 else
732 {
733 mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1,
734 token->location, token->text);
735 }
Geoff Lang06e24a72015-04-27 14:48:59 -0400736 }
alokp@chromium.org7c884542012-05-24 19:13:03 +0000737 if (valid)
738 mDirectiveHandler->handleExtension(token->location, name, behavior);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000739}
740
Zhenyao Mod526f982014-05-13 14:51:19 -0700741void DirectiveParser::parseVersion(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000742{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000743 assert(getDirective(token) == DIRECTIVE_VERSION);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000744
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000745 if (mPastFirstStatement)
746 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500747 mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_STATEMENT,
alokp@chromium.orgd0d9f872012-07-03 16:06:40 +0000748 token->location, token->text);
749 skipUntilEOD(mTokenizer, token);
750 return;
751 }
752
alokp@chromium.org7c884542012-05-24 19:13:03 +0000753 enum State
754 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000755 VERSION_NUMBER,
756 VERSION_PROFILE,
757 VERSION_ENDLINE
alokp@chromium.org7c884542012-05-24 19:13:03 +0000758 };
759
760 bool valid = true;
761 int version = 0;
762 int state = VERSION_NUMBER;
763
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000764 mTokenizer->lex(token);
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000765 while (valid && (token->type != '\n') && (token->type != Token::LAST))
alokp@chromium.org7c884542012-05-24 19:13:03 +0000766 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000767 switch (state)
alokp@chromium.org7c884542012-05-24 19:13:03 +0000768 {
769 case VERSION_NUMBER:
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000770 if (token->type != Token::CONST_INT)
alokp@chromium.org7c884542012-05-24 19:13:03 +0000771 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500772 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_NUMBER,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000773 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000774 valid = false;
775 }
alokp@chromium.org2e818912012-06-29 21:26:03 +0000776 if (valid && !token->iValue(&version))
777 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500778 mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW,
alokp@chromium.org2e818912012-06-29 21:26:03 +0000779 token->location, token->text);
780 valid = false;
781 }
alokp@chromium.org7c884542012-05-24 19:13:03 +0000782 if (valid)
783 {
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000784 state = (version < 300) ? VERSION_ENDLINE : VERSION_PROFILE;
785 }
786 break;
787 case VERSION_PROFILE:
788 if (token->type != Token::IDENTIFIER || token->text != "es")
789 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500790 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000791 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000792 valid = false;
793 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000794 state = VERSION_ENDLINE;
795 break;
796 default:
Shannon Woods7f2d7942013-11-19 15:07:58 -0500797 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000798 token->location, token->text);
799 valid = false;
alokp@chromium.org7c884542012-05-24 19:13:03 +0000800 break;
801 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000802
alokp@chromium.org7c884542012-05-24 19:13:03 +0000803 mTokenizer->lex(token);
804 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000805
806 if (valid && (state != VERSION_ENDLINE))
alokp@chromium.org7c884542012-05-24 19:13:03 +0000807 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500808 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000809 token->location, token->text);
alokp@chromium.org7c884542012-05-24 19:13:03 +0000810 valid = false;
811 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000812
Olli Etuahoc378cd82015-05-25 15:21:44 +0300813 if (valid && version >= 300 && token->location.line > 1)
814 {
815 mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_LINE_ESSL3,
816 token->location, token->text);
817 valid = false;
818 }
819
alokp@chromium.org7c884542012-05-24 19:13:03 +0000820 if (valid)
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000821 {
alokp@chromium.org7c884542012-05-24 19:13:03 +0000822 mDirectiveHandler->handleVersion(token->location, version);
Geoff Langb3a6a8f2015-06-23 16:10:14 -0400823 mShaderVersion = version;
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000824 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000825}
826
Zhenyao Mod526f982014-05-13 14:51:19 -0700827void DirectiveParser::parseLine(Token *token)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000828{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000829 assert(getDirective(token) == DIRECTIVE_LINE);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000830
831 enum State
832 {
833 LINE_NUMBER,
834 FILE_NUMBER
835 };
836
837 bool valid = true;
838 int line = 0, file = 0;
839 int state = LINE_NUMBER;
840
alokp@chromium.org98d04ec2012-05-21 22:47:20 +0000841 MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000842 macroExpander.lex(token);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000843 while ((token->type != '\n') && (token->type != Token::LAST))
844 {
845 switch (state++)
846 {
847 case LINE_NUMBER:
848 if (valid && (token->type != Token::CONST_INT))
849 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500850 mDiagnostics->report(Diagnostics::PP_INVALID_LINE_NUMBER,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000851 token->location, token->text);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000852 valid = false;
853 }
alokp@chromium.org2e818912012-06-29 21:26:03 +0000854 if (valid && !token->iValue(&line))
855 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500856 mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW,
alokp@chromium.org2e818912012-06-29 21:26:03 +0000857 token->location, token->text);
858 valid = false;
859 }
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000860 break;
861 case FILE_NUMBER:
862 if (valid && (token->type != Token::CONST_INT))
863 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500864 mDiagnostics->report(Diagnostics::PP_INVALID_FILE_NUMBER,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000865 token->location, token->text);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000866 valid = false;
867 }
alokp@chromium.org2e818912012-06-29 21:26:03 +0000868 if (valid && !token->iValue(&file))
869 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500870 mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW,
alokp@chromium.org2e818912012-06-29 21:26:03 +0000871 token->location, token->text);
872 valid = false;
873 }
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000874 break;
875 default:
876 if (valid)
877 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500878 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000879 token->location, token->text);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000880 valid = false;
881 }
882 break;
883 }
884 macroExpander.lex(token);
885 }
886
887 if (valid && (state != FILE_NUMBER) && (state != FILE_NUMBER + 1))
888 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500889 mDiagnostics->report(Diagnostics::PP_INVALID_LINE_DIRECTIVE,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000890 token->location, token->text);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000891 valid = false;
892 }
893 if (valid)
894 {
895 mTokenizer->setLineNumber(line);
Zhenyao Mod526f982014-05-13 14:51:19 -0700896 if (state == FILE_NUMBER + 1)
897 mTokenizer->setFileNumber(file);
alokp@chromium.org46aa13d2012-06-15 15:40:27 +0000898 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000899}
900
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000901bool DirectiveParser::skipping() const
902{
Zhenyao Mod526f982014-05-13 14:51:19 -0700903 if (mConditionalStack.empty())
904 return false;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000905
906 const ConditionalBlock& block = mConditionalStack.back();
907 return block.skipBlock || block.skipGroup;
908}
909
Zhenyao Mod526f982014-05-13 14:51:19 -0700910void DirectiveParser::parseConditionalIf(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000911{
912 ConditionalBlock block;
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000913 block.type = token->text;
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000914 block.location = token->location;
915
916 if (skipping())
917 {
918 // This conditional block is inside another conditional group
919 // which is skipped. As a consequence this whole block is skipped.
920 // Be careful not to parse the conditional expression that might
921 // emit a diagnostic.
922 skipUntilEOD(mTokenizer, token);
923 block.skipBlock = true;
924 }
925 else
926 {
927 DirectiveType directive = getDirective(token);
928
929 int expression = 0;
930 switch (directive)
931 {
932 case DIRECTIVE_IF:
933 expression = parseExpressionIf(token);
934 break;
935 case DIRECTIVE_IFDEF:
936 expression = parseExpressionIfdef(token);
937 break;
938 case DIRECTIVE_IFNDEF:
939 expression = parseExpressionIfdef(token) == 0 ? 1 : 0;
940 break;
941 default:
942 assert(false);
943 break;
944 }
945 block.skipGroup = expression == 0;
946 block.foundValidGroup = expression != 0;
947 }
948 mConditionalStack.push_back(block);
949}
950
Zhenyao Mod526f982014-05-13 14:51:19 -0700951int DirectiveParser::parseExpressionIf(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000952{
953 assert((getDirective(token) == DIRECTIVE_IF) ||
954 (getDirective(token) == DIRECTIVE_ELIF));
955
956 DefinedParser definedParser(mTokenizer, mMacroSet, mDiagnostics);
957 MacroExpander macroExpander(&definedParser, mMacroSet, mDiagnostics);
958 ExpressionParser expressionParser(&macroExpander, mDiagnostics);
959
960 int expression = 0;
961 macroExpander.lex(token);
962 expressionParser.parse(token, &expression);
963
Geoff Lang95a423d2015-04-28 11:09:45 -0400964 // Check if there are tokens after #if expression.
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000965 if (!isEOD(token))
966 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500967 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000968 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000969 skipUntilEOD(mTokenizer, token);
970 }
971
972 return expression;
973}
974
Zhenyao Mod526f982014-05-13 14:51:19 -0700975int DirectiveParser::parseExpressionIfdef(Token *token)
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000976{
977 assert((getDirective(token) == DIRECTIVE_IFDEF) ||
978 (getDirective(token) == DIRECTIVE_IFNDEF));
979
980 mTokenizer->lex(token);
981 if (token->type != Token::IDENTIFIER)
982 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500983 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000984 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000985 skipUntilEOD(mTokenizer, token);
986 return 0;
987 }
988
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000989 MacroSet::const_iterator iter = mMacroSet->find(token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000990 int expression = iter != mMacroSet->end() ? 1 : 0;
991
Geoff Lang95a423d2015-04-28 11:09:45 -0400992 // Check if there are tokens after #ifdef expression.
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000993 mTokenizer->lex(token);
994 if (!isEOD(token))
995 {
Shannon Woods7f2d7942013-11-19 15:07:58 -0500996 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
alokp@chromium.org5b6a68e2012-06-28 20:29:13 +0000997 token->location, token->text);
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000998 skipUntilEOD(mTokenizer, token);
999 }
1000 return expression;
1001}
1002
alokp@chromium.org04d7d222012-05-16 19:24:07 +00001003} // namespace pp