/* collects parameter tokens of a used macro and stores them for the unwrap */ static void cf_preprocess_save_macro_params(struct cf_preprocessor *pp, struct cf_token **p_cur_token, const struct cf_def *def, const struct cf_token *base, const struct macro_params *cur_params, struct macro_params *dst) { struct cf_token *cur_token = *p_cur_token; size_t count = 0; next_token(&cur_token, false); if (cur_token->type != CFTOKEN_OTHER || *cur_token->str.array != '(') { cf_adderror_expecting(pp, cur_token, "'('"); goto exit; } do { struct macro_param param; macro_param_init(¶m); cur_token++; count++; cf_preprocess_save_macro_param(pp, &cur_token, ¶m, base, cur_params); if (cur_token->type != CFTOKEN_OTHER || (*cur_token->str.array != ',' && *cur_token->str.array != ')')) { macro_param_free(¶m); cf_adderror_expecting(pp, cur_token, "',' or ')'"); goto exit; } if (param_is_whitespace(¶m)) { /* if 0-param macro, ignore first entry */ if (count == 1 && !def->params.num && *cur_token->str.array == ')') { macro_param_free(¶m); break; } } if (count <= def->params.num) { cf_token_copy(¶m.name, cf_def_getparam(def, count-1)); da_push_back(dst->params, ¶m); } else { macro_param_free(¶m); } } while (*cur_token->str.array != ')'); if (count != def->params.num) cf_adderror(pp, cur_token, "Mismatching number of macro parameters", NULL, NULL, NULL); exit: *p_cur_token = cur_token; }
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 cf_preprocess_ifdef(struct cf_preprocessor *pp, bool ifnot, struct cf_token **p_cur_token) { struct cf_token *cur_token = *p_cur_token; struct cf_def *def; bool is_true; next_token(&cur_token, true); if (cur_token->type != CFTOKEN_NAME) { cf_adderror_expecting(pp, cur_token, "identifier"); go_to_newline(&cur_token); goto exit; } def = cf_preprocess_get_def(pp, &cur_token->str); is_true = (def == NULL) == ifnot; if (!cf_preprocess_subblock(pp, !is_true, &cur_token)) goto exit; if (strref_cmp(&cur_token->str, "else") == 0) { if (!cf_preprocess_subblock(pp, is_true, &cur_token)) goto exit; /*} else if (strref_cmp(&cur_token->str, "elif") == 0) {*/ } cur_token++; exit: *p_cur_token = cur_token; }
static void cf_preprocess_include(struct cf_preprocessor *pp, struct cf_token **p_cur_token) { struct cf_token *cur_token = *p_cur_token; if (pp->ignore_state) { go_to_newline(p_cur_token); return; } next_token(&cur_token, true); if (cur_token->type != CFTOKEN_STRING) { cf_adderror_expecting(pp, cur_token, "string"); go_to_newline(&cur_token); goto exit; } if (is_sys_include(&cur_token->str)) { /* TODO */ } else if (is_loc_include(&cur_token->str)) { if (!pp->ignore_state) cf_include_file(pp, cur_token); } else { cf_adderror(pp, cur_token, "Invalid or incomplete string", NULL, NULL, NULL); go_to_newline(&cur_token); goto exit; } cur_token++; exit: *p_cur_token = cur_token; }
static bool cf_preprocess_macro_params(struct cf_preprocessor *pp, struct cf_def *def, struct cf_token **p_cur_token) { struct cf_token *cur_token = *p_cur_token; bool success = false; def->macro = true; do { next_token(&cur_token, true); if (cur_token->type != CFTOKEN_NAME) { cf_adderror_expecting(pp, cur_token, "identifier"); go_to_newline(&cur_token); goto exit; } cf_def_addparam(def, cur_token); next_token(&cur_token, true); if (cur_token->type != CFTOKEN_OTHER || (*cur_token->str.array != ',' && *cur_token->str.array != ')')) { cf_adderror_expecting(pp, cur_token, "',' or ')'"); go_to_newline(&cur_token); goto exit; } } while (*cur_token->str.array != ')'); /* ended properly, now go to first define token (or newline) */ next_token(&cur_token, true); success = true; exit: *p_cur_token = cur_token; return success; }
static void cf_preprocess_define(struct cf_preprocessor *pp, struct cf_token **p_cur_token) { struct cf_token *cur_token = *p_cur_token; struct cf_def def; if (pp->ignore_state) { go_to_newline(p_cur_token); return; } cf_def_init(&def); next_token(&cur_token, true); if (cur_token->type != CFTOKEN_NAME) { cf_adderror_expecting(pp, cur_token, "identifier"); go_to_newline(&cur_token); goto exit; } append_space(pp, &def.tokens.da, NULL); cf_token_copy(&def.name, cur_token); if (!next_token(&cur_token, true)) goto complete; /* process macro */ if (*cur_token->str.array == '(') { if (!cf_preprocess_macro_params(pp, &def, &cur_token)) goto error; } while (cur_token->type != CFTOKEN_NEWLINE && cur_token->type != CFTOKEN_NONE) cf_def_addtoken(&def, cur_token++); complete: append_end_token(&def.tokens.da); append_space(pp, &def.tokens.da, NULL); da_push_back(pp->defines, &def); goto exit; error: cf_def_free(&def); exit: *p_cur_token = cur_token; }
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 void cf_preprocess_undef(struct cf_preprocessor *pp, struct cf_token **p_cur_token) { struct cf_token *cur_token = *p_cur_token; if (pp->ignore_state) { go_to_newline(p_cur_token); return; } next_token(&cur_token, true); if (cur_token->type != CFTOKEN_NAME) { cf_adderror_expecting(pp, cur_token, "identifier"); go_to_newline(&cur_token); goto exit; } cf_preprocess_remove_def_strref(pp, &cur_token->str); cur_token++; exit: *p_cur_token = cur_token; }
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; }