blob: 588660de91c70d90c63f3dcc283db73321ed3201 [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;
daniel@transgaming.comd8e93722010-05-14 17:31:09 +0000101
102 SourceLoc location = {0};
103 Symbol *symbol;
104 MacroSymbol macro = {0};
105 yystypepp one = {0};
106
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000107 // Add various atoms needed by the CPP line scanner:
108 bindAtom = LookUpAddString(atable, "bind");
109 constAtom = LookUpAddString(atable, "const");
110 defaultAtom = LookUpAddString(atable, "default");
111 defineAtom = LookUpAddString(atable, "define");
112 definedAtom = LookUpAddString(atable, "defined");
113 elifAtom = LookUpAddString(atable, "elif");
114 elseAtom = LookUpAddString(atable, "else");
115 endifAtom = LookUpAddString(atable, "endif");
116 ifAtom = LookUpAddString(atable, "if");
117 ifdefAtom = LookUpAddString(atable, "ifdef");
118 ifndefAtom = LookUpAddString(atable, "ifndef");
119 includeAtom = LookUpAddString(atable, "include");
120 lineAtom = LookUpAddString(atable, "line");
121 pragmaAtom = LookUpAddString(atable, "pragma");
122 texunitAtom = LookUpAddString(atable, "texunit");
123 undefAtom = LookUpAddString(atable, "undef");
124 errorAtom = LookUpAddString(atable, "error");
125 __LINE__Atom = LookUpAddString(atable, "__LINE__");
126 __FILE__Atom = LookUpAddString(atable, "__FILE__");
127 __VERSION__Atom = LookUpAddString(atable, "__VERSION__");
daniel@transgaming.com9bc5d232010-05-14 17:30:33 +0000128 gl_esAtom = LookUpAddString(atable, "GL_ES");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000129 versionAtom = LookUpAddString(atable, "version");
130 extensionAtom = LookUpAddString(atable, "extension");
131 macros = NewScopeInPool(mem_CreatePool(0, 0));
132 strcpy(buffer, "PROFILE_");
133 t = buffer + strlen(buffer);
134 f = cpp->options.profileString;
135 while ((isalnum(*f) || *f == '_') && t < buffer + sizeof(buffer) - 1)
136 *t++ = toupper(*f++);
137 *t = 0;
daniel@transgaming.comd8e93722010-05-14 17:31:09 +0000138
139 // #define GL_ES 1
140 macro.body = NewTokenStream("GL_ES", macros->pool);
141 one.sc_int = 1;
142 strcpy(one.symbol_name, "1");
143 RecordToken(macro.body, CPP_INTCONSTANT, &one);
144 symbol = AddSymbol(&location, macros, gl_esAtom, MACRO_S);
145 symbol->details.mac = macro;
146
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000147 return 1;
148} // InitCPP
149
150int FreeCPP(void)
151{
152 if (macros)
153 {
154 mem_FreePool(macros->pool);
155 macros = 0;
156 }
157
158 return 1;
159}
160
161int FinalCPP(void)
162{
163 if (cpp->ifdepth)
164 CPPErrorToInfoLog("#if mismatch");
165 return 1;
166}
167
168static int CPPdefine(yystypepp * yylvalpp)
169{
170 int token, name, args[MAX_MACRO_ARGS], argc;
171 const char *message;
172 MacroSymbol mac;
173 Symbol *symb;
174 SourceLoc dummyLoc;
175 memset(&mac, 0, sizeof(mac));
176 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
177 if (token != CPP_IDENTIFIER) {
178 CPPErrorToInfoLog("#define");
179 return token;
180 }
181 name = yylvalpp->sc_ident;
182 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
183 if (token == '(' && !yylvalpp->sc_int) {
184 // gather arguments
185 argc = 0;
186 do {
187 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
188 if (argc == 0 && token == ')') break;
189 if (token != CPP_IDENTIFIER) {
190 CPPErrorToInfoLog("#define");
191 return token;
192 }
193 if (argc < MAX_MACRO_ARGS)
194 args[argc++] = yylvalpp->sc_ident;
195 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
196 } while (token == ',');
197 if (token != ')') {
198 CPPErrorToInfoLog("#define");
199 return token;
200 }
201 mac.argc = argc;
202 mac.args = mem_Alloc(macros->pool, argc * sizeof(int));
203 memcpy(mac.args, args, argc * sizeof(int));
204 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
205 }
206 mac.body = NewTokenStream(GetAtomString(atable, name), macros->pool);
207 while (token != '\n') {
daniel@transgaming.comedff8dc2010-05-14 17:30:27 +0000208 if (token == '\\') {
209 CPPErrorToInfoLog("The line continuation character (\\) is not part of the OpenGL ES Shading Language");
210 return token;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000211 }
212 RecordToken(mac.body, token, yylvalpp);
213 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
214 };
215
216 symb = LookUpSymbol(macros, name);
217 if (symb) {
218 if (!symb->details.mac.undef) {
219 // already defined -- need to make sure they are identical
220 if (symb->details.mac.argc != mac.argc) goto error;
221 for (argc=0; argc < mac.argc; argc++)
222 if (symb->details.mac.args[argc] != mac.args[argc])
223 goto error;
224 RewindTokenStream(symb->details.mac.body);
225 RewindTokenStream(mac.body);
226 do {
227 int old_lval, old_token;
228 old_token = ReadToken(symb->details.mac.body, yylvalpp);
229 old_lval = yylvalpp->sc_int;
230 token = ReadToken(mac.body, yylvalpp);
231 if (token != old_token || yylvalpp->sc_int != old_lval) {
232 error:
233 StoreStr("Macro Redefined");
234 StoreStr(GetStringOfAtom(atable,name));
235 message=GetStrfromTStr();
236 DecLineNumber();
237 CPPShInfoLogMsg(message);
238 IncLineNumber();
239 ResetTString();
240 break; }
241 } while (token > 0);
242 }
243 //FreeMacro(&symb->details.mac);
244 } else {
245 dummyLoc.file = 0;
246 dummyLoc.line = 0;
247 symb = AddSymbol(&dummyLoc, macros, name, MACRO_S);
248 }
249 symb->details.mac = mac;
250 return '\n';
251} // CPPdefine
252
253static int CPPundef(yystypepp * yylvalpp)
254{
255 int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
256 Symbol *symb;
257 if(token == '\n'){
258 CPPErrorToInfoLog("#undef");
259 return token;
260 }
261 if (token != CPP_IDENTIFIER)
262 goto error;
263 symb = LookUpSymbol(macros, yylvalpp->sc_ident);
264 if (symb) {
265 symb->details.mac.undef = 1;
266 }
267 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
268 if (token != '\n') {
269 error:
270 CPPErrorToInfoLog("#undef");
271 }
272 return token;
273} // CPPundef
274
275/* CPPelse -- skip forward to appropriate spot. This is actually used
276** to skip to and #endif after seeing an #else, AND to skip to a #else,
277** #elif, or #endif after a #if/#ifdef/#ifndef/#elif test was false
278*/
279
280static int CPPelse(int matchelse, yystypepp * yylvalpp)
281{
282 int atom,depth=0;
283 int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
284
285 while (token > 0) {
286 if (token != '#') {
287 while (token != '\n')
288 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
289
290 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
291 continue;
292 }
293 if ((token = cpp->currentInput->scan(cpp->currentInput, yylvalpp)) != CPP_IDENTIFIER)
294 continue;
295 atom = yylvalpp->sc_ident;
296 if (atom == ifAtom || atom == ifdefAtom || atom == ifndefAtom){
297 depth++; cpp->ifdepth++; cpp->elsetracker++;
daniel@transgaming.com9e78e5e2010-04-29 03:39:02 +0000298 cpp->elsedepth[cpp->elsetracker] = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000299 }
300 else if (atom == endifAtom) {
daniel@transgaming.com9e78e5e2010-04-29 03:39:02 +0000301 if(--depth<0){
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000302 --cpp->elsetracker;
303 if (cpp->ifdepth)
304 --cpp->ifdepth;
305 break;
306 }
307 --cpp->elsetracker;
308 --cpp->ifdepth;
309 }
310 else if (((int)(matchelse) != 0)&& depth==0) {
311 if (atom == elseAtom ) {
312 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
313 if (token != '\n') {
314 CPPWarningToInfoLog("unexpected tokens following #else preprocessor directive - expected a newline");
315 while (token != '\n')
316 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
317 }
318 break;
319 }
320 else if (atom == elifAtom) {
321 /* we decrement cpp->ifdepth here, because CPPif will increment
322 * it and we really want to leave it alone */
323 if (cpp->ifdepth){
324 --cpp->ifdepth;
325 --cpp->elsetracker;
326 }
327 return CPPif(yylvalpp);
328 }
329 }
330 else if((atom==elseAtom) && (!ChkCorrectElseNesting())){
331 CPPErrorToInfoLog("#else after a #else");
332 cpp->CompileError=1;
333 }
334 };
335 return token;
336}
337
338enum eval_prec {
339 MIN_PREC,
340 COND, LOGOR, LOGAND, OR, XOR, AND, EQUAL, RELATION, SHIFT, ADD, MUL, UNARY,
341 MAX_PREC
342};
343
344static int op_logor(int a, int b) { return a || b; }
345static int op_logand(int a, int b) { return a && b; }
346static int op_or(int a, int b) { return a | b; }
347static int op_xor(int a, int b) { return a ^ b; }
348static int op_and(int a, int b) { return a & b; }
349static int op_eq(int a, int b) { return a == b; }
350static int op_ne(int a, int b) { return a != b; }
351static int op_ge(int a, int b) { return a >= b; }
352static int op_le(int a, int b) { return a <= b; }
353static int op_gt(int a, int b) { return a > b; }
354static int op_lt(int a, int b) { return a < b; }
355static int op_shl(int a, int b) { return a << b; }
356static int op_shr(int a, int b) { return a >> b; }
357static int op_add(int a, int b) { return a + b; }
358static int op_sub(int a, int b) { return a - b; }
359static int op_mul(int a, int b) { return a * b; }
360static int op_div(int a, int b) { return a / b; }
361static int op_mod(int a, int b) { return a % b; }
362static int op_pos(int a) { return a; }
363static int op_neg(int a) { return -a; }
364static int op_cmpl(int a) { return ~a; }
365static int op_not(int a) { return !a; }
366
367struct {
368 int token, prec, (*op)(int, int);
369} binop[] = {
370 { CPP_OR_OP, LOGOR, op_logor },
371 { CPP_AND_OP, LOGAND, op_logand },
372 { '|', OR, op_or },
373 { '^', XOR, op_xor },
374 { '&', AND, op_and },
375 { CPP_EQ_OP, EQUAL, op_eq },
376 { CPP_NE_OP, EQUAL, op_ne },
377 { '>', RELATION, op_gt },
378 { CPP_GE_OP, RELATION, op_ge },
379 { '<', RELATION, op_lt },
380 { CPP_LE_OP, RELATION, op_le },
381 { CPP_LEFT_OP, SHIFT, op_shl },
382 { CPP_RIGHT_OP, SHIFT, op_shr },
383 { '+', ADD, op_add },
384 { '-', ADD, op_sub },
385 { '*', MUL, op_mul },
386 { '/', MUL, op_div },
387 { '%', MUL, op_mod },
388};
389
390struct {
391 int token, (*op)(int);
392} unop[] = {
393 { '+', op_pos },
394 { '-', op_neg },
395 { '~', op_cmpl },
396 { '!', op_not },
397};
398
399#define ALEN(A) (sizeof(A)/sizeof(A[0]))
400
401static int eval(int token, int prec, int *res, int *err, yystypepp * yylvalpp)
402{
403 int i, val;
404 Symbol *s;
405 if (token == CPP_IDENTIFIER) {
406 if (yylvalpp->sc_ident == definedAtom) {
407 int needclose = 0;
408 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
409 if (token == '(') {
410 needclose = 1;
411 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
412 }
413 if (token != CPP_IDENTIFIER)
414 goto error;
415 *res = (s = LookUpSymbol(macros, yylvalpp->sc_ident))
416 ? !s->details.mac.undef : 0;
417 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
418 if (needclose) {
419 if (token != ')')
420 goto error;
421 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
422 }
423 } else if (MacroExpand(yylvalpp->sc_ident, yylvalpp)) {
424 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
425 return eval(token, prec, res, err, yylvalpp);
426 } else {
427 goto error;
428 }
429 } else if (token == CPP_INTCONSTANT) {
430 *res = yylvalpp->sc_int;
431 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
432 } else if (token == '(') {
433 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
434 token = eval(token, MIN_PREC, res, err, yylvalpp);
435 if (!*err) {
436 if (token != ')')
437 goto error;
438 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
439 }
440 } else {
441 for (i = ALEN(unop) - 1; i >= 0; i--) {
442 if (unop[i].token == token)
443 break;
444 }
445 if (i >= 0) {
446 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
447 token = eval(token, UNARY, res, err, yylvalpp);
448 *res = unop[i].op(*res);
449 } else {
450 goto error;
451 }
452 }
453 while (!*err) {
454 if (token == ')' || token == '\n') break;
455 for (i = ALEN(binop) - 1; i >= 0; i--) {
456 if (binop[i].token == token)
457 break;
458 }
459 if (i < 0 || binop[i].prec <= prec)
460 break;
461 val = *res;
462 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
463 token = eval(token, binop[i].prec, res, err, yylvalpp);
464 *res = binop[i].op(val, *res);
465 }
466 return token;
467error:
468 CPPErrorToInfoLog("incorrect preprocessor directive");
469 *err = 1;
470 *res = 0;
471 return token;
472} // eval
473
474static int CPPif(yystypepp * yylvalpp) {
475 int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
476 int res = 0, err = 0;
477 cpp->elsetracker++;
daniel@transgaming.com9e78e5e2010-04-29 03:39:02 +0000478 cpp->elsedepth[cpp->elsetracker] = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000479 if (!cpp->ifdepth++)
480 ifloc = *cpp->tokenLoc;
481 if(cpp->ifdepth >MAX_IF_NESTING){
482 CPPErrorToInfoLog("max #if nesting depth exceeded");
483 return 0;
484 }
485 token = eval(token, MIN_PREC, &res, &err, yylvalpp);
486 if (token != '\n') {
487 CPPWarningToInfoLog("unexpected tokens following the preprocessor directive - expected a newline");
488 while (token != '\n')
489 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
490 }
491 if (!res && !err) {
492 token = CPPelse(1, yylvalpp);
493 }
494
495 return token;
496} // CPPif
497
498static int CPPifdef(int defined, yystypepp * yylvalpp)
499{
500 int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
501 int name = yylvalpp->sc_ident;
502 if(++cpp->ifdepth >MAX_IF_NESTING){
503 CPPErrorToInfoLog("max #if nesting depth exceeded");
504 return 0;
505 }
506 cpp->elsetracker++;
daniel@transgaming.com9e78e5e2010-04-29 03:39:02 +0000507 cpp->elsedepth[cpp->elsetracker] = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000508 if (token != CPP_IDENTIFIER) {
509 defined ? CPPErrorToInfoLog("ifdef"):CPPErrorToInfoLog("ifndef");
510 } else {
511 Symbol *s = LookUpSymbol(macros, name);
512 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
513 if (token != '\n') {
514 CPPWarningToInfoLog("unexpected tokens following #ifdef preprocessor directive - expected a newline");
515 while (token != '\n')
516 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
517 }
518 if (((s && !s->details.mac.undef) ? 1 : 0) != defined)
519 token = CPPelse(1, yylvalpp);
520 }
521 return token;
522} // CPPifdef
523
524static int CPPline(yystypepp * yylvalpp)
525{
526 int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
527 if(token=='\n'){
528 DecLineNumber();
529 CPPErrorToInfoLog("#line");
530 IncLineNumber();
531 return token;
532 }
533 else if (token == CPP_INTCONSTANT) {
534 yylvalpp->sc_int=atoi(yylvalpp->symbol_name);
535 SetLineNumber(yylvalpp->sc_int);
536 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
537
538 if (token == CPP_INTCONSTANT) {
539 yylvalpp->sc_int=atoi(yylvalpp->symbol_name);
540 SetStringNumber(yylvalpp->sc_int);
541 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
542 if(token!='\n')
543 CPPErrorToInfoLog("#line");
544 }
545 else if (token == '\n'){
546 return token;
547 }
548 else{
549 CPPErrorToInfoLog("#line");
550 }
551 }
552 else{
553 CPPErrorToInfoLog("#line");
554 }
555 return token;
556}
557
558static int CPPerror(yystypepp * yylvalpp) {
559
560 int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
561 const char *message;
562
563 while (token != '\n') {
564 if (token == CPP_FLOATCONSTANT || token == CPP_INTCONSTANT){
565 StoreStr(yylvalpp->symbol_name);
566 }else if(token == CPP_IDENTIFIER || token == CPP_STRCONSTANT){
567 StoreStr(GetStringOfAtom(atable,yylvalpp->sc_ident));
568 }else {
569 StoreStr(GetStringOfAtom(atable,token));
570 }
571 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
572 }
573 DecLineNumber();
574 //store this msg into the shader's information log..set the Compile Error flag!!!!
575 message=GetStrfromTStr();
576 CPPShInfoLogMsg(message);
577 ResetTString();
578 cpp->CompileError=1;
579 IncLineNumber();
580 return '\n';
581}//CPPerror
582
583static int CPPpragma(yystypepp * yylvalpp)
584{
585 char SrcStrName[2];
586 char** allTokens;
587 int tokenCount = 0;
588 int maxTokenCount = 10;
589 const char* SrcStr;
590 int i;
591
592 int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
593
594 if (token=='\n') {
595 DecLineNumber();
596 CPPErrorToInfoLog("#pragma");
597 IncLineNumber();
598 return token;
599 }
600
601 allTokens = (char**)malloc(sizeof(char*) * maxTokenCount);
602
603 while (token != '\n') {
604 if (tokenCount >= maxTokenCount) {
605 maxTokenCount *= 2;
606 allTokens = (char**)realloc((char**)allTokens, sizeof(char*) * maxTokenCount);
607 }
608 switch (token) {
609 case CPP_IDENTIFIER:
610 SrcStr = GetAtomString(atable, yylvalpp->sc_ident);
611 allTokens[tokenCount] = (char*)malloc(strlen(SrcStr) + 1);
612 strcpy(allTokens[tokenCount++], SrcStr);
613 break;
614 case CPP_INTCONSTANT:
615 SrcStr = yylvalpp->symbol_name;
616 allTokens[tokenCount] = (char*)malloc(strlen(SrcStr) + 1);
617 strcpy(allTokens[tokenCount++], SrcStr);
618 break;
619 case CPP_FLOATCONSTANT:
620 SrcStr = yylvalpp->symbol_name;
621 allTokens[tokenCount] = (char*)malloc(strlen(SrcStr) + 1);
622 strcpy(allTokens[tokenCount++], SrcStr);
623 break;
624 case -1:
625 // EOF
626 CPPShInfoLogMsg("#pragma directive must end with a newline");
627 return token;
628 default:
629 SrcStrName[0] = token;
630 SrcStrName[1] = '\0';
631 allTokens[tokenCount] = (char*)malloc(2);
632 strcpy(allTokens[tokenCount++], SrcStrName);
633 }
634 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
635 }
636
637 cpp->currentInput->ungetch(cpp->currentInput, token, yylvalpp);
638 HandlePragma((const char**)allTokens, tokenCount);
639 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
640
641 for (i = 0; i < tokenCount; ++i) {
642 free (allTokens[i]);
643 }
644 free (allTokens);
645
646 return token;
647} // CPPpragma
648
daniel@transgaming.com76039472010-04-15 20:45:18 +0000649#define ESSL_VERSION_NUMBER 100
650#define ESSL_VERSION_STRING "100"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000651
652static int CPPversion(yystypepp * yylvalpp)
653{
654
655 int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
656
daniel@transgaming.comdec19e22010-04-29 03:35:42 +0000657 if (cpp->pastFirstStatement == 1)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000658 CPPShInfoLogMsg("#version must occur before any other statement in the program");
659
660 if(token=='\n'){
661 DecLineNumber();
662 CPPErrorToInfoLog("#version");
663 IncLineNumber();
664 return token;
665 }
666 if (token != CPP_INTCONSTANT)
667 CPPErrorToInfoLog("#version");
668
669 yylvalpp->sc_int=atoi(yylvalpp->symbol_name);
670 //SetVersionNumber(yylvalpp->sc_int);
671
daniel@transgaming.com76039472010-04-15 20:45:18 +0000672 if (yylvalpp->sc_int != ESSL_VERSION_NUMBER)
673 CPPShInfoLogMsg("Version number not supported by ESSL");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000674
675 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
676
677 if (token == '\n'){
678 return token;
679 }
680 else{
681 CPPErrorToInfoLog("#version");
682 }
683 return token;
684} // CPPversion
685
686static int CPPextension(yystypepp * yylvalpp)
687{
688
689 int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
690 char extensionName[80];
691
692 if(token=='\n'){
693 DecLineNumber();
694 CPPShInfoLogMsg("extension name not specified");
695 IncLineNumber();
696 return token;
697 }
698
699 if (token != CPP_IDENTIFIER)
700 CPPErrorToInfoLog("#extension");
701
702 strcpy(extensionName, GetAtomString(atable, yylvalpp->sc_ident));
703
704 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
705 if (token != ':') {
706 CPPShInfoLogMsg("':' missing after extension name");
707 return token;
708 }
709
710 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
711 if (token != CPP_IDENTIFIER) {
712 CPPShInfoLogMsg("behavior for extension not specified");
713 return token;
714 }
715
716 updateExtensionBehavior(extensionName, GetAtomString(atable, yylvalpp->sc_ident));
717
718 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
719 if (token == '\n'){
720 return token;
721 }
722 else{
723 CPPErrorToInfoLog("#extension");
724 }
725 return token;
726} // CPPextension
727
728int readCPPline(yystypepp * yylvalpp)
729{
730 int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
731 const char *message;
732 int isVersion = 0;
733
734 if (token == CPP_IDENTIFIER) {
735 if (yylvalpp->sc_ident == defineAtom) {
736 token = CPPdefine(yylvalpp);
737 } else if (yylvalpp->sc_ident == elseAtom) {
738 if(ChkCorrectElseNesting()){
739 if (!cpp->ifdepth ){
740 CPPErrorToInfoLog("#else mismatch");
741 cpp->CompileError=1;
742 }
743 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
744 if (token != '\n') {
745 CPPWarningToInfoLog("unexpected tokens following #else preprocessor directive - expected a newline");
746 while (token != '\n')
747 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
748 }
749 token = CPPelse(0, yylvalpp);
750 }else{
751 CPPErrorToInfoLog("#else after a #else");
752 cpp->ifdepth=0;
daniel@transgaming.comdec19e22010-04-29 03:35:42 +0000753 cpp->pastFirstStatement = 1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000754 return 0;
755 }
756 } else if (yylvalpp->sc_ident == elifAtom) {
757 if (!cpp->ifdepth){
758 CPPErrorToInfoLog("#elif mismatch");
759 cpp->CompileError=1;
760 }
761 // this token is really a dont care, but we still need to eat the tokens
762 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
763 while (token != '\n')
764 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
765 token = CPPelse(0, yylvalpp);
766 } else if (yylvalpp->sc_ident == endifAtom) {
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000767 --cpp->elsetracker;
768 if (!cpp->ifdepth){
769 CPPErrorToInfoLog("#endif mismatch");
770 cpp->CompileError=1;
771 }
772 else
773 --cpp->ifdepth;
774 } else if (yylvalpp->sc_ident == ifAtom) {
775 token = CPPif(yylvalpp);
776 } else if (yylvalpp->sc_ident == ifdefAtom) {
777 token = CPPifdef(1, yylvalpp);
778 } else if (yylvalpp->sc_ident == ifndefAtom) {
779 token = CPPifdef(0, yylvalpp);
780 } else if (yylvalpp->sc_ident == lineAtom) {
781 token = CPPline(yylvalpp);
782 } else if (yylvalpp->sc_ident == pragmaAtom) {
783 token = CPPpragma(yylvalpp);
784 } else if (yylvalpp->sc_ident == undefAtom) {
785 token = CPPundef(yylvalpp);
786 } else if (yylvalpp->sc_ident == errorAtom) {
787 token = CPPerror(yylvalpp);
788 } else if (yylvalpp->sc_ident == versionAtom) {
789 token = CPPversion(yylvalpp);
790 isVersion = 1;
791 } else if (yylvalpp->sc_ident == extensionAtom) {
792 token = CPPextension(yylvalpp);
793 } else {
794 StoreStr("Invalid Directive");
795 StoreStr(GetStringOfAtom(atable,yylvalpp->sc_ident));
796 message=GetStrfromTStr();
797 CPPShInfoLogMsg(message);
798 ResetTString();
799 }
800 }
801 while (token != '\n' && token != 0 && token != EOF) {
802 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
803 }
804
daniel@transgaming.comdec19e22010-04-29 03:35:42 +0000805 cpp->pastFirstStatement = 1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000806
807 return token;
808} // readCPPline
809
810void FreeMacro(MacroSymbol *s) {
811 DeleteTokenStream(s->body);
812}
813
814static int eof_scan(InputSrc *in, yystypepp * yylvalpp) { return -1; }
815static void noop(InputSrc *in, int ch, yystypepp * yylvalpp) { }
816
817static void PushEofSrc() {
818 InputSrc *in = malloc(sizeof(InputSrc));
819 memset(in, 0, sizeof(InputSrc));
820 in->scan = eof_scan;
821 in->getch = eof_scan;
822 in->ungetch = noop;
823 in->prev = cpp->currentInput;
824 cpp->currentInput = in;
825}
826
827static void PopEofSrc() {
828 if (cpp->currentInput->scan == eof_scan) {
829 InputSrc *in = cpp->currentInput;
830 cpp->currentInput = in->prev;
831 free(in);
832 }
833}
834
835static TokenStream *PrescanMacroArg(TokenStream *a, yystypepp * yylvalpp) {
836 int token;
837 TokenStream *n;
838 RewindTokenStream(a);
839 do {
840 token = ReadToken(a, yylvalpp);
841 if (token == CPP_IDENTIFIER && LookUpSymbol(macros, yylvalpp->sc_ident))
842 break;
843 } while (token > 0);
844 if (token <= 0) return a;
845 n = NewTokenStream("macro arg", 0);
846 PushEofSrc();
847 ReadFromTokenStream(a, 0, 0);
848 while ((token = cpp->currentInput->scan(cpp->currentInput, yylvalpp)) > 0) {
849 if (token == CPP_IDENTIFIER && MacroExpand(yylvalpp->sc_ident, yylvalpp))
850 continue;
851 RecordToken(n, token, yylvalpp);
852 }
853 PopEofSrc();
854 DeleteTokenStream(a);
855 return n;
856} // PrescanMacroArg
857
858typedef struct MacroInputSrc {
859 InputSrc base;
860 MacroSymbol *mac;
861 TokenStream **args;
862} MacroInputSrc;
863
864/* macro_scan ---
865** return the next token for a macro expanion, handling macro args
866*/
867static int macro_scan(MacroInputSrc *in, yystypepp * yylvalpp) {
868 int i;
869 int token = ReadToken(in->mac->body, yylvalpp);
870 if (token == CPP_IDENTIFIER) {
871 for (i = in->mac->argc-1; i>=0; i--)
872 if (in->mac->args[i] == yylvalpp->sc_ident) break;
873 if (i >= 0) {
874 ReadFromTokenStream(in->args[i], yylvalpp->sc_ident, 0);
875 return cpp->currentInput->scan(cpp->currentInput, yylvalpp);
876 }
877 }
878 if (token > 0) return token;
879 in->mac->busy = 0;
880 cpp->currentInput = in->base.prev;
881 if (in->args) {
882 for (i=in->mac->argc-1; i>=0; i--)
883 DeleteTokenStream(in->args[i]);
884 free(in->args);
885 }
886 free(in);
887 return cpp->currentInput->scan(cpp->currentInput, yylvalpp);
888} // macro_scan
889
890/* MacroExpand
891** check an identifier (atom) to see if it a macro that should be expanded.
892** If it is, push an InputSrc that will produce the appropriate expansion
893** and return TRUE. If not, return FALSE.
894*/
895
896int MacroExpand(int atom, yystypepp * yylvalpp)
897{
898 Symbol *sym = LookUpSymbol(macros, atom);
899 MacroInputSrc *in;
900 int i,j, token, depth=0;
901 const char *message;
902 if (atom == __LINE__Atom) {
903 yylvalpp->sc_int = GetLineNumber();
904 sprintf(yylvalpp->symbol_name,"%d",yylvalpp->sc_int);
905 UngetToken(CPP_INTCONSTANT, yylvalpp);
906 return 1;
907 }
908 if (atom == __FILE__Atom) {
909 yylvalpp->sc_int = GetStringNumber();
910 sprintf(yylvalpp->symbol_name,"%d",yylvalpp->sc_int);
911 UngetToken(CPP_INTCONSTANT, yylvalpp);
912 return 1;
913 }
914 if (atom == __VERSION__Atom) {
daniel@transgaming.com76039472010-04-15 20:45:18 +0000915 strcpy(yylvalpp->symbol_name,ESSL_VERSION_STRING);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000916 yylvalpp->sc_int = atoi(yylvalpp->symbol_name);
917 UngetToken(CPP_INTCONSTANT, yylvalpp);
918 return 1;
919 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000920 if (!sym || sym->details.mac.undef) return 0;
921 if (sym->details.mac.busy) return 0; // no recursive expansions
922 in = malloc(sizeof(*in));
923 memset(in, 0, sizeof(*in));
924 in->base.scan = (void *)macro_scan;
925 in->base.line = cpp->currentInput->line;
926 in->base.name = cpp->currentInput->name;
927 in->mac = &sym->details.mac;
928 if (sym->details.mac.args) {
929 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
930 if (token != '(') {
931 UngetToken(token, yylvalpp);
932 yylvalpp->sc_ident = atom;
933 return 0;
934 }
935 in->args = malloc(in->mac->argc * sizeof(TokenStream *));
936 for (i=0; i<in->mac->argc; i++)
937 in->args[i] = NewTokenStream("macro arg", 0);
938 i=0;j=0;
939 do{
940 depth = 0;
941 while(1) {
942 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
943 if (token <= 0) {
944 StoreStr("EOF in Macro ");
945 StoreStr(GetStringOfAtom(atable,atom));
946 message=GetStrfromTStr();
947 CPPShInfoLogMsg(message);
948 ResetTString();
949 return 1;
950 }
951 if((in->mac->argc==0) && (token!=')')) break;
952 if (depth == 0 && (token == ',' || token == ')')) break;
953 if (token == '(') depth++;
954 if (token == ')') depth--;
955 RecordToken(in->args[i], token, yylvalpp);
956 j=1;
957 }
958 if (token == ')') {
959 if((in->mac->argc==1) &&j==0)
960 break;
961 i++;
962 break;
963 }
964 i++;
965 }while(i < in->mac->argc);
966
967 if (i < in->mac->argc) {
968 StoreStr("Too few args in Macro ");
969 StoreStr(GetStringOfAtom(atable,atom));
970 message=GetStrfromTStr();
971 CPPShInfoLogMsg(message);
972 ResetTString();
973 } else if (token != ')') {
974 depth=0;
975 while (token >= 0 && (depth > 0 || token != ')')) {
976 if (token == ')') depth--;
977 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
978 if (token == '(') depth++;
979 }
980
981 if (token <= 0) {
982 StoreStr("EOF in Macro ");
983 StoreStr(GetStringOfAtom(atable,atom));
984 message=GetStrfromTStr();
985 CPPShInfoLogMsg(message);
986 ResetTString();
987 return 1;
988 }
989 StoreStr("Too many args in Macro ");
990 StoreStr(GetStringOfAtom(atable,atom));
991 message=GetStrfromTStr();
992 CPPShInfoLogMsg(message);
993 ResetTString();
994 }
995 for (i=0; i<in->mac->argc; i++) {
996 in->args[i] = PrescanMacroArg(in->args[i], yylvalpp);
997 }
998 }
999#if 0
1000 printf(" <%s:%d>found macro %s\n", GetAtomString(atable, loc.file),
1001 loc.line, GetAtomString(atable, atom));
1002 for (i=0; i<in->mac->argc; i++) {
1003 printf("\targ %s = '", GetAtomString(atable, in->mac->args[i]));
1004 DumpTokenStream(stdout, in->args[i]);
1005 printf("'\n");
1006 }
1007#endif
1008 /*retain the input source*/
1009 in->base.prev = cpp->currentInput;
1010 sym->details.mac.busy = 1;
1011 RewindTokenStream(sym->details.mac.body);
1012 cpp->currentInput = &in->base;
1013 return 1;
1014} // MacroExpand
1015
1016int ChkCorrectElseNesting(void)
1017{
1018 if(cpp->elsedepth[cpp->elsetracker]==0){
1019 cpp->elsedepth[cpp->elsetracker]=1;
1020 return 1;
1021 }
1022 return 0;
1023}
1024
1025