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