1 //
2 // Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
3 // Copyright (C) 2013 LunarG, Inc.
4 // Copyright (C) 2015-2018 Google, Inc.
5 //
6 // All rights reserved.
7 //
8 // Redistribution and use in source and binary forms, with or without
9 // modification, are permitted provided that the following conditions
10 // are met:
11 //
12 // Redistributions of source code must retain the above copyright
13 // notice, this list of conditions and the following disclaimer.
14 //
15 // Redistributions in binary form must reproduce the above
16 // copyright notice, this list of conditions and the following
17 // disclaimer in the documentation and/or other materials provided
18 // with the distribution.
19 //
20 // Neither the name of 3Dlabs Inc. Ltd. nor the names of its
21 // contributors may be used to endorse or promote products derived
22 // from this software without specific prior written permission.
23 //
24 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28 // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 // POSSIBILITY OF SUCH DAMAGE.
36 //
37 /****************************************************************************\
38 Copyright (c) 2002, NVIDIA Corporation.
39
40 NVIDIA Corporation("NVIDIA") supplies this software to you in
41 consideration of your agreement to the following terms, and your use,
42 installation, modification or redistribution of this NVIDIA software
43 constitutes acceptance of these terms. If you do not agree with these
44 terms, please do not use, install, modify or redistribute this NVIDIA
45 software.
46
47 In consideration of your agreement to abide by the following terms, and
48 subject to these terms, NVIDIA grants you a personal, non-exclusive
49 license, under NVIDIA's copyrights in this original NVIDIA software (the
50 "NVIDIA Software"), to use, reproduce, modify and redistribute the
51 NVIDIA Software, with or without modifications, in source and/or binary
52 forms; provided that if you redistribute the NVIDIA Software, you must
53 retain the copyright notice of NVIDIA, this notice and the following
54 text and disclaimers in all such redistributions of the NVIDIA Software.
55 Neither the name, trademarks, service marks nor logos of NVIDIA
56 Corporation may be used to endorse or promote products derived from the
57 NVIDIA Software without specific prior written permission from NVIDIA.
58 Except as expressly stated in this notice, no other rights or licenses
59 express or implied, are granted by NVIDIA herein, including but not
60 limited to any patent rights that may be infringed by your derivative
61 works or by other works in which the NVIDIA Software may be
62 incorporated. No hardware is licensed hereunder.
63
64 THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
65 WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
66 INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
67 NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
68 ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
69 PRODUCTS.
70
71 IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
72 INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
73 TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
74 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
75 OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
76 NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
77 TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
78 NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
79 \****************************************************************************/
80
81 //
82 // For recording and playing back the stream of tokens in a macro definition.
83 //
84
85 #ifndef _CRT_SECURE_NO_WARNINGS
86 #define _CRT_SECURE_NO_WARNINGS
87 #endif
88 #if (defined(_MSC_VER) && _MSC_VER < 1900 /*vs2015*/)
89 #define snprintf sprintf_s
90 #endif
91
92 #include <cassert>
93 #include <cstdlib>
94 #include <cstring>
95 #include <cctype>
96
97 #include "PpContext.h"
98 #include "PpTokens.h"
99
100 namespace glslang {
101
102
103 namespace {
104
105 // When recording (and playing back) should the backing name string
106 // be saved (restored)?
SaveName(int atom)107 bool SaveName(int atom)
108 {
109 switch (atom) {
110 case PpAtomIdentifier:
111 case PpAtomConstString:
112 case PpAtomConstInt:
113 case PpAtomConstUint:
114 case PpAtomConstInt64:
115 case PpAtomConstUint64:
116 #ifdef AMD_EXTENSIONS
117 case PpAtomConstInt16:
118 case PpAtomConstUint16:
119 #endif
120 case PpAtomConstFloat:
121 case PpAtomConstDouble:
122 case PpAtomConstFloat16:
123 return true;
124 default:
125 return false;
126 }
127 }
128
129 // When recording (and playing back) should the numeric value
130 // be saved (restored)?
SaveValue(int atom)131 bool SaveValue(int atom)
132 {
133 switch (atom) {
134 case PpAtomConstInt:
135 case PpAtomConstUint:
136 case PpAtomConstInt64:
137 case PpAtomConstUint64:
138 #ifdef AMD_EXTENSIONS
139 case PpAtomConstInt16:
140 case PpAtomConstUint16:
141 #endif
142 case PpAtomConstFloat:
143 case PpAtomConstDouble:
144 case PpAtomConstFloat16:
145 return true;
146 default:
147 return false;
148 }
149 }
150 }
151
152 // push onto back of stream
putSubtoken(char subtoken)153 void TPpContext::TokenStream::putSubtoken(char subtoken)
154 {
155 data.push_back(static_cast<unsigned char>(subtoken));
156 }
157
158 // get the next token in stream
getSubtoken()159 int TPpContext::TokenStream::getSubtoken()
160 {
161 if (current < data.size())
162 return data[current++];
163 else
164 return EndOfInput;
165 }
166
167 // back up one position in the stream
ungetSubtoken()168 void TPpContext::TokenStream::ungetSubtoken()
169 {
170 if (current > 0)
171 --current;
172 }
173
174 // Add a complete token (including backing string) to the end of a list
175 // for later playback.
putToken(int atom,TPpToken * ppToken)176 void TPpContext::TokenStream::putToken(int atom, TPpToken* ppToken)
177 {
178 // save the atom
179 assert((atom & ~0xff) == 0);
180 putSubtoken(static_cast<char>(atom));
181
182 // save the backing name string
183 if (SaveName(atom)) {
184 const char* s = ppToken->name;
185 while (*s)
186 putSubtoken(*s++);
187 putSubtoken(0);
188 }
189
190 // save the numeric value
191 if (SaveValue(atom)) {
192 const char* n = reinterpret_cast<const char*>(&ppToken->i64val);
193 for (size_t i = 0; i < sizeof(ppToken->i64val); ++i)
194 putSubtoken(*n++);
195 }
196 }
197
198 // Read the next token from a token stream.
199 // (Not the source stream, but a stream used to hold a tokenized macro).
getToken(TParseContextBase & parseContext,TPpToken * ppToken)200 int TPpContext::TokenStream::getToken(TParseContextBase& parseContext, TPpToken *ppToken)
201 {
202 // get the atom
203 int atom = getSubtoken();
204 if (atom == EndOfInput)
205 return atom;
206
207 // init the token
208 ppToken->clear();
209 ppToken->loc = parseContext.getCurrentLoc();
210
211 // get the backing name string
212 if (SaveName(atom)) {
213 int ch = getSubtoken();
214 int len = 0;
215 while (ch != 0 && ch != EndOfInput) {
216 if (len < MaxTokenLength) {
217 ppToken->name[len] = (char)ch;
218 len++;
219 ch = getSubtoken();
220 } else {
221 parseContext.error(ppToken->loc, "token too long", "", "");
222 break;
223 }
224 }
225 ppToken->name[len] = 0;
226 }
227
228 // Check for ##, unless the current # is the last character
229 if (atom == '#') {
230 if (current < data.size()) {
231 if (getSubtoken() == '#') {
232 parseContext.requireProfile(ppToken->loc, ~EEsProfile, "token pasting (##)");
233 parseContext.profileRequires(ppToken->loc, ~EEsProfile, 130, 0, "token pasting (##)");
234 atom = PpAtomPaste;
235 } else
236 ungetSubtoken();
237 }
238 }
239
240 // get the numeric value
241 if (SaveValue(atom)) {
242 char* n = reinterpret_cast<char*>(&ppToken->i64val);
243 for (size_t i = 0; i < sizeof(ppToken->i64val); ++i)
244 *n++ = (char)getSubtoken();
245 }
246
247 return atom;
248 }
249
250 // We are pasting if
251 // 1. we are preceding a pasting operator within this stream
252 // or
253 // 2. the entire macro is preceding a pasting operator (lastTokenPastes)
254 // and we are also on the last token
peekTokenizedPasting(bool lastTokenPastes)255 bool TPpContext::TokenStream::peekTokenizedPasting(bool lastTokenPastes)
256 {
257 // 1. preceding ##?
258
259 size_t savePos = current;
260 int subtoken;
261 // skip white space
262 do {
263 subtoken = getSubtoken();
264 } while (subtoken == ' ');
265 current = savePos;
266 if (subtoken == PpAtomPaste)
267 return true;
268
269 // 2. last token and we've been told after this there will be a ##
270
271 if (! lastTokenPastes)
272 return false;
273 // Getting here means the last token will be pasted, after this
274
275 // Are we at the last non-whitespace token?
276 savePos = current;
277 bool moreTokens = false;
278 do {
279 subtoken = getSubtoken();
280 if (subtoken == EndOfInput)
281 break;
282 if (subtoken != ' ') {
283 moreTokens = true;
284 break;
285 }
286 } while (true);
287 current = savePos;
288
289 return !moreTokens;
290 }
291
292 // See if the next non-white-space tokens are two consecutive #
peekUntokenizedPasting()293 bool TPpContext::TokenStream::peekUntokenizedPasting()
294 {
295 // don't return early, have to restore this
296 size_t savePos = current;
297
298 // skip white-space
299 int subtoken;
300 do {
301 subtoken = getSubtoken();
302 } while (subtoken == ' ');
303
304 // check for ##
305 bool pasting = false;
306 if (subtoken == '#') {
307 subtoken = getSubtoken();
308 if (subtoken == '#')
309 pasting = true;
310 }
311
312 current = savePos;
313
314 return pasting;
315 }
316
pushTokenStreamInput(TokenStream & ts,bool prepasting)317 void TPpContext::pushTokenStreamInput(TokenStream& ts, bool prepasting)
318 {
319 pushInput(new tTokenInput(this, &ts, prepasting));
320 ts.reset();
321 }
322
scan(TPpToken * ppToken)323 int TPpContext::tUngotTokenInput::scan(TPpToken* ppToken)
324 {
325 if (done)
326 return EndOfInput;
327
328 int ret = token;
329 *ppToken = lval;
330 done = true;
331
332 return ret;
333 }
334
UngetToken(int token,TPpToken * ppToken)335 void TPpContext::UngetToken(int token, TPpToken* ppToken)
336 {
337 pushInput(new tUngotTokenInput(this, token, ppToken));
338 }
339
340 } // end namespace glslang
341