📄 preproc.c
字号:
} else if (t->text) { len += strlen(t->text); } } p = line = nasm_malloc(len + 1); for (t = tlist; t; t = t->next) { if (t->type == TOK_WHITESPACE) { *p = ' '; p++; *p = '\0'; } else if (t->text) { strcpy(p, t->text); p += strlen(p); } } *p = '\0'; return line;}/* * A scanner, suitable for use by the expression evaluator, which * operates on a line of Tokens. Expects a pointer to a pointer to * the first token in the line to be passed in as its private_data * field. */static intppscan(void *private_data, struct tokenval *tokval){ Token **tlineptr = private_data; Token *tline; do { tline = *tlineptr; *tlineptr = tline ? tline->next : NULL; } while (tline && (tline->type == TOK_WHITESPACE || tline->type == TOK_COMMENT)); if (!tline) return tokval->t_type = TOKEN_EOS; if (tline->text[0] == '$' && !tline->text[1]) return tokval->t_type = TOKEN_HERE; if (tline->text[0] == '$' && tline->text[1] == '$' && !tline->text[2]) return tokval->t_type = TOKEN_BASE; if (tline->type == TOK_ID) { tokval->t_charptr = tline->text; if (tline->text[0] == '$') { tokval->t_charptr++; return tokval->t_type = TOKEN_ID; } /* * This is the only special case we actually need to worry * about in this restricted context. */ if (!nasm_stricmp(tline->text, "seg")) return tokval->t_type = TOKEN_SEG; return tokval->t_type = TOKEN_ID; } if (tline->type == TOK_NUMBER) { int rn_error; tokval->t_integer = readnum(tline->text, &rn_error); if (rn_error) return tokval->t_type = TOKEN_ERRNUM; tokval->t_charptr = NULL; return tokval->t_type = TOKEN_NUM; } if (tline->type == TOK_STRING) { int rn_warn; char q, *r; int l; r = tline->text; q = *r++; l = strlen(r); if (l == 0 || r[l - 1] != q) return tokval->t_type = TOKEN_ERRNUM; tokval->t_integer = readstrnum(r, l - 1, &rn_warn); if (rn_warn) error(ERR_WARNING | ERR_PASS1, "character constant too long"); tokval->t_charptr = NULL; return tokval->t_type = TOKEN_NUM; } if (tline->type == TOK_OTHER) { if (!strcmp(tline->text, "<<")) return tokval->t_type = TOKEN_SHL; if (!strcmp(tline->text, ">>")) return tokval->t_type = TOKEN_SHR; if (!strcmp(tline->text, "//")) return tokval->t_type = TOKEN_SDIV; if (!strcmp(tline->text, "%%")) return tokval->t_type = TOKEN_SMOD; if (!strcmp(tline->text, "==")) return tokval->t_type = TOKEN_EQ; if (!strcmp(tline->text, "<>")) return tokval->t_type = TOKEN_NE; if (!strcmp(tline->text, "!=")) return tokval->t_type = TOKEN_NE; if (!strcmp(tline->text, "<=")) return tokval->t_type = TOKEN_LE; if (!strcmp(tline->text, ">=")) return tokval->t_type = TOKEN_GE; if (!strcmp(tline->text, "&&")) return tokval->t_type = TOKEN_DBL_AND; if (!strcmp(tline->text, "^^")) return tokval->t_type = TOKEN_DBL_XOR; if (!strcmp(tline->text, "||")) return tokval->t_type = TOKEN_DBL_OR; } /* * We have no other options: just return the first character of * the token text. */ return tokval->t_type = tline->text[0];}/* * Compare a string to the name of an existing macro; this is a * simple wrapper which calls either strcmp or nasm_stricmp * depending on the value of the `casesense' parameter. */static intmstrcmp(char *p, char *q, int casesense){ return casesense ? strcmp(p, q) : nasm_stricmp(p, q);}/* * Return the Context structure associated with a %$ token. Return * NULL, having _already_ reported an error condition, if the * context stack isn't deep enough for the supplied number of $ * signs. * If all_contexts == TRUE, contexts that enclose current are * also scanned for such smacro, until it is found; if not - * only the context that directly results from the number of $'s * in variable's name. */static Context *get_ctx(char *name, int all_contexts){ Context *ctx; SMacro *m; int i; if (!name || name[0] != '%' || name[1] != '$') return NULL; if (!cstk) { error(ERR_NONFATAL, "`%s': context stack is empty", name); return NULL; } for (i = strspn(name + 2, "$"), ctx = cstk; (i > 0) && ctx; i--) { ctx = ctx->next;/* i--; Lino - 02/25/02 */ } if (!ctx) { error(ERR_NONFATAL, "`%s': context stack is only" " %d level%s deep", name, i - 1, (i == 2 ? "" : "s")); return NULL; } if (!all_contexts) return ctx; do { /* Search for this smacro in found context */ m = ctx->localmac; while (m) { if (!mstrcmp(m->name, name, m->casesense)) return ctx; m = m->next; } ctx = ctx->next; } while (ctx); return NULL;}/* * Open an include file. This routine must always return a valid * file pointer if it returns - it's responsible for throwing an * ERR_FATAL and bombing out completely if not. It should also try * the include path one by one until it finds the file or reaches * the end of the path. */static FILE *inc_fopen(char *file){ FILE *fp; char *prefix = "", *combine; IncPath *ip = ipath; static int namelen = 0; int len = strlen(file); while (1) { combine = nasm_malloc(strlen(prefix) + len + 1); strcpy(combine, prefix); strcat(combine, file); fp = fopen(combine, "r"); if (pass == 0 && fp) { namelen += strlen(combine) + 1; if (namelen > 62) { printf(" \\\n "); namelen = 2; } printf(" %s", combine); } nasm_free(combine); if (fp) return fp; if (!ip) break; prefix = ip->path; ip = ip->next; } error(ERR_FATAL, "unable to open include file `%s'", file); return NULL; /* never reached - placate compilers */}/* * Determine if we should warn on defining a single-line macro of * name `name', with `nparam' parameters. If nparam is 0 or -1, will * return TRUE if _any_ single-line macro of that name is defined. * Otherwise, will return TRUE if a single-line macro with either * `nparam' or no parameters is defined. * * If a macro with precisely the right number of parameters is * defined, or nparam is -1, the address of the definition structure * will be returned in `defn'; otherwise NULL will be returned. If `defn' * is NULL, no action will be taken regarding its contents, and no * error will occur. * * Note that this is also called with nparam zero to resolve * `ifdef'. * * If you already know which context macro belongs to, you can pass * the context pointer as first parameter; if you won't but name begins * with %$ the context will be automatically computed. If all_contexts * is true, macro will be searched in outer contexts as well. */static intsmacro_defined(Context * ctx, char *name, int nparam, SMacro ** defn, int nocase){ SMacro *m; if (ctx) m = ctx->localmac; else if (name[0] == '%' && name[1] == '$') { if (cstk) ctx = get_ctx(name, FALSE); if (!ctx) return FALSE; /* got to return _something_ */ m = ctx->localmac; } else m = smacros[hash(name)]; while (m) { if (!mstrcmp(m->name, name, m->casesense && nocase) && (nparam <= 0 || m->nparam == 0 || nparam == m->nparam)) { if (defn) { if (nparam == m->nparam || nparam == -1) *defn = m; else *defn = NULL; } return TRUE; } m = m->next; } return FALSE;}/* * Count and mark off the parameters in a multi-line macro call. * This is called both from within the multi-line macro expansion * code, and also to mark off the default parameters when provided * in a %macro definition line. */static voidcount_mmac_params(Token * t, int *nparam, Token *** params){ int paramsize, brace; *nparam = paramsize = 0; *params = NULL; while (t) { if (*nparam >= paramsize) { paramsize += PARAM_DELTA; *params = nasm_realloc(*params, sizeof(**params) * paramsize); } skip_white_(t); brace = FALSE; if (tok_is_(t, "{")) brace = TRUE; (*params)[(*nparam)++] = t; while (tok_isnt_(t, brace ? "}" : ",")) t = t->next; if (t) { /* got a comma/brace */ t = t->next; if (brace) { /* * Now we've found the closing brace, look further * for the comma. */ skip_white_(t); if (tok_isnt_(t, ",")) { error(ERR_NONFATAL, "braces do not enclose all of macro parameter"); while (tok_isnt_(t, ",")) t = t->next; } if (t) t = t->next; /* eat the comma */ } } }}/* * Determine whether one of the various `if' conditions is true or * not. * * We must free the tline we get passed. */static intif_condition(Token * tline, int i){ int j, casesense; Token *t, *tt, **tptr, *origline; struct tokenval tokval; expr *evalresult; origline = tline; switch (i) { case PP_IFCTX: case PP_ELIFCTX: case PP_IFNCTX: case PP_ELIFNCTX: j = FALSE; /* have we matched yet? */ while (cstk && tline) { skip_white_(tline); if (!tline || tline->type != TOK_ID) { error(ERR_NONFATAL, "`%s' expects context identifiers", directives[i]); free_tlist(origline); return -1; } if (!nasm_stricmp(tline->text, cstk->name)) j = TRUE; tline = tline->next; } if (i == PP_IFNCTX || i == PP_ELIFNCTX) j = !j; free_tlist(origline); return j; case PP_IFDEF: case PP_ELIFDEF: case PP_IFNDEF: case PP_ELIFNDEF: j = FALSE; /* have we matched yet? */ while (tline) { skip_white_(tline); if (!tline || (tline->type != TOK_ID && (tline->type != TOK_PREPROC_ID || tline->text[1] != '$'))) { error(ERR_NONFATAL, "`%s' expects macro identifiers", directives[i]); free_tlist(origline); return -1; } if (smacro_defined(NULL, tline->text, 0, NULL, 1)) j = TRUE; tline = tline->next; } if (i == PP_IFNDEF || i == PP_ELIFNDEF) j = !j; free_tlist(origline); return j; case PP_IFIDN: case PP_ELIFIDN: case PP_IFNIDN: case PP_ELIFNIDN: case PP_IFIDNI: case PP_ELIFIDNI: case PP_IFNIDNI: case PP_ELIFNIDNI: tline = expand_smacro(tline); t = tt = tline; while (tok_isnt_(tt, ",")) tt = tt->next; if (!tt) { error(ERR_NONFATAL, "`%s' expects two comma-separated arguments", directives[i]); free_tlist(tline); return -1; } tt = tt->next; casesense = (i == PP_IFIDN || i == PP_ELIFIDN || i == PP_IFNIDN || i == PP_ELIFNIDN); j = TRUE; /* assume equality unless proved not */ while ((t->type != TOK_OTHER || strcmp(t->text, ",")) && tt) { if (tt->type == TOK_OTHER && !strcmp(tt->text, ",")) { error(ERR_NONFATAL, "`%s': more than one comma on line", directives[i]); free_tlist(tline); return -1; } if (t->type == TOK_WHITESPACE) { t = t->next; continue; } else if (tt->type == TOK_WHITESPACE) { tt = tt->next; continue; } else if (tt->type != t->type || mstrcmp(tt->text, t->text, casesense)) { j = FALSE; /* found mismatching tokens */ break; } else { t = t->next; tt = tt->next; continue; } } if ((t->type != TOK_OTHER || strcmp(t->text, ",")) || tt) j = FALSE; /* trailing gunk on one end or other */ if (i == PP_IFNIDN || i == PP_ELIFNIDN || i == PP_IFNIDNI || i == PP_ELIFNIDNI) j = !j; free_tlist(tline); return j; case PP_IFMACRO: case PP_ELIFMACRO: case PP_IFNMACRO: case PP_ELIFNMACRO: { int found = 0; MMacro searching, *mmac; tline = tline->next; skip_white_(tline); tline = expand_id(tline); if (!tok_type_(tline, TOK_ID)) { error(ERR_NONFATAL, "`%s' expects a macro name", directives[i]); return -1; } searching.name = nasm_strdup(tline->text); searching.casesense = (i == PP_MACRO); searching.plus = FALSE; searching.nolist = FALSE; searching.in_progress = FALSE; searching.rep_nest = NULL; searching.nparam_min = 0; searching.nparam_max = INT_MAX; tline = expand_smacro(tline->next); skip_white_(tline); if (!tline) { } else if (!tok_type_(tline, TOK_NUMBER)) { error(ERR_NONFATAL,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -