--- a/assemble.c Wed Dec 10 03:55:06 2008 -0500
+++ b/assemble.c Wed Dec 10 04:14:50 2008 -0500
@@ -25,7 +25,7 @@
pd = MOJOSHADER_assemble(buf, NULL, NULL, NULL);
if (pd->error != NULL)
- printf("ERROR: %s\n", pd->error);
+ printf("ERROR: (line %d) %s\n", pd->error_position, pd->error);
else
{
if (pd->output != NULL)
--- a/mojoshader_assembler.c Wed Dec 10 03:55:06 2008 -0500
+++ b/mojoshader_assembler.c Wed Dec 10 04:14:50 2008 -0500
@@ -23,6 +23,7 @@
void *malloc_data;
const char *failstr;
const char *source;
+ int started_parsing;
MOJOSHADER_shaderType shader_type;
uint8 major_ver;
uint8 minor_ver;
@@ -36,6 +37,7 @@
int tokenbufpos;
DestArgInfo dest_arg;
uint32 *output;
+ uint32 *token_to_line;
size_t output_len;
size_t output_allocation;
};
@@ -142,17 +144,30 @@
{
const size_t output_alloc_bump = 1024; // that's tokens, not bytes.
const size_t newsize = ctx->output_allocation + output_alloc_bump;
- void *ptr = Malloc(ctx, newsize * sizeof (uint32));
+ void *ptr;
+
+ ptr = Malloc(ctx, newsize * sizeof (uint32));
if (ptr == NULL)
return;
if (ctx->output_len > 0)
memcpy(ptr, ctx->output, ctx->output_len * sizeof (uint32));
Free(ctx, ctx->output);
+ ctx->output = (uint32 *) ptr;
+
+ ptr = Malloc(ctx, newsize * sizeof (uint32));
+ if (ptr == NULL)
+ return;
+ if (ctx->output_len > 0)
+ memcpy(ptr, ctx->token_to_line, ctx->output_len * sizeof (uint32));
+ Free(ctx, ctx->token_to_line);
+ ctx->token_to_line = (uint32 *) ptr;
+
ctx->output_allocation = newsize;
- ctx->output = (uint32 *) ptr;
} // if
- ctx->output[ctx->output_len++] = token;
+ ctx->output[ctx->output_len] = token;
+ ctx->token_to_line[ctx->output_len] = ctx->linenum;
+ ctx->output_len++;
} // output_token_noswap
@@ -1454,7 +1469,6 @@
ctx->free = f;
ctx->malloc_data = d;
ctx->source = source;
- ctx->linenum = 1;
return ctx;
} // build_context
@@ -1470,6 +1484,8 @@
f((void *) ctx->failstr, d);
if (ctx->output != NULL)
f(ctx->output, d);
+ if (ctx->token_to_line != NULL)
+ f(ctx->token_to_line, d);
f(ctx, d);
} // if
} // destroy_context
@@ -1492,6 +1508,11 @@
retval->error = ctx->failstr; // we recycle. :)
ctx->failstr = NULL; // don't let this get free()'d too soon.
+ if (ctx->started_parsing)
+ retval->error_position = ctx->linenum;
+ else
+ retval->error_position = -1;
+
return retval;
} // build_failed_assembly
@@ -1502,7 +1523,7 @@
const MOJOSHADER_parseData *MOJOSHADER_assemble(const char *source,
MOJOSHADER_malloc m, MOJOSHADER_free f, void *d)
{
- const MOJOSHADER_parseData *retval = NULL;
+ MOJOSHADER_parseData *retval = NULL;
Context *ctx = NULL;
if ( ((m == NULL) && (f != NULL)) || ((m != NULL) && (f == NULL)) )
@@ -1513,8 +1534,10 @@
return &out_of_mem_data;
// Version token always comes first.
+ ctx->started_parsing = 1;
parse_version_token(ctx);
+ ctx->started_parsing = 0; // make error messages sane if CTAB fails, etc.
const char *credit = "Generated by MojoShader assembler revision "
MOJOSHADER_CHANGESET
", http://icculus.org/mojoshader/";
@@ -1522,6 +1545,8 @@
// !!! FIXME: insert CTAB here.
+ ctx->started_parsing = 1;
+
// parse out the rest of the tokens after the version token...
while (nexttoken(ctx, 1, 1, 0, 1) == NOFAIL)
parse_token(ctx);
@@ -1529,7 +1554,7 @@
output_token(ctx, 0x0000FFFF); // end token always 0x0000FFFF.
if (isfail(ctx))
- retval = build_failed_assembly(ctx);
+ retval = (MOJOSHADER_parseData *) build_failed_assembly(ctx);
else
{
// This validates the shader; there are lots of things that are
@@ -1538,10 +1563,22 @@
// duplicate most of the validation here.
// It also saves us the trouble of duplicating all the other work,
// like setting up the uniforms list, etc.
- retval = MOJOSHADER_parse(MOJOSHADER_PROFILE_BYTECODE,
- (const unsigned char *) ctx->output,
- ctx->output_len * sizeof (uint32),
- NULL, 0, m, f, d);
+ retval = (MOJOSHADER_parseData *)
+ MOJOSHADER_parse(MOJOSHADER_PROFILE_BYTECODE,
+ (const unsigned char *) ctx->output,
+ ctx->output_len * sizeof (uint32),
+ NULL, 0, m, f, d);
+
+ // on error, map the bytecode back to a line number.
+ if (retval->error_position >= 0)
+ {
+ assert(retval != &out_of_mem_data);
+ const int pos = retval->error_position / sizeof (uint32);
+ if (pos < ctx->output_len)
+ retval->error_position = ctx->token_to_line[pos];
+ else
+ retval->error_position = -1; // oh well.
+ } // if
} // if
destroy_context(ctx);