xref: /aosp_15_r20/external/angle/src/compiler/preprocessor/DirectiveParser.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1*8975f5c5SAndroid Build Coastguard Worker //
2*8975f5c5SAndroid Build Coastguard Worker // Copyright 2011 The ANGLE Project Authors. All rights reserved.
3*8975f5c5SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
4*8975f5c5SAndroid Build Coastguard Worker // found in the LICENSE file.
5*8975f5c5SAndroid Build Coastguard Worker //
6*8975f5c5SAndroid Build Coastguard Worker 
7*8975f5c5SAndroid Build Coastguard Worker #include "compiler/preprocessor/DirectiveParser.h"
8*8975f5c5SAndroid Build Coastguard Worker 
9*8975f5c5SAndroid Build Coastguard Worker #include <algorithm>
10*8975f5c5SAndroid Build Coastguard Worker #include <cstdlib>
11*8975f5c5SAndroid Build Coastguard Worker #include <sstream>
12*8975f5c5SAndroid Build Coastguard Worker 
13*8975f5c5SAndroid Build Coastguard Worker #include "GLSLANG/ShaderLang.h"
14*8975f5c5SAndroid Build Coastguard Worker #include "common/debug.h"
15*8975f5c5SAndroid Build Coastguard Worker #include "compiler/preprocessor/DiagnosticsBase.h"
16*8975f5c5SAndroid Build Coastguard Worker #include "compiler/preprocessor/DirectiveHandlerBase.h"
17*8975f5c5SAndroid Build Coastguard Worker #include "compiler/preprocessor/ExpressionParser.h"
18*8975f5c5SAndroid Build Coastguard Worker #include "compiler/preprocessor/MacroExpander.h"
19*8975f5c5SAndroid Build Coastguard Worker #include "compiler/preprocessor/Token.h"
20*8975f5c5SAndroid Build Coastguard Worker #include "compiler/preprocessor/Tokenizer.h"
21*8975f5c5SAndroid Build Coastguard Worker 
22*8975f5c5SAndroid Build Coastguard Worker namespace angle
23*8975f5c5SAndroid Build Coastguard Worker {
24*8975f5c5SAndroid Build Coastguard Worker 
25*8975f5c5SAndroid Build Coastguard Worker namespace
26*8975f5c5SAndroid Build Coastguard Worker {
27*8975f5c5SAndroid Build Coastguard Worker enum DirectiveType
28*8975f5c5SAndroid Build Coastguard Worker {
29*8975f5c5SAndroid Build Coastguard Worker     DIRECTIVE_NONE,
30*8975f5c5SAndroid Build Coastguard Worker     DIRECTIVE_DEFINE,
31*8975f5c5SAndroid Build Coastguard Worker     DIRECTIVE_UNDEF,
32*8975f5c5SAndroid Build Coastguard Worker     DIRECTIVE_IF,
33*8975f5c5SAndroid Build Coastguard Worker     DIRECTIVE_IFDEF,
34*8975f5c5SAndroid Build Coastguard Worker     DIRECTIVE_IFNDEF,
35*8975f5c5SAndroid Build Coastguard Worker     DIRECTIVE_ELSE,
36*8975f5c5SAndroid Build Coastguard Worker     DIRECTIVE_ELIF,
37*8975f5c5SAndroid Build Coastguard Worker     DIRECTIVE_ENDIF,
38*8975f5c5SAndroid Build Coastguard Worker     DIRECTIVE_ERROR,
39*8975f5c5SAndroid Build Coastguard Worker     DIRECTIVE_PRAGMA,
40*8975f5c5SAndroid Build Coastguard Worker     DIRECTIVE_EXTENSION,
41*8975f5c5SAndroid Build Coastguard Worker     DIRECTIVE_VERSION,
42*8975f5c5SAndroid Build Coastguard Worker     DIRECTIVE_LINE
43*8975f5c5SAndroid Build Coastguard Worker };
44*8975f5c5SAndroid Build Coastguard Worker 
getDirective(const pp::Token * token)45*8975f5c5SAndroid Build Coastguard Worker DirectiveType getDirective(const pp::Token *token)
46*8975f5c5SAndroid Build Coastguard Worker {
47*8975f5c5SAndroid Build Coastguard Worker     const char kDirectiveDefine[]    = "define";
48*8975f5c5SAndroid Build Coastguard Worker     const char kDirectiveUndef[]     = "undef";
49*8975f5c5SAndroid Build Coastguard Worker     const char kDirectiveIf[]        = "if";
50*8975f5c5SAndroid Build Coastguard Worker     const char kDirectiveIfdef[]     = "ifdef";
51*8975f5c5SAndroid Build Coastguard Worker     const char kDirectiveIfndef[]    = "ifndef";
52*8975f5c5SAndroid Build Coastguard Worker     const char kDirectiveElse[]      = "else";
53*8975f5c5SAndroid Build Coastguard Worker     const char kDirectiveElif[]      = "elif";
54*8975f5c5SAndroid Build Coastguard Worker     const char kDirectiveEndif[]     = "endif";
55*8975f5c5SAndroid Build Coastguard Worker     const char kDirectiveError[]     = "error";
56*8975f5c5SAndroid Build Coastguard Worker     const char kDirectivePragma[]    = "pragma";
57*8975f5c5SAndroid Build Coastguard Worker     const char kDirectiveExtension[] = "extension";
58*8975f5c5SAndroid Build Coastguard Worker     const char kDirectiveVersion[]   = "version";
59*8975f5c5SAndroid Build Coastguard Worker     const char kDirectiveLine[]      = "line";
60*8975f5c5SAndroid Build Coastguard Worker 
61*8975f5c5SAndroid Build Coastguard Worker     if (token->type != pp::Token::IDENTIFIER)
62*8975f5c5SAndroid Build Coastguard Worker         return DIRECTIVE_NONE;
63*8975f5c5SAndroid Build Coastguard Worker 
64*8975f5c5SAndroid Build Coastguard Worker     if (token->text == kDirectiveDefine)
65*8975f5c5SAndroid Build Coastguard Worker         return DIRECTIVE_DEFINE;
66*8975f5c5SAndroid Build Coastguard Worker     if (token->text == kDirectiveUndef)
67*8975f5c5SAndroid Build Coastguard Worker         return DIRECTIVE_UNDEF;
68*8975f5c5SAndroid Build Coastguard Worker     if (token->text == kDirectiveIf)
69*8975f5c5SAndroid Build Coastguard Worker         return DIRECTIVE_IF;
70*8975f5c5SAndroid Build Coastguard Worker     if (token->text == kDirectiveIfdef)
71*8975f5c5SAndroid Build Coastguard Worker         return DIRECTIVE_IFDEF;
72*8975f5c5SAndroid Build Coastguard Worker     if (token->text == kDirectiveIfndef)
73*8975f5c5SAndroid Build Coastguard Worker         return DIRECTIVE_IFNDEF;
74*8975f5c5SAndroid Build Coastguard Worker     if (token->text == kDirectiveElse)
75*8975f5c5SAndroid Build Coastguard Worker         return DIRECTIVE_ELSE;
76*8975f5c5SAndroid Build Coastguard Worker     if (token->text == kDirectiveElif)
77*8975f5c5SAndroid Build Coastguard Worker         return DIRECTIVE_ELIF;
78*8975f5c5SAndroid Build Coastguard Worker     if (token->text == kDirectiveEndif)
79*8975f5c5SAndroid Build Coastguard Worker         return DIRECTIVE_ENDIF;
80*8975f5c5SAndroid Build Coastguard Worker     if (token->text == kDirectiveError)
81*8975f5c5SAndroid Build Coastguard Worker         return DIRECTIVE_ERROR;
82*8975f5c5SAndroid Build Coastguard Worker     if (token->text == kDirectivePragma)
83*8975f5c5SAndroid Build Coastguard Worker         return DIRECTIVE_PRAGMA;
84*8975f5c5SAndroid Build Coastguard Worker     if (token->text == kDirectiveExtension)
85*8975f5c5SAndroid Build Coastguard Worker         return DIRECTIVE_EXTENSION;
86*8975f5c5SAndroid Build Coastguard Worker     if (token->text == kDirectiveVersion)
87*8975f5c5SAndroid Build Coastguard Worker         return DIRECTIVE_VERSION;
88*8975f5c5SAndroid Build Coastguard Worker     if (token->text == kDirectiveLine)
89*8975f5c5SAndroid Build Coastguard Worker         return DIRECTIVE_LINE;
90*8975f5c5SAndroid Build Coastguard Worker 
91*8975f5c5SAndroid Build Coastguard Worker     return DIRECTIVE_NONE;
92*8975f5c5SAndroid Build Coastguard Worker }
93*8975f5c5SAndroid Build Coastguard Worker 
isConditionalDirective(DirectiveType directive)94*8975f5c5SAndroid Build Coastguard Worker bool isConditionalDirective(DirectiveType directive)
95*8975f5c5SAndroid Build Coastguard Worker {
96*8975f5c5SAndroid Build Coastguard Worker     switch (directive)
97*8975f5c5SAndroid Build Coastguard Worker     {
98*8975f5c5SAndroid Build Coastguard Worker         case DIRECTIVE_IF:
99*8975f5c5SAndroid Build Coastguard Worker         case DIRECTIVE_IFDEF:
100*8975f5c5SAndroid Build Coastguard Worker         case DIRECTIVE_IFNDEF:
101*8975f5c5SAndroid Build Coastguard Worker         case DIRECTIVE_ELSE:
102*8975f5c5SAndroid Build Coastguard Worker         case DIRECTIVE_ELIF:
103*8975f5c5SAndroid Build Coastguard Worker         case DIRECTIVE_ENDIF:
104*8975f5c5SAndroid Build Coastguard Worker             return true;
105*8975f5c5SAndroid Build Coastguard Worker         default:
106*8975f5c5SAndroid Build Coastguard Worker             return false;
107*8975f5c5SAndroid Build Coastguard Worker     }
108*8975f5c5SAndroid Build Coastguard Worker }
109*8975f5c5SAndroid Build Coastguard Worker 
110*8975f5c5SAndroid Build Coastguard Worker // Returns true if the token represents End Of Directive.
isEOD(const pp::Token * token)111*8975f5c5SAndroid Build Coastguard Worker bool isEOD(const pp::Token *token)
112*8975f5c5SAndroid Build Coastguard Worker {
113*8975f5c5SAndroid Build Coastguard Worker     return (token->type == '\n') || (token->type == pp::Token::LAST);
114*8975f5c5SAndroid Build Coastguard Worker }
115*8975f5c5SAndroid Build Coastguard Worker 
skipUntilEOD(pp::Lexer * lexer,pp::Token * token)116*8975f5c5SAndroid Build Coastguard Worker void skipUntilEOD(pp::Lexer *lexer, pp::Token *token)
117*8975f5c5SAndroid Build Coastguard Worker {
118*8975f5c5SAndroid Build Coastguard Worker     while (!isEOD(token))
119*8975f5c5SAndroid Build Coastguard Worker     {
120*8975f5c5SAndroid Build Coastguard Worker         lexer->lex(token);
121*8975f5c5SAndroid Build Coastguard Worker     }
122*8975f5c5SAndroid Build Coastguard Worker }
123*8975f5c5SAndroid Build Coastguard Worker 
isMacroNameReserved(const std::string & name)124*8975f5c5SAndroid Build Coastguard Worker bool isMacroNameReserved(const std::string &name)
125*8975f5c5SAndroid Build Coastguard Worker {
126*8975f5c5SAndroid Build Coastguard Worker     // Names prefixed with "GL_" and the name "defined" are reserved.
127*8975f5c5SAndroid Build Coastguard Worker     return name == "defined" || (name.substr(0, 3) == "GL_");
128*8975f5c5SAndroid Build Coastguard Worker }
129*8975f5c5SAndroid Build Coastguard Worker 
hasDoubleUnderscores(const std::string & name)130*8975f5c5SAndroid Build Coastguard Worker bool hasDoubleUnderscores(const std::string &name)
131*8975f5c5SAndroid Build Coastguard Worker {
132*8975f5c5SAndroid Build Coastguard Worker     return (name.find("__") != std::string::npos);
133*8975f5c5SAndroid Build Coastguard Worker }
134*8975f5c5SAndroid Build Coastguard Worker 
isMacroPredefined(const std::string & name,const pp::MacroSet & macroSet)135*8975f5c5SAndroid Build Coastguard Worker bool isMacroPredefined(const std::string &name, const pp::MacroSet &macroSet)
136*8975f5c5SAndroid Build Coastguard Worker {
137*8975f5c5SAndroid Build Coastguard Worker     pp::MacroSet::const_iterator iter = macroSet.find(name);
138*8975f5c5SAndroid Build Coastguard Worker     return iter != macroSet.end() ? iter->second->predefined : false;
139*8975f5c5SAndroid Build Coastguard Worker }
140*8975f5c5SAndroid Build Coastguard Worker 
141*8975f5c5SAndroid Build Coastguard Worker }  // namespace
142*8975f5c5SAndroid Build Coastguard Worker 
143*8975f5c5SAndroid Build Coastguard Worker namespace pp
144*8975f5c5SAndroid Build Coastguard Worker {
DirectiveParser(Tokenizer * tokenizer,MacroSet * macroSet,Diagnostics * diagnostics,DirectiveHandler * directiveHandler,const PreprocessorSettings & settings)145*8975f5c5SAndroid Build Coastguard Worker DirectiveParser::DirectiveParser(Tokenizer *tokenizer,
146*8975f5c5SAndroid Build Coastguard Worker                                  MacroSet *macroSet,
147*8975f5c5SAndroid Build Coastguard Worker                                  Diagnostics *diagnostics,
148*8975f5c5SAndroid Build Coastguard Worker                                  DirectiveHandler *directiveHandler,
149*8975f5c5SAndroid Build Coastguard Worker                                  const PreprocessorSettings &settings)
150*8975f5c5SAndroid Build Coastguard Worker     : mHandledVersion(false),
151*8975f5c5SAndroid Build Coastguard Worker       mPastFirstStatement(false),
152*8975f5c5SAndroid Build Coastguard Worker       mSeenNonPreprocessorToken(false),
153*8975f5c5SAndroid Build Coastguard Worker       mTokenizer(tokenizer),
154*8975f5c5SAndroid Build Coastguard Worker       mMacroSet(macroSet),
155*8975f5c5SAndroid Build Coastguard Worker       mDiagnostics(diagnostics),
156*8975f5c5SAndroid Build Coastguard Worker       mDirectiveHandler(directiveHandler),
157*8975f5c5SAndroid Build Coastguard Worker       mShaderVersion(100),
158*8975f5c5SAndroid Build Coastguard Worker       mSettings(settings)
159*8975f5c5SAndroid Build Coastguard Worker {}
160*8975f5c5SAndroid Build Coastguard Worker 
~DirectiveParser()161*8975f5c5SAndroid Build Coastguard Worker DirectiveParser::~DirectiveParser() {}
162*8975f5c5SAndroid Build Coastguard Worker 
lex(Token * token)163*8975f5c5SAndroid Build Coastguard Worker void DirectiveParser::lex(Token *token)
164*8975f5c5SAndroid Build Coastguard Worker {
165*8975f5c5SAndroid Build Coastguard Worker     do
166*8975f5c5SAndroid Build Coastguard Worker     {
167*8975f5c5SAndroid Build Coastguard Worker         mTokenizer->lex(token);
168*8975f5c5SAndroid Build Coastguard Worker 
169*8975f5c5SAndroid Build Coastguard Worker         if (token->type == Token::PP_HASH)
170*8975f5c5SAndroid Build Coastguard Worker         {
171*8975f5c5SAndroid Build Coastguard Worker             parseDirective(token);
172*8975f5c5SAndroid Build Coastguard Worker             mPastFirstStatement = true;
173*8975f5c5SAndroid Build Coastguard Worker         }
174*8975f5c5SAndroid Build Coastguard Worker         else if (!isEOD(token) && !skipping())
175*8975f5c5SAndroid Build Coastguard Worker         {
176*8975f5c5SAndroid Build Coastguard Worker             mSeenNonPreprocessorToken = true;
177*8975f5c5SAndroid Build Coastguard Worker             if (!mHandledVersion)
178*8975f5c5SAndroid Build Coastguard Worker             {
179*8975f5c5SAndroid Build Coastguard Worker                 // If #version does not appear before first token, then this is
180*8975f5c5SAndroid Build Coastguard Worker                 // an ESSL1 shader without a version directive
181*8975f5c5SAndroid Build Coastguard Worker                 handleVersion(token->location);
182*8975f5c5SAndroid Build Coastguard Worker             }
183*8975f5c5SAndroid Build Coastguard Worker         }
184*8975f5c5SAndroid Build Coastguard Worker 
185*8975f5c5SAndroid Build Coastguard Worker         if (token->type == Token::LAST)
186*8975f5c5SAndroid Build Coastguard Worker         {
187*8975f5c5SAndroid Build Coastguard Worker             if (!mConditionalStack.empty())
188*8975f5c5SAndroid Build Coastguard Worker             {
189*8975f5c5SAndroid Build Coastguard Worker                 const ConditionalBlock &block = mConditionalStack.back();
190*8975f5c5SAndroid Build Coastguard Worker                 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNTERMINATED, block.location,
191*8975f5c5SAndroid Build Coastguard Worker                                      block.type);
192*8975f5c5SAndroid Build Coastguard Worker             }
193*8975f5c5SAndroid Build Coastguard Worker             break;
194*8975f5c5SAndroid Build Coastguard Worker         }
195*8975f5c5SAndroid Build Coastguard Worker 
196*8975f5c5SAndroid Build Coastguard Worker     } while (skipping() || (token->type == '\n'));
197*8975f5c5SAndroid Build Coastguard Worker 
198*8975f5c5SAndroid Build Coastguard Worker     mPastFirstStatement = true;
199*8975f5c5SAndroid Build Coastguard Worker }
200*8975f5c5SAndroid Build Coastguard Worker 
parseDirective(Token * token)201*8975f5c5SAndroid Build Coastguard Worker void DirectiveParser::parseDirective(Token *token)
202*8975f5c5SAndroid Build Coastguard Worker {
203*8975f5c5SAndroid Build Coastguard Worker     ASSERT(token->type == Token::PP_HASH);
204*8975f5c5SAndroid Build Coastguard Worker 
205*8975f5c5SAndroid Build Coastguard Worker     mTokenizer->lex(token);
206*8975f5c5SAndroid Build Coastguard Worker     if (isEOD(token))
207*8975f5c5SAndroid Build Coastguard Worker     {
208*8975f5c5SAndroid Build Coastguard Worker         // Empty Directive.
209*8975f5c5SAndroid Build Coastguard Worker         return;
210*8975f5c5SAndroid Build Coastguard Worker     }
211*8975f5c5SAndroid Build Coastguard Worker 
212*8975f5c5SAndroid Build Coastguard Worker     DirectiveType directive = getDirective(token);
213*8975f5c5SAndroid Build Coastguard Worker 
214*8975f5c5SAndroid Build Coastguard Worker     if (!mHandledVersion && directive != DIRECTIVE_VERSION)
215*8975f5c5SAndroid Build Coastguard Worker     {
216*8975f5c5SAndroid Build Coastguard Worker         // If first directive is not #version, then this is an ESSL1 shader
217*8975f5c5SAndroid Build Coastguard Worker         // without a version directive
218*8975f5c5SAndroid Build Coastguard Worker         handleVersion(token->location);
219*8975f5c5SAndroid Build Coastguard Worker     }
220*8975f5c5SAndroid Build Coastguard Worker 
221*8975f5c5SAndroid Build Coastguard Worker     // While in an excluded conditional block/group,
222*8975f5c5SAndroid Build Coastguard Worker     // we only parse conditional directives.
223*8975f5c5SAndroid Build Coastguard Worker     if (skipping() && !isConditionalDirective(directive))
224*8975f5c5SAndroid Build Coastguard Worker     {
225*8975f5c5SAndroid Build Coastguard Worker         skipUntilEOD(mTokenizer, token);
226*8975f5c5SAndroid Build Coastguard Worker         return;
227*8975f5c5SAndroid Build Coastguard Worker     }
228*8975f5c5SAndroid Build Coastguard Worker 
229*8975f5c5SAndroid Build Coastguard Worker     switch (directive)
230*8975f5c5SAndroid Build Coastguard Worker     {
231*8975f5c5SAndroid Build Coastguard Worker         case DIRECTIVE_NONE:
232*8975f5c5SAndroid Build Coastguard Worker             mDiagnostics->report(Diagnostics::PP_DIRECTIVE_INVALID_NAME, token->location,
233*8975f5c5SAndroid Build Coastguard Worker                                  token->text);
234*8975f5c5SAndroid Build Coastguard Worker             skipUntilEOD(mTokenizer, token);
235*8975f5c5SAndroid Build Coastguard Worker             break;
236*8975f5c5SAndroid Build Coastguard Worker         case DIRECTIVE_DEFINE:
237*8975f5c5SAndroid Build Coastguard Worker             parseDefine(token);
238*8975f5c5SAndroid Build Coastguard Worker             break;
239*8975f5c5SAndroid Build Coastguard Worker         case DIRECTIVE_UNDEF:
240*8975f5c5SAndroid Build Coastguard Worker             parseUndef(token);
241*8975f5c5SAndroid Build Coastguard Worker             break;
242*8975f5c5SAndroid Build Coastguard Worker         case DIRECTIVE_IF:
243*8975f5c5SAndroid Build Coastguard Worker             parseIf(token);
244*8975f5c5SAndroid Build Coastguard Worker             break;
245*8975f5c5SAndroid Build Coastguard Worker         case DIRECTIVE_IFDEF:
246*8975f5c5SAndroid Build Coastguard Worker             parseIfdef(token);
247*8975f5c5SAndroid Build Coastguard Worker             break;
248*8975f5c5SAndroid Build Coastguard Worker         case DIRECTIVE_IFNDEF:
249*8975f5c5SAndroid Build Coastguard Worker             parseIfndef(token);
250*8975f5c5SAndroid Build Coastguard Worker             break;
251*8975f5c5SAndroid Build Coastguard Worker         case DIRECTIVE_ELSE:
252*8975f5c5SAndroid Build Coastguard Worker             parseElse(token);
253*8975f5c5SAndroid Build Coastguard Worker             break;
254*8975f5c5SAndroid Build Coastguard Worker         case DIRECTIVE_ELIF:
255*8975f5c5SAndroid Build Coastguard Worker             parseElif(token);
256*8975f5c5SAndroid Build Coastguard Worker             break;
257*8975f5c5SAndroid Build Coastguard Worker         case DIRECTIVE_ENDIF:
258*8975f5c5SAndroid Build Coastguard Worker             parseEndif(token);
259*8975f5c5SAndroid Build Coastguard Worker             break;
260*8975f5c5SAndroid Build Coastguard Worker         case DIRECTIVE_ERROR:
261*8975f5c5SAndroid Build Coastguard Worker             parseError(token);
262*8975f5c5SAndroid Build Coastguard Worker             break;
263*8975f5c5SAndroid Build Coastguard Worker         case DIRECTIVE_PRAGMA:
264*8975f5c5SAndroid Build Coastguard Worker             parsePragma(token);
265*8975f5c5SAndroid Build Coastguard Worker             break;
266*8975f5c5SAndroid Build Coastguard Worker         case DIRECTIVE_EXTENSION:
267*8975f5c5SAndroid Build Coastguard Worker             parseExtension(token);
268*8975f5c5SAndroid Build Coastguard Worker             break;
269*8975f5c5SAndroid Build Coastguard Worker         case DIRECTIVE_VERSION:
270*8975f5c5SAndroid Build Coastguard Worker             parseVersion(token);
271*8975f5c5SAndroid Build Coastguard Worker             break;
272*8975f5c5SAndroid Build Coastguard Worker         case DIRECTIVE_LINE:
273*8975f5c5SAndroid Build Coastguard Worker             parseLine(token);
274*8975f5c5SAndroid Build Coastguard Worker             break;
275*8975f5c5SAndroid Build Coastguard Worker         default:
276*8975f5c5SAndroid Build Coastguard Worker             UNREACHABLE();
277*8975f5c5SAndroid Build Coastguard Worker             break;
278*8975f5c5SAndroid Build Coastguard Worker     }
279*8975f5c5SAndroid Build Coastguard Worker 
280*8975f5c5SAndroid Build Coastguard Worker     skipUntilEOD(mTokenizer, token);
281*8975f5c5SAndroid Build Coastguard Worker     if (token->type == Token::LAST)
282*8975f5c5SAndroid Build Coastguard Worker     {
283*8975f5c5SAndroid Build Coastguard Worker         mDiagnostics->report(Diagnostics::PP_EOF_IN_DIRECTIVE, token->location, token->text);
284*8975f5c5SAndroid Build Coastguard Worker     }
285*8975f5c5SAndroid Build Coastguard Worker }
286*8975f5c5SAndroid Build Coastguard Worker 
parseDefine(Token * token)287*8975f5c5SAndroid Build Coastguard Worker void DirectiveParser::parseDefine(Token *token)
288*8975f5c5SAndroid Build Coastguard Worker {
289*8975f5c5SAndroid Build Coastguard Worker     ASSERT(getDirective(token) == DIRECTIVE_DEFINE);
290*8975f5c5SAndroid Build Coastguard Worker 
291*8975f5c5SAndroid Build Coastguard Worker     mTokenizer->lex(token);
292*8975f5c5SAndroid Build Coastguard Worker     if (token->type != Token::IDENTIFIER)
293*8975f5c5SAndroid Build Coastguard Worker     {
294*8975f5c5SAndroid Build Coastguard Worker         mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
295*8975f5c5SAndroid Build Coastguard Worker         return;
296*8975f5c5SAndroid Build Coastguard Worker     }
297*8975f5c5SAndroid Build Coastguard Worker     if (isMacroPredefined(token->text, *mMacroSet))
298*8975f5c5SAndroid Build Coastguard Worker     {
299*8975f5c5SAndroid Build Coastguard Worker         mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_REDEFINED, token->location,
300*8975f5c5SAndroid Build Coastguard Worker                              token->text);
301*8975f5c5SAndroid Build Coastguard Worker         return;
302*8975f5c5SAndroid Build Coastguard Worker     }
303*8975f5c5SAndroid Build Coastguard Worker     if (isMacroNameReserved(token->text))
304*8975f5c5SAndroid Build Coastguard Worker     {
305*8975f5c5SAndroid Build Coastguard Worker         mDiagnostics->report(Diagnostics::PP_MACRO_NAME_RESERVED, token->location, token->text);
306*8975f5c5SAndroid Build Coastguard Worker         return;
307*8975f5c5SAndroid Build Coastguard Worker     }
308*8975f5c5SAndroid Build Coastguard Worker     // Using double underscores is allowed, but may result in unintended
309*8975f5c5SAndroid Build Coastguard Worker     // behavior, so a warning is issued. At the time of writing this was
310*8975f5c5SAndroid Build Coastguard Worker     // specified in ESSL 3.10, but the intent judging from Khronos
311*8975f5c5SAndroid Build Coastguard Worker     // discussions and dEQP tests was that double underscores should be
312*8975f5c5SAndroid Build Coastguard Worker     // allowed in earlier ESSL versions too.
313*8975f5c5SAndroid Build Coastguard Worker     if (hasDoubleUnderscores(token->text))
314*8975f5c5SAndroid Build Coastguard Worker     {
315*8975f5c5SAndroid Build Coastguard Worker         mDiagnostics->report(Diagnostics::PP_WARNING_MACRO_NAME_RESERVED, token->location,
316*8975f5c5SAndroid Build Coastguard Worker                              token->text);
317*8975f5c5SAndroid Build Coastguard Worker     }
318*8975f5c5SAndroid Build Coastguard Worker 
319*8975f5c5SAndroid Build Coastguard Worker     std::shared_ptr<Macro> macro = std::make_shared<Macro>();
320*8975f5c5SAndroid Build Coastguard Worker     macro->type                  = Macro::kTypeObj;
321*8975f5c5SAndroid Build Coastguard Worker     macro->name                  = token->text;
322*8975f5c5SAndroid Build Coastguard Worker 
323*8975f5c5SAndroid Build Coastguard Worker     mTokenizer->lex(token);
324*8975f5c5SAndroid Build Coastguard Worker     if (token->type == '(' && !token->hasLeadingSpace())
325*8975f5c5SAndroid Build Coastguard Worker     {
326*8975f5c5SAndroid Build Coastguard Worker         // Function-like macro. Collect arguments.
327*8975f5c5SAndroid Build Coastguard Worker         macro->type = Macro::kTypeFunc;
328*8975f5c5SAndroid Build Coastguard Worker         do
329*8975f5c5SAndroid Build Coastguard Worker         {
330*8975f5c5SAndroid Build Coastguard Worker             mTokenizer->lex(token);
331*8975f5c5SAndroid Build Coastguard Worker             if (token->type != Token::IDENTIFIER)
332*8975f5c5SAndroid Build Coastguard Worker                 break;
333*8975f5c5SAndroid Build Coastguard Worker 
334*8975f5c5SAndroid Build Coastguard Worker             if (std::find(macro->parameters.begin(), macro->parameters.end(), token->text) !=
335*8975f5c5SAndroid Build Coastguard Worker                 macro->parameters.end())
336*8975f5c5SAndroid Build Coastguard Worker             {
337*8975f5c5SAndroid Build Coastguard Worker                 mDiagnostics->report(Diagnostics::PP_MACRO_DUPLICATE_PARAMETER_NAMES,
338*8975f5c5SAndroid Build Coastguard Worker                                      token->location, token->text);
339*8975f5c5SAndroid Build Coastguard Worker                 return;
340*8975f5c5SAndroid Build Coastguard Worker             }
341*8975f5c5SAndroid Build Coastguard Worker 
342*8975f5c5SAndroid Build Coastguard Worker             macro->parameters.push_back(token->text);
343*8975f5c5SAndroid Build Coastguard Worker 
344*8975f5c5SAndroid Build Coastguard Worker             mTokenizer->lex(token);  // Get ','.
345*8975f5c5SAndroid Build Coastguard Worker         } while (token->type == ',');
346*8975f5c5SAndroid Build Coastguard Worker 
347*8975f5c5SAndroid Build Coastguard Worker         if (token->type != ')')
348*8975f5c5SAndroid Build Coastguard Worker         {
349*8975f5c5SAndroid Build Coastguard Worker             mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
350*8975f5c5SAndroid Build Coastguard Worker             return;
351*8975f5c5SAndroid Build Coastguard Worker         }
352*8975f5c5SAndroid Build Coastguard Worker         mTokenizer->lex(token);  // Get ')'.
353*8975f5c5SAndroid Build Coastguard Worker     }
354*8975f5c5SAndroid Build Coastguard Worker 
355*8975f5c5SAndroid Build Coastguard Worker     while ((token->type != '\n') && (token->type != Token::LAST))
356*8975f5c5SAndroid Build Coastguard Worker     {
357*8975f5c5SAndroid Build Coastguard Worker         // Reset the token location because it is unnecessary in replacement
358*8975f5c5SAndroid Build Coastguard Worker         // list. Resetting it also allows us to reuse Token::equals() to
359*8975f5c5SAndroid Build Coastguard Worker         // compare macros.
360*8975f5c5SAndroid Build Coastguard Worker         token->location = SourceLocation();
361*8975f5c5SAndroid Build Coastguard Worker         macro->replacements.push_back(*token);
362*8975f5c5SAndroid Build Coastguard Worker         mTokenizer->lex(token);
363*8975f5c5SAndroid Build Coastguard Worker     }
364*8975f5c5SAndroid Build Coastguard Worker     if (!macro->replacements.empty())
365*8975f5c5SAndroid Build Coastguard Worker     {
366*8975f5c5SAndroid Build Coastguard Worker         // Whitespace preceding the replacement list is not considered part of
367*8975f5c5SAndroid Build Coastguard Worker         // the replacement list for either form of macro.
368*8975f5c5SAndroid Build Coastguard Worker         macro->replacements.front().setHasLeadingSpace(false);
369*8975f5c5SAndroid Build Coastguard Worker     }
370*8975f5c5SAndroid Build Coastguard Worker 
371*8975f5c5SAndroid Build Coastguard Worker     // Check for macro redefinition.
372*8975f5c5SAndroid Build Coastguard Worker     MacroSet::const_iterator iter = mMacroSet->find(macro->name);
373*8975f5c5SAndroid Build Coastguard Worker     if (iter != mMacroSet->end() && !macro->equals(*iter->second))
374*8975f5c5SAndroid Build Coastguard Worker     {
375*8975f5c5SAndroid Build Coastguard Worker         mDiagnostics->report(Diagnostics::PP_MACRO_REDEFINED, token->location, macro->name);
376*8975f5c5SAndroid Build Coastguard Worker         return;
377*8975f5c5SAndroid Build Coastguard Worker     }
378*8975f5c5SAndroid Build Coastguard Worker     mMacroSet->insert(std::make_pair(macro->name, macro));
379*8975f5c5SAndroid Build Coastguard Worker }
380*8975f5c5SAndroid Build Coastguard Worker 
parseUndef(Token * token)381*8975f5c5SAndroid Build Coastguard Worker void DirectiveParser::parseUndef(Token *token)
382*8975f5c5SAndroid Build Coastguard Worker {
383*8975f5c5SAndroid Build Coastguard Worker     ASSERT(getDirective(token) == DIRECTIVE_UNDEF);
384*8975f5c5SAndroid Build Coastguard Worker 
385*8975f5c5SAndroid Build Coastguard Worker     mTokenizer->lex(token);
386*8975f5c5SAndroid Build Coastguard Worker     if (token->type != Token::IDENTIFIER)
387*8975f5c5SAndroid Build Coastguard Worker     {
388*8975f5c5SAndroid Build Coastguard Worker         mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
389*8975f5c5SAndroid Build Coastguard Worker         return;
390*8975f5c5SAndroid Build Coastguard Worker     }
391*8975f5c5SAndroid Build Coastguard Worker 
392*8975f5c5SAndroid Build Coastguard Worker     MacroSet::iterator iter = mMacroSet->find(token->text);
393*8975f5c5SAndroid Build Coastguard Worker     if (iter != mMacroSet->end())
394*8975f5c5SAndroid Build Coastguard Worker     {
395*8975f5c5SAndroid Build Coastguard Worker         if (iter->second->predefined)
396*8975f5c5SAndroid Build Coastguard Worker         {
397*8975f5c5SAndroid Build Coastguard Worker             mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_UNDEFINED, token->location,
398*8975f5c5SAndroid Build Coastguard Worker                                  token->text);
399*8975f5c5SAndroid Build Coastguard Worker             return;
400*8975f5c5SAndroid Build Coastguard Worker         }
401*8975f5c5SAndroid Build Coastguard Worker         else if (iter->second->expansionCount > 0)
402*8975f5c5SAndroid Build Coastguard Worker         {
403*8975f5c5SAndroid Build Coastguard Worker             mDiagnostics->report(Diagnostics::PP_MACRO_UNDEFINED_WHILE_INVOKED, token->location,
404*8975f5c5SAndroid Build Coastguard Worker                                  token->text);
405*8975f5c5SAndroid Build Coastguard Worker             return;
406*8975f5c5SAndroid Build Coastguard Worker         }
407*8975f5c5SAndroid Build Coastguard Worker         else
408*8975f5c5SAndroid Build Coastguard Worker         {
409*8975f5c5SAndroid Build Coastguard Worker             mMacroSet->erase(iter);
410*8975f5c5SAndroid Build Coastguard Worker         }
411*8975f5c5SAndroid Build Coastguard Worker     }
412*8975f5c5SAndroid Build Coastguard Worker 
413*8975f5c5SAndroid Build Coastguard Worker     mTokenizer->lex(token);
414*8975f5c5SAndroid Build Coastguard Worker     if (!isEOD(token))
415*8975f5c5SAndroid Build Coastguard Worker     {
416*8975f5c5SAndroid Build Coastguard Worker         mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
417*8975f5c5SAndroid Build Coastguard Worker         skipUntilEOD(mTokenizer, token);
418*8975f5c5SAndroid Build Coastguard Worker     }
419*8975f5c5SAndroid Build Coastguard Worker }
420*8975f5c5SAndroid Build Coastguard Worker 
parseIf(Token * token)421*8975f5c5SAndroid Build Coastguard Worker void DirectiveParser::parseIf(Token *token)
422*8975f5c5SAndroid Build Coastguard Worker {
423*8975f5c5SAndroid Build Coastguard Worker     ASSERT(getDirective(token) == DIRECTIVE_IF);
424*8975f5c5SAndroid Build Coastguard Worker     parseConditionalIf(token);
425*8975f5c5SAndroid Build Coastguard Worker }
426*8975f5c5SAndroid Build Coastguard Worker 
parseIfdef(Token * token)427*8975f5c5SAndroid Build Coastguard Worker void DirectiveParser::parseIfdef(Token *token)
428*8975f5c5SAndroid Build Coastguard Worker {
429*8975f5c5SAndroid Build Coastguard Worker     ASSERT(getDirective(token) == DIRECTIVE_IFDEF);
430*8975f5c5SAndroid Build Coastguard Worker     parseConditionalIf(token);
431*8975f5c5SAndroid Build Coastguard Worker }
432*8975f5c5SAndroid Build Coastguard Worker 
parseIfndef(Token * token)433*8975f5c5SAndroid Build Coastguard Worker void DirectiveParser::parseIfndef(Token *token)
434*8975f5c5SAndroid Build Coastguard Worker {
435*8975f5c5SAndroid Build Coastguard Worker     ASSERT(getDirective(token) == DIRECTIVE_IFNDEF);
436*8975f5c5SAndroid Build Coastguard Worker     parseConditionalIf(token);
437*8975f5c5SAndroid Build Coastguard Worker }
438*8975f5c5SAndroid Build Coastguard Worker 
parseElse(Token * token)439*8975f5c5SAndroid Build Coastguard Worker void DirectiveParser::parseElse(Token *token)
440*8975f5c5SAndroid Build Coastguard Worker {
441*8975f5c5SAndroid Build Coastguard Worker     ASSERT(getDirective(token) == DIRECTIVE_ELSE);
442*8975f5c5SAndroid Build Coastguard Worker 
443*8975f5c5SAndroid Build Coastguard Worker     if (mConditionalStack.empty())
444*8975f5c5SAndroid Build Coastguard Worker     {
445*8975f5c5SAndroid Build Coastguard Worker         mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_WITHOUT_IF, token->location,
446*8975f5c5SAndroid Build Coastguard Worker                              token->text);
447*8975f5c5SAndroid Build Coastguard Worker         skipUntilEOD(mTokenizer, token);
448*8975f5c5SAndroid Build Coastguard Worker         return;
449*8975f5c5SAndroid Build Coastguard Worker     }
450*8975f5c5SAndroid Build Coastguard Worker 
451*8975f5c5SAndroid Build Coastguard Worker     ConditionalBlock &block = mConditionalStack.back();
452*8975f5c5SAndroid Build Coastguard Worker     if (block.skipBlock)
453*8975f5c5SAndroid Build Coastguard Worker     {
454*8975f5c5SAndroid Build Coastguard Worker         // No diagnostics. Just skip the whole line.
455*8975f5c5SAndroid Build Coastguard Worker         skipUntilEOD(mTokenizer, token);
456*8975f5c5SAndroid Build Coastguard Worker         return;
457*8975f5c5SAndroid Build Coastguard Worker     }
458*8975f5c5SAndroid Build Coastguard Worker     if (block.foundElseGroup)
459*8975f5c5SAndroid Build Coastguard Worker     {
460*8975f5c5SAndroid Build Coastguard Worker         mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_AFTER_ELSE, token->location,
461*8975f5c5SAndroid Build Coastguard Worker                              token->text);
462*8975f5c5SAndroid Build Coastguard Worker         skipUntilEOD(mTokenizer, token);
463*8975f5c5SAndroid Build Coastguard Worker         return;
464*8975f5c5SAndroid Build Coastguard Worker     }
465*8975f5c5SAndroid Build Coastguard Worker 
466*8975f5c5SAndroid Build Coastguard Worker     block.foundElseGroup  = true;
467*8975f5c5SAndroid Build Coastguard Worker     block.skipGroup       = block.foundValidGroup;
468*8975f5c5SAndroid Build Coastguard Worker     block.foundValidGroup = true;
469*8975f5c5SAndroid Build Coastguard Worker 
470*8975f5c5SAndroid Build Coastguard Worker     // Check if there are extra tokens after #else.
471*8975f5c5SAndroid Build Coastguard Worker     mTokenizer->lex(token);
472*8975f5c5SAndroid Build Coastguard Worker     if (!isEOD(token))
473*8975f5c5SAndroid Build Coastguard Worker     {
474*8975f5c5SAndroid Build Coastguard Worker         mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location,
475*8975f5c5SAndroid Build Coastguard Worker                              token->text);
476*8975f5c5SAndroid Build Coastguard Worker         skipUntilEOD(mTokenizer, token);
477*8975f5c5SAndroid Build Coastguard Worker     }
478*8975f5c5SAndroid Build Coastguard Worker }
479*8975f5c5SAndroid Build Coastguard Worker 
parseElif(Token * token)480*8975f5c5SAndroid Build Coastguard Worker void DirectiveParser::parseElif(Token *token)
481*8975f5c5SAndroid Build Coastguard Worker {
482*8975f5c5SAndroid Build Coastguard Worker     ASSERT(getDirective(token) == DIRECTIVE_ELIF);
483*8975f5c5SAndroid Build Coastguard Worker 
484*8975f5c5SAndroid Build Coastguard Worker     if (mConditionalStack.empty())
485*8975f5c5SAndroid Build Coastguard Worker     {
486*8975f5c5SAndroid Build Coastguard Worker         mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_WITHOUT_IF, token->location,
487*8975f5c5SAndroid Build Coastguard Worker                              token->text);
488*8975f5c5SAndroid Build Coastguard Worker         skipUntilEOD(mTokenizer, token);
489*8975f5c5SAndroid Build Coastguard Worker         return;
490*8975f5c5SAndroid Build Coastguard Worker     }
491*8975f5c5SAndroid Build Coastguard Worker 
492*8975f5c5SAndroid Build Coastguard Worker     ConditionalBlock &block = mConditionalStack.back();
493*8975f5c5SAndroid Build Coastguard Worker     if (block.skipBlock)
494*8975f5c5SAndroid Build Coastguard Worker     {
495*8975f5c5SAndroid Build Coastguard Worker         // No diagnostics. Just skip the whole line.
496*8975f5c5SAndroid Build Coastguard Worker         skipUntilEOD(mTokenizer, token);
497*8975f5c5SAndroid Build Coastguard Worker         return;
498*8975f5c5SAndroid Build Coastguard Worker     }
499*8975f5c5SAndroid Build Coastguard Worker     if (block.foundElseGroup)
500*8975f5c5SAndroid Build Coastguard Worker     {
501*8975f5c5SAndroid Build Coastguard Worker         mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_AFTER_ELSE, token->location,
502*8975f5c5SAndroid Build Coastguard Worker                              token->text);
503*8975f5c5SAndroid Build Coastguard Worker         skipUntilEOD(mTokenizer, token);
504*8975f5c5SAndroid Build Coastguard Worker         return;
505*8975f5c5SAndroid Build Coastguard Worker     }
506*8975f5c5SAndroid Build Coastguard Worker     if (block.foundValidGroup)
507*8975f5c5SAndroid Build Coastguard Worker     {
508*8975f5c5SAndroid Build Coastguard Worker         // Do not parse the expression.
509*8975f5c5SAndroid Build Coastguard Worker         // Also be careful not to emit a diagnostic.
510*8975f5c5SAndroid Build Coastguard Worker         block.skipGroup = true;
511*8975f5c5SAndroid Build Coastguard Worker         skipUntilEOD(mTokenizer, token);
512*8975f5c5SAndroid Build Coastguard Worker         return;
513*8975f5c5SAndroid Build Coastguard Worker     }
514*8975f5c5SAndroid Build Coastguard Worker 
515*8975f5c5SAndroid Build Coastguard Worker     int expression        = parseExpressionIf(token);
516*8975f5c5SAndroid Build Coastguard Worker     block.skipGroup       = expression == 0;
517*8975f5c5SAndroid Build Coastguard Worker     block.foundValidGroup = expression != 0;
518*8975f5c5SAndroid Build Coastguard Worker }
519*8975f5c5SAndroid Build Coastguard Worker 
parseEndif(Token * token)520*8975f5c5SAndroid Build Coastguard Worker void DirectiveParser::parseEndif(Token *token)
521*8975f5c5SAndroid Build Coastguard Worker {
522*8975f5c5SAndroid Build Coastguard Worker     ASSERT(getDirective(token) == DIRECTIVE_ENDIF);
523*8975f5c5SAndroid Build Coastguard Worker 
524*8975f5c5SAndroid Build Coastguard Worker     if (mConditionalStack.empty())
525*8975f5c5SAndroid Build Coastguard Worker     {
526*8975f5c5SAndroid Build Coastguard Worker         mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ENDIF_WITHOUT_IF, token->location,
527*8975f5c5SAndroid Build Coastguard Worker                              token->text);
528*8975f5c5SAndroid Build Coastguard Worker         skipUntilEOD(mTokenizer, token);
529*8975f5c5SAndroid Build Coastguard Worker         return;
530*8975f5c5SAndroid Build Coastguard Worker     }
531*8975f5c5SAndroid Build Coastguard Worker 
532*8975f5c5SAndroid Build Coastguard Worker     mConditionalStack.pop_back();
533*8975f5c5SAndroid Build Coastguard Worker 
534*8975f5c5SAndroid Build Coastguard Worker     // Check if there are tokens after #endif.
535*8975f5c5SAndroid Build Coastguard Worker     mTokenizer->lex(token);
536*8975f5c5SAndroid Build Coastguard Worker     if (!isEOD(token))
537*8975f5c5SAndroid Build Coastguard Worker     {
538*8975f5c5SAndroid Build Coastguard Worker         mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location,
539*8975f5c5SAndroid Build Coastguard Worker                              token->text);
540*8975f5c5SAndroid Build Coastguard Worker         skipUntilEOD(mTokenizer, token);
541*8975f5c5SAndroid Build Coastguard Worker     }
542*8975f5c5SAndroid Build Coastguard Worker }
543*8975f5c5SAndroid Build Coastguard Worker 
parseError(Token * token)544*8975f5c5SAndroid Build Coastguard Worker void DirectiveParser::parseError(Token *token)
545*8975f5c5SAndroid Build Coastguard Worker {
546*8975f5c5SAndroid Build Coastguard Worker     ASSERT(getDirective(token) == DIRECTIVE_ERROR);
547*8975f5c5SAndroid Build Coastguard Worker 
548*8975f5c5SAndroid Build Coastguard Worker     std::ostringstream stream;
549*8975f5c5SAndroid Build Coastguard Worker     mTokenizer->lex(token);
550*8975f5c5SAndroid Build Coastguard Worker     while ((token->type != '\n') && (token->type != Token::LAST))
551*8975f5c5SAndroid Build Coastguard Worker     {
552*8975f5c5SAndroid Build Coastguard Worker         stream << *token;
553*8975f5c5SAndroid Build Coastguard Worker         mTokenizer->lex(token);
554*8975f5c5SAndroid Build Coastguard Worker     }
555*8975f5c5SAndroid Build Coastguard Worker     mDirectiveHandler->handleError(token->location, stream.str());
556*8975f5c5SAndroid Build Coastguard Worker }
557*8975f5c5SAndroid Build Coastguard Worker 
558*8975f5c5SAndroid Build Coastguard Worker // Parses pragma of form: #pragma name[(value)].
parsePragma(Token * token)559*8975f5c5SAndroid Build Coastguard Worker void DirectiveParser::parsePragma(Token *token)
560*8975f5c5SAndroid Build Coastguard Worker {
561*8975f5c5SAndroid Build Coastguard Worker     ASSERT(getDirective(token) == DIRECTIVE_PRAGMA);
562*8975f5c5SAndroid Build Coastguard Worker 
563*8975f5c5SAndroid Build Coastguard Worker     enum State
564*8975f5c5SAndroid Build Coastguard Worker     {
565*8975f5c5SAndroid Build Coastguard Worker         PRAGMA_NAME,
566*8975f5c5SAndroid Build Coastguard Worker         LEFT_PAREN,
567*8975f5c5SAndroid Build Coastguard Worker         PRAGMA_VALUE,
568*8975f5c5SAndroid Build Coastguard Worker         RIGHT_PAREN
569*8975f5c5SAndroid Build Coastguard Worker     };
570*8975f5c5SAndroid Build Coastguard Worker 
571*8975f5c5SAndroid Build Coastguard Worker     bool valid = true;
572*8975f5c5SAndroid Build Coastguard Worker     std::string name, value;
573*8975f5c5SAndroid Build Coastguard Worker     int state = PRAGMA_NAME;
574*8975f5c5SAndroid Build Coastguard Worker 
575*8975f5c5SAndroid Build Coastguard Worker     mTokenizer->lex(token);
576*8975f5c5SAndroid Build Coastguard Worker     bool stdgl = token->text == "STDGL";
577*8975f5c5SAndroid Build Coastguard Worker     if (stdgl)
578*8975f5c5SAndroid Build Coastguard Worker     {
579*8975f5c5SAndroid Build Coastguard Worker         mTokenizer->lex(token);
580*8975f5c5SAndroid Build Coastguard Worker     }
581*8975f5c5SAndroid Build Coastguard Worker     while ((token->type != '\n') && (token->type != Token::LAST))
582*8975f5c5SAndroid Build Coastguard Worker     {
583*8975f5c5SAndroid Build Coastguard Worker         switch (state++)
584*8975f5c5SAndroid Build Coastguard Worker         {
585*8975f5c5SAndroid Build Coastguard Worker             case PRAGMA_NAME:
586*8975f5c5SAndroid Build Coastguard Worker                 name  = token->text;
587*8975f5c5SAndroid Build Coastguard Worker                 valid = valid && (token->type == Token::IDENTIFIER);
588*8975f5c5SAndroid Build Coastguard Worker                 break;
589*8975f5c5SAndroid Build Coastguard Worker             case LEFT_PAREN:
590*8975f5c5SAndroid Build Coastguard Worker                 valid = valid && (token->type == '(');
591*8975f5c5SAndroid Build Coastguard Worker                 break;
592*8975f5c5SAndroid Build Coastguard Worker             case PRAGMA_VALUE:
593*8975f5c5SAndroid Build Coastguard Worker                 value = token->text;
594*8975f5c5SAndroid Build Coastguard Worker                 valid = valid && (token->type == Token::IDENTIFIER);
595*8975f5c5SAndroid Build Coastguard Worker                 break;
596*8975f5c5SAndroid Build Coastguard Worker             case RIGHT_PAREN:
597*8975f5c5SAndroid Build Coastguard Worker                 valid = valid && (token->type == ')');
598*8975f5c5SAndroid Build Coastguard Worker                 break;
599*8975f5c5SAndroid Build Coastguard Worker             default:
600*8975f5c5SAndroid Build Coastguard Worker                 valid = false;
601*8975f5c5SAndroid Build Coastguard Worker                 break;
602*8975f5c5SAndroid Build Coastguard Worker         }
603*8975f5c5SAndroid Build Coastguard Worker         mTokenizer->lex(token);
604*8975f5c5SAndroid Build Coastguard Worker     }
605*8975f5c5SAndroid Build Coastguard Worker 
606*8975f5c5SAndroid Build Coastguard Worker     valid = valid && ((state == PRAGMA_NAME) ||     // Empty pragma.
607*8975f5c5SAndroid Build Coastguard Worker                       (state == LEFT_PAREN) ||      // Without value.
608*8975f5c5SAndroid Build Coastguard Worker                       (state == RIGHT_PAREN + 1));  // With value.
609*8975f5c5SAndroid Build Coastguard Worker     if (!valid)
610*8975f5c5SAndroid Build Coastguard Worker     {
611*8975f5c5SAndroid Build Coastguard Worker         mDiagnostics->report(Diagnostics::PP_UNRECOGNIZED_PRAGMA, token->location, name);
612*8975f5c5SAndroid Build Coastguard Worker     }
613*8975f5c5SAndroid Build Coastguard Worker     else if (state > PRAGMA_NAME)  // Do not notify for empty pragma.
614*8975f5c5SAndroid Build Coastguard Worker     {
615*8975f5c5SAndroid Build Coastguard Worker         mDirectiveHandler->handlePragma(token->location, name, value, stdgl);
616*8975f5c5SAndroid Build Coastguard Worker     }
617*8975f5c5SAndroid Build Coastguard Worker }
618*8975f5c5SAndroid Build Coastguard Worker 
parseExtension(Token * token)619*8975f5c5SAndroid Build Coastguard Worker void DirectiveParser::parseExtension(Token *token)
620*8975f5c5SAndroid Build Coastguard Worker {
621*8975f5c5SAndroid Build Coastguard Worker     ASSERT(getDirective(token) == DIRECTIVE_EXTENSION);
622*8975f5c5SAndroid Build Coastguard Worker 
623*8975f5c5SAndroid Build Coastguard Worker     enum State
624*8975f5c5SAndroid Build Coastguard Worker     {
625*8975f5c5SAndroid Build Coastguard Worker         EXT_NAME,
626*8975f5c5SAndroid Build Coastguard Worker         COLON,
627*8975f5c5SAndroid Build Coastguard Worker         EXT_BEHAVIOR
628*8975f5c5SAndroid Build Coastguard Worker     };
629*8975f5c5SAndroid Build Coastguard Worker 
630*8975f5c5SAndroid Build Coastguard Worker     bool valid = true;
631*8975f5c5SAndroid Build Coastguard Worker     std::string name, behavior;
632*8975f5c5SAndroid Build Coastguard Worker     int state = EXT_NAME;
633*8975f5c5SAndroid Build Coastguard Worker 
634*8975f5c5SAndroid Build Coastguard Worker     mTokenizer->lex(token);
635*8975f5c5SAndroid Build Coastguard Worker     while ((token->type != '\n') && (token->type != Token::LAST))
636*8975f5c5SAndroid Build Coastguard Worker     {
637*8975f5c5SAndroid Build Coastguard Worker         switch (state++)
638*8975f5c5SAndroid Build Coastguard Worker         {
639*8975f5c5SAndroid Build Coastguard Worker             case EXT_NAME:
640*8975f5c5SAndroid Build Coastguard Worker                 if (valid && (token->type != Token::IDENTIFIER))
641*8975f5c5SAndroid Build Coastguard Worker                 {
642*8975f5c5SAndroid Build Coastguard Worker                     mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_NAME, token->location,
643*8975f5c5SAndroid Build Coastguard Worker                                          token->text);
644*8975f5c5SAndroid Build Coastguard Worker                     valid = false;
645*8975f5c5SAndroid Build Coastguard Worker                 }
646*8975f5c5SAndroid Build Coastguard Worker                 if (valid)
647*8975f5c5SAndroid Build Coastguard Worker                     name = token->text;
648*8975f5c5SAndroid Build Coastguard Worker                 break;
649*8975f5c5SAndroid Build Coastguard Worker             case COLON:
650*8975f5c5SAndroid Build Coastguard Worker                 if (valid && (token->type != ':'))
651*8975f5c5SAndroid Build Coastguard Worker                 {
652*8975f5c5SAndroid Build Coastguard Worker                     mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
653*8975f5c5SAndroid Build Coastguard Worker                                          token->text);
654*8975f5c5SAndroid Build Coastguard Worker                     valid = false;
655*8975f5c5SAndroid Build Coastguard Worker                 }
656*8975f5c5SAndroid Build Coastguard Worker                 break;
657*8975f5c5SAndroid Build Coastguard Worker             case EXT_BEHAVIOR:
658*8975f5c5SAndroid Build Coastguard Worker                 if (valid && (token->type != Token::IDENTIFIER))
659*8975f5c5SAndroid Build Coastguard Worker                 {
660*8975f5c5SAndroid Build Coastguard Worker                     mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_BEHAVIOR,
661*8975f5c5SAndroid Build Coastguard Worker                                          token->location, token->text);
662*8975f5c5SAndroid Build Coastguard Worker                     valid = false;
663*8975f5c5SAndroid Build Coastguard Worker                 }
664*8975f5c5SAndroid Build Coastguard Worker                 if (valid)
665*8975f5c5SAndroid Build Coastguard Worker                     behavior = token->text;
666*8975f5c5SAndroid Build Coastguard Worker                 break;
667*8975f5c5SAndroid Build Coastguard Worker             default:
668*8975f5c5SAndroid Build Coastguard Worker                 if (valid)
669*8975f5c5SAndroid Build Coastguard Worker                 {
670*8975f5c5SAndroid Build Coastguard Worker                     mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
671*8975f5c5SAndroid Build Coastguard Worker                                          token->text);
672*8975f5c5SAndroid Build Coastguard Worker                     valid = false;
673*8975f5c5SAndroid Build Coastguard Worker                 }
674*8975f5c5SAndroid Build Coastguard Worker                 break;
675*8975f5c5SAndroid Build Coastguard Worker         }
676*8975f5c5SAndroid Build Coastguard Worker         mTokenizer->lex(token);
677*8975f5c5SAndroid Build Coastguard Worker     }
678*8975f5c5SAndroid Build Coastguard Worker     if (valid && (state != EXT_BEHAVIOR + 1))
679*8975f5c5SAndroid Build Coastguard Worker     {
680*8975f5c5SAndroid Build Coastguard Worker         mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_DIRECTIVE, token->location,
681*8975f5c5SAndroid Build Coastguard Worker                              token->text);
682*8975f5c5SAndroid Build Coastguard Worker         valid = false;
683*8975f5c5SAndroid Build Coastguard Worker     }
684*8975f5c5SAndroid Build Coastguard Worker     if (valid && mSeenNonPreprocessorToken)
685*8975f5c5SAndroid Build Coastguard Worker     {
686*8975f5c5SAndroid Build Coastguard Worker         if (mShaderVersion >= 300)
687*8975f5c5SAndroid Build Coastguard Worker         {
688*8975f5c5SAndroid Build Coastguard Worker             mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL3,
689*8975f5c5SAndroid Build Coastguard Worker                                  token->location, token->text);
690*8975f5c5SAndroid Build Coastguard Worker             valid = false;
691*8975f5c5SAndroid Build Coastguard Worker         }
692*8975f5c5SAndroid Build Coastguard Worker         else
693*8975f5c5SAndroid Build Coastguard Worker         {
694*8975f5c5SAndroid Build Coastguard Worker             if (mSettings.shaderSpec == SH_WEBGL_SPEC)
695*8975f5c5SAndroid Build Coastguard Worker             {
696*8975f5c5SAndroid Build Coastguard Worker                 mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_WEBGL,
697*8975f5c5SAndroid Build Coastguard Worker                                      token->location, token->text);
698*8975f5c5SAndroid Build Coastguard Worker             }
699*8975f5c5SAndroid Build Coastguard Worker             else
700*8975f5c5SAndroid Build Coastguard Worker             {
701*8975f5c5SAndroid Build Coastguard Worker                 mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1,
702*8975f5c5SAndroid Build Coastguard Worker                                      token->location, token->text);
703*8975f5c5SAndroid Build Coastguard Worker                 // This is just a warning on CHROME OS http://anglebug.com/42262661
704*8975f5c5SAndroid Build Coastguard Worker #if !defined(ANGLE_PLATFORM_CHROMEOS)
705*8975f5c5SAndroid Build Coastguard Worker                 valid = false;
706*8975f5c5SAndroid Build Coastguard Worker #endif
707*8975f5c5SAndroid Build Coastguard Worker             }
708*8975f5c5SAndroid Build Coastguard Worker         }
709*8975f5c5SAndroid Build Coastguard Worker     }
710*8975f5c5SAndroid Build Coastguard Worker     if (valid)
711*8975f5c5SAndroid Build Coastguard Worker         mDirectiveHandler->handleExtension(token->location, name, behavior);
712*8975f5c5SAndroid Build Coastguard Worker }
713*8975f5c5SAndroid Build Coastguard Worker 
parseVersion(Token * token)714*8975f5c5SAndroid Build Coastguard Worker void DirectiveParser::parseVersion(Token *token)
715*8975f5c5SAndroid Build Coastguard Worker {
716*8975f5c5SAndroid Build Coastguard Worker     ASSERT(getDirective(token) == DIRECTIVE_VERSION);
717*8975f5c5SAndroid Build Coastguard Worker 
718*8975f5c5SAndroid Build Coastguard Worker     if (mPastFirstStatement)
719*8975f5c5SAndroid Build Coastguard Worker     {
720*8975f5c5SAndroid Build Coastguard Worker         mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_STATEMENT, token->location,
721*8975f5c5SAndroid Build Coastguard Worker                              token->text);
722*8975f5c5SAndroid Build Coastguard Worker         skipUntilEOD(mTokenizer, token);
723*8975f5c5SAndroid Build Coastguard Worker         return;
724*8975f5c5SAndroid Build Coastguard Worker     }
725*8975f5c5SAndroid Build Coastguard Worker 
726*8975f5c5SAndroid Build Coastguard Worker     enum State
727*8975f5c5SAndroid Build Coastguard Worker     {
728*8975f5c5SAndroid Build Coastguard Worker         VERSION_NUMBER,
729*8975f5c5SAndroid Build Coastguard Worker         VERSION_PROFILE_ES,
730*8975f5c5SAndroid Build Coastguard Worker         VERSION_ENDLINE
731*8975f5c5SAndroid Build Coastguard Worker     };
732*8975f5c5SAndroid Build Coastguard Worker 
733*8975f5c5SAndroid Build Coastguard Worker     bool valid  = true;
734*8975f5c5SAndroid Build Coastguard Worker     int version = 0;
735*8975f5c5SAndroid Build Coastguard Worker     int state   = VERSION_NUMBER;
736*8975f5c5SAndroid Build Coastguard Worker 
737*8975f5c5SAndroid Build Coastguard Worker     mTokenizer->lex(token);
738*8975f5c5SAndroid Build Coastguard Worker     while (valid && (token->type != '\n') && (token->type != Token::LAST))
739*8975f5c5SAndroid Build Coastguard Worker     {
740*8975f5c5SAndroid Build Coastguard Worker         switch (state)
741*8975f5c5SAndroid Build Coastguard Worker         {
742*8975f5c5SAndroid Build Coastguard Worker             case VERSION_NUMBER:
743*8975f5c5SAndroid Build Coastguard Worker                 if (token->type != Token::CONST_INT)
744*8975f5c5SAndroid Build Coastguard Worker                 {
745*8975f5c5SAndroid Build Coastguard Worker                     mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_NUMBER, token->location,
746*8975f5c5SAndroid Build Coastguard Worker                                          token->text);
747*8975f5c5SAndroid Build Coastguard Worker                     valid = false;
748*8975f5c5SAndroid Build Coastguard Worker                 }
749*8975f5c5SAndroid Build Coastguard Worker                 if (valid && !token->iValue(&version))
750*8975f5c5SAndroid Build Coastguard Worker                 {
751*8975f5c5SAndroid Build Coastguard Worker                     mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW, token->location,
752*8975f5c5SAndroid Build Coastguard Worker                                          token->text);
753*8975f5c5SAndroid Build Coastguard Worker                     valid = false;
754*8975f5c5SAndroid Build Coastguard Worker                 }
755*8975f5c5SAndroid Build Coastguard Worker                 if (valid)
756*8975f5c5SAndroid Build Coastguard Worker                 {
757*8975f5c5SAndroid Build Coastguard Worker                     if (version < 300)
758*8975f5c5SAndroid Build Coastguard Worker                     {
759*8975f5c5SAndroid Build Coastguard Worker                         state = VERSION_ENDLINE;
760*8975f5c5SAndroid Build Coastguard Worker                     }
761*8975f5c5SAndroid Build Coastguard Worker                     else
762*8975f5c5SAndroid Build Coastguard Worker                     {
763*8975f5c5SAndroid Build Coastguard Worker                         state = VERSION_PROFILE_ES;
764*8975f5c5SAndroid Build Coastguard Worker                     }
765*8975f5c5SAndroid Build Coastguard Worker                 }
766*8975f5c5SAndroid Build Coastguard Worker                 break;
767*8975f5c5SAndroid Build Coastguard Worker             case VERSION_PROFILE_ES:
768*8975f5c5SAndroid Build Coastguard Worker                 if (token->type != Token::IDENTIFIER || token->text != "es")
769*8975f5c5SAndroid Build Coastguard Worker                 {
770*8975f5c5SAndroid Build Coastguard Worker                     mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE, token->location,
771*8975f5c5SAndroid Build Coastguard Worker                                          token->text);
772*8975f5c5SAndroid Build Coastguard Worker                     valid = false;
773*8975f5c5SAndroid Build Coastguard Worker                 }
774*8975f5c5SAndroid Build Coastguard Worker                 state = VERSION_ENDLINE;
775*8975f5c5SAndroid Build Coastguard Worker                 break;
776*8975f5c5SAndroid Build Coastguard Worker             default:
777*8975f5c5SAndroid Build Coastguard Worker                 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
778*8975f5c5SAndroid Build Coastguard Worker                                      token->text);
779*8975f5c5SAndroid Build Coastguard Worker                 valid = false;
780*8975f5c5SAndroid Build Coastguard Worker                 break;
781*8975f5c5SAndroid Build Coastguard Worker         }
782*8975f5c5SAndroid Build Coastguard Worker 
783*8975f5c5SAndroid Build Coastguard Worker         mTokenizer->lex(token);
784*8975f5c5SAndroid Build Coastguard Worker     }
785*8975f5c5SAndroid Build Coastguard Worker 
786*8975f5c5SAndroid Build Coastguard Worker     if (valid && (state != VERSION_ENDLINE))
787*8975f5c5SAndroid Build Coastguard Worker     {
788*8975f5c5SAndroid Build Coastguard Worker         mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE, token->location,
789*8975f5c5SAndroid Build Coastguard Worker                              token->text);
790*8975f5c5SAndroid Build Coastguard Worker         valid = false;
791*8975f5c5SAndroid Build Coastguard Worker     }
792*8975f5c5SAndroid Build Coastguard Worker 
793*8975f5c5SAndroid Build Coastguard Worker     if (valid && version >= 300 && token->location.line > 1)
794*8975f5c5SAndroid Build Coastguard Worker     {
795*8975f5c5SAndroid Build Coastguard Worker         mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_LINE_ESSL3, token->location,
796*8975f5c5SAndroid Build Coastguard Worker                              token->text);
797*8975f5c5SAndroid Build Coastguard Worker         valid = false;
798*8975f5c5SAndroid Build Coastguard Worker     }
799*8975f5c5SAndroid Build Coastguard Worker 
800*8975f5c5SAndroid Build Coastguard Worker     if (valid)
801*8975f5c5SAndroid Build Coastguard Worker     {
802*8975f5c5SAndroid Build Coastguard Worker         mShaderVersion = version;
803*8975f5c5SAndroid Build Coastguard Worker         handleVersion(token->location);
804*8975f5c5SAndroid Build Coastguard Worker     }
805*8975f5c5SAndroid Build Coastguard Worker }
806*8975f5c5SAndroid Build Coastguard Worker 
parseLine(Token * token)807*8975f5c5SAndroid Build Coastguard Worker void DirectiveParser::parseLine(Token *token)
808*8975f5c5SAndroid Build Coastguard Worker {
809*8975f5c5SAndroid Build Coastguard Worker     ASSERT(getDirective(token) == DIRECTIVE_LINE);
810*8975f5c5SAndroid Build Coastguard Worker 
811*8975f5c5SAndroid Build Coastguard Worker     bool valid            = true;
812*8975f5c5SAndroid Build Coastguard Worker     bool parsedFileNumber = false;
813*8975f5c5SAndroid Build Coastguard Worker     int line = 0, file = 0;
814*8975f5c5SAndroid Build Coastguard Worker 
815*8975f5c5SAndroid Build Coastguard Worker     MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, mSettings, false);
816*8975f5c5SAndroid Build Coastguard Worker 
817*8975f5c5SAndroid Build Coastguard Worker     // Lex the first token after "#line" so we can check it for EOD.
818*8975f5c5SAndroid Build Coastguard Worker     macroExpander.lex(token);
819*8975f5c5SAndroid Build Coastguard Worker 
820*8975f5c5SAndroid Build Coastguard Worker     if (isEOD(token))
821*8975f5c5SAndroid Build Coastguard Worker     {
822*8975f5c5SAndroid Build Coastguard Worker         mDiagnostics->report(Diagnostics::PP_INVALID_LINE_DIRECTIVE, token->location, token->text);
823*8975f5c5SAndroid Build Coastguard Worker         valid = false;
824*8975f5c5SAndroid Build Coastguard Worker     }
825*8975f5c5SAndroid Build Coastguard Worker     else
826*8975f5c5SAndroid Build Coastguard Worker     {
827*8975f5c5SAndroid Build Coastguard Worker         ExpressionParser expressionParser(&macroExpander, mDiagnostics);
828*8975f5c5SAndroid Build Coastguard Worker         ExpressionParser::ErrorSettings errorSettings;
829*8975f5c5SAndroid Build Coastguard Worker 
830*8975f5c5SAndroid Build Coastguard Worker         // See GLES3 section 12.42
831*8975f5c5SAndroid Build Coastguard Worker         errorSettings.integerLiteralsMustFit32BitSignedRange = true;
832*8975f5c5SAndroid Build Coastguard Worker 
833*8975f5c5SAndroid Build Coastguard Worker         errorSettings.unexpectedIdentifier = Diagnostics::PP_INVALID_LINE_NUMBER;
834*8975f5c5SAndroid Build Coastguard Worker         // The first token was lexed earlier to check if it was EOD. Include
835*8975f5c5SAndroid Build Coastguard Worker         // the token in parsing for a second time by setting the
836*8975f5c5SAndroid Build Coastguard Worker         // parsePresetToken flag to true.
837*8975f5c5SAndroid Build Coastguard Worker         expressionParser.parse(token, &line, true, errorSettings, &valid);
838*8975f5c5SAndroid Build Coastguard Worker         if (!isEOD(token) && valid)
839*8975f5c5SAndroid Build Coastguard Worker         {
840*8975f5c5SAndroid Build Coastguard Worker             errorSettings.unexpectedIdentifier = Diagnostics::PP_INVALID_FILE_NUMBER;
841*8975f5c5SAndroid Build Coastguard Worker             // After parsing the line expression expressionParser has also
842*8975f5c5SAndroid Build Coastguard Worker             // advanced to the first token of the file expression - this is the
843*8975f5c5SAndroid Build Coastguard Worker             // token that makes the parser reduce the "input" rule for the line
844*8975f5c5SAndroid Build Coastguard Worker             // expression and stop. So we're using parsePresetToken = true here
845*8975f5c5SAndroid Build Coastguard Worker             // as well.
846*8975f5c5SAndroid Build Coastguard Worker             expressionParser.parse(token, &file, true, errorSettings, &valid);
847*8975f5c5SAndroid Build Coastguard Worker             parsedFileNumber = true;
848*8975f5c5SAndroid Build Coastguard Worker         }
849*8975f5c5SAndroid Build Coastguard Worker         if (!isEOD(token))
850*8975f5c5SAndroid Build Coastguard Worker         {
851*8975f5c5SAndroid Build Coastguard Worker             if (valid)
852*8975f5c5SAndroid Build Coastguard Worker             {
853*8975f5c5SAndroid Build Coastguard Worker                 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
854*8975f5c5SAndroid Build Coastguard Worker                                      token->text);
855*8975f5c5SAndroid Build Coastguard Worker                 valid = false;
856*8975f5c5SAndroid Build Coastguard Worker             }
857*8975f5c5SAndroid Build Coastguard Worker             skipUntilEOD(mTokenizer, token);
858*8975f5c5SAndroid Build Coastguard Worker         }
859*8975f5c5SAndroid Build Coastguard Worker     }
860*8975f5c5SAndroid Build Coastguard Worker 
861*8975f5c5SAndroid Build Coastguard Worker     if (valid)
862*8975f5c5SAndroid Build Coastguard Worker     {
863*8975f5c5SAndroid Build Coastguard Worker         mTokenizer->setLineNumber(line);
864*8975f5c5SAndroid Build Coastguard Worker         if (parsedFileNumber)
865*8975f5c5SAndroid Build Coastguard Worker             mTokenizer->setFileNumber(file);
866*8975f5c5SAndroid Build Coastguard Worker     }
867*8975f5c5SAndroid Build Coastguard Worker }
868*8975f5c5SAndroid Build Coastguard Worker 
skipping() const869*8975f5c5SAndroid Build Coastguard Worker bool DirectiveParser::skipping() const
870*8975f5c5SAndroid Build Coastguard Worker {
871*8975f5c5SAndroid Build Coastguard Worker     if (mConditionalStack.empty())
872*8975f5c5SAndroid Build Coastguard Worker         return false;
873*8975f5c5SAndroid Build Coastguard Worker 
874*8975f5c5SAndroid Build Coastguard Worker     const ConditionalBlock &block = mConditionalStack.back();
875*8975f5c5SAndroid Build Coastguard Worker     return block.skipBlock || block.skipGroup;
876*8975f5c5SAndroid Build Coastguard Worker }
877*8975f5c5SAndroid Build Coastguard Worker 
parseConditionalIf(Token * token)878*8975f5c5SAndroid Build Coastguard Worker void DirectiveParser::parseConditionalIf(Token *token)
879*8975f5c5SAndroid Build Coastguard Worker {
880*8975f5c5SAndroid Build Coastguard Worker     ConditionalBlock block;
881*8975f5c5SAndroid Build Coastguard Worker     block.type     = token->text;
882*8975f5c5SAndroid Build Coastguard Worker     block.location = token->location;
883*8975f5c5SAndroid Build Coastguard Worker 
884*8975f5c5SAndroid Build Coastguard Worker     if (skipping())
885*8975f5c5SAndroid Build Coastguard Worker     {
886*8975f5c5SAndroid Build Coastguard Worker         // This conditional block is inside another conditional group
887*8975f5c5SAndroid Build Coastguard Worker         // which is skipped. As a consequence this whole block is skipped.
888*8975f5c5SAndroid Build Coastguard Worker         // Be careful not to parse the conditional expression that might
889*8975f5c5SAndroid Build Coastguard Worker         // emit a diagnostic.
890*8975f5c5SAndroid Build Coastguard Worker         skipUntilEOD(mTokenizer, token);
891*8975f5c5SAndroid Build Coastguard Worker         block.skipBlock = true;
892*8975f5c5SAndroid Build Coastguard Worker     }
893*8975f5c5SAndroid Build Coastguard Worker     else
894*8975f5c5SAndroid Build Coastguard Worker     {
895*8975f5c5SAndroid Build Coastguard Worker         DirectiveType directive = getDirective(token);
896*8975f5c5SAndroid Build Coastguard Worker 
897*8975f5c5SAndroid Build Coastguard Worker         int expression = 0;
898*8975f5c5SAndroid Build Coastguard Worker         switch (directive)
899*8975f5c5SAndroid Build Coastguard Worker         {
900*8975f5c5SAndroid Build Coastguard Worker             case DIRECTIVE_IF:
901*8975f5c5SAndroid Build Coastguard Worker                 expression = parseExpressionIf(token);
902*8975f5c5SAndroid Build Coastguard Worker                 break;
903*8975f5c5SAndroid Build Coastguard Worker             case DIRECTIVE_IFDEF:
904*8975f5c5SAndroid Build Coastguard Worker                 expression = parseExpressionIfdef(token);
905*8975f5c5SAndroid Build Coastguard Worker                 break;
906*8975f5c5SAndroid Build Coastguard Worker             case DIRECTIVE_IFNDEF:
907*8975f5c5SAndroid Build Coastguard Worker                 expression = parseExpressionIfdef(token) == 0 ? 1 : 0;
908*8975f5c5SAndroid Build Coastguard Worker                 break;
909*8975f5c5SAndroid Build Coastguard Worker             default:
910*8975f5c5SAndroid Build Coastguard Worker                 UNREACHABLE();
911*8975f5c5SAndroid Build Coastguard Worker                 break;
912*8975f5c5SAndroid Build Coastguard Worker         }
913*8975f5c5SAndroid Build Coastguard Worker         block.skipGroup       = expression == 0;
914*8975f5c5SAndroid Build Coastguard Worker         block.foundValidGroup = expression != 0;
915*8975f5c5SAndroid Build Coastguard Worker     }
916*8975f5c5SAndroid Build Coastguard Worker     mConditionalStack.push_back(block);
917*8975f5c5SAndroid Build Coastguard Worker }
918*8975f5c5SAndroid Build Coastguard Worker 
parseExpressionIf(Token * token)919*8975f5c5SAndroid Build Coastguard Worker int DirectiveParser::parseExpressionIf(Token *token)
920*8975f5c5SAndroid Build Coastguard Worker {
921*8975f5c5SAndroid Build Coastguard Worker     ASSERT((getDirective(token) == DIRECTIVE_IF) || (getDirective(token) == DIRECTIVE_ELIF));
922*8975f5c5SAndroid Build Coastguard Worker 
923*8975f5c5SAndroid Build Coastguard Worker     MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, mSettings, true);
924*8975f5c5SAndroid Build Coastguard Worker     ExpressionParser expressionParser(&macroExpander, mDiagnostics);
925*8975f5c5SAndroid Build Coastguard Worker 
926*8975f5c5SAndroid Build Coastguard Worker     int expression = 0;
927*8975f5c5SAndroid Build Coastguard Worker     ExpressionParser::ErrorSettings errorSettings;
928*8975f5c5SAndroid Build Coastguard Worker     errorSettings.integerLiteralsMustFit32BitSignedRange = false;
929*8975f5c5SAndroid Build Coastguard Worker     errorSettings.unexpectedIdentifier = Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN;
930*8975f5c5SAndroid Build Coastguard Worker 
931*8975f5c5SAndroid Build Coastguard Worker     bool valid = true;
932*8975f5c5SAndroid Build Coastguard Worker     expressionParser.parse(token, &expression, false, errorSettings, &valid);
933*8975f5c5SAndroid Build Coastguard Worker 
934*8975f5c5SAndroid Build Coastguard Worker     // Check if there are tokens after #if expression.
935*8975f5c5SAndroid Build Coastguard Worker     if (!isEOD(token))
936*8975f5c5SAndroid Build Coastguard Worker     {
937*8975f5c5SAndroid Build Coastguard Worker         mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location,
938*8975f5c5SAndroid Build Coastguard Worker                              token->text);
939*8975f5c5SAndroid Build Coastguard Worker         skipUntilEOD(mTokenizer, token);
940*8975f5c5SAndroid Build Coastguard Worker     }
941*8975f5c5SAndroid Build Coastguard Worker 
942*8975f5c5SAndroid Build Coastguard Worker     return expression;
943*8975f5c5SAndroid Build Coastguard Worker }
944*8975f5c5SAndroid Build Coastguard Worker 
parseExpressionIfdef(Token * token)945*8975f5c5SAndroid Build Coastguard Worker int DirectiveParser::parseExpressionIfdef(Token *token)
946*8975f5c5SAndroid Build Coastguard Worker {
947*8975f5c5SAndroid Build Coastguard Worker     ASSERT((getDirective(token) == DIRECTIVE_IFDEF) || (getDirective(token) == DIRECTIVE_IFNDEF));
948*8975f5c5SAndroid Build Coastguard Worker 
949*8975f5c5SAndroid Build Coastguard Worker     mTokenizer->lex(token);
950*8975f5c5SAndroid Build Coastguard Worker     if (token->type != Token::IDENTIFIER)
951*8975f5c5SAndroid Build Coastguard Worker     {
952*8975f5c5SAndroid Build Coastguard Worker         mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
953*8975f5c5SAndroid Build Coastguard Worker         skipUntilEOD(mTokenizer, token);
954*8975f5c5SAndroid Build Coastguard Worker         return 0;
955*8975f5c5SAndroid Build Coastguard Worker     }
956*8975f5c5SAndroid Build Coastguard Worker 
957*8975f5c5SAndroid Build Coastguard Worker     MacroSet::const_iterator iter = mMacroSet->find(token->text);
958*8975f5c5SAndroid Build Coastguard Worker     int expression                = iter != mMacroSet->end() ? 1 : 0;
959*8975f5c5SAndroid Build Coastguard Worker 
960*8975f5c5SAndroid Build Coastguard Worker     // Check if there are tokens after #ifdef expression.
961*8975f5c5SAndroid Build Coastguard Worker     mTokenizer->lex(token);
962*8975f5c5SAndroid Build Coastguard Worker     if (!isEOD(token))
963*8975f5c5SAndroid Build Coastguard Worker     {
964*8975f5c5SAndroid Build Coastguard Worker         mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location,
965*8975f5c5SAndroid Build Coastguard Worker                              token->text);
966*8975f5c5SAndroid Build Coastguard Worker         skipUntilEOD(mTokenizer, token);
967*8975f5c5SAndroid Build Coastguard Worker     }
968*8975f5c5SAndroid Build Coastguard Worker     return expression;
969*8975f5c5SAndroid Build Coastguard Worker }
970*8975f5c5SAndroid Build Coastguard Worker 
handleVersion(const SourceLocation & location)971*8975f5c5SAndroid Build Coastguard Worker void DirectiveParser::handleVersion(const SourceLocation &location)
972*8975f5c5SAndroid Build Coastguard Worker {
973*8975f5c5SAndroid Build Coastguard Worker     PredefineMacro(mMacroSet, "__VERSION__", mShaderVersion);
974*8975f5c5SAndroid Build Coastguard Worker     mDirectiveHandler->handleVersion(location, mShaderVersion, mSettings.shaderSpec, mMacroSet);
975*8975f5c5SAndroid Build Coastguard Worker     mHandledVersion = true;
976*8975f5c5SAndroid Build Coastguard Worker }
977*8975f5c5SAndroid Build Coastguard Worker 
978*8975f5c5SAndroid Build Coastguard Worker }  // namespace pp
979*8975f5c5SAndroid Build Coastguard Worker 
980*8975f5c5SAndroid Build Coastguard Worker }  // namespace angle
981