From 7c240118737ae63314c99a2ea505e5921df6fa70 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Tue, 3 Feb 2009 04:14:00 -0500 Subject: [PATCH] More work on multiple error messages. Removed all the FAIL/NOFAIL nastiness, and let errors flow through. Some of these changes are really dicey, especially in the assembler. We'll see what bugs show up now. --- mojoshader.c | 446 ++++++++++++------------ mojoshader_assembler.c | 747 +++++++++++++++++++++++------------------ mojoshader_internal.h | 14 +- 3 files changed, 642 insertions(+), 565 deletions(-) diff --git a/mojoshader.c b/mojoshader.c index 83f85200..47c94bab 100644 --- a/mojoshader.c +++ b/mojoshader.c @@ -9,7 +9,6 @@ // !!! FIXME: this file really needs to be split up. // !!! FIXME: I keep changing coding styles for symbols and typedefs. -// !!! FIXME: this should report all errors, not quit on the first fail(). #define __MOJOSHADER_INTERNAL__ 1 #include "mojoshader_internal.h" @@ -108,12 +107,6 @@ typedef struct ConstantsList struct ConstantsList *next; } ConstantsList; -typedef struct ErrorList -{ - MOJOSHADER_error error; - struct ErrorList *next; -} ErrorList; - typedef struct VariableList { MOJOSHADER_uniformType type; @@ -250,11 +243,9 @@ MOJOSHADER_parseData out_of_mem_data = { 1, &out_of_mem_error, 0, 0, 0, 0, MOJOSHADER_TYPE_UNKNOWN, 0, 0, 0, 0 }; -const char *out_of_mem_str = "Out of memory"; -static inline int out_of_memory(Context *ctx) +static inline void out_of_memory(Context *ctx) { ctx->isfail = ctx->out_of_memory = 1; - return FAIL; } // out_of_memory static inline void *Malloc(Context *ctx, const size_t len) @@ -353,12 +344,12 @@ static inline char *get_scratch_buffer(Context *ctx) } // get_scratch_buffer -static int failf(Context *ctx, const char *fmt, ...) ISPRINTF(2,3); -static int failf(Context *ctx, const char *fmt, ...) +static void failf(Context *ctx, const char *fmt, ...) ISPRINTF(2,3); +static void failf(Context *ctx, const char *fmt, ...) { ctx->isfail = 1; if (ctx->out_of_memory) - return FAIL; + return; int error_position = 0; switch (ctx->parse_phase) @@ -374,12 +365,12 @@ static int failf(Context *ctx, const char *fmt, ...) break; default: assert(0 && "Unexpected value"); - return FAIL; + return; } // switch ErrorList *error = (ErrorList *) Malloc(ctx, sizeof (ErrorList)); if (error == NULL) - return FAIL; + return; char *scratch = get_scratch_buffer(ctx); va_list ap; @@ -421,19 +412,17 @@ static int failf(Context *ctx, const char *fmt, ...) ctx->error_count++; } // else - - return FAIL; } // failf -static inline int fail(Context *ctx, const char *reason) +static inline void fail(Context *ctx, const char *reason) { - return failf(ctx, "%s", reason); + failf(ctx, "%s", reason); } // fail -static int output_line(Context *ctx, const char *fmt, ...) ISPRINTF(2,3); -static int output_line(Context *ctx, const char *fmt, ...) +static void output_line(Context *ctx, const char *fmt, ...) ISPRINTF(2,3); +static void output_line(Context *ctx, const char *fmt, ...) { OutputListNode *item = NULL; @@ -453,13 +442,13 @@ static int output_line(Context *ctx, const char *fmt, ...) item = (OutputListNode *) Malloc(ctx, sizeof (OutputListNode)); if (item == NULL) - return FAIL; + return; item->str = (char *) Malloc(ctx, len + 1); if (item->str == NULL) { Free(ctx, item); - return FAIL; + return; } // if // If we overflowed our scratch buffer, that's okay. We were going to @@ -481,15 +470,13 @@ static int output_line(Context *ctx, const char *fmt, ...) ctx->output->tail->next = item; ctx->output->tail = item; ctx->output_len += len + ctx->endline_len; - - return 0; } // output_line // this is just to stop gcc whining. -static inline int output_blank_line(Context *ctx) +static inline void output_blank_line(Context *ctx) { - return output_line(ctx, "%s", ""); + output_line(ctx, "%s", ""); } // output_blank_line @@ -5030,12 +5017,11 @@ static const struct { const char *from; const char *to; } profileMap[] = static int parse_destination_token(Context *ctx, DestArgInfo *info) { // !!! FIXME: recheck against the spec for ranges (like RASTOUT values, etc). - - if (isfail(ctx)) - return FAIL; // already failed elsewhere. - if (ctx->tokencount == 0) - return fail(ctx, "Out of tokens in destination parameter"); + { + fail(ctx, "Out of tokens in destination parameter"); + return 0; + } // if const uint32 token = SWAP32(*(ctx->tokens)); const int reserved1 = (int) ((token >> 14) & 0x3); // bits 14 through 15 @@ -5083,57 +5069,56 @@ static int parse_destination_token(Context *ctx, DestArgInfo *info) ctx->tokencount--; // swallow token for now, for multiple calls in a row. if (reserved1 != 0x0) - return fail(ctx, "Reserved bit #1 in destination token must be zero"); + fail(ctx, "Reserved bit #1 in destination token must be zero"); if (reserved2 != 0x1) - return fail(ctx, "Reserved bit #2 in destination token must be one"); + fail(ctx, "Reserved bit #2 in destination token must be one"); if (info->relative) { if (!shader_is_vertex(ctx)) - return fail(ctx, "Relative addressing in non-vertex shader"); - else if (!shader_version_atleast(ctx, 3, 0)) - return fail(ctx, "Relative addressing in vertex shader version < 3.0"); - else if (!ctx->have_ctab) // it's hard to do this efficiently without! - return fail(ctx, "relative addressing unsupported without a CTAB"); + fail(ctx, "Relative addressing in non-vertex shader"); + if (!shader_version_atleast(ctx, 3, 0)) + fail(ctx, "Relative addressing in vertex shader version < 3.0"); + if (!ctx->have_ctab) // it's hard to do this efficiently without! + fail(ctx, "relative addressing unsupported without a CTAB"); + // !!! FIXME: I don't have a shader that has a relative dest currently. - return fail(ctx, "Relative addressing of dest tokens is unsupported"); + fail(ctx, "Relative addressing of dest tokens is unsupported"); + return 2; } // if const int s = info->result_shift; if (s != 0) { if (!shader_is_pixel(ctx)) - return fail(ctx, "Result shift scale in non-pixel shader"); - else if (shader_version_atleast(ctx, 2, 0)) - return fail(ctx, "Result shift scale in pixel shader version >= 2.0"); - else if ( ! (((s >= 1) && (s <= 3)) || ((s >= 0xD) && (s <= 0xF))) ) - return fail(ctx, "Result shift scale isn't 1 to 3, or 13 to 15."); + fail(ctx, "Result shift scale in non-pixel shader"); + if (shader_version_atleast(ctx, 2, 0)) + fail(ctx, "Result shift scale in pixel shader version >= 2.0"); + if ( ! (((s >= 1) && (s <= 3)) || ((s >= 0xD) && (s <= 0xF))) ) + fail(ctx, "Result shift scale isn't 1 to 3, or 13 to 15."); } // if if (info->result_mod & MOD_PP) // Partial precision (pixel shaders only) { if (!shader_is_pixel(ctx)) - return fail(ctx, "Partial precision result mod in non-pixel shader"); + fail(ctx, "Partial precision result mod in non-pixel shader"); } // if if (info->result_mod & MOD_CENTROID) // Centroid (pixel shaders only) { if (!shader_is_pixel(ctx)) - return fail(ctx, "Centroid result mod in non-pixel shader"); + fail(ctx, "Centroid result mod in non-pixel shader"); else if (!ctx->centroid_allowed) // only on DCL opcodes! - return fail(ctx, "Centroid modifier not allowed here"); + fail(ctx, "Centroid modifier not allowed here"); } // if if ((info->regtype < 0) || (info->regtype > REG_TYPE_MAX)) - return fail(ctx, "Register type is out of range"); + fail(ctx, "Register type is out of range"); - // !!! FIXME: from msdn: - // "_sat cannot be used with instructions writing to output o# registers." - // !!! FIXME: actually, just go over this page: - // http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/reference/shaders/ps_instructionmodifiers.asp + if (!isfail(ctx)) + set_used_register(ctx, info->regtype, info->regnum); - set_used_register(ctx, info->regtype, info->regnum); return 1; } // parse_destination_token @@ -5270,11 +5255,11 @@ static int parse_source_token(Context *ctx, SourceArgInfo *info) { int retval = 1; - if (isfail(ctx)) - return FAIL; // already failed elsewhere. - if (ctx->tokencount == 0) - return fail(ctx, "Out of tokens in source parameter"); + { + fail(ctx, "Out of tokens in source parameter"); + return 0; + } // if const uint32 token = SWAP32(*(ctx->tokens)); const int reserved1 = (int) ((token >> 14) & 0x3); // bits 14 through 15 @@ -5315,18 +5300,21 @@ static int parse_source_token(Context *ctx, SourceArgInfo *info) ctx->tokencount--; // swallow token for now, for multiple calls in a row. if (reserved1 != 0x0) - return fail(ctx, "Reserved bits #1 in source token must be zero"); + fail(ctx, "Reserved bits #1 in source token must be zero"); if (reserved2 != 0x1) - return fail(ctx, "Reserved bit #2 in source token must be one"); + fail(ctx, "Reserved bit #2 in source token must be one"); + + if ((info->relative) && (ctx->tokencount == 0)) + { + fail(ctx, "Out of tokens in relative source parameter"); + info->relative = 0; // don't try to process it. + } // if if (info->relative) { if ( (shader_is_pixel(ctx)) && (!shader_version_atleast(ctx, 3, 0)) ) - return fail(ctx, "Relative addressing in pixel shader version < 3.0"); - - if (ctx->tokencount == 0) - return fail(ctx, "Out of tokens in relative source parameter"); + fail(ctx, "Relative addressing in pixel shader version < 3.0"); const uint32 reltoken = SWAP32(*(ctx->tokens)); ctx->tokens++; // swallow token for now, for multiple calls in a row. @@ -5339,10 +5327,10 @@ static int parse_source_token(Context *ctx, SourceArgInfo *info) ((reltoken >> 8) & 0x18)); if (((reltoken >> 31) & 0x1) == 0) - return fail(ctx, "bit #31 in relative address must be set"); + fail(ctx, "bit #31 in relative address must be set"); if ((reltoken & 0xF00E000) != 0) // usused bits. - return fail(ctx, "relative address reserved bit must be zero"); + fail(ctx, "relative address reserved bit must be zero"); switch (info->relative_regtype) { @@ -5350,48 +5338,51 @@ static int parse_source_token(Context *ctx, SourceArgInfo *info) case REG_TYPE_ADDRESS: break; default: - return fail(ctx, "invalid register for relative address"); + fail(ctx, "invalid register for relative address"); break; } // switch if (info->relative_regnum != 0) // true for now. - return fail(ctx, "invalid register for relative address"); + fail(ctx, "invalid register for relative address"); if (!replicate_swizzle(relswiz)) - return fail(ctx, "relative address needs replicate swizzle"); + fail(ctx, "relative address needs replicate swizzle"); if (info->regtype == REG_TYPE_INPUT) { if ( (shader_is_pixel(ctx)) || (!shader_version_atleast(ctx, 3, 0)) ) - return fail(ctx, "relative addressing of input registers not supported in this shader model"); + fail(ctx, "relative addressing of input registers not supported in this shader model"); ctx->have_relative_input_registers = 1; } // if else if (info->regtype == REG_TYPE_CONST) { // figure out what array we're in... if (!ctx->have_ctab) // it's hard to do this efficiently without! - return fail(ctx, "relative addressing unsupported without a CTAB"); - determine_constants_arrays(ctx); - - VariableList *var; - const int reltarget = info->regnum; - for (var = ctx->variables; var != NULL; var = var->next) + fail(ctx, "relative addressing unsupported without a CTAB"); + else { - const int lo = var->index; - if ( (reltarget >= lo) && (reltarget < (lo + var->count)) ) - break; // match! - } // for + determine_constants_arrays(ctx); + + VariableList *var; + const int reltarget = info->regnum; + for (var = ctx->variables; var != NULL; var = var->next) + { + const int lo = var->index; + if ( (reltarget >= lo) && (reltarget < (lo + var->count)) ) + break; // match! + } // for - if (var == NULL) - return fail(ctx, "relative addressing of indeterminate array"); + if (var == NULL) + fail(ctx, "relative addressing of indeterminate array"); - var->used = 1; - info->relative_array = var; - set_used_register(ctx, info->relative_regtype, info->relative_regnum); + var->used = 1; + info->relative_array = var; + set_used_register(ctx, info->relative_regtype, info->relative_regnum); + } // else } // else if else { - return fail(ctx, "relative addressing of invalid register"); + fail(ctx, "relative addressing of invalid register"); } // else retval++; @@ -5416,19 +5407,19 @@ static int parse_source_token(Context *ctx, SourceArgInfo *info) case SRCMOD_DZ: case SRCMOD_DW: if (shader_version_atleast(ctx, 2, 0)) - return fail(ctx, "illegal source mod for this Shader Model."); + fail(ctx, "illegal source mod for this Shader Model."); break; case SRCMOD_NOT: // !!! FIXME: I _think_ this is right... if (shader_version_atleast(ctx, 2, 0)) { if (info->regtype != REG_TYPE_PREDICATE) - return fail(ctx, "NOT only allowed on predicate register."); + fail(ctx, "NOT only allowed on predicate register."); } // if break; default: - return fail(ctx, "Unknown source modifier"); + fail(ctx, "Unknown source modifier"); } // switch // !!! FIXME: docs say this for sm3 ... check these! @@ -5440,7 +5431,9 @@ static int parse_source_token(Context *ctx, SourceArgInfo *info) // All of the constant floating-point registers must use the abs modifier. // None of the constant floating-point registers can use the abs modifier. - set_used_register(ctx, info->regtype, info->regnum); + if (!isfail(ctx)) + set_used_register(ctx, info->regtype, info->regnum); + return retval; } // parse_source_token @@ -5448,16 +5441,15 @@ static int parse_source_token(Context *ctx, SourceArgInfo *info) static int parse_predicated_token(Context *ctx) { SourceArgInfo *arg = &ctx->predicate_arg; - if (parse_source_token(ctx, arg) == FAIL) - return FAIL; - else if (arg->regtype != REG_TYPE_PREDICATE) - return fail(ctx, "Predicated instruction but not predicate register!"); - else if ((arg->src_mod != SRCMOD_NONE) && (arg->src_mod != SRCMOD_NOT)) - return fail(ctx, "Predicated instruction register is not NONE or NOT"); - else if ( !no_swizzle(arg->swizzle) && !replicate_swizzle(arg->swizzle) ) - return fail(ctx, "Predicated instruction register has wrong swizzle"); - else if (arg->relative) // I'm pretty sure this is illegal...? - return fail(ctx, "relative addressing in predicated token"); + parse_source_token(ctx, arg); + if (arg->regtype != REG_TYPE_PREDICATE) + fail(ctx, "Predicated instruction but not predicate register!"); + if ((arg->src_mod != SRCMOD_NONE) && (arg->src_mod != SRCMOD_NOT)) + fail(ctx, "Predicated instruction register is not NONE or NOT"); + if ( !no_swizzle(arg->swizzle) && !replicate_swizzle(arg->swizzle) ) + fail(ctx, "Predicated instruction register has wrong swizzle"); + if (arg->relative) // I'm pretty sure this is illegal...? + fail(ctx, "relative addressing in predicated token"); return 1; } // parse_predicated_token @@ -5465,18 +5457,17 @@ static int parse_predicated_token(Context *ctx) static int parse_args_NULL(Context *ctx) { - return (isfail(ctx) ? FAIL : 1); + return 1; } // parse_args_NULL static int parse_args_DEF(Context *ctx) { - if (parse_destination_token(ctx, &ctx->dest_arg) == FAIL) - return FAIL; - else if (ctx->dest_arg.regtype != REG_TYPE_CONST) - return fail(ctx, "DEF using non-CONST register"); - else if (ctx->dest_arg.relative) // I'm pretty sure this is illegal...? - return fail(ctx, "relative addressing in DEF"); + parse_destination_token(ctx, &ctx->dest_arg); + if (ctx->dest_arg.regtype != REG_TYPE_CONST) + fail(ctx, "DEF using non-CONST register"); + if (ctx->dest_arg.relative) // I'm pretty sure this is illegal...? + fail(ctx, "relative addressing in DEF"); ctx->dwords[0] = SWAP32(ctx->tokens[0]); ctx->dwords[1] = SWAP32(ctx->tokens[1]); @@ -5489,12 +5480,11 @@ static int parse_args_DEF(Context *ctx) static int parse_args_DEFI(Context *ctx) { - if (parse_destination_token(ctx, &ctx->dest_arg) == FAIL) - return FAIL; - else if (ctx->dest_arg.regtype != REG_TYPE_CONSTINT) - return fail(ctx, "DEFI using non-CONSTING register"); - else if (ctx->dest_arg.relative) // I'm pretty sure this is illegal...? - return fail(ctx, "relative addressing in DEFI"); + parse_destination_token(ctx, &ctx->dest_arg); + if (ctx->dest_arg.regtype != REG_TYPE_CONSTINT) + fail(ctx, "DEFI using non-CONSTING register"); + if (ctx->dest_arg.relative) // I'm pretty sure this is illegal...? + fail(ctx, "relative addressing in DEFI"); ctx->dwords[0] = SWAP32(ctx->tokens[0]); ctx->dwords[1] = SWAP32(ctx->tokens[1]); @@ -5507,12 +5497,11 @@ static int parse_args_DEFI(Context *ctx) static int parse_args_DEFB(Context *ctx) { - if (parse_destination_token(ctx, &ctx->dest_arg) == FAIL) - return FAIL; - else if (ctx->dest_arg.regtype != REG_TYPE_CONSTBOOL) - return fail(ctx, "DEFB using non-CONSTBOOL register"); - else if (ctx->dest_arg.relative) // I'm pretty sure this is illegal...? - return fail(ctx, "relative addressing in DEFB"); + parse_destination_token(ctx, &ctx->dest_arg); + if (ctx->dest_arg.regtype != REG_TYPE_CONSTBOOL) + fail(ctx, "DEFB using non-CONSTBOOL register"); + if (ctx->dest_arg.relative) // I'm pretty sure this is illegal...? + fail(ctx, "relative addressing in DEFB"); ctx->dwords[0] = *(ctx->tokens) ? 1 : 0; @@ -5543,20 +5532,18 @@ static int parse_args_DCL(Context *ctx) uint32 reserved_mask = 0x00000000; if (reserved1 != 0x1) - return fail(ctx, "Bit #31 in DCL token must be one"); + fail(ctx, "Bit #31 in DCL token must be one"); ctx->centroid_allowed = 1; ctx->tokens++; ctx->tokencount--; - const int parse_dest_rc = parse_destination_token(ctx, &ctx->dest_arg); + parse_destination_token(ctx, &ctx->dest_arg); ctx->centroid_allowed = 0; - if (parse_dest_rc == FAIL) - return FAIL; if (ctx->dest_arg.result_shift != 0) // I'm pretty sure this is illegal...? - return fail(ctx, "shift scale in DCL"); - else if (ctx->dest_arg.relative) // I'm pretty sure this is illegal...? - return fail(ctx, "relative addressing in DCL"); + fail(ctx, "shift scale in DCL"); + if (ctx->dest_arg.relative) // I'm pretty sure this is illegal...? + fail(ctx, "relative addressing in DCL"); const RegisterType regtype = ctx->dest_arg.regtype; const int regnum = ctx->dest_arg.regnum; @@ -5580,11 +5567,11 @@ static int parse_args_DCL(Context *ctx) { reserved_mask = 0x7FFFFFFF; if (!writemask_xyzw(ctx->dest_arg.orig_writemask)) - return fail(ctx, "DCL face writemask must be full"); - else if (ctx->dest_arg.result_mod != 0) - return fail(ctx, "DCL face result modifier must be zero"); - else if (ctx->dest_arg.result_shift != 0) - return fail(ctx, "DCL face shift scale must be zero"); + fail(ctx, "DCL face writemask must be full"); + if (ctx->dest_arg.result_mod != 0) + fail(ctx, "DCL face result modifier must be zero"); + if (ctx->dest_arg.result_shift != 0) + fail(ctx, "DCL face shift scale must be zero"); } // else if else { @@ -5602,16 +5589,16 @@ static int parse_args_DCL(Context *ctx) if (usage == MOJOSHADER_USAGE_TEXCOORD) { if (index > 7) - return fail(ctx, "DCL texcoord usage must have 0-7 index"); + fail(ctx, "DCL texcoord usage must have 0-7 index"); } // if else if (usage == MOJOSHADER_USAGE_COLOR) { if (index != 0) - return fail(ctx, "DCL color usage must have 0 index"); + fail(ctx, "DCL color usage must have 0 index"); } // else if else { - return fail(ctx, "Invalid DCL texture usage"); + fail(ctx, "Invalid DCL texture usage"); } // else reserved_mask = 0x7FF0FFE0; @@ -5623,7 +5610,7 @@ static int parse_args_DCL(Context *ctx) { const uint32 ttype = ((token >> 27) & 0xF); if (!valid_texture_type(ttype)) - return fail(ctx, "unknown sampler texture type"); + fail(ctx, "unknown sampler texture type"); reserved_mask = 0x7FFFFFF; ctx->dwords[0] = ttype; } // else if @@ -5652,7 +5639,7 @@ static int parse_args_DCL(Context *ctx) { const uint32 ttype = ((token >> 27) & 0xF); if (!valid_texture_type(ttype)) - return fail(ctx, "unknown sampler texture type"); + fail(ctx, "unknown sampler texture type"); reserved_mask = 0x7FFFFFF; ctx->dwords[0] = ttype; } // else if @@ -5700,10 +5687,10 @@ static int parse_args_DCL(Context *ctx) } // else if (unsupported) - return fail(ctx, "invalid DCL register type for this shader model"); + fail(ctx, "invalid DCL register type for this shader model"); if ((token & reserved_mask) != 0) - return fail(ctx, "reserved bits in DCL dword aren't zero"); + fail(ctx, "reserved bits in DCL dword aren't zero"); return 3; } // parse_args_DCL @@ -5713,7 +5700,7 @@ static int parse_args_D(Context *ctx) { int retval = 1; retval += parse_destination_token(ctx, &ctx->dest_arg); - return isfail(ctx) ? FAIL : retval; + return retval; } // parse_args_D @@ -5721,7 +5708,7 @@ static int parse_args_S(Context *ctx) { int retval = 1; retval += parse_source_token(ctx, &ctx->source_args[0]); - return isfail(ctx) ? FAIL : retval; + return retval; } // parse_args_S @@ -5730,7 +5717,7 @@ static int parse_args_SS(Context *ctx) int retval = 1; retval += parse_source_token(ctx, &ctx->source_args[0]); retval += parse_source_token(ctx, &ctx->source_args[1]); - return isfail(ctx) ? FAIL : retval; + return retval; } // parse_args_SS @@ -5739,7 +5726,7 @@ static int parse_args_DS(Context *ctx) int retval = 1; retval += parse_destination_token(ctx, &ctx->dest_arg); retval += parse_source_token(ctx, &ctx->source_args[0]); - return isfail(ctx) ? FAIL : retval; + return retval; } // parse_args_DS @@ -5749,7 +5736,7 @@ static int parse_args_DSS(Context *ctx) retval += parse_destination_token(ctx, &ctx->dest_arg); retval += parse_source_token(ctx, &ctx->source_args[0]); retval += parse_source_token(ctx, &ctx->source_args[1]); - return isfail(ctx) ? FAIL : retval; + return retval; } // parse_args_DSS @@ -5760,7 +5747,7 @@ static int parse_args_DSSS(Context *ctx) retval += parse_source_token(ctx, &ctx->source_args[0]); retval += parse_source_token(ctx, &ctx->source_args[1]); retval += parse_source_token(ctx, &ctx->source_args[2]); - return isfail(ctx) ? FAIL : retval; + return retval; } // parse_args_DSSS @@ -5772,7 +5759,7 @@ static int parse_args_DSSSS(Context *ctx) retval += parse_source_token(ctx, &ctx->source_args[1]); retval += parse_source_token(ctx, &ctx->source_args[2]); retval += parse_source_token(ctx, &ctx->source_args[3]); - return isfail(ctx) ? FAIL : retval; + return retval; } // parse_args_DSSSS @@ -6047,25 +6034,20 @@ static void state_RET(Context *ctx) fail(ctx, "REP without ENDREP"); } // state_RET -static int check_label_register(Context *ctx, int arg, const char *opcode) +static void check_label_register(Context *ctx, int arg, const char *opcode) { const SourceArgInfo *info = &ctx->source_args[arg]; const RegisterType regtype = info->regtype; const int regnum = info->regnum; if (regtype != REG_TYPE_LABEL) - return failf(ctx, "%s with a non-label register specified", opcode); - - else if (!shader_version_atleast(ctx, 2, 0)) - return failf(ctx, "%s not supported in Shader Model 1", opcode); - - else if ((shader_version_atleast(ctx, 2, 255)) && (regnum > 2047)) - return failf(ctx, "label register number must be <= 2047"); - - else if (regnum > 15) - return failf(ctx, "label register number must be <= 15"); - - return 0; + failf(ctx, "%s with a non-label register specified", opcode); + if (!shader_version_atleast(ctx, 2, 0)) + failf(ctx, "%s not supported in Shader Model 1", opcode); + if ((shader_version_atleast(ctx, 2, 255)) && (regnum > 2047)) + fail(ctx, "label register number must be <= 2047"); + if (regnum > 15) + fail(ctx, "label register number must be <= 15"); } // check_label_register static void state_LABEL(Context *ctx) @@ -6100,8 +6082,8 @@ static void check_call_loop_wrappage(Context *ctx, const int regnum) static void state_CALL(Context *ctx) { - if (check_label_register(ctx, 0, "CALL") != FAIL) - check_call_loop_wrappage(ctx, ctx->source_args[0].regnum); + check_label_register(ctx, 0, "CALL"); + check_call_loop_wrappage(ctx, ctx->source_args[0].regnum); } // state_CALL static void state_CALLNZ(Context *ctx) @@ -6109,8 +6091,8 @@ static void state_CALLNZ(Context *ctx) const RegisterType regtype = ctx->source_args[1].regtype; if ((regtype != REG_TYPE_CONSTBOOL) && (regtype != REG_TYPE_PREDICATE)) fail(ctx, "CALLNZ argument isn't constbool or predicate register"); - else if (check_label_register(ctx, 0, "CALLNZ") != FAIL) - check_call_loop_wrappage(ctx, ctx->source_args[0].regnum); + check_label_register(ctx, 0, "CALLNZ"); + check_call_loop_wrappage(ctx, ctx->source_args[0].regnum); } // state_CALLNZ static void state_MOVA(Context *ctx) @@ -6444,7 +6426,7 @@ static const Instruction instructions[] = static int parse_instruction_token(Context *ctx) { - int retval = NOFAIL; + int retval = 0; const uint32 *start_tokens = ctx->tokens; const uint32 start_tokencount = ctx->tokencount; const uint32 token = SWAP32(*(ctx->tokens)); @@ -6461,24 +6443,28 @@ static int parse_instruction_token(Context *ctx) const emit_function emitter = instruction->emitter[ctx->profileid]; if ((token & 0x80000000) != 0) - return fail(ctx, "instruction token high bit must be zero."); // so says msdn. - else if (instruction->opcode_string == NULL) - return fail(ctx, "Unknown opcode."); + fail(ctx, "instruction token high bit must be zero."); // so says msdn. + + if (instruction->opcode_string == NULL) + { + fail(ctx, "Unknown opcode."); + return 1; // pray that you resync later. + } // if if (coissue) { if (!shader_is_pixel(ctx)) - return fail(ctx, "coissue instruction on non-pixel shader"); - else if (shader_version_atleast(ctx, 2, 0)) - return fail(ctx, "coissue instruction in Shader Model >= 2.0"); + fail(ctx, "coissue instruction on non-pixel shader"); + if (shader_version_atleast(ctx, 2, 0)) + fail(ctx, "coissue instruction in Shader Model >= 2.0"); // !!! FIXME: I'm not sure what this actually means, yet. - return fail(ctx, "coissue instructions unsupported"); + fail(ctx, "coissue instructions unsupported"); } // if if ((ctx->shader_type & instruction->shader_types) == 0) { - return failf(ctx, "opcode '%s' not available in this shader type.", - instruction->opcode_string); + failf(ctx, "opcode '%s' not available in this shader type.", + instruction->opcode_string); } // if memset(ctx->dwords, '\0', sizeof (ctx->dwords)); @@ -6489,52 +6475,40 @@ static int parse_instruction_token(Context *ctx) ctx->tokens++; ctx->tokencount--; retval = instruction->parse_args(ctx); - assert((isfail(ctx)) || (retval >= 0)); - if ( (!isfail(ctx)) && (predicated) ) - { - if (parse_predicated_token(ctx) != FAIL) - retval++; // one more token. - } // if + if (predicated) + retval += parse_predicated_token(ctx); // parse_args() moves these forward for convenience...reset them. ctx->tokens = start_tokens; ctx->tokencount = start_tokencount; - if (!isfail(ctx)) - { - if (instruction->state != NULL) - instruction->state(ctx); - } // if + if (instruction->state != NULL) + instruction->state(ctx); ctx->instruction_count += instruction->slots; - if (isfail(ctx)) - retval = FAIL; - else + if (!isfail(ctx)) emitter(ctx); // call the profile's emitter. ctx->previous_opcode = opcode; ctx->scratch_registers = 0; // reset after every instruction. - if (!isfail(ctx)) + if (!shader_version_atleast(ctx, 2, 0)) { - if (!shader_version_atleast(ctx, 2, 0)) + if (insttoks != 0) // reserved field in shaders < 2.0 ... + fail(ctx, "instruction token count must be zero"); + } // if + else + { + if (retval != (insttoks+1)) { - if (insttoks != 0) // reserved field in shaders < 2.0 ... - return fail(ctx, "instruction token count must be zero"); + failf(ctx, "wrong token count (%u, not %u) for opcode '%s'.", + (uint) retval, (uint) (insttoks+1), + instruction->opcode_string); + retval = insttoks + 1; // try to keep sync. } // if - else - { - if (retval != (insttoks+1)) - { - return failf(ctx, - "wrong token count (%u, not %u) for opcode '%s'.", - (uint) retval, (uint) (insttoks+1), - instruction->opcode_string); - } // if - } // else - } // if + } // else return retval; } // parse_instruction_token @@ -6543,7 +6517,10 @@ static int parse_instruction_token(Context *ctx) static int parse_version_token(Context *ctx, const char *profilestr) { if (ctx->tokencount == 0) - return fail(ctx, "Expected version token, got none at all."); + { + fail(ctx, "Expected version token, got none at all."); + return 0; + } // if const uint32 token = SWAP32(*(ctx->tokens)); const uint32 shadertype = ((token >> 16) & 0xFFFF); @@ -6565,7 +6542,7 @@ static int parse_version_token(Context *ctx, const char *profilestr) } // else if else // geometry shader? Bogus data? { - return fail(ctx, "Unsupported shader type or not a shader at all"); + fail(ctx, "Unsupported shader type or not a shader at all"); } // else ctx->major_ver = major; @@ -6573,11 +6550,13 @@ static int parse_version_token(Context *ctx, const char *profilestr) if (!shader_version_supported(major, minor)) { - return failf(ctx, "Shader Model %u.%u is currently unsupported.", - (uint) major, (uint) minor); + failf(ctx, "Shader Model %u.%u is currently unsupported.", + (uint) major, (uint) minor); } // if - ctx->profile->start_emitter(ctx, profilestr); + if (!isfail(ctx)) + ctx->profile->start_emitter(ctx, profilestr); + return 1; // ate one token. } // parse_version_token @@ -6666,18 +6645,13 @@ static int parse_comment_token(Context *ctx) const uint32 token = SWAP32(*(ctx->tokens)); if ((token & 0xFFFF) != 0xFFFE) return 0; // not a comment token. - else if ((token & 0x80000000) != 0) - return fail(ctx, "comment token high bit must be zero."); // so says msdn. - else - { - const uint32 commenttoks = ((token >> 16) & 0xFFFF); - if ((commenttoks >= 8) && (commenttoks < ctx->tokencount)) - parse_constant_table(ctx, commenttoks * 4); - return commenttoks + 1; // comment data plus the initial token. - } // else + if ((token & 0x80000000) != 0) + fail(ctx, "comment token high bit must be zero."); // so says msdn. - // shouldn't hit this. - return failf(ctx, "Logic error at %s:%d", __FILE__, __LINE__); + const uint32 commenttoks = ((token >> 16) & 0xFFFF); + if ((commenttoks >= 8) && (commenttoks < ctx->tokencount)) + parse_constant_table(ctx, commenttoks * 4); + return commenttoks + 1; // comment data plus the initial token. } // parse_comment_token @@ -6687,11 +6661,12 @@ static int parse_end_token(Context *ctx) return 0; // not us, eat no tokens. if (ctx->tokencount != 1) // we _must_ be last. If not: fail. - return fail(ctx, "end token before end of stream"); + fail(ctx, "end token before end of stream"); - ctx->profile->end_emitter(ctx); + if (!isfail(ctx)) + ctx->profile->end_emitter(ctx); - return END_OF_STREAM; + return 1; } // parse_end_token @@ -6700,9 +6675,13 @@ static int parse_phase_token(Context *ctx) // !!! FIXME: needs state; allow only one phase token per shader, I think? if (SWAP32(*(ctx->tokens)) != 0x0000FFFD) // phase token always 0x0000FFFD. return 0; // not us, eat no tokens. - else if ( (!shader_is_pixel(ctx)) || (!shader_version_exactly(ctx, 1, 4)) ) - return fail(ctx, "phase token only available in 1.4 pixel shaders"); - ctx->profile->phase_emitter(ctx); + + if ( (!shader_is_pixel(ctx)) || (!shader_version_exactly(ctx, 1, 4)) ) + fail(ctx, "phase token only available in 1.4 pixel shaders"); + + if (!isfail(ctx)) + ctx->profile->phase_emitter(ctx); + return 1; } // parse_phase_token @@ -6711,11 +6690,10 @@ static int parse_token(Context *ctx) { int rc = 0; - if (ctx->output_stack_len != 0) - return fail(ctx, "BUG: output stack isn't empty on new token!"); + assert(ctx->output_stack_len == 0); - else if (ctx->tokencount == 0) - return fail(ctx, "unexpected end of shader."); + if (ctx->tokencount == 0) + fail(ctx, "unexpected end of shader."); else if ((rc = parse_comment_token(ctx)) != 0) return rc; @@ -6729,7 +6707,8 @@ static int parse_token(Context *ctx) else if ((rc = parse_instruction_token(ctx)) != 0) return rc; - return failf(ctx, "unknown token (%u)", (uint) *ctx->tokens); + failf(ctx, "unknown token (%u)", (uint) *ctx->tokens); + return 1; // good luck! } // parse_token @@ -7486,7 +7465,7 @@ const MOJOSHADER_parseData *MOJOSHADER_parse(const char *profile, { MOJOSHADER_parseData *retval = NULL; Context *ctx = NULL; - int rc = FAIL; + int rc = 0; int failed = 0; if ( ((m == NULL) && (f != NULL)) || ((m != NULL) && (f == NULL)) ) @@ -7499,14 +7478,11 @@ const MOJOSHADER_parseData *MOJOSHADER_parse(const char *profile, verify_swizzles(ctx); // Version token always comes first. - if (!isfail(ctx)) - { - ctx->parse_phase = MOJOSHADER_PARSEPHASE_WORKING; - rc = parse_version_token(ctx, profile); - } // if + ctx->parse_phase = MOJOSHADER_PARSEPHASE_WORKING; + rc = parse_version_token(ctx, profile); // parse out the rest of the tokens after the version token... - while (rc > 0) + while (ctx->tokencount > 0) { // reset for each token. if (isfail(ctx)) diff --git a/mojoshader_assembler.c b/mojoshader_assembler.c index acdffef1..298a1e09 100644 --- a/mojoshader_assembler.c +++ b/mojoshader_assembler.c @@ -7,8 +7,6 @@ * This file written by Ryan C. Gordon. */ -// !!! FIXME: this should report all errors, not quit on the first fail(). - #define __MOJOSHADER_INTERNAL__ 1 #include "mojoshader_internal.h" @@ -37,10 +35,14 @@ typedef struct SourcePos // Context...this is state that changes as we assemble a shader... typedef struct Context { + int isfail; + int out_of_memory; + int eof; MOJOSHADER_malloc malloc; MOJOSHADER_free free; void *malloc_data; - const char *failstr; + int error_count; + ErrorList *errors; TokenizerContext tctx; MOJOSHADER_parsePhase parse_phase; MOJOSHADER_shaderType shader_type; @@ -62,11 +64,9 @@ typedef struct Context // Convenience functions for allocators... -static inline int out_of_memory(Context *ctx) +static inline void out_of_memory(Context *ctx) { - if (ctx->failstr == NULL) - ctx->failstr = out_of_mem_str; // fail() would call malloc(). - return FAIL; + ctx->isfail = ctx->out_of_memory = 1; } // out_of_memory static inline void *Malloc(Context *ctx, const size_t len) @@ -77,44 +77,100 @@ static inline void *Malloc(Context *ctx, const size_t len) return retval; } // Malloc +static inline char *StrDup(Context *ctx, const char *str) +{ + char *retval = (char *) Malloc(ctx, strlen(str) + 1); + if (retval == NULL) + out_of_memory(ctx); + else + strcpy(retval, str); + return retval; +} // StrDup + static inline void Free(Context *ctx, void *ptr) { if (ptr != NULL) // check for NULL in case of dumb free() impl. ctx->free(ptr, ctx->malloc_data); } // Free -static int failf(Context *ctx, const char *fmt, ...) ISPRINTF(2,3); -static int failf(Context *ctx, const char *fmt, ...) +static void failf(Context *ctx, const char *fmt, ...) ISPRINTF(2,3); +static void failf(Context *ctx, const char *fmt, ...) { - if (ctx->failstr == NULL) // don't change existing error. + const char *fname = NULL; + unsigned int linenum = 0; + int error_position = 0; + + switch (ctx->parse_phase) + { + case MOJOSHADER_PARSEPHASE_NOTSTARTED: + error_position = -2; + break; + case MOJOSHADER_PARSEPHASE_WORKING: + // !!! FIXME: fname == base source file if output_pos == 0. + if (ctx->output_len > 0) + { + const size_t idx = ctx->output_len - 1; + linenum = ctx->token_to_source[idx].line; + fname = ctx->token_to_source[idx].filename; + } // if + error_position = linenum; + break; + case MOJOSHADER_PARSEPHASE_DONE: + error_position = -1; + break; + default: + assert(0 && "Unexpected value"); + return; + } // switch + + ErrorList *error = (ErrorList *) Malloc(ctx, sizeof (ErrorList)); + if (error == NULL) + return; + + char scratch = 0; + va_list ap; + va_start(ap, fmt); + const int len = vsnprintf(&scratch, sizeof (scratch), fmt, ap); + va_end(ap); + + char *failstr = (char *) Malloc(ctx, len + 1); + if (failstr == NULL) + Free(ctx, error); + else { - char scratch = 0; - va_list ap; va_start(ap, fmt); - const int len = vsnprintf(&scratch, sizeof (scratch), fmt, ap); + vsnprintf(failstr, len + 1, fmt, ap); // rebuild it. va_end(ap); - char *failstr = (char *) Malloc(ctx, len + 1); - if (failstr != NULL) + error->error.error = failstr; + error->error.filename = fname ? StrDup(ctx, fname) : NULL; + error->error.error_position = error_position; + + ErrorList *prev = NULL; + error->next = ctx->errors; + while (error->next != NULL) { - va_start(ap, fmt); - vsnprintf(failstr, len + 1, fmt, ap); // rebuild it. - va_end(ap); - ctx->failstr = failstr; - } // if - } // if + prev = error->next; + error->next = error->next->next; + } // while + + if (prev != NULL) + prev->next = error; + else + ctx->errors = error; - return FAIL; + ctx->error_count++; + } // else } // failf -static inline int fail(Context *ctx, const char *reason) +static inline void fail(Context *ctx, const char *reason) { - return failf(ctx, "%s", reason); + failf(ctx, "%s", reason); } // fail static inline int isfail(const Context *ctx) { - return (ctx->failstr != NULL); + return ctx->isfail; } // isfail @@ -243,13 +299,10 @@ static int tokenize_ctx(Context *ctx, TokenizerContext *tctx) { int idx = 0; - if (isfail(ctx)) - return FAIL; - if (tctx->pushedback) { tctx->pushedback = 0; - return NOFAIL; + return 1; } // if if (tctx->on_endline) @@ -262,7 +315,10 @@ static int tokenize_ctx(Context *ctx, TokenizerContext *tctx) { // !!! FIXME: carefully crafted (but legal) comments can trigger this. if (idx >= sizeof (tctx->token)) - return fail(ctx, "buffer overflow"); + { + fail(ctx, "buffer overflow"); + return 0; + } // if char ch = *tctx->source; if (ch == '\t') @@ -280,7 +336,7 @@ static int tokenize_ctx(Context *ctx, TokenizerContext *tctx) if ((idx > 0) && ((tctx->prevchar < '0') || (tctx->prevchar > '9'))) { tctx->token[idx++] = '\0'; - return NOFAIL; + return 1; } // if } // if else @@ -289,7 +345,7 @@ static int tokenize_ctx(Context *ctx, TokenizerContext *tctx) if ((idx > 0) && ((tctx->prevchar >= '0') && (tctx->prevchar <= '9'))) { tctx->token[idx++] = '\0'; - return NOFAIL; + return 1; } // if } // else @@ -310,7 +366,7 @@ static int tokenize_ctx(Context *ctx, TokenizerContext *tctx) } // if tctx->token[idx++] = '\0'; } // else - return NOFAIL; + return 1; case ' ': if (tctx->prevchar == ' ') @@ -338,13 +394,14 @@ static int tokenize_ctx(Context *ctx, TokenizerContext *tctx) tctx->token[idx++] = ch; tctx->token[idx++] = '\0'; } // else - return NOFAIL; + return 1; case '\0': tctx->token[idx] = '\0'; if (idx != 0) // had any chars? It's a token. - return NOFAIL; - return END_OF_STREAM; + return 1; + ctx->eof = 1; + return 0; default: tctx->source++; @@ -355,7 +412,8 @@ static int tokenize_ctx(Context *ctx, TokenizerContext *tctx) tctx->prevchar = ch; } // while - return fail(ctx, "???"); // shouldn't hit this. + assert(0 && "Shouldn't hit this code"); + return 0; } // tokenize_ctx @@ -364,10 +422,7 @@ static inline int tokenize(Context *ctx) const int rc = tokenize_ctx(ctx, &ctx->tctx); #if DEBUG_TOKENIZER - printf("TOKENIZE: %s '%s'\n", - (rc == END_OF_STREAM) ? "END_OF_STREAM" : - (rc == FAIL) ? "FAIL" : - (rc == NOFAIL) ? "NOFAIL" : "???", + printf("TOKENIZE: %d '%s'\n", rc, (ctx->tctx.token[0] == '\n') ? "\\n" : ctx->tctx.token); #endif @@ -375,28 +430,19 @@ static inline int tokenize(Context *ctx) } // tokenize -static int pushback_ctx(Context *ctx, TokenizerContext *tctx) +static void pushback_ctx(Context *ctx, TokenizerContext *tctx) { - if (tctx->pushedback) - return fail(ctx, "BUG: Double pushback in parser"); - else - tctx->pushedback = 1; + assert(!tctx->pushedback); + tctx->pushedback = 1; +} // pushback_ctx - return NOFAIL; -} -static inline int pushback(Context *ctx) +static inline void pushback(Context *ctx) { - const int rc = pushback_ctx(ctx, &ctx->tctx); - + pushback_ctx(ctx, &ctx->tctx); #if DEBUG_TOKENIZER - printf("PUSHBACK: %s\n", - (rc == END_OF_STREAM) ? "END_OF_STREAM" : - (rc == FAIL) ? "FAIL" : - (rc == NOFAIL) ? "NOFAIL" : "???"); + printf("PUSHBACK\n"); #endif - - return rc; } // pushback @@ -404,16 +450,17 @@ static int nexttoken_ctx(Context *ctx, TokenizerContext *tctx, const int ignoreeol, const int ignorewhitespace, const int eolok, const int eosok) { - int rc = NOFAIL; - - while ((rc = tokenize_ctx(ctx, tctx)) == NOFAIL) + while (tokenize_ctx(ctx, tctx)) { if (tokeq(tctx, "\n")) { if (ignoreeol) continue; else if (!eolok) - return fail(ctx, "Unexpected EOL"); + { + fail(ctx, "Unexpected EOL"); + return 0; + } // else if } // if else if (tokeq(tctx, " ")) @@ -425,7 +472,7 @@ static int nexttoken_ctx(Context *ctx, TokenizerContext *tctx, // skip comments... else if (tokeq(tctx, "//") || tokeq(tctx, ";")) { - while ((rc = tokenize_ctx(ctx, tctx)) == NOFAIL) + while (tokenize_ctx(ctx, tctx)) { if (tokeq(tctx, "\n")) { @@ -439,10 +486,13 @@ static int nexttoken_ctx(Context *ctx, TokenizerContext *tctx, break; } // while - if ((rc == END_OF_STREAM) && (!eosok)) - return fail(ctx, "Unexpected EOF"); + if ((ctx->eof) && (!eosok)) + { + fail(ctx, "Unexpected EOF"); + return 0; + } // if - return rc; + return 1; } // nexttoken_ctx @@ -454,10 +504,7 @@ static inline int nexttoken(Context *ctx, const int ignoreeol, ignorewhitespace, eolok, eosok); #if DEBUG_TOKENIZER - printf("NEXTTOKEN: %s '%s'\n", - (rc == END_OF_STREAM) ? "END_OF_STREAM" : - (rc == FAIL) ? "FAIL" : - (rc == NOFAIL) ? "NOFAIL" : "???", + printf("NEXTTOKEN: %d '%s'\n", rc, (ctx->tctx.token[0] == '\n') ? "\\n" : ctx->tctx.token); #endif @@ -465,17 +512,30 @@ static inline int nexttoken(Context *ctx, const int ignoreeol, } // nexttoken -static int require_endline(Context *ctx) +static void skip_line(Context *ctx) +{ + if (!tokeq(&ctx->tctx, "\n")) + { + while (nexttoken(ctx, 0, 1, 1, 1)) + { + if (tokeq(&ctx->tctx, "\n")) + break; + } // while + } // if +} // skip_line + + +static void require_endline(Context *ctx) { TokenizerContext *tctx = &ctx->tctx; const int rc = nexttoken(ctx, 0, 1, 1, 1); - if (rc == FAIL) - return FAIL; - else if (rc == END_OF_STREAM) - return NOFAIL; // we'll call this an EOL. - else if (!tokeq(tctx, "\n")) - return fail(ctx, "Endline expected"); - return NOFAIL; + if (ctx->eof) + return; // we'll call this an EOL. + else if ((rc == 0) || (!tokeq(tctx, "\n"))) + { + fail(ctx, "Endline expected"); + skip_line(ctx); + } // else if } // require_endline @@ -483,19 +543,20 @@ static int require_comma(Context *ctx) { TokenizerContext *tctx = &ctx->tctx; const int rc = nexttoken(ctx, 0, 1, 0, 0); - if (rc == FAIL) - return FAIL; - else if (!tokeq(tctx, ",")) - return fail(ctx, "Comma expected"); - return NOFAIL; + if ((rc == 0) || (!tokeq(tctx, ","))) + { + fail(ctx, "Comma expected"); + return 0; + } // if + return 1; } // require_comma static int parse_register_name(Context *ctx, RegisterType *rtype, int *rnum) { TokenizerContext *tctx = &ctx->tctx; - if (nexttoken(ctx, 0, 1, 0, 0) == FAIL) - return FAIL; + if (!nexttoken(ctx, 0, 1, 0, 0)) + return 0; int neednum = 1; int regnum = 0; @@ -533,25 +594,25 @@ static int parse_register_name(Context *ctx, RegisterType *rtype, int *rnum) else if (tokeq(tctx, "o")) { if (!shader_is_vertex(ctx) || !shader_version_atleast(ctx, 3, 0)) - return fail(ctx, "Output register not valid in this shader type"); + fail(ctx, "Output register not valid in this shader type"); regtype = REG_TYPE_OUTPUT; } // else if else if (tokeq(tctx, "oT")) { if (shader_is_vertex(ctx) && shader_version_atleast(ctx, 3, 0)) - return fail(ctx, "Output register not valid in this shader type"); + fail(ctx, "Output register not valid in this shader type"); regtype = REG_TYPE_OUTPUT; } // else if else if (tokeq(tctx, "a")) { if (!shader_is_vertex(ctx)) - return fail(ctx, "Address register only valid in vertex shaders."); + fail(ctx, "Address register only valid in vertex shaders."); regtype = REG_TYPE_ADDRESS; } // else if else if (tokeq(tctx, "t")) { if (!shader_is_pixel(ctx)) - return fail(ctx, "Address register only valid in pixel shaders."); + fail(ctx, "Address register only valid in pixel shaders."); regtype = REG_TYPE_ADDRESS; } // else if else if (tokeq(tctx, "vPos")) @@ -589,7 +650,10 @@ static int parse_register_name(Context *ctx, RegisterType *rtype, int *rnum) else { - return fail(ctx, "expected register type"); + fail(ctx, "expected register type"); + regtype = REG_TYPE_CONST; + regnum = 0; + neednum = 0; } // else if (neednum) @@ -599,20 +663,20 @@ static int parse_register_name(Context *ctx, RegisterType *rtype, int *rnum) // that whitespace back. TokenizerContext tmptctx; memcpy(&tmptctx, tctx, sizeof (TokenizerContext)); - if (nexttoken_ctx(ctx, &tmptctx, 0, 1, 1, 1) == FAIL) - return FAIL; + if (!nexttoken_ctx(ctx, &tmptctx, 0, 1, 1, 1)) + return 0; else if (tokeq(&tmptctx, "[")) neednum = 0; } // if if (neednum) { - if (nexttoken(ctx, 0, 0, 0, 0) == FAIL) - return FAIL; + if (!nexttoken(ctx, 0, 0, 0, 0)) + return 0; uint32 ui32 = 0; if (!ui32fromstr(tctx->token, &ui32)) - return fail(ctx, "Invalid register index"); + fail(ctx, "Invalid register index"); regnum = (int) ui32; } // if @@ -641,23 +705,22 @@ static int parse_register_name(Context *ctx, RegisterType *rtype, int *rnum) } // if else { - return fail(ctx, "Invalid const register index"); + fail(ctx, "Invalid const register index"); } // else } // if *rtype = regtype; *rnum = regnum; - return NOFAIL; + return 1; } // parse_register_name -static int set_result_shift(Context *ctx, DestArgInfo *info, const int val) +static void set_result_shift(Context *ctx, DestArgInfo *info, const int val) { if (info->result_shift != 0) - return fail(ctx, "Multiple result shift modifiers"); + fail(ctx, "Multiple result shift modifiers"); info->result_shift = val; - return NOFAIL; } // set_result_shift @@ -671,19 +734,19 @@ static int parse_destination_token(Context *ctx) // See if there are destination modifiers on the instruction itself... while (1) { - if (nexttoken(ctx, 0, 0, 0, 0) == FAIL) - return FAIL; + if (!nexttoken(ctx, 0, 0, 0, 0)) + return 1; else if (tokeq(tctx, " ")) break; // done with modifiers. else if (!tokeq(tctx, "_")) - return fail(ctx, "Expected modifier or whitespace"); - else if (nexttoken(ctx, 0, 0, 0, 0) == FAIL) - return FAIL; + fail(ctx, "Expected modifier or whitespace"); + else if (!nexttoken(ctx, 0, 0, 0, 0)) + return 1; // !!! FIXME: this can be cleaned up when tokenizer is fixed. else if (tokeq(tctx, "x")) { - if (nexttoken(ctx, 0, 0, 0, 0) == FAIL) - return FAIL; + if (!nexttoken(ctx, 0, 0, 0, 0)) + return 1; else if (tokeq(tctx, "2")) set_result_shift(ctx, info, 0x1); else if (tokeq(tctx, "4")) @@ -691,13 +754,13 @@ static int parse_destination_token(Context *ctx) else if (tokeq(tctx, "8")) set_result_shift(ctx, info, 0x3); else - return fail(ctx, "Expected modifier"); + fail(ctx, "Expected modifier"); } // else if // !!! FIXME: this can be cleaned up when tokenizer is fixed. else if (tokeq(tctx, "d")) { - if (nexttoken(ctx, 0, 0, 0, 0) == FAIL) - return FAIL; + if (!nexttoken(ctx, 0, 0, 0, 0)) + return 1; else if (tokeq(tctx, "8")) set_result_shift(ctx, info, 0xD); else if (tokeq(tctx, "4")) @@ -705,7 +768,7 @@ static int parse_destination_token(Context *ctx) else if (tokeq(tctx, "2")) set_result_shift(ctx, info, 0xF); else - return fail(ctx, "Expected modifier"); + fail(ctx, "Expected modifier"); } // else if else if (tokeq(tctx, "sat")) info->result_mod |= MOD_SATURATE; @@ -714,25 +777,26 @@ static int parse_destination_token(Context *ctx) else if (tokeq(tctx, "centroid")) info->result_mod |= MOD_CENTROID; else - return fail(ctx, "Expected modifier"); + fail(ctx, "Expected modifier"); } // while - if (nexttoken(ctx, 0, 1, 0, 0) == FAIL) - return FAIL; + if (!nexttoken(ctx, 0, 1, 0, 0)) + return 1; // !!! FIXME: predicates. if (tokeq(tctx, "(")) - return fail(ctx, "Predicates unsupported at this time"); + fail(ctx, "Predicates unsupported at this time"); // !!! FIXME: ... + pushback(ctx); // parse_register_name calls nexttoken(). - if (parse_register_name(ctx, &info->regtype, &info->regnum) == FAIL) - return FAIL; + parse_register_name(ctx, &info->regtype, &info->regnum); - if (nexttoken(ctx, 0, 1, 1, 1) == FAIL) - return FAIL; + if (!nexttoken(ctx, 0, 1, 1, 1)) + return 1; // !!! FIXME: can dest registers do relative addressing? + int invalid_writemask = 0; int implicit_writemask = 0; if (!tokeq(tctx, ".")) { @@ -744,11 +808,11 @@ static int parse_destination_token(Context *ctx) // !!! FIXME: Cg generates code with oDepth.z ... this is a bug, I think. //else if (scalar_register(ctx->shader_type, info->regtype, info->regnum)) else if ( (scalar_register(ctx->shader_type, info->regtype, info->regnum)) && (info->regtype != REG_TYPE_DEPTHOUT) ) - return fail(ctx, "Writemask specified for scalar register"); - else if (nexttoken(ctx, 0, 1, 0, 0) == FAIL) - return FAIL; + fail(ctx, "Writemask specified for scalar register"); + else if (!nexttoken(ctx, 0, 1, 0, 0)) + return 1; else if (tokeq(tctx, "")) - return fail(ctx, "Invalid writemask"); + invalid_writemask = 1; else { char *ptr = tctx->token; @@ -766,7 +830,7 @@ static int parse_destination_token(Context *ctx) } // if if (*ptr != '\0') - return fail(ctx, "Invalid writemask"); + invalid_writemask = 1; info->writemask = ( ((info->writemask0 & 0x1) << 0) | ((info->writemask1 & 0x1) << 1) | @@ -774,18 +838,24 @@ static int parse_destination_token(Context *ctx) ((info->writemask3 & 0x1) << 3) ); } // else + if (invalid_writemask) + fail(ctx, "Invalid writemask"); + // !!! FIXME: Cg generates code with oDepth.z ... this is a bug, I think. if (info->regtype == REG_TYPE_DEPTHOUT) { if ( (!implicit_writemask) && ((info->writemask0 + info->writemask1 + info->writemask2 + info->writemask3) > 1) ) - return fail(ctx, "Writemask specified for scalar register"); + fail(ctx, "Writemask specified for scalar register"); } // if info->orig_writemask = info->writemask; if (ctx->tokenbufpos >= STATICARRAYLEN(ctx->tokenbuf)) - return fail(ctx, "Too many tokens"); + { + fail(ctx, "Too many tokens"); + return 1; + } // if ctx->tokenbuf[ctx->tokenbufpos++] = ( ((((uint32) 1)) << 31) | @@ -818,21 +888,25 @@ static int parse_source_token_maybe_relative(Context *ctx, const int relok) int retval = 1; if (ctx->tokenbufpos >= STATICARRAYLEN(ctx->tokenbuf)) - return fail(ctx, "Too many tokens"); + { + fail(ctx, "Too many tokens"); + return 0; + } // if // mark this now, so optional relative addressing token is placed second. uint32 *token = &ctx->tokenbuf[ctx->tokenbufpos++]; + *token = 0; SourceMod srcmod = SRCMOD_NONE; int negate = 0; - if (nexttoken(ctx, 0, 1, 0, 0) == FAIL) - return FAIL; + if (!nexttoken(ctx, 0, 1, 0, 0)) + return 1; else if (tokeq(tctx, "1")) { - if (nexttoken(ctx, 0, 1, 0, 0) == FAIL) - return FAIL; + if (!nexttoken(ctx, 0, 1, 0, 0)) + return 1; else if (!tokeq(tctx, "-")) - return fail(ctx, "Unexpected value"); + fail(ctx, "Unexpected value"); else srcmod = SRCMOD_COMPLEMENT; } // else @@ -845,14 +919,13 @@ static int parse_source_token_maybe_relative(Context *ctx, const int relok) RegisterType regtype; int regnum; - if (parse_register_name(ctx, ®type, ®num) == FAIL) - return FAIL; - else if (nexttoken(ctx, 0, 1, 1, 1) == FAIL) - return FAIL; + parse_register_name(ctx, ®type, ®num); + if (!nexttoken(ctx, 0, 1, 1, 1)) + return 1; else if (!tokeq(tctx, "_")) pushback(ctx); - else if (nexttoken(ctx, 0, 0, 0, 0) == FAIL) - return FAIL; + else if (!nexttoken(ctx, 0, 0, 0, 0)) + return 1; else if (tokeq(tctx, "bias")) set_source_mod(ctx, negate, SRCMOD_BIAS, SRCMOD_BIASNEGATE, &srcmod); else if (tokeq(tctx, "bx2")) @@ -866,48 +939,49 @@ static int parse_source_token_maybe_relative(Context *ctx, const int relok) else if (tokeq(tctx, "abs")) set_source_mod(ctx, negate, SRCMOD_ABS, SRCMOD_ABSNEGATE, &srcmod); else - return fail(ctx, "Invalid source modifier"); + fail(ctx, "Invalid source modifier"); - if (nexttoken(ctx, 0, 1, 1, 1) == FAIL) - return FAIL; + if (!nexttoken(ctx, 0, 1, 1, 1)) + return 1; uint32 relative = 0; if (!tokeq(tctx, "[")) pushback(ctx); // not relative addressing? - else if (!relok) - return fail(ctx, "Relative addressing not permitted here."); else { - const int rc = parse_source_token_maybe_relative(ctx, 0); - if (rc == FAIL) - return FAIL; - retval += rc; + if (!relok) + fail(ctx, "Relative addressing not permitted here."); + else + retval++; + + parse_source_token_maybe_relative(ctx, 0); relative = 1; - if (nexttoken(ctx, 0, 1, 0, 0) == FAIL) - return FAIL; + if (!nexttoken(ctx, 0, 1, 0, 0)) + return retval; else if (!tokeq(tctx, "+")) pushback(ctx); - else if (nexttoken(ctx, 0, 1, 0, 0) == FAIL) - return FAIL; + else if (!nexttoken(ctx, 0, 1, 0, 0)) + return retval; else { if (regnum != 0) // !!! FIXME: maybe c3[a0.x + 5] is legal and becomes c[a0.x + 8] ? fail(ctx, "Relative addressing with explicit register number."); uint32 ui32 = 0; if (!ui32fromstr(tctx->token, &ui32)) - return fail(ctx, "Invalid relative addressing offset"); + fail(ctx, "Invalid relative addressing offset"); regnum += (int) ui32; } // else - if (nexttoken(ctx, 0, 1, 0, 0) == FAIL) - return FAIL; + if (!nexttoken(ctx, 0, 1, 0, 0)) + return retval; else if (!tokeq(tctx, "]")) - return fail(ctx, "Expected ']'"); + fail(ctx, "Expected ']'"); } // else - if (nexttoken(ctx, 0, 1, 1, 1) == FAIL) - return FAIL; + if (!nexttoken(ctx, 0, 1, 1, 1)) + return retval; + int invalid_swizzle = 0; uint32 swizzle = 0; if (!tokeq(tctx, ".")) { @@ -915,11 +989,11 @@ static int parse_source_token_maybe_relative(Context *ctx, const int relok) pushback(ctx); // no explicit writemask; do full mask. } // if else if (scalar_register(ctx->shader_type, regtype, regnum)) - return fail(ctx, "Swizzle specified for scalar register"); - else if (nexttoken(ctx, 0, 1, 0, 0) == FAIL) - return FAIL; + fail(ctx, "Swizzle specified for scalar register"); + else if (!nexttoken(ctx, 0, 1, 0, 0)) + return retval; else if (tokeq(tctx, "")) - return fail(ctx, "Invalid swizzle"); + invalid_swizzle = 1; else { // deal with shortened form (.x = .xxxx, etc). @@ -930,10 +1004,10 @@ static int parse_source_token_maybe_relative(Context *ctx, const int relok) else if (tctx->token[3] == '\0') tctx->token[3] = tctx->token[2]; else if (tctx->token[4] != '\0') - return fail(ctx, "Invalid swizzle"); + invalid_swizzle = 1; tctx->token[4] = '\0'; - uint32 val; + uint32 val = 0; int saw_xyzw = 0; int saw_rgba = 0; int i; @@ -950,15 +1024,18 @@ static int parse_source_token_maybe_relative(Context *ctx, const int relok) case 'g': val = 1; saw_rgba = 1; break; case 'b': val = 2; saw_rgba = 1; break; case 'a': val = 3; saw_rgba = 1; break; - default: return fail(ctx, "Invalid swizzle"); + default: invalid_swizzle = 1; break; } // switch swizzle |= (val << (i * 2)); } // for if (saw_xyzw && saw_rgba) - return fail(ctx, "Invalid swizzle"); + invalid_swizzle = 1; } // else + if (invalid_swizzle) + fail(ctx, "Invalid swizzle"); + *token = ( ((((uint32) 1)) << 31) | ((((uint32) regnum) & 0x7ff) << 0) | ((((uint32) relative) & 0x1) << 13) | @@ -979,7 +1056,7 @@ static inline int parse_source_token(Context *ctx) static int parse_args_NULL(Context *ctx) { - return (isfail(ctx) ? FAIL : 1); + return 1; } // parse_args_NULL @@ -990,41 +1067,43 @@ static int parse_num(Context *ctx, const int floatok, uint32 *token) union { float f; int32 si32; uint32 ui32; } cvt; cvt.si32 = 0; - if (nexttoken(ctx, 0, 1, 0, 0) == FAIL) - return FAIL; + *token = 0; + + if (!nexttoken(ctx, 0, 1, 0, 0)) + return 0; else if (tokeq(tctx, "-")) negative = -1; else pushback(ctx); uint32 val = 0; - if (nexttoken(ctx, 0, 1, 0, 0) == FAIL) - return FAIL; + if (!nexttoken(ctx, 0, 1, 0, 0)) + return 0; else if (!ui32fromstr(tctx->token, &val)) - return fail(ctx, "Expected number"); + fail(ctx, "Expected number"); uint32 fraction = 0; - if (nexttoken(ctx, 0, 1, 1, 1) == FAIL) - return FAIL; + if (!nexttoken(ctx, 0, 1, 1, 1)) + return 0; else if (!tokeq(tctx, ".")) pushback(ctx); // whole number else if (!floatok) - return fail(ctx, "Expected whole number"); - else if (nexttoken(ctx, 0, 1, 0, 0) == FAIL) - return FAIL; + fail(ctx, "Expected whole number"); + else if (!nexttoken(ctx, 0, 1, 0, 0)) + return 0; else if (!ui32fromstr(tctx->token, &fraction)) - return fail(ctx, "Expected number"); + fail(ctx, "Expected number"); uint32 exponent = 0; int negexp = 0; - if (nexttoken(ctx, 0, 1, 1, 1) == FAIL) - return FAIL; + if (!nexttoken(ctx, 0, 1, 1, 1)) + return 0; else if (!tokeq(tctx, "e")) pushback(ctx); else if (!floatok) - return fail(ctx, "Exponent on whole number"); // !!! FIXME: illegal? - else if (nexttoken(ctx, 0, 1, 0, 0) == FAIL) - return FAIL; + fail(ctx, "Exponent on whole number"); // !!! FIXME: illegal? + else if (!nexttoken(ctx, 0, 1, 0, 0)) + return 0; else { if (!tokeq(tctx, "-")) @@ -1032,10 +1111,10 @@ static int parse_num(Context *ctx, const int floatok, uint32 *token) else negexp = 1; - if (nexttoken(ctx, 0, 1, 0, 0) == FAIL) - return FAIL; + if (!nexttoken(ctx, 0, 1, 0, 0)) + return 0; else if (!ui32fromstr(tctx->token, &exponent)) - return fail(ctx, "Expected exponent"); + fail(ctx, "Expected exponent"); } // else if (!floatok) @@ -1066,30 +1145,21 @@ static int parse_num(Context *ctx, const int floatok, uint32 *token) } // else *token = cvt.ui32; - return NOFAIL; + return 1; } // parse_num static int parse_args_DEFx(Context *ctx, const int isflt) { - if (parse_destination_token(ctx) == FAIL) - return FAIL; - else if (require_comma(ctx) == FAIL) - return FAIL; - else if (parse_num(ctx, isflt, &ctx->tokenbuf[ctx->tokenbufpos++]) == FAIL) - return FAIL; - else if (require_comma(ctx) == FAIL) - return FAIL; - else if (parse_num(ctx, isflt, &ctx->tokenbuf[ctx->tokenbufpos++]) == FAIL) - return FAIL; - else if (require_comma(ctx) == FAIL) - return FAIL; - else if (parse_num(ctx, isflt, &ctx->tokenbuf[ctx->tokenbufpos++]) == FAIL) - return FAIL; - else if (require_comma(ctx) == FAIL) - return FAIL; - else if (parse_num(ctx, isflt, &ctx->tokenbuf[ctx->tokenbufpos++]) == FAIL) - return FAIL; + parse_destination_token(ctx); + require_comma(ctx); + parse_num(ctx, isflt, &ctx->tokenbuf[ctx->tokenbufpos++]); + require_comma(ctx); + parse_num(ctx, isflt, &ctx->tokenbuf[ctx->tokenbufpos++]); + require_comma(ctx); + parse_num(ctx, isflt, &ctx->tokenbuf[ctx->tokenbufpos++]); + require_comma(ctx); + parse_num(ctx, isflt, &ctx->tokenbuf[ctx->tokenbufpos++]); return 6; } // parse_args_DEFx @@ -1109,20 +1179,16 @@ static int parse_args_DEFI(Context *ctx) static int parse_args_DEFB(Context *ctx) { TokenizerContext *tctx = &ctx->tctx; - if (parse_destination_token(ctx) == FAIL) - return FAIL; - else if (nexttoken(ctx, 0, 1, 0, 0) == FAIL) - return FAIL; - else if (!tokeq(tctx, ",")) - return fail(ctx, "Expected ','"); - else if (nexttoken(ctx, 0, 1, 0, 0) == FAIL) - return FAIL; + parse_destination_token(ctx); + require_comma(ctx); + if (!nexttoken(ctx, 0, 1, 0, 0)) + return 1; else if (tokeq(tctx, "true")) ctx->tokenbuf[ctx->tokenbufpos++] = 1; else if (tokeq(tctx, "false")) ctx->tokenbuf[ctx->tokenbufpos++] = 0; else - return fail(ctx, "Expected 'true' or 'false'"); + fail(ctx, "Expected 'true' or 'false'"); return 3; } // parse_args_DEFB @@ -1144,8 +1210,8 @@ static int parse_dcl_usage(Context *ctx, uint32 *val, int *issampler) strcpy(token, tctx->token); if (tokeq(tctx, "2")) // "2d" is two tokens. { - if (nexttoken(ctx, 0, 0, 1, 1) == FAIL) - return FAIL; + if (!nexttoken(ctx, 0, 0, 1, 1)) + return 0; else if (!tokeq(tctx, "d") != 0) pushback(ctx); else @@ -1158,7 +1224,7 @@ static int parse_dcl_usage(Context *ctx, uint32 *val, int *issampler) { *issampler = 0; *val = i; - return NOFAIL; + return 1; } // if } // for @@ -1168,7 +1234,7 @@ static int parse_dcl_usage(Context *ctx, uint32 *val, int *issampler) { *issampler = 1; *val = i + 2; - return NOFAIL; + return 1; } // if } // for @@ -1182,11 +1248,11 @@ static int parse_dcl_usage(Context *ctx, uint32 *val, int *issampler) tctx->source -= strlen(token); // !!! FIXME: hack to move back strcpy(tctx->token, "_"); // !!! FIXME: hack to move back pushback(ctx); // !!! FIXME: hack to move back - return NOFAIL; // if you have "dcl_pp", then "_pp" isn't a usage. + return 1; // if you have "dcl_pp", then "_pp" isn't a usage. } // if } // for - return FAIL; + return 0; } // parse_dcl_usage @@ -1198,31 +1264,31 @@ static int parse_args_DCL(Context *ctx) uint32 index = 0; ctx->tokenbufpos++; // save a spot for the usage/index token. + ctx->tokenbuf[0] = 0; - if (nexttoken(ctx, 0, 0, 0, 0) == FAIL) - return FAIL; + if (!nexttoken(ctx, 0, 0, 0, 0)) + return 1; else if (tokeq(tctx, " ")) pushback(ctx); else if (!tokeq(tctx, "_")) - return fail(ctx, "Expected register or usage"); - else if (nexttoken(ctx, 0, 0, 0, 0) == FAIL) - return FAIL; - else if (parse_dcl_usage(ctx, &usage, &issampler) == FAIL) - return FAIL; - - if (nexttoken(ctx, 0, 0, 0, 0) == FAIL) - return FAIL; + fail(ctx, "Expected register or usage"); + else if (!nexttoken(ctx, 0, 0, 0, 0)) + return 1; + else + parse_dcl_usage(ctx, &usage, &issampler); + + if (!nexttoken(ctx, 0, 0, 0, 0)) + return 1; else if (tokeq(tctx, " ") || tokeq(tctx, "_")) pushback(ctx); // parse_destination_token() wants these. else if (!ui32fromstr(tctx->token, &index)) - return fail(ctx, "Expected usage index or register"); + fail(ctx, "Expected usage index or register"); - if (parse_destination_token(ctx) == FAIL) - return FAIL; + parse_destination_token(ctx); const int samplerreg = (ctx->dest_arg.regtype == REG_TYPE_SAMPLER); if (issampler != samplerreg) - return fail(ctx, "Invalid usage"); + fail(ctx, "Invalid usage"); else if (samplerreg) ctx->tokenbuf[0] = (usage << 27) | 0x80000000; else @@ -1236,7 +1302,7 @@ static int parse_args_D(Context *ctx) { int retval = 1; retval += parse_destination_token(ctx); - return isfail(ctx) ? FAIL : retval; + return retval; } // parse_args_D @@ -1244,7 +1310,7 @@ static int parse_args_S(Context *ctx) { int retval = 1; retval += parse_source_token(ctx); - return isfail(ctx) ? FAIL : retval; + return retval; } // parse_args_S @@ -1252,9 +1318,9 @@ static int parse_args_SS(Context *ctx) { int retval = 1; retval += parse_source_token(ctx); - if (require_comma(ctx) == FAIL) return FAIL; + require_comma(ctx); retval += parse_source_token(ctx); - return isfail(ctx) ? FAIL : retval; + return retval; } // parse_args_SS @@ -1262,9 +1328,9 @@ static int parse_args_DS(Context *ctx) { int retval = 1; retval += parse_destination_token(ctx); - if (require_comma(ctx) == FAIL) return FAIL; + require_comma(ctx); retval += parse_source_token(ctx); - return isfail(ctx) ? FAIL : retval; + return retval; } // parse_args_DS @@ -1272,11 +1338,11 @@ static int parse_args_DSS(Context *ctx) { int retval = 1; retval += parse_destination_token(ctx); - if (require_comma(ctx) == FAIL) return FAIL; + require_comma(ctx); retval += parse_source_token(ctx); - if (require_comma(ctx) == FAIL) return FAIL; + require_comma(ctx); retval += parse_source_token(ctx); - return isfail(ctx) ? FAIL : retval; + return retval; } // parse_args_DSS @@ -1284,13 +1350,13 @@ static int parse_args_DSSS(Context *ctx) { int retval = 1; retval += parse_destination_token(ctx); - if (require_comma(ctx) == FAIL) return FAIL; + require_comma(ctx); retval += parse_source_token(ctx); - if (require_comma(ctx) == FAIL) return FAIL; + require_comma(ctx); retval += parse_source_token(ctx); - if (require_comma(ctx) == FAIL) return FAIL; + require_comma(ctx); retval += parse_source_token(ctx); - return isfail(ctx) ? FAIL : retval; + return retval; } // parse_args_DSSS @@ -1298,15 +1364,15 @@ static int parse_args_DSSSS(Context *ctx) { int retval = 1; retval += parse_destination_token(ctx); - if (require_comma(ctx) == FAIL) return FAIL; + require_comma(ctx); retval += parse_source_token(ctx); - if (require_comma(ctx) == FAIL) return FAIL; + require_comma(ctx); retval += parse_source_token(ctx); - if (require_comma(ctx) == FAIL) return FAIL; + require_comma(ctx); retval += parse_source_token(ctx); - if (require_comma(ctx) == FAIL) return FAIL; + require_comma(ctx); retval += parse_source_token(ctx); - return isfail(ctx) ? FAIL : retval; + return retval; } // parse_args_DSSSS @@ -1365,7 +1431,7 @@ static const Instruction instructions[] = static int parse_condition(Context *ctx, uint32 *controls) { TokenizerContext *tctx = &ctx->tctx; - if (nexttoken(ctx, 0, 0, 0, 0) == FAIL) + if (!nexttoken(ctx, 0, 0, 0, 0)) return 0; else if (!tokeq(tctx, "_")) { @@ -1373,7 +1439,7 @@ static int parse_condition(Context *ctx, uint32 *controls) return 0; } // else if - if (nexttoken(ctx, 0, 0, 0, 0) == FAIL) + if (!nexttoken(ctx, 0, 0, 0, 0)) return 0; else { @@ -1413,8 +1479,8 @@ static int parse_instruction_token(Context *ctx) if (tokeq(tctx, "+")) { - if (nexttoken(ctx, 0, 1, 0, 0) == FAIL) - return FAIL; + if (!nexttoken(ctx, 0, 1, 0, 0)) + return 0; coissue = 1; } // if @@ -1425,7 +1491,10 @@ static int parse_instruction_token(Context *ctx) while (1) { if ( (strlen(opstr) + strlen(tctx->token)) >= (sizeof (opstr)-1) ) - return fail(ctx, "Expected instruction"); + { + fail(ctx, "Expected instruction"); + return 0; + } // if char *ptr; for (ptr = tctx->token; *ptr != '\0'; ptr++) @@ -1442,8 +1511,8 @@ static int parse_instruction_token(Context *ctx) strcat(opstr, tctx->token); - if (nexttoken(ctx, 0, 0, 1, 1) == FAIL) - return FAIL; + if (!nexttoken(ctx, 0, 0, 1, 1)) + return 0; } // while uint32 controls = 0; @@ -1479,7 +1548,10 @@ static int parse_instruction_token(Context *ctx) uint32 opcode = (uint32) i; if (!valid_opcode) - return failf(ctx, "Unknown instruction '%s'", opstr); + { + failf(ctx, "Unknown instruction '%s'", opstr); + return 0; + } // if // This might need to be IFC instead of IF. // !!! FIXME: compare opcode, not string @@ -1502,7 +1574,7 @@ static int parse_instruction_token(Context *ctx) else if (strcmp(instruction->opcode_string, "SETP") == 0) { if (!parse_condition(ctx, &controls)) - return fail(ctx, "SETP requires a condition"); + fail(ctx, "SETP requires a condition"); } // else if instruction = &instructions[opcode]; // ...in case this changed. @@ -1512,8 +1584,7 @@ static int parse_instruction_token(Context *ctx) ctx->tokenbufpos = 0; const int tokcount = instruction->parse_args(ctx); - if (require_endline(ctx) == FAIL) - return FAIL; + require_endline(ctx); // insttoks bits are reserved and should be zero if < SM2. const uint32 insttoks = shader_version_atleast(ctx, 2, 0) ? tokcount-1 : 0; @@ -1529,15 +1600,15 @@ static int parse_instruction_token(Context *ctx) for (i = 0; i < (tokcount-1); i++) output_token(ctx, ctx->tokenbuf[i]); - return NOFAIL; + return 1; } // parse_instruction_token -static int parse_version_token(Context *ctx) +static void parse_version_token(Context *ctx) { TokenizerContext *tctx = &ctx->tctx; - if (nexttoken(ctx, 1, 1, 0, 0) == FAIL) - return FAIL; + if (!nexttoken(ctx, 1, 1, 0, 0)) + return; uint32 shader_type = 0; if (tokeq(tctx, "vs")) @@ -1553,75 +1624,75 @@ static int parse_version_token(Context *ctx) else { // !!! FIXME: geometry shaders? - return fail(ctx, "Expected version string"); + fail(ctx, "Expected version string"); } // else + int bad_version = 0; + uint32 major = 0; - if (nexttoken(ctx, 0, 0, 0, 0) == FAIL) - return FAIL; + if (!nexttoken(ctx, 0, 0, 0, 0)) + return; else if ( (!tokeq(tctx, "_")) && (!tokeq(tctx, ".")) ) - return fail(ctx, "Expected version string"); - else if (nexttoken(ctx, 0, 0, 0, 0) == FAIL) - return FAIL; + bad_version = 1; + else if (!nexttoken(ctx, 0, 0, 0, 0)) + return; else if (!ui32fromstr(tctx->token, &major)) - return fail(ctx, "Expected version string"); + bad_version = 1; uint32 minor = 0; - if (nexttoken(ctx, 0, 0, 0, 0) == FAIL) - return FAIL; + if (!nexttoken(ctx, 0, 0, 0, 0)) + return; else if ( (!tokeq(tctx, "_")) && (!tokeq(tctx, ".")) ) - return fail(ctx, "Expected version string"); - else if (nexttoken(ctx, 0, 0, 0, 0) == FAIL) - return FAIL; + bad_version = 1; + else if (!nexttoken(ctx, 0, 0, 0, 0)) + return; else if (tokeq(tctx, "x")) minor = 1; else if (tokeq(tctx, "sw")) minor = 255; else if (!ui32fromstr(tctx->token, &minor)) - return fail(ctx, "Expected version string"); + bad_version = 1; + + if (bad_version) + fail(ctx, "Expected version string"); + else + require_endline(ctx); ctx->major_ver = major; ctx->minor_ver = minor; - if (require_endline(ctx) == FAIL) - return FAIL; - ctx->version_token = (shader_type << 16) | (major << 8) | (minor << 0); output_token(ctx, ctx->version_token); - return NOFAIL; } // parse_version_token -static int parse_phase_token(Context *ctx) +static void parse_phase_token(Context *ctx) { - if (require_endline(ctx) == FAIL) - return FAIL; + require_endline(ctx); output_token(ctx, 0x0000FFFD); // phase token always 0x0000FFFD. - return NOFAIL; } // parse_phase_token -static int parse_end_token(Context *ctx) +static void parse_end_token(Context *ctx) { - if (require_endline(ctx) == FAIL) - return FAIL; + require_endline(ctx); // We don't emit the end token bits here, since it's valid for a shader // to not specify an "end" string at all; it's implicit, in that case. // Instead, we make sure if we see "end" that it's the last thing we see. - if (nexttoken(ctx, 1, 1, 0, 1) != END_OF_STREAM) - return fail(ctx, "Content after END"); - return NOFAIL; + nexttoken(ctx, 1, 1, 0, 1); + if (!ctx->eof) + fail(ctx, "Content after END"); } // parse_end_token -static int parse_token(Context *ctx) +static void parse_token(Context *ctx) { TokenizerContext *tctx = &ctx->tctx; if (tokeq(tctx, "end")) - return parse_end_token(ctx); + parse_end_token(ctx); else if (tokeq(tctx, "phase")) - return parse_phase_token(ctx); - return parse_instruction_token(ctx); + parse_phase_token(ctx); + parse_instruction_token(ctx); } // parse_token @@ -1647,14 +1718,26 @@ static Context *build_context(const char *source, MOJOSHADER_malloc m, } // build_context +static void free_error_list(MOJOSHADER_free f, void *d, ErrorList *item) +{ + while (item != NULL) + { + ErrorList *next = item->next; + f((void *) item->error.error, d); + f((void *) item->error.filename, d); + f(item, d); + item = next; + } // while +} // free_error_list + + static void destroy_context(Context *ctx) { if (ctx != NULL) { MOJOSHADER_free f = ((ctx->free != NULL) ? ctx->free : internal_free); void *d = ctx->malloc_data; - if ((ctx->failstr != NULL) && (ctx->failstr != out_of_mem_str)) - f((void *) ctx->failstr, d); + free_error_list(f, d, ctx->errors); if (ctx->output != NULL) f(ctx->output, d); if (ctx->token_to_source != NULL) @@ -1666,6 +1749,31 @@ static void destroy_context(Context *ctx) } // destroy_context +static MOJOSHADER_error *build_errors(Context *ctx) +{ + int total = 0; + MOJOSHADER_error *retval = (MOJOSHADER_error *) + Malloc(ctx, sizeof (MOJOSHADER_error) * ctx->error_count); + if (retval == NULL) + return NULL; + + ErrorList *item = ctx->errors; + while (item != NULL) + { + ErrorList *next = item->next; + // reuse the string allocations + memcpy(&retval[total], &item->error, sizeof (MOJOSHADER_error)); + Free(ctx, item); + item = next; + total++; + } // while + ctx->errors = NULL; + + assert(total == ctx->error_count); + return retval; +} // build_errors + + static const MOJOSHADER_parseData *build_failed_assembly(Context *ctx) { MOJOSHADER_parseData *retval = NULL; @@ -1681,32 +1789,13 @@ static const MOJOSHADER_parseData *build_failed_assembly(Context *ctx) retval->free = (ctx->free == internal_free) ? NULL : ctx->free; retval->malloc_data = ctx->malloc_data; - // !!! FIXME: handle multiple errors. - retval->error_count = 1; - retval->errors = (MOJOSHADER_error *) - Malloc(ctx, sizeof (MOJOSHADER_error)); - if (retval->errors == NULL) + retval->error_count = ctx->error_count; + retval->errors = build_errors(ctx); + if ((retval->errors == NULL) && (ctx->error_count > 0)) { Free(ctx, retval); return &out_of_mem_data; } // if - retval->errors->error = ctx->failstr; - retval->errors->filename = NULL; - - ctx->failstr = NULL; // don't let this get free()'d too soon. - - switch (ctx->parse_phase) - { - case MOJOSHADER_PARSEPHASE_NOTSTARTED: - retval->errors->error_position = -2; - break; - case MOJOSHADER_PARSEPHASE_WORKING: - retval->errors->error_position = ctx->tctx.linenum; - break; - case MOJOSHADER_PARSEPHASE_DONE: - retval->errors->error_position = -1; - break; - } // switch return retval; } // build_failed_assembly @@ -1884,8 +1973,7 @@ static void output_comments(Context *ctx, const char **comments, for (i = 0; i < comment_count; i++) output_comment_string(ctx, comments[i]); - if (!isfail(ctx)) - ctx->parse_phase = MOJOSHADER_PARSEPHASE_WORKING; + ctx->parse_phase = MOJOSHADER_PARSEPHASE_WORKING; } // output_comments @@ -1897,6 +1985,7 @@ const MOJOSHADER_parseData *MOJOSHADER_assemble(const char *source, unsigned int symbol_count, MOJOSHADER_malloc m, MOJOSHADER_free f, void *d) { + int failed = 0; MOJOSHADER_parseData *retval = NULL; Context *ctx = NULL; @@ -1913,12 +2002,22 @@ const MOJOSHADER_parseData *MOJOSHADER_assemble(const char *source, output_comments(ctx, comments, comment_count, symbols, symbol_count); // parse out the rest of the tokens after the version token... - while (nexttoken(ctx, 1, 1, 0, 1) == NOFAIL) + while (nexttoken(ctx, 1, 1, 0, 1)) + { + if (isfail(ctx)) + { + failed = 1; + ctx->isfail = 0; + skip_line(ctx); // start fresh on next line. + } // if parse_token(ctx); + } // while + + ctx->isfail = failed; output_token(ctx, 0x0000FFFF); // end token always 0x0000FFFF. - if (isfail(ctx)) + if (failed) retval = (MOJOSHADER_parseData *) build_failed_assembly(ctx); else { diff --git a/mojoshader_internal.h b/mojoshader_internal.h index 302a7b64..a3878ef4 100644 --- a/mojoshader_internal.h +++ b/mojoshader_internal.h @@ -83,11 +83,6 @@ typedef int32_t int32; #define STATICARRAYLEN(x) ( (sizeof ((x))) / (sizeof ((x)[0])) ) -// Special-case return values from the parsing pipeline... -#define FAIL (-1) -#define NOFAIL (-2) -#define END_OF_STREAM (-3) - // Byteswap magic... @@ -269,7 +264,14 @@ typedef enum } MOJOSHADER_parsePhase; extern MOJOSHADER_parseData out_of_mem_data; -extern const char *out_of_mem_str; + +typedef struct ErrorList +{ + MOJOSHADER_error error; + struct ErrorList *next; +} ErrorList; + + #endif // _INCLUDE_MOJOSHADER_INTERNAL_H_