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