static GLuint execute_expressions (slang_string *output, grammar eid, const byte *expr, GLint results[2], slang_info_log *elog) { GLint success; byte *code; GLuint size, count = 0; success = grammar_fast_check (eid, expr, &code, &size, 64); if (success) { GLuint i = 0; while (code[i++] == EXP_EXPRESSION) { assert (count < 2); if (!execute_expression (output, code, &i, &results[count], elog)) { count = 0; break; } count++; } grammar_alloc_free (code); } else { slang_info_log_error (elog, "syntax error in preprocessor expression.");\ } return count; }
GLboolean _slang_preprocess_version (const char *text, GLuint *version, GLuint *eaten, slang_info_log *log) { grammar id; byte *prod, *I; unsigned int size; id = grammar_load_from_text ((const byte *) (slang_pp_version_syn)); if (id == 0) { grammar_error_to_log (log); return GL_FALSE; } if (!grammar_fast_check (id, (const byte *) (text), &prod, &size, 8)) { grammar_error_to_log (log); grammar_destroy (id); return GL_FALSE; } /* there can be multiple #version directives - grab the last one */ I = &prod[size - 6]; *version = (GLuint) (I[0]) + (GLuint) (I[1]) * 100; *eaten = (GLuint) (I[2]) + ((GLuint) (I[3]) << 8) + ((GLuint) (I[4]) << 16) + ((GLuint) (I[5]) << 24); grammar_destroy (id); grammar_alloc_free (prod); return GL_TRUE; }
int _slang_preprocess_version (const char *text, unsigned int *version, unsigned int *eaten, slang_info_log *log) { grammar id; byte *prod, *I; unsigned int size; id = grammar_load_from_text ((const byte *) slang_version_syn); if (id == 0) { char buf[1024]; unsigned int pos; grammar_get_last_error ( (unsigned char*) buf, 1024, (int*) &pos); slang_info_log_error (log, buf); return 0; } if (!grammar_fast_check (id, (const byte *) text, &prod, &size, 8)) { char buf[1024]; unsigned int pos; grammar_get_last_error ( (unsigned char*) buf, 1024, (int*) &pos); slang_info_log_error (log, buf); grammar_destroy (id); return 0; } grammar_destroy (id); /* there can be multiple #version directives - grab the last one */ I = prod; while (I < prod + size) { *version = (unsigned int) I[0] + (unsigned int) I[1] * 100; *eaten = ((unsigned int) I[2]) + ((unsigned int) I[3] << 8) + ((unsigned int) I[4] << 16) + ((unsigned int) I[5] << 24); I += 6; } grammar_alloc_free (prod); return 1; }
static GLboolean preprocess_source (slang_string *output, const char *source, grammar pid, grammar eid, slang_info_log *elog, const struct gl_extensions *extensions, struct gl_sl_pragmas *pragmas) { static const char *predefined[] = { "__FILE__", "__LINE__", "__VERSION__", #if FEATURE_es2_glsl "GL_ES", "GL_FRAGMENT_PRECISION_HIGH", #endif NULL }; byte *prod; GLuint size, i; pp_state state; if (!grammar_fast_check (pid, (const byte *) (source), &prod, &size, 65536)) { grammar_error_to_log (elog); return GL_FALSE; } pp_state_init (&state, elog, extensions); pp_pragmas_init (pragmas); /* add the predefined symbols to the symbol table */ for (i = 0; predefined[i]; i++) { pp_symbol *symbol = NULL; symbol = pp_symbols_push(&state.symbols); assert(symbol); slang_string_pushs(&symbol->name, predefined[i], _mesa_strlen(predefined[i])); } i = 0; while (i < size) { if (prod[i] != ESCAPE_TOKEN) { if (state.cond.top->effective) { slang_string input; expand_state es; /* Eat only one line of source code to expand it. * FIXME: This approach has one drawback. If a macro with parameters spans across * multiple lines, the preprocessor will raise an error. */ slang_string_init (&input); while (prod[i] != '\0' && prod[i] != '\n') slang_string_pushc (&input, prod[i++]); if (prod[i] != '\0') slang_string_pushc (&input, prod[i++]); /* Increment line number. */ state.line++; es.output = output; es.input = slang_string_cstr (&input); es.state = &state; if (!expand (&es, &state.symbols)) goto error; slang_string_free (&input); } else { /* Condition stack is disabled - keep track on line numbers and output only newlines. */ if (prod[i] == '\n') { state.line++; /*pp_annotate (output, "%c", prod[i]);*/ } else { /*pp_annotate (output, "%c", prod[i]);*/ } i++; } } else { const char *id; GLuint idlen; GLubyte token; i++; token = prod[i++]; switch (token) { case TOKEN_END: /* End of source string. * Check if all #ifs have been terminated by matching #endifs. * On condition stack there should be only the global condition context. */ if (state.cond.top->endif_required) { slang_info_log_error (elog, "end of source without matching #endif."); return GL_FALSE; } break; case TOKEN_DEFINE: { pp_symbol *symbol = NULL; /* Parse macro name. */ id = (const char *) (&prod[i]); idlen = _mesa_strlen (id); if (state.cond.top->effective) { pp_annotate (output, "// #define %s(", id); /* If the symbol is already defined, override it. */ symbol = pp_symbols_find (&state.symbols, id); if (symbol == NULL) { symbol = pp_symbols_push (&state.symbols); if (symbol == NULL) goto error; slang_string_pushs (&symbol->name, id, idlen); } else { pp_symbol_reset (symbol); } } i += idlen + 1; /* Parse optional macro parameters. */ while (prod[i++] != PARAM_END) { pp_symbol *param; id = (const char *) (&prod[i]); idlen = _mesa_strlen (id); if (state.cond.top->effective) { pp_annotate (output, "%s, ", id); param = pp_symbols_push (&symbol->parameters); if (param == NULL) goto error; slang_string_pushs (¶m->name, id, idlen); } i += idlen + 1; } /* Parse macro replacement. */ id = (const char *) (&prod[i]); idlen = _mesa_strlen (id); if (state.cond.top->effective) { slang_string replacement; expand_state es; pp_annotate (output, ") %s", id); slang_string_init(&replacement); slang_string_pushs(&replacement, id, idlen); /* Expand macro replacement. */ es.output = &symbol->replacement; es.input = slang_string_cstr(&replacement); es.state = &state; if (!expand(&es, &state.symbols)) { slang_string_free(&replacement); goto error; } slang_string_free(&replacement); } i += idlen + 1; } break; case TOKEN_UNDEF: id = (const char *) (&prod[i]); i += _mesa_strlen (id) + 1; if (state.cond.top->effective) { pp_symbol *symbol; pp_annotate (output, "// #undef %s", id); /* Try to find symbol with given name and remove it. */ symbol = pp_symbols_find (&state.symbols, id); if (symbol != NULL) if (!pp_symbols_erase (&state.symbols, symbol)) goto error; } break; case TOKEN_IF: { GLint result; /* Parse #if expression end execute it. */ pp_annotate (output, "// #if "); if (!parse_if (output, prod, &i, &result, &state, eid)) goto error; /* Push new condition on the stack. */ if (!pp_cond_stack_push (&state.cond, state.elog)) goto error; state.cond.top->current = result ? GL_TRUE : GL_FALSE; state.cond.top->else_allowed = GL_TRUE; state.cond.top->endif_required = GL_TRUE; pp_cond_stack_reevaluate (&state.cond); } break; case TOKEN_ELSE: /* Check if #else is alloved here. */ if (!state.cond.top->else_allowed) { slang_info_log_error (elog, "#else without matching #if."); goto error; } /* Negate current condition and reevaluate it. */ state.cond.top->current = !state.cond.top->current; state.cond.top->else_allowed = GL_FALSE; pp_cond_stack_reevaluate (&state.cond); if (state.cond.top->effective) pp_annotate (output, "// #else"); break; case TOKEN_ELIF: /* Check if #elif is alloved here. */ if (!state.cond.top->else_allowed) { slang_info_log_error (elog, "#elif without matching #if."); goto error; } /* Negate current condition and reevaluate it. */ state.cond.top->current = !state.cond.top->current; pp_cond_stack_reevaluate (&state.cond); if (state.cond.top->effective) pp_annotate (output, "// #elif "); { GLint result; /* Parse #elif expression end execute it. */ if (!parse_if (output, prod, &i, &result, &state, eid)) goto error; /* Update current condition and reevaluate it. */ state.cond.top->current = result ? GL_TRUE : GL_FALSE; pp_cond_stack_reevaluate (&state.cond); } break; case TOKEN_ENDIF: /* Check if #endif is alloved here. */ if (!state.cond.top->endif_required) { slang_info_log_error (elog, "#endif without matching #if."); goto error; } /* Pop the condition off the stack. */ state.cond.top++; if (state.cond.top->effective) pp_annotate (output, "// #endif"); break; case TOKEN_EXTENSION: /* Parse the extension name. */ id = (const char *) (&prod[i]); i += _mesa_strlen (id) + 1; if (state.cond.top->effective) pp_annotate (output, "// #extension %s: ", id); /* Parse and apply extension behavior. */ if (state.cond.top->effective) { switch (prod[i++]) { case BEHAVIOR_REQUIRE: pp_annotate (output, "require"); if (!pp_ext_set (&state.ext, id, GL_TRUE)) { if (_mesa_strcmp (id, "all") == 0) { slang_info_log_error (elog, "require: bad behavior for #extension all."); goto error; } else { slang_info_log_error (elog, "%s: required extension is not supported.", id); goto error; } } break; case BEHAVIOR_ENABLE: pp_annotate (output, "enable"); if (!pp_ext_set (&state.ext, id, GL_TRUE)) { if (_mesa_strcmp (id, "all") == 0) { slang_info_log_error (elog, "enable: bad behavior for #extension all."); goto error; } else { slang_info_log_warning (elog, "%s: enabled extension is not supported.", id); } } break; case BEHAVIOR_WARN: pp_annotate (output, "warn"); if (!pp_ext_set (&state.ext, id, GL_TRUE)) { if (_mesa_strcmp (id, "all") != 0) { slang_info_log_warning (elog, "%s: enabled extension is not supported.", id); } } break; case BEHAVIOR_DISABLE: pp_annotate (output, "disable"); if (!pp_ext_set (&state.ext, id, GL_FALSE)) { if (_mesa_strcmp (id, "all") == 0) { pp_ext_disable_all (&state.ext); } else { slang_info_log_warning (elog, "%s: disabled extension is not supported.", id); } } break; default: assert (0); } } break; case TOKEN_PRAGMA: { GLint have_param; const char *pragma, *param; pragma = (const char *) (&prod[i]); i += _mesa_strlen(pragma) + 1; have_param = (prod[i++] == PRAGMA_PARAM); if (have_param) { param = (const char *) (&prod[i]); i += _mesa_strlen(param) + 1; } else { param = NULL; } pp_pragma(pragmas, pragma, param); } break; case TOKEN_LINE: id = (const char *) (&prod[i]); i += _mesa_strlen (id) + 1; if (state.cond.top->effective) { slang_string buffer; GLuint count; GLint results[2]; expand_state es; slang_string_init (&buffer); state.line++; es.output = &buffer; es.input = id; es.state = &state; if (!expand (&es, &state.symbols)) goto error; pp_annotate (output, "// #line "); count = execute_expressions (output, eid, (const byte *) (slang_string_cstr (&buffer)), results, state.elog); slang_string_free (&buffer); if (count == 0) goto error; state.line = results[0] - 1; if (count == 2) state.file = results[1]; } break; } } } /* Check for missing #endifs. */ if (state.cond.top->endif_required) { slang_info_log_error (elog, "#endif expected but end of source found."); goto error; } grammar_alloc_free(prod); pp_state_free (&state); return GL_TRUE; error: grammar_alloc_free(prod); pp_state_free (&state); return GL_FALSE; }