blob: f15c56db52dba3db40bbecf2fd9a7a9ef505a82d [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001/****************************************************************************\
2Copyright (c) 2002, NVIDIA Corporation.
3
4NVIDIA Corporation("NVIDIA") supplies this software to you in
5consideration of your agreement to the following terms, and your use,
6installation, modification or redistribution of this NVIDIA software
7constitutes acceptance of these terms. If you do not agree with these
8terms, please do not use, install, modify or redistribute this NVIDIA
9software.
10
11In consideration of your agreement to abide by the following terms, and
12subject to these terms, NVIDIA grants you a personal, non-exclusive
13license, under NVIDIA's copyrights in this original NVIDIA software (the
14"NVIDIA Software"), to use, reproduce, modify and redistribute the
15NVIDIA Software, with or without modifications, in source and/or binary
16forms; provided that if you redistribute the NVIDIA Software, you must
17retain the copyright notice of NVIDIA, this notice and the following
18text and disclaimers in all such redistributions of the NVIDIA Software.
19Neither the name, trademarks, service marks nor logos of NVIDIA
20Corporation may be used to endorse or promote products derived from the
21NVIDIA Software without specific prior written permission from NVIDIA.
22Except as expressly stated in this notice, no other rights or licenses
23express or implied, are granted by NVIDIA herein, including but not
24limited to any patent rights that may be infringed by your derivative
25works or by other works in which the NVIDIA Software may be
26incorporated. No hardware is licensed hereunder.
27
28THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
29WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
30INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
31NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
32ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
33PRODUCTS.
34
35IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
36INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
37TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
38USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
39OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
40NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
41TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
42NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43\****************************************************************************/
44//
45// cpp.c
46//
47
48#include <stdarg.h>
49#include <stdio.h>
50#include <stdlib.h>
51#include <string.h>
52#include <ctype.h>
53
daniel@transgaming.come6842292010-04-20 18:52:50 +000054#include "compiler/preprocessor/slglobals.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000055
56static int CPPif(yystypepp * yylvalpp);
57
58/* Don't use memory.c's replacements, as we clean up properly here */
59#undef malloc
60#undef free
61
62static int bindAtom = 0;
63static int constAtom = 0;
64static int defaultAtom = 0;
65static int defineAtom = 0;
66static int definedAtom = 0;
67static int elseAtom = 0;
68static int elifAtom = 0;
69static int endifAtom = 0;
70static int ifAtom = 0;
71static int ifdefAtom = 0;
72static int ifndefAtom = 0;
73static int includeAtom = 0;
74static int lineAtom = 0;
75static int pragmaAtom = 0;
76static int texunitAtom = 0;
77static int undefAtom = 0;
78static int errorAtom = 0;
79static int __LINE__Atom = 0;
80static int __FILE__Atom = 0;
81static int __VERSION__Atom = 0;
82static int versionAtom = 0;
83static int extensionAtom = 0;
84
85static Scope *macros = 0;
86#define MAX_MACRO_ARGS 64
87#define MAX_IF_NESTING 64
88
89static SourceLoc ifloc; /* outermost #if */
90
91int InitCPP(void)
92{
93 char buffer[64], *t;
94 const char *f;
daniel@transgaming.comd8e93722010-05-14 17:31:09 +000095
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000096 // Add various atoms needed by the CPP line scanner:
97 bindAtom = LookUpAddString(atable, "bind");
98 constAtom = LookUpAddString(atable, "const");
99 defaultAtom = LookUpAddString(atable, "default");
100 defineAtom = LookUpAddString(atable, "define");
101 definedAtom = LookUpAddString(atable, "defined");
102 elifAtom = LookUpAddString(atable, "elif");
103 elseAtom = LookUpAddString(atable, "else");
104 endifAtom = LookUpAddString(atable, "endif");
105 ifAtom = LookUpAddString(atable, "if");
106 ifdefAtom = LookUpAddString(atable, "ifdef");
107 ifndefAtom = LookUpAddString(atable, "ifndef");
108 includeAtom = LookUpAddString(atable, "include");
109 lineAtom = LookUpAddString(atable, "line");
110 pragmaAtom = LookUpAddString(atable, "pragma");
111 texunitAtom = LookUpAddString(atable, "texunit");
112 undefAtom = LookUpAddString(atable, "undef");
113 errorAtom = LookUpAddString(atable, "error");
114 __LINE__Atom = LookUpAddString(atable, "__LINE__");
115 __FILE__Atom = LookUpAddString(atable, "__FILE__");
116 __VERSION__Atom = LookUpAddString(atable, "__VERSION__");
117 versionAtom = LookUpAddString(atable, "version");
118 extensionAtom = LookUpAddString(atable, "extension");
119 macros = NewScopeInPool(mem_CreatePool(0, 0));
120 strcpy(buffer, "PROFILE_");
121 t = buffer + strlen(buffer);
122 f = cpp->options.profileString;
123 while ((isalnum(*f) || *f == '_') && t < buffer + sizeof(buffer) - 1)
124 *t++ = toupper(*f++);
125 *t = 0;
daniel@transgaming.comd8e93722010-05-14 17:31:09 +0000126
daniel@transgaming.comcd0a9a82010-05-18 18:51:59 +0000127 PredefineIntMacro("GL_ES", 1);
128 PredefineIntMacro("GL_FRAGMENT_PRECISION_HIGH", 1);
daniel@transgaming.comd8e93722010-05-14 17:31:09 +0000129
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000130 return 1;
131} // InitCPP
132
133int FreeCPP(void)
134{
135 if (macros)
136 {
137 mem_FreePool(macros->pool);
138 macros = 0;
139 }
140
141 return 1;
142}
143
144int FinalCPP(void)
145{
146 if (cpp->ifdepth)
147 CPPErrorToInfoLog("#if mismatch");
148 return 1;
149}
150
151static int CPPdefine(yystypepp * yylvalpp)
152{
153 int token, name, args[MAX_MACRO_ARGS], argc;
154 const char *message;
155 MacroSymbol mac;
156 Symbol *symb;
157 SourceLoc dummyLoc;
158 memset(&mac, 0, sizeof(mac));
159 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
160 if (token != CPP_IDENTIFIER) {
161 CPPErrorToInfoLog("#define");
162 return token;
163 }
164 name = yylvalpp->sc_ident;
165 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
166 if (token == '(' && !yylvalpp->sc_int) {
167 // gather arguments
168 argc = 0;
169 do {
170 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
171 if (argc == 0 && token == ')') break;
172 if (token != CPP_IDENTIFIER) {
173 CPPErrorToInfoLog("#define");
174 return token;
175 }
176 if (argc < MAX_MACRO_ARGS)
177 args[argc++] = yylvalpp->sc_ident;
178 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
179 } while (token == ',');
180 if (token != ')') {
181 CPPErrorToInfoLog("#define");
182 return token;
183 }
184 mac.argc = argc;
185 mac.args = mem_Alloc(macros->pool, argc * sizeof(int));
186 memcpy(mac.args, args, argc * sizeof(int));
187 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
188 }
189 mac.body = NewTokenStream(GetAtomString(atable, name), macros->pool);
190 while (token != '\n') {
daniel@transgaming.comedff8dc2010-05-14 17:30:27 +0000191 if (token == '\\') {
192 CPPErrorToInfoLog("The line continuation character (\\) is not part of the OpenGL ES Shading Language");
193 return token;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000194 }
195 RecordToken(mac.body, token, yylvalpp);
196 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
197 };
198
199 symb = LookUpSymbol(macros, name);
200 if (symb) {
201 if (!symb->details.mac.undef) {
202 // already defined -- need to make sure they are identical
203 if (symb->details.mac.argc != mac.argc) goto error;
204 for (argc=0; argc < mac.argc; argc++)
205 if (symb->details.mac.args[argc] != mac.args[argc])
206 goto error;
207 RewindTokenStream(symb->details.mac.body);
208 RewindTokenStream(mac.body);
209 do {
210 int old_lval, old_token;
211 old_token = ReadToken(symb->details.mac.body, yylvalpp);
212 old_lval = yylvalpp->sc_int;
213 token = ReadToken(mac.body, yylvalpp);
214 if (token != old_token || yylvalpp->sc_int != old_lval) {
215 error:
216 StoreStr("Macro Redefined");
217 StoreStr(GetStringOfAtom(atable,name));
218 message=GetStrfromTStr();
219 DecLineNumber();
220 CPPShInfoLogMsg(message);
221 IncLineNumber();
222 ResetTString();
223 break; }
224 } while (token > 0);
225 }
226 //FreeMacro(&symb->details.mac);
227 } else {
228 dummyLoc.file = 0;
229 dummyLoc.line = 0;
230 symb = AddSymbol(&dummyLoc, macros, name, MACRO_S);
231 }
232 symb->details.mac = mac;
233 return '\n';
234} // CPPdefine
235
236static int CPPundef(yystypepp * yylvalpp)
237{
238 int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
239 Symbol *symb;
240 if(token == '\n'){
241 CPPErrorToInfoLog("#undef");
242 return token;
243 }
244 if (token != CPP_IDENTIFIER)
245 goto error;
246 symb = LookUpSymbol(macros, yylvalpp->sc_ident);
247 if (symb) {
248 symb->details.mac.undef = 1;
249 }
250 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
251 if (token != '\n') {
252 error:
253 CPPErrorToInfoLog("#undef");
254 }
255 return token;
256} // CPPundef
257
258/* CPPelse -- skip forward to appropriate spot. This is actually used
259** to skip to and #endif after seeing an #else, AND to skip to a #else,
260** #elif, or #endif after a #if/#ifdef/#ifndef/#elif test was false
261*/
262
263static int CPPelse(int matchelse, yystypepp * yylvalpp)
264{
265 int atom,depth=0;
266 int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
267
268 while (token > 0) {
269 if (token != '#') {
270 while (token != '\n')
271 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
272
273 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
274 continue;
275 }
276 if ((token = cpp->currentInput->scan(cpp->currentInput, yylvalpp)) != CPP_IDENTIFIER)
277 continue;
278 atom = yylvalpp->sc_ident;
279 if (atom == ifAtom || atom == ifdefAtom || atom == ifndefAtom){
280 depth++; cpp->ifdepth++; cpp->elsetracker++;
daniel@transgaming.com9e78e5e2010-04-29 03:39:02 +0000281 cpp->elsedepth[cpp->elsetracker] = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000282 }
283 else if (atom == endifAtom) {
daniel@transgaming.com9e78e5e2010-04-29 03:39:02 +0000284 if(--depth<0){
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000285 --cpp->elsetracker;
286 if (cpp->ifdepth)
287 --cpp->ifdepth;
288 break;
289 }
290 --cpp->elsetracker;
291 --cpp->ifdepth;
292 }
293 else if (((int)(matchelse) != 0)&& depth==0) {
294 if (atom == elseAtom ) {
295 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
296 if (token != '\n') {
297 CPPWarningToInfoLog("unexpected tokens following #else preprocessor directive - expected a newline");
298 while (token != '\n')
299 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
300 }
301 break;
302 }
303 else if (atom == elifAtom) {
304 /* we decrement cpp->ifdepth here, because CPPif will increment
305 * it and we really want to leave it alone */
306 if (cpp->ifdepth){
307 --cpp->ifdepth;
308 --cpp->elsetracker;
309 }
310 return CPPif(yylvalpp);
311 }
312 }
313 else if((atom==elseAtom) && (!ChkCorrectElseNesting())){
314 CPPErrorToInfoLog("#else after a #else");
315 cpp->CompileError=1;
316 }
317 };
318 return token;
319}
320
321enum eval_prec {
322 MIN_PREC,
323 COND, LOGOR, LOGAND, OR, XOR, AND, EQUAL, RELATION, SHIFT, ADD, MUL, UNARY,
324 MAX_PREC
325};
326
327static int op_logor(int a, int b) { return a || b; }
328static int op_logand(int a, int b) { return a && b; }
329static int op_or(int a, int b) { return a | b; }
330static int op_xor(int a, int b) { return a ^ b; }
331static int op_and(int a, int b) { return a & b; }
332static int op_eq(int a, int b) { return a == b; }
333static int op_ne(int a, int b) { return a != b; }
334static int op_ge(int a, int b) { return a >= b; }
335static int op_le(int a, int b) { return a <= b; }
336static int op_gt(int a, int b) { return a > b; }
337static int op_lt(int a, int b) { return a < b; }
338static int op_shl(int a, int b) { return a << b; }
339static int op_shr(int a, int b) { return a >> b; }
340static int op_add(int a, int b) { return a + b; }
341static int op_sub(int a, int b) { return a - b; }
342static int op_mul(int a, int b) { return a * b; }
343static int op_div(int a, int b) { return a / b; }
344static int op_mod(int a, int b) { return a % b; }
345static int op_pos(int a) { return a; }
346static int op_neg(int a) { return -a; }
347static int op_cmpl(int a) { return ~a; }
348static int op_not(int a) { return !a; }
349
350struct {
351 int token, prec, (*op)(int, int);
352} binop[] = {
353 { CPP_OR_OP, LOGOR, op_logor },
354 { CPP_AND_OP, LOGAND, op_logand },
355 { '|', OR, op_or },
356 { '^', XOR, op_xor },
357 { '&', AND, op_and },
358 { CPP_EQ_OP, EQUAL, op_eq },
359 { CPP_NE_OP, EQUAL, op_ne },
360 { '>', RELATION, op_gt },
361 { CPP_GE_OP, RELATION, op_ge },
362 { '<', RELATION, op_lt },
363 { CPP_LE_OP, RELATION, op_le },
364 { CPP_LEFT_OP, SHIFT, op_shl },
365 { CPP_RIGHT_OP, SHIFT, op_shr },
366 { '+', ADD, op_add },
367 { '-', ADD, op_sub },
368 { '*', MUL, op_mul },
369 { '/', MUL, op_div },
370 { '%', MUL, op_mod },
371};
372
373struct {
374 int token, (*op)(int);
375} unop[] = {
376 { '+', op_pos },
377 { '-', op_neg },
378 { '~', op_cmpl },
379 { '!', op_not },
380};
381
382#define ALEN(A) (sizeof(A)/sizeof(A[0]))
383
384static int eval(int token, int prec, int *res, int *err, yystypepp * yylvalpp)
385{
386 int i, val;
387 Symbol *s;
388 if (token == CPP_IDENTIFIER) {
389 if (yylvalpp->sc_ident == definedAtom) {
390 int needclose = 0;
391 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
392 if (token == '(') {
393 needclose = 1;
394 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
395 }
396 if (token != CPP_IDENTIFIER)
397 goto error;
398 *res = (s = LookUpSymbol(macros, yylvalpp->sc_ident))
399 ? !s->details.mac.undef : 0;
400 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
401 if (needclose) {
402 if (token != ')')
403 goto error;
404 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
405 }
406 } else if (MacroExpand(yylvalpp->sc_ident, yylvalpp)) {
407 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
408 return eval(token, prec, res, err, yylvalpp);
409 } else {
410 goto error;
411 }
412 } else if (token == CPP_INTCONSTANT) {
413 *res = yylvalpp->sc_int;
414 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
415 } else if (token == '(') {
416 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
417 token = eval(token, MIN_PREC, res, err, yylvalpp);
418 if (!*err) {
419 if (token != ')')
420 goto error;
421 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
422 }
423 } else {
424 for (i = ALEN(unop) - 1; i >= 0; i--) {
425 if (unop[i].token == token)
426 break;
427 }
428 if (i >= 0) {
429 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
430 token = eval(token, UNARY, res, err, yylvalpp);
431 *res = unop[i].op(*res);
432 } else {
433 goto error;
434 }
435 }
436 while (!*err) {
437 if (token == ')' || token == '\n') break;
438 for (i = ALEN(binop) - 1; i >= 0; i--) {
439 if (binop[i].token == token)
440 break;
441 }
442 if (i < 0 || binop[i].prec <= prec)
443 break;
444 val = *res;
445 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
446 token = eval(token, binop[i].prec, res, err, yylvalpp);
447 *res = binop[i].op(val, *res);
448 }
449 return token;
450error:
451 CPPErrorToInfoLog("incorrect preprocessor directive");
452 *err = 1;
453 *res = 0;
454 return token;
455} // eval
456
457static int CPPif(yystypepp * yylvalpp) {
458 int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
459 int res = 0, err = 0;
460 cpp->elsetracker++;
daniel@transgaming.com9e78e5e2010-04-29 03:39:02 +0000461 cpp->elsedepth[cpp->elsetracker] = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000462 if (!cpp->ifdepth++)
463 ifloc = *cpp->tokenLoc;
464 if(cpp->ifdepth >MAX_IF_NESTING){
465 CPPErrorToInfoLog("max #if nesting depth exceeded");
466 return 0;
467 }
468 token = eval(token, MIN_PREC, &res, &err, yylvalpp);
469 if (token != '\n') {
470 CPPWarningToInfoLog("unexpected tokens following the preprocessor directive - expected a newline");
471 while (token != '\n')
472 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
473 }
474 if (!res && !err) {
475 token = CPPelse(1, yylvalpp);
476 }
477
478 return token;
479} // CPPif
480
481static int CPPifdef(int defined, yystypepp * yylvalpp)
482{
483 int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
484 int name = yylvalpp->sc_ident;
485 if(++cpp->ifdepth >MAX_IF_NESTING){
486 CPPErrorToInfoLog("max #if nesting depth exceeded");
487 return 0;
488 }
489 cpp->elsetracker++;
daniel@transgaming.com9e78e5e2010-04-29 03:39:02 +0000490 cpp->elsedepth[cpp->elsetracker] = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000491 if (token != CPP_IDENTIFIER) {
492 defined ? CPPErrorToInfoLog("ifdef"):CPPErrorToInfoLog("ifndef");
493 } else {
494 Symbol *s = LookUpSymbol(macros, name);
495 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
496 if (token != '\n') {
497 CPPWarningToInfoLog("unexpected tokens following #ifdef preprocessor directive - expected a newline");
498 while (token != '\n')
499 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
500 }
501 if (((s && !s->details.mac.undef) ? 1 : 0) != defined)
502 token = CPPelse(1, yylvalpp);
503 }
504 return token;
505} // CPPifdef
506
507static int CPPline(yystypepp * yylvalpp)
508{
509 int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
510 if(token=='\n'){
511 DecLineNumber();
512 CPPErrorToInfoLog("#line");
513 IncLineNumber();
514 return token;
515 }
516 else if (token == CPP_INTCONSTANT) {
517 yylvalpp->sc_int=atoi(yylvalpp->symbol_name);
518 SetLineNumber(yylvalpp->sc_int);
519 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
520
521 if (token == CPP_INTCONSTANT) {
522 yylvalpp->sc_int=atoi(yylvalpp->symbol_name);
523 SetStringNumber(yylvalpp->sc_int);
524 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
525 if(token!='\n')
526 CPPErrorToInfoLog("#line");
527 }
528 else if (token == '\n'){
529 return token;
530 }
531 else{
532 CPPErrorToInfoLog("#line");
533 }
534 }
535 else{
536 CPPErrorToInfoLog("#line");
537 }
538 return token;
539}
540
541static int CPPerror(yystypepp * yylvalpp) {
542
543 int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
544 const char *message;
545
546 while (token != '\n') {
547 if (token == CPP_FLOATCONSTANT || token == CPP_INTCONSTANT){
548 StoreStr(yylvalpp->symbol_name);
549 }else if(token == CPP_IDENTIFIER || token == CPP_STRCONSTANT){
550 StoreStr(GetStringOfAtom(atable,yylvalpp->sc_ident));
551 }else {
552 StoreStr(GetStringOfAtom(atable,token));
553 }
554 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
555 }
556 DecLineNumber();
557 //store this msg into the shader's information log..set the Compile Error flag!!!!
558 message=GetStrfromTStr();
559 CPPShInfoLogMsg(message);
560 ResetTString();
561 cpp->CompileError=1;
562 IncLineNumber();
563 return '\n';
564}//CPPerror
565
566static int CPPpragma(yystypepp * yylvalpp)
567{
568 char SrcStrName[2];
569 char** allTokens;
570 int tokenCount = 0;
571 int maxTokenCount = 10;
572 const char* SrcStr;
573 int i;
574
575 int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
576
577 if (token=='\n') {
578 DecLineNumber();
579 CPPErrorToInfoLog("#pragma");
580 IncLineNumber();
581 return token;
582 }
583
584 allTokens = (char**)malloc(sizeof(char*) * maxTokenCount);
585
586 while (token != '\n') {
587 if (tokenCount >= maxTokenCount) {
588 maxTokenCount *= 2;
589 allTokens = (char**)realloc((char**)allTokens, sizeof(char*) * maxTokenCount);
590 }
591 switch (token) {
592 case CPP_IDENTIFIER:
593 SrcStr = GetAtomString(atable, yylvalpp->sc_ident);
594 allTokens[tokenCount] = (char*)malloc(strlen(SrcStr) + 1);
595 strcpy(allTokens[tokenCount++], SrcStr);
596 break;
597 case CPP_INTCONSTANT:
598 SrcStr = yylvalpp->symbol_name;
599 allTokens[tokenCount] = (char*)malloc(strlen(SrcStr) + 1);
600 strcpy(allTokens[tokenCount++], SrcStr);
601 break;
602 case CPP_FLOATCONSTANT:
603 SrcStr = yylvalpp->symbol_name;
604 allTokens[tokenCount] = (char*)malloc(strlen(SrcStr) + 1);
605 strcpy(allTokens[tokenCount++], SrcStr);
606 break;
607 case -1:
608 // EOF
609 CPPShInfoLogMsg("#pragma directive must end with a newline");
610 return token;
611 default:
612 SrcStrName[0] = token;
613 SrcStrName[1] = '\0';
614 allTokens[tokenCount] = (char*)malloc(2);
615 strcpy(allTokens[tokenCount++], SrcStrName);
616 }
617 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
618 }
619
620 cpp->currentInput->ungetch(cpp->currentInput, token, yylvalpp);
621 HandlePragma((const char**)allTokens, tokenCount);
622 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
623
624 for (i = 0; i < tokenCount; ++i) {
625 free (allTokens[i]);
626 }
627 free (allTokens);
628
629 return token;
630} // CPPpragma
631
daniel@transgaming.com76039472010-04-15 20:45:18 +0000632#define ESSL_VERSION_NUMBER 100
633#define ESSL_VERSION_STRING "100"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000634
635static int CPPversion(yystypepp * yylvalpp)
636{
637
638 int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
639
daniel@transgaming.comdec19e22010-04-29 03:35:42 +0000640 if (cpp->pastFirstStatement == 1)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000641 CPPShInfoLogMsg("#version must occur before any other statement in the program");
642
643 if(token=='\n'){
644 DecLineNumber();
645 CPPErrorToInfoLog("#version");
646 IncLineNumber();
647 return token;
648 }
649 if (token != CPP_INTCONSTANT)
650 CPPErrorToInfoLog("#version");
651
652 yylvalpp->sc_int=atoi(yylvalpp->symbol_name);
653 //SetVersionNumber(yylvalpp->sc_int);
654
daniel@transgaming.com76039472010-04-15 20:45:18 +0000655 if (yylvalpp->sc_int != ESSL_VERSION_NUMBER)
656 CPPShInfoLogMsg("Version number not supported by ESSL");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000657
658 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
659
660 if (token == '\n'){
661 return token;
662 }
663 else{
664 CPPErrorToInfoLog("#version");
665 }
666 return token;
667} // CPPversion
668
669static int CPPextension(yystypepp * yylvalpp)
670{
671
672 int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
673 char extensionName[80];
674
675 if(token=='\n'){
676 DecLineNumber();
677 CPPShInfoLogMsg("extension name not specified");
678 IncLineNumber();
679 return token;
680 }
681
682 if (token != CPP_IDENTIFIER)
683 CPPErrorToInfoLog("#extension");
684
685 strcpy(extensionName, GetAtomString(atable, yylvalpp->sc_ident));
686
687 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
688 if (token != ':') {
689 CPPShInfoLogMsg("':' missing after extension name");
690 return token;
691 }
692
693 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
694 if (token != CPP_IDENTIFIER) {
695 CPPShInfoLogMsg("behavior for extension not specified");
696 return token;
697 }
698
699 updateExtensionBehavior(extensionName, GetAtomString(atable, yylvalpp->sc_ident));
700
701 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
702 if (token == '\n'){
703 return token;
704 }
705 else{
706 CPPErrorToInfoLog("#extension");
707 }
708 return token;
709} // CPPextension
710
711int readCPPline(yystypepp * yylvalpp)
712{
713 int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
714 const char *message;
715 int isVersion = 0;
716
717 if (token == CPP_IDENTIFIER) {
718 if (yylvalpp->sc_ident == defineAtom) {
719 token = CPPdefine(yylvalpp);
720 } else if (yylvalpp->sc_ident == elseAtom) {
721 if(ChkCorrectElseNesting()){
722 if (!cpp->ifdepth ){
723 CPPErrorToInfoLog("#else mismatch");
724 cpp->CompileError=1;
725 }
726 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
727 if (token != '\n') {
728 CPPWarningToInfoLog("unexpected tokens following #else preprocessor directive - expected a newline");
729 while (token != '\n')
730 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
731 }
732 token = CPPelse(0, yylvalpp);
733 }else{
734 CPPErrorToInfoLog("#else after a #else");
735 cpp->ifdepth=0;
daniel@transgaming.comdec19e22010-04-29 03:35:42 +0000736 cpp->pastFirstStatement = 1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000737 return 0;
738 }
739 } else if (yylvalpp->sc_ident == elifAtom) {
740 if (!cpp->ifdepth){
741 CPPErrorToInfoLog("#elif mismatch");
742 cpp->CompileError=1;
743 }
744 // this token is really a dont care, but we still need to eat the tokens
745 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
746 while (token != '\n')
747 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
748 token = CPPelse(0, yylvalpp);
749 } else if (yylvalpp->sc_ident == endifAtom) {
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000750 --cpp->elsetracker;
751 if (!cpp->ifdepth){
752 CPPErrorToInfoLog("#endif mismatch");
753 cpp->CompileError=1;
754 }
755 else
756 --cpp->ifdepth;
757 } else if (yylvalpp->sc_ident == ifAtom) {
758 token = CPPif(yylvalpp);
759 } else if (yylvalpp->sc_ident == ifdefAtom) {
760 token = CPPifdef(1, yylvalpp);
761 } else if (yylvalpp->sc_ident == ifndefAtom) {
762 token = CPPifdef(0, yylvalpp);
763 } else if (yylvalpp->sc_ident == lineAtom) {
764 token = CPPline(yylvalpp);
765 } else if (yylvalpp->sc_ident == pragmaAtom) {
766 token = CPPpragma(yylvalpp);
767 } else if (yylvalpp->sc_ident == undefAtom) {
768 token = CPPundef(yylvalpp);
769 } else if (yylvalpp->sc_ident == errorAtom) {
770 token = CPPerror(yylvalpp);
771 } else if (yylvalpp->sc_ident == versionAtom) {
772 token = CPPversion(yylvalpp);
773 isVersion = 1;
774 } else if (yylvalpp->sc_ident == extensionAtom) {
775 token = CPPextension(yylvalpp);
776 } else {
777 StoreStr("Invalid Directive");
778 StoreStr(GetStringOfAtom(atable,yylvalpp->sc_ident));
779 message=GetStrfromTStr();
780 CPPShInfoLogMsg(message);
781 ResetTString();
782 }
783 }
784 while (token != '\n' && token != 0 && token != EOF) {
785 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
786 }
787
daniel@transgaming.comdec19e22010-04-29 03:35:42 +0000788 cpp->pastFirstStatement = 1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000789
790 return token;
791} // readCPPline
792
793void FreeMacro(MacroSymbol *s) {
794 DeleteTokenStream(s->body);
795}
796
daniel@transgaming.comcd0a9a82010-05-18 18:51:59 +0000797void PredefineIntMacro(const char *name, int value) {
798 SourceLoc location = {0};
799 Symbol *symbol = NULL;
800 MacroSymbol macro = {0};
801 yystypepp val = {0};
802 int atom = 0;
803
804 macro.body = NewTokenStream(name, macros->pool);
805 val.sc_int = value;
806 sprintf(val.symbol_name, "%d", value);
807 RecordToken(macro.body, CPP_INTCONSTANT, &val);
808 atom = LookUpAddString(atable, name);
809 symbol = AddSymbol(&location, macros, atom, MACRO_S);
810 symbol->details.mac = macro;
811}
812
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000813static int eof_scan(InputSrc *in, yystypepp * yylvalpp) { return -1; }
814static void noop(InputSrc *in, int ch, yystypepp * yylvalpp) { }
815
816static void PushEofSrc() {
817 InputSrc *in = malloc(sizeof(InputSrc));
818 memset(in, 0, sizeof(InputSrc));
819 in->scan = eof_scan;
820 in->getch = eof_scan;
821 in->ungetch = noop;
822 in->prev = cpp->currentInput;
823 cpp->currentInput = in;
824}
825
826static void PopEofSrc() {
827 if (cpp->currentInput->scan == eof_scan) {
828 InputSrc *in = cpp->currentInput;
829 cpp->currentInput = in->prev;
830 free(in);
831 }
832}
833
834static TokenStream *PrescanMacroArg(TokenStream *a, yystypepp * yylvalpp) {
835 int token;
836 TokenStream *n;
837 RewindTokenStream(a);
838 do {
839 token = ReadToken(a, yylvalpp);
840 if (token == CPP_IDENTIFIER && LookUpSymbol(macros, yylvalpp->sc_ident))
841 break;
842 } while (token > 0);
843 if (token <= 0) return a;
844 n = NewTokenStream("macro arg", 0);
845 PushEofSrc();
846 ReadFromTokenStream(a, 0, 0);
847 while ((token = cpp->currentInput->scan(cpp->currentInput, yylvalpp)) > 0) {
848 if (token == CPP_IDENTIFIER && MacroExpand(yylvalpp->sc_ident, yylvalpp))
849 continue;
850 RecordToken(n, token, yylvalpp);
851 }
852 PopEofSrc();
853 DeleteTokenStream(a);
854 return n;
855} // PrescanMacroArg
856
857typedef struct MacroInputSrc {
858 InputSrc base;
859 MacroSymbol *mac;
860 TokenStream **args;
861} MacroInputSrc;
862
863/* macro_scan ---
864** return the next token for a macro expanion, handling macro args
865*/
866static int macro_scan(MacroInputSrc *in, yystypepp * yylvalpp) {
867 int i;
868 int token = ReadToken(in->mac->body, yylvalpp);
869 if (token == CPP_IDENTIFIER) {
870 for (i = in->mac->argc-1; i>=0; i--)
871 if (in->mac->args[i] == yylvalpp->sc_ident) break;
872 if (i >= 0) {
873 ReadFromTokenStream(in->args[i], yylvalpp->sc_ident, 0);
874 return cpp->currentInput->scan(cpp->currentInput, yylvalpp);
875 }
876 }
877 if (token > 0) return token;
878 in->mac->busy = 0;
879 cpp->currentInput = in->base.prev;
880 if (in->args) {
881 for (i=in->mac->argc-1; i>=0; i--)
882 DeleteTokenStream(in->args[i]);
883 free(in->args);
884 }
885 free(in);
886 return cpp->currentInput->scan(cpp->currentInput, yylvalpp);
887} // macro_scan
888
889/* MacroExpand
890** check an identifier (atom) to see if it a macro that should be expanded.
891** If it is, push an InputSrc that will produce the appropriate expansion
892** and return TRUE. If not, return FALSE.
893*/
894
895int MacroExpand(int atom, yystypepp * yylvalpp)
896{
897 Symbol *sym = LookUpSymbol(macros, atom);
898 MacroInputSrc *in;
899 int i,j, token, depth=0;
900 const char *message;
901 if (atom == __LINE__Atom) {
902 yylvalpp->sc_int = GetLineNumber();
903 sprintf(yylvalpp->symbol_name,"%d",yylvalpp->sc_int);
904 UngetToken(CPP_INTCONSTANT, yylvalpp);
905 return 1;
906 }
907 if (atom == __FILE__Atom) {
908 yylvalpp->sc_int = GetStringNumber();
909 sprintf(yylvalpp->symbol_name,"%d",yylvalpp->sc_int);
910 UngetToken(CPP_INTCONSTANT, yylvalpp);
911 return 1;
912 }
913 if (atom == __VERSION__Atom) {
daniel@transgaming.com76039472010-04-15 20:45:18 +0000914 strcpy(yylvalpp->symbol_name,ESSL_VERSION_STRING);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000915 yylvalpp->sc_int = atoi(yylvalpp->symbol_name);
916 UngetToken(CPP_INTCONSTANT, yylvalpp);
917 return 1;
918 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000919 if (!sym || sym->details.mac.undef) return 0;
920 if (sym->details.mac.busy) return 0; // no recursive expansions
921 in = malloc(sizeof(*in));
922 memset(in, 0, sizeof(*in));
923 in->base.scan = (void *)macro_scan;
924 in->base.line = cpp->currentInput->line;
925 in->base.name = cpp->currentInput->name;
926 in->mac = &sym->details.mac;
927 if (sym->details.mac.args) {
928 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
929 if (token != '(') {
930 UngetToken(token, yylvalpp);
931 yylvalpp->sc_ident = atom;
932 return 0;
933 }
934 in->args = malloc(in->mac->argc * sizeof(TokenStream *));
935 for (i=0; i<in->mac->argc; i++)
936 in->args[i] = NewTokenStream("macro arg", 0);
937 i=0;j=0;
938 do{
939 depth = 0;
940 while(1) {
941 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
942 if (token <= 0) {
943 StoreStr("EOF in Macro ");
944 StoreStr(GetStringOfAtom(atable,atom));
945 message=GetStrfromTStr();
946 CPPShInfoLogMsg(message);
947 ResetTString();
948 return 1;
949 }
950 if((in->mac->argc==0) && (token!=')')) break;
951 if (depth == 0 && (token == ',' || token == ')')) break;
952 if (token == '(') depth++;
953 if (token == ')') depth--;
954 RecordToken(in->args[i], token, yylvalpp);
955 j=1;
956 }
957 if (token == ')') {
958 if((in->mac->argc==1) &&j==0)
959 break;
960 i++;
961 break;
962 }
963 i++;
964 }while(i < in->mac->argc);
965
966 if (i < in->mac->argc) {
967 StoreStr("Too few args in Macro ");
968 StoreStr(GetStringOfAtom(atable,atom));
969 message=GetStrfromTStr();
970 CPPShInfoLogMsg(message);
971 ResetTString();
972 } else if (token != ')') {
973 depth=0;
974 while (token >= 0 && (depth > 0 || token != ')')) {
975 if (token == ')') depth--;
976 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
977 if (token == '(') depth++;
978 }
979
980 if (token <= 0) {
981 StoreStr("EOF in Macro ");
982 StoreStr(GetStringOfAtom(atable,atom));
983 message=GetStrfromTStr();
984 CPPShInfoLogMsg(message);
985 ResetTString();
986 return 1;
987 }
988 StoreStr("Too many args in Macro ");
989 StoreStr(GetStringOfAtom(atable,atom));
990 message=GetStrfromTStr();
991 CPPShInfoLogMsg(message);
992 ResetTString();
993 }
994 for (i=0; i<in->mac->argc; i++) {
995 in->args[i] = PrescanMacroArg(in->args[i], yylvalpp);
996 }
997 }
998#if 0
999 printf(" <%s:%d>found macro %s\n", GetAtomString(atable, loc.file),
1000 loc.line, GetAtomString(atable, atom));
1001 for (i=0; i<in->mac->argc; i++) {
1002 printf("\targ %s = '", GetAtomString(atable, in->mac->args[i]));
1003 DumpTokenStream(stdout, in->args[i]);
1004 printf("'\n");
1005 }
1006#endif
1007 /*retain the input source*/
1008 in->base.prev = cpp->currentInput;
1009 sym->details.mac.busy = 1;
1010 RewindTokenStream(sym->details.mac.body);
1011 cpp->currentInput = &in->base;
1012 return 1;
1013} // MacroExpand
1014
1015int ChkCorrectElseNesting(void)
1016{
1017 if(cpp->elsedepth[cpp->elsetracker]==0){
1018 cpp->elsedepth[cpp->elsetracker]=1;
1019 return 1;
1020 }
1021 return 0;
1022}
1023
1024