ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

slang_preprocess.c
Go to the documentation of this file.
00001 /*
00002  * Mesa 3-D graphics library
00003  *
00004  * Copyright (C) 2005-2008  Brian Paul   All Rights Reserved.
00005  * Copyright (C) 2009 VMware, Inc.   All Rights Reserved.
00006  *
00007  * Permission is hereby granted, free of charge, to any person obtaining a
00008  * copy of this software and associated documentation files (the "Software"),
00009  * to deal in the Software without restriction, including without limitation
00010  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
00011  * and/or sell copies of the Software, and to permit persons to whom the
00012  * Software is furnished to do so, subject to the following conditions:
00013  *
00014  * The above copyright notice and this permission notice shall be included
00015  * in all copies or substantial portions of the Software.
00016  *
00017  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00018  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00019  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
00020  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
00021  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00022  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00023  */
00024 
00031 #include "main/imports.h"
00032 #include "shader/grammar/grammar_mesa.h"
00033 #include "slang_preprocess.h"
00034 
00035 LONGSTRING static const char *slang_pp_directives_syn =
00036 #include "library/slang_pp_directives_syn.h"
00037 ;
00038 
00039 LONGSTRING static const char *slang_pp_expression_syn =
00040 #include "library/slang_pp_expression_syn.h"
00041 ;
00042 
00043 LONGSTRING static const char *slang_pp_version_syn =
00044 #include "library/slang_pp_version_syn.h"
00045 ;
00046 
00047 static GLvoid
00048 grammar_error_to_log (slang_info_log *log)
00049 {
00050    char buf[1024];
00051    GLint pos;
00052 
00053    grammar_get_last_error ((byte *) (buf), sizeof (buf), &pos);
00054    if (buf[0] == 0) {
00055       _mesa_snprintf(buf, sizeof(buf), "Preprocessor error");
00056    }
00057    slang_info_log_error (log, buf);
00058 }
00059 
00060 GLboolean
00061 _slang_preprocess_version (const char *text, GLuint *version, GLuint *eaten, slang_info_log *log)
00062 {
00063    grammar id;
00064    byte *prod, *I;
00065    unsigned int size;
00066 
00067    id = grammar_load_from_text ((const byte *) (slang_pp_version_syn));
00068    if (id == 0) {
00069       grammar_error_to_log (log);
00070       return GL_FALSE;
00071    }
00072 
00073    if (!grammar_fast_check (id, (const byte *) (text), &prod, &size, 8)) {
00074       grammar_error_to_log (log);
00075       grammar_destroy (id);
00076       return GL_FALSE;
00077    }
00078 
00079    /* there can be multiple #version directives - grab the last one */
00080    I = &prod[size - 6];
00081    *version = (GLuint) (I[0]) + (GLuint) (I[1]) * 100;
00082    *eaten = (GLuint) (I[2]) + ((GLuint) (I[3]) << 8) + ((GLuint) (I[4]) << 16) + ((GLuint) (I[5]) << 24);
00083 
00084    grammar_destroy (id);
00085    grammar_alloc_free (prod);
00086    return GL_TRUE;
00087 }
00088 
00089 /*
00090  * The preprocessor does the following work.
00091  * 1. Remove comments. Each comment block is replaced with a single space and if the
00092  *    block contains new-lines, they are preserved. This ensures that line numbers
00093  *    stay the same and if a comment block delimits two tokens, the are delitmited
00094  *    by the space after comment removal.
00095  * 2. Remove preprocessor directives from the source string, checking their syntax and
00096  *    executing them if appropriate. Again, new-lines are preserved.
00097  * 3. Expand macros.
00098  * 4. Tokenize the source string by ensuring there is at least one space between every
00099  *    two adjacent tokens.
00100  */
00101 
00102 #define PP_ANNOTATE 0
00103 
00104 static GLvoid
00105 pp_annotate (slang_string *output, const char *fmt, ...)
00106 {
00107 #if PP_ANNOTATE
00108    va_list va;
00109    char buffer[1024];
00110 
00111    va_start (va, fmt);
00112    _mesa_vsprintf (buffer, fmt, va);
00113    va_end (va);
00114    slang_string_pushs (output, buffer, _mesa_strlen (buffer));
00115 #else
00116    (GLvoid) (output);
00117    (GLvoid) (fmt);
00118 #endif
00119 }
00120 
00121  /*
00122  * The expression is executed on a fixed-sized stack. The PUSH macro makes a runtime
00123  * check if the stack is not overflown by too complex expressions. In that situation the
00124  * GLSL preprocessor should report internal compiler error.
00125  * The BINARYDIV makes a runtime check if the divider is not 0. If it is, it reports
00126  * compilation error.
00127  */
00128 
00129 #define EXECUTION_STACK_SIZE 1024
00130 
00131 #define PUSH(x)\
00132    do {\
00133       if (sp == 0) {\
00134          slang_info_log_error (elog, "internal compiler error: preprocessor execution stack overflow.");\
00135          return GL_FALSE;\
00136       }\
00137       stack[--sp] = x;\
00138    } while (GL_FALSE)
00139 
00140 #define POP(x)\
00141    do {\
00142       assert (sp < EXECUTION_STACK_SIZE);\
00143       x = stack[sp++];\
00144    } while (GL_FALSE)
00145 
00146 #define BINARY(op)\
00147    do {\
00148       GLint a, b;\
00149       POP(b);\
00150       POP(a);\
00151       PUSH(a op b);\
00152    } while (GL_FALSE)
00153 
00154 #define BINARYDIV(op)\
00155    do {\
00156       GLint a, b;\
00157       POP(b);\
00158       POP(a);\
00159       if (b == 0) {\
00160          slang_info_log_error (elog, "division by zero in preprocessor expression.");\
00161          return GL_FALSE;\
00162       }\
00163       PUSH(a op b);\
00164    } while (GL_FALSE)
00165 
00166 #define UNARY(op)\
00167    do {\
00168       GLint a;\
00169       POP(a);\
00170       PUSH(op a);\
00171    } while (GL_FALSE)
00172 
00173 #define OP_END          0
00174 #define OP_PUSHINT      1
00175 #define OP_LOGICALOR    2
00176 #define OP_LOGICALAND   3
00177 #define OP_OR           4
00178 #define OP_XOR          5
00179 #define OP_AND          6
00180 #define OP_EQUAL        7
00181 #define OP_NOTEQUAL     8
00182 #define OP_LESSEQUAL    9
00183 #define OP_GREATEREQUAL 10
00184 #define OP_LESS         11
00185 #define OP_GREATER      12
00186 #define OP_LEFTSHIFT    13
00187 #define OP_RIGHTSHIFT   14
00188 #define OP_ADD          15
00189 #define OP_SUBTRACT     16
00190 #define OP_MULTIPLY     17
00191 #define OP_DIVIDE       18
00192 #define OP_MODULUS      19
00193 #define OP_PLUS         20
00194 #define OP_MINUS        21
00195 #define OP_NEGATE       22
00196 #define OP_COMPLEMENT   23
00197 
00198 static GLboolean
00199 execute_expression (slang_string *output, const byte *code, GLuint *pi, GLint *result,
00200                     slang_info_log *elog)
00201 {
00202    GLuint i = *pi;
00203    GLint stack[EXECUTION_STACK_SIZE];
00204    GLuint sp = EXECUTION_STACK_SIZE;
00205 
00206    while (code[i] != OP_END) {
00207       switch (code[i++]) {
00208          case OP_PUSHINT:
00209             i++;
00210             PUSH(_mesa_atoi ((const char *) (&code[i])));
00211             i += _mesa_strlen ((const char *) (&code[i])) + 1;
00212             break;
00213          case OP_LOGICALOR:
00214             BINARY(||);
00215             break;
00216          case OP_LOGICALAND:
00217             BINARY(&&);
00218             break;
00219          case OP_OR:
00220             BINARY(|);
00221             break;
00222          case OP_XOR:
00223             BINARY(^);
00224             break;
00225          case OP_AND:
00226             BINARY(&);
00227             break;
00228          case OP_EQUAL:
00229             BINARY(==);
00230             break;
00231          case OP_NOTEQUAL:
00232             BINARY(!=);
00233             break;
00234          case OP_LESSEQUAL:
00235             BINARY(<=);
00236             break;
00237          case OP_GREATEREQUAL:
00238             BINARY(>=);
00239             break;
00240          case OP_LESS:
00241             BINARY(<);
00242             break;
00243          case OP_GREATER:
00244             BINARY(>);
00245             break;
00246          case OP_LEFTSHIFT:
00247             BINARY(<<);
00248             break;
00249          case OP_RIGHTSHIFT:
00250             BINARY(>>);
00251             break;
00252          case OP_ADD:
00253             BINARY(+);
00254             break;
00255          case OP_SUBTRACT:
00256             BINARY(-);
00257             break;
00258          case OP_MULTIPLY:
00259             BINARY(*);
00260             break;
00261          case OP_DIVIDE:
00262             BINARYDIV(/);
00263             break;
00264          case OP_MODULUS:
00265             BINARYDIV(%);
00266             break;
00267          case OP_PLUS:
00268             UNARY(+);
00269             break;
00270          case OP_MINUS:
00271             UNARY(-);
00272             break;
00273          case OP_NEGATE:
00274             UNARY(!);
00275             break;
00276          case OP_COMPLEMENT:
00277             UNARY(~);
00278             break;
00279          default:
00280             assert (0);
00281       }
00282    }
00283 
00284    /* Write-back the index skipping the OP_END. */
00285    *pi = i + 1;
00286 
00287    /* There should be exactly one value left on the stack. This is our result. */
00288    POP(*result);
00289    pp_annotate (output, "%d ", *result);
00290    assert (sp == EXECUTION_STACK_SIZE);
00291    return GL_TRUE;
00292 }
00293 
00294 /*
00295  * Function execute_expressions() executes up to 2 expressions. The second expression is there
00296  * for the #line directive which takes 1 or 2 expressions that indicate line and file numbers.
00297  * If it fails, it returns 0. If it succeeds, it returns the number of executed expressions.
00298  */
00299 
00300 #define EXP_END        0
00301 #define EXP_EXPRESSION 1
00302 
00303 static GLuint
00304 execute_expressions (slang_string *output, grammar eid, const byte *expr, GLint results[2],
00305                      slang_info_log *elog)
00306 {
00307    GLint success;
00308    byte *code;
00309    GLuint size, count = 0;
00310 
00311    success = grammar_fast_check (eid, expr, &code, &size, 64);
00312    if (success) {
00313       GLuint i = 0;
00314 
00315       while (code[i++] == EXP_EXPRESSION) {
00316          assert (count < 2);
00317 
00318          if (!execute_expression (output, code, &i, &results[count], elog)) {
00319             count = 0;
00320             break;
00321          }
00322          count++;
00323       }
00324       grammar_alloc_free (code);
00325    }
00326    else {
00327       slang_info_log_error (elog, "syntax error in preprocessor expression.");\
00328    }
00329    return count;
00330 }
00331 
00332 /*
00333  * The pp_symbol structure is used to hold macro definitions and macro formal parameters. The
00334  * pp_symbols strcture is a collection of pp_symbol. It is used both for storing macro formal
00335  * parameters and all global macro definitions. Making this unification wastes some memory,
00336  * becuse macro formal parameters don't need further lists of symbols. We lose 8 bytes per
00337  * formal parameter here, but making this we can use the same code to substitute macro parameters
00338  * as well as macros in the source string.
00339  */
00340 
00341 typedef struct
00342 {
00343    struct pp_symbol_ *symbols;
00344    GLuint count;
00345 } pp_symbols;
00346 
00347 static GLvoid
00348 pp_symbols_init (pp_symbols *self)
00349 {
00350    self->symbols = NULL;
00351    self->count = 0;
00352 }
00353 
00354 static GLvoid
00355 pp_symbols_free (pp_symbols *);
00356 
00357 typedef struct pp_symbol_
00358 {
00359    slang_string name;
00360    slang_string replacement;
00361    pp_symbols parameters;
00362 } pp_symbol;
00363 
00364 static GLvoid
00365 pp_symbol_init (pp_symbol *self)
00366 {
00367    slang_string_init (&self->name);
00368    slang_string_init (&self->replacement);
00369    pp_symbols_init (&self->parameters);
00370 }
00371 
00372 static GLvoid
00373 pp_symbol_free (pp_symbol *self)
00374 {
00375    slang_string_free (&self->name);
00376    slang_string_free (&self->replacement);
00377    pp_symbols_free (&self->parameters);
00378 }
00379 
00380 static GLvoid
00381 pp_symbol_reset (pp_symbol *self)
00382 {
00383    /* Leave symbol name intact. */
00384    slang_string_reset (&self->replacement);
00385    pp_symbols_free (&self->parameters);
00386    pp_symbols_init (&self->parameters);
00387 }
00388 
00389 static GLvoid
00390 pp_symbols_free (pp_symbols *self)
00391 {
00392    GLuint i;
00393 
00394    for (i = 0; i < self->count; i++)
00395       pp_symbol_free (&self->symbols[i]);
00396    _mesa_free (self->symbols);
00397 }
00398 
00399 static pp_symbol *
00400 pp_symbols_push (pp_symbols *self)
00401 {
00402    self->symbols = (pp_symbol *) (_mesa_realloc (self->symbols, self->count * sizeof (pp_symbol),
00403                                                  (self->count + 1) * sizeof (pp_symbol)));
00404    if (self->symbols == NULL)
00405       return NULL;
00406    pp_symbol_init (&self->symbols[self->count]);
00407    return &self->symbols[self->count++];
00408 }
00409 
00410 static GLboolean
00411 pp_symbols_erase (pp_symbols *self, pp_symbol *symbol)
00412 {
00413    assert (symbol >= self->symbols && symbol < self->symbols + self->count);
00414 
00415    self->count--;
00416    pp_symbol_free (symbol);
00417    if (symbol < self->symbols + self->count)
00418       _mesa_memcpy (symbol, symbol + 1, sizeof (pp_symbol) * (self->symbols + self->count - symbol));
00419    self->symbols = (pp_symbol *) (_mesa_realloc (self->symbols, (self->count + 1) * sizeof (pp_symbol),
00420                                                  self->count * sizeof (pp_symbol)));
00421    return self->symbols != NULL;
00422 }
00423 
00424 static pp_symbol *
00425 pp_symbols_find (pp_symbols *self, const char *name)
00426 {
00427    GLuint i;
00428 
00429    for (i = 0; i < self->count; i++)
00430       if (_mesa_strcmp (name, slang_string_cstr (&self->symbols[i].name)) == 0)
00431          return &self->symbols[i];
00432    return NULL;
00433 }
00434 
00435 /*
00436  * The condition context of a single #if/#else/#endif level. Those can be nested, so there
00437  * is a stack of condition contexts.
00438  * There is a special global context on the bottom of the stack. It is there to simplify
00439  * context handling.
00440  */
00441 
00442 typedef struct
00443 {
00444    GLboolean current;         /* The condition value of this level. */
00445    GLboolean effective;       /* The effective product of current condition, outer level conditions
00446                                * and position within #if-#else-#endif sections. */
00447    GLboolean else_allowed;    /* TRUE if in #if-#else section, FALSE if in #else-#endif section
00448                                * and for global context. */
00449    GLboolean endif_required;  /* FALSE for global context only. */
00450 } pp_cond_ctx;
00451 
00452 /* Should be enuff. */
00453 #define CONDITION_STACK_SIZE 64
00454 
00455 typedef struct
00456 {
00457    pp_cond_ctx stack[CONDITION_STACK_SIZE];
00458    pp_cond_ctx *top;
00459 } pp_cond_stack;
00460 
00461 static GLboolean
00462 pp_cond_stack_push (pp_cond_stack *self, slang_info_log *elog)
00463 {
00464    if (self->top == self->stack) {
00465       slang_info_log_error (elog, "internal compiler error: preprocessor condition stack overflow.");
00466       return GL_FALSE;
00467    }
00468    self->top--;
00469    return GL_TRUE;
00470 }
00471 
00472 static GLvoid
00473 pp_cond_stack_reevaluate (pp_cond_stack *self)
00474 {
00475    /* There must be at least 2 conditions on the stack - one global and one being evaluated. */
00476    assert (self->top <= &self->stack[CONDITION_STACK_SIZE - 2]);
00477 
00478    self->top->effective = self->top->current && self->top[1].effective;
00479 }
00480 
00481 
00486 typedef struct
00487 {
00488    GLboolean ARB_draw_buffers;
00489    GLboolean ARB_texture_rectangle;
00490 } pp_ext;
00491 
00492 
00496 static GLvoid
00497 pp_ext_disable_all(pp_ext *self)
00498 {
00499    _mesa_memset(self, 0, sizeof(self));
00500 }
00501 
00502 
00507 static GLvoid
00508 pp_ext_init(pp_ext *self, const struct gl_extensions *extensions)
00509 {
00510    pp_ext_disable_all (self);
00511    if (extensions->ARB_draw_buffers)
00512       self->ARB_draw_buffers = GL_TRUE;
00513    if (extensions->NV_texture_rectangle)
00514       self->ARB_texture_rectangle = GL_TRUE;
00515 }
00516 
00521 static GLboolean
00522 pp_ext_set(pp_ext *self, const char *name, GLboolean enable)
00523 {
00524    if (_mesa_strcmp (name, "GL_ARB_draw_buffers") == 0)
00525       self->ARB_draw_buffers = enable;
00526    else if (_mesa_strcmp (name, "GL_ARB_texture_rectangle") == 0)
00527       self->ARB_texture_rectangle = enable;
00528    else
00529       return GL_FALSE;
00530    return GL_TRUE;
00531 }
00532 
00533 
00534 static void
00535 pp_pragmas_init(struct gl_sl_pragmas *pragmas)
00536 {
00537    pragmas->Optimize = GL_TRUE;
00538    pragmas->Debug = GL_FALSE;
00539 }
00540 
00541 
00547 static GLboolean
00548 pp_pragma(struct gl_sl_pragmas *pragmas, const char *pragma, const char *param)
00549 {
00550 #if 0
00551    printf("#pragma %s %s\n", pragma, param);
00552 #endif
00553    if (_mesa_strcmp(pragma, "optimize") == 0) {
00554       if (!param)
00555          return GL_FALSE; /* missing required param */
00556       if (_mesa_strcmp(param, "on") == 0) {
00557          pragmas->Optimize = GL_TRUE;
00558       }
00559       else if (_mesa_strcmp(param, "off") == 0) {
00560          pragmas->Optimize = GL_FALSE;
00561       }
00562       else {
00563          return GL_FALSE; /* invalid param */
00564       }
00565    }
00566    else if (_mesa_strcmp(pragma, "debug") == 0) {
00567       if (!param)
00568          return GL_FALSE; /* missing required param */
00569       if (_mesa_strcmp(param, "on") == 0) {
00570          pragmas->Debug = GL_TRUE;
00571       }
00572       else if (_mesa_strcmp(param, "off") == 0) {
00573          pragmas->Debug = GL_FALSE;
00574       }
00575       else {
00576          return GL_FALSE; /* invalid param */
00577       }
00578    }
00579    /* all other pragmas are silently ignored */
00580    return GL_TRUE;
00581 }
00582 
00583 
00588 typedef struct
00589 {
00590    GLint line;
00591    GLint file;
00592    GLint version;
00593    pp_symbols symbols;
00594    pp_ext ext;
00595    slang_info_log *elog;
00596    pp_cond_stack cond;
00597 } pp_state;
00598 
00599 static GLvoid
00600 pp_state_init (pp_state *self, slang_info_log *elog,
00601                const struct gl_extensions *extensions)
00602 {
00603    self->line = 0;
00604    self->file = 1;
00605 #if FEATURE_es2_glsl
00606    self->version = 100;
00607 #else
00608    self->version = 110;
00609 #endif
00610    pp_symbols_init (&self->symbols);
00611    pp_ext_init (&self->ext, extensions);
00612    self->elog = elog;
00613 
00614    /* Initialize condition stack and create the global context. */
00615    self->cond.top = &self->cond.stack[CONDITION_STACK_SIZE - 1];
00616    self->cond.top->current = GL_TRUE;
00617    self->cond.top->effective = GL_TRUE;
00618    self->cond.top->else_allowed = GL_FALSE;
00619    self->cond.top->endif_required = GL_FALSE;
00620 }
00621 
00622 static GLvoid
00623 pp_state_free (pp_state *self)
00624 {
00625    pp_symbols_free (&self->symbols);
00626 }
00627 
00628 #define IS_FIRST_ID_CHAR(x) (((x) >= 'a' && (x) <= 'z') || ((x) >= 'A' && (x) <= 'Z') || (x) == '_')
00629 #define IS_NEXT_ID_CHAR(x) (IS_FIRST_ID_CHAR(x) || ((x) >= '0' && (x) <= '9'))
00630 #define IS_WHITE(x) ((x) == ' ' || (x) == '\n')
00631 #define IS_NULL(x) ((x) == '\0')
00632 
00633 #define SKIP_WHITE(x) do { while (IS_WHITE(*(x))) (x)++; } while (GL_FALSE)
00634 
00635 typedef struct
00636 {
00637    slang_string *output;
00638    const char *input;
00639    pp_state *state;
00640 } expand_state;
00641 
00642 static GLboolean
00643 expand_defined (expand_state *e, slang_string *buffer)
00644 {
00645    GLboolean in_paren = GL_FALSE;
00646    const char *id;
00647 
00648    /* Parse the optional opening parenthesis. */
00649    SKIP_WHITE(e->input);
00650    if (*e->input == '(') {
00651       e->input++;
00652       in_paren = GL_TRUE;
00653       SKIP_WHITE(e->input);
00654    }
00655 
00656    /* Parse operand. */
00657    if (!IS_FIRST_ID_CHAR(*e->input)) {
00658       slang_info_log_error (e->state->elog,
00659                             "preprocess error: identifier expected after operator 'defined'.");
00660       return GL_FALSE;
00661    }
00662    slang_string_reset (buffer);
00663    slang_string_pushc (buffer, *e->input++);
00664    while (IS_NEXT_ID_CHAR(*e->input))
00665       slang_string_pushc (buffer, *e->input++);
00666    id = slang_string_cstr (buffer);
00667 
00668    /* Check if the operand is defined. Output 1 if it is defined, output 0 if not. */
00669    if (pp_symbols_find (&e->state->symbols, id) == NULL)
00670       slang_string_pushs (e->output, " 0 ", 3);
00671    else
00672       slang_string_pushs (e->output, " 1 ", 3);
00673 
00674    /* Parse the closing parentehesis if the opening one was there. */
00675    if (in_paren) {
00676       SKIP_WHITE(e->input);
00677       if (*e->input != ')') {
00678          slang_info_log_error (e->state->elog, "preprocess error: ')' expected.");
00679          return GL_FALSE;
00680       }
00681       e->input++;
00682       SKIP_WHITE(e->input);
00683    }
00684    return GL_TRUE;
00685 }
00686 
00687 static GLboolean
00688 expand (expand_state *, pp_symbols *);
00689 
00690 static GLboolean
00691 expand_symbol (expand_state *e, pp_symbol *symbol)
00692 {
00693    expand_state es;
00694 
00695    /* If the macro has some parameters, we need to parse them. */
00696    if (symbol->parameters.count != 0) {
00697       GLuint i;
00698 
00699       /* Parse the opening parenthesis. */
00700       SKIP_WHITE(e->input);
00701       if (*e->input != '(') {
00702          slang_info_log_error (e->state->elog, "preprocess error: '(' expected.");
00703          return GL_FALSE;
00704       }
00705       e->input++;
00706       SKIP_WHITE(e->input);
00707 
00708       /* Parse macro actual parameters. This can be anything, separated by a colon.
00709        */
00710       for (i = 0; i < symbol->parameters.count; i++) {
00711          GLuint nested_paren_count = 0; /* track number of nested parentheses */
00712 
00713          if (*e->input == ')') {
00714             slang_info_log_error (e->state->elog, "preprocess error: unexpected ')'.");
00715             return GL_FALSE;
00716          }
00717 
00718          /* Eat all characters up to the comma or closing parentheses. */
00719          pp_symbol_reset (&symbol->parameters.symbols[i]);
00720          while (!IS_NULL(*e->input)) {
00721             /* Exit loop only when all nested parens have been eaten. */
00722             if (nested_paren_count == 0 && (*e->input == ',' || *e->input == ')'))
00723                break;
00724 
00725             /* Actually count nested parens here. */
00726             if (*e->input == '(')
00727                nested_paren_count++;
00728             else if (*e->input == ')')
00729                nested_paren_count--;
00730 
00731             slang_string_pushc (&symbol->parameters.symbols[i].replacement, *e->input++);
00732          }
00733 
00734          /* If it was not the last paremeter, skip the comma. Otherwise, skip the
00735           * closing parentheses. */
00736          if (i + 1 == symbol->parameters.count) {
00737             /* This is the last paremeter - skip the closing parentheses. */
00738             if (*e->input != ')') {
00739                slang_info_log_error (e->state->elog, "preprocess error: ')' expected.");
00740                return GL_FALSE;
00741             }
00742             e->input++;
00743             SKIP_WHITE(e->input);
00744          }
00745          else {
00746             /* Skip the separating comma. */
00747             if (*e->input != ',') {
00748                slang_info_log_error (e->state->elog, "preprocess error: ',' expected.");
00749                return GL_FALSE;
00750             }
00751             e->input++;
00752             SKIP_WHITE(e->input);
00753          }
00754       }
00755    }
00756 
00757    /* Expand the macro. Use its parameters as a priority symbol list to expand
00758     * macro parameters correctly. */
00759    es.output = e->output;
00760    es.input = slang_string_cstr (&symbol->replacement);
00761    es.state = e->state;
00762    slang_string_pushc (e->output, ' ');
00763    if (!expand (&es, &symbol->parameters))
00764       return GL_FALSE;
00765    slang_string_pushc (e->output, ' ');
00766    return GL_TRUE;
00767 }
00768 
00769 /*
00770  * Function expand() expands source text from <input> to <output>. The expansion is made using
00771  * the list passed in <symbols> parameter. It allows us to expand macro formal parameters with
00772  * actual parameters. The global list of symbols from pp state is used when doing a recursive
00773  * call of expand().
00774  */
00775 
00776 static GLboolean
00777 expand (expand_state *e, pp_symbols *symbols)
00778 {
00779    while (!IS_NULL(*e->input)) {
00780       if (IS_FIRST_ID_CHAR(*e->input)) {
00781          slang_string buffer;
00782          const char *id;
00783 
00784          /* Parse the identifier. */
00785          slang_string_init (&buffer);
00786          slang_string_pushc (&buffer, *e->input++);
00787          while (IS_NEXT_ID_CHAR(*e->input))
00788             slang_string_pushc (&buffer, *e->input++);
00789          id = slang_string_cstr (&buffer);
00790 
00791          /* Now check if the identifier is special in some way. The "defined" identifier is
00792           * actually an operator that we must handle here and expand it either to " 0 " or " 1 ".
00793           * The other identifiers start with "__" and we expand it to appropriate values
00794           * taken from the preprocessor state. */
00795          if (_mesa_strcmp (id, "defined") == 0) {
00796             if (!expand_defined (e, &buffer))
00797                return GL_FALSE;
00798          }
00799          else if (_mesa_strcmp (id, "__LINE__") == 0) {
00800             slang_string_pushc (e->output, ' ');
00801             slang_string_pushi (e->output, e->state->line);
00802             slang_string_pushc (e->output, ' ');
00803          }
00804          else if (_mesa_strcmp (id, "__FILE__") == 0) {
00805             slang_string_pushc (e->output, ' ');
00806             slang_string_pushi (e->output, e->state->file);
00807             slang_string_pushc (e->output, ' ');
00808          }
00809          else if (_mesa_strcmp (id, "__VERSION__") == 0) {
00810             slang_string_pushc (e->output, ' ');
00811             slang_string_pushi (e->output, e->state->version);
00812             slang_string_pushc (e->output, ' ');
00813          }
00814 #if FEATURE_es2_glsl
00815          else if (_mesa_strcmp (id, "GL_ES") == 0 ||
00816                   _mesa_strcmp (id, "GL_FRAGMENT_PRECISION_HIGH") == 0) {
00817             slang_string_pushc (e->output, ' ');
00818             slang_string_pushi (e->output, '1');
00819             slang_string_pushc (e->output, ' ');
00820          }
00821 #endif
00822          else {
00823             pp_symbol *symbol;
00824 
00825             /* The list of symbols from <symbols> take precedence over the list from <state>.
00826              * Note that in some cases this is the same list so avoid double look-up. */
00827             symbol = pp_symbols_find (symbols, id);
00828             if (symbol == NULL && symbols != &e->state->symbols)
00829                symbol = pp_symbols_find (&e->state->symbols, id);
00830 
00831             /* If the symbol was found, recursively expand its definition. */
00832             if (symbol != NULL) {
00833                if (!expand_symbol (e, symbol)) {
00834                   slang_string_free (&buffer);
00835                   return GL_FALSE;
00836                }
00837             }
00838             else {
00839                slang_string_push (e->output, &buffer);
00840             }
00841          }
00842          slang_string_free (&buffer);
00843       }
00844       else if (IS_WHITE(*e->input)) {
00845          slang_string_pushc (e->output, *e->input++);
00846       }
00847       else {
00848          while (!IS_WHITE(*e->input) && !IS_NULL(*e->input) && !IS_FIRST_ID_CHAR(*e->input))
00849             slang_string_pushc (e->output, *e->input++);
00850       }
00851    }
00852    return GL_TRUE;
00853 }
00854 
00855 static GLboolean
00856 parse_if (slang_string *output, const byte *prod, GLuint *pi, GLint *result, pp_state *state,
00857           grammar eid)
00858 {
00859    const char *text;
00860    GLuint len;
00861 
00862    text = (const char *) (&prod[*pi]);
00863    len = _mesa_strlen (text);
00864 
00865    if (state->cond.top->effective) {
00866       slang_string expr;
00867       GLuint count;
00868       GLint results[2];
00869       expand_state es;
00870 
00871       /* Expand the expression. */
00872       slang_string_init (&expr);
00873       es.output = &expr;
00874       es.input = text;
00875       es.state = state;
00876       if (!expand (&es, &state->symbols))
00877          return GL_FALSE;
00878 
00879       /* Execute the expression. */
00880       count = execute_expressions (output, eid, (const byte *) (slang_string_cstr (&expr)),
00881                                    results, state->elog);
00882       slang_string_free (&expr);
00883       if (count != 1)
00884          return GL_FALSE;
00885       *result = results[0];
00886    }
00887    else {
00888       /* The directive is dead. */
00889       *result = 0;
00890    }
00891 
00892    *pi += len + 1;
00893    return GL_TRUE;
00894 }
00895 
00896 #define ESCAPE_TOKEN 0
00897 
00898 #define TOKEN_END       0
00899 #define TOKEN_DEFINE    1
00900 #define TOKEN_UNDEF     2
00901 #define TOKEN_IF        3
00902 #define TOKEN_ELSE      4
00903 #define TOKEN_ELIF      5
00904 #define TOKEN_ENDIF     6
00905 #define TOKEN_ERROR     7
00906 #define TOKEN_PRAGMA    8
00907 #define TOKEN_EXTENSION 9
00908 #define TOKEN_LINE      10
00909 
00910 #define PARAM_END       0
00911 #define PARAM_PARAMETER 1
00912 
00913 #define BEHAVIOR_REQUIRE 1
00914 #define BEHAVIOR_ENABLE  2
00915 #define BEHAVIOR_WARN    3
00916 #define BEHAVIOR_DISABLE 4
00917 
00918 #define PRAGMA_NO_PARAM  0
00919 #define PRAGMA_PARAM     1
00920 
00921 
00922 static GLboolean
00923 preprocess_source (slang_string *output, const char *source,
00924                    grammar pid, grammar eid,
00925                    slang_info_log *elog,
00926                    const struct gl_extensions *extensions,
00927                    struct gl_sl_pragmas *pragmas)
00928 {
00929    static const char *predefined[] = {
00930       "__FILE__",
00931       "__LINE__",
00932       "__VERSION__",
00933 #if FEATURE_es2_glsl
00934       "GL_ES",
00935       "GL_FRAGMENT_PRECISION_HIGH",
00936 #endif
00937       NULL
00938    };
00939    byte *prod;
00940    GLuint size, i;
00941    pp_state state;
00942 
00943    if (!grammar_fast_check (pid, (const byte *) (source), &prod, &size, 65536)) {
00944       grammar_error_to_log (elog);
00945       return GL_FALSE;
00946    }
00947 
00948    pp_state_init (&state, elog, extensions);
00949    pp_pragmas_init (pragmas);
00950 
00951    /* add the predefined symbols to the symbol table */
00952    for (i = 0; predefined[i]; i++) {
00953       pp_symbol *symbol = NULL;
00954       symbol = pp_symbols_push(&state.symbols);
00955       assert(symbol);
00956       slang_string_pushs(&symbol->name,
00957                          predefined[i], _mesa_strlen(predefined[i]));
00958    }
00959 
00960    i = 0;
00961    while (i < size) {
00962       if (prod[i] != ESCAPE_TOKEN) {
00963          if (state.cond.top->effective) {
00964             slang_string input;
00965             expand_state es;
00966 
00967             /* Eat only one line of source code to expand it.
00968              * FIXME: This approach has one drawback. If a macro with parameters spans across
00969              *        multiple lines, the preprocessor will raise an error. */
00970             slang_string_init (&input);
00971             while (prod[i] != '\0' && prod[i] != '\n')
00972                slang_string_pushc (&input, prod[i++]);
00973             if (prod[i] != '\0')
00974                slang_string_pushc (&input, prod[i++]);
00975 
00976             /* Increment line number. */
00977             state.line++;
00978 
00979             es.output = output;
00980             es.input = slang_string_cstr (&input);
00981             es.state = &state;
00982             if (!expand (&es, &state.symbols))
00983                goto error;
00984 
00985             slang_string_free (&input);
00986          }
00987          else {
00988             /* Condition stack is disabled - keep track on line numbers and output only newlines. */
00989             if (prod[i] == '\n') {
00990                state.line++;
00991                /*pp_annotate (output, "%c", prod[i]);*/
00992             }
00993             else {
00994                /*pp_annotate (output, "%c", prod[i]);*/
00995             }
00996             i++;
00997          }
00998       }
00999       else {
01000          const char *id;
01001          GLuint idlen;
01002          GLubyte token;
01003 
01004          i++;
01005          token = prod[i++];
01006          switch (token) {
01007 
01008          case TOKEN_END:
01009             /* End of source string.
01010                * Check if all #ifs have been terminated by matching #endifs.
01011                * On condition stack there should be only the global condition context. */
01012             if (state.cond.top->endif_required) {
01013                slang_info_log_error (elog, "end of source without matching #endif.");
01014                return GL_FALSE;
01015             }
01016             break;
01017 
01018          case TOKEN_DEFINE:
01019             {
01020                pp_symbol *symbol = NULL;
01021 
01022                /* Parse macro name. */
01023                id = (const char *) (&prod[i]);
01024                idlen = _mesa_strlen (id);
01025                if (state.cond.top->effective) {
01026                   pp_annotate (output, "// #define %s(", id);
01027 
01028                   /* If the symbol is already defined, override it. */
01029                   symbol = pp_symbols_find (&state.symbols, id);
01030                   if (symbol == NULL) {
01031                      symbol = pp_symbols_push (&state.symbols);
01032                      if (symbol == NULL)
01033                         goto error;
01034                      slang_string_pushs (&symbol->name, id, idlen);
01035                   }
01036                   else {
01037                      pp_symbol_reset (symbol);
01038                   }
01039                }
01040                i += idlen + 1;
01041 
01042                /* Parse optional macro parameters. */
01043                while (prod[i++] != PARAM_END) {
01044                   if (state.cond.top->effective) {
01045                      pp_symbol *param;
01046 
01047                      id = (const char *) (&prod[i]);
01048                      idlen = _mesa_strlen (id);
01049                      pp_annotate (output, "%s, ", id);
01050                      param = pp_symbols_push (&symbol->parameters);
01051                      if (param == NULL)
01052                         goto error;
01053                      slang_string_pushs (&param->name, id, idlen);
01054                   }
01055                   i += idlen + 1;
01056                }
01057 
01058                /* Parse macro replacement. */
01059                id = (const char *) (&prod[i]);
01060                idlen = _mesa_strlen (id);
01061                if (state.cond.top->effective) {
01062                   pp_annotate (output, ") %s", id);
01063                   slang_string_pushs (&symbol->replacement, id, idlen);
01064                }
01065                i += idlen + 1;
01066             }
01067             break;
01068 
01069          case TOKEN_UNDEF:
01070             id = (const char *) (&prod[i]);
01071             i += _mesa_strlen (id) + 1;
01072             if (state.cond.top->effective) {
01073                pp_symbol *symbol;
01074 
01075                pp_annotate (output, "// #undef %s", id);
01076                /* Try to find symbol with given name and remove it. */
01077                symbol = pp_symbols_find (&state.symbols, id);
01078                if (symbol != NULL)
01079                   if (!pp_symbols_erase (&state.symbols, symbol))
01080                      goto error;
01081             }
01082             break;
01083 
01084          case TOKEN_IF:
01085             {
01086                GLint result;
01087 
01088                /* Parse #if expression end execute it. */
01089                pp_annotate (output, "// #if ");
01090                if (!parse_if (output, prod, &i, &result, &state, eid))
01091                   goto error;
01092 
01093                /* Push new condition on the stack. */
01094                if (!pp_cond_stack_push (&state.cond, state.elog))
01095                   goto error;
01096                state.cond.top->current = result ? GL_TRUE : GL_FALSE;
01097                state.cond.top->else_allowed = GL_TRUE;
01098                state.cond.top->endif_required = GL_TRUE;
01099                pp_cond_stack_reevaluate (&state.cond);
01100             }
01101             break;
01102 
01103          case TOKEN_ELSE:
01104             /* Check if #else is alloved here. */
01105             if (!state.cond.top->else_allowed) {
01106                slang_info_log_error (elog, "#else without matching #if.");
01107                goto error;
01108             }
01109 
01110             /* Negate current condition and reevaluate it. */
01111             state.cond.top->current = !state.cond.top->current;
01112             state.cond.top->else_allowed = GL_FALSE;
01113             pp_cond_stack_reevaluate (&state.cond);
01114             if (state.cond.top->effective)
01115                pp_annotate (output, "// #else");
01116             break;
01117 
01118          case TOKEN_ELIF:
01119             /* Check if #elif is alloved here. */
01120             if (!state.cond.top->else_allowed) {
01121                slang_info_log_error (elog, "#elif without matching #if.");
01122                goto error;
01123             }
01124 
01125             /* Negate current condition and reevaluate it. */
01126             state.cond.top->current = !state.cond.top->current;
01127             pp_cond_stack_reevaluate (&state.cond);
01128 
01129             if (state.cond.top->effective)
01130                pp_annotate (output, "// #elif ");
01131 
01132             {
01133                GLint result;
01134 
01135                /* Parse #elif expression end execute it. */
01136                if (!parse_if (output, prod, &i, &result, &state, eid))
01137                   goto error;
01138 
01139                /* Update current condition and reevaluate it. */
01140                state.cond.top->current = result ? GL_TRUE : GL_FALSE;
01141                pp_cond_stack_reevaluate (&state.cond);
01142             }
01143             break;
01144 
01145          case TOKEN_ENDIF:
01146             /* Check if #endif is alloved here. */
01147             if (!state.cond.top->endif_required) {
01148                slang_info_log_error (elog, "#endif without matching #if.");
01149                goto error;
01150             }
01151 
01152             /* Pop the condition off the stack. */
01153             state.cond.top++;
01154             if (state.cond.top->effective)
01155                pp_annotate (output, "// #endif");
01156             break;
01157 
01158          case TOKEN_EXTENSION:
01159             /* Parse the extension name. */
01160             id = (const char *) (&prod[i]);
01161             i += _mesa_strlen (id) + 1;
01162             if (state.cond.top->effective)
01163                pp_annotate (output, "// #extension %s: ", id);
01164 
01165             /* Parse and apply extension behavior. */
01166             if (state.cond.top->effective) {
01167                switch (prod[i++]) {
01168 
01169                case BEHAVIOR_REQUIRE:
01170                   pp_annotate (output, "require");
01171                   if (!pp_ext_set (&state.ext, id, GL_TRUE)) {
01172                      if (_mesa_strcmp (id, "all") == 0) {
01173                         slang_info_log_error (elog, "require: bad behavior for #extension all.");
01174                         goto error;
01175                      }
01176                      else {
01177                         slang_info_log_error (elog, "%s: required extension is not supported.", id);
01178                         goto error;
01179                      }
01180                   }
01181                   break;
01182 
01183                case BEHAVIOR_ENABLE:
01184                   pp_annotate (output, "enable");
01185                   if (!pp_ext_set (&state.ext, id, GL_TRUE)) {
01186                      if (_mesa_strcmp (id, "all") == 0) {
01187                         slang_info_log_error (elog, "enable: bad behavior for #extension all.");
01188                         goto error;
01189                      }
01190                      else {
01191                         slang_info_log_warning (elog, "%s: enabled extension is not supported.", id);
01192                      }
01193                   }
01194                   break;
01195 
01196                case BEHAVIOR_WARN:
01197                   pp_annotate (output, "warn");
01198                   if (!pp_ext_set (&state.ext, id, GL_TRUE)) {
01199                      if (_mesa_strcmp (id, "all") != 0) {
01200                         slang_info_log_warning (elog, "%s: enabled extension is not supported.", id);
01201                      }
01202                   }
01203                   break;
01204 
01205                case BEHAVIOR_DISABLE:
01206                   pp_annotate (output, "disable");
01207                   if (!pp_ext_set (&state.ext, id, GL_FALSE)) {
01208                      if (_mesa_strcmp (id, "all") == 0) {
01209                         pp_ext_disable_all (&state.ext);
01210                      }
01211                      else {
01212                         slang_info_log_warning (elog, "%s: disabled extension is not supported.", id);
01213                      }
01214                   }
01215                   break;
01216 
01217                default:
01218                   assert (0);
01219                }
01220             }
01221             break;
01222 
01223          case TOKEN_PRAGMA:
01224             {
01225                GLint have_param;
01226                const char *pragma, *param;
01227 
01228                pragma = (const char *) (&prod[i]);
01229                i += _mesa_strlen(pragma) + 1;
01230                have_param = (prod[i++] == PRAGMA_PARAM);
01231                if (have_param) {
01232                   param = (const char *) (&prod[i]);
01233                   i += _mesa_strlen(param) + 1;
01234                }
01235                else {
01236                   param = NULL;
01237                }
01238                pp_pragma(pragmas, pragma, param);
01239             }
01240             break;
01241 
01242          case TOKEN_LINE:
01243             id = (const char *) (&prod[i]);
01244             i += _mesa_strlen (id) + 1;
01245 
01246             if (state.cond.top->effective) {
01247                slang_string buffer;
01248                GLuint count;
01249                GLint results[2];
01250                expand_state es;
01251 
01252                slang_string_init (&buffer);
01253                state.line++;
01254                es.output = &buffer;
01255                es.input = id;
01256                es.state = &state;
01257                if (!expand (&es, &state.symbols))
01258                   goto error;
01259 
01260                pp_annotate (output, "// #line ");
01261                count = execute_expressions (output, eid,
01262                                              (const byte *) (slang_string_cstr (&buffer)),
01263                                              results, state.elog);
01264                slang_string_free (&buffer);
01265                if (count == 0)
01266                   goto error;
01267 
01268                state.line = results[0] - 1;
01269                if (count == 2)
01270                   state.file = results[1];
01271             }
01272             break;
01273          }
01274       }
01275    }
01276 
01277    /* Check for missing #endifs. */
01278    if (state.cond.top->endif_required) {
01279       slang_info_log_error (elog, "#endif expected but end of source found.");
01280       goto error;
01281    }
01282 
01283    grammar_alloc_free(prod);
01284    pp_state_free (&state);
01285    return GL_TRUE;
01286 
01287 error:
01288    grammar_alloc_free(prod);
01289    pp_state_free (&state);
01290    return GL_FALSE;
01291 }
01292 
01293 
01302 GLboolean
01303 _slang_preprocess_directives(slang_string *output,
01304                              const char *input,
01305                              slang_info_log *elog,
01306                              const struct gl_extensions *extensions,
01307                              struct gl_sl_pragmas *pragmas)
01308 {
01309    grammar pid, eid;
01310    GLboolean success;
01311 
01312    pid = grammar_load_from_text ((const byte *) (slang_pp_directives_syn));
01313    if (pid == 0) {
01314       grammar_error_to_log (elog);
01315       return GL_FALSE;
01316    }
01317    eid = grammar_load_from_text ((const byte *) (slang_pp_expression_syn));
01318    if (eid == 0) {
01319       grammar_error_to_log (elog);
01320       grammar_destroy (pid);
01321       return GL_FALSE;
01322    }
01323    success = preprocess_source (output, input, pid, eid, elog, extensions, pragmas);
01324    grammar_destroy (eid);
01325    grammar_destroy (pid);
01326    return success;
01327 }
01328 

Generated on Sun May 27 2012 04:20:41 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.