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

📄 preproc.c

📁 一个汇编语言编译器源码
💻 C
📖 第 1 页 / 共 5 页
字号:

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