📄 preproc.c
字号:
error(ERR_WARNING, "trailing garbage after `%%include' ignored"); if (tline->type != TOK_INTERNAL_STRING) { p = tline->text + 1; /* point past the quote to the name */ p[strlen(p) - 1] = '\0'; /* remove the trailing quote */ } else p = tline->text; /* internal_string is easier */ expand_macros_in_string(&p); inc = nasm_malloc(sizeof(Include)); inc->next = istk; inc->conds = NULL; inc->fp = inc_fopen(p); inc->fname = src_set_fname(p); inc->lineno = src_set_linnum(0); inc->lineinc = 1; inc->expansion = NULL; inc->mstk = NULL; istk = inc; list->uplevel(LIST_INCLUDE); free_tlist(origline); return DIRECTIVE_FOUND; case PP_PUSH: tline = tline->next; skip_white_(tline); tline = expand_id(tline); if (!tok_type_(tline, TOK_ID)) { error(ERR_NONFATAL, "`%%push' expects a context identifier"); free_tlist(origline); return DIRECTIVE_FOUND; /* but we did _something_ */ } if (tline->next) error(ERR_WARNING, "trailing garbage after `%%push' ignored"); ctx = nasm_malloc(sizeof(Context)); ctx->next = cstk; ctx->localmac = NULL; ctx->name = nasm_strdup(tline->text); ctx->number = unique++; cstk = ctx; free_tlist(origline); break; case PP_REPL: tline = tline->next; skip_white_(tline); tline = expand_id(tline); if (!tok_type_(tline, TOK_ID)) { error(ERR_NONFATAL, "`%%repl' expects a context identifier"); free_tlist(origline); return DIRECTIVE_FOUND; /* but we did _something_ */ } if (tline->next) error(ERR_WARNING, "trailing garbage after `%%repl' ignored"); if (!cstk) error(ERR_NONFATAL, "`%%repl': context stack is empty"); else { nasm_free(cstk->name); cstk->name = nasm_strdup(tline->text); } free_tlist(origline); break; case PP_POP: if (tline->next) error(ERR_WARNING, "trailing garbage after `%%pop' ignored"); if (!cstk) error(ERR_NONFATAL, "`%%pop': context stack is already empty"); else ctx_pop(); free_tlist(origline); break; case PP_ERROR: tline->next = expand_smacro(tline->next); tline = tline->next; skip_white_(tline); if (tok_type_(tline, TOK_STRING)) { p = tline->text + 1; /* point past the quote to the name */ p[strlen(p) - 1] = '\0'; /* remove the trailing quote */ expand_macros_in_string(&p); error(ERR_NONFATAL, "%s", p); nasm_free(p); } else { p = detoken(tline, FALSE); error(ERR_WARNING, "%s", p); nasm_free(p); } free_tlist(origline); break; case PP_IF: case PP_IFCTX: case PP_IFDEF: case PP_IFID: case PP_IFIDN: case PP_IFIDNI: case PP_IFMACRO: case PP_IFNCTX: case PP_IFNDEF: case PP_IFNID: case PP_IFNIDN: case PP_IFNIDNI: case PP_IFNMACRO: case PP_IFNNUM: case PP_IFNSTR: case PP_IFNUM: case PP_IFSTR: if (istk->conds && !emitting(istk->conds->state)) j = COND_NEVER; else { j = if_condition(tline->next, i); tline->next = NULL; /* it got freed */ free_tlist(origline); j = j < 0 ? COND_NEVER : j ? COND_IF_TRUE : COND_IF_FALSE; } cond = nasm_malloc(sizeof(Cond)); cond->next = istk->conds; cond->state = j; istk->conds = cond; return DIRECTIVE_FOUND; case PP_ELIF: case PP_ELIFCTX: case PP_ELIFDEF: case PP_ELIFID: case PP_ELIFIDN: case PP_ELIFIDNI: case PP_ELIFMACRO: case PP_ELIFNCTX: case PP_ELIFNDEF: case PP_ELIFNID: case PP_ELIFNIDN: case PP_ELIFNIDNI: case PP_ELIFNMACRO: case PP_ELIFNNUM: case PP_ELIFNSTR: case PP_ELIFNUM: case PP_ELIFSTR: if (!istk->conds) error(ERR_FATAL, "`%s': no matching `%%if'", directives[i]); if (emitting(istk->conds->state) || istk->conds->state == COND_NEVER) istk->conds->state = COND_NEVER; else { /* * IMPORTANT: In the case of %if, we will already have * called expand_mmac_params(); however, if we're * processing an %elif we must have been in a * non-emitting mode, which would have inhibited * the normal invocation of expand_mmac_params(). Therefore, * we have to do it explicitly here. */ j = if_condition(expand_mmac_params(tline->next), i); tline->next = NULL; /* it got freed */ free_tlist(origline); istk->conds->state = j < 0 ? COND_NEVER : j ? COND_IF_TRUE : COND_IF_FALSE; } return DIRECTIVE_FOUND; case PP_ELSE: if (tline->next) error(ERR_WARNING, "trailing garbage after `%%else' ignored"); if (!istk->conds) error(ERR_FATAL, "`%%else': no matching `%%if'"); if (emitting(istk->conds->state) || istk->conds->state == COND_NEVER) istk->conds->state = COND_ELSE_FALSE; else istk->conds->state = COND_ELSE_TRUE; free_tlist(origline); return DIRECTIVE_FOUND; case PP_ENDIF: if (tline->next) error(ERR_WARNING, "trailing garbage after `%%endif' ignored"); if (!istk->conds) error(ERR_FATAL, "`%%endif': no matching `%%if'"); cond = istk->conds; istk->conds = cond->next; nasm_free(cond); free_tlist(origline); return DIRECTIVE_FOUND; case PP_MACRO: case PP_IMACRO: if (defining) error(ERR_FATAL, "`%%%smacro': already defining a macro", (i == PP_IMACRO ? "i" : "")); tline = tline->next; skip_white_(tline); tline = expand_id(tline); if (!tok_type_(tline, TOK_ID)) { error(ERR_NONFATAL, "`%%%smacro' expects a macro name", (i == PP_IMACRO ? "i" : "")); return DIRECTIVE_FOUND; } defining = nasm_malloc(sizeof(MMacro)); defining->name = nasm_strdup(tline->text); defining->casesense = (i == PP_MACRO); defining->plus = FALSE; defining->nolist = FALSE; defining->in_progress = FALSE; defining->rep_nest = NULL; tline = expand_smacro(tline->next); skip_white_(tline); if (!tok_type_(tline, TOK_NUMBER)) { error(ERR_NONFATAL, "`%%%smacro' expects a parameter count", (i == PP_IMACRO ? "i" : "")); defining->nparam_min = defining->nparam_max = 0; } else { defining->nparam_min = defining->nparam_max = readnum(tline->text, &j); if (j) error(ERR_NONFATAL, "unable to parse parameter count `%s'", tline->text); } if (tline && tok_is_(tline->next, "-")) { tline = tline->next->next; if (tok_is_(tline, "*")) defining->nparam_max = INT_MAX; else if (!tok_type_(tline, TOK_NUMBER)) error(ERR_NONFATAL, "`%%%smacro' expects a parameter count after `-'", (i == PP_IMACRO ? "i" : "")); else { defining->nparam_max = readnum(tline->text, &j); if (j) error(ERR_NONFATAL, "unable to parse parameter count `%s'", tline->text); if (defining->nparam_min > defining->nparam_max) error(ERR_NONFATAL, "minimum parameter count exceeds maximum"); } } if (tline && tok_is_(tline->next, "+")) { tline = tline->next; defining->plus = TRUE; } if (tline && tok_type_(tline->next, TOK_ID) && !nasm_stricmp(tline->next->text, ".nolist")) { tline = tline->next; defining->nolist = TRUE; } mmac = mmacros[hash(defining->name)]; while (mmac) { if (!strcmp(mmac->name, defining->name) && (mmac->nparam_min <= defining->nparam_max || defining->plus) && (defining->nparam_min <= mmac->nparam_max || mmac->plus)) { error(ERR_WARNING, "redefining multi-line macro `%s'", defining->name); break; } mmac = mmac->next; } /* * Handle default parameters. */ if (tline && tline->next) { defining->dlist = tline->next; tline->next = NULL; count_mmac_params(defining->dlist, &defining->ndefs, &defining->defaults); } else { defining->dlist = NULL; defining->defaults = NULL; } defining->expansion = NULL; free_tlist(origline); return DIRECTIVE_FOUND; case PP_ENDM: case PP_ENDMACRO: if (!defining) { error(ERR_NONFATAL, "`%s': not defining a macro", tline->text); return DIRECTIVE_FOUND; } k = hash(defining->name); defining->next = mmacros[k]; mmacros[k] = defining; defining = NULL; free_tlist(origline); return DIRECTIVE_FOUND; case PP_ROTATE: if (tline->next && tline->next->type == TOK_WHITESPACE) tline = tline->next; if (tline->next == NULL) { free_tlist(origline); error(ERR_NONFATAL, "`%%rotate' missing rotate count"); return DIRECTIVE_FOUND; } t = expand_smacro(tline->next); tline->next = NULL; free_tlist(origline); tline = t; tptr = &t; tokval.t_type = TOKEN_INVALID; evalresult = evaluate(ppscan, tptr, &tokval, NULL, pass, error, NULL); free_tlist(tline); if (!evalresult) return DIRECTIVE_FOUND; if (tokval.t_type) error(ERR_WARNING, "trailing garbage after expression ignored"); if (!is_simple(evalresult)) { error(ERR_NONFATAL, "non-constant value given to `%%rotate'"); return DIRECTIVE_FOUND; } mmac = istk->mstk; while (mmac && !mmac->name) /* avoid mistaking %reps for macros */ mmac = mmac->next_active; if (!mmac) { error(ERR_NONFATAL, "`%%rotate' invoked outside a macro call"); } else if (mmac->nparam == 0) { error(ERR_NONFATAL, "`%%rotate' invoked within macro without parameters"); } else { mmac->rotate = mmac->rotate + reloc_value(evalresult); if (mmac->rotate < 0) mmac->rotate = mmac->nparam - (-mmac->rotate) % mmac->nparam; mmac->rotate %= mmac->nparam; } return DIRECTIVE_FOUND; case PP_REP: nolist = FALSE; do { tline = tline->next; } while (tok_type_(tline, TOK_WHITESPACE)); if (tok_type_(tline, TOK_ID) && nasm_stricmp(tline->text, ".nolist") == 0) { nolist = TRUE; do { tline = tline->next; } while (tok_type_(tline, TOK_WHITESPACE)); } if (tline) { t = expand_smacro(tline); tptr = &t; tokval.t_type = TOKEN_INVALID; evalresult = evaluate(ppscan, tptr, &tokval, NULL, pass, error, NULL); if (!evalresult) { free_tlist(origline); return DIRECTIVE_FOUND; } if (tokval.t_type) error(ERR_WARNING, "trailing garbage after expression ignored"); if (!is_simple(evalresult)) { error(ERR_NONFATAL, "non-constant value given to `%%rep'"); return DIRECTIVE_FOUND; } i = (int)reloc_value(evalresult) + 1; } else { error(ERR_NONFATAL, "`%%rep' expects a repeat count"); i = 0; } free_tlist(origline); tmp_defining = defining; defining = nasm_malloc(sizeof(MMacro)); defining->name = NULL; /* flags this macro as a %rep block */ defining->casesense = 0; defining->plus = FALSE; defining->nolist = nolist; defining->in_progress = i; defining->nparam_min = defining->nparam_max = 0; defining->defaults = NULL; defining->dlist = NULL; defining->expansion = NULL; defining->next_active = istk->mstk; defining->rep_nest = tmp_defining; return DIRECTIVE_FOUND; case PP_ENDREP: if (!defining || defining->name) { error(ERR_NONFATAL, "`%%endrep': no matching `%%rep'"); return DIRECTIVE_FOUND; } /* * Now we have a "macro" defined - although it has no name * and we won't be entering it in the hash tables - we must * push a macro-end marker for it on to istk->expansion. * After that, it will take care of propagating itself (a * macro-end marker line for a macro which is really a %rep * block will cause the macro to be re-expanded, complete * with another macro-end marker to ensure the process * continues) until the whole expansion is forcibly removed * from istk->expansion by a %exitrep. */ l = nasm_malloc(sizeof(Line)); l->next = istk->expansion; l->finishes = defining; l->first = NULL; istk->expansion = l; istk->mstk = defining; list->uplevel(defining->nolist ? LIST_MACRO_NOLIST : LIST_MACRO); tmp_defining = defining; defining = defining->rep_nest; free_tlist(origline); return DIRECTIVE_FOUND; case PP_EXITREP: /* * We must search along istk->expansion until we hit a * macro-end marker for a macro with no name. Then we set * its `in_progress' flag to 0. */ for (l = istk->expansion; l; l = l->next) if (l->finishes && !l->finishes->name) break; if (l) l->finishes->in_progress = 0; else error(ERR_NONFATAL, "`%%exitrep' not within `%%rep' block"); free_tlist(origline); return DIRECTIVE_FOUND; case PP_XDEFINE: case PP_IXDEFINE: case PP_DEFINE: case PP_IDEFINE: tline = tline->next; skip_white_(tline); tline = expand_id(tline); if (!tline || (tline->type != TOK_ID && (tline->type != TOK_PREPROC_ID || tline->text[1] != '$'))) { error(ERR_NONFATAL, "`%%%s%sdefine' expects a macro identifier", ((i == PP_IDEFINE || i == PP_IXDEFINE) ? "i" : ""), ((i == PP_XDEFINE || i == PP_IXDEFINE) ? "x" : "")); free_tlist(origline); return DIRECTIVE_FOUND; } ctx = get_ctx(tline->text, FALSE); if (!ctx) smhead = &smacros[hash(tline->text)]; else smhead = &ctx->localmac; mname = tline->text; last = tline; param_start = tline = tline->next; nparam = 0; /* Expand the macro definition now for %xdefine and %ixdefine */ if ((i == PP_XDEFINE) || (i == PP_IXDEFINE)) tline = expand_smacro(tline); if (tok_is_(tline, "(")) { /* * This macro has parameters. */ tline = tline->next; while (1) { skip_white_(tline); if (!tline) { error(ERR_NONFATAL, "parameter identifier expected"); free_tlist(origline); return DIRECTIVE_
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -