📄 preproc.c
字号:
}
return false;
}
/*
* 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(const char *file, StrList **dhead, StrList ***dtail,
bool missing_ok)
{
FILE *fp;
char *prefix = "";
IncPath *ip = ipath;
int len = strlen(file);
size_t prefix_len = 0;
StrList *sl;
while (1) {
sl = nasm_malloc(prefix_len+len+1+sizeof sl->next);
memcpy(sl->str, prefix, prefix_len);
memcpy(sl->str+prefix_len, file, len+1);
fp = fopen(sl->str, "r");
if (fp && dhead && !in_list(*dhead, sl->str)) {
sl->next = NULL;
**dtail = sl;
*dtail = &sl->next;
} else {
nasm_free(sl);
}
if (fp)
return fp;
if (!ip) {
if (!missing_ok)
break;
prefix = NULL;
} else {
prefix = ip->path;
ip = ip->next;
}
if (prefix) {
prefix_len = strlen(prefix);
} else {
/* -MG given and file not found */
if (dhead && !in_list(*dhead, file)) {
sl = nasm_malloc(len+1+sizeof sl->next);
sl->next = NULL;
strcpy(sl->str, file);
**dtail = sl;
*dtail = &sl->next;
}
return NULL;
}
}
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 bool
smacro_defined(Context * ctx, const char *name, int nparam, SMacro ** defn,
bool nocase)
{
struct hash_table *smtbl;
SMacro *m;
if (ctx) {
smtbl = &ctx->localmac;
} else if (name[0] == '%' && name[1] == '$') {
if (cstk)
ctx = get_ctx(name, false);
if (!ctx)
return false; /* got to return _something_ */
smtbl = &ctx->localmac;
} else {
smtbl = &smacros;
}
m = (SMacro *) hash_findix(smtbl, name);
while (m) {
if (!mstrcmp(m->name, name, m->casesense && nocase) &&
(nparam <= 0 || m->nparam == 0 || nparam == (int) m->nparam)) {
if (defn) {
if (nparam == (int) 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 void count_mmac_params(Token * t, int *nparam, Token *** params)
{
int paramsize, brace;
*nparam = paramsize = 0;
*params = NULL;
while (t) {
/* +1: we need space for the final NULL */
if (*nparam+1 >= 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 bool if_condition(Token * tline, enum preproc_token ct)
{
enum pp_conditional i = PP_COND(ct);
bool j;
Token *t, *tt, **tptr, *origline;
struct tokenval tokval;
expr *evalresult;
enum pp_token_type needtype;
origline = tline;
switch (i) {
case PPC_IFCTX:
j = false; /* have we matched yet? */
while (true) {
skip_white_(tline);
if (!tline)
break;
if (tline->type != TOK_ID) {
error(ERR_NONFATAL,
"`%s' expects context identifiers", pp_directives[ct]);
free_tlist(origline);
return -1;
}
if (cstk && cstk->name && !nasm_stricmp(tline->text, cstk->name))
j = true;
tline = tline->next;
}
break;
case PPC_IFDEF:
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", pp_directives[ct]);
goto fail;
}
if (smacro_defined(NULL, tline->text, 0, NULL, true))
j = true;
tline = tline->next;
}
break;
case PPC_IFIDN:
case PPC_IFIDNI:
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",
pp_directives[ct]);
goto fail;
}
tt = tt->next;
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",
pp_directives[ct]);
goto fail;
}
if (t->type == TOK_WHITESPACE) {
t = t->next;
continue;
}
if (tt->type == TOK_WHITESPACE) {
tt = tt->next;
continue;
}
if (tt->type != t->type) {
j = false; /* found mismatching tokens */
break;
}
/* When comparing strings, need to unquote them first */
if (t->type == TOK_STRING) {
size_t l1 = nasm_unquote(t->text, NULL);
size_t l2 = nasm_unquote(tt->text, NULL);
if (l1 != l2) {
j = false;
break;
}
if (mmemcmp(t->text, tt->text, l1, i == PPC_IFIDN)) {
j = false;
break;
}
} else if (mstrcmp(tt->text, t->text, i == PPC_IFIDN) != 0) {
j = false; /* found mismatching tokens */
break;
}
t = t->next;
tt = tt->next;
}
if ((t->type != TOK_OTHER || strcmp(t->text, ",")) || tt)
j = false; /* trailing gunk on one end or other */
break;
case PPC_IFMACRO:
{
bool found = false;
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", pp_directives[ct]);
goto fail;
}
searching.name = nasm_strdup(tline->text);
searching.casesense = true;
searching.plus = false;
searching.nolist = false;
searching.in_progress = 0;
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,
"`%s' expects a parameter count or nothing",
pp_directives[ct]);
} else {
searching.nparam_min = searching.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, "*"))
searching.nparam_max = INT_MAX;
else if (!tok_type_(tline, TOK_NUMBER))
error(ERR_NONFATAL,
"`%s' expects a parameter count after `-'",
pp_directives[ct]);
else {
searching.nparam_max = readnum(tline->text, &j);
if (j)
error(ERR_NONFATAL,
"unable to parse parameter count `%s'",
tline->text);
if (searching.nparam_min > searching.nparam_max)
error(ERR_NONFATAL,
"minimum parameter count exceeds maximum");
}
}
if (tline && tok_is_(tline->next, "+")) {
tline = tline->next;
searching.plus = true;
}
mmac = (MMacro *) hash_findix(&mmacros, searching.name);
while (mmac) {
if (!strcmp(mmac->name, searching.name) &&
(mmac->nparam_min <= searching.nparam_max
|| searching.plus)
&& (searching.nparam_min <= mmac->nparam_max
|| mmac->plus)) {
found = true;
break;
}
mmac = mmac->next;
}
if(tline && tline->next)
error(ERR_WARNING|ERR_PASS1,
"trailing garbage after %%ifmacro ignored");
nasm_free(searching.name);
j = found;
break;
}
case PPC_IFID:
needtype = TOK_ID;
goto iftype;
case PPC_IFNUM:
needtype = TOK_NUMBER;
goto iftype;
case PPC_IFSTR:
needtype = TOK_STRING;
goto iftype;
iftype:
t = tline = expand_smacro(tline);
while (tok_type_(t, TOK_WHITESPACE) ||
(needtype == TOK_NUMBER &&
tok_type_(t, TOK_OTHER) &&
(t->text[0] == '-' || t->text[0] == '+') &&
!t->text[1]))
t = t->next;
j = tok_type_(t, needtype);
break;
case PPC_IFTOKEN:
t = tline = expand_smacro(tline);
while (tok_type_(t, TOK_WHITESPACE))
t = t->next;
j = false;
if (t) {
t = t->next; /* Skip the actual token */
while (tok_type_(t, TOK_WHITESPACE))
t = t->next;
j = !t; /* Should be nothing left */
}
break;
case PPC_IFEMPTY:
t = tline = expand_smacro(tline);
while (tok_type_(t, TOK_WHITESPACE))
t = t->next;
j = !t; /* Should be empty */
break;
case PPC_IF:
t = tline = expand_smacro(tline);
tptr = &t;
tokval.t_type = TOKEN_INVALID;
evalresult = evaluate(ppscan, tptr, &tokval,
NULL, pass | CRITICAL, error, NULL);
if (!evalresult)
return -1;
if (tokval.t_type)
error(ERR_WARNING|ERR_PASS1,
"trailing garbage after expression ignored");
if (!is_simple(evalresult)) {
error(ERR_NONFATAL,
"non-constant value given to `%s'", pp_directives[ct]);
goto fail;
}
j = reloc_value(evalresult) != 0;
break;
default:
error(ERR_FATAL,
"preprocessor directive `%s' not yet implemented",
pp_directives[ct]);
goto fail;
}
free_tlist(origline);
return j ^ PP_NEGATIVE(ct);
fail:
free_tlist(origline);
return -1;
}
/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -