1 //
2 // Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
3 // Copyright (C) 2013 LunarG, Inc.
4 // Copyright (C) 2017 ARM Limited.
5 // Copyright (C) 2015-2018 Google, Inc.
6 // Copyright (c) 2023, Mobica Limited
7 //
8 // All rights reserved.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions
12 // are met:
13 //
14 // Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // Redistributions in binary form must reproduce the above
18 // copyright notice, this list of conditions and the following
19 // disclaimer in the documentation and/or other materials provided
20 // with the distribution.
21 //
22 // Neither the name of 3Dlabs Inc. Ltd. nor the names of its
23 // contributors may be used to endorse or promote products derived
24 // from this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
29 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
30 // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
31 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
32 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
33 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
34 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
36 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 // POSSIBILITY OF SUCH DAMAGE.
38 //
39 /****************************************************************************\
40 Copyright (c) 2002, NVIDIA Corporation.
41
42 NVIDIA Corporation("NVIDIA") supplies this software to you in
43 consideration of your agreement to the following terms, and your use,
44 installation, modification or redistribution of this NVIDIA software
45 constitutes acceptance of these terms. If you do not agree with these
46 terms, please do not use, install, modify or redistribute this NVIDIA
47 software.
48
49 In consideration of your agreement to abide by the following terms, and
50 subject to these terms, NVIDIA grants you a personal, non-exclusive
51 license, under NVIDIA's copyrights in this original NVIDIA software (the
52 "NVIDIA Software"), to use, reproduce, modify and redistribute the
53 NVIDIA Software, with or without modifications, in source and/or binary
54 forms; provided that if you redistribute the NVIDIA Software, you must
55 retain the copyright notice of NVIDIA, this notice and the following
56 text and disclaimers in all such redistributions of the NVIDIA Software.
57 Neither the name, trademarks, service marks nor logos of NVIDIA
58 Corporation may be used to endorse or promote products derived from the
59 NVIDIA Software without specific prior written permission from NVIDIA.
60 Except as expressly stated in this notice, no other rights or licenses
61 express or implied, are granted by NVIDIA herein, including but not
62 limited to any patent rights that may be infringed by your derivative
63 works or by other works in which the NVIDIA Software may be
64 incorporated. No hardware is licensed hereunder.
65
66 THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
67 WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
68 INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
69 NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
70 ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
71 PRODUCTS.
72
73 IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
74 INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
75 TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
76 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
77 OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
78 NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
79 TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
80 NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
81 \****************************************************************************/
82
83 #ifndef _CRT_SECURE_NO_WARNINGS
84 #define _CRT_SECURE_NO_WARNINGS
85 #endif
86
87 #include <cstdlib>
88 #include <cstring>
89
90 #include "PpContext.h"
91 #include "PpTokens.h"
92 #include "../Scan.h"
93
94 namespace glslang {
95
96 ///////////////////////////////////////////////////////////////////////////////////////////////
97 /////////////////////////////////// Floating point constants: /////////////////////////////////
98 ///////////////////////////////////////////////////////////////////////////////////////////////
99
100 //
101 // Scan a single- or double-precision floating point constant.
102 // Assumes that the scanner has seen at least one digit,
103 // followed by either a decimal '.' or the letter 'e', or a
104 // precision ending (e.g., F or LF).
105 //
106 // This is technically not correct, as the preprocessor should just
107 // accept the numeric literal along with whatever suffix it has, but
108 // currently, it stops on seeing a bad suffix, treating that as the
109 // next token. This effects things like token pasting, where it is
110 // relevant how many tokens something was broken into.
111 //
112 // See peekContinuedPasting().
lFloatConst(int len,int ch,TPpToken * ppToken)113 int TPpContext::lFloatConst(int len, int ch, TPpToken* ppToken)
114 {
115 const auto saveName = [&](int ch) {
116 if (len <= MaxTokenLength)
117 ppToken->name[len++] = static_cast<char>(ch);
118 };
119
120 // find the range of non-zero digits before the decimal point
121 int startNonZero = 0;
122 while (startNonZero < len && ppToken->name[startNonZero] == '0')
123 ++startNonZero;
124 int endNonZero = len;
125 while (endNonZero > startNonZero && ppToken->name[endNonZero-1] == '0')
126 --endNonZero;
127 int numWholeNumberDigits = endNonZero - startNonZero;
128
129 // accumulate the range's value
130 bool fastPath = numWholeNumberDigits <= 15; // when the number gets too complex, set to false
131 unsigned long long wholeNumber = 0;
132 if (fastPath) {
133 for (int i = startNonZero; i < endNonZero; ++i)
134 wholeNumber = wholeNumber * 10 + (ppToken->name[i] - '0');
135 }
136 int decimalShift = len - endNonZero;
137
138 // Decimal point:
139 bool hasDecimalOrExponent = false;
140 if (ch == '.') {
141 hasDecimalOrExponent = true;
142 saveName(ch);
143 ch = getChar();
144 int firstDecimal = len;
145
146 #ifdef ENABLE_HLSL
147 // 1.#INF or -1.#INF
148 if (ch == '#' && (ifdepth > 0 || parseContext.intermediate.getSource() == EShSourceHlsl)) {
149 if ((len < 2) ||
150 (len == 2 && ppToken->name[0] != '1') ||
151 (len == 3 && ppToken->name[1] != '1' && !(ppToken->name[0] == '-' || ppToken->name[0] == '+')) ||
152 (len > 3))
153 parseContext.ppError(ppToken->loc, "unexpected use of", "#", "");
154 else {
155 // we have 1.# or -1.# or +1.#, check for 'INF'
156 if ((ch = getChar()) != 'I' ||
157 (ch = getChar()) != 'N' ||
158 (ch = getChar()) != 'F')
159 parseContext.ppError(ppToken->loc, "expected 'INF'", "#", "");
160 else {
161 // we have [+-].#INF, and we are targeting IEEE 754, so wrap it up:
162 saveName('I');
163 saveName('N');
164 saveName('F');
165 ppToken->name[len] = '\0';
166 if (ppToken->name[0] == '-')
167 ppToken->i64val = 0xfff0000000000000; // -Infinity
168 else
169 ppToken->i64val = 0x7ff0000000000000; // +Infinity
170 return PpAtomConstFloat;
171 }
172 }
173 }
174 #endif
175
176 // Consume leading-zero digits after the decimal point
177 while (ch == '0') {
178 saveName(ch);
179 ch = getChar();
180 }
181 int startNonZeroDecimal = len;
182 int endNonZeroDecimal = len;
183
184 // Consume remaining digits, up to the exponent
185 while (ch >= '0' && ch <= '9') {
186 saveName(ch);
187 if (ch != '0')
188 endNonZeroDecimal = len;
189 ch = getChar();
190 }
191
192 // Compute accumulation up to the last non-zero digit
193 if (endNonZeroDecimal > startNonZeroDecimal) {
194 numWholeNumberDigits += endNonZeroDecimal - endNonZero - 1; // don't include the "."
195 if (numWholeNumberDigits > 15)
196 fastPath = false;
197 if (fastPath) {
198 for (int i = endNonZero; i < endNonZeroDecimal; ++i) {
199 if (ppToken->name[i] != '.')
200 wholeNumber = wholeNumber * 10 + (ppToken->name[i] - '0');
201 }
202 }
203 decimalShift = firstDecimal - endNonZeroDecimal;
204 }
205 }
206
207 // Exponent:
208 bool negativeExponent = false;
209 double exponentValue = 0.0;
210 int exponent = 0;
211 {
212 if (ch == 'e' || ch == 'E') {
213 hasDecimalOrExponent = true;
214 saveName(ch);
215 ch = getChar();
216 if (ch == '+' || ch == '-') {
217 negativeExponent = ch == '-';
218 saveName(ch);
219 ch = getChar();
220 }
221 if (ch >= '0' && ch <= '9') {
222 while (ch >= '0' && ch <= '9') {
223 exponent = exponent * 10 + (ch - '0');
224 saveName(ch);
225 ch = getChar();
226 }
227 } else {
228 parseContext.ppError(ppToken->loc, "bad character in float exponent", "", "");
229 }
230 }
231
232 // Compensate for location of decimal
233 if (negativeExponent)
234 exponent -= decimalShift;
235 else {
236 exponent += decimalShift;
237 if (exponent < 0) {
238 negativeExponent = true;
239 exponent = -exponent;
240 }
241 }
242 if (exponent > 22)
243 fastPath = false;
244
245 if (fastPath) {
246 // Compute the floating-point value of the exponent
247 exponentValue = 1.0;
248 if (exponent > 0) {
249 double expFactor = 10;
250 while (exponent > 0) {
251 if (exponent & 0x1)
252 exponentValue *= expFactor;
253 expFactor *= expFactor;
254 exponent >>= 1;
255 }
256 }
257 }
258 }
259
260 // Suffix:
261 bool isDouble = false;
262 bool isFloat16 = false;
263 if (ch == 'l' || ch == 'L') {
264 if (ifdepth == 0 && parseContext.intermediate.getSource() == EShSourceGlsl)
265 parseContext.doubleCheck(ppToken->loc, "double floating-point suffix");
266 if (ifdepth == 0 && !hasDecimalOrExponent)
267 parseContext.ppError(ppToken->loc, "float literal needs a decimal point or exponent", "", "");
268 if (parseContext.intermediate.getSource() == EShSourceGlsl) {
269 int ch2 = getChar();
270 if (ch2 != 'f' && ch2 != 'F') {
271 ungetChar();
272 ungetChar();
273 } else {
274 saveName(ch);
275 saveName(ch2);
276 isDouble = true;
277 }
278 } else if (parseContext.intermediate.getSource() == EShSourceHlsl) {
279 saveName(ch);
280 isDouble = true;
281 }
282 } else if (ch == 'h' || ch == 'H') {
283 if (ifdepth == 0 && parseContext.intermediate.getSource() == EShSourceGlsl)
284 parseContext.float16Check(ppToken->loc, "half floating-point suffix");
285 if (ifdepth == 0 && !hasDecimalOrExponent)
286 parseContext.ppError(ppToken->loc, "float literal needs a decimal point or exponent", "", "");
287 if (parseContext.intermediate.getSource() == EShSourceGlsl) {
288 int ch2 = getChar();
289 if (ch2 != 'f' && ch2 != 'F') {
290 ungetChar();
291 ungetChar();
292 } else {
293 saveName(ch);
294 saveName(ch2);
295 isFloat16 = true;
296 }
297 } else if (parseContext.intermediate.getSource() == EShSourceHlsl) {
298 saveName(ch);
299 isFloat16 = true;
300 }
301 } else
302 if (ch == 'f' || ch == 'F') {
303 if (ifdepth == 0)
304 parseContext.profileRequires(ppToken->loc, EEsProfile, 300, nullptr, "floating-point suffix");
305 if (ifdepth == 0 && !parseContext.relaxedErrors())
306 parseContext.profileRequires(ppToken->loc, ~EEsProfile, 120, nullptr, "floating-point suffix");
307 if (ifdepth == 0 && !hasDecimalOrExponent)
308 parseContext.ppError(ppToken->loc, "float literal needs a decimal point or exponent", "", "");
309 saveName(ch);
310 } else
311 ungetChar();
312
313 // Patch up the name and length for overflow
314
315 if (len > MaxTokenLength) {
316 len = MaxTokenLength;
317 parseContext.ppError(ppToken->loc, "float literal too long", "", "");
318 }
319 ppToken->name[len] = '\0';
320
321 // Compute the numerical value
322 if (fastPath) {
323 // compute the floating-point value of the exponent
324 if (exponentValue == 0.0)
325 ppToken->dval = (double)wholeNumber;
326 else if (negativeExponent)
327 ppToken->dval = (double)wholeNumber / exponentValue;
328 else
329 ppToken->dval = (double)wholeNumber * exponentValue;
330 } else {
331 // slow path
332 ppToken->dval = 0.0;
333
334 // remove suffix
335 TString numstr(ppToken->name);
336 if (numstr.back() == 'f' || numstr.back() == 'F')
337 numstr.pop_back();
338 if (numstr.back() == 'h' || numstr.back() == 'H')
339 numstr.pop_back();
340 if (numstr.back() == 'l' || numstr.back() == 'L')
341 numstr.pop_back();
342
343 // use platform library
344 strtodStream.clear();
345 strtodStream.str(numstr.c_str());
346 strtodStream >> ppToken->dval;
347 if (strtodStream.fail()) {
348 // Assume failure combined with a large exponent was overflow, in
349 // an attempt to set INF.
350 if (!negativeExponent && exponent + numWholeNumberDigits > 300)
351 ppToken->i64val = 0x7ff0000000000000; // +Infinity
352 // Assume failure combined with a small exponent was overflow.
353 if (negativeExponent && exponent + numWholeNumberDigits > 300)
354 ppToken->dval = 0.0;
355 // Unknown reason for failure. Theory is that either
356 // - the 0.0 is still there, or
357 // - something reasonable was written that is better than 0.0
358 }
359 }
360
361 // Return the right token type
362 if (isDouble)
363 return PpAtomConstDouble;
364 else if (isFloat16)
365 return PpAtomConstFloat16;
366 else
367 return PpAtomConstFloat;
368 }
369
370 // Recognize a character literal.
371 //
372 // The first ' has already been accepted, read the rest, through the closing '.
373 //
374 // Always returns PpAtomConstInt.
375 //
characterLiteral(TPpToken * ppToken)376 int TPpContext::characterLiteral(TPpToken* ppToken)
377 {
378 ppToken->name[0] = 0;
379 ppToken->ival = 0;
380
381 if (parseContext.intermediate.getSource() != EShSourceHlsl) {
382 // illegal, except in macro definition, for which case we report the character
383 return '\'';
384 }
385
386 int ch = getChar();
387 switch (ch) {
388 case '\'':
389 // As empty sequence: ''
390 parseContext.ppError(ppToken->loc, "unexpected", "\'", "");
391 return PpAtomConstInt;
392 case '\\':
393 // As escape sequence: '\XXX'
394 switch (ch = getChar()) {
395 case 'a':
396 ppToken->ival = 7;
397 break;
398 case 'b':
399 ppToken->ival = 8;
400 break;
401 case 't':
402 ppToken->ival = 9;
403 break;
404 case 'n':
405 ppToken->ival = 10;
406 break;
407 case 'v':
408 ppToken->ival = 11;
409 break;
410 case 'f':
411 ppToken->ival = 12;
412 break;
413 case 'r':
414 ppToken->ival = 13;
415 break;
416 case 'x':
417 case '0':
418 parseContext.ppError(ppToken->loc, "octal and hex sequences not supported", "\\", "");
419 break;
420 default:
421 // This catches '\'', '\"', '\?', etc.
422 // Also, things like '\C' mean the same thing as 'C'
423 // (after the above cases are filtered out).
424 ppToken->ival = ch;
425 break;
426 }
427 break;
428 default:
429 ppToken->ival = ch;
430 break;
431 }
432 ppToken->name[0] = (char)ppToken->ival;
433 ppToken->name[1] = '\0';
434 ch = getChar();
435 if (ch != '\'') {
436 parseContext.ppError(ppToken->loc, "expected", "\'", "");
437 // Look ahead for a closing '
438 do {
439 ch = getChar();
440 } while (ch != '\'' && ch != EndOfInput && ch != '\n');
441 }
442
443 return PpAtomConstInt;
444 }
445
446 //
447 // Scanner used to tokenize source stream.
448 //
449 // N.B. Invalid numeric suffixes are not consumed.//
450 // This is technically not correct, as the preprocessor should just
451 // accept the numeric literal along with whatever suffix it has, but
452 // currently, it stops on seeing a bad suffix, treating that as the
453 // next token. This effects things like token pasting, where it is
454 // relevant how many tokens something was broken into.
455 // See peekContinuedPasting().
456 //
scan(TPpToken * ppToken)457 int TPpContext::tStringInput::scan(TPpToken* ppToken)
458 {
459 int AlreadyComplained = 0;
460 int len = 0;
461 int ch = 0;
462 int ii = 0;
463 unsigned long long ival = 0;
464 const auto floatingPointChar = [&](int ch) { return ch == '.' || ch == 'e' || ch == 'E' ||
465 ch == 'f' || ch == 'F' ||
466 ch == 'h' || ch == 'H'; };
467
468 static const char* const Int64_Extensions[] = {
469 E_GL_ARB_gpu_shader_int64,
470 E_GL_EXT_shader_explicit_arithmetic_types,
471 E_GL_EXT_shader_explicit_arithmetic_types_int64 };
472 static const int Num_Int64_Extensions = sizeof(Int64_Extensions) / sizeof(Int64_Extensions[0]);
473
474 static const char* const Int16_Extensions[] = {
475 E_GL_AMD_gpu_shader_int16,
476 E_GL_EXT_shader_explicit_arithmetic_types,
477 E_GL_EXT_shader_explicit_arithmetic_types_int16 };
478 static const int Num_Int16_Extensions = sizeof(Int16_Extensions) / sizeof(Int16_Extensions[0]);
479
480 ppToken->clear();
481 ch = getch();
482 for (;;) {
483 while (ch == ' ' || ch == '\t') {
484 ppToken->space = true;
485 ch = getch();
486 }
487
488 ppToken->loc = pp->parseContext.getCurrentLoc();
489 len = 0;
490 switch (ch) {
491 default:
492 // Single character token, including EndOfInput, '#' and '\' (escaped newlines are handled at a lower level, so this is just a '\' token)
493 if (ch > PpAtomMaxSingle)
494 ch = PpAtomBadToken;
495 return ch;
496
497 case 'A': case 'B': case 'C': case 'D': case 'E':
498 case 'F': case 'G': case 'H': case 'I': case 'J':
499 case 'K': case 'L': case 'M': case 'N': case 'O':
500 case 'P': case 'Q': case 'R': case 'S': case 'T':
501 case 'U': case 'V': case 'W': case 'X': case 'Y':
502 case 'Z': case '_':
503 case 'a': case 'b': case 'c': case 'd': case 'e':
504 case 'f': case 'g': case 'h': case 'i': case 'j':
505 case 'k': case 'l': case 'm': case 'n': case 'o':
506 case 'p': case 'q': case 'r': case 's': case 't':
507 case 'u': case 'v': case 'w': case 'x': case 'y':
508 case 'z':
509 do {
510 if (len < MaxTokenLength) {
511 ppToken->name[len++] = (char)ch;
512 ch = getch();
513 } else {
514 if (! AlreadyComplained) {
515 pp->parseContext.ppError(ppToken->loc, "name too long", "", "");
516 AlreadyComplained = 1;
517 }
518 ch = getch();
519 }
520 } while ((ch >= 'a' && ch <= 'z') ||
521 (ch >= 'A' && ch <= 'Z') ||
522 (ch >= '0' && ch <= '9') ||
523 ch == '_');
524
525 // line continuation with no token before or after makes len == 0, and need to start over skipping white space, etc.
526 if (len == 0)
527 continue;
528
529 ppToken->name[len] = '\0';
530 ungetch();
531 return PpAtomIdentifier;
532 case '0':
533 ppToken->name[len++] = (char)ch;
534 ch = getch();
535 if (ch == 'x' || ch == 'X') {
536 // must be hexadecimal
537
538 bool isUnsigned = false;
539 bool isInt64 = false;
540 bool isInt16 = false;
541 ppToken->name[len++] = (char)ch;
542 ch = getch();
543 if ((ch >= '0' && ch <= '9') ||
544 (ch >= 'A' && ch <= 'F') ||
545 (ch >= 'a' && ch <= 'f')) {
546
547 ival = 0;
548 do {
549 if (len < MaxTokenLength && ival <= 0x7fffffffffffffffull) {
550 ppToken->name[len++] = (char)ch;
551 if (ch >= '0' && ch <= '9') {
552 ii = ch - '0';
553 } else if (ch >= 'A' && ch <= 'F') {
554 ii = ch - 'A' + 10;
555 } else if (ch >= 'a' && ch <= 'f') {
556 ii = ch - 'a' + 10;
557 } else
558 pp->parseContext.ppError(ppToken->loc, "bad digit in hexadecimal literal", "", "");
559 ival = (ival << 4) | ii;
560 } else {
561 if (! AlreadyComplained) {
562 if(len < MaxTokenLength)
563 pp->parseContext.ppError(ppToken->loc, "hexadecimal literal too big", "", "");
564 else
565 pp->parseContext.ppError(ppToken->loc, "hexadecimal literal too long", "", "");
566 AlreadyComplained = 1;
567 }
568 ival = 0xffffffffffffffffull;
569 }
570 ch = getch();
571 } while ((ch >= '0' && ch <= '9') ||
572 (ch >= 'A' && ch <= 'F') ||
573 (ch >= 'a' && ch <= 'f'));
574 } else {
575 pp->parseContext.ppError(ppToken->loc, "bad digit in hexadecimal literal", "", "");
576 }
577 if (ch == 'u' || ch == 'U') {
578 if (len < MaxTokenLength)
579 ppToken->name[len++] = (char)ch;
580 isUnsigned = true;
581
582 int nextCh = getch();
583 if (nextCh == 'l' || nextCh == 'L') {
584 if (len < MaxTokenLength)
585 ppToken->name[len++] = (char)nextCh;
586 isInt64 = true;
587 } else
588 ungetch();
589
590 nextCh = getch();
591 if ((nextCh == 's' || nextCh == 'S') &&
592 pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
593 if (len < MaxTokenLength)
594 ppToken->name[len++] = (char)nextCh;
595 isInt16 = true;
596 } else
597 ungetch();
598 } else if (ch == 'l' || ch == 'L') {
599 if (len < MaxTokenLength)
600 ppToken->name[len++] = (char)ch;
601 isInt64 = true;
602 } else if ((ch == 's' || ch == 'S') &&
603 pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
604 if (len < MaxTokenLength)
605 ppToken->name[len++] = (char)ch;
606 isInt16 = true;
607 } else
608 ungetch();
609 ppToken->name[len] = '\0';
610
611 if (isInt64 && pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
612 if (pp->ifdepth == 0) {
613 pp->parseContext.requireProfile(ppToken->loc, ~EEsProfile,
614 "64-bit hexadecimal literal");
615 pp->parseContext.profileRequires(ppToken->loc, ~EEsProfile, 0,
616 Num_Int64_Extensions, Int64_Extensions, "64-bit hexadecimal literal");
617 }
618 ppToken->i64val = ival;
619 return isUnsigned ? PpAtomConstUint64 : PpAtomConstInt64;
620 } else if (isInt16) {
621 if (pp->ifdepth == 0) {
622 if (pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
623 pp->parseContext.requireProfile(ppToken->loc, ~EEsProfile,
624 "16-bit hexadecimal literal");
625 pp->parseContext.profileRequires(ppToken->loc, ~EEsProfile, 0,
626 Num_Int16_Extensions, Int16_Extensions, "16-bit hexadecimal literal");
627 }
628 }
629 ppToken->ival = (int)ival;
630 return isUnsigned ? PpAtomConstUint16 : PpAtomConstInt16;
631 } else {
632 if (ival > 0xffffffffu && !AlreadyComplained)
633 pp->parseContext.ppError(ppToken->loc, "hexadecimal literal too big", "", "");
634 ppToken->ival = (int)ival;
635 return isUnsigned ? PpAtomConstUint : PpAtomConstInt;
636 }
637 } else if ((ch == 'b' || ch == 'B') && pp->parseContext.intermediate.getSource() == EShSourceHlsl) {
638 // must be binary
639 bool isUnsigned = false;
640 bool isInt64 = false;
641 bool isInt16 = false;
642 ppToken->name[len++] = (char)ch;
643 ch = getch();
644
645 // Check value
646 if ((ch == '0' || ch == '1'))
647 {
648 ival = 0;
649 do {
650 if (len < MaxTokenLength && ival <= 0x7fffffffffffffffull) {
651 ppToken->name[len++] = (char)ch;
652 if (ch == '0' || ch == '1') {
653 ii = ch - '0';
654 } else {
655 pp->parseContext.ppError(ppToken->loc, "bad digit in binary literal", "", "");
656 }
657 ival = (ival << 1) | ii;
658 }
659 else
660 {
661 if (! AlreadyComplained) {
662 if(len < MaxTokenLength)
663 pp->parseContext.ppError(ppToken->loc, "binary literal too big", "", "");
664 else
665 pp->parseContext.ppError(ppToken->loc, "binary literal too long", "", "");
666 AlreadyComplained = 1;
667 }
668 ival = 0xffffffffffffffffull;
669 }
670 ch = getch();
671 } while (ch == '0' || ch == '1');
672 }
673 else
674 {
675 pp->parseContext.ppError(ppToken->loc, "bad digit in binary literal", "", "");
676 }
677
678 // check type
679 if (ch == 'u' || ch == 'U') {
680 if (len < MaxTokenLength)
681 ppToken->name[len++] = (char)ch;
682 isUnsigned = true;
683
684 int nextCh = getch();
685 if (nextCh == 'l' || nextCh == 'L') {
686 if (len < MaxTokenLength)
687 ppToken->name[len++] = (char)nextCh;
688 isInt64 = true;
689 } else
690 ungetch();
691
692 nextCh = getch();
693 if ((nextCh == 's' || nextCh == 'S') &&
694 pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
695 if (len < MaxTokenLength)
696 ppToken->name[len++] = (char)nextCh;
697 isInt16 = true;
698 } else
699 ungetch();
700 } else if (ch == 'l' || ch == 'L') {
701 if (len < MaxTokenLength)
702 ppToken->name[len++] = (char)ch;
703 isInt64 = true;
704 } else if ((ch == 's' || ch == 'S') &&
705 pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
706 if (len < MaxTokenLength)
707 ppToken->name[len++] = (char)ch;
708 isInt16 = true;
709 } else {
710 ungetch();
711 }
712 ppToken->name[len] = '\0';
713
714 // Assign value
715 if (isInt64 && pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
716 if (pp->ifdepth == 0) {
717 pp->parseContext.requireProfile(ppToken->loc, ~EEsProfile,
718 "64-bit binary literal");
719 pp->parseContext.profileRequires(ppToken->loc, ~EEsProfile, 0,
720 Num_Int64_Extensions, Int64_Extensions, "64-bit binary literal");
721 }
722 ppToken->i64val = ival;
723 return isUnsigned ? PpAtomConstUint64 : PpAtomConstInt64;
724 } else if (isInt16) {
725 if (pp->ifdepth == 0) {
726 if (pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
727 pp->parseContext.requireProfile(ppToken->loc, ~EEsProfile,
728 "16-bit binary literal");
729 pp->parseContext.profileRequires(ppToken->loc, ~EEsProfile, 0,
730 Num_Int16_Extensions, Int16_Extensions, "16-bit binary literal");
731 }
732 }
733 ppToken->ival = (int)ival;
734 return isUnsigned ? PpAtomConstUint16 : PpAtomConstInt16;
735 } else {
736 ppToken->ival = (int)ival;
737 return isUnsigned ? PpAtomConstUint : PpAtomConstInt;
738 }
739 } else {
740 // could be octal integer or floating point, speculative pursue octal until it must be floating point
741
742 bool isUnsigned = false;
743 bool isInt64 = false;
744 bool isInt16 = false;
745 bool octalOverflow = false;
746 bool nonOctal = false;
747 ival = 0;
748
749 // see how much octal-like stuff we can read
750 while (ch >= '0' && ch <= '7') {
751 if (len < MaxTokenLength)
752 ppToken->name[len++] = (char)ch;
753 else if (! AlreadyComplained) {
754 pp->parseContext.ppError(ppToken->loc, "numeric literal too long", "", "");
755 AlreadyComplained = 1;
756 }
757 if (ival <= 0x1fffffffffffffffull) {
758 ii = ch - '0';
759 ival = (ival << 3) | ii;
760 } else
761 octalOverflow = true;
762 ch = getch();
763 }
764
765 // could be part of a float...
766 if (ch == '8' || ch == '9') {
767 nonOctal = true;
768 do {
769 if (len < MaxTokenLength)
770 ppToken->name[len++] = (char)ch;
771 else if (! AlreadyComplained) {
772 pp->parseContext.ppError(ppToken->loc, "numeric literal too long", "", "");
773 AlreadyComplained = 1;
774 }
775 ch = getch();
776 } while (ch >= '0' && ch <= '9');
777 }
778 if (floatingPointChar(ch))
779 return pp->lFloatConst(len, ch, ppToken);
780
781 // wasn't a float, so must be octal...
782 if (nonOctal)
783 pp->parseContext.ppError(ppToken->loc, "octal literal digit too large", "", "");
784
785 if (ch == 'u' || ch == 'U') {
786 if (len < MaxTokenLength)
787 ppToken->name[len++] = (char)ch;
788 isUnsigned = true;
789
790 int nextCh = getch();
791 if (nextCh == 'l' || nextCh == 'L') {
792 if (len < MaxTokenLength)
793 ppToken->name[len++] = (char)nextCh;
794 isInt64 = true;
795 } else
796 ungetch();
797
798 nextCh = getch();
799 if ((nextCh == 's' || nextCh == 'S') &&
800 pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
801 if (len < MaxTokenLength)
802 ppToken->name[len++] = (char)nextCh;
803 isInt16 = true;
804 } else
805 ungetch();
806 } else if (ch == 'l' || ch == 'L') {
807 if (len < MaxTokenLength)
808 ppToken->name[len++] = (char)ch;
809 isInt64 = true;
810 } else if ((ch == 's' || ch == 'S') &&
811 pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
812 if (len < MaxTokenLength)
813 ppToken->name[len++] = (char)ch;
814 isInt16 = true;
815 } else
816 ungetch();
817 ppToken->name[len] = '\0';
818
819 if (!isInt64 && ival > 0xffffffffu)
820 octalOverflow = true;
821
822 if (octalOverflow)
823 pp->parseContext.ppError(ppToken->loc, "octal literal too big", "", "");
824
825 if (isInt64 && pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
826 if (pp->ifdepth == 0) {
827 pp->parseContext.requireProfile(ppToken->loc, ~EEsProfile,
828 "64-bit octal literal");
829 pp->parseContext.profileRequires(ppToken->loc, ~EEsProfile, 0,
830 Num_Int64_Extensions, Int64_Extensions, "64-bit octal literal");
831 }
832 ppToken->i64val = ival;
833 return isUnsigned ? PpAtomConstUint64 : PpAtomConstInt64;
834 } else if (isInt16) {
835 if (pp->ifdepth == 0) {
836 if (pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
837 pp->parseContext.requireProfile(ppToken->loc, ~EEsProfile,
838 "16-bit octal literal");
839 pp->parseContext.profileRequires(ppToken->loc, ~EEsProfile, 0,
840 Num_Int16_Extensions, Int16_Extensions, "16-bit octal literal");
841 }
842 }
843 ppToken->ival = (int)ival;
844 return isUnsigned ? PpAtomConstUint16 : PpAtomConstInt16;
845 } else {
846 ppToken->ival = (int)ival;
847 return isUnsigned ? PpAtomConstUint : PpAtomConstInt;
848 }
849 }
850 break;
851 case '1': case '2': case '3': case '4':
852 case '5': case '6': case '7': case '8': case '9':
853 // can't be hexadecimal or octal, is either decimal or floating point
854
855 do {
856 if (len < MaxTokenLength)
857 ppToken->name[len++] = (char)ch;
858 else if (! AlreadyComplained) {
859 pp->parseContext.ppError(ppToken->loc, "numeric literal too long", "", "");
860 AlreadyComplained = 1;
861 }
862 ch = getch();
863 } while (ch >= '0' && ch <= '9');
864 if (floatingPointChar(ch))
865 return pp->lFloatConst(len, ch, ppToken);
866 else {
867 // Finish handling signed and unsigned integers
868 int numericLen = len;
869 bool isUnsigned = false;
870 bool isInt64 = false;
871 bool isInt16 = false;
872 if (ch == 'u' || ch == 'U') {
873 if (len < MaxTokenLength)
874 ppToken->name[len++] = (char)ch;
875 isUnsigned = true;
876
877 int nextCh = getch();
878 if (nextCh == 'l' || nextCh == 'L') {
879 if (len < MaxTokenLength)
880 ppToken->name[len++] = (char)nextCh;
881 isInt64 = true;
882 } else
883 ungetch();
884
885 nextCh = getch();
886 if ((nextCh == 's' || nextCh == 'S') &&
887 pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
888 if (len < MaxTokenLength)
889 ppToken->name[len++] = (char)nextCh;
890 isInt16 = true;
891 } else
892 ungetch();
893 } else if (ch == 'l' || ch == 'L') {
894 if (len < MaxTokenLength)
895 ppToken->name[len++] = (char)ch;
896 isInt64 = true;
897 } else if ((ch == 's' || ch == 'S') &&
898 pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
899 if (len < MaxTokenLength)
900 ppToken->name[len++] = (char)ch;
901 isInt16 = true;
902 } else
903 ungetch();
904
905 ppToken->name[len] = '\0';
906 ival = 0;
907 const unsigned oneTenthMaxInt = 0xFFFFFFFFu / 10;
908 const unsigned remainderMaxInt = 0xFFFFFFFFu - 10 * oneTenthMaxInt;
909 const unsigned long long oneTenthMaxInt64 = 0xFFFFFFFFFFFFFFFFull / 10;
910 const unsigned long long remainderMaxInt64 = 0xFFFFFFFFFFFFFFFFull - 10 * oneTenthMaxInt64;
911 const unsigned short oneTenthMaxInt16 = 0xFFFFu / 10;
912 const unsigned short remainderMaxInt16 = 0xFFFFu - 10 * oneTenthMaxInt16;
913 for (int i = 0; i < numericLen; i++) {
914 ch = ppToken->name[i] - '0';
915 bool overflow = false;
916 if (isInt64)
917 overflow = (ival > oneTenthMaxInt64 || (ival == oneTenthMaxInt64 && (unsigned long long)ch > remainderMaxInt64));
918 else if (isInt16)
919 overflow = (ival > oneTenthMaxInt16 || (ival == oneTenthMaxInt16 && (unsigned short)ch > remainderMaxInt16));
920 else
921 overflow = (ival > oneTenthMaxInt || (ival == oneTenthMaxInt && (unsigned)ch > remainderMaxInt));
922 if (overflow) {
923 pp->parseContext.ppError(ppToken->loc, "numeric literal too big", "", "");
924 ival = 0xFFFFFFFFFFFFFFFFull;
925 break;
926 } else
927 ival = ival * 10 + ch;
928 }
929
930 if (isInt64 && pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
931 if (pp->ifdepth == 0) {
932 pp->parseContext.requireProfile(ppToken->loc, ~EEsProfile,
933 "64-bit literal");
934 pp->parseContext.profileRequires(ppToken->loc, ~EEsProfile, 0,
935 Num_Int64_Extensions, Int64_Extensions, "64-bit literal");
936 }
937 ppToken->i64val = ival;
938 return isUnsigned ? PpAtomConstUint64 : PpAtomConstInt64;
939 } else if (isInt16) {
940 if (pp->ifdepth == 0 && pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
941 pp->parseContext.requireProfile(ppToken->loc, ~EEsProfile,
942 "16-bit literal");
943 pp->parseContext.profileRequires(ppToken->loc, ~EEsProfile, 0,
944 Num_Int16_Extensions, Int16_Extensions, "16-bit literal");
945 }
946 ppToken->ival = (int)ival;
947 return isUnsigned ? PpAtomConstUint16 : PpAtomConstInt16;
948 } else {
949 ppToken->ival = (int)ival;
950 return isUnsigned ? PpAtomConstUint : PpAtomConstInt;
951 }
952 }
953 break;
954 case '-':
955 ch = getch();
956 if (ch == '-') {
957 return PpAtomDecrement;
958 } else if (ch == '=') {
959 return PPAtomSubAssign;
960 } else {
961 ungetch();
962 return '-';
963 }
964 case '+':
965 ch = getch();
966 if (ch == '+') {
967 return PpAtomIncrement;
968 } else if (ch == '=') {
969 return PPAtomAddAssign;
970 } else {
971 ungetch();
972 return '+';
973 }
974 case '*':
975 ch = getch();
976 if (ch == '=') {
977 return PPAtomMulAssign;
978 } else {
979 ungetch();
980 return '*';
981 }
982 case '%':
983 ch = getch();
984 if (ch == '=') {
985 return PPAtomModAssign;
986 } else {
987 ungetch();
988 return '%';
989 }
990 case '^':
991 ch = getch();
992 if (ch == '^') {
993 return PpAtomXor;
994 } else {
995 if (ch == '=')
996 return PpAtomXorAssign;
997 else{
998 ungetch();
999 return '^';
1000 }
1001 }
1002
1003 case '=':
1004 ch = getch();
1005 if (ch == '=') {
1006 return PpAtomEQ;
1007 } else {
1008 ungetch();
1009 return '=';
1010 }
1011 case '!':
1012 ch = getch();
1013 if (ch == '=') {
1014 return PpAtomNE;
1015 } else {
1016 ungetch();
1017 return '!';
1018 }
1019 case '|':
1020 ch = getch();
1021 if (ch == '|') {
1022 return PpAtomOr;
1023 } else if (ch == '=') {
1024 return PpAtomOrAssign;
1025 } else {
1026 ungetch();
1027 return '|';
1028 }
1029 case '&':
1030 ch = getch();
1031 if (ch == '&') {
1032 return PpAtomAnd;
1033 } else if (ch == '=') {
1034 return PpAtomAndAssign;
1035 } else {
1036 ungetch();
1037 return '&';
1038 }
1039 case '<':
1040 ch = getch();
1041 if (ch == '<') {
1042 ch = getch();
1043 if (ch == '=')
1044 return PpAtomLeftAssign;
1045 else {
1046 ungetch();
1047 return PpAtomLeft;
1048 }
1049 } else if (ch == '=') {
1050 return PpAtomLE;
1051 } else {
1052 ungetch();
1053 return '<';
1054 }
1055 case '>':
1056 ch = getch();
1057 if (ch == '>') {
1058 ch = getch();
1059 if (ch == '=')
1060 return PpAtomRightAssign;
1061 else {
1062 ungetch();
1063 return PpAtomRight;
1064 }
1065 } else if (ch == '=') {
1066 return PpAtomGE;
1067 } else {
1068 ungetch();
1069 return '>';
1070 }
1071 case '.':
1072 ch = getch();
1073 if (ch >= '0' && ch <= '9') {
1074 ungetch();
1075 return pp->lFloatConst(0, '.', ppToken);
1076 } else {
1077 ungetch();
1078 return '.';
1079 }
1080 case '/':
1081 ch = getch();
1082 if (ch == '/') {
1083 pp->inComment = true;
1084 do {
1085 ch = getch();
1086 } while (ch != '\n' && ch != EndOfInput);
1087 ppToken->space = true;
1088 pp->inComment = false;
1089
1090 return ch;
1091 } else if (ch == '*') {
1092 ch = getch();
1093 do {
1094 while (ch != '*') {
1095 if (ch == EndOfInput) {
1096 pp->parseContext.ppError(ppToken->loc, "End of input in comment", "comment", "");
1097 return ch;
1098 }
1099 ch = getch();
1100 }
1101 ch = getch();
1102 if (ch == EndOfInput) {
1103 pp->parseContext.ppError(ppToken->loc, "End of input in comment", "comment", "");
1104 return ch;
1105 }
1106 } while (ch != '/');
1107 ppToken->space = true;
1108 // loop again to get the next token...
1109 break;
1110 } else if (ch == '=') {
1111 return PPAtomDivAssign;
1112 } else {
1113 ungetch();
1114 return '/';
1115 }
1116 break;
1117 case '\'':
1118 return pp->characterLiteral(ppToken);
1119 case '"':
1120 // #include uses scanHeaderName() to ignore these escape sequences.
1121 ch = getch();
1122 while (ch != '"' && ch != '\n' && ch != EndOfInput) {
1123 if (len < MaxTokenLength) {
1124 if (ch == '\\' && !pp->disableEscapeSequences) {
1125 int nextCh = getch();
1126 switch (nextCh) {
1127 case '\'': ch = 0x27; break;
1128 case '"': ch = 0x22; break;
1129 case '?': ch = 0x3f; break;
1130 case '\\': ch = 0x5c; break;
1131 case 'a': ch = 0x07; break;
1132 case 'b': ch = 0x08; break;
1133 case 'f': ch = 0x0c; break;
1134 case 'n': ch = 0x0a; break;
1135 case 'r': ch = 0x0d; break;
1136 case 't': ch = 0x09; break;
1137 case 'v': ch = 0x0b; break;
1138 case 'x':
1139 // Hex value, arbitrary number of characters. Terminated by the first
1140 // non-hex digit
1141 {
1142 int numDigits = 0;
1143 ch = 0;
1144 while (true) {
1145 nextCh = getch();
1146 if (nextCh >= '0' && nextCh <= '9')
1147 nextCh -= '0';
1148 else if (nextCh >= 'A' && nextCh <= 'F')
1149 nextCh -= 'A' - 10;
1150 else if (nextCh >= 'a' && nextCh <= 'f')
1151 nextCh -= 'a' - 10;
1152 else {
1153 ungetch();
1154 break;
1155 }
1156 numDigits++;
1157 ch = ch * 0x10 + nextCh;
1158 }
1159 if (numDigits == 0) {
1160 pp->parseContext.ppError(ppToken->loc, "Expected hex value in escape sequence", "string", "");
1161 }
1162 break;
1163 }
1164 case '0':
1165 case '1':
1166 case '2':
1167 case '3':
1168 case '4':
1169 case '5':
1170 case '6':
1171 case '7':
1172 // Octal value, up to three octal digits
1173 {
1174 int numDigits = 1;
1175 ch = nextCh - '0';
1176 while (numDigits < 3) {
1177 nextCh = getch();
1178 if (nextCh >= '0' && nextCh <= '7')
1179 nextCh -= '0';
1180 else {
1181 ungetch();
1182 break;
1183 }
1184 numDigits++;
1185 ch = ch * 8 + nextCh;
1186 }
1187 break;
1188 }
1189 default:
1190 pp->parseContext.ppError(ppToken->loc, "Invalid escape sequence", "string", "");
1191 break;
1192 }
1193 }
1194 ppToken->name[len] = (char)ch;
1195 len++;
1196 ch = getch();
1197 } else
1198 break;
1199 };
1200 ppToken->name[len] = '\0';
1201 if (ch != '"') {
1202 ungetch();
1203 pp->parseContext.ppError(ppToken->loc, "End of line in string", "string", "");
1204 }
1205 return PpAtomConstString;
1206 case ':':
1207 ch = getch();
1208 if (ch == ':')
1209 return PpAtomColonColon;
1210 ungetch();
1211 return ':';
1212 }
1213
1214 ch = getch();
1215 }
1216 }
1217
1218 //
1219 // The main functional entry point into the preprocessor, which will
1220 // scan the source strings to figure out and return the next processing token.
1221 //
1222 // Return the token, or EndOfInput when no more tokens.
1223 //
tokenize(TPpToken & ppToken)1224 int TPpContext::tokenize(TPpToken& ppToken)
1225 {
1226 for(;;) {
1227 int token = scanToken(&ppToken);
1228
1229 // Handle token-pasting logic
1230 token = tokenPaste(token, ppToken);
1231
1232 if (token == EndOfInput) {
1233 missingEndifCheck();
1234 return EndOfInput;
1235 }
1236 if (token == '#') {
1237 if (previous_token == '\n') {
1238 token = readCPPline(&ppToken);
1239 if (token == EndOfInput) {
1240 missingEndifCheck();
1241 return EndOfInput;
1242 }
1243 continue;
1244 } else {
1245 parseContext.ppError(ppToken.loc, "preprocessor directive cannot be preceded by another token", "#", "");
1246 return EndOfInput;
1247 }
1248 }
1249 previous_token = token;
1250
1251 if (token == '\n')
1252 continue;
1253
1254 // expand macros
1255 if (token == PpAtomIdentifier) {
1256 switch (MacroExpand(&ppToken, false, true)) {
1257 case MacroExpandNotStarted:
1258 break;
1259 case MacroExpandError:
1260 return EndOfInput;
1261 case MacroExpandStarted:
1262 case MacroExpandUndef:
1263 continue;
1264 }
1265 }
1266
1267 switch (token) {
1268 case PpAtomIdentifier:
1269 case PpAtomConstInt:
1270 case PpAtomConstUint:
1271 case PpAtomConstFloat:
1272 case PpAtomConstInt64:
1273 case PpAtomConstUint64:
1274 case PpAtomConstInt16:
1275 case PpAtomConstUint16:
1276 case PpAtomConstDouble:
1277 case PpAtomConstFloat16:
1278 if (ppToken.name[0] == '\0')
1279 continue;
1280 break;
1281 case PpAtomConstString:
1282 // HLSL allows string literals.
1283 // GLSL allows string literals with GL_EXT_debug_printf.
1284 if (ifdepth == 0 && parseContext.intermediate.getSource() != EShSourceHlsl) {
1285 const char* const string_literal_EXTs[] = { E_GL_EXT_debug_printf, E_GL_EXT_spirv_intrinsics };
1286 parseContext.requireExtensions(ppToken.loc, 2, string_literal_EXTs, "string literal");
1287 if (!parseContext.extensionTurnedOn(E_GL_EXT_debug_printf) &&
1288 !parseContext.extensionTurnedOn(E_GL_EXT_spirv_intrinsics))
1289 continue;
1290 }
1291 break;
1292 case '\'':
1293 parseContext.ppError(ppToken.loc, "character literals not supported", "\'", "");
1294 continue;
1295 default:
1296 snprintf(ppToken.name, sizeof(ppToken.name), "%s", atomStrings.getString(token));
1297 break;
1298 }
1299
1300 return token;
1301 }
1302 }
1303
1304 //
1305 // Do all token-pasting related combining of two pasted tokens when getting a
1306 // stream of tokens from a replacement list. Degenerates to no processing if a
1307 // replacement list is not the source of the token stream.
1308 //
tokenPaste(int token,TPpToken & ppToken)1309 int TPpContext::tokenPaste(int token, TPpToken& ppToken)
1310 {
1311 // starting with ## is illegal, skip to next token
1312 if (token == PpAtomPaste) {
1313 parseContext.ppError(ppToken.loc, "unexpected location", "##", "");
1314 return scanToken(&ppToken);
1315 }
1316
1317 int resultToken = token; // "foo" pasted with "35" is an identifier, not a number
1318
1319 // ## can be chained, process all in the chain at once
1320 while (peekPasting()) {
1321 TPpToken pastedPpToken;
1322
1323 // next token has to be ##
1324 token = scanToken(&pastedPpToken);
1325 assert(token == PpAtomPaste);
1326
1327 // This covers end of macro expansion
1328 if (endOfReplacementList()) {
1329 parseContext.ppError(ppToken.loc, "unexpected location; end of replacement list", "##", "");
1330 break;
1331 }
1332
1333 // Get the token(s) after the ##.
1334 // Because of "space" semantics, and prior tokenization, what
1335 // appeared a single token, e.g. "3A", might have been tokenized
1336 // into two tokens "3" and "A", but the "A" will have 'space' set to
1337 // false. Accumulate all of these to recreate the original lexical
1338 // appearing token.
1339 do {
1340 token = scanToken(&pastedPpToken);
1341
1342 // This covers end of argument expansion
1343 if (token == tMarkerInput::marker) {
1344 parseContext.ppError(ppToken.loc, "unexpected location; end of argument", "##", "");
1345 return resultToken;
1346 }
1347
1348 // get the token text
1349 switch (resultToken) {
1350 case PpAtomIdentifier:
1351 // already have the correct text in token.names
1352 break;
1353 case '=':
1354 case '!':
1355 case '-':
1356 case '~':
1357 case '+':
1358 case '*':
1359 case '/':
1360 case '%':
1361 case '<':
1362 case '>':
1363 case '|':
1364 case '^':
1365 case '&':
1366 case PpAtomRight:
1367 case PpAtomLeft:
1368 case PpAtomAnd:
1369 case PpAtomOr:
1370 case PpAtomXor:
1371 snprintf(ppToken.name, sizeof(ppToken.name), "%s", atomStrings.getString(resultToken));
1372 snprintf(pastedPpToken.name, sizeof(pastedPpToken.name), "%s", atomStrings.getString(token));
1373 break;
1374 default:
1375 parseContext.ppError(ppToken.loc, "not supported for these tokens", "##", "");
1376 return resultToken;
1377 }
1378
1379 // combine the tokens
1380 if (strlen(ppToken.name) + strlen(pastedPpToken.name) > MaxTokenLength) {
1381 parseContext.ppError(ppToken.loc, "combined tokens are too long", "##", "");
1382 return resultToken;
1383 }
1384 snprintf(&ppToken.name[0] + strlen(ppToken.name), sizeof(ppToken.name) - strlen(ppToken.name),
1385 "%s", pastedPpToken.name);
1386
1387 // correct the kind of token we are making, if needed (identifiers stay identifiers)
1388 if (resultToken != PpAtomIdentifier) {
1389 int newToken = atomStrings.getAtom(ppToken.name);
1390 if (newToken > 0)
1391 resultToken = newToken;
1392 else
1393 parseContext.ppError(ppToken.loc, "combined token is invalid", "##", "");
1394 }
1395 } while (peekContinuedPasting(resultToken));
1396 }
1397
1398 return resultToken;
1399 }
1400
1401 // Checks if we've seen balanced #if...#endif
missingEndifCheck()1402 void TPpContext::missingEndifCheck()
1403 {
1404 if (ifdepth > 0)
1405 parseContext.ppError(parseContext.getCurrentLoc(), "missing #endif", "", "");
1406 }
1407
1408 } // end namespace glslang
1409