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 = ¯o->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 (¯o->sub); sb_new (&name); macro->formal_count = 0; macro->formals = 0; idx = sb_skip_white (idx, in); if (! buffer_and_nest ("MACRO", "ENDM", ¯o->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 + -
显示快捷键?