blob: 92e8443efc1bfe3fd664d3625344347aa41efa9a [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++;
284 }
285 else if (atom == endifAtom) {
286 if(--depth<=0){
287 cpp->elsedepth[cpp->elsetracker]=0;
288 --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++;
464 if (!cpp->ifdepth++)
465 ifloc = *cpp->tokenLoc;
466 if(cpp->ifdepth >MAX_IF_NESTING){
467 CPPErrorToInfoLog("max #if nesting depth exceeded");
468 return 0;
469 }
470 token = eval(token, MIN_PREC, &res, &err, yylvalpp);
471 if (token != '\n') {
472 CPPWarningToInfoLog("unexpected tokens following the preprocessor directive - expected a newline");
473 while (token != '\n')
474 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
475 }
476 if (!res && !err) {
477 token = CPPelse(1, yylvalpp);
478 }
479
480 return token;
481} // CPPif
482
483static int CPPifdef(int defined, yystypepp * yylvalpp)
484{
485 int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
486 int name = yylvalpp->sc_ident;
487 if(++cpp->ifdepth >MAX_IF_NESTING){
488 CPPErrorToInfoLog("max #if nesting depth exceeded");
489 return 0;
490 }
491 cpp->elsetracker++;
492 if (token != CPP_IDENTIFIER) {
493 defined ? CPPErrorToInfoLog("ifdef"):CPPErrorToInfoLog("ifndef");
494 } else {
495 Symbol *s = LookUpSymbol(macros, name);
496 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
497 if (token != '\n') {
498 CPPWarningToInfoLog("unexpected tokens following #ifdef preprocessor directive - expected a newline");
499 while (token != '\n')
500 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
501 }
502 if (((s && !s->details.mac.undef) ? 1 : 0) != defined)
503 token = CPPelse(1, yylvalpp);
504 }
505 return token;
506} // CPPifdef
507
508static int CPPline(yystypepp * yylvalpp)
509{
510 int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
511 if(token=='\n'){
512 DecLineNumber();
513 CPPErrorToInfoLog("#line");
514 IncLineNumber();
515 return token;
516 }
517 else if (token == CPP_INTCONSTANT) {
518 yylvalpp->sc_int=atoi(yylvalpp->symbol_name);
519 SetLineNumber(yylvalpp->sc_int);
520 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
521
522 if (token == CPP_INTCONSTANT) {
523 yylvalpp->sc_int=atoi(yylvalpp->symbol_name);
524 SetStringNumber(yylvalpp->sc_int);
525 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
526 if(token!='\n')
527 CPPErrorToInfoLog("#line");
528 }
529 else if (token == '\n'){
530 return token;
531 }
532 else{
533 CPPErrorToInfoLog("#line");
534 }
535 }
536 else{
537 CPPErrorToInfoLog("#line");
538 }
539 return token;
540}
541
542static int CPPerror(yystypepp * yylvalpp) {
543
544 int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
545 const char *message;
546
547 while (token != '\n') {
548 if (token == CPP_FLOATCONSTANT || token == CPP_INTCONSTANT){
549 StoreStr(yylvalpp->symbol_name);
550 }else if(token == CPP_IDENTIFIER || token == CPP_STRCONSTANT){
551 StoreStr(GetStringOfAtom(atable,yylvalpp->sc_ident));
552 }else {
553 StoreStr(GetStringOfAtom(atable,token));
554 }
555 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
556 }
557 DecLineNumber();
558 //store this msg into the shader's information log..set the Compile Error flag!!!!
559 message=GetStrfromTStr();
560 CPPShInfoLogMsg(message);
561 ResetTString();
562 cpp->CompileError=1;
563 IncLineNumber();
564 return '\n';
565}//CPPerror
566
567static int CPPpragma(yystypepp * yylvalpp)
568{
569 char SrcStrName[2];
570 char** allTokens;
571 int tokenCount = 0;
572 int maxTokenCount = 10;
573 const char* SrcStr;
574 int i;
575
576 int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
577
578 if (token=='\n') {
579 DecLineNumber();
580 CPPErrorToInfoLog("#pragma");
581 IncLineNumber();
582 return token;
583 }
584
585 allTokens = (char**)malloc(sizeof(char*) * maxTokenCount);
586
587 while (token != '\n') {
588 if (tokenCount >= maxTokenCount) {
589 maxTokenCount *= 2;
590 allTokens = (char**)realloc((char**)allTokens, sizeof(char*) * maxTokenCount);
591 }
592 switch (token) {
593 case CPP_IDENTIFIER:
594 SrcStr = GetAtomString(atable, yylvalpp->sc_ident);
595 allTokens[tokenCount] = (char*)malloc(strlen(SrcStr) + 1);
596 strcpy(allTokens[tokenCount++], SrcStr);
597 break;
598 case CPP_INTCONSTANT:
599 SrcStr = yylvalpp->symbol_name;
600 allTokens[tokenCount] = (char*)malloc(strlen(SrcStr) + 1);
601 strcpy(allTokens[tokenCount++], SrcStr);
602 break;
603 case CPP_FLOATCONSTANT:
604 SrcStr = yylvalpp->symbol_name;
605 allTokens[tokenCount] = (char*)malloc(strlen(SrcStr) + 1);
606 strcpy(allTokens[tokenCount++], SrcStr);
607 break;
608 case -1:
609 // EOF
610 CPPShInfoLogMsg("#pragma directive must end with a newline");
611 return token;
612 default:
613 SrcStrName[0] = token;
614 SrcStrName[1] = '\0';
615 allTokens[tokenCount] = (char*)malloc(2);
616 strcpy(allTokens[tokenCount++], SrcStrName);
617 }
618 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
619 }
620
621 cpp->currentInput->ungetch(cpp->currentInput, token, yylvalpp);
622 HandlePragma((const char**)allTokens, tokenCount);
623 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
624
625 for (i = 0; i < tokenCount; ++i) {
626 free (allTokens[i]);
627 }
628 free (allTokens);
629
630 return token;
631} // CPPpragma
632
daniel@transgaming.com76039472010-04-15 20:45:18 +0000633#define ESSL_VERSION_NUMBER 100
634#define ESSL_VERSION_STRING "100"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000635
636static int CPPversion(yystypepp * yylvalpp)
637{
638
639 int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
640
641 if (cpp->notAVersionToken == 1)
642 CPPShInfoLogMsg("#version must occur before any other statement in the program");
643
644 if(token=='\n'){
645 DecLineNumber();
646 CPPErrorToInfoLog("#version");
647 IncLineNumber();
648 return token;
649 }
650 if (token != CPP_INTCONSTANT)
651 CPPErrorToInfoLog("#version");
652
653 yylvalpp->sc_int=atoi(yylvalpp->symbol_name);
654 //SetVersionNumber(yylvalpp->sc_int);
655
daniel@transgaming.com76039472010-04-15 20:45:18 +0000656 if (yylvalpp->sc_int != ESSL_VERSION_NUMBER)
657 CPPShInfoLogMsg("Version number not supported by ESSL");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000658
659 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
660
661 if (token == '\n'){
662 return token;
663 }
664 else{
665 CPPErrorToInfoLog("#version");
666 }
667 return token;
668} // CPPversion
669
670static int CPPextension(yystypepp * yylvalpp)
671{
672
673 int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
674 char extensionName[80];
675
676 if(token=='\n'){
677 DecLineNumber();
678 CPPShInfoLogMsg("extension name not specified");
679 IncLineNumber();
680 return token;
681 }
682
683 if (token != CPP_IDENTIFIER)
684 CPPErrorToInfoLog("#extension");
685
686 strcpy(extensionName, GetAtomString(atable, yylvalpp->sc_ident));
687
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;
737 cpp->notAVersionToken = 1;
738 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) {
751 cpp->elsedepth[cpp->elsetracker]=0;
752 --cpp->elsetracker;
753 if (!cpp->ifdepth){
754 CPPErrorToInfoLog("#endif mismatch");
755 cpp->CompileError=1;
756 }
757 else
758 --cpp->ifdepth;
759 } else if (yylvalpp->sc_ident == ifAtom) {
760 token = CPPif(yylvalpp);
761 } else if (yylvalpp->sc_ident == ifdefAtom) {
762 token = CPPifdef(1, yylvalpp);
763 } else if (yylvalpp->sc_ident == ifndefAtom) {
764 token = CPPifdef(0, yylvalpp);
765 } else if (yylvalpp->sc_ident == lineAtom) {
766 token = CPPline(yylvalpp);
767 } else if (yylvalpp->sc_ident == pragmaAtom) {
768 token = CPPpragma(yylvalpp);
769 } else if (yylvalpp->sc_ident == undefAtom) {
770 token = CPPundef(yylvalpp);
771 } else if (yylvalpp->sc_ident == errorAtom) {
772 token = CPPerror(yylvalpp);
773 } else if (yylvalpp->sc_ident == versionAtom) {
774 token = CPPversion(yylvalpp);
775 isVersion = 1;
776 } else if (yylvalpp->sc_ident == extensionAtom) {
777 token = CPPextension(yylvalpp);
778 } else {
779 StoreStr("Invalid Directive");
780 StoreStr(GetStringOfAtom(atable,yylvalpp->sc_ident));
781 message=GetStrfromTStr();
782 CPPShInfoLogMsg(message);
783 ResetTString();
784 }
785 }
786 while (token != '\n' && token != 0 && token != EOF) {
787 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
788 }
789
790 cpp->notAVersionToken = !isVersion;
791
792 return token;
793} // readCPPline
794
795void FreeMacro(MacroSymbol *s) {
796 DeleteTokenStream(s->body);
797}
798
799static int eof_scan(InputSrc *in, yystypepp * yylvalpp) { return -1; }
800static void noop(InputSrc *in, int ch, yystypepp * yylvalpp) { }
801
802static void PushEofSrc() {
803 InputSrc *in = malloc(sizeof(InputSrc));
804 memset(in, 0, sizeof(InputSrc));
805 in->scan = eof_scan;
806 in->getch = eof_scan;
807 in->ungetch = noop;
808 in->prev = cpp->currentInput;
809 cpp->currentInput = in;
810}
811
812static void PopEofSrc() {
813 if (cpp->currentInput->scan == eof_scan) {
814 InputSrc *in = cpp->currentInput;
815 cpp->currentInput = in->prev;
816 free(in);
817 }
818}
819
820static TokenStream *PrescanMacroArg(TokenStream *a, yystypepp * yylvalpp) {
821 int token;
822 TokenStream *n;
823 RewindTokenStream(a);
824 do {
825 token = ReadToken(a, yylvalpp);
826 if (token == CPP_IDENTIFIER && LookUpSymbol(macros, yylvalpp->sc_ident))
827 break;
828 } while (token > 0);
829 if (token <= 0) return a;
830 n = NewTokenStream("macro arg", 0);
831 PushEofSrc();
832 ReadFromTokenStream(a, 0, 0);
833 while ((token = cpp->currentInput->scan(cpp->currentInput, yylvalpp)) > 0) {
834 if (token == CPP_IDENTIFIER && MacroExpand(yylvalpp->sc_ident, yylvalpp))
835 continue;
836 RecordToken(n, token, yylvalpp);
837 }
838 PopEofSrc();
839 DeleteTokenStream(a);
840 return n;
841} // PrescanMacroArg
842
843typedef struct MacroInputSrc {
844 InputSrc base;
845 MacroSymbol *mac;
846 TokenStream **args;
847} MacroInputSrc;
848
849/* macro_scan ---
850** return the next token for a macro expanion, handling macro args
851*/
852static int macro_scan(MacroInputSrc *in, yystypepp * yylvalpp) {
853 int i;
854 int token = ReadToken(in->mac->body, yylvalpp);
855 if (token == CPP_IDENTIFIER) {
856 for (i = in->mac->argc-1; i>=0; i--)
857 if (in->mac->args[i] == yylvalpp->sc_ident) break;
858 if (i >= 0) {
859 ReadFromTokenStream(in->args[i], yylvalpp->sc_ident, 0);
860 return cpp->currentInput->scan(cpp->currentInput, yylvalpp);
861 }
862 }
863 if (token > 0) return token;
864 in->mac->busy = 0;
865 cpp->currentInput = in->base.prev;
866 if (in->args) {
867 for (i=in->mac->argc-1; i>=0; i--)
868 DeleteTokenStream(in->args[i]);
869 free(in->args);
870 }
871 free(in);
872 return cpp->currentInput->scan(cpp->currentInput, yylvalpp);
873} // macro_scan
874
875/* MacroExpand
876** check an identifier (atom) to see if it a macro that should be expanded.
877** If it is, push an InputSrc that will produce the appropriate expansion
878** and return TRUE. If not, return FALSE.
879*/
880
881int MacroExpand(int atom, yystypepp * yylvalpp)
882{
883 Symbol *sym = LookUpSymbol(macros, atom);
884 MacroInputSrc *in;
885 int i,j, token, depth=0;
886 const char *message;
887 if (atom == __LINE__Atom) {
888 yylvalpp->sc_int = GetLineNumber();
889 sprintf(yylvalpp->symbol_name,"%d",yylvalpp->sc_int);
890 UngetToken(CPP_INTCONSTANT, yylvalpp);
891 return 1;
892 }
893 if (atom == __FILE__Atom) {
894 yylvalpp->sc_int = GetStringNumber();
895 sprintf(yylvalpp->symbol_name,"%d",yylvalpp->sc_int);
896 UngetToken(CPP_INTCONSTANT, yylvalpp);
897 return 1;
898 }
899 if (atom == __VERSION__Atom) {
daniel@transgaming.com76039472010-04-15 20:45:18 +0000900 strcpy(yylvalpp->symbol_name,ESSL_VERSION_STRING);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000901 yylvalpp->sc_int = atoi(yylvalpp->symbol_name);
902 UngetToken(CPP_INTCONSTANT, yylvalpp);
903 return 1;
904 }
905 if (!sym || sym->details.mac.undef) return 0;
906 if (sym->details.mac.busy) return 0; // no recursive expansions
907 in = malloc(sizeof(*in));
908 memset(in, 0, sizeof(*in));
909 in->base.scan = (void *)macro_scan;
910 in->base.line = cpp->currentInput->line;
911 in->base.name = cpp->currentInput->name;
912 in->mac = &sym->details.mac;
913 if (sym->details.mac.args) {
914 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
915 if (token != '(') {
916 UngetToken(token, yylvalpp);
917 yylvalpp->sc_ident = atom;
918 return 0;
919 }
920 in->args = malloc(in->mac->argc * sizeof(TokenStream *));
921 for (i=0; i<in->mac->argc; i++)
922 in->args[i] = NewTokenStream("macro arg", 0);
923 i=0;j=0;
924 do{
925 depth = 0;
926 while(1) {
927 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
928 if (token <= 0) {
929 StoreStr("EOF in Macro ");
930 StoreStr(GetStringOfAtom(atable,atom));
931 message=GetStrfromTStr();
932 CPPShInfoLogMsg(message);
933 ResetTString();
934 return 1;
935 }
936 if((in->mac->argc==0) && (token!=')')) break;
937 if (depth == 0 && (token == ',' || token == ')')) break;
938 if (token == '(') depth++;
939 if (token == ')') depth--;
940 RecordToken(in->args[i], token, yylvalpp);
941 j=1;
942 }
943 if (token == ')') {
944 if((in->mac->argc==1) &&j==0)
945 break;
946 i++;
947 break;
948 }
949 i++;
950 }while(i < in->mac->argc);
951
952 if (i < in->mac->argc) {
953 StoreStr("Too few args in Macro ");
954 StoreStr(GetStringOfAtom(atable,atom));
955 message=GetStrfromTStr();
956 CPPShInfoLogMsg(message);
957 ResetTString();
958 } else if (token != ')') {
959 depth=0;
960 while (token >= 0 && (depth > 0 || token != ')')) {
961 if (token == ')') depth--;
962 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
963 if (token == '(') depth++;
964 }
965
966 if (token <= 0) {
967 StoreStr("EOF in Macro ");
968 StoreStr(GetStringOfAtom(atable,atom));
969 message=GetStrfromTStr();
970 CPPShInfoLogMsg(message);
971 ResetTString();
972 return 1;
973 }
974 StoreStr("Too many args in Macro ");
975 StoreStr(GetStringOfAtom(atable,atom));
976 message=GetStrfromTStr();
977 CPPShInfoLogMsg(message);
978 ResetTString();
979 }
980 for (i=0; i<in->mac->argc; i++) {
981 in->args[i] = PrescanMacroArg(in->args[i], yylvalpp);
982 }
983 }
984#if 0
985 printf(" <%s:%d>found macro %s\n", GetAtomString(atable, loc.file),
986 loc.line, GetAtomString(atable, atom));
987 for (i=0; i<in->mac->argc; i++) {
988 printf("\targ %s = '", GetAtomString(atable, in->mac->args[i]));
989 DumpTokenStream(stdout, in->args[i]);
990 printf("'\n");
991 }
992#endif
993 /*retain the input source*/
994 in->base.prev = cpp->currentInput;
995 sym->details.mac.busy = 1;
996 RewindTokenStream(sym->details.mac.body);
997 cpp->currentInput = &in->base;
998 return 1;
999} // MacroExpand
1000
1001int ChkCorrectElseNesting(void)
1002{
1003 if(cpp->elsedepth[cpp->elsetracker]==0){
1004 cpp->elsedepth[cpp->elsetracker]=1;
1005 return 1;
1006 }
1007 return 0;
1008}
1009
1010