macro.c

来自「基于4个mips核的noc设计」· C语言 代码 · 共 1,254 行 · 第 1/2 页

C
1,254
字号
/* macro.c - macro support for gas and gasp   Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000   Free Software Foundation, Inc.   Written by Steve and Judy Chamberlain of Cygnus Support,      sac@cygnus.com   This file is part of GAS, the GNU Assembler.   GAS is free software; you can redistribute it and/or modify   it under the terms of the GNU General Public License as published by   the Free Software Foundation; either version 2, or (at your option)   any later version.   GAS is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   GNU General Public License for more details.   You should have received a copy of the GNU General Public License   along with GAS; see the file COPYING.  If not, write to the Free   Software Foundation, 59 Temple Place - Suite 330, Boston, MA   02111-1307, USA.  */#include "config.h"/* AIX requires this to be the first thing in the file.  */#ifdef __GNUC__# ifndef alloca#  ifdef __STDC__extern void *alloca ();#  elseextern char *alloca ();#  endif# endif#else# if HAVE_ALLOCA_H#  include <alloca.h># else#  ifdef _AIX #pragma alloca#  else#   ifndef alloca /* predefined by HP cc +Olibcalls */#    if !defined (__STDC__) && !defined (__hpux)extern char *alloca ();#    elseextern void *alloca ();#    endif /* __STDC__, __hpux */#   endif /* alloca */#  endif /* _AIX */# endif /* HAVE_ALLOCA_H */#endif#include <stdio.h>#ifdef HAVE_STRING_H#include <string.h>#else#include <strings.h>#endif#include <ctype.h>#ifdef HAVE_STDLIB_H#include <stdlib.h>#endif#include "libiberty.h"#include "sb.h"#include "hash.h"#include "macro.h"#include "asintl.h"/* The routines in this file handle macro definition and expansion.   They are called by both gasp and gas.  *//* Internal functions.  */static int get_token PARAMS ((int, sb *, sb *));static int getstring PARAMS ((int, sb *, sb *));static int get_any_string PARAMS ((int, sb *, sb *, int, int));static int do_formals PARAMS ((macro_entry *, int, sb *));static int get_apost_token PARAMS ((int, sb *, sb *, int));static int sub_actual  PARAMS ((int, sb *, sb *, struct hash_control *, int, sb *, int));static const char *macro_expand_body  PARAMS ((sb *, sb *, formal_entry *, struct hash_control *, int, int));static const char *macro_expand PARAMS ((int, sb *, macro_entry *, sb *, int));#define ISWHITE(x) ((x) == ' ' || (x) == '\t')#define ISSEP(x) \ ((x) == ' ' || (x) == '\t' || (x) == ',' || (x) == '"' || (x) == ';' \  || (x) == ')' || (x) == '(' \  || ((macro_alternate || macro_mri) && ((x) == '<' || (x) == '>')))#define ISBASE(x) \  ((x) == 'b' || (x) == 'B' \   || (x) == 'q' || (x) == 'Q' \   || (x) == 'h' || (x) == 'H' \   || (x) == 'd' || (x) == 'D')/* The macro hash table.  */static struct hash_control *macro_hash;/* Whether any macros have been defined.  */int macro_defined;/* Whether we are in GASP alternate mode.  */static int macro_alternate;/* Whether we are in MRI mode.  */static int macro_mri;/* Whether we should strip '@' characters.  */static int macro_strip_at;/* Function to use to parse an expression.  */static int (*macro_expr) PARAMS ((const char *, int, sb *, int *));/* Number of macro expansions that have been done.  */static int macro_number;/* Initialize macro processing.  */voidmacro_init (alternate, mri, strip_at, expr)     int alternate;     int mri;     int strip_at;     int (*expr) PARAMS ((const char *, int, sb *, int *));{  macro_hash = hash_new ();  macro_defined = 0;  macro_alternate = alternate;  macro_mri = mri;  macro_strip_at = strip_at;  macro_expr = expr;}/* Switch in and out of MRI mode on the fly.  */voidmacro_mri_mode (mri)     int mri;{  macro_mri = mri;}/* Read input lines till we get to a TO string.   Increase nesting depth if we get a FROM string.   Put the results into sb at PTR.   Add a new input line to an sb using GET_LINE.   Return 1 on success, 0 on unexpected EOF.  */intbuffer_and_nest (from, to, ptr, get_line)     const char *from;     const char *to;     sb *ptr;     int (*get_line) PARAMS ((sb *));{  int from_len = strlen (from);  int to_len = strlen (to);  int depth = 1;  int line_start = ptr->len;  int more = get_line (ptr);  while (more)    {      /* Try and find the first pseudo op on the line.  */      int i = line_start;      if (! macro_alternate && ! macro_mri)	{	  /* With normal syntax we can suck what we want till we get	     to the dot.  With the alternate, labels have to start in	     the first column, since we cant tell what's a label and	     whats a pseudoop.  */	  /* Skip leading whitespace.  */	  while (i < ptr->len && ISWHITE (ptr->ptr[i]))	    i++;	  /* Skip over a label.  */	  while (i < ptr->len		 && (isalnum ((unsigned char) ptr->ptr[i])		     || ptr->ptr[i] == '_'		     || ptr->ptr[i] == '$'))	    i++;	  /* And a colon.  */	  if (i < ptr->len	      && ptr->ptr[i] == ':')	    i++;	}      /* Skip trailing whitespace.  */      while (i < ptr->len && ISWHITE (ptr->ptr[i]))	i++;      if (i < ptr->len && (ptr->ptr[i] == '.'			   || macro_alternate			   || macro_mri))	{	  if (ptr->ptr[i] == '.')	    i++;	  if (strncasecmp (ptr->ptr + i, from, from_len) == 0	      && (ptr->len == (i + from_len)		  || ! isalnum (ptr->ptr[i + from_len])))	    depth++;	  if (strncasecmp (ptr->ptr + i, to, to_len) == 0	      && (ptr->len == (i + to_len)		  || ! isalnum (ptr->ptr[i + to_len])))	    {	      depth--;	      if (depth == 0)		{		  /* Reset the string to not include the ending rune.  */		  ptr->len = line_start;		  break;		}	    }	}      /* Add a CR to the end and keep running.  */      sb_add_char (ptr, '\n');      line_start = ptr->len;      more = get_line (ptr);    }  /* Return 1 on success, 0 on unexpected EOF.  */  return depth == 0;}/* Pick up a token.  */static intget_token (idx, in, name)     int idx;     sb *in;     sb *name;{  if (idx < in->len      && (isalpha ((unsigned char) in->ptr[idx])	  || in->ptr[idx] == '_'	  || in->ptr[idx] == '$'))    {      sb_add_char (name, in->ptr[idx++]);      while (idx < in->len	     && (isalnum ((unsigned char) in->ptr[idx])		 || in->ptr[idx] == '_'		 || in->ptr[idx] == '$'))	{	  sb_add_char (name, in->ptr[idx++]);	}    }  /* Ignore trailing &.  */  if (macro_alternate && idx < in->len && in->ptr[idx] == '&')    idx++;  return idx;}/* Pick up a string.  */static intgetstring (idx, in, acc)     int idx;     sb *in;     sb *acc;{  idx = sb_skip_white (idx, in);  while (idx < in->len	 && (in->ptr[idx] == '"'	     || (in->ptr[idx] == '<' && (macro_alternate || macro_mri))	     || (in->ptr[idx] == '\'' && macro_alternate)))    {      if (in->ptr[idx] == '<')	{	  int nest = 0;	  idx++;	  while ((in->ptr[idx] != '>' || nest)		 && idx < in->len)	    {	      if (in->ptr[idx] == '!')		{		  idx++;		  sb_add_char (acc, in->ptr[idx++]);		}	      else		{		  if (in->ptr[idx] == '>')		    nest--;		  if (in->ptr[idx] == '<')		    nest++;		  sb_add_char (acc, in->ptr[idx++]);		}	    }	  idx++;	}      else if (in->ptr[idx] == '"' || in->ptr[idx] == '\'')	{	  char tchar = in->ptr[idx];	  int escaped = 0;	  idx++;	  while (idx < in->len)	    {	      if (in->ptr[idx - 1] == '\\')		escaped ^= 1;	      else		escaped = 0;	      if (macro_alternate && in->ptr[idx] == '!')		{		  idx ++;		  sb_add_char (acc, in->ptr[idx]);		  idx ++;		}	      else if (escaped && in->ptr[idx] == tchar)		{		  sb_add_char (acc, tchar);		  idx ++;		}	      else		{		  if (in->ptr[idx] == tchar)		    {		      idx ++;		      if (idx >= in->len || in->ptr[idx] != tchar)			break;		    }		  sb_add_char (acc, in->ptr[idx]);		  idx ++;		}	    }	}    }  return idx;}/* Fetch string from the input stream,   rules:    'Bxyx<whitespace>  	-> return 'Bxyza    %<char>		-> return string of decimal value of x    "<string>"		-> return string    xyx<whitespace>     -> return xyz*/static intget_any_string (idx, in, out, expand, pretend_quoted)     int idx;     sb *in;     sb *out;     int expand;     int pretend_quoted;{  sb_reset (out);  idx = sb_skip_white (idx, in);  if (idx < in->len)    {      if (in->len > 2 && in->ptr[idx + 1] == '\'' && ISBASE (in->ptr[idx]))	{	  while (!ISSEP (in->ptr[idx]))	    sb_add_char (out, in->ptr[idx++]);	}      else if (in->ptr[idx] == '%'	       && macro_alternate	       && expand)	{	  int val;	  char buf[20];	  /* Turns the next expression into a string.  */	  idx = (*macro_expr) (_("% operator needs absolute expression"),			       idx + 1,			       in,			       &val);	  sprintf(buf, "%d", val);	  sb_add_string (out, buf);	}      else if (in->ptr[idx] == '"'	       || (in->ptr[idx] == '<' && (macro_alternate || macro_mri))	       || (macro_alternate && in->ptr[idx] == '\''))	{	  if (macro_alternate	      && ! macro_strip_at	      && expand)	    {	      /* Keep the quotes.  */	      sb_add_char (out, '\"');	      idx = getstring (idx, in, out);	      sb_add_char (out, '\"');	    }	  else	    {	      idx = getstring (idx, in, out);	    }	}      else	{	  while (idx < in->len		 && (in->ptr[idx] == '"'		     || in->ptr[idx] == '\''		     || pretend_quoted		     || (in->ptr[idx] != ' '			 && in->ptr[idx] != '\t'			 && in->ptr[idx] != ','			 && (in->ptr[idx] != '<'			     || (! macro_alternate && ! macro_mri)))))	    {	      if (in->ptr[idx] == '"'		  || in->ptr[idx] == '\'')		{		  char tchar = in->ptr[idx];		  sb_add_char (out, in->ptr[idx++]);		  while (idx < in->len			 && in->ptr[idx] != tchar)		    sb_add_char (out, in->ptr[idx++]);		  if (idx == in->len)		    return idx;		}	      sb_add_char (out, in->ptr[idx++]);	    }	}    }  return idx;}/* Pick up the formal parameters of a macro definition.  */static intdo_formals (macro, idx, in)     macro_entry *macro;     int idx;     sb *in;{  formal_entry **p = &macro->formals;  macro->formal_count = 0;  macro->formal_hash = hash_new ();  while (idx < in->len)    {      formal_entry *formal;      formal = (formal_entry *) xmalloc (sizeof (formal_entry));      sb_new (&formal->name);      sb_new (&formal->def);      sb_new (&formal->actual);      idx = sb_skip_white (idx, in);      idx = get_token (idx, in, &formal->name);      if (formal->name.len == 0)	break;      idx = sb_skip_white (idx, in);      if (formal->name.len)	{	  /* This is a formal.  */	  if (idx < in->len && in->ptr[idx] == '=')	    {	      /* Got a default.  */	      idx = get_any_string (idx + 1, in, &formal->def, 1, 0);	    }	}      /* Add to macro's hash table.  */      hash_jam (macro->formal_hash, sb_terminate (&formal->name), formal);      formal->index = macro->formal_count;      idx = sb_skip_comma (idx, in);      macro->formal_count++;      *p = formal;      p = &formal->next;      *p = NULL;    }  if (macro_mri)    {      formal_entry *formal;      const char *name;      /* Add a special NARG formal, which macro_expand will set to the         number of arguments.  */      formal = (formal_entry *) xmalloc (sizeof (formal_entry));      sb_new (&formal->name);      sb_new (&formal->def);      sb_new (&formal->actual);      /* The same MRI assemblers which treat '@' characters also use         the name $NARG.  At least until we find an exception.  */      if (macro_strip_at)	name = "$NARG";      else	name = "NARG";      sb_add_string (&formal->name, name);      /* Add to macro's hash table.  */      hash_jam (macro->formal_hash, name, formal);      formal->index = NARG_INDEX;      *p = formal;      formal->next = NULL;    }  return idx;}/* Define a new macro.  Returns NULL on success, otherwise returns an   error message.  If NAMEP is not NULL, *NAMEP is set to the name of   the macro which was defined.  */const char *define_macro (idx, in, label, get_line, namep)     int idx;     sb *in;     sb *label;     int (*get_line) PARAMS ((sb *));     const char **namep;{  macro_entry *macro;  sb name;  const char *namestr;  macro = (macro_entry *) xmalloc (sizeof (macro_entry));  sb_new (&macro->sub);  sb_new (&name);  macro->formal_count = 0;  macro->formals = 0;  idx = sb_skip_white (idx, in);  if (! buffer_and_nest ("MACRO", "ENDM", &macro->sub, get_line))    return _("unexpected end of file in macro definition");  if (label != NULL && label->len != 0)    {      sb_add_sb (&name, label);      if (idx < in->len && in->ptr[idx] == '(')	{	  /* It's the label: MACRO (formals,...)  sort  */	  idx = do_formals (macro, idx + 1, in);	  if (in->ptr[idx] != ')')	    return _("missing ) after formals");	}      else	{	  /* It's the label: MACRO formals,...  sort  */	  idx = do_formals (macro, idx, in);	}    }  else    {      idx = get_token (idx, in, &name);      idx = sb_skip_comma (idx, in);      idx = do_formals (macro, idx, in);    }  /* And stick it in the macro hash table.  */  for (idx = 0; idx < name.len; idx++)    if (isupper ((unsigned char) name.ptr[idx]))      name.ptr[idx] = tolower (name.ptr[idx]);  namestr = sb_terminate (&name);  hash_jam (macro_hash, namestr, (PTR) macro);  macro_defined = 1;  if (namep != NULL)    *namep = namestr;  return NULL;}/* Scan a token, and then skip KIND.  */static intget_apost_token (idx, in, name, kind)     int idx;     sb *in;     sb *name;     int kind;{  idx = get_token (idx, in, name);  if (idx < in->len      && in->ptr[idx] == kind      && (! macro_mri || macro_strip_at)      && (! macro_strip_at || kind == '@'))    idx++;  return idx;}/* Substitute the actual value for a formal parameter.  */static intsub_actual (start, in, t, formal_hash, kind, out, copyifnotthere)     int start;     sb *in;     sb *t;     struct hash_control *formal_hash;     int kind;     sb *out;     int copyifnotthere;{  int src;  formal_entry *ptr;  src = get_apost_token (start, in, t, kind);  /* See if it's in the macro's hash table, unless this is     macro_strip_at and kind is '@' and the token did not end in '@'.  */  if (macro_strip_at      && kind == '@'      && (src == start || in->ptr[src - 1] != '@'))

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?