📄 slang_preprocess.c
字号:
return &self->symbols[self->count++];}static GLbooleanpp_symbols_erase (pp_symbols *self, pp_symbol *symbol){ assert (symbol >= self->symbols && symbol < self->symbols + self->count); self->count--; pp_symbol_free (symbol); if (symbol < self->symbols + self->count) _mesa_memcpy (symbol, symbol + 1, sizeof (pp_symbol) * (self->symbols + self->count - symbol)); self->symbols = (pp_symbol *) (_mesa_realloc (self->symbols, (self->count + 1) * sizeof (pp_symbol), self->count * sizeof (pp_symbol))); return self->symbols != NULL;}static pp_symbol *pp_symbols_find (pp_symbols *self, const char *name){ GLuint i; for (i = 0; i < self->count; i++) if (_mesa_strcmp (name, slang_string_cstr (&self->symbols[i].name)) == 0) return &self->symbols[i]; return NULL;}/* * The condition context of a single #if/#else/#endif level. Those can be nested, so there * is a stack of condition contexts. * There is a special global context on the bottom of the stack. It is there to simplify * context handling. */typedef struct{ GLboolean current; /* The condition value of this level. */ GLboolean effective; /* The effective product of current condition, outer level conditions * and position within #if-#else-#endif sections. */ GLboolean else_allowed; /* TRUE if in #if-#else section, FALSE if in #else-#endif section * and for global context. */ GLboolean endif_required; /* FALSE for global context only. */} pp_cond_ctx;/* Should be enuff. */#define CONDITION_STACK_SIZE 64typedef struct{ pp_cond_ctx stack[CONDITION_STACK_SIZE]; pp_cond_ctx *top;} pp_cond_stack;static GLbooleanpp_cond_stack_push (pp_cond_stack *self, slang_info_log *elog){ if (self->top == self->stack) { slang_info_log_error (elog, "internal compiler error: preprocessor condition stack overflow."); return GL_FALSE; } self->top--; return GL_TRUE;}static GLvoidpp_cond_stack_reevaluate (pp_cond_stack *self){ /* There must be at least 2 conditions on the stack - one global and one being evaluated. */ assert (self->top <= &self->stack[CONDITION_STACK_SIZE - 2]); self->top->effective = self->top->current && self->top[1].effective;}/* * Extension enables through #extension directive. * NOTE: Currently, only enable/disable state is stored. */typedef struct{ GLboolean MESA_shader_debug; /* GL_MESA_shader_debug enable */ GLboolean ARB_texture_rectangle; /* GL_ARB_texture_rectangle enable */} pp_ext;/* * Disable all extensions. Called at startup and on #extension all: disable. */static GLvoidpp_ext_disable_all (pp_ext *self){ self->MESA_shader_debug = GL_FALSE;}static GLvoidpp_ext_init (pp_ext *self){ pp_ext_disable_all (self); self->ARB_texture_rectangle = GL_TRUE; /* Other initialization code goes here. */}static GLbooleanpp_ext_set (pp_ext *self, const char *name, GLboolean enable){ if (_mesa_strcmp (name, "MESA_shader_debug") == 0) self->MESA_shader_debug = enable; else if (_mesa_strcmp (name, "GL_ARB_texture_rectangle") == 0) self->ARB_texture_rectangle = enable; /* Next extension name tests go here. */ else return GL_FALSE; return GL_TRUE;}/* * The state of preprocessor: current line, file and version number, list of all defined macros * and the #if/#endif context. */typedef struct{ GLint line; GLint file; GLint version; pp_symbols symbols; pp_ext ext; slang_info_log *elog; pp_cond_stack cond;} pp_state;static GLvoidpp_state_init (pp_state *self, slang_info_log *elog){ self->line = 0; self->file = 1;#if FEATURE_es2_glsl self->version = 100;#else self->version = 110;#endif pp_symbols_init (&self->symbols); pp_ext_init (&self->ext); self->elog = elog; /* Initialize condition stack and create the global context. */ self->cond.top = &self->cond.stack[CONDITION_STACK_SIZE - 1]; self->cond.top->current = GL_TRUE; self->cond.top->effective = GL_TRUE; self->cond.top->else_allowed = GL_FALSE; self->cond.top->endif_required = GL_FALSE;}static GLvoidpp_state_free (pp_state *self){ pp_symbols_free (&self->symbols);}#define IS_FIRST_ID_CHAR(x) (((x) >= 'a' && (x) <= 'z') || ((x) >= 'A' && (x) <= 'Z') || (x) == '_')#define IS_NEXT_ID_CHAR(x) (IS_FIRST_ID_CHAR(x) || ((x) >= '0' && (x) <= '9'))#define IS_WHITE(x) ((x) == ' ' || (x) == '\n')#define IS_NULL(x) ((x) == '\0')#define SKIP_WHITE(x) do { while (IS_WHITE(*(x))) (x)++; } while (GL_FALSE)typedef struct{ slang_string *output; const char *input; pp_state *state;} expand_state;static GLbooleanexpand_defined (expand_state *e, slang_string *buffer){ GLboolean in_paren = GL_FALSE; const char *id; /* Parse the optional opening parenthesis. */ SKIP_WHITE(e->input); if (*e->input == '(') { e->input++; in_paren = GL_TRUE; SKIP_WHITE(e->input); } /* Parse operand. */ if (!IS_FIRST_ID_CHAR(*e->input)) { slang_info_log_error (e->state->elog, "preprocess error: identifier expected after operator 'defined'."); return GL_FALSE; } slang_string_reset (buffer); slang_string_pushc (buffer, *e->input++); while (IS_NEXT_ID_CHAR(*e->input)) slang_string_pushc (buffer, *e->input++); id = slang_string_cstr (buffer); /* Check if the operand is defined. Output 1 if it is defined, output 0 if not. */ if (pp_symbols_find (&e->state->symbols, id) == NULL) slang_string_pushs (e->output, " 0 ", 3); else slang_string_pushs (e->output, " 1 ", 3); /* Parse the closing parentehesis if the opening one was there. */ if (in_paren) { SKIP_WHITE(e->input); if (*e->input != ')') { slang_info_log_error (e->state->elog, "preprocess error: ')' expected."); return GL_FALSE; } e->input++; SKIP_WHITE(e->input); } return GL_TRUE;}static GLbooleanexpand (expand_state *, pp_symbols *);static GLbooleanexpand_symbol (expand_state *e, pp_symbol *symbol){ expand_state es; /* If the macro has some parameters, we need to parse them. */ if (symbol->parameters.count != 0) { GLuint i; /* Parse the opening parenthesis. */ SKIP_WHITE(e->input); if (*e->input != '(') { slang_info_log_error (e->state->elog, "preprocess error: '(' expected."); return GL_FALSE; } e->input++; SKIP_WHITE(e->input); /* Parse macro actual parameters. This can be anything, separated by a colon. * TODO: What about nested/grouped parameters by parenthesis? */ for (i = 0; i < symbol->parameters.count; i++) { if (*e->input == ')') { slang_info_log_error (e->state->elog, "preprocess error: unexpected ')'."); return GL_FALSE; } /* Eat all characters up to the comma or closing parentheses. */ pp_symbol_reset (&symbol->parameters.symbols[i]); while (!IS_NULL(*e->input) && *e->input != ',' && *e->input != ')') slang_string_pushc (&symbol->parameters.symbols[i].replacement, *e->input++); /* If it was not the last paremeter, skip the comma. Otherwise, skip the * closing parentheses. */ if (i + 1 == symbol->parameters.count) { /* This is the last paremeter - skip the closing parentheses. */ if (*e->input != ')') { slang_info_log_error (e->state->elog, "preprocess error: ')' expected."); return GL_FALSE; } e->input++; SKIP_WHITE(e->input); } else { /* Skip the separating comma. */ if (*e->input != ',') { slang_info_log_error (e->state->elog, "preprocess error: ',' expected."); return GL_FALSE; } e->input++; SKIP_WHITE(e->input); } } } /* Expand the macro. Use its parameters as a priority symbol list to expand * macro parameters correctly. */ es.output = e->output; es.input = slang_string_cstr (&symbol->replacement); es.state = e->state; slang_string_pushc (e->output, ' '); if (!expand (&es, &symbol->parameters)) return GL_FALSE; slang_string_pushc (e->output, ' '); return GL_TRUE;}/* * Function expand() expands source text from <input> to <output>. The expansion is made using * the list passed in <symbols> parameter. It allows us to expand macro formal parameters with * actual parameters. The global list of symbols from pp state is used when doing a recursive * call of expand(). */static GLbooleanexpand (expand_state *e, pp_symbols *symbols){ while (!IS_NULL(*e->input)) { if (IS_FIRST_ID_CHAR(*e->input)) { slang_string buffer; const char *id; /* Parse the identifier. */ slang_string_init (&buffer); slang_string_pushc (&buffer, *e->input++); while (IS_NEXT_ID_CHAR(*e->input)) slang_string_pushc (&buffer, *e->input++); id = slang_string_cstr (&buffer); /* Now check if the identifier is special in some way. The "defined" identifier is * actually an operator that we must handle here and expand it either to " 0 " or " 1 ". * The other identifiers start with "__" and we expand it to appropriate values * taken from the preprocessor state. */ if (_mesa_strcmp (id, "defined") == 0) { if (!expand_defined (e, &buffer)) return GL_FALSE; } else if (_mesa_strcmp (id, "__LINE__") == 0) { slang_string_pushc (e->output, ' '); slang_string_pushi (e->output, e->state->line); slang_string_pushc (e->output, ' '); } else if (_mesa_strcmp (id, "__FILE__") == 0) { slang_string_pushc (e->output, ' '); slang_string_pushi (e->output, e->state->file); slang_string_pushc (e->output, ' '); } else if (_mesa_strcmp (id, "__VERSION__") == 0) { slang_string_pushc (e->output, ' '); slang_string_pushi (e->output, e->state->version); slang_string_pushc (e->output, ' '); }#if FEATURE_es2_glsl else if (_mesa_strcmp (id, "GL_ES") == 0 || _mesa_strcmp (id, "GL_FRAGMENT_PRECISION_HIGH") == 0) { slang_string_pushc (e->output, ' '); slang_string_pushi (e->output, '1'); slang_string_pushc (e->output, ' '); }#endif else { pp_symbol *symbol; /* The list of symbols from <symbols> take precedence over the list from <state>. * Note that in some cases this is the same list so avoid double look-up. */ symbol = pp_symbols_find (symbols, id); if (symbol == NULL && symbols != &e->state->symbols) symbol = pp_symbols_find (&e->state->symbols, id); /* If the symbol was found, recursively expand its definition. */ if (symbol != NULL) { if (!expand_symbol (e, symbol)) { slang_string_free (&buffer); return GL_FALSE; } } else { slang_string_push (e->output, &buffer); } } slang_string_free (&buffer); } else if (IS_WHITE(*e->input)) { slang_string_pushc (e->output, *e->input++); } else { while (!IS_WHITE(*e->input) && !IS_NULL(*e->input) && !IS_FIRST_ID_CHAR(*e->input)) slang_string_pushc (e->output, *e->input++); } } return GL_TRUE;}static GLbooleanparse_if (slang_string *output, const byte *prod, GLuint *pi, GLint *result, pp_state *state, grammar eid){ const char *text; GLuint len; text = (const char *) (&prod[*pi]); len = _mesa_strlen (text); if (state->cond.top->effective) { slang_string expr; GLuint count; GLint results[2]; expand_state es; /* Expand the expression. */ slang_string_init (&expr); es.output = &expr; es.input = text; es.state = state; if (!expand (&es, &state->symbols)) return GL_FALSE; /* Execute the expression. */ count = execute_expressions (output, eid, (const byte *) (slang_string_cstr (&expr)), results, state->elog); slang_string_free (&expr); if (count != 1) return GL_FALSE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -