📄 preproc.c
字号:
* 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 int
smacro_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 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 int if_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;
}
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, casesense) != 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 */
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,
"`%s' expects a parameter count or nothing",
directives[i]);
} 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 `-'",
directives[i]);
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 = mmacros[hash(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);
free_tlist(origline);
if (i == PP_IFNMACRO || i == PP_ELIFNMACRO)
found = !found;
return found;
}
case PP_IFID:
case PP_ELIFID:
case PP_IFNID:
case PP_ELIFNID:
case PP_IFNUM:
case PP_ELIFNUM:
case PP_IFNNUM:
case PP_ELIFNNUM:
case PP_IFSTR:
case PP_ELIFSTR:
case PP_IFNSTR:
case PP_ELIFNSTR:
tline = expand_smacro(tline);
t = tline;
while (tok_type_(t, TOK_WHITESPACE))
t = t->next;
j = FALSE; /* placate optimiser */
if (t)
switch (i) {
case PP_IFID:
case PP_ELIFID:
case PP_IFNID:
case PP_ELIFNID:
j = (t->type == TOK_ID);
break;
case PP_IFNUM:
case PP_ELIFNUM:
case PP_IFNNUM:
case PP_ELIFNNUM:
j = (t->type == TOK_NUMBER);
break;
case PP_IFSTR:
case PP_ELIFSTR:
case PP_IFNSTR:
case PP_ELIFNSTR:
j = (t->type == TOK_STRING);
break;
}
if (i == PP_IFNID || i == PP_ELIFNID ||
i == PP_IFNNUM || i == PP_ELIFNNUM ||
i == PP_IFNSTR || i == PP_ELIFNSTR)
j = !j;
free_tlist(tline);
return j;
case PP_IF:
case PP_ELIF:
t = tline = expand_smacro(tline);
tptr = &t;
tokval.t_type = TOKEN_INVALID;
evalresult = evaluate(ppscan, tptr, &tokval,
NULL, pass | CRITICAL, error, NULL);
free_tlist(tline);
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'", directives[i]);
return -1;
}
return reloc_value(evalresult) != 0;
default:
error(ERR_FATAL,
"preprocessor directive `%s' not yet implemented",
directives[i]);
free_tlist(origline);
return -1; /* yeah, right */
}
}
/*
* Expand macros in a string. Used in %error and %include directives.
* First tokenise the string, apply "expand_smacro" and then de-tokenise back.
* The returned variable should ALWAYS be freed after usage.
*/
void expand_macros_in_string(char **p)
{
Token *line = tokenise(*p);
line = expand_smacro(line);
*p = detoken(line, FALSE);
}
/**
* 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)
{
int i, j, k, m, nparam, nolist;
int offset;
char *p, *mname;
Include *inc;
Context *ctx;
Cond *cond;
SMacro *smac, **smhead;
MMacro *mmac;
Token *t, *tt, *param_start, *macro_start, *last, **tptr, *origline;
Line *l;
struct tokenval tokval;
expr *evalresult;
MMacro *tmp_defining; /* Used when manipulating rep_nest */
origline = tline;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -