[svn] Cleaned up and improved output and fail state. trunk
authoricculus
Sun, 09 Mar 2008 04:18:31 -0400
branchtrunk
changeset 12 d81712dd1a46
parent 11 c9bb617d9b77
child 13 f2baea592d2a
[svn] Cleaned up and improved output and fail state.
d3d2glsl.c
--- a/d3d2glsl.c	Sun Mar 09 03:08:04 2008 -0400
+++ b/d3d2glsl.c	Sun Mar 09 04:18:31 2008 -0400
@@ -13,19 +13,32 @@
 #include <string.h>
 #include <stdlib.h>
 #include <stdint.h>
+#include <stdarg.h>
 
 #include "d3d2glsl.h"
 
+#ifdef __GNUC__
+#define ISPRINTF(x,y) __attribute__((format (printf, x, y)))
+#else
+#define ISPRINTF(x,y)
+#endif
+
 typedef unsigned int uint;  // this is a printf() helper. don't use for code.
 typedef uint8_t uint8;
 typedef uint32_t uint32;
 
+#define D3D2GLSL_SCRATCH_BUFFER_SIZE 256
+#define D3D2GLSL_SCRATCH_BUFFERS 5
+
 // Context...this is state that changes as we parse through a shader...
 typedef struct D3D2GLSL_context
 {
     const uint32 *tokens;
     uint32 tokencount;
-    char buffers[128][5];  // scratch buffers we cycle through.
+    char *output;
+    uint32 output_len;
+    char *failstr;
+    char buffers[D3D2GLSL_SCRATCH_BUFFER_SIZE][D3D2GLSL_SCRATCH_BUFFERS];
     int bufidx;  // current scratch buffer.
 } D3D2GLSL_context;
 
@@ -49,15 +62,78 @@
 #endif
 
 
+static inline char *get_scratch_buffer(D3D2GLSL_context *ctx)
+{
+    ctx->bufidx = (ctx->bufidx + 1) % D3D2GLSL_SCRATCH_BUFFERS;
+    return ctx->buffers[ctx->bufidx];
+} // get_scratch_buffer
+
+
 // Special-case return values from the parsing pipeline...
-
+#define FAIL (-1)
 #define END_OF_STREAM (-2)
-//#define FAIL(x) (-1)
-static int FAIL(const char *reason)
+
+static int failf(D3D2GLSL_context *ctx, const char *fmt, ...) ISPRINTF(2,3);
+static int failf(D3D2GLSL_context *ctx, const char *fmt, ...)
+{
+    if (ctx->failstr == NULL)  // don't change existing error.
+    {
+        char *buffer = get_scratch_buffer(ctx);
+        va_list ap;
+        va_start(ap, fmt);
+        vsnprintf(buffer, D3D2GLSL_SCRATCH_BUFFER_SIZE, fmt, ap);
+        va_end(ap);
+
+        ctx->failstr = (char *) malloc(strlen(buffer) + 1);
+        if (ctx->failstr != NULL)
+            strcpy(ctx->failstr, buffer);
+    } // if
+
+    return FAIL;
+} // failf
+
+
+static inline int fail(D3D2GLSL_context *ctx, const char *reason)
+{
+    return failf(ctx, "%s", reason);
+} // fail
+
+
+static int output_line(D3D2GLSL_context *ctx, const char *fmt, ...) ISPRINTF(2,3);
+static int output_line(D3D2GLSL_context *ctx, const char *fmt, ...)
 {
-    printf("%s FAIL.\n", reason);
-    return -1;
-} // FAIL
+    if (ctx->failstr != NULL)
+        return FAIL;  // we failed previously, don't go on...
+
+    char *buffer = get_scratch_buffer(ctx);
+    va_list ap;
+    va_start(ap, fmt);
+    const int len = vsnprintf(buffer, D3D2GLSL_SCRATCH_BUFFER_SIZE, fmt, ap);
+    va_end(ap);
+
+    if (len >= D3D2GLSL_SCRATCH_BUFFER_SIZE)
+    {
+        return failf(ctx, "Internal bug--String is too big (%d vs %d bytes).",
+                     (int) len, (int) D3D2GLSL_SCRATCH_BUFFER_SIZE);
+    } // if
+
+    const size_t newlen = ctx->output_len + len + 1;
+    char *ptr = (char *) realloc(ctx->output, newlen+1);
+    if (ptr == NULL)
+        return fail(ctx, "Out of memory");
+
+    memcpy(ptr + ctx->output_len, buffer, len);
+    ptr[newlen-1] = '\n';
+    ptr[newlen] = '\0';
+    ctx->output = ptr;
+    ctx->output_len = newlen;
+    return 0;
+} // output_line
+
+
+static int parse_destination_token(D3D2GLSL_context *ctx)
+{
+} // parse_destination_token
 
 
 // one function for each opcode...
@@ -71,412 +147,412 @@
 
 static int parse_MOV(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_MOV
 
 static int parse_ADD(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_ADD
 
 static int parse_SUB(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_SUB
 
 static int parse_MAD(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_MAD
 
 static int parse_MUL(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_MUL
 
 static int parse_RCP(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_RCP
 
 static int parse_RSQ(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_RSQ
 
 static int parse_DP3(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_DP3
 
 static int parse_DP4(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_DP4
 
 static int parse_MIN(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_MIN
 
 static int parse_MAX(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_MAX
 
 static int parse_SLT(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_SLT
 
 static int parse_SGE(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_SGE
 
 static int parse_EXP(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_EXP
 
 static int parse_LOG(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_LOG
 
 static int parse_LIT(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_LIT
 
 static int parse_DST(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_DST
 
 static int parse_LRP(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_LRP
 
 static int parse_FRC(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_FRC
 
 static int parse_M4X4(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_M4X4
 
 static int parse_M4X3(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_M4X3
 
 static int parse_M3X4(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_M3X4
 
 static int parse_M3X3(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_M3X3
 
 static int parse_M3X2(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_M3X2
 
 static int parse_CALL(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_CALL
 
 static int parse_CALLNZ(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_CALLNZ
 
 static int parse_LOOP(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_LOOP
 
 static int parse_RET(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_RET
 
 static int parse_ENDLOOP(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_ENDLOOP
 
 static int parse_LABEL(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_LABEL
 
 static int parse_DCL(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_DCL
 
 static int parse_POW(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_POW
 
 static int parse_CRS(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_CRS
 
 static int parse_SGN(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_SGN
 
 static int parse_ABS(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_ABS
 
 static int parse_NRM(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_NRM
 
 static int parse_SINCOS(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_SINCOS
 
 static int parse_REP(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_REP
 
 static int parse_ENDREP(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_ENDREP
 
 static int parse_IF(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_IF
 
 static int parse_IFC(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_IFC
 
 static int parse_ELSE(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_ELSE
 
 static int parse_ENDIF(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_ENDIF
 
 static int parse_BREAK(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_BREAK
 
 static int parse_BREAKC(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_BREAKC
 
 static int parse_MOVA(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_MOVA
 
 static int parse_DEFB(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_DEFB
 
 static int parse_DEFI(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_DEFI
 
 static int parse_TEXCOORD(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_TEXCOORD
 
 static int parse_TEXKILL(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_TEXKILL
 
 static int parse_TEX(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_TEX
 
 static int parse_TEXBEM(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_TEXBEM
 
 static int parse_TEXBEML(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_TEXBEML
 
 static int parse_TEXREG2AR(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_TEXREG2AR
 
 static int parse_TEXREG2GB(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_TEXREG2GB
 
 static int parse_TEXM3X2PAD(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_TEXM3X2PAD
 
 static int parse_TEXM3X2TEX(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_TEXM3X2TEX
 
 static int parse_TEXM3X3PAD(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_TEXM3X3PAD
 
 static int parse_TEXM3X3TEX(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_TEXM3X3TEX
 
 static int parse_RESERVED0(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_RESERVED0
 
 static int parse_TEXM3X3SPEC(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_TEXM3X3SPEC
 
 static int parse_TEXM3X3VSPEC(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_TEXM3X3VSPEC
 
 static int parse_EXPP(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_EXPP
 
 static int parse_LOGP(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_LOGP
 
 static int parse_CND(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_CND
 
 static int parse_DEF(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_DEF
 
 static int parse_TEXREG2RGB(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_TEXREG2RGB
 
 static int parse_TEXDP3TEX(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_TEXDP3TEX
 
 static int parse_TEXM3X2DEPTH(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_TEXM3X2DEPTH
 
 static int parse_TEXDP3(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_TEXDP3
 
 static int parse_TEXM3X3(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_TEXM3X3
 
 static int parse_TEXDEPTH(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_TEXDEPTH
 
 static int parse_CMP(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_CMP
 
 static int parse_BEM(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_BEM
 
 static int parse_DP2ADD(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_DP2ADD
 
 static int parse_DSX(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_DSX
 
 static int parse_DSY(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_DSY
 
 static int parse_TEXLDD(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_TEXLDD
 
 static int parse_SETP(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_SETP
 
 static int parse_TEXLDL(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_TEXLDL
 
 static int parse_BREAKP(D3D2GLSL_context *ctx)
 {
-    return FAIL("unimplemented.");  // !!! FIXME
+    return fail(ctx, "unimplemented.");  // !!! FIXME
 } // parse_BREAKP
 
 static int parse_RESERVED(D3D2GLSL_context *ctx)
 {
-    return FAIL("Tried to use RESERVED opcode.");
+    return fail(ctx, "Tried to use RESERVED opcode.");
 } // parse_BREAKP
 
 
@@ -607,21 +683,32 @@
     const int coissue = (token & 0x40000000) ? 1 : 0;
     const int predicated = (token & 0x10000000) ? 1 : 0;
     const Instruction *instruction = &instructions[opcode];
+    int rc = 0;
 
     if ( opcode >= (sizeof (instructions) / sizeof (instructions[0])) )
         return 0;  // not an instruction token, or just not handled here.
 
     if ((token & 0x80000000) != 0)
-        return FAIL("instruction token high bit must be zero.");  // so says msdn.
+        return fail(ctx, "instruction token high bit must be zero.");  // so says msdn.
 
-    printf("%s\n", instruction->opcode_string);
+    // this isn't right.
+    output_line(ctx, instruction->opcode_string);
 
     if (instruction->arg_tokens >= 0)
     {
         if (instruction->arg_tokens != insttoks)
-            return FAIL("unexpected number of tokens for instruction.");
+        {
+            return failf(ctx,
+                    "unexpected number of tokens (%u) for instruction '%s'.",
+                    (uint) insttoks, instruction->opcode_string);
+        } // if
         else if (ctx->tokencount <= instruction->arg_tokens)
-            return FAIL("not enough tokens left in shader for instruction.");
+        {
+            return failf(ctx,
+                    "need more tokens (need %u, got %u) for instruction '%s'.",
+                    (uint) instruction->arg_tokens, (uint) ctx->tokencount,
+                    instruction->opcode_string);
+        } // else if
     } // if
 
 return insttoks + 1;
@@ -632,7 +719,7 @@
 static int parse_version_token(D3D2GLSL_context *ctx)
 {
     if (ctx->tokencount == 0)
-        return FAIL("Expected version token, got none at all.");
+        return fail(ctx, "Expected version token, got none at all.");
 
     const uint32 token = SWAP32(*(ctx->tokens));
     const uint32 shadertype = ((token >> 16) & 0xFFFF);
@@ -640,13 +727,13 @@
     const uint32 minor = (token & 0xFF);
 
     if (shadertype == 0xFFFF)
-        printf("Pixel shader\n");
+        output_line(ctx, "Pixel shader");
     else if (shadertype == 0xFFFE)
-        printf("Vertex shader\n");
+        output_line(ctx, "Vertex shader");
     else
-        return FAIL("geometry shader? Unsupported at the moment.");
+        return fail(ctx, "geometry shader? Unsupported at the moment.");
 
-    printf("Version %u.%u\n", (uint) major, (uint) minor);
+    output_line(ctx, "Version %u.%u", (uint) major, (uint) minor);
 
     return 1;  // ate one token.
 } // parse_version_token
@@ -658,19 +745,17 @@
     if ((token & 0xFFFF) != 0xFFFE)
         return 0;  // not a comment token.
     else if ((token & 0x80000000) != 0)
-        return FAIL("comment token high bit must be zero.");  // so says msdn.
+        return fail(ctx, "comment token high bit must be zero.");  // so says msdn.
 
     const uint32 commenttoks = ((token >> 16) & 0xFFFF);
     const uint32 commentlen = commenttoks * sizeof (uint32);
-    printf("Comment (%u tokens, %u bytes): ",
-            (uint) commenttoks, (uint) commentlen);
+    output_line(ctx, "Comment (%u tokens, %u bytes): ",
+                (uint) commenttoks, (uint) commentlen);
 
-    uint32 i = 0;
-    const char *comment = (const char *) (ctx->tokens+1);
-    while (i < commentlen)
-        fputc(comment[i++], stdout);
-
-    printf("\n");
+//    uint32 i = 0;
+//    const char *comment = (const char *) (ctx->tokens+1);
+//    while (i < commentlen)
+//        fputc(comment[i++], stdout);
 
     return commenttoks + 1;  // comment data plus the initial token.
 } // parse_comment_token
@@ -681,10 +766,10 @@
     if (SWAP32(*(ctx->tokens)) != 0x0000FFFF)   // end token always 0x0000FFFF.
         return 0;  // not us, eat no tokens.
 
-    printf("END\n");
+    output_line(ctx, "END");
 
-    if (ctx->tokencount != 1)  // we _must_ be last. If not: FAIL.
-        return FAIL("end token before end of stream");
+    if (ctx->tokencount != 1)  // we _must_ be last. If not: fail.
+        return fail(ctx, "end token before end of stream");
 
     return END_OF_STREAM;
 } // parse_end_token
@@ -694,7 +779,7 @@
 {
     if (SWAP32(*(ctx->tokens)) != 0x0000FFFD) // phase token always 0x0000FFFD.
         return 0;  // not us, eat no tokens.
-    return FAIL("not sure what this thing is yet.");
+    return fail(ctx, "not sure what this thing is yet.");
 } // parse_phase_token
 
 
@@ -702,8 +787,11 @@
 {
     int rc = 0;
 
+    if (ctx->failstr != NULL)
+        return FAIL;  // just in case...catch previously unhandled fails here.
+
     if (ctx->tokencount == 0)
-        return FAIL("unexpected end of shader.");
+        return fail(ctx, "unexpected end of shader.");
 
     if ((rc = parse_comment_token(ctx)) != 0)
         return rc;
@@ -717,7 +805,7 @@
     if ((rc = parse_instruction_token(ctx)) != 0)
         return rc;
 
-    return FAIL("unknown token");
+    return failf(ctx, "unknown token (%u)", (uint) *ctx->tokens);
 } // parse_token
 
 
@@ -741,6 +829,16 @@
         rc = parse_token(&ctx);
     } // while
 
+    // !!! FIXME: temp
+    if (ctx.output != NULL)
+        printf("%s\n", ctx.output);
+
+    if (ctx.failstr != NULL)
+        printf("FAIL: %s\n", ctx.failstr);
+
+    free(ctx.failstr);
+    free(ctx.output);
+
     return (rc == END_OF_STREAM);
 } // D3D2GLSL_parse