📄 preproc.c
字号:
* 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, char *name, int nparam, SMacro ** defn,
bool 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 = (SMacro *) hash_findix(smacros, 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 void count_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 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 (cstk && tline) {
skip_white_(tline);
if (!tline || tline->type != TOK_ID) {
error(ERR_NONFATAL,
"`%s' expects context identifiers", pp_directives[ct]);
free_tlist(origline);
return -1;
}
if (!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;
}
/* Unify surrounding quotes for strings */
if (t->type == TOK_STRING) {
tt->text[0] = t->text[0];
tt->text[strlen(tt->text) - 1] = t->text[0];
}
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;
}
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:
tline = expand_smacro(tline);
t = tline;
while (tok_type_(t, TOK_WHITESPACE))
t = t->next;
j = false; /* placate optimiser */
if (t)
j = t->type == needtype;
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,
"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;
return j;
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;
}
/*
* Expand macros in a string. Used in %error and %include directives.
* First tokenize the string, apply "expand_smacro" and then de-tokenize back.
* The returned variable should ALWAYS be freed after usage.
*/
void expand_macros_in_string(char **p)
{
Token *line = tokenize(*p);
line = expand_smacro(line);
*p = detoken(line, false);
}
/*
* Common code for defining an smacro
*/
static bool define_smacro(Context *ctx, char *mname, bool casesense,
int nparam, Token *expansion)
{
SMacro *smac, **smhead;
if (smacro_defined(ctx, mname, nparam, &smac, casesense)) {
if (!smac) {
error(ERR_WARNING,
"single-line macro `%s' defined both with and"
" without parameters", mname);
/* Some instances of the old code considered this a failure,
some others didn't. What is the right thing to do here? */
free_tlist(expansion);
return false; /* Failure */
} else {
/*
* We're redefining, so we have to take over an
* existing SMacro structure. This means freeing
* what was already in it.
*/
nasm_free(smac->name);
free_tlist(smac->expansion);
}
} else {
if (!ctx)
smhead = (SMacro **) hash_findi_add(smacros, mname);
else
smhead = &ctx->localmac;
smac = nasm_malloc(sizeof(SMacro));
smac->next = *smhead;
*smhead = smac;
}
smac->name = nasm_strdup(mname);
smac->casesense = casesense;
smac->nparam = nparam;
smac->expansion = expansion;
smac->in_progress = false;
return true; /* Success */
}
/*
* Undefine an smacro
*/
static void undef_smacro(Context *ctx, const char *mname)
{
SMacro **smhead, *s, **sp;
if (!ctx)
smhead = (SMacro **) hash_findi(smacros, mname, NULL);
else
smhead = &ctx->localmac;
if (smhead) {
/*
* We now have a macro name... go hunt for it.
*/
sp = smhead;
while ((s = *sp) != NULL) {
if (!mstrcmp(s->name, mname, s->casesense)) {
*sp = s->next;
nasm_free(s->name);
free_tlist(s->expansion);
nasm_free(s);
} else {
sp = &s->next;
}
}
}
}
/**
* find and process preprocessor directive in passed line
* Find out if a line contains a preprocessor directive, and deal
* with it if so.
*
* If a directive _is_ found, it is the responsibility of this routine
* (and not the caller) to free_tlist() the line.
*
* @param tline a pointer to the current tokeninzed line linked list
* @return DIRECTIVE_FOUND or NO_DIRECTIVE_FOUND
*
*/
static int do_directive(Token * tline)
{
enum preproc_token i;
int j;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -