static int ep_parse_pass_command(struct effect_parser *ep, struct ep_pass *pass) { struct darray *call; /* struct cf_token */ if (!cf_next_valid_token(&ep->cfp)) return PARSE_EOF; if (cf_token_is(&ep->cfp, "vertex_shader") || cf_token_is(&ep->cfp, "vertex_program")) { call = &pass->vertex_program.da; } else if (cf_token_is(&ep->cfp, "pixel_shader") || cf_token_is(&ep->cfp, "pixel_program")) { call = &pass->fragment_program.da; } else { cf_adderror_syntax_error(&ep->cfp); if (!cf_go_to_valid_token(&ep->cfp, ";", "}")) return PARSE_EOF; return PARSE_CONTINUE; } if (cf_next_token_should_be(&ep->cfp, "=", ";", "}") != PARSE_SUCCESS) return PARSE_CONTINUE; if (!cf_next_valid_token(&ep->cfp)) return PARSE_EOF; if (cf_token_is(&ep->cfp, "compile")) { cf_adderror(&ep->cfp, "compile keyword not necessary", LEX_WARNING, NULL, NULL, NULL); if (!cf_next_valid_token(&ep->cfp)) return PARSE_EOF; } return ep_parse_pass_command_call(ep, call); }
bool shader_parse(struct shader_parser *sp, const char *shader, const char *file) { if (!cf_parser_parse(&sp->cfp, shader, file)) return false; while (sp->cfp.cur_token && sp->cfp.cur_token->type != CFTOKEN_NONE) { if (cf_token_is(&sp->cfp, ";") || is_whitespace(*sp->cfp.cur_token->str.array)) { sp->cfp.cur_token++; } else if (cf_token_is(&sp->cfp, "struct")) { sp_parse_struct(sp); } else if (cf_token_is(&sp->cfp, "sampler_state")) { sp_parse_sampler_state(sp); } else if (cf_token_is(&sp->cfp, "{")) { cf_adderror(&sp->cfp, "Unexpected code segment", LEX_ERROR, NULL, NULL, NULL); cf_pass_pair(&sp->cfp, '{', '}'); } else { /* parameters and functions */ sp_parse_other(sp); } } return !error_data_has_errors(&sp->cfp.error_list); }
static int ep_parse_pass(struct effect_parser *ep, struct ep_pass *pass) { struct cf_token peek; if (!cf_token_is(&ep->cfp, "pass")) return PARSE_UNEXPECTED_CONTINUE; if (!cf_next_valid_token(&ep->cfp)) return PARSE_EOF; if (!cf_token_is(&ep->cfp, "{")) { pass->name = bstrdup_n(ep->cfp.cur_token->str.array, ep->cfp.cur_token->str.len); if (!cf_next_valid_token(&ep->cfp)) return PARSE_EOF; } if (!cf_peek_valid_token(&ep->cfp, &peek)) return PARSE_EOF; while (strref_cmp(&peek.str, "}") != 0) { int ret = ep_parse_pass_command(ep, pass); if (ret < 0 && ret != PARSE_CONTINUE) return ret; if (!cf_peek_valid_token(&ep->cfp, &peek)) return PARSE_EOF; } /* token is '}' */ cf_next_token(&ep->cfp); return PARSE_SUCCESS; }
static inline bool ep_parse_func_contents(struct effect_parser *ep, struct ep_func *func) { int braces = 1; dstr_cat_strref(&func->contents, &ep->cfp.cur_token->str); while (braces > 0) { if ((ep->cfp.cur_token++)->type == CFTOKEN_NONE) return false; if (ep->cfp.cur_token->type == CFTOKEN_SPACETAB || ep->cfp.cur_token->type == CFTOKEN_NEWLINE) { } else if (cf_token_is(&ep->cfp, "{")) { braces++; } else if (cf_token_is(&ep->cfp, "}")) { braces--; } else if (ep_process_struct_dep(ep, func) || ep_process_func_dep(ep, func) || ep_process_sampler_dep(ep, func) || ep_process_param_dep(ep, func)) { } dstr_cat_strref(&func->contents, &ep->cfp.cur_token->str); } return true; }
static void ep_parse_param(struct effect_parser *ep, char *type, char *name, bool is_property, bool is_const, bool is_uniform) { struct ep_param param; ep_param_init(¶m, type, name, is_property, is_const, is_uniform); if (cf_token_is(&ep->cfp, ";")) goto complete; if (cf_token_is(&ep->cfp, "[") && !ep_parse_param_array(ep, ¶m)) goto error; if (cf_token_is(&ep->cfp, "<") && !ep_parse_param_annotations(ep, ¶m)) goto error; if (cf_token_is(&ep->cfp, "=") && !ep_parse_param_assign(ep, ¶m)) goto error; /* if (cf_token_is(&ep->cfp, "<") && !ep_parse_param_property(ep, ¶m)) goto error; */ if (!cf_token_is(&ep->cfp, ";")) goto error; complete: da_push_back(ep->params, ¶m); return; error: ep_param_free(¶m); }
bool ep_parse(struct effect_parser *ep, gs_effect_t *effect, const char *effect_string, const char *file) { bool success; const char *graphics_preprocessor = gs_preprocessor_name(); if (graphics_preprocessor) { struct cf_def def; cf_def_init(&def); def.name.str.array = graphics_preprocessor; def.name.str.len = strlen(graphics_preprocessor); strref_copy(&def.name.unmerged_str, &def.name.str); cf_preprocessor_add_def(&ep->cfp.pp, &def); } ep->effect = effect; if (!cf_parser_parse(&ep->cfp, effect_string, file)) return false; while (ep->cfp.cur_token && ep->cfp.cur_token->type != CFTOKEN_NONE) { if (cf_token_is(&ep->cfp, ";") || is_whitespace(*ep->cfp.cur_token->str.array)) { /* do nothing */ ep->cfp.cur_token++; } else if (cf_token_is(&ep->cfp, "struct")) { ep_parse_struct(ep); } else if (cf_token_is(&ep->cfp, "technique")) { ep_parse_technique(ep); } else if (cf_token_is(&ep->cfp, "sampler_state")) { ep_parse_sampler_state(ep); } else if (cf_token_is(&ep->cfp, "{")) { /* add error and pass braces */ cf_adderror(&ep->cfp, "Unexpected code segment", LEX_ERROR, NULL, NULL, NULL); cf_pass_pair(&ep->cfp, '{', '}'); } else { /* parameters and functions */ ep_parse_other(ep); } } success = !error_data_has_errors(&ep->cfp.error_list); if (success) success = ep_compile(ep); return success; }
static int ep_parse_annotations(struct effect_parser *ep, struct darray *annotations) { if (!cf_token_is(&ep->cfp, "<")) { cf_adderror_expecting(&ep->cfp, "<"); goto error; } /* get annotation variables */ while (true) { bool do_break = false; struct ep_param var; ep_param_init(&var, bstrdup(""), bstrdup(""), false, false, false); switch (ep_parse_param_annotation_var(ep, &var)) { case PARSE_UNEXPECTED_CONTINUE: cf_adderror_syntax_error(&ep->cfp); /* Falls through. */ case PARSE_CONTINUE: ep_param_free(&var); continue; case PARSE_UNEXPECTED_BREAK: cf_adderror_syntax_error(&ep->cfp); /* Falls through. */ case PARSE_BREAK: ep_param_free(&var); do_break = true; break; case PARSE_EOF: ep_param_free(&var); goto error; } if (do_break) break; darray_push_back(sizeof(struct ep_param), annotations, &var); } if (!cf_token_is(&ep->cfp, ">")) { cf_adderror_expecting(&ep->cfp, ">"); goto error; } if (!cf_next_valid_token(&ep->cfp)) goto error; return true; error: return false; }
static void ep_parse_technique(struct effect_parser *ep) { struct ep_technique ept; ep_technique_init(&ept); if (cf_next_name(&ep->cfp, &ept.name, "name", ";") != PARSE_SUCCESS) goto error; if (!cf_next_valid_token(&ep->cfp)) return; if (!cf_token_is(&ep->cfp, "{")) { if (!cf_go_to_token(&ep->cfp, ";", NULL)) { cf_adderror_expecting(&ep->cfp, ";"); return; } cf_adderror_expecting(&ep->cfp, "{"); goto error; } if (!cf_next_valid_token(&ep->cfp)) goto error; while (!cf_token_is(&ep->cfp, "}")) { struct ep_pass pass; ep_pass_init(&pass); switch (ep_parse_pass(ep, &pass)) { case PARSE_UNEXPECTED_CONTINUE: ep_pass_free(&pass); if (!cf_go_to_token(&ep->cfp, "}", NULL)) goto error; continue; case PARSE_EOF: ep_pass_free(&pass); goto error; } da_push_back(ept.passes, &pass); if (!cf_next_valid_token(&ep->cfp)) goto error; } /* pass the current token (which is '}') if we reached here */ cf_next_token(&ep->cfp); da_push_back(ep->techniques, &ept); return; error: cf_next_token(&ep->cfp); ep_technique_free(&ept); }
static void sp_parse_other(struct shader_parser *sp) { bool is_const = false, is_uniform = false; char *type = NULL, *name = NULL; if (!sp_get_var_specifiers(sp, &is_const, &is_uniform)) goto error; if (cf_get_name(&sp->cfp, &type, "type", ";") != PARSE_SUCCESS) goto error; if (cf_next_name(&sp->cfp, &name, "name", ";") != PARSE_SUCCESS) goto error; if (!cf_next_valid_token(&sp->cfp)) goto error; if (cf_token_is(&sp->cfp, "(")) { report_invalid_func_keyword(sp, "const", is_const); report_invalid_func_keyword(sp, "uniform", is_uniform); sp_parse_function(sp, type, name); return; } else { sp_parse_param(sp, type, name, is_const, is_uniform); return; } error: bfree(type); bfree(name); }
static void ep_parse_other(struct effect_parser *ep) { bool is_property = false, is_const = false, is_uniform = false; char *type = NULL, *name = NULL; if (!ep_get_var_specifiers(ep, &is_property, &is_const, &is_uniform)) goto error; if (cf_get_name(&ep->cfp, &type, "type", ";") != PARSE_SUCCESS) goto error; if (cf_next_name(&ep->cfp, &name, "name", ";") != PARSE_SUCCESS) goto error; if (!cf_next_valid_token(&ep->cfp)) goto error; if (cf_token_is(&ep->cfp, "(")) { report_invalid_func_keyword(ep, "property", is_property); report_invalid_func_keyword(ep, "const", is_const); report_invalid_func_keyword(ep, "uniform", is_uniform); ep_parse_function(ep, type, name); return; } else { ep_parse_param(ep, type, name, is_property, is_const, is_uniform); return; } error: bfree(type); bfree(name); }
static inline int ep_parse_param_assign_intfloat(struct effect_parser *ep, struct ep_param *param, bool is_float) { int code; bool is_negative = false; if (!cf_next_valid_token(&ep->cfp)) return PARSE_EOF; if (cf_token_is(&ep->cfp, "-")) { is_negative = true; if (!cf_next_token(&ep->cfp)) return PARSE_EOF; } code = cf_token_is_type(&ep->cfp, CFTOKEN_NUM, "numeric value", ";"); if (code != PARSE_SUCCESS) return code; if (is_float) { float f = (float)os_strtod(ep->cfp.cur_token->str.array); if (is_negative) f = -f; da_push_back_array(param->default_val, &f, sizeof(float)); } else { long l = strtol(ep->cfp.cur_token->str.array, NULL, 10); if (is_negative) l = -l; da_push_back_array(param->default_val, &l, sizeof(long)); } return PARSE_SUCCESS; }
static void ep_parse_function(struct effect_parser *ep, char *type, char *name) { struct ep_func func; int code; ep_func_init(&func, type, name); if (ep_getstruct(ep, type)) da_push_back(func.struct_deps, &func.ret_type); if (!ep_parse_func_params(ep, &func)) goto error; if (!cf_next_valid_token(&ep->cfp)) goto error; /* if function is mapped to something, for example COLOR */ if (cf_token_is(&ep->cfp, ":")) { code = cf_next_name(&ep->cfp, &func.mapping, "mapping specifier", "{"); if (code == PARSE_EOF) goto error; else if (code != PARSE_CONTINUE) { if (!cf_next_valid_token(&ep->cfp)) goto error; } } if (!cf_token_is(&ep->cfp, "{")) { cf_adderror_expecting(&ep->cfp, "{"); goto error; } if (!ep_parse_func_contents(ep, &func)) goto error; /* it is established that the current token is '}' if we reach this */ cf_next_token(&ep->cfp); da_push_back(ep->funcs, &func); return; error: ep_func_free(&func); }
static void sp_parse_function(struct shader_parser *sp, char *type, char *name) { struct shader_func func; shader_func_init(&func, type, name); if (!sp_parse_func_params(sp, &func)) goto error; if (!cf_next_valid_token(&sp->cfp)) goto error; /* if function is mapped to something, for example COLOR */ if (cf_token_is(&sp->cfp, ":")) { char *mapping = NULL; int errorcode = cf_next_name(&sp->cfp, &mapping, "mapping", "{"); if (errorcode != PARSE_SUCCESS) goto error; func.mapping = mapping; if (!cf_next_valid_token(&sp->cfp)) goto error; } if (!cf_token_is(&sp->cfp, "{")) { cf_adderror_expecting(&sp->cfp, "{"); goto error; } func.start = sp->cfp.cur_token; if (!cf_pass_pair(&sp->cfp, '{', '}')) goto error; /* it is established that the current token is '}' if we reach this */ cf_next_token(&sp->cfp); func.end = sp->cfp.cur_token; da_push_back(sp->funcs, &func); return; error: shader_func_free(&func); }
static inline int ep_parse_param_assign_bool(struct effect_parser *ep, struct ep_param *param) { if (!cf_next_valid_token(&ep->cfp)) return PARSE_EOF; if (cf_token_is(&ep->cfp, "true")) { long l = 1; da_push_back_array(param->default_val, &l, sizeof(long)); return PARSE_SUCCESS; } else if (cf_token_is(&ep->cfp, "false")) { long l = 0; da_push_back_array(param->default_val, &l, sizeof(long)); return PARSE_SUCCESS; } cf_adderror_expecting(&ep->cfp, "true or false"); return PARSE_EOF; }
static inline int ep_parse_pass_command_call(struct effect_parser *ep, struct darray *call) { struct cf_token end_token; cf_token_clear(&end_token); while (!cf_token_is(&ep->cfp, ";")) { if (cf_token_is(&ep->cfp, "}")) { cf_adderror_expecting(&ep->cfp, ";"); return PARSE_CONTINUE; } darray_push_back(sizeof(struct cf_token), call, ep->cfp.cur_token); if (!cf_next_valid_token(&ep->cfp)) return PARSE_EOF; } darray_push_back(sizeof(struct cf_token), call, ep->cfp.cur_token); darray_push_back(sizeof(struct cf_token), call, &end_token); return PARSE_SUCCESS; }
static bool sp_parse_func_params(struct shader_parser *sp, struct shader_func *func) { struct cf_token peek; int code; cf_token_clear(&peek); if (!cf_peek_valid_token(&sp->cfp, &peek)) return false; if (*peek.str.array == ')') { cf_next_token(&sp->cfp); goto exit; } do { struct shader_var var; shader_var_init(&var); if (!cf_token_is(&sp->cfp, "(") && !cf_token_is(&sp->cfp, ",")) cf_adderror_syntax_error(&sp->cfp); code = sp_parse_func_param(sp, &var); if (code != PARSE_SUCCESS) { shader_var_free(&var); if (code == PARSE_CONTINUE) goto exit; else if (code == PARSE_EOF) return false; } da_push_back(func->params, &var); } while (!cf_token_is(&sp->cfp, ")")); exit: return true; }
static void sp_parse_param(struct shader_parser *sp, char *type, char *name, bool is_const, bool is_uniform) { struct shader_var param; shader_var_init_param(¶m, type, name, is_uniform, is_const); if (cf_token_is(&sp->cfp, ";")) goto complete; if (cf_token_is(&sp->cfp, "[") && !sp_parse_param_array(sp, ¶m)) goto error; if (cf_token_is(&sp->cfp, "=") && !sp_parse_param_assign(sp, ¶m)) goto error; if (!cf_token_is(&sp->cfp, ";")) goto error; complete: da_push_back(sp->params, ¶m); return; error: shader_var_free(¶m); }
static inline bool gl_write_texture_call(struct gl_shader_parser *glsp, struct shader_var *var, const char *call, bool sampler) { struct cf_parser *cfp = &glsp->parser.cfp; size_t sampler_id = (size_t)-1; if (!cf_next_token(cfp)) return false; if (!cf_token_is(cfp, "(")) return false; if (sampler) { if (!cf_next_token(cfp)) return false; sampler_id = sp_getsampler(glsp, cfp->cur_token); if (sampler_id == (size_t) -1) return false; var->gl_sampler_id = sampler_id; if (!cf_next_token(cfp)) return false; if (!cf_token_is(cfp, ",")) return false; } dstr_cat(&glsp->gl_string, call); dstr_cat(&glsp->gl_string, "("); dstr_cat(&glsp->gl_string, var->name); dstr_cat(&glsp->gl_string, ", "); return true; }
static bool gl_write_saturate(struct gl_shader_parser *glsp, struct cf_token **p_token) { struct cf_parser *cfp = &glsp->parser.cfp; cfp->cur_token = *p_token; if (!cf_next_token(cfp)) return false; if (!cf_token_is(cfp, "(")) return false; dstr_cat(&glsp->gl_string, "clamp"); gl_write_function_contents(glsp, &cfp->cur_token, ")"); dstr_cat(&glsp->gl_string, ", 0.0, 1.0)"); *p_token = cfp->cur_token; return true; }
static inline int ep_check_for_keyword(struct effect_parser *ep, const char *keyword, bool *val) { bool new_val = cf_token_is(&ep->cfp, keyword); if (new_val) { if (!cf_next_valid_token(&ep->cfp)) return PARSE_EOF; if (new_val && *val) cf_adderror(&ep->cfp, "'$1' keyword already specified", LEX_WARNING, keyword, NULL, NULL); *val = new_val; return PARSE_CONTINUE; } return PARSE_SUCCESS; }
static inline int ep_parse_func_param(struct effect_parser *ep, struct ep_func *func, struct ep_var *var) { int code; if (!cf_next_valid_token(&ep->cfp)) return PARSE_EOF; code = ep_check_for_keyword(ep, "uniform", &var->uniform); if (code == PARSE_EOF) return PARSE_EOF; code = cf_get_name(&ep->cfp, &var->type, "type", ")"); if (code != PARSE_SUCCESS) return code; code = cf_next_name(&ep->cfp, &var->name, "name", ")"); if (code != PARSE_SUCCESS) return code; if (!cf_next_valid_token(&ep->cfp)) return PARSE_EOF; if (cf_token_is(&ep->cfp, ":")) { code = cf_next_name(&ep->cfp, &var->mapping, "mapping specifier", ")"); if (code != PARSE_SUCCESS) return code; if (!cf_next_valid_token(&ep->cfp)) return PARSE_EOF; } if (ep_getstruct(ep, var->type) != NULL) da_push_back(func->struct_deps, &var->type); else if (ep_getsampler(ep, var->type) != NULL) da_push_back(func->sampler_deps, &var->type); return PARSE_SUCCESS; }
static inline int sp_parse_func_param(struct shader_parser *sp, struct shader_var *var) { int code; bool is_uniform = false; if (!cf_next_valid_token(&sp->cfp)) return PARSE_EOF; code = sp_check_for_keyword(sp, "uniform", &is_uniform); if (code == PARSE_EOF) return PARSE_EOF; var->var_type = is_uniform ? SHADER_VAR_UNIFORM : SHADER_VAR_NONE; code = cf_get_name(&sp->cfp, &var->type, "type", ")"); if (code != PARSE_SUCCESS) return code; code = cf_next_name(&sp->cfp, &var->name, "name", ")"); if (code != PARSE_SUCCESS) return code; if (!cf_next_valid_token(&sp->cfp)) return PARSE_EOF; if (cf_token_is(&sp->cfp, ":")) { code = cf_next_name(&sp->cfp, &var->mapping, "mapping specifier", ")"); if (code != PARSE_SUCCESS) return code; if (!cf_next_valid_token(&sp->cfp)) return PARSE_EOF; } return PARSE_SUCCESS; }
/* processes texture.Sample(sampler, texcoord) */ static bool gl_write_texture_code(struct gl_shader_parser *glsp, struct cf_token **p_token, struct shader_var *var) { struct cf_parser *cfp = &glsp->parser.cfp; bool written = false; cfp->cur_token = *p_token; if (!cf_next_token(cfp)) return false; if (!cf_token_is(cfp, ".")) return false; if (!cf_next_token(cfp)) return false; const char *function_end = ")"; if (cf_token_is(cfp, "Sample")) written = gl_write_texture_call(glsp, var, "texture", true); else if (cf_token_is(cfp, "SampleBias")) written = gl_write_texture_call(glsp, var, "texture", true); else if (cf_token_is(cfp, "SampleGrad")) written = gl_write_texture_call(glsp, var, "textureGrad", true); else if (cf_token_is(cfp, "SampleLevel")) written = gl_write_texture_call(glsp, var, "textureLod", true); else if (cf_token_is(cfp, "Load")) { written = gl_write_texture_call(glsp, var, "texelFetch", false); dstr_cat(&glsp->gl_string, "("); function_end = ").xy, 0)"; } if (!written) return false; if (!cf_next_token(cfp)) return false; gl_write_function_contents(glsp, &cfp->cur_token, ")"); dstr_cat(&glsp->gl_string, function_end); *p_token = cfp->cur_token; return true; }
static inline int ep_parse_param_annotation_var(struct effect_parser *ep, struct ep_param *var) { int code; /* -------------------------------------- */ /* variable type */ if (!cf_next_valid_token(&ep->cfp)) return PARSE_EOF; if (cf_token_is(&ep->cfp, ";")) return PARSE_CONTINUE; if (cf_token_is(&ep->cfp, ">")) return PARSE_BREAK; code = cf_token_is_type(&ep->cfp, CFTOKEN_NAME, "type name", ";"); if (code != PARSE_SUCCESS) return code; bfree(var->type); cf_copy_token(&ep->cfp, &var->type); /* -------------------------------------- */ /* variable name */ if (!cf_next_valid_token(&ep->cfp)) return PARSE_EOF; if (cf_token_is(&ep->cfp, ";")) { cf_adderror_expecting(&ep->cfp, "variable name"); return PARSE_UNEXPECTED_CONTINUE; } if (cf_token_is(&ep->cfp, ">")) { cf_adderror_expecting(&ep->cfp, "variable name"); return PARSE_UNEXPECTED_BREAK; } code = cf_token_is_type(&ep->cfp, CFTOKEN_NAME, "variable name", ";"); if (code != PARSE_SUCCESS) return code; bfree(var->name); cf_copy_token(&ep->cfp, &var->name); /* -------------------------------------- */ /* variable mapping if any (POSITION, TEXCOORD, etc) */ if (!cf_next_valid_token(&ep->cfp)) return PARSE_EOF; if (cf_token_is(&ep->cfp, ":")) { cf_adderror_expecting(&ep->cfp, "= or ;"); return PARSE_UNEXPECTED_BREAK; } else if (cf_token_is(&ep->cfp, ">")) { cf_adderror_expecting(&ep->cfp, "= or ;"); return PARSE_UNEXPECTED_BREAK; } else if (cf_token_is(&ep->cfp, "=")) { if (!ep_parse_param_assign(ep, var)) { cf_adderror_expecting(&ep->cfp, "assignment value"); return PARSE_UNEXPECTED_BREAK; } } /* -------------------------------------- */ if (!cf_token_is(&ep->cfp, ";")) { if (!cf_go_to_valid_token(&ep->cfp, ";", ">")) { cf_adderror_expecting(&ep->cfp, "; or >"); return PARSE_EOF; } return PARSE_CONTINUE; } return PARSE_SUCCESS; }
static inline int ep_parse_struct_var(struct effect_parser *ep, struct ep_var *var) { int code; /* -------------------------------------- */ /* variable type */ if (!cf_next_valid_token(&ep->cfp)) return PARSE_EOF; if (cf_token_is(&ep->cfp, ";")) return PARSE_CONTINUE; if (cf_token_is(&ep->cfp, "}")) return PARSE_BREAK; code = cf_token_is_type(&ep->cfp, CFTOKEN_NAME, "type name", ";"); if (code != PARSE_SUCCESS) return code; cf_copy_token(&ep->cfp, &var->type); /* -------------------------------------- */ /* variable name */ if (!cf_next_valid_token(&ep->cfp)) return PARSE_EOF; if (cf_token_is(&ep->cfp, ";")) return PARSE_UNEXPECTED_CONTINUE; if (cf_token_is(&ep->cfp, "}")) return PARSE_UNEXPECTED_BREAK; code = cf_token_is_type(&ep->cfp, CFTOKEN_NAME, "variable name", ";"); if (code != PARSE_SUCCESS) return code; cf_copy_token(&ep->cfp, &var->name); /* -------------------------------------- */ /* variable mapping if any (POSITION, TEXCOORD, etc) */ if (!cf_next_valid_token(&ep->cfp)) return PARSE_EOF; if (cf_token_is(&ep->cfp, ":")) { if (!cf_next_valid_token(&ep->cfp)) return PARSE_EOF; if (cf_token_is(&ep->cfp, ";")) return PARSE_UNEXPECTED_CONTINUE; if (cf_token_is(&ep->cfp, "}")) return PARSE_UNEXPECTED_BREAK; code = cf_token_is_type(&ep->cfp, CFTOKEN_NAME, "mapping name", ";"); if (code != PARSE_SUCCESS) return code; cf_copy_token(&ep->cfp, &var->mapping); if (!cf_next_valid_token(&ep->cfp)) return PARSE_EOF; } /* -------------------------------------- */ if (!cf_token_is(&ep->cfp, ";")) { if (!cf_go_to_valid_token(&ep->cfp, ";", "}")) return PARSE_EOF; return PARSE_CONTINUE; } return PARSE_SUCCESS; }