--- a/mojoshader_preprocessor.c Thu Feb 25 02:25:42 2010 -0500
+++ b/mojoshader_preprocessor.c Thu Feb 25 02:26:36 2010 -0500
@@ -515,6 +515,24 @@
} // find_define_by_token
+static const Define *find_macro_arg(const IncludeState *state)
+{
+ const Define *def = NULL;
+ char *sym = (char *) alloca(state->tokenlen + 1);
+ memcpy(sym, state->token, state->tokenlen);
+ sym[state->tokenlen] = '\0';
+
+ for (def = state->defines; def != NULL; def = def->next)
+ {
+ assert(def->paramcount == 0); // args can't have args!
+ if (strcmp(def->identifier, sym) == 0)
+ break;
+ } // while
+
+ return def;
+} // find_macro_arg
+
+
static void put_all_defines(Context *ctx)
{
size_t i;
@@ -1066,12 +1084,12 @@
case ((Token) ' '): // may not actually point to ' '.
assert(buffer.total_bytes > 0);
if (!add_to_buffer(&buffer, &space, 1, m, d))
- ctx->out_of_memory = 1;
+ out_of_memory(ctx);
break;
default:
if (!add_to_buffer(&buffer,state->token,state->tokenlen,m,d))
- ctx->out_of_memory = 1;
+ out_of_memory(ctx);
break;
} // switch
} // while
@@ -1080,7 +1098,8 @@
if (!ctx->out_of_memory)
{
definition = flatten_buffer(&buffer, m, d);
- ctx->out_of_memory = (definition == NULL);
+ if (definition == NULL)
+ out_of_memory(ctx);
} // if
size_t buflen = buffer.total_bytes + 1;
@@ -1230,18 +1249,10 @@
memcpy(sym, state->token, state->tokenlen);
sym[state->tokenlen] = '\0';
- // IncludeState defines (macro args) take precedence over Context defines.
- const Define *def = state->defines;
- while (def)
- {
- assert(def->paramcount == 0); // args can't have args!
- if (strcmp(def->identifier, sym) == 0)
- break;
- def = def->next;
- } // while
-
Define *params = NULL;
+ // IncludeState defines (macro args) take precedence over Context defines.
+ const Define *def = find_macro_arg(state);
if (def == NULL)
{
def = find_define(ctx, sym);
@@ -1781,18 +1792,7 @@
assert(state->is_macro);
if (lexer(state) == TOKEN_IDENTIFIER)
- {
- char *sym = (char *) alloca(state->tokenlen+1);
- memcpy(sym, state->token, state->tokenlen);
- sym[state->tokenlen] = '\0';
-
- for (def = state->defines; def != NULL; def = def->next)
- {
- assert(def->paramcount == 0); // args can't have args!
- if (strcmp(def->identifier, sym) == 0)
- break;
- } // while
- } // if
+ def = find_macro_arg(state);
if (def == NULL)
{
@@ -1815,6 +1815,80 @@
} // handle_pp_stringify
+static int handle_pp_concat(Context *ctx)
+{
+ MOJOSHADER_malloc m = ctx->malloc;
+ MOJOSHADER_free f = ctx->free;
+ void *d = ctx->malloc_data;
+ IncludeState *state = ctx->include_stack;
+ Buffer buffer;
+ int glued = 0;
+ int rc = 0;
+ const Define *def = NULL;
+
+ assert(state->is_macro);
+
+ init_buffer(&buffer);
+
+ def = (state->tokenval == TOKEN_IDENTIFIER) ? find_macro_arg(state) : 0;
+ if (def)
+ rc = add_to_buffer(&buffer, def->definition, strlen(def->definition), m, d);
+ else
+ rc = add_to_buffer(&buffer, state->token, state->tokenlen, m, d);
+
+ while (rc)
+ {
+ IncludeState saved; // can't just pushback; we need all the state.
+ memcpy(&saved, state, sizeof (IncludeState));
+ if (lexer(state) != TOKEN_HASHHASH) // concat operator ("##")
+ {
+ memcpy(state, &saved, sizeof (IncludeState));
+ break;
+ } // if
+
+ lexer(state); // step past ## token.
+
+ // we checked these things when parsing the macro.
+ assert(state->is_macro);
+ assert(state->tokenval != TOKEN_EOI);
+ assert(state->tokenval != ((Token) ' '));
+
+ def = (state->tokenval == TOKEN_IDENTIFIER) ? find_macro_arg(state) : 0;
+ if (def)
+ rc = add_to_buffer(&buffer, def->definition, strlen(def->definition), m, d);
+ else
+ rc = add_to_buffer(&buffer, state->token, state->tokenlen, m, d);
+
+ glued = 1;
+ } // while
+
+ if (!rc)
+ {
+ out_of_memory(ctx);
+ return 0;
+ } // if
+
+ if (glued)
+ {
+ char *combined = flatten_buffer(&buffer, m, d);
+ if (combined == NULL)
+ {
+ out_of_memory(ctx);
+ glued = 0;
+ } // if
+ else
+ {
+ const char *filename = state->filename;
+ push_source(ctx, filename, combined, buffer.total_bytes,
+ state->line, close_define_include, NULL, 0);
+ } // else
+ } // if
+
+ free_buffer(&buffer, f, d);
+ return glued;
+} // handle_pp_concat
+
+
static void unterminated_pp_condition(Context *ctx)
{
IncludeState *state = ctx->include_stack;
@@ -1958,14 +2032,20 @@
continue; // will return at top of loop.
} // else if
- // stringify operator ("#") ... only during macro replacement.
- else if ((token == TOKEN_HASH) && (state->is_macro))
+ // stringify ("#") and concat ("##") only during macro replacement.
+ if (state->is_macro)
{
- handle_pp_stringify(ctx);
- continue;
- } // else if
+ if (token == TOKEN_HASH)
+ {
+ handle_pp_stringify(ctx);
+ continue;
+ } // if
- else if (token == TOKEN_IDENTIFIER)
+ if (handle_pp_concat(ctx))
+ continue;
+ } // if
+
+ if (token == TOKEN_IDENTIFIER)
{
if (handle_pp_identifier(ctx))
continue; // pushed the include_stack.