blob: a8e22f3e2bbd5e06159faed99fe38288ef1baba4 [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;
daniel@transgaming.com9bc5d232010-05-14 17:30:33 +000087static int gl_esAtom = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000088static int versionAtom = 0;
89static int extensionAtom = 0;
90
91static Scope *macros = 0;
92#define MAX_MACRO_ARGS 64
93#define MAX_IF_NESTING 64
94
95static SourceLoc ifloc; /* outermost #if */
96
97int InitCPP(void)
98{
99 char buffer[64], *t;
100 const char *f;
101 // Add various atoms needed by the CPP line scanner:
102 bindAtom = LookUpAddString(atable, "bind");
103 constAtom = LookUpAddString(atable, "const");
104 defaultAtom = LookUpAddString(atable, "default");
105 defineAtom = LookUpAddString(atable, "define");
106 definedAtom = LookUpAddString(atable, "defined");
107 elifAtom = LookUpAddString(atable, "elif");
108 elseAtom = LookUpAddString(atable, "else");
109 endifAtom = LookUpAddString(atable, "endif");
110 ifAtom = LookUpAddString(atable, "if");
111 ifdefAtom = LookUpAddString(atable, "ifdef");
112 ifndefAtom = LookUpAddString(atable, "ifndef");
113 includeAtom = LookUpAddString(atable, "include");
114 lineAtom = LookUpAddString(atable, "line");
115 pragmaAtom = LookUpAddString(atable, "pragma");
116 texunitAtom = LookUpAddString(atable, "texunit");
117 undefAtom = LookUpAddString(atable, "undef");
118 errorAtom = LookUpAddString(atable, "error");
119 __LINE__Atom = LookUpAddString(atable, "__LINE__");
120 __FILE__Atom = LookUpAddString(atable, "__FILE__");
121 __VERSION__Atom = LookUpAddString(atable, "__VERSION__");
daniel@transgaming.com9bc5d232010-05-14 17:30:33 +0000122 gl_esAtom = LookUpAddString(atable, "GL_ES");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000123 versionAtom = LookUpAddString(atable, "version");
124 extensionAtom = LookUpAddString(atable, "extension");
125 macros = NewScopeInPool(mem_CreatePool(0, 0));
126 strcpy(buffer, "PROFILE_");
127 t = buffer + strlen(buffer);
128 f = cpp->options.profileString;
129 while ((isalnum(*f) || *f == '_') && t < buffer + sizeof(buffer) - 1)
130 *t++ = toupper(*f++);
131 *t = 0;
132 return 1;
133} // InitCPP
134
135int FreeCPP(void)
136{
137 if (macros)
138 {
139 mem_FreePool(macros->pool);
140 macros = 0;
141 }
142
143 return 1;
144}
145
146int FinalCPP(void)
147{
148 if (cpp->ifdepth)
149 CPPErrorToInfoLog("#if mismatch");
150 return 1;
151}
152
153static int CPPdefine(yystypepp * yylvalpp)
154{
155 int token, name, args[MAX_MACRO_ARGS], argc;
156 const char *message;
157 MacroSymbol mac;
158 Symbol *symb;
159 SourceLoc dummyLoc;
160 memset(&mac, 0, sizeof(mac));
161 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
162 if (token != CPP_IDENTIFIER) {
163 CPPErrorToInfoLog("#define");
164 return token;
165 }
166 name = yylvalpp->sc_ident;
167 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
168 if (token == '(' && !yylvalpp->sc_int) {
169 // gather arguments
170 argc = 0;
171 do {
172 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
173 if (argc == 0 && token == ')') break;
174 if (token != CPP_IDENTIFIER) {
175 CPPErrorToInfoLog("#define");
176 return token;
177 }
178 if (argc < MAX_MACRO_ARGS)
179 args[argc++] = yylvalpp->sc_ident;
180 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
181 } while (token == ',');
182 if (token != ')') {
183 CPPErrorToInfoLog("#define");
184 return token;
185 }
186 mac.argc = argc;
187 mac.args = mem_Alloc(macros->pool, argc * sizeof(int));
188 memcpy(mac.args, args, argc * sizeof(int));
189 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
190 }
191 mac.body = NewTokenStream(GetAtomString(atable, name), macros->pool);
192 while (token != '\n') {
daniel@transgaming.comedff8dc2010-05-14 17:30:27 +0000193 if (token == '\\') {
194 CPPErrorToInfoLog("The line continuation character (\\) is not part of the OpenGL ES Shading Language");
195 return token;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000196 }
197 RecordToken(mac.body, token, yylvalpp);
198 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
199 };
200
201 symb = LookUpSymbol(macros, name);
202 if (symb) {
203 if (!symb->details.mac.undef) {
204 // already defined -- need to make sure they are identical
205 if (symb->details.mac.argc != mac.argc) goto error;
206 for (argc=0; argc < mac.argc; argc++)
207 if (symb->details.mac.args[argc] != mac.args[argc])
208 goto error;
209 RewindTokenStream(symb->details.mac.body);
210 RewindTokenStream(mac.body);
211 do {
212 int old_lval, old_token;
213 old_token = ReadToken(symb->details.mac.body, yylvalpp);
214 old_lval = yylvalpp->sc_int;
215 token = ReadToken(mac.body, yylvalpp);
216 if (token != old_token || yylvalpp->sc_int != old_lval) {
217 error:
218 StoreStr("Macro Redefined");
219 StoreStr(GetStringOfAtom(atable,name));
220 message=GetStrfromTStr();
221 DecLineNumber();
222 CPPShInfoLogMsg(message);
223 IncLineNumber();
224 ResetTString();
225 break; }
226 } while (token > 0);
227 }
228 //FreeMacro(&symb->details.mac);
229 } else {
230 dummyLoc.file = 0;
231 dummyLoc.line = 0;
232 symb = AddSymbol(&dummyLoc, macros, name, MACRO_S);
233 }
234 symb->details.mac = mac;
235 return '\n';
236} // CPPdefine
237
238static int CPPundef(yystypepp * yylvalpp)
239{
240 int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
241 Symbol *symb;
242 if(token == '\n'){
243 CPPErrorToInfoLog("#undef");
244 return token;
245 }
246 if (token != CPP_IDENTIFIER)
247 goto error;
248 symb = LookUpSymbol(macros, yylvalpp->sc_ident);
249 if (symb) {
250 symb->details.mac.undef = 1;
251 }
252 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
253 if (token != '\n') {
254 error:
255 CPPErrorToInfoLog("#undef");
256 }
257 return token;
258} // CPPundef
259
260/* CPPelse -- skip forward to appropriate spot. This is actually used
261** to skip to and #endif after seeing an #else, AND to skip to a #else,
262** #elif, or #endif after a #if/#ifdef/#ifndef/#elif test was false
263*/
264
265static int CPPelse(int matchelse, yystypepp * yylvalpp)
266{
267 int atom,depth=0;
268 int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
269
270 while (token > 0) {
271 if (token != '#') {
272 while (token != '\n')
273 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
274
275 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
276 continue;
277 }
278 if ((token = cpp->currentInput->scan(cpp->currentInput, yylvalpp)) != CPP_IDENTIFIER)
279 continue;
280 atom = yylvalpp->sc_ident;
281 if (atom == ifAtom || atom == ifdefAtom || atom == ifndefAtom){
282 depth++; cpp->ifdepth++; cpp->elsetracker++;
daniel@transgaming.com9e78e5e2010-04-29 03:39:02 +0000283 cpp->elsedepth[cpp->elsetracker] = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000284 }
285 else if (atom == endifAtom) {
daniel@transgaming.com9e78e5e2010-04-29 03:39:02 +0000286 if(--depth<0){
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000287 --cpp->elsetracker;
288 if (cpp->ifdepth)
289 --cpp->ifdepth;
290 break;
291 }
292 --cpp->elsetracker;
293 --cpp->ifdepth;
294 }
295 else if (((int)(matchelse) != 0)&& depth==0) {
296 if (atom == elseAtom ) {
297 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
298 if (token != '\n') {
299 CPPWarningToInfoLog("unexpected tokens following #else preprocessor directive - expected a newline");
300 while (token != '\n')
301 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
302 }
303 break;
304 }
305 else if (atom == elifAtom) {
306 /* we decrement cpp->ifdepth here, because CPPif will increment
307 * it and we really want to leave it alone */
308 if (cpp->ifdepth){
309 --cpp->ifdepth;
310 --cpp->elsetracker;
311 }
312 return CPPif(yylvalpp);
313 }
314 }
315 else if((atom==elseAtom) && (!ChkCorrectElseNesting())){
316 CPPErrorToInfoLog("#else after a #else");
317 cpp->CompileError=1;
318 }
319 };
320 return token;
321}
322
323enum eval_prec {
324 MIN_PREC,
325 COND, LOGOR, LOGAND, OR, XOR, AND, EQUAL, RELATION, SHIFT, ADD, MUL, UNARY,
326 MAX_PREC
327};
328
329static int op_logor(int a, int b) { return a || b; }
330static int op_logand(int a, int b) { return a && b; }
331static int op_or(int a, int b) { return a | b; }
332static int op_xor(int a, int b) { return a ^ b; }
333static int op_and(int a, int b) { return a & b; }
334static int op_eq(int a, int b) { return a == b; }
335static int op_ne(int a, int b) { return a != b; }
336static int op_ge(int a, int b) { return a >= b; }
337static int op_le(int a, int b) { return a <= b; }
338static int op_gt(int a, int b) { return a > b; }
339static int op_lt(int a, int b) { return a < b; }
340static int op_shl(int a, int b) { return a << b; }
341static int op_shr(int a, int b) { return a >> b; }
342static int op_add(int a, int b) { return a + b; }
343static int op_sub(int a, int b) { return a - b; }
344static int op_mul(int a, int b) { return a * b; }
345static int op_div(int a, int b) { return a / b; }
346static int op_mod(int a, int b) { return a % b; }
347static int op_pos(int a) { return a; }
348static int op_neg(int a) { return -a; }
349static int op_cmpl(int a) { return ~a; }
350static int op_not(int a) { return !a; }
351
352struct {
353 int token, prec, (*op)(int, int);
354} binop[] = {
355 { CPP_OR_OP, LOGOR, op_logor },
356 { CPP_AND_OP, LOGAND, op_logand },
357 { '|', OR, op_or },
358 { '^', XOR, op_xor },
359 { '&', AND, op_and },
360 { CPP_EQ_OP, EQUAL, op_eq },
361 { CPP_NE_OP, EQUAL, op_ne },
362 { '>', RELATION, op_gt },
363 { CPP_GE_OP, RELATION, op_ge },
364 { '<', RELATION, op_lt },
365 { CPP_LE_OP, RELATION, op_le },
366 { CPP_LEFT_OP, SHIFT, op_shl },
367 { CPP_RIGHT_OP, SHIFT, op_shr },
368 { '+', ADD, op_add },
369 { '-', ADD, op_sub },
370 { '*', MUL, op_mul },
371 { '/', MUL, op_div },
372 { '%', MUL, op_mod },
373};
374
375struct {
376 int token, (*op)(int);
377} unop[] = {
378 { '+', op_pos },
379 { '-', op_neg },
380 { '~', op_cmpl },
381 { '!', op_not },
382};
383
384#define ALEN(A) (sizeof(A)/sizeof(A[0]))
385
386static int eval(int token, int prec, int *res, int *err, yystypepp * yylvalpp)
387{
388 int i, val;
389 Symbol *s;
390 if (token == CPP_IDENTIFIER) {
391 if (yylvalpp->sc_ident == definedAtom) {
392 int needclose = 0;
393 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
394 if (token == '(') {
395 needclose = 1;
396 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
397 }
398 if (token != CPP_IDENTIFIER)
399 goto error;
400 *res = (s = LookUpSymbol(macros, yylvalpp->sc_ident))
401 ? !s->details.mac.undef : 0;
402 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
403 if (needclose) {
404 if (token != ')')
405 goto error;
406 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
407 }
408 } else if (MacroExpand(yylvalpp->sc_ident, yylvalpp)) {
409 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
410 return eval(token, prec, res, err, yylvalpp);
411 } else {
412 goto error;
413 }
414 } else if (token == CPP_INTCONSTANT) {
415 *res = yylvalpp->sc_int;
416 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
417 } else if (token == '(') {
418 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
419 token = eval(token, MIN_PREC, res, err, yylvalpp);
420 if (!*err) {
421 if (token != ')')
422 goto error;
423 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
424 }
425 } else {
426 for (i = ALEN(unop) - 1; i >= 0; i--) {
427 if (unop[i].token == token)
428 break;
429 }
430 if (i >= 0) {
431 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
432 token = eval(token, UNARY, res, err, yylvalpp);
433 *res = unop[i].op(*res);
434 } else {
435 goto error;
436 }
437 }
438 while (!*err) {
439 if (token == ')' || token == '\n') break;
440 for (i = ALEN(binop) - 1; i >= 0; i--) {
441 if (binop[i].token == token)
442 break;
443 }
444 if (i < 0 || binop[i].prec <= prec)
445 break;
446 val = *res;
447 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
448 token = eval(token, binop[i].prec, res, err, yylvalpp);
449 *res = binop[i].op(val, *res);
450 }
451 return token;
452error:
453 CPPErrorToInfoLog("incorrect preprocessor directive");
454 *err = 1;
455 *res = 0;
456 return token;
457} // eval
458
459static int CPPif(yystypepp * yylvalpp) {
460 int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
461 int res = 0, err = 0;
462 cpp->elsetracker++;
daniel@transgaming.com9e78e5e2010-04-29 03:39:02 +0000463 cpp->elsedepth[cpp->elsetracker] = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000464 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++;
daniel@transgaming.com9e78e5e2010-04-29 03:39:02 +0000492 cpp->elsedepth[cpp->elsetracker] = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000493 if (token != CPP_IDENTIFIER) {
494 defined ? CPPErrorToInfoLog("ifdef"):CPPErrorToInfoLog("ifndef");
495 } else {
496 Symbol *s = LookUpSymbol(macros, name);
497 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
498 if (token != '\n') {
499 CPPWarningToInfoLog("unexpected tokens following #ifdef preprocessor directive - expected a newline");
500 while (token != '\n')
501 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
502 }
503 if (((s && !s->details.mac.undef) ? 1 : 0) != defined)
504 token = CPPelse(1, yylvalpp);
505 }
506 return token;
507} // CPPifdef
508
509static int CPPline(yystypepp * yylvalpp)
510{
511 int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
512 if(token=='\n'){
513 DecLineNumber();
514 CPPErrorToInfoLog("#line");
515 IncLineNumber();
516 return token;
517 }
518 else if (token == CPP_INTCONSTANT) {
519 yylvalpp->sc_int=atoi(yylvalpp->symbol_name);
520 SetLineNumber(yylvalpp->sc_int);
521 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
522
523 if (token == CPP_INTCONSTANT) {
524 yylvalpp->sc_int=atoi(yylvalpp->symbol_name);
525 SetStringNumber(yylvalpp->sc_int);
526 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
527 if(token!='\n')
528 CPPErrorToInfoLog("#line");
529 }
530 else if (token == '\n'){
531 return token;
532 }
533 else{
534 CPPErrorToInfoLog("#line");
535 }
536 }
537 else{
538 CPPErrorToInfoLog("#line");
539 }
540 return token;
541}
542
543static int CPPerror(yystypepp * yylvalpp) {
544
545 int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
546 const char *message;
547
548 while (token != '\n') {
549 if (token == CPP_FLOATCONSTANT || token == CPP_INTCONSTANT){
550 StoreStr(yylvalpp->symbol_name);
551 }else if(token == CPP_IDENTIFIER || token == CPP_STRCONSTANT){
552 StoreStr(GetStringOfAtom(atable,yylvalpp->sc_ident));
553 }else {
554 StoreStr(GetStringOfAtom(atable,token));
555 }
556 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
557 }
558 DecLineNumber();
559 //store this msg into the shader's information log..set the Compile Error flag!!!!
560 message=GetStrfromTStr();
561 CPPShInfoLogMsg(message);
562 ResetTString();
563 cpp->CompileError=1;
564 IncLineNumber();
565 return '\n';
566}//CPPerror
567
568static int CPPpragma(yystypepp * yylvalpp)
569{
570 char SrcStrName[2];
571 char** allTokens;
572 int tokenCount = 0;
573 int maxTokenCount = 10;
574 const char* SrcStr;
575 int i;
576
577 int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
578
579 if (token=='\n') {
580 DecLineNumber();
581 CPPErrorToInfoLog("#pragma");
582 IncLineNumber();
583 return token;
584 }
585
586 allTokens = (char**)malloc(sizeof(char*) * maxTokenCount);
587
588 while (token != '\n') {
589 if (tokenCount >= maxTokenCount) {
590 maxTokenCount *= 2;
591 allTokens = (char**)realloc((char**)allTokens, sizeof(char*) * maxTokenCount);
592 }
593 switch (token) {
594 case CPP_IDENTIFIER:
595 SrcStr = GetAtomString(atable, yylvalpp->sc_ident);
596 allTokens[tokenCount] = (char*)malloc(strlen(SrcStr) + 1);
597 strcpy(allTokens[tokenCount++], SrcStr);
598 break;
599 case CPP_INTCONSTANT:
600 SrcStr = yylvalpp->symbol_name;
601 allTokens[tokenCount] = (char*)malloc(strlen(SrcStr) + 1);
602 strcpy(allTokens[tokenCount++], SrcStr);
603 break;
604 case CPP_FLOATCONSTANT:
605 SrcStr = yylvalpp->symbol_name;
606 allTokens[tokenCount] = (char*)malloc(strlen(SrcStr) + 1);
607 strcpy(allTokens[tokenCount++], SrcStr);
608 break;
609 case -1:
610 // EOF
611 CPPShInfoLogMsg("#pragma directive must end with a newline");
612 return token;
613 default:
614 SrcStrName[0] = token;
615 SrcStrName[1] = '\0';
616 allTokens[tokenCount] = (char*)malloc(2);
617 strcpy(allTokens[tokenCount++], SrcStrName);
618 }
619 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
620 }
621
622 cpp->currentInput->ungetch(cpp->currentInput, token, yylvalpp);
623 HandlePragma((const char**)allTokens, tokenCount);
624 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
625
626 for (i = 0; i < tokenCount; ++i) {
627 free (allTokens[i]);
628 }
629 free (allTokens);
630
631 return token;
632} // CPPpragma
633
daniel@transgaming.com76039472010-04-15 20:45:18 +0000634#define ESSL_VERSION_NUMBER 100
635#define ESSL_VERSION_STRING "100"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000636
637static int CPPversion(yystypepp * yylvalpp)
638{
639
640 int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
641
daniel@transgaming.comdec19e22010-04-29 03:35:42 +0000642 if (cpp->pastFirstStatement == 1)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000643 CPPShInfoLogMsg("#version must occur before any other statement in the program");
644
645 if(token=='\n'){
646 DecLineNumber();
647 CPPErrorToInfoLog("#version");
648 IncLineNumber();
649 return token;
650 }
651 if (token != CPP_INTCONSTANT)
652 CPPErrorToInfoLog("#version");
653
654 yylvalpp->sc_int=atoi(yylvalpp->symbol_name);
655 //SetVersionNumber(yylvalpp->sc_int);
656
daniel@transgaming.com76039472010-04-15 20:45:18 +0000657 if (yylvalpp->sc_int != ESSL_VERSION_NUMBER)
658 CPPShInfoLogMsg("Version number not supported by ESSL");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000659
660 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
661
662 if (token == '\n'){
663 return token;
664 }
665 else{
666 CPPErrorToInfoLog("#version");
667 }
668 return token;
669} // CPPversion
670
671static int CPPextension(yystypepp * yylvalpp)
672{
673
674 int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
675 char extensionName[80];
676
677 if(token=='\n'){
678 DecLineNumber();
679 CPPShInfoLogMsg("extension name not specified");
680 IncLineNumber();
681 return token;
682 }
683
684 if (token != CPP_IDENTIFIER)
685 CPPErrorToInfoLog("#extension");
686
687 strcpy(extensionName, GetAtomString(atable, yylvalpp->sc_ident));
688
689 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
690 if (token != ':') {
691 CPPShInfoLogMsg("':' missing after extension name");
692 return token;
693 }
694
695 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
696 if (token != CPP_IDENTIFIER) {
697 CPPShInfoLogMsg("behavior for extension not specified");
698 return token;
699 }
700
701 updateExtensionBehavior(extensionName, GetAtomString(atable, yylvalpp->sc_ident));
702
703 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
704 if (token == '\n'){
705 return token;
706 }
707 else{
708 CPPErrorToInfoLog("#extension");
709 }
710 return token;
711} // CPPextension
712
713int readCPPline(yystypepp * yylvalpp)
714{
715 int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
716 const char *message;
717 int isVersion = 0;
718
719 if (token == CPP_IDENTIFIER) {
720 if (yylvalpp->sc_ident == defineAtom) {
721 token = CPPdefine(yylvalpp);
722 } else if (yylvalpp->sc_ident == elseAtom) {
723 if(ChkCorrectElseNesting()){
724 if (!cpp->ifdepth ){
725 CPPErrorToInfoLog("#else mismatch");
726 cpp->CompileError=1;
727 }
728 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
729 if (token != '\n') {
730 CPPWarningToInfoLog("unexpected tokens following #else preprocessor directive - expected a newline");
731 while (token != '\n')
732 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
733 }
734 token = CPPelse(0, yylvalpp);
735 }else{
736 CPPErrorToInfoLog("#else after a #else");
737 cpp->ifdepth=0;
daniel@transgaming.comdec19e22010-04-29 03:35:42 +0000738 cpp->pastFirstStatement = 1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000739 return 0;
740 }
741 } else if (yylvalpp->sc_ident == elifAtom) {
742 if (!cpp->ifdepth){
743 CPPErrorToInfoLog("#elif mismatch");
744 cpp->CompileError=1;
745 }
746 // this token is really a dont care, but we still need to eat the tokens
747 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
748 while (token != '\n')
749 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
750 token = CPPelse(0, yylvalpp);
751 } else if (yylvalpp->sc_ident == endifAtom) {
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000752 --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
daniel@transgaming.comdec19e22010-04-29 03:35:42 +0000790 cpp->pastFirstStatement = 1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000791
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 }
daniel@transgaming.com9bc5d232010-05-14 17:30:33 +0000905 if (atom == gl_esAtom) {
906 strcpy(yylvalpp->symbol_name,"1");
907 yylvalpp->sc_int = 1;
908 UngetToken(CPP_INTCONSTANT, yylvalpp);
909 return 1;
910 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000911 if (!sym || sym->details.mac.undef) return 0;
912 if (sym->details.mac.busy) return 0; // no recursive expansions
913 in = malloc(sizeof(*in));
914 memset(in, 0, sizeof(*in));
915 in->base.scan = (void *)macro_scan;
916 in->base.line = cpp->currentInput->line;
917 in->base.name = cpp->currentInput->name;
918 in->mac = &sym->details.mac;
919 if (sym->details.mac.args) {
920 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
921 if (token != '(') {
922 UngetToken(token, yylvalpp);
923 yylvalpp->sc_ident = atom;
924 return 0;
925 }
926 in->args = malloc(in->mac->argc * sizeof(TokenStream *));
927 for (i=0; i<in->mac->argc; i++)
928 in->args[i] = NewTokenStream("macro arg", 0);
929 i=0;j=0;
930 do{
931 depth = 0;
932 while(1) {
933 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
934 if (token <= 0) {
935 StoreStr("EOF in Macro ");
936 StoreStr(GetStringOfAtom(atable,atom));
937 message=GetStrfromTStr();
938 CPPShInfoLogMsg(message);
939 ResetTString();
940 return 1;
941 }
942 if((in->mac->argc==0) && (token!=')')) break;
943 if (depth == 0 && (token == ',' || token == ')')) break;
944 if (token == '(') depth++;
945 if (token == ')') depth--;
946 RecordToken(in->args[i], token, yylvalpp);
947 j=1;
948 }
949 if (token == ')') {
950 if((in->mac->argc==1) &&j==0)
951 break;
952 i++;
953 break;
954 }
955 i++;
956 }while(i < in->mac->argc);
957
958 if (i < in->mac->argc) {
959 StoreStr("Too few args in Macro ");
960 StoreStr(GetStringOfAtom(atable,atom));
961 message=GetStrfromTStr();
962 CPPShInfoLogMsg(message);
963 ResetTString();
964 } else if (token != ')') {
965 depth=0;
966 while (token >= 0 && (depth > 0 || token != ')')) {
967 if (token == ')') depth--;
968 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
969 if (token == '(') depth++;
970 }
971
972 if (token <= 0) {
973 StoreStr("EOF in Macro ");
974 StoreStr(GetStringOfAtom(atable,atom));
975 message=GetStrfromTStr();
976 CPPShInfoLogMsg(message);
977 ResetTString();
978 return 1;
979 }
980 StoreStr("Too many args in Macro ");
981 StoreStr(GetStringOfAtom(atable,atom));
982 message=GetStrfromTStr();
983 CPPShInfoLogMsg(message);
984 ResetTString();
985 }
986 for (i=0; i<in->mac->argc; i++) {
987 in->args[i] = PrescanMacroArg(in->args[i], yylvalpp);
988 }
989 }
990#if 0
991 printf(" <%s:%d>found macro %s\n", GetAtomString(atable, loc.file),
992 loc.line, GetAtomString(atable, atom));
993 for (i=0; i<in->mac->argc; i++) {
994 printf("\targ %s = '", GetAtomString(atable, in->mac->args[i]));
995 DumpTokenStream(stdout, in->args[i]);
996 printf("'\n");
997 }
998#endif
999 /*retain the input source*/
1000 in->base.prev = cpp->currentInput;
1001 sym->details.mac.busy = 1;
1002 RewindTokenStream(sym->details.mac.body);
1003 cpp->currentInput = &in->base;
1004 return 1;
1005} // MacroExpand
1006
1007int ChkCorrectElseNesting(void)
1008{
1009 if(cpp->elsedepth[cpp->elsetracker]==0){
1010 cpp->elsedepth[cpp->elsetracker]=1;
1011 return 1;
1012 }
1013 return 0;
1014}
1015
1016