⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 preproc.c

📁 CC386 is a general-purpose 32-bit C compiler. It is not an optimizing compiler but given that the co
💻 C
📖 第 1 页 / 共 5 页
字号:

    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 + -