blob: e73e31411d1c3aed5bfe3be87a2205c1e8a70b9a [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);
alokp@chromium.org43668cd2010-10-20 20:55:53 +0000673 char extensionName[MAX_SYMBOL_NAME_LEN + 1];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000674
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
alokp@chromium.org43668cd2010-10-20 20:55:53 +0000685 strncpy(extensionName, GetAtomString(atable, yylvalpp->sc_ident), MAX_SYMBOL_NAME_LEN);
686 extensionName[MAX_SYMBOL_NAME_LEN] = '\0';
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000687
688 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
689 if (token != ':') {
690 CPPShInfoLogMsg("':' missing after extension name");
691 return token;
692 }
693
694 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
695 if (token != CPP_IDENTIFIER) {
696 CPPShInfoLogMsg("behavior for extension not specified");
697 return token;
698 }
699
700 updateExtensionBehavior(extensionName, GetAtomString(atable, yylvalpp->sc_ident));
701
702 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
703 if (token == '\n'){
704 return token;
705 }
706 else{
707 CPPErrorToInfoLog("#extension");
708 }
709 return token;
710} // CPPextension
711
712int readCPPline(yystypepp * yylvalpp)
713{
714 int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
715 const char *message;
716 int isVersion = 0;
717
718 if (token == CPP_IDENTIFIER) {
719 if (yylvalpp->sc_ident == defineAtom) {
720 token = CPPdefine(yylvalpp);
721 } else if (yylvalpp->sc_ident == elseAtom) {
722 if(ChkCorrectElseNesting()){
723 if (!cpp->ifdepth ){
724 CPPErrorToInfoLog("#else mismatch");
725 cpp->CompileError=1;
726 }
727 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
728 if (token != '\n') {
729 CPPWarningToInfoLog("unexpected tokens following #else preprocessor directive - expected a newline");
730 while (token != '\n')
731 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
732 }
733 token = CPPelse(0, yylvalpp);
734 }else{
735 CPPErrorToInfoLog("#else after a #else");
736 cpp->ifdepth=0;
daniel@transgaming.comdec19e22010-04-29 03:35:42 +0000737 cpp->pastFirstStatement = 1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000738 return 0;
739 }
740 } else if (yylvalpp->sc_ident == elifAtom) {
741 if (!cpp->ifdepth){
742 CPPErrorToInfoLog("#elif mismatch");
743 cpp->CompileError=1;
744 }
745 // this token is really a dont care, but we still need to eat the tokens
746 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
747 while (token != '\n')
748 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
749 token = CPPelse(0, yylvalpp);
750 } else if (yylvalpp->sc_ident == endifAtom) {
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000751 --cpp->elsetracker;
752 if (!cpp->ifdepth){
753 CPPErrorToInfoLog("#endif mismatch");
754 cpp->CompileError=1;
755 }
756 else
757 --cpp->ifdepth;
758 } else if (yylvalpp->sc_ident == ifAtom) {
759 token = CPPif(yylvalpp);
760 } else if (yylvalpp->sc_ident == ifdefAtom) {
761 token = CPPifdef(1, yylvalpp);
762 } else if (yylvalpp->sc_ident == ifndefAtom) {
763 token = CPPifdef(0, yylvalpp);
764 } else if (yylvalpp->sc_ident == lineAtom) {
765 token = CPPline(yylvalpp);
766 } else if (yylvalpp->sc_ident == pragmaAtom) {
767 token = CPPpragma(yylvalpp);
768 } else if (yylvalpp->sc_ident == undefAtom) {
769 token = CPPundef(yylvalpp);
770 } else if (yylvalpp->sc_ident == errorAtom) {
771 token = CPPerror(yylvalpp);
772 } else if (yylvalpp->sc_ident == versionAtom) {
773 token = CPPversion(yylvalpp);
774 isVersion = 1;
775 } else if (yylvalpp->sc_ident == extensionAtom) {
776 token = CPPextension(yylvalpp);
777 } else {
778 StoreStr("Invalid Directive");
779 StoreStr(GetStringOfAtom(atable,yylvalpp->sc_ident));
780 message=GetStrfromTStr();
781 CPPShInfoLogMsg(message);
782 ResetTString();
783 }
784 }
785 while (token != '\n' && token != 0 && token != EOF) {
786 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
787 }
788
daniel@transgaming.comdec19e22010-04-29 03:35:42 +0000789 cpp->pastFirstStatement = 1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000790
791 return token;
792} // readCPPline
793
794void FreeMacro(MacroSymbol *s) {
795 DeleteTokenStream(s->body);
796}
797
daniel@transgaming.comcd0a9a82010-05-18 18:51:59 +0000798void PredefineIntMacro(const char *name, int value) {
799 SourceLoc location = {0};
800 Symbol *symbol = NULL;
801 MacroSymbol macro = {0};
802 yystypepp val = {0};
803 int atom = 0;
804
805 macro.body = NewTokenStream(name, macros->pool);
806 val.sc_int = value;
807 sprintf(val.symbol_name, "%d", value);
808 RecordToken(macro.body, CPP_INTCONSTANT, &val);
809 atom = LookUpAddString(atable, name);
810 symbol = AddSymbol(&location, macros, atom, MACRO_S);
811 symbol->details.mac = macro;
812}
813
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000814static int eof_scan(InputSrc *in, yystypepp * yylvalpp) { return -1; }
815static void noop(InputSrc *in, int ch, yystypepp * yylvalpp) { }
816
817static void PushEofSrc() {
818 InputSrc *in = malloc(sizeof(InputSrc));
819 memset(in, 0, sizeof(InputSrc));
820 in->scan = eof_scan;
821 in->getch = eof_scan;
822 in->ungetch = noop;
823 in->prev = cpp->currentInput;
824 cpp->currentInput = in;
825}
826
827static void PopEofSrc() {
828 if (cpp->currentInput->scan == eof_scan) {
829 InputSrc *in = cpp->currentInput;
830 cpp->currentInput = in->prev;
831 free(in);
832 }
833}
834
835static TokenStream *PrescanMacroArg(TokenStream *a, yystypepp * yylvalpp) {
836 int token;
837 TokenStream *n;
838 RewindTokenStream(a);
839 do {
840 token = ReadToken(a, yylvalpp);
841 if (token == CPP_IDENTIFIER && LookUpSymbol(macros, yylvalpp->sc_ident))
842 break;
843 } while (token > 0);
844 if (token <= 0) return a;
845 n = NewTokenStream("macro arg", 0);
846 PushEofSrc();
847 ReadFromTokenStream(a, 0, 0);
848 while ((token = cpp->currentInput->scan(cpp->currentInput, yylvalpp)) > 0) {
849 if (token == CPP_IDENTIFIER && MacroExpand(yylvalpp->sc_ident, yylvalpp))
850 continue;
851 RecordToken(n, token, yylvalpp);
852 }
853 PopEofSrc();
854 DeleteTokenStream(a);
855 return n;
856} // PrescanMacroArg
857
858typedef struct MacroInputSrc {
859 InputSrc base;
860 MacroSymbol *mac;
861 TokenStream **args;
862} MacroInputSrc;
863
864/* macro_scan ---
865** return the next token for a macro expanion, handling macro args
866*/
867static int macro_scan(MacroInputSrc *in, yystypepp * yylvalpp) {
868 int i;
869 int token = ReadToken(in->mac->body, yylvalpp);
870 if (token == CPP_IDENTIFIER) {
871 for (i = in->mac->argc-1; i>=0; i--)
872 if (in->mac->args[i] == yylvalpp->sc_ident) break;
873 if (i >= 0) {
874 ReadFromTokenStream(in->args[i], yylvalpp->sc_ident, 0);
875 return cpp->currentInput->scan(cpp->currentInput, yylvalpp);
876 }
877 }
878 if (token > 0) return token;
879 in->mac->busy = 0;
880 cpp->currentInput = in->base.prev;
881 if (in->args) {
882 for (i=in->mac->argc-1; i>=0; i--)
883 DeleteTokenStream(in->args[i]);
884 free(in->args);
885 }
886 free(in);
887 return cpp->currentInput->scan(cpp->currentInput, yylvalpp);
888} // macro_scan
889
890/* MacroExpand
891** check an identifier (atom) to see if it a macro that should be expanded.
892** If it is, push an InputSrc that will produce the appropriate expansion
893** and return TRUE. If not, return FALSE.
894*/
895
896int MacroExpand(int atom, yystypepp * yylvalpp)
897{
898 Symbol *sym = LookUpSymbol(macros, atom);
899 MacroInputSrc *in;
900 int i,j, token, depth=0;
901 const char *message;
902 if (atom == __LINE__Atom) {
903 yylvalpp->sc_int = GetLineNumber();
904 sprintf(yylvalpp->symbol_name,"%d",yylvalpp->sc_int);
905 UngetToken(CPP_INTCONSTANT, yylvalpp);
906 return 1;
907 }
908 if (atom == __FILE__Atom) {
909 yylvalpp->sc_int = GetStringNumber();
910 sprintf(yylvalpp->symbol_name,"%d",yylvalpp->sc_int);
911 UngetToken(CPP_INTCONSTANT, yylvalpp);
912 return 1;
913 }
914 if (atom == __VERSION__Atom) {
daniel@transgaming.com76039472010-04-15 20:45:18 +0000915 strcpy(yylvalpp->symbol_name,ESSL_VERSION_STRING);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000916 yylvalpp->sc_int = atoi(yylvalpp->symbol_name);
917 UngetToken(CPP_INTCONSTANT, yylvalpp);
918 return 1;
919 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000920 if (!sym || sym->details.mac.undef) return 0;
921 if (sym->details.mac.busy) return 0; // no recursive expansions
922 in = malloc(sizeof(*in));
923 memset(in, 0, sizeof(*in));
924 in->base.scan = (void *)macro_scan;
925 in->base.line = cpp->currentInput->line;
926 in->base.name = cpp->currentInput->name;
927 in->mac = &sym->details.mac;
928 if (sym->details.mac.args) {
929 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
930 if (token != '(') {
931 UngetToken(token, yylvalpp);
932 yylvalpp->sc_ident = atom;
933 return 0;
934 }
935 in->args = malloc(in->mac->argc * sizeof(TokenStream *));
936 for (i=0; i<in->mac->argc; i++)
937 in->args[i] = NewTokenStream("macro arg", 0);
938 i=0;j=0;
939 do{
940 depth = 0;
941 while(1) {
942 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
943 if (token <= 0) {
944 StoreStr("EOF in Macro ");
945 StoreStr(GetStringOfAtom(atable,atom));
946 message=GetStrfromTStr();
947 CPPShInfoLogMsg(message);
948 ResetTString();
949 return 1;
950 }
951 if((in->mac->argc==0) && (token!=')')) break;
952 if (depth == 0 && (token == ',' || token == ')')) break;
953 if (token == '(') depth++;
954 if (token == ')') depth--;
955 RecordToken(in->args[i], token, yylvalpp);
956 j=1;
957 }
958 if (token == ')') {
959 if((in->mac->argc==1) &&j==0)
960 break;
961 i++;
962 break;
963 }
964 i++;
965 }while(i < in->mac->argc);
966
967 if (i < in->mac->argc) {
968 StoreStr("Too few args in Macro ");
969 StoreStr(GetStringOfAtom(atable,atom));
970 message=GetStrfromTStr();
971 CPPShInfoLogMsg(message);
972 ResetTString();
973 } else if (token != ')') {
974 depth=0;
975 while (token >= 0 && (depth > 0 || token != ')')) {
976 if (token == ')') depth--;
977 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
978 if (token == '(') depth++;
979 }
980
981 if (token <= 0) {
982 StoreStr("EOF in Macro ");
983 StoreStr(GetStringOfAtom(atable,atom));
984 message=GetStrfromTStr();
985 CPPShInfoLogMsg(message);
986 ResetTString();
987 return 1;
988 }
989 StoreStr("Too many args in Macro ");
990 StoreStr(GetStringOfAtom(atable,atom));
991 message=GetStrfromTStr();
992 CPPShInfoLogMsg(message);
993 ResetTString();
994 }
995 for (i=0; i<in->mac->argc; i++) {
996 in->args[i] = PrescanMacroArg(in->args[i], yylvalpp);
997 }
998 }
999#if 0
1000 printf(" <%s:%d>found macro %s\n", GetAtomString(atable, loc.file),
1001 loc.line, GetAtomString(atable, atom));
1002 for (i=0; i<in->mac->argc; i++) {
1003 printf("\targ %s = '", GetAtomString(atable, in->mac->args[i]));
1004 DumpTokenStream(stdout, in->args[i]);
1005 printf("'\n");
1006 }
1007#endif
1008 /*retain the input source*/
1009 in->base.prev = cpp->currentInput;
1010 sym->details.mac.busy = 1;
1011 RewindTokenStream(sym->details.mac.body);
1012 cpp->currentInput = &in->base;
1013 return 1;
1014} // MacroExpand
1015
1016int ChkCorrectElseNesting(void)
1017{
1018 if(cpp->elsedepth[cpp->elsetracker]==0){
1019 cpp->elsedepth[cpp->elsetracker]=1;
1020 return 1;
1021 }
1022 return 0;
1023}
1024
1025