示例#1
0
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;
}
示例#2
0
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;
}
示例#3
0
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;
}
示例#4
0
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 (&param->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;
}