📄 preproc.c
字号:
len = 0;
for (t = tlist; t; t = t->next)
{
if (t->type == TOK_PREPROC_ID && t->text[1] == '!')
{
char *p = getenv(t->text + 2);
nasm_free(t->text);
if (p)
t->text = nasm_strdup(p);
else
t->text = NULL;
}
/* Expand local macros here and not during preprocessing */
if (expand_locals &&
t->type == TOK_PREPROC_ID && t->text &&
t->text[0] == '%' && t->text[1] == '$')
{
Context *ctx = get_ctx(t->text, FALSE);
if (ctx)
{
char buffer[40];
char *p, *q = t->text + 2;
q += strspn(q, "$");
sprintf(buffer, "..@%lu.", ctx->number);
p = nasm_strcat(buffer, q);
nasm_free(t->text);
t->text = p;
}
}
if (t->type == TOK_WHITESPACE)
{
len++;
}
else if (t->text)
{
len += strlen(t->text);
}
}
p = line = nasm_malloc(len + 1);
for (t = tlist; t; t = t->next)
{
if (t->type == TOK_WHITESPACE)
{
*p = ' ';
p++;
*p = '\0';
}
else if (t->text)
{
strcpy(p, t->text);
p += strlen(p);
}
}
*p = '\0';
return line;
}
/*
* A scanner, suitable for use by the expression evaluator, which
* operates on a line of Tokens. Expects a pointer to a pointer to
* the first token in the line to be passed in as its private_data
* field.
*/
static int
ppscan(void *private_data, struct tokenval *tokval)
{
Token **tlineptr = private_data;
Token *tline;
do
{
tline = *tlineptr;
*tlineptr = tline ? tline->next : NULL;
}
while (tline && (tline->type == TOK_WHITESPACE ||
tline->type == TOK_COMMENT));
if (!tline)
return tokval->t_type = TOKEN_EOS;
if (tline->text[0] == '$' && !tline->text[1])
return tokval->t_type = TOKEN_HERE;
if (tline->text[0] == '$' && tline->text[1] == '$' && !tline->text[2])
return tokval->t_type = TOKEN_BASE;
if (tline->type == TOK_ID)
{
tokval->t_charptr = tline->text;
if (tline->text[0] == '$')
{
tokval->t_charptr++;
return tokval->t_type = TOKEN_ID;
}
/*
* This is the only special case we actually need to worry
* about in this restricted context.
*/
if (!nasm_stricmp(tline->text, "seg"))
return tokval->t_type = TOKEN_SEG;
return tokval->t_type = TOKEN_ID;
}
if (tline->type == TOK_NUMBER)
{
int rn_error;
tokval->t_integer = readnum(tline->text, &rn_error);
if (rn_error)
return tokval->t_type = TOKEN_ERRNUM;
tokval->t_charptr = NULL;
return tokval->t_type = TOKEN_NUM;
}
if (tline->type == TOK_STRING)
{
int rn_warn;
char q, *r;
int l;
r = tline->text;
q = *r++;
l = strlen(r);
if (l == 0 || r[l - 1] != q)
return tokval->t_type = TOKEN_ERRNUM;
tokval->t_integer = readstrnum(r, l - 1, &rn_warn);
if (rn_warn)
error(ERR_WARNING | ERR_PASS1, "character constant too long");
tokval->t_charptr = NULL;
return tokval->t_type = TOKEN_NUM;
}
if (tline->type == TOK_OTHER)
{
if (!strcmp(tline->text, "<<"))
return tokval->t_type = TOKEN_SHL;
if (!strcmp(tline->text, ">>"))
return tokval->t_type = TOKEN_SHR;
if (!strcmp(tline->text, "//"))
return tokval->t_type = TOKEN_SDIV;
if (!strcmp(tline->text, "%%"))
return tokval->t_type = TOKEN_SMOD;
if (!strcmp(tline->text, "=="))
return tokval->t_type = TOKEN_EQ;
if (!strcmp(tline->text, "<>"))
return tokval->t_type = TOKEN_NE;
if (!strcmp(tline->text, "!="))
return tokval->t_type = TOKEN_NE;
if (!strcmp(tline->text, "<="))
return tokval->t_type = TOKEN_LE;
if (!strcmp(tline->text, ">="))
return tokval->t_type = TOKEN_GE;
if (!strcmp(tline->text, "&&"))
return tokval->t_type = TOKEN_DBL_AND;
if (!strcmp(tline->text, "^^"))
return tokval->t_type = TOKEN_DBL_XOR;
if (!strcmp(tline->text, "||"))
return tokval->t_type = TOKEN_DBL_OR;
}
/*
* We have no other options: just return the first character of
* the token text.
*/
return tokval->t_type = tline->text[0];
}
/*
* Compare a string to the name of an existing macro; this is a
* simple wrapper which calls either strcmp or nasm_stricmp
* depending on the value of the `casesense' parameter.
*/
static int
mstrcmp(char *p, char *q, int casesense)
{
return casesense ? strcmp(p, q) : nasm_stricmp(p, q);
}
/*
* Return the Context structure associated with a %$ token. Return
* NULL, having _already_ reported an error condition, if the
* context stack isn't deep enough for the supplied number of $
* signs.
* If all_contexts == TRUE, contexts that enclose current are
* also scanned for such smacro, until it is found; if not -
* only the context that directly results from the number of $'s
* in variable's name.
*/
static Context *
get_ctx(char *name, int all_contexts)
{
Context *ctx;
SMacro *m;
int i;
if (!name || name[0] != '%' || name[1] != '$')
return NULL;
if (!cstk)
{
error(ERR_NONFATAL, "`%s': context stack is empty", name);
return NULL;
}
for (i = strspn(name + 2, "$"), ctx = cstk; (i > 0) && ctx; i--)
{
ctx = ctx->next;
/* i--; Lino - 02/25/02 */
}
if (!ctx)
{
error(ERR_NONFATAL, "`%s': context stack is only"
" %d level%s deep", name, i - 1, (i == 2 ? "" : "s"));
return NULL;
}
if (!all_contexts)
return ctx;
do
{
/* Search for this smacro in found context */
m = ctx->localmac;
while (m)
{
if (!mstrcmp(m->name, name, m->casesense))
return ctx;
m = m->next;
}
ctx = ctx->next;
}
while (ctx);
return NULL;
}
/*
* 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(char *file)
{
FILE *fp;
char *prefix = "", *combine;
IncPath *ip = ipath;
static int namelen = 0;
int len = strlen(file);
while (1)
{
combine = nasm_malloc(strlen(prefix) + len + 1);
strcpy(combine, prefix);
strcat(combine, file);
fp = fopen(combine, "r");
if (pass == 0 && fp)
{
namelen += strlen(combine) + 1;
if (namelen > 62)
{
printf(" \\\n ");
namelen = 2;
}
printf(" %s", combine);
}
nasm_free(combine);
if (fp)
return fp;
if (!ip)
break;
prefix = ip->path;
ip = ip->next;
}
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 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;
}
else if (tt->type == TOK_WHITESPACE)
{
tt = tt->next;
continue;
}
else if (tt->type != t->type ||
mstrcmp(tt->text, t->text, casesense))
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -