mojoshader_assembler.c
changeset 486 45efac751027
parent 485 1cf40e016918
child 487 99302a771d1a
--- 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);