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