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

📄 preproc.c

📁 一个汇编语言编译器源码
💻 C
📖 第 1 页 / 共 5 页
字号:
	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 + -