📄 preproc.c
字号:
if (tokval.t_type)
error(ERR_WARNING,
"trailing garbage after expression ignored");
if (!is_simple(evalresult)) {
error(ERR_NONFATAL,
"non-constant value given to `%%%sassign'",
(i == PP_IASSIGN ? "i" : ""));
free_tlist (origline);
return 3;
}
macro_start = nasm_malloc(sizeof(*macro_start));
macro_start->next = NULL;
make_tok_num(macro_start, reloc_value(evalresult));
macro_start->mac = NULL;
/*
* We now have a macro name, an implicit parameter count of
* zero, and a numeric token to use as an expansion. Create
* and store an SMacro.
*/
if (smacro_defined (mname, 0, &smac, i==PP_ASSIGN)) {
if (!smac)
error (ERR_WARNING,
"single-line macro `%s' defined both with and"
" without parameters", mname);
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 {
smac = nasm_malloc(sizeof(SMacro));
smac->next = *smhead;
*smhead = smac;
}
smac->name = nasm_strdup(p);
smac->casesense = (i == PP_ASSIGN);
smac->nparam = 0;
smac->expansion = macro_start;
smac->in_progress = FALSE;
free_tlist (origline);
return 3;
case PP_LINE:
/*
* Syntax is `%line nnn[+mmm] [filename]'
*/
tline = tline->next;
skip_white_(tline);
if (!tok_type_(tline, TOK_NUMBER)) {
error (ERR_NONFATAL, "`%%line' expects line number");
free_tlist (origline);
return 3;
}
k = readnum(tline->text, &j);
m = 1;
tline = tline->next;
if (tok_is_(tline, "+")) {
tline = tline->next;
if (!tok_type_(tline, TOK_NUMBER)) {
error (ERR_NONFATAL,
"`%%line' expects line increment");
free_tlist (origline);
return 3;
}
m = readnum(tline->text, &j);
tline = tline->next;
}
skip_white_(tline);
src_set_linnum(k);
istk->lineinc = m;
if (tline) {
nasm_free ( src_set_fname ( detoken(tline) ) );
}
free_tlist (origline);
return 5;
default:
error(ERR_FATAL,
"preprocessor directive `%s' not yet implemented",
directives[i]);
break;
}
return 3;
}
/*
* Ensure that a macro parameter contains a condition code and
* nothing else. Return the condition code index if so, or -1
* otherwise.
*/
static int find_cc (Token *t)
{
Token *tt;
int i, j, k, m;
skip_white_(t);
if (t->type != TOK_ID)
return -1;
tt = t->next;
skip_white_(tt);
if (tt && (tt->type != TOK_OTHER || strcmp(tt->text, ",")))
return -1;
i = -1;
j = sizeof(conditions)/sizeof(*conditions);
while (j-i > 1) {
k = (j+i) / 2;
m = nasm_stricmp(t->text, conditions[k]);
if (m == 0) {
i = k;
j = -2;
break;
} else if (m < 0) {
j = k;
} else
i = k;
}
if (j != -2)
return -1;
return i;
}
/*
* Expand MMacro-local things: parameter references (%0, %n, %+n,
* %-n) and MMacro-local identifiers (%%foo).
*/
static Token *expand_mmac_params (Token *tline)
{
Token *t, *tt, *ttt, **tail, *thead;
tail = &thead;
thead = NULL;
while (tline) {
if (tline->type == TOK_PREPROC_ID &&
(tline->text[1] == '+' || tline->text[1] == '-' ||
tline->text[1] == '%' ||
(tline->text[1] >= '0' && tline->text[1] <= '9'))) {
char *text = NULL;
int type = 0, cc; /* type = 0 to placate optimisers */
char tmpbuf[30];
int n, i;
MMacro *mac;
t = tline;
tline = tline->next;
mac = istk->mstk;
while (mac && !mac->name) /* avoid mistaking %reps for macros */
mac = mac->next_active;
if (!mac)
error(ERR_NONFATAL, "`%s': not in a macro call", t->text);
else switch (t->text[1]) {
/*
* We have to make a substitution of one of the
* forms %1, %-1, %+1, %%foo, %0.
*/
case '0':
type = TOK_NUMBER;
sprintf(tmpbuf, "%d", mac->nparam);
text = nasm_strdup(tmpbuf);
break;
case '%':
type = TOK_ID;
sprintf(tmpbuf, "..@%lu.", mac->unique);
text = nasm_strcat(tmpbuf, t->text+2);
break;
case '-':
n = atoi(t->text+2)-1;
if (n >= mac->nparam)
tt = NULL;
else {
if (mac->nparam > 1)
n = (n + mac->rotate) % mac->nparam;
tt = mac->params[n];
}
cc = find_cc (tt);
if (cc == -1) {
error (ERR_NONFATAL,
"macro parameter %d is not a condition code",
n+1);
text = NULL;
} else {
type = TOK_ID;
if (inverse_ccs[cc] == -1) {
error (ERR_NONFATAL,
"condition code `%s' is not invertible",
conditions[cc]);
text = NULL;
} else
text = nasm_strdup(conditions[inverse_ccs[cc]]);
}
break;
case '+':
n = atoi(t->text+2)-1;
if (n >= mac->nparam)
tt = NULL;
else {
if (mac->nparam > 1)
n = (n + mac->rotate) % mac->nparam;
tt = mac->params[n];
}
cc = find_cc (tt);
if (cc == -1) {
error (ERR_NONFATAL,
"macro parameter %d is not a condition code",
n+1);
text = NULL;
} else {
type = TOK_ID;
text = nasm_strdup(conditions[cc]);
}
break;
default:
n = atoi(t->text+1)-1;
if (n >= mac->nparam)
tt = NULL;
else {
if (mac->nparam > 1)
n = (n + mac->rotate) % mac->nparam;
tt = mac->params[n];
}
if (tt) {
for (i=0; i<mac->paramlen[n]; i++) {
ttt = *tail = nasm_malloc(sizeof(Token));
tail = &ttt->next;
ttt->type = tt->type;
ttt->text = nasm_strdup(tt->text);
ttt->mac = NULL;
tt = tt->next;
}
}
text = NULL; /* we've done it here */
break;
}
nasm_free (t->text);
if (!text) {
nasm_free (t);
} else {
*tail = t;
tail = &t->next;
t->type = type;
t->text = text;
t->mac = NULL;
}
continue;
} else {
t = *tail = tline;
tline = tline->next;
t->mac = NULL;
tail = &t->next;
}
}
*tail = NULL;
t = thead;
for (; t && (tt=t->next)!=NULL ; t = t->next)
switch (t->type) {
case TOK_WHITESPACE:
if (tt->type == TOK_WHITESPACE) {
t->next = tt->next;
nasm_free(tt->text);
nasm_free(tt);
}
break;
case TOK_ID:
if (tt->type == TOK_ID || tt->type == TOK_NUMBER) {
char *tmp = nasm_strcat(t->text, tt->text);
nasm_free(t->text);
t->text = tmp;
t->next = tt->next;
nasm_free(tt->text);
nasm_free(tt);
}
break;
case TOK_NUMBER:
if (tt->type == TOK_NUMBER) {
char *tmp = nasm_strcat(t->text, tt->text);
nasm_free(t->text);
t->text = tmp;
t->next = tt->next;
nasm_free(tt->text);
nasm_free(tt);
}
break;
}
return thead;
}
/*
* Expand all single-line macro calls made in the given line.
* Return the expanded version of the line. The original is deemed
* to be destroyed in the process. (In reality we'll just move
* Tokens from input to output a lot of the time, rather than
* actually bothering to destroy and replicate.)
*/
static Token *expand_smacro (Token *tline)
{
Token *t, *tt, *mstart, **tail, *thead;
SMacro *head = NULL, *m;
Token **params;
int *paramsize;
int nparam, sparam, brackets;
char *p;
tail = &thead;
thead = NULL;
while (tline) { /* main token loop */
p = NULL;
if (tline->type == TOK_ID) {
head = smacros[hash(tline->text)];
p = tline->text;
} else if (tline->type == TOK_PREPROC_ID && tline->text[1] == '$') {
Context *ctx = get_ctx (tline->text);
if (ctx) {
head = ctx->localmac;
p = tline->text+2;
p += strspn(p, "$");
}
}
if (p) {
/*
* We've hit an identifier. As in is_mmacro below, we first
* check whether the identifier is a single-line macro at
* all, then think about checking for parameters if
* necessary.
*/
for (m = head; m; m = m->next)
if (!mstrcmp(m->name, p, m->casesense))
break;
if (m) {
mstart = tline;
params = NULL;
paramsize = NULL;
if (m->nparam == 0) {
/*
* Simple case: the macro is parameterless. Discard the
* one token that the macro call took, and push the
* expansion back on the to-do stack.
*/
if (!m->expansion)
{
if (!strcmp("__FILE__", m->name)) {
long num=0;
src_get(&num, &(tline->text));
nasm_quote(&(tline->text));
tline->type = TOK_STRING;
continue;
}
if (!strcmp("__LINE__", m->name)) {
nasm_free(tline->text);
make_tok_num(tline, src_get_linnum());
continue;
}
t = tline;
tline = tline->next;
nasm_free (t->text);
nasm_free (t);
continue;
}
}
else {
/*
* Complicated case: at least one macro with this name
* exists and takes parameters. We must find the
* parameters in the call, count them, find the SMacro
* that corresponds to that form of the macro call, and
* substitute for the parameters when we expand. What a
* pain.
*/
tline = tline->next;
skip_white_(tline);
if (!tok_is_(tline, "(")) {
/*
* This macro wasn't called with parameters: ignore
* the call. (Behaviour borrowed from gnu cpp.)
*/
tline = mstart;
m = NULL;
}
else {
int paren = 0;
int white = 0;
brackets = 0;
nparam = 0;
tline = tline->next;
sparam = PARAM_DELTA;
params = nasm_malloc (sparam*sizeof(Token *));
params[0] = tline;
paramsize = nasm_malloc (sparam*sizeof(int));
paramsize[0] = 0;
for (;;tline = tline->next) { /* parameter loop */
if (!tline) {
error(ERR_NONFATAL,
"macro call expects terminating `)'");
break;
}
if (tline->type == TOK_WHITESPACE && brackets<=0) {
if (paramsize[nparam])
white++;
else
params[nparam] = tline->next;
continue; /* parameter loop */
}
if (tline->type == TOK_OTHER && tline->text[1]==0) {
char ch = tline->text[0];
if (ch == ',' && !paren && brackets<=0) {
if (++nparam >= sparam) {
sparam += PARAM_DELTA;
params = nasm_realloc (params,
sparam*sizeof(Token *));
paramsize = nasm_realloc (paramsize,
sparam*sizeof(int));
}
params[nparam] = tline->next;
paramsize[nparam] = 0;
white = 0;
continue; /* parameter loop */
}
if (ch == '{' &&
(brackets>0 || (brackets==0 &&
!paramsize[nparam])))
{
if (!(brackets++))
{
params[nparam] = tline->next;
continue; /* parameter loop */
}
}
if (ch == '}' && brackets>0)
if (--brackets == 0) {
brackets = -1;
continue; /* parameter loop */
}
if (ch == '(' && !brackets)
paren++;
if (ch == ')' && brackets<=0)
if (--paren < 0)
break;
}
if (brackets<0) {
brackets = 0;
error (ERR_NONFATAL, "braces do not "
"enclose all of macro parameter");
}
paramsize[nparam] += white+1;
white = 0;
} /* parameter loop */
nparam++;
while (m && (m->nparam != nparam ||
mstrcmp(m->name, p, m->casesense)))
m = m->next;
if (!m)
error (ERR_WARNING|ERR_WARN_MNP,
"macro `%s' exists, "
"but not taking %d parameters",
mstart->text, nparam);
}
}
if (m && m->in_progress)
m = NULL;
if (!m) /* in progess or didn't find '(' or wrong nparam */
{
/*
* Design question: should we handle !tline, which
* indicates missing ')' here, or expand those
* macros anyway, which requires the (t) test a few
* lines down?
*/
nasm_free (params);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -