📄 preproc.c
字号:
*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? */
if (!cstk)
error(ERR_FATAL,
"`%s': context stack is empty", directives[i]);
else while (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,
"`%%if%sdef' expects macro identifiers",
(i==PP_ELIFNDEF ? "n" : ""));
free_tlist (origline);
return -1;
}
if (smacro_defined(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 ||
(casesense ? strcmp(tt->text, t->text) :
nasm_stricmp(tt->text, t->text))) {
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_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 | 0x10, 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 */
}
}
/*
* Find out if a line contains a preprocessor directive, and deal
* with it if so.
*
* If a directive _is_ found, we are expected to free_tlist() the
* line.
*
* Return values go like this:
*
* bit 0 is set if a directive was found (so the line gets freed)
*/
static int do_directive (Token *tline)
{
int i, j, k, m, nparam, nolist;
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;
skip_white_(tline);
if (!tok_type_(tline, TOK_PREPROC_ID) ||
(tline->text[1]=='%' || tline->text[1]=='$' || tline->text[1]=='!'))
return 0;
i = -1;
j = sizeof(directives)/sizeof(*directives);
while (j-i > 1) {
k = (j+i) / 2;
m = nasm_stricmp(tline->text, directives[k]);
if (m == 0) {
i = k;
j = -2;
break;
} else if (m < 0) {
j = k;
} else
i = k;
}
/*
* If we're in a non-emitting branch of a condition construct,
* or walking to the end of an already terminated %rep block,
* we should ignore all directives except for condition
* directives.
*/
if (((istk->conds && !emitting(istk->conds->state)) ||
(istk->mstk && !istk->mstk->in_progress)) &&
i != PP_IF && i != PP_ELIF &&
i != PP_IFCTX && i != PP_ELIFCTX &&
i != PP_IFDEF && i != PP_ELIFDEF &&
i != PP_IFID && i != PP_ELIFID &&
i != PP_IFIDN && i != PP_ELIFIDN &&
i != PP_IFIDNI && i != PP_ELIFIDNI &&
i != PP_IFNCTX && i != PP_ELIFNCTX &&
i != PP_IFNDEF && i != PP_ELIFNDEF &&
i != PP_IFNID && i != PP_ELIFNID &&
i != PP_IFNIDN && i != PP_ELIFNIDN &&
i != PP_IFNIDNI && i != PP_ELIFNIDNI &&
i != PP_IFNNUM && i != PP_ELIFNNUM &&
i != PP_IFNSTR && i != PP_ELIFNSTR &&
i != PP_IFNUM && i != PP_ELIFNUM &&
i != PP_IFSTR && i != PP_ELIFSTR &&
i != PP_ELSE && i != PP_ENDIF)
{
return 0;
}
/*
* If we're defining a macro or reading a %rep block, we should
* ignore all directives except for %macro/%imacro (which
* generate an error), %endm/%endmacro, and (only if we're in a
* %rep block) %endrep. If we're in a %rep block, another %rep
* causes an error, so should be let through.
*/
if (defining && i != PP_MACRO && i != PP_IMACRO &&
i != PP_ENDMACRO && i != PP_ENDM &&
(defining->name || (i != PP_ENDREP && i != PP_REP)))
{
return 0;
}
if (j != -2) {
error(ERR_NONFATAL, "unknown preprocessor directive `%s'",
tline->text);
return 0; /* didn't get it */
}
switch (i) {
case PP_CLEAR:
if (tline->next)
error(ERR_WARNING,
"trailing garbage after `%%clear' ignored");
for (j=0; j<NHASH; j++) {
while (mmacros[j]) {
MMacro *m = mmacros[j];
mmacros[j] = m->next;
free_mmacro(m);
}
while (smacros[j]) {
SMacro *s = smacros[j];
smacros[j] = smacros[j]->next;
nasm_free (s->name);
free_tlist (s->expansion);
nasm_free (s);
}
}
free_tlist (origline);
return 3;
case PP_INCLUDE:
tline = tline->next;
skip_white_(tline);
if (!tline || (tline->type != TOK_STRING &&
tline->type != TOK_INTERNAL_STRING))
{
error(ERR_NONFATAL, "`%%include' expects a file name");
free_tlist (origline);
return 3; /* but we did _something_ */
}
if (tline->next)
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 */
inc = nasm_malloc(sizeof(Include));
inc->next = istk;
inc->conds = NULL;
inc->fp = inc_fopen(p);
inc->fname = src_set_fname(nasm_strdup(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 5;
case PP_PUSH:
tline = tline->next;
skip_white_(tline);
if (!tok_type_(tline, TOK_ID)) {
error(ERR_NONFATAL,
"`%%push' expects a context identifier");
free_tlist (origline);
return 3; /* 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);
if (!tok_type_(tline, TOK_ID)) {
error(ERR_NONFATAL,
"`%%repl' expects a context identifier");
free_tlist (origline);
return 3; /* 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 */
error(ERR_NONFATAL, "user error: %s", p);
} else {
p = detoken(tline);
error(ERR_WARNING, "user error: %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_IFNCTX:
case PP_IFNDEF:
case PP_IFNID:
case PP_IFNIDN:
case PP_IFNIDNI:
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);
if (j < 0)
/*
* Bogus expression in %if, but we should pretend
* it was OK anyway, so that we don't get an error
* cascade on the subsequent %else / %endif.
*/
j = COND_NEVER;
else
j = j ? COND_IF_TRUE : COND_IF_FALSE;
}
cond = nasm_malloc(sizeof(Cond));
cond->next = istk->conds;
cond->state = j;
istk->conds = cond;
return (j == COND_IF_TRUE ? 3 : 1);
case PP_ELIF:
case PP_ELIFCTX:
case PP_ELIFDEF:
case PP_ELIFID:
case PP_ELIFIDN:
case PP_ELIFIDNI:
case PP_ELIFNCTX:
case PP_ELIFNDEF:
case PP_ELIFNID:
case PP_ELIFNIDN:
case PP_ELIFNIDNI:
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 {
j = if_condition(expand_mmac_params(tline->next), i);
tline->next = NULL; /* it got freed */
free_tlist (origline);
if (j < 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -