diff --git a/gas/.Sanitize b/gas/.Sanitize index 75d45c5444..c5bae55279 100644 --- a/gas/.Sanitize +++ b/gas/.Sanitize @@ -76,6 +76,8 @@ link.cmd listing.c listing.h literal.c +macro.c +macro.h messages.c mpw-config.in mpw-make.in @@ -84,6 +86,8 @@ output-file.c output-file.h read.c read.h +sb.c +sb.h stabs.c struc-symbol.h subsegs.c diff --git a/gas/ChangeLog b/gas/ChangeLog index 786bb167d6..3a44e5c405 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,67 @@ +Mon Aug 21 13:57:20 1995 Ian Lance Taylor + + Add support for macros. + * as.c: Include sb.h and macro.h. + (max_macro_next): New global variable. + (main): Call macro_init. + (macro_expr): New static function. + * as.h (max_macro_nest): Declare. + * read.c (line_label): Rename from mri_line_label. Change all + uses. + (potable): Add exitm, irp, irpc, macro, mexit, rept. + (read_a_source_file): Always clear line_label at the start of a + line, not just when flag_mri or LABELS_WITHOUT_COLONS. Fixup + MRI/LABELS_WITHOUT_COLONS handling. In MRI mode, permit label: + equ val. Set line_label when calling colon. In MRI mode, a + leading '.' does not imply a pseudo-op. Check for macro expansion + before calling md_assemble. + (s_irp): New function. + (get_line_sb): New static function. + (s_macro): New function. + (s_mexit): New function. + (s_rept): New function. + * read.h (line_label): Rename from mri_line_label. + (s_irp, s_rept): Declare. + (s_macro, s_mexit): Declare. + * input-scrub.c: Include sb.h. + (sb_index, from_sb): New static variables. + (macro_nest): New static variable. + (struct input_save): Add sb_index and from_sb fields. Change + next_saved_file field to be struct input_save *. + (next_saved_file): Changed to be struct input_save *. + (input_scrub_push): Change to return type struct input_save *. + Save sb_index and from_sb. + (input_scrub_pop): Change parameter type to struct input_save *. + Restore sb_index and from_sb. + (input_scrub_include_sb): New function. + (input_scrub_next_buffer): Handle reading from from_sb. + (bump_line_counters): Only increment lines if not using from_sb. + * config/tc-m68k.c (opt_table): Add nest. + (opt_nest): New static function. + * gasp.c: Include sb.h and macro.h. Move all sb related functions + and definitions to sb.h and sb.c. Move all macro related + functions and definitions to macro.h and macro.c. + * sb.h, sb.c: New files, extracted from gasp.c. + * macro.h, macro.c: Likewise. + * Makefile.in (OBJS): Add sb.o and macro.o + (GASPOBJS): Define. + (gasp.new): Depend upon $(GASPOBJS). Use $(GASPOBJS) to link. + (TARG_CPU_DEP_m68k): Depend upon subsegs.h. + (gasp.o): Depend upon sb.h and macro.h. + (sb.o): New target. + (macro.o): New target. + (as.o): Depend upon sb.h and macro.h. + (input-scrub.o): Depend upon sb.h. + (read.o): Depend upon sb.h and macro.h. + + * cond.c (get_mri_string): New static function. + (s_ifc): New function. + * read.c (potable): Add ifc and ifnc. + * read.h (s_ifc): Declare. + + * app.c (do_scrub_begin): In MRI mode, set lex of ' to + LEX_IS_STRINGQUOTE. + Mon Aug 21 13:41:33 1995 Michael Meissner * config/tc-ppc.c (md_assemble): Allow @HA, @L, and @H suffixes on diff --git a/gas/Makefile.in b/gas/Makefile.in index dc1d112918..c997b59947 100644 --- a/gas/Makefile.in +++ b/gas/Makefile.in @@ -163,6 +163,8 @@ LINKED_HEADERS = \ HEADERS = $(LINKED_HEADERS) $(REAL_HEADERS) +TE_OBJS= + # @target_frag@ OBJS = \ @@ -192,9 +194,17 @@ OBJS = \ listing.o \ ecoff.o \ stabs.o \ + sb.o \ + macro.o \ @extra_objects@ \ $(TE_OBJS) +GASPOBJS = \ + gasp.o \ + macro.o \ + sb.o \ + hash.o + all: .gdbinit as.new gasp.new @srcroot=`cd $(srcroot); pwd`; export srcroot; \ (cd doc ; $(MAKE) $(FLAGS_TO_PASS) all) @@ -245,8 +255,8 @@ $(OBJS): config.h as.h targ-env.h obj-format.h targ-cpu.h flonum.h expr.h \ struc-symbol.h write.h frags.h hash.h read.h symbols.h tc.h obj.h \ listing.h bignum.h -gasp.new: gasp.o - $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o gasp.new gasp.o $(LIBS) $(LOADLIBES) +gasp.new: $(GASPOBJS) + $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o gasp.new $(GASPOBJS) $(LIBS) $(LOADLIBES) installcheck: @echo No installcheck target is available yet for the GNU assembler. @@ -291,7 +301,7 @@ TARG_CPU_DEP_i386 = $(srcdir)/../include/opcode/i386.h TARG_CPU_DEP_i860 = TARG_CPU_DEP_i960 = TARG_CPU_DEP_m68k = $(srcdir)/../include/opcode/m68k.h \ - $(srcdir)/config/m68k-parse.h + $(srcdir)/config/m68k-parse.h subsegs.h TARG_CPU_DEP_m88k = $(srcdir)/config/m88k-opcode.h TARG_CPU_DEP_mips = $(srcdir)/../include/opcode/mips.h TARG_CPU_DEP_ns32k = @@ -306,9 +316,11 @@ TARG_CPU_DEP_vax = TARG_CPU_DEP_w65 = $(srcdir)/../opcodes/w65-opc.h TARG_CPU_DEP_z8k = $(srcdir)/../opcodes/z8k-opc.h -gasp.o : gasp.c config.h +gasp.o : gasp.c sb.h macro.h config.h +sb.o : sb.c sb.h config.h +macro.o : macro.c macro.h sb.h hash.h config.h app.o : app.c write.h -as.o : as.c output-file.h write.h subsegs.h +as.o : as.c output-file.h write.h subsegs.h sb.h macro.h atof-generic.o : atof-generic.c bignum-copy.o : bignum-copy.c cond.o : cond.c @@ -320,12 +332,12 @@ flonum-mult.o : flonum-mult.c frags.o : frags.c subsegs.h hash.o : hash.c input-file.o : input-file.c input-file.h -input-scrub.o : input-scrub.c input-file.h +input-scrub.o : input-scrub.c input-file.h sb.h listing.o : listing.c input-file.h subsegs.h literal.o : literal.c subsegs.h messages.o : messages.c output-file.o : output-file.c output-file.h -read.o : read.c +read.o : read.c sb.h macro.h subsegs.o : subsegs.c subsegs.h symbols.o : symbols.c subsegs.h write.o : write.c subsegs.h output-file.h diff --git a/gas/NEWS b/gas/NEWS index c35108e7d5..ee4d9a1e80 100644 --- a/gas/NEWS +++ b/gas/NEWS @@ -1,5 +1,15 @@ -*- text -*- +Changes since 2.5: + +Gas now directly supports macros, without requiring GASP. + +Gas now has an MRI assembler compatibility mode. + +Added -mips4 support to MIPS assembler. + +Added PIC support to Solaris and SPARC SunOS 4 assembler. + Changes since 2.3: Converted this directory to use an autoconf-generated configure script. @@ -18,17 +28,19 @@ used, it should become obvious pretty quickly what the problem is. Usage message is available with "--help". +The GNU Assembler Preprocessor (gasp) is included. (Actually, it was in 2.3 +also, but didn't get into the NEWS file.) + Weak symbol support for a.out. A bug in the listing code which could cause an infinite loop has been fixed. Bugs in listings when generating a COFF object file have also been fixed. Initial i386-svr4 PIC implementation from Eric Youngdale, based on code by Paul -Kranenburg. This code was oriented towards gas version 1.xx; in updating some -aspects of it for version 2, I broke it. +Kranenburg. Improved Alpha support. Immediate constants can have a much larger range now. -Support for the 21164 has been added. +Support for the 21164 has been contributed by Digital. Updated ns32k (pc532-mach, netbsd532) support from Ian Dall. diff --git a/gas/as.c b/gas/as.c index e2da5cb963..4850e866bb 100644 --- a/gas/as.c +++ b/gas/as.c @@ -15,7 +15,7 @@ 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* * Main program for AS; a 32-bit assembler of GNU. @@ -40,13 +40,20 @@ #include "as.h" #include "subsegs.h" #include "output-file.h" +#include "sb.h" +#include "macro.h" static void perform_an_assembly_pass PARAMS ((int argc, char **argv)); +static int macro_expr PARAMS ((const char *, int, sb *, int *)); int listing; /* true if a listing is wanted */ static char *listing_filename = NULL; /* Name of listing file. */ +/* Maximum level of macro nesting. */ + +int max_macro_nest = 100; + char *myname; /* argv[0] */ #ifdef BFD_ASSEMBLER segT reg_section, expr_section; @@ -94,6 +101,7 @@ Options:\n\ -K warn when differences altered for long displacements\n\ -L keep local symbols (starting with `L')\n"); fprintf (stream, "\ +-M,--mri assemble in MRI compatibility mode\n\ -nocpp ignored\n\ -o OBJFILE name the object-file output OBJFILE (default a.out)\n\ -R fold data section into text section\n\ @@ -224,7 +232,7 @@ parse_args (pargc, pargv) /* -K is not meaningful if .word is not being hacked. */ 'K', #endif - 'L', 'R', 'W', 'Z', 'f', 'a', ':', ':', 'D', 'I', ':', 'o', ':', + 'L', 'M', 'R', 'W', 'Z', 'f', 'a', ':', ':', 'D', 'I', ':', 'o', ':', #ifndef VMS /* -v takes an argument on VMS, so we don't make it a generic option. */ @@ -239,6 +247,7 @@ parse_args (pargc, pargv) static const struct option std_longopts[] = { #define OPTION_HELP (OPTION_STD_BASE) {"help", no_argument, NULL, OPTION_HELP}, + {"mri", no_argument, NULL, 'M'}, #define OPTION_NOCPP (OPTION_STD_BASE + 1) {"nocpp", no_argument, NULL, OPTION_NOCPP}, #define OPTION_STATISTICS (OPTION_STD_BASE + 2) @@ -370,6 +379,10 @@ parse_args (pargc, pargv) flag_keep_locals = 1; break; + case 'M': + flag_mri = 1; + break; + case 'R': flag_readonly_data_in_text = 1; break; @@ -499,9 +512,10 @@ main (argc, argv) frag_init (); subsegs_begin (); read_begin (); - input_scrub_begin (); - PROGRESS (1); parse_args (&argc, &argv); + input_scrub_begin (); + expr_begin (); + macro_init (0, flag_mri, macro_expr); PROGRESS (1); @@ -683,4 +697,32 @@ perform_an_assembly_pass (argc, argv) read_a_source_file (""); } /* perform_an_assembly_pass() */ +/* The interface between the macro code and gas expression handling. */ + +static int +macro_expr (emsg, idx, in, val) + const char *emsg; + int idx; + sb *in; + int *val; +{ + char *hold; + expressionS ex; + + sb_terminate (in); + + hold = input_line_pointer; + input_line_pointer = in->ptr + idx; + expression (&ex); + idx = input_line_pointer - in->ptr; + input_line_pointer = hold; + + if (ex.X_op != O_constant) + as_bad ("%s", emsg); + + *val = (int) ex.X_add_number; + + return idx; +} + /* end of as.c */ diff --git a/gas/as.h b/gas/as.h index 3cd5c58e10..76d75d6d7a 100644 --- a/gas/as.h +++ b/gas/as.h @@ -519,6 +519,9 @@ COMMON int linkrelax; /* TRUE if we should produce a listing. */ extern int listing; +/* Maximum level of macro nesting. */ +extern int max_macro_nest; + struct _pseudo_type { /* assembler mnemonic, lower case, no '.' */ diff --git a/gas/config/tc-m68k.c b/gas/config/tc-m68k.c index b212d507c2..fe3ee54b5e 100644 --- a/gas/config/tc-m68k.c +++ b/gas/config/tc-m68k.c @@ -4243,6 +4243,7 @@ struct opt_action /* The table used to handle the MRI OPT pseudo-op. */ static void skip_to_comma PARAMS ((int, int)); +static void opt_nest PARAMS ((int, int)); static void opt_chip PARAMS ((int, int)); static void opt_list PARAMS ((int, int)); static void opt_list_symbols PARAMS ((int, int)); @@ -4274,6 +4275,7 @@ static const struct opt_action opt_table[] = { "mex", 0, 0, 0, 0 }, { "mc", 0, 0, 0, 0 }, { "md", 0, 0, 0, 0 }, + { "nest", opt_nest, 0, 0, 0 }, { "next", skip_to_comma, 0, 0, 0 }, { "o", 0, 0, 0, 0 }, { "old", 0, 0, 0, 0 }, @@ -4373,6 +4375,23 @@ skip_to_comma (arg, on) ++input_line_pointer; } +/* Handle the OPT NEST=depth option. */ + +static void +opt_nest (arg, on) + int arg; + int on; +{ + if (*input_line_pointer != '=') + { + as_bad ("bad format of OPT NEST=depth"); + return; + } + + ++input_line_pointer; + max_macro_nest = get_absolute_expression (); +} + /* Handle the OPT P=chip option. */ static void @@ -4424,7 +4443,7 @@ s_reg (ignore) struct m68k_op rop; unsigned long mask; - if (mri_line_label == NULL) + if (line_label == NULL) { as_bad ("missing label"); ignore_rest_of_line (); @@ -4481,9 +4500,9 @@ s_reg (ignore) return; } - S_SET_SEGMENT (mri_line_label, absolute_section); - S_SET_VALUE (mri_line_label, mask); - mri_line_label->sy_frag = &zero_address_frag; + S_SET_SEGMENT (line_label, absolute_section); + S_SET_VALUE (line_label, mask); + line_label->sy_frag = &zero_address_frag; demand_empty_rest_of_line (); } diff --git a/gas/gasp.c b/gas/gasp.c index 0380543b88..1e242202a4 100644 --- a/gas/gasp.c +++ b/gas/gasp.c @@ -65,6 +65,8 @@ extern char *malloc (); #include "ansidecl.h" #include "libiberty.h" +#include "sb.h" +#include "macro.h" char *program_version = "1.2"; @@ -88,58 +90,6 @@ int had_end; /* Seen .END */ /* The output stream */ FILE *outfile; -/* string blocks - - I had a couple of choices when deciding upon this data structure. - gas uses null terminated strings for all its internal work. This - often means that parts of the program that want to examine - substrings have to manipulate the data in the string to do the - right thing (a common operation is to single out a bit of text by - saving away the character after it, nulling it out, operating on - the substring and then replacing the character which was under the - null). This is a pain and I remember a load of problems that I had with - code in gas which almost got this right. Also, it's harder to grow and - allocate null terminated strings efficiently. - - Obstacks provide all the functionality needed, but are too - complicated, hence the sb. - - An sb is allocated by the caller, and is initialzed to point to an - sb_element. sb_elements are kept on a free lists, and used when - needed, replaced onto the free list when unused. - */ - -#define max_power_two 30 /* don't allow strings more than - 2^max_power_two long */ -/* structure of an sb */ -typedef struct sb - { - char *ptr; /* points to the current block. */ - int len; /* how much is used. */ - int pot; /* the maximum length is 1<ptr[*]; - sb_kill (&foo); - -*/ - -/* initializes an sb. */ - -static void -sb_build (ptr, size) - sb *ptr; - int size; -{ - /* see if we can find one to allocate */ - sb_element *e; - - if (size > max_power_two) - { - FATAL ((stderr, "string longer than %d bytes requested.\n", - 1 << max_power_two)); - } - e = free_list.size[size]; - if (!e) - { - /* nothing there, allocate one and stick into the free list */ - e = (sb_element *) xmalloc (sizeof (sb_element) + (1 << size)); - e->next = free_list.size[size]; - e->size = 1 << size; - free_list.size[size] = e; - string_count[size]++; - } - - /* remove from free list */ - - free_list.size[size] = e->next; - - /* copy into callers world */ - ptr->ptr = e->data; - ptr->pot = size; - ptr->len = 0; - ptr->item = e; -} - - -static void -sb_new (ptr) - sb *ptr; -{ - sb_build (ptr, dsize); -} - -/* deallocate the sb at ptr */ - -static -void -sb_kill (ptr) - sb *ptr; -{ - /* return item to free list */ - ptr->item->next = free_list.size[ptr->pot]; - free_list.size[ptr->pot] = ptr->item; -} - -/* add the sb at s to the end of the sb at ptr */ - -static void sb_check (); - -static -void -sb_add_sb (ptr, s) - sb *ptr; - sb *s; -{ - sb_check (ptr, s->len); - memcpy (ptr->ptr + ptr->len, s->ptr, s->len); - ptr->len += s->len; -} - -/* make sure that the sb at ptr has room for another len characters, - and grow it if it doesn't. */ - -static void -sb_check (ptr, len) - sb *ptr; - int len; -{ - if (ptr->len + len >= 1 << ptr->pot) - { - sb tmp; - int pot = ptr->pot; - while (ptr->len + len >= 1 << pot) - pot++; - sb_build (&tmp, pot); - sb_add_sb (&tmp, ptr); - sb_kill (ptr); - *ptr = tmp; - } -} - -/* make the sb at ptr point back to the beginning. */ - -static void -sb_reset (ptr) - sb *ptr; -{ - ptr->len = 0; -} - -/* add character c to the end of the sb at ptr. */ - -static void -sb_add_char (ptr, c) - sb *ptr; - int c; -{ - sb_check (ptr, 1); - ptr->ptr[ptr->len++] = c; -} - -/* add null terminated string s to the end of sb at ptr. */ - -static void -sb_add_string (ptr, s) - sb *ptr; - const char *s; -{ - int len = strlen (s); - sb_check (ptr, len); - memcpy (ptr->ptr + ptr->len, s, len); - ptr->len += len; -} - -/* add string at s of length len to sb at ptr */ - -static void -sb_add_buffer (ptr, s, len) - sb *ptr; - const char *s; - int len; -{ - sb_check (ptr, len); - memcpy (ptr->ptr + ptr->len, s, len); - ptr->len += len; -} - - -/* print the sb at ptr to the output file */ - -static -void -sb_print (ptr) - sb *ptr; -{ - int i; - int nc = 0; - - for (i = 0; i < ptr->len; i++) - { - if (nc) - { - fprintf (outfile, ","); - } - fprintf (outfile, "%d", ptr->ptr[i]); - nc = 1; - } -} - -static void -sb_print_at (idx, ptr) - int idx; - sb *ptr; -{ - int i; - for (i = idx; i < ptr->len; i++) - putc (ptr->ptr[i], outfile); -} -/* put a null at the end of the sb at in and return the start of the - string, so that it can be used as an arg to printf %s. */ - -static -char * -sb_name (in) - sb *in; -{ - /* stick a null on the end of the string */ - sb_add_char (in, 0); - return in->ptr; -} - -/* start at the index idx into the string in sb at ptr and skip - whitespace. return the index of the first non whitespace character */ - -static int -sb_skip_white (idx, ptr) - int idx; - sb *ptr; -{ - while (idx < ptr->len && ISWHITE (ptr->ptr[idx])) - idx++; - return idx; -} - -/* start at the index idx into the sb at ptr. skips whitespace, - a comma and any following whitespace. returnes the index of the - next character. */ - -static int -sb_skip_comma (idx, ptr) - int idx; - sb *ptr; -{ - while (idx < ptr->len && ISWHITE (ptr->ptr[idx])) - idx++; - - if (idx < ptr->len - && ptr->ptr[idx] == ',') - idx++; - - while (idx < ptr->len && ISWHITE (ptr->ptr[idx])) - idx++; - - return idx; -} - - /* hash table maintenance. */ /* build a new hash table with size buckets, and fill in the info at ptr. */ @@ -1680,7 +1368,7 @@ do_data (idx, in, size) } } sb_kill (&acc); - sb_print_at (idx, in); + sb_print_at (outfile, idx, in); fprintf (outfile, "\n"); } @@ -2703,89 +2391,6 @@ do_ifc (idx, in, ifnc) ifstack[ifi].hadelse = 0; } -/* Read input lines till we get to a TO string. - Increase nesting depth if we geta FROM string. - Put the results into sb at PTR. */ - -static void -buffer_and_nest (from, to, ptr) - const char *from; - const char *to; - sb *ptr; -{ - int from_len = strlen (from); - int to_len = strlen (to); - int depth = 1; - int line_start = ptr->len; - int line = linecount (); - - int more = get_line (ptr); - - while (more) - { - /* Try and find the first pseudo op on the line */ - int i = line_start; - - if (!alternate && !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 - && ISNEXTCHAR (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] == '.' - || alternate - || mri)) - { - if (ptr->ptr[i] == '.') - i++; - if (strncasecmp (ptr->ptr + i, from, from_len) == 0) - depth++; - if (strncasecmp (ptr->ptr + i, to, to_len) == 0) - { - 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); - } - - - if (depth) - FATAL ((stderr, "End of file whilst inside %s, started on line %d.\n", from, line)); -} - - /* .ENDR */ static void do_aendr () @@ -2804,18 +2409,19 @@ do_awhile (idx, in) int idx; sb *in; { + int line = linecount (); sb exp; - sb sub; - int doit; + sb_new (&sub); sb_new (&exp); process_assigns (idx, in, &exp); doit = istrue (0, &exp); - buffer_and_nest ("AWHILE", "AENDW", &sub); + if (! buffer_and_nest ("AWHILE", "AENDW", &sub, get_line)) + FATAL ((stderr, "AWHILE without a AENDW at %d.\n", line - 1)); /* Turn .AWHILE exp @@ -2886,20 +2492,25 @@ do_arepeat (idx, in) int idx; sb *in; { + int line = linecount (); sb exp; /* buffer with expression in it */ sb copy; /* expanded repeat block */ sb sub; /* contents of AREPEAT */ int rc; + int ret; char buffer[30]; + sb_new (&exp); sb_new (©); sb_new (&sub); process_assigns (idx, in, &exp); idx = exp_get_abs ("AREPEAT must have absolute operand.\n", 0, &exp, &rc); if (!mri) - buffer_and_nest ("AREPEAT", "AENDR", &sub); + ret = buffer_and_nest ("AREPEAT", "AENDR", &sub, get_line); else - buffer_and_nest ("REPT", "ENDR", &sub); + ret = buffer_and_nest ("REPT", "ENDR", &sub, get_line); + if (! ret) + FATAL ((stderr, "AREPEAT without a AENDR at %d.\n", line - 1)); if (rc > 0) { /* Push back the text following the repeat, and another repeat block @@ -2952,174 +2563,22 @@ do_irp (idx, in, irpc) sb *in; int irpc; { - const char *mn; - sb sub; - formal_entry f; - hash_table h; - hash_entry *p; - sb name; + const char *err; sb out; - if (irpc) - mn = "IRPC"; - else - mn = "IRP"; - - idx = sb_skip_white (idx, in); - - sb_new (&sub); - buffer_and_nest (mn, "ENDR", &sub); - - sb_new (&f.name); - sb_new (&f.def); - sb_new (&f.actual); - - idx = get_token (idx, in, &f.name); - if (f.name.len == 0) - { - ERROR ((stderr, "Missing model parameter in %s", mn)); - return; - } - - hash_new_table (1, &h); - p = hash_create (&h, &f.name); - p->type = hash_formal; - p->value.f = &f; - - f.index = 1; - f.next = NULL; - - sb_new (&name); - sb_add_string (&name, mn); - sb_new (&out); - idx = sb_skip_comma (idx, in); - if (eol (idx, in)) - { - /* Expand once with a null string. */ - macro_expand_body (&name, &sub, &out, &f, &h); - fprintf (outfile, "%s", sb_name (&out)); - } - else - { - while (!eol (idx, in)) - { - if (!irpc) - idx = get_any_string (idx, in, &f.actual, 1, 0); - else - { - sb_reset (&f.actual); - sb_add_char (&f.actual, in->ptr[idx]); - ++idx; - } - sb_reset (&out); - macro_expand_body (&name, &sub, &out, &f, &h); - fprintf (outfile, "%s", sb_name (&out)); - if (!irpc) - idx = sb_skip_comma (idx, in); - else - idx = sb_skip_white (idx, in); - } - } + err = expand_irp (irpc, idx, in, &out, get_line, comment_char); + if (err != NULL) + ERROR ((stderr, "%s\n", err)); + + fprintf (outfile, "%s", sb_terminate (&out)); - sb_kill (&sub); - sb_kill (&name); sb_kill (&out); } /* MACRO PROCESSING */ -static int number; -hash_table macro_table; - -/* Understand - - .MACRO - stuff - .ENDM -*/ - -static int -do_formals (macro, idx, in) - macro_entry *macro; - int idx; - sb *in; -{ - formal_entry **p = ¯o->formals; - macro->formal_count = 0; - hash_new_table (5, ¯o->formal_hash); - 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_entry *p = hash_create (¯o->formal_hash, &formal->name); - p->type = hash_formal; - p->value.f = formal; - } - - formal->index = macro->formal_count; - idx = sb_skip_comma (idx, in); - macro->formal_count++; - *p = formal; - p = &formal->next; - *p = NULL; - } - - if (mri) - { - formal_entry *formal; - - /* 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); - - sb_add_string (&formal->name, "NARG"); - - { - /* Add to macro's hash table */ - - hash_entry *p = hash_create (¯o->formal_hash, &formal->name); - p->type = hash_formal; - p->value.f = formal; - } - - formal->index = -2; - *p = formal; - formal->next = NULL; - } - - return idx; -} - /* Parse off LOCAL n1, n2,... Invent a label name for it */ static void @@ -3127,482 +2586,20 @@ do_local (idx, line) int idx; sb *line; { - static int ln; - sb acc; - sb sub; - char subs[10]; - sb_new (&acc); - sb_new (&sub); - idx = sb_skip_white (idx, line); - while (!eol(idx, line)) - { - sb_reset (&acc); - sb_reset (&sub); - ln++; - sprintf(subs, "LL%04x", ln); - idx = get_token(idx, line, &acc); - sb_add_string (&sub, subs); - hash_add_to_string_table (&assign_hash_table, &acc, &sub, 1); - idx = sb_skip_comma (idx, line); - } - sb_kill (&sub); - sb_kill (&acc); + ERROR ((stderr, "LOCAL outside of MACRO")); } -static -void +static void do_macro (idx, in) int idx; sb *in; { - macro_entry *macro; - sb name; + const char *err; + int line = linecount (); - 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); - buffer_and_nest ("MACRO", "ENDM", ¯o->sub); - if (label.len) - { - - sb_add_sb (&name, &label); - if (in->ptr[idx] == '(') - { - /* It's the label: MACRO (formals,...) sort */ - idx = do_formals (macro, idx + 1, in); - if (in->ptr[idx] != ')') - ERROR ((stderr, "Missing ) after formals.\n")); - } - else { - /* It's the label: MACRO formals,... sort */ - idx = do_formals (macro, idx, in); - } - } - else - { - idx = get_token (idx, in, &name); - idx = sb_skip_white (idx, in); - idx = do_formals (macro, idx, in); - } - - /* and stick it in the macro hash table */ - hash_create (¯o_table, &name)->value.m = macro; -} - -static -int -get_token (idx, in, name) - int idx; - sb *in; - sb *name; -{ - if (idx < in->len - && ISFIRSTCHAR (in->ptr[idx])) - { - sb_add_char (name, in->ptr[idx++]); - while (idx < in->len - && ISNEXTCHAR (in->ptr[idx])) - { - sb_add_char (name, in->ptr[idx++]); - } - } - /* Ignore trailing & */ - if (alternate && idx < in->len && in->ptr[idx] == '&') - idx++; - return idx; -} - -/* Scan a token, but stop if a ' is seen */ -static int -get_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) - idx++; - return idx; -} - -static int -sub_actual (src, in, t, formal_hash, kind, out, copyifnotthere) - int src; - sb *in; - sb *t; - hash_table *formal_hash; - int kind; - sb *out; - int copyifnotthere; -{ - /* This is something to take care of */ - hash_entry *ptr; - src = get_apost_token (src, in, t, kind); - /* See if it's in the macro's hash table */ - ptr = hash_lookup (formal_hash, t); - if (ptr) - { - if (ptr->value.f->actual.len) - { - sb_add_sb (out, &ptr->value.f->actual); - } - else - { - sb_add_sb (out, &ptr->value.f->def); - } - } - else if (copyifnotthere) - { - sb_add_sb (out, t); - } - else - { - sb_add_char (out, '\\'); - sb_add_sb (out, t); - } - return src; -} - -/* Copy the body from the macro buffer into a safe place and - substitute any args. */ - -static void -macro_expand_body (name, in, out, formals, formal_hash) - sb *name; - sb *in; - sb *out; - formal_entry *formals; - hash_table *formal_hash; -{ - sb t; - int src = 0; - int inquote = 0; - - sb_new (&t); - - while (src < in->len) - { - if (in->ptr[src] == '&') - { - sb_reset (&t); - if (mri && src + 1 < in->len && in->ptr[src + 1] == '&') - { - src = sub_actual (src + 2, in, &t, formal_hash, '\'', out, 1); - } - else - { - src = sub_actual (src + 1, in, &t, formal_hash, '&', out, 0); - } - } - else if (in->ptr[src] == '\\') - { - src++; - if (in->ptr[src] == comment_char) - { - /* This is a comment, just drop the rest of the line */ - while (src < in->len - && in->ptr[src] != '\n') - src++; - - } - else if (in->ptr[src] == '(') - { - /* Sub in till the next ')' literally */ - src++; - while (src < in->len && in->ptr[src] != ')') - { - sb_add_char (out, in->ptr[src++]); - } - if (in->ptr[src] == ')') - src++; - else - ERROR ((stderr, "Missplaced ).\n")); - } - else if (in->ptr[src] == '@') - { - /* Sub in the macro invocation number */ - - char buffer[6]; - src++; - sprintf (buffer, "%05d", number); - sb_add_string (out, buffer); - } - else if (in->ptr[src] == '&') - { - /* This is a preprocessor variable name, we don't do them - here */ - sb_add_char (out, '\\'); - sb_add_char (out, '&'); - src++; - } - else if (mri - && isalnum ((unsigned char) in->ptr[src])) - { - int ind; - formal_entry *f; - - if (isdigit ((unsigned char) in->ptr[src])) - ind = in->ptr[src] - '0'; - else if (isupper ((unsigned char) in->ptr[src])) - ind = in->ptr[src] - 'A' + 10; - else - ind = in->ptr[src] - 'a' + 10; - ++src; - for (f = formals; f != NULL; f = f->next) - { - if (f->index == ind - 1) - { - if (f->actual.len != 0) - sb_add_sb (out, &f->actual); - else - sb_add_sb (out, &f->def); - break; - } - } - } - else - { - sb_reset (&t); - src = sub_actual (src, in, &t, formal_hash, '\'', out, 0); - } - } - else if (ISFIRSTCHAR (in->ptr[src]) && (alternate || mri)) - { - sb_reset (&t); - src = sub_actual (src, in, &t, formal_hash, '\'', out, 1); - } - else if (ISCOMMENTCHAR (in->ptr[src]) - && src + 1 < in->len - && ISCOMMENTCHAR (in->ptr[src+1]) - && !inquote) - { - /* Two comment chars in a row cause the rest of the line to - be dropped. */ - while (src < in->len && in->ptr[src] != '\n') - src++; - } - else if (in->ptr[src] == '"' - || (mri && in->ptr[src] == '\'')) - { - inquote = !inquote; - sb_add_char (out, in->ptr[src++]); - } - else if (mri - && in->ptr[src] == '=' - && src + 1 < in->len - && in->ptr[src + 1] == '=') - { - hash_entry *ptr; - - sb_reset (&t); - src = get_token (src + 2, in, &t); - ptr = hash_lookup (formal_hash, &t); - if (ptr == NULL) - { - ERROR ((stderr, "MACRO formal argument %s does not exist.\n", - sb_name (&t))); - } - else - { - if (ptr->value.f->actual.len) - { - sb_add_string (out, "-1"); - } - else - { - sb_add_char (out, '0'); - } - } - } - else - { - sb_add_char (out, in->ptr[src++]); - } - } - - sb_kill (&t); -} - -static void -macro_expand (name, idx, in, m) - sb *name; - int idx; - sb *in; - macro_entry *m; -{ - sb t; - sb out; - hash_entry *ptr; - formal_entry *f; - int is_positional = 0; - int is_keyword = 0; - int narg = 0; - - sb_new (&t); - sb_new (&out); - - /* Reset any old value the actuals may have */ - for (f = m->formals; f; f = f->next) - sb_reset (&f->actual); - f = m->formals; - - if (mri) - { - /* The macro may be called with an optional qualifier, which may - be referred to in the macro body as \0. */ - if (idx < in->len && in->ptr[idx] == '.') - { - formal_entry *n; - - n = (formal_entry *) xmalloc (sizeof (formal_entry)); - sb_new (&n->name); - sb_new (&n->def); - sb_new (&n->actual); - n->index = -1; - - n->next = m->formals; - m->formals = n; - - idx = get_any_string (idx + 1, in, &n->actual, 1, 0); - } - } - - /* Peel off the actuals and store them away in the hash tables' actuals */ - while (!eol(idx, in)) - { - int scan; - idx = sb_skip_white (idx, in); - /* Look and see if it's a positional or keyword arg */ - scan = idx; - while (scan < in->len - && !ISSEP (in->ptr[scan]) - && (!alternate && in->ptr[scan] != '=')) - scan++; - if (scan < in->len && (!alternate) && in->ptr[scan] == '=') - { - is_keyword = 1; - if (is_positional) - { - ERROR ((stderr, "Can't mix positional and keyword arguments.\n")); - return; - } - /* This is a keyword arg, fetch the formal name and - then the actual stuff */ - sb_reset (&t); - idx = get_token (idx, in, &t); - if (in->ptr[idx] != '=') - ERROR ((stderr, "confused about formal params.\n")); - - /* Lookup the formal in the macro's list */ - ptr = hash_lookup (&m->formal_hash, &t); - if (!ptr) - { - ERROR ((stderr, "MACRO formal argument %s does not exist.\n", sb_name (&t))); - return; - } - else - { - /* Insert this value into the right place */ - sb_reset (&ptr->value.f->actual); - idx = get_any_string (idx + 1, in, &ptr->value.f->actual, 0, 0); - if (ptr->value.f->actual.len > 0) - ++narg; - } - } - else - { - /* This is a positional arg */ - is_positional = 1; - if (is_keyword) - { - ERROR ((stderr, "Can't mix positional and keyword arguments.\n")); - return; - } - if (!f) - { - formal_entry **pf; - int c; - - if (!mri) - { - ERROR ((stderr, "Too many positional arguments.\n")); - return; - } - f = (formal_entry *) xmalloc (sizeof (formal_entry)); - sb_new (&f->name); - sb_new (&f->def); - sb_new (&f->actual); - f->next = NULL; - - c = -1; - for (pf = &m->formals; *pf != NULL; pf = &(*pf)->next) - if ((*pf)->index >= c) - c = (*pf)->index + 1; - *pf = f; - f->index = c; - } - - sb_reset (&f->actual); - idx = get_any_string (idx, in, &f->actual, 1, 0); - if (f->actual.len > 0) - ++narg; - do - { - f = f->next; - } - while (f != NULL && f->index < 0); - } - - idx = sb_skip_comma (idx, in); - } - - if (mri) - { - char buffer[20]; - - sb_reset (&t); - sb_add_string (&t, "NARG"); - ptr = hash_lookup (&m->formal_hash, &t); - sb_reset (&ptr->value.f->actual); - sprintf (buffer, "%d", narg); - sb_add_string (&ptr->value.f->actual, buffer); - } - - macro_expand_body (name, &m->sub, &out, m->formals, &m->formal_hash); - - include_buf (name, &out, include_macro, include_next_index ()); - - if (mri) - { - formal_entry **pf; - - /* Discard any unnamed formal arguments. */ - pf = &m->formals; - while (*pf != NULL) - { - if ((*pf)->name.len != 0) - pf = &(*pf)->next; - else - { - sb_kill (&(*pf)->name); - sb_kill (&(*pf)->def); - sb_kill (&(*pf)->actual); - f = (*pf)->next; - free (*pf); - *pf = f; - } - } - } - - sb_kill (&t); - sb_kill (&out); - number++; + err = define_macro (idx, in, &label, get_line); + if (err != NULL) + ERROR ((stderr, "macro at line %d: %s\n", line - 1, err)); } static int @@ -3610,36 +2607,31 @@ macro_op (idx, in) int idx; sb *in; { - int res = 0; - /* The macro name must be the first thing on the line */ - if (idx < in->len) - { - sb name; - hash_entry *ptr; - sb_new (&name); - idx = get_token (idx, in, &name); + const char *err; + sb out; + sb name; - if (name.len) - { - /* Got a name, look it up */ + if (! macro_defined) + return 0; - ptr = hash_lookup (¯o_table, &name); + sb_terminate (in); + if (! check_macro (in->ptr + idx, &out, comment_char, &err)) + return 0; - if (ptr) - { - /* It's in the table, copy out the stuff and convert any macro args */ - macro_expand (&name, idx, in, ptr->value.m); - res = 1; - } - } - sb_kill (&name); - } + if (err != NULL) + ERROR ((stderr, "%s\n", err)); + sb_new (&name); + sb_add_string (&name, "macro expansion"); - return res; + include_buf (&name, &out, include_macro, include_next_index ()); + + sb_kill (&name); + sb_kill (&out); + + return 1; } - /* STRING HANDLING */ static int @@ -3810,7 +2802,7 @@ do_sdatab (idx, in) if (i) fprintf (outfile, "\t"); fprintf (outfile, ".byte\t"); - sb_print (&acc); + sb_print (outfile, &acc); fprintf (outfile, "\n"); } sb_kill (&acc); @@ -4233,6 +3225,7 @@ process_pseudo_op (idx, line, acc) { case K_ALTERNATE: alternate = 1; + macro_init (1, mri, exp_get_abs); return 1; case K_AELSE: do_aelse (); @@ -4543,7 +3536,6 @@ main (argc, argv) program_name = argv[0]; xmalloc_set_program_name (program_name); - hash_new_table (101, ¯o_table); hash_new_table (101, &keyword_hash_table); hash_new_table (101, &assign_hash_table); hash_new_table (101, &vars); @@ -4613,6 +3605,8 @@ main (argc, argv) process_init (); + macro_init (alternate, mri, exp_get_abs); + if (out_name) { outfile = fopen (out_name, "w"); if (!outfile) diff --git a/gas/input-scrub.c b/gas/input-scrub.c index bdfd91ca97..b495ae0640 100644 --- a/gas/input-scrub.c +++ b/gas/input-scrub.c @@ -1,29 +1,30 @@ /* input_scrub.c - Break up input buffers into whole numbers of lines. Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc. - + 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include /* Need this to make errno declaration right */ +#include /* Need this to make errno declaration right */ #include "as.h" #include "input-file.h" +#include "sb.h" /* * O/S independent module to supply buffers of sanitised source code - * to rest of assembler. We get sanitized input data of arbitrary length. + * to rest of assembler. We get sanitised input data of arbitrary length. * We break these buffers on line boundaries, recombine pieces that * were broken across buffers, and return a buffer of full lines to * the caller. @@ -52,22 +53,26 @@ #define BEFORE_SIZE (1) #define AFTER_SIZE (1) -static char * buffer_start; /*->1st char of full buffer area. */ -static char * partial_where; /*->after last full line in buffer. */ +static char *buffer_start; /*->1st char of full buffer area. */ +static char *partial_where; /*->after last full line in buffer. */ static int partial_size; /* >=0. Number of chars in partial line in buffer. */ -static char save_source [AFTER_SIZE]; +static char save_source[AFTER_SIZE]; /* Because we need AFTER_STRING just after last */ /* full line, it clobbers 1st part of partial */ /* line. So we preserve 1st part of partial */ /* line here. */ -static int buffer_length; /* What is the largest size buffer that */ +static unsigned int buffer_length; /* What is the largest size buffer that */ /* input_file_give_next_buffer() could */ /* return to us? */ -/* Saved information about the file that .include'd this one. When we hit EOF, - we automatically pop to that file. */ +/* The index into an sb structure we are reading from. -1 if none. */ +static int sb_index = -1; -static char *next_saved_file; +/* If we are reading from an sb structure, this is it. */ +static sb from_sb; + +/* The number of nested sb structures we have included. */ +static int macro_nest; /* We can have more than one source file open at once, though the info for all but the latest one are saved off in a struct input_save. These files remain @@ -80,140 +85,152 @@ static char *next_saved_file; source line numbers. Whenever we open a file we must fill in physical_input_file. So if it is NULL we have not opened any files yet. */ -char *physical_input_file; -char *logical_input_file; +static char *physical_input_file; +static char *logical_input_file; -typedef unsigned int line_numberT; /* 1-origin line number in a source file. */ +typedef unsigned int line_numberT; /* 1-origin line number in a source file. */ /* A line ends in '\n' or eof. */ -line_numberT physical_input_line; -line_numberT logical_input_line; +static line_numberT physical_input_line; +static int logical_input_line; /* Struct used to save the state of the input handler during include files */ -struct input_save { - char *buffer_start; - char *partial_where; - int partial_size; - char save_source [AFTER_SIZE]; - int buffer_length; - char *physical_input_file; - char *logical_input_file; - line_numberT physical_input_line; - line_numberT logical_input_line; - char *next_saved_file; /* Chain of input_saves */ - char *input_file_save; /* Saved state of input routines */ - char *saved_position; /* Caller's saved position in buf */ -}; +struct input_save + { + char *buffer_start; + char *partial_where; + int partial_size; + char save_source[AFTER_SIZE]; + unsigned int buffer_length; + char *physical_input_file; + char *logical_input_file; + line_numberT physical_input_line; + int logical_input_line; + int sb_index; + sb from_sb; + struct input_save *next_saved_file; /* Chain of input_saves */ + char *input_file_save; /* Saved state of input routines */ + char *saved_position; /* Caller's saved position in buf */ + }; -#if __STDC__ == 1 -static void as_1_char(unsigned int c, FILE *stream); -#else /* __STDC__ */ -static void as_1_char(); -#endif /* not __STDC__ */ +static struct input_save *input_scrub_push PARAMS ((char *saved_position)); +static char *input_scrub_pop PARAMS ((struct input_save *arg)); +static void as_1_char PARAMS ((unsigned int c, FILE * stream)); + +/* Saved information about the file that .include'd this one. When we hit EOF, + we automatically pop to that file. */ + +static struct input_save *next_saved_file; /* Push the state of input reading and scrubbing so that we can #include. The return value is a 'void *' (fudged for old compilers) to a save area, which can be restored by passing it to input_scrub_pop(). */ -char *input_scrub_push(saved_position) -char *saved_position; +static struct input_save * +input_scrub_push (saved_position) + char *saved_position; { - register struct input_save *saved; - - saved = (struct input_save *) xmalloc(sizeof *saved); - - saved->saved_position = saved_position; - saved->buffer_start = buffer_start; - saved->partial_where = partial_where; - saved->partial_size = partial_size; - saved->buffer_length = buffer_length; - saved->physical_input_file = physical_input_file; - saved->logical_input_file = logical_input_file; - saved->physical_input_line = physical_input_line; - saved->logical_input_line = logical_input_line; - memcpy(saved->save_source, save_source, sizeof(save_source)); - saved->next_saved_file = next_saved_file; - saved->input_file_save = input_file_push(); - - input_file_begin(); /* Reinitialize! */ - logical_input_line = 0; - logical_input_file = (char *)NULL; - - return((char *) saved); -} /* input_scrub_push() */ + register struct input_save *saved; -char * - input_scrub_pop (arg) -char *arg; + saved = (struct input_save *) xmalloc (sizeof *saved); + + saved->saved_position = saved_position; + saved->buffer_start = buffer_start; + saved->partial_where = partial_where; + saved->partial_size = partial_size; + saved->buffer_length = buffer_length; + saved->physical_input_file = physical_input_file; + saved->logical_input_file = logical_input_file; + saved->physical_input_line = physical_input_line; + saved->logical_input_line = logical_input_line; + saved->sb_index = sb_index; + saved->from_sb = from_sb; + memcpy (saved->save_source, save_source, sizeof (save_source)); + saved->next_saved_file = next_saved_file; + saved->input_file_save = input_file_push (); + + input_file_begin (); /* Reinitialize! */ + logical_input_line = -1; + logical_input_file = (char *) NULL; + buffer_length = input_file_buffer_size (); + + buffer_start = xmalloc ((BEFORE_SIZE + buffer_length + buffer_length + AFTER_SIZE)); + memcpy (buffer_start, BEFORE_STRING, (int) BEFORE_SIZE); + + return saved; +} /* input_scrub_push() */ + +static char * +input_scrub_pop (saved) + struct input_save *saved; { - register struct input_save *saved; - char *saved_position; - - input_scrub_end (); /* Finish off old buffer */ - - saved = (struct input_save *)arg; - - input_file_pop (saved->input_file_save); - saved_position = saved->saved_position; - buffer_start = saved->buffer_start; - buffer_length = saved->buffer_length; - physical_input_file = saved->physical_input_file; - logical_input_file = saved->logical_input_file; - physical_input_line = saved->physical_input_line; - logical_input_line = saved->logical_input_line; - partial_where = saved->partial_where; - partial_size = saved->partial_size; - next_saved_file = saved->next_saved_file; - memcpy(save_source, saved->save_source, sizeof (save_source)); - - free(arg); - return saved_position; + char *saved_position; + + input_scrub_end (); /* Finish off old buffer */ + + input_file_pop (saved->input_file_save); + saved_position = saved->saved_position; + buffer_start = saved->buffer_start; + buffer_length = saved->buffer_length; + physical_input_file = saved->physical_input_file; + logical_input_file = saved->logical_input_file; + physical_input_line = saved->physical_input_line; + logical_input_line = saved->logical_input_line; + sb_index = saved->sb_index; + from_sb = saved->from_sb; + partial_where = saved->partial_where; + partial_size = saved->partial_size; + next_saved_file = saved->next_saved_file; + memcpy (save_source, saved->save_source, sizeof (save_source)); + + free (saved); + return saved_position; } - + void - input_scrub_begin () +input_scrub_begin () { - know(strlen(BEFORE_STRING) == BEFORE_SIZE); - know(strlen(AFTER_STRING) == AFTER_SIZE || (AFTER_STRING[0] == '\0' && AFTER_SIZE == 1)); - - input_file_begin (); - - buffer_length = input_file_buffer_size (); - - buffer_start = xmalloc((long)(BEFORE_SIZE + buffer_length + buffer_length + AFTER_SIZE)); - memcpy(buffer_start, BEFORE_STRING, (int) BEFORE_SIZE); - - /* Line number things. */ - logical_input_line = 0; - logical_input_file = (char *)NULL; - physical_input_file = NULL; /* No file read yet. */ - next_saved_file = NULL; /* At EOF, don't pop to any other file */ - do_scrub_begin(); + know (strlen (BEFORE_STRING) == BEFORE_SIZE); + know (strlen (AFTER_STRING) == AFTER_SIZE || (AFTER_STRING[0] == '\0' && AFTER_SIZE == 1)); + + input_file_begin (); + + buffer_length = input_file_buffer_size (); + + buffer_start = xmalloc ((BEFORE_SIZE + buffer_length + buffer_length + AFTER_SIZE)); + memcpy (buffer_start, BEFORE_STRING, (int) BEFORE_SIZE); + + /* Line number things. */ + logical_input_line = -1; + logical_input_file = (char *) NULL; + physical_input_file = NULL; /* No file read yet. */ + next_saved_file = NULL; /* At EOF, don't pop to any other file */ + do_scrub_begin (); } void - input_scrub_end () +input_scrub_end () { - if (buffer_start) - { - free (buffer_start); - buffer_start = 0; - input_file_end (); - } + if (buffer_start) + { + free (buffer_start); + buffer_start = 0; + input_file_end (); + } } /* Start reading input from a new file. */ char * /* Return start of caller's part of buffer. */ - input_scrub_new_file (filename) -char * filename; +input_scrub_new_file (filename) + char *filename; { - input_file_open (filename, !flagseen['f']); - physical_input_file = filename[0] ? filename : "{standard input}"; - physical_input_line = 0; - - partial_size = 0; - return (buffer_start + BEFORE_SIZE); + input_file_open (filename, !flag_no_comments); + physical_input_file = filename[0] ? filename : "{standard input}"; + physical_input_line = 0; + + partial_size = 0; + return (buffer_start + BEFORE_SIZE); } @@ -222,94 +239,113 @@ char * filename; input_scrub_new_file. */ char * - input_scrub_include_file (filename, position) -char *filename; -char *position; +input_scrub_include_file (filename, position) + char *filename; + char *position; { - next_saved_file = input_scrub_push(position); - return input_scrub_new_file (filename); + next_saved_file = input_scrub_push (position); + return input_scrub_new_file (filename); +} + +/* Start getting input from an sb structure. This is used when + expanding a macro. */ + +void +input_scrub_include_sb (from, position) + sb *from; + char *position; +{ + if (macro_nest > max_macro_nest) + as_fatal ("macros nested too deeply"); + ++macro_nest; + + next_saved_file = input_scrub_push (position); + + sb_new (&from_sb); + /* Add the sentinel required by read.c. */ + sb_add_char (&from_sb, '\n'); + sb_add_sb (&from_sb, from); + sb_index = 1; + + /* These variables are reset by input_scrub_push. Restore them + since we are, after all, still at the same point in the file. */ + logical_input_line = next_saved_file->logical_input_line; + logical_input_file = next_saved_file->logical_input_file; } void - input_scrub_close () +input_scrub_close () { - input_file_close (); + input_file_close (); } + char * - input_scrub_next_buffer (bufp) -char **bufp; +input_scrub_next_buffer (bufp) + char **bufp; { - register char * limit; /*->just after last char of buffer. */ - - *bufp = buffer_start + BEFORE_SIZE; - -#ifdef DONTDEF - if(preprocess) { - if(save_buffer) { - *bufp = save_buffer; - save_buffer = 0; - } - limit = input_file_give_next_buffer(buffer_start+BEFORE_SIZE); - if (!limit) { - partial_where = 0; - if(partial_size) - as_warn("Partial line at end of file ignored"); - return partial_where; - } - - if(partial_size) - memcpy(partial_where, save_source, (int) AFTER_SIZE); - do_scrub(partial_where,partial_size,buffer_start+BEFORE_SIZE,limit-(buffer_start+BEFORE_SIZE),&out_string,&out_length); - limit=out_string + out_length; - for(p=limit;*--p!='\n';) - ; - p++; - if(p<=buffer_start+BEFORE_SIZE) - as_fatal("Source line too long. Please change file '%s' and re-make the assembler.", __FILE__); - - partial_where = p; - partial_size = limit-p; - memcpy(save_source, partial_where, (int) AFTER_SIZE); - memcpy(partial_where, AFTER_STRING, (int) AFTER_SIZE); - - save_buffer = *bufp; - *bufp = out_string; - - return partial_where; + register char *limit; /*->just after last char of buffer. */ + + if (sb_index >= 0) + { + if (sb_index >= from_sb.len) + { + sb_kill (&from_sb); + --macro_nest; + partial_where = NULL; + if (next_saved_file != NULL) + *bufp = input_scrub_pop (next_saved_file); + return partial_where; } - - /* We're not preprocessing. Do the right thing */ -#endif - if (partial_size) { - memcpy(buffer_start + BEFORE_SIZE, partial_where, (int) partial_size); - memcpy(buffer_start + BEFORE_SIZE, save_source, (int) AFTER_SIZE); + + partial_where = from_sb.ptr + from_sb.len; + partial_size = 0; + *bufp = from_sb.ptr + sb_index; + sb_index = from_sb.len; + return partial_where; + } + + *bufp = buffer_start + BEFORE_SIZE; + + if (partial_size) + { + memcpy (buffer_start + BEFORE_SIZE, partial_where, + (unsigned int) partial_size); + memcpy (buffer_start + BEFORE_SIZE, save_source, AFTER_SIZE); + } + limit = input_file_give_next_buffer (buffer_start + + BEFORE_SIZE + + partial_size); + if (limit) + { + register char *p; /* Find last newline. */ + + for (p = limit; *--p != '\n';);; + ++p; + if (p <= buffer_start + BEFORE_SIZE) + { + as_fatal ("Source line too long. Please change file %s then rebuild assembler.", __FILE__); } - limit = input_file_give_next_buffer (buffer_start + BEFORE_SIZE + partial_size); - if (limit) { - register char * p; /* Find last newline. */ - - for (p = limit; *--p != '\n';) ;; - ++p; - if (p <= buffer_start + BEFORE_SIZE) { - as_fatal("Source line too long. Please change file %s then rebuild assembler.", __FILE__); - } - partial_where = p; - partial_size = limit - p; - memcpy(save_source, partial_where, (int) AFTER_SIZE); - memcpy(partial_where, AFTER_STRING, (int) AFTER_SIZE); - } else { - partial_where = 0; - if (partial_size > 0) { - as_warn("Partial line at end of file ignored"); - } - /* If we should pop to another file at EOF, do it. */ - if (next_saved_file) { - *bufp = input_scrub_pop (next_saved_file); /* Pop state */ - /* partial_where is now correct to return, since we popped it. */ - } + partial_where = p; + partial_size = limit - p; + memcpy (save_source, partial_where, (int) AFTER_SIZE); + memcpy (partial_where, AFTER_STRING, (int) AFTER_SIZE); + } + else + { + partial_where = 0; + if (partial_size > 0) + { + as_warn ("Partial line at end of file ignored"); } - return(partial_where); -} /* input_scrub_next_buffer() */ + /* If we should pop to another file at EOF, do it. */ + if (next_saved_file) + { + *bufp = input_scrub_pop (next_saved_file); /* Pop state */ + /* partial_where is now correct to return, since we popped it. */ + } + } + return (partial_where); +} /* input_scrub_next_buffer() */ /* * The remaining part of this file deals with line numbers, error @@ -318,83 +354,84 @@ char **bufp; int - seen_at_least_1_file () /* TRUE if we opened any file. */ +seen_at_least_1_file () /* TRUE if we opened any file. */ { - return (physical_input_file != NULL); + return (physical_input_file != NULL); } void - bump_line_counters () +bump_line_counters () { - ++ physical_input_line; - /* ++ logical_input_line; FIXME-now remove this. */ + if (sb_index < 0) + { + ++physical_input_line; + if (logical_input_line >= 0) + ++logical_input_line; + } } /* * new_logical_line() * * Tells us what the new logical line number and file are. - * If the line_number is <0, we don't change the current logical line number. + * If the line_number is -1, we don't change the current logical line + * number. If it is -2, we decrement the logical line number (this is + * to support the .appfile pseudo-op inserted into the stream by + * do_scrub_next_char). * If the fname is NULL, we don't change the current logical file name. */ -void new_logical_line(fname, line_number) -char *fname; /* DON'T destroy it! We point to it! */ -int line_number; +void +new_logical_line (fname, line_number) + char *fname; /* DON'T destroy it! We point to it! */ + int line_number; { - if (fname) { - logical_input_file = fname; - } /* if we have a file name */ - - if (line_number >= 0) { - logical_input_line = line_number; - } /* if we have a line number */ -} /* new_logical_line() */ + if (fname) + { + logical_input_file = fname; + } /* if we have a file name */ + + if (line_number >= 0) + logical_input_line = line_number; + else if (line_number == -2 && logical_input_line > 0) + --logical_input_line; +} /* new_logical_line() */ /* * a s _ w h e r e () * - * Write a line to stderr locating where we are in reading - * input source files. - * As a sop to the debugger of AS, pretty-print the offending line. + * Return the current file name and line number. + * namep should be char * const *, but there are compilers which screw + * up declarations like that, and it's easier to avoid it. */ -void as_where() { - char *p; - line_numberT line; - - if (logical_input_file && (logical_input_line > 0)) { - p = logical_input_file; - line = logical_input_line; - } else { - p = physical_input_file; - line = physical_input_line; - } /* line number should match file name */ - - fprintf(stderr, "%s:%u: ", p, line); - -#ifdef DONTDEF - if (physical_input_file) { - if (input_file_is_open()) { /* we can still read lines from source */ - fprintf (stderr," @ physical line %ld., file \"%s\"", - (long) physical_input_line, physical_input_file); - fprintf (stderr," @ logical line %ld., file \"%s\"\n", - (long) logical_input_line, logical_input_file); - (void)putc(' ', stderr); - as_howmuch (stderr); - (void)putc('\n', stderr); - } else { - fprintf(stderr, " After reading source.\n"); - } /* input file is still open */ - } else { - fprintf(stderr, " Before reading source.\n"); - } /* we tried to read SOME source */ -#endif /* DONTDEF */ - - return; -} /* as_where() */ - - - +void +as_where (namep, linep) + char **namep; + unsigned int *linep; +{ + if (logical_input_file != NULL + && (linep == NULL || logical_input_line >= 0)) + { + *namep = logical_input_file; + if (linep != NULL) + *linep = logical_input_line; + } + else if (physical_input_file != NULL) + { + *namep = physical_input_file; + if (linep != NULL) + *linep = physical_input_line; + } + else + { + *namep = (char *) "*unknown*"; + if (linep != NULL) + *linep = 0; + } +} /* as_where() */ + + + /* * a s _ h o w m u c h () * @@ -403,46 +440,40 @@ void as_where() { * No free '\n' at end of line. */ void - as_howmuch (stream) -FILE * stream; /* Opened for write please. */ +as_howmuch (stream) + FILE *stream; /* Opened for write please. */ { - register char * p; /* Scan input line. */ - /* register char c; JF unused */ - - for (p = input_line_pointer - 1; * p != '\n'; --p) - { - } - ++ p; /* p->1st char of line. */ - for (; p <= input_line_pointer; p++) - { - /* Assume ASCII. EBCDIC & other micro-computer char sets ignored. */ - /* c = *p & 0xFF; JF unused */ - as_1_char(*p, stream); - } + register char *p; /* Scan input line. */ + /* register char c; JF unused */ + + for (p = input_line_pointer - 1; *p != '\n'; --p) + { + } + ++p; /* p->1st char of line. */ + for (; p <= input_line_pointer; p++) + { + /* Assume ASCII. EBCDIC & other micro-computer char sets ignored. */ + /* c = *p & 0xFF; JF unused */ + as_1_char ((unsigned char) *p, stream); + } } -static void as_1_char (c,stream) -unsigned int c; -FILE *stream; +static void +as_1_char (c, stream) + unsigned int c; + FILE *stream; { - if (c > 127) - { - (void)putc('%', stream); - c -= 128; - } - if (c < 32) - { - (void)putc('^', stream); - c += '@'; - } - (void)putc(c, stream); + if (c > 127) + { + (void) putc ('%', stream); + c -= 128; + } + if (c < 32) + { + (void) putc ('^', stream); + c += '@'; + } + (void) putc (c, stream); } -/* - * Local Variables: - * comment-column: 0 - * fill-column: 131 - * End: - */ - /* end of input_scrub.c */ diff --git a/gas/macro.h b/gas/macro.h new file mode 100644 index 0000000000..7a4c4ebbf3 --- /dev/null +++ b/gas/macro.h @@ -0,0 +1,46 @@ +/* macro.h - header file for macro support for gas and gasp + Copyright (C) 1994, 1995 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. */ + +#ifndef MACRO_H + +#define MACRO_H + +#include "ansidecl.h" +#include "sb.h" + +/* Whether any macros have been defined. */ + +extern int macro_defined; + +extern int buffer_and_nest + PARAMS ((const char *, const char *, sb *, int (*) PARAMS ((sb *)))); +extern void macro_init + PARAMS ((int alternate, int mri, + int (*) PARAMS ((const char *, int, sb *, int *)))); +extern const char *define_macro + PARAMS ((int idx, sb *in, sb *label, int (*get_line) PARAMS ((sb *)))); +extern int check_macro PARAMS ((const char *, sb *, int, const char **)); +extern const char *expand_irp + PARAMS ((int, int, sb *, sb *, int (*) PARAMS ((sb *)), int)); + +#endif diff --git a/gas/read.c b/gas/read.c index 7a9cd3e494..a117b75736 100644 --- a/gas/read.c +++ b/gas/read.c @@ -42,6 +42,8 @@ the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307 #include "as.h" #include "subsegs.h" +#include "sb.h" +#include "macro.h" #include "libiberty.h" #include "obstack.h" #include "listing.h" @@ -176,7 +178,7 @@ addressT abs_section_offset; /* If this line had an MRI style label, it is stored in this variable. This is used by some of the MRI pseudo-ops. */ -symbolS *mri_line_label; +symbolS *line_label; /* This global variable is used to support MRI common sections. We translate such sections into a common symbol. This variable is @@ -197,6 +199,7 @@ int is_it_end_of_statement PARAMS ((void)); static segT get_segmented_expression PARAMS ((expressionS *expP)); static segT get_known_segmented_expression PARAMS ((expressionS * expP)); static void pobegin PARAMS ((void)); +static int get_line_sb PARAMS ((sb *)); void @@ -275,6 +278,7 @@ static const pseudo_typeS potable[] = /* endef */ {"equ", s_set, 0}, /* err */ + {"exitm", s_mexit, 0}, /* extend */ {"extern", s_ignore, 0}, /* We treat all undef as ext */ {"appfile", s_app_file, 1}, @@ -288,6 +292,7 @@ static const pseudo_typeS potable[] = {"globl", s_globl, 0}, {"hword", cons, 2}, {"if", s_if, (int) O_ne}, + {"ifc", s_ifc, 0}, {"ifdef", s_ifdef, 0}, {"ifeq", s_if, (int) O_eq}, {"ifeqs", s_ifeqs, 0}, @@ -295,18 +300,23 @@ static const pseudo_typeS potable[] = {"ifgt", s_if, (int) O_gt}, {"ifle", s_if, (int) O_le}, {"iflt", s_if, (int) O_lt}, + {"ifnc", s_ifc, 1}, {"ifndef", s_ifdef, 1}, {"ifne", s_if, (int) O_ne}, {"ifnes", s_ifeqs, 1}, {"ifnotdef", s_ifdef, 1}, {"include", s_include, 0}, {"int", cons, 4}, + {"irp", s_irp, 0}, + {"irpc", s_irp, 1}, {"lcomm", s_lcomm, 0}, {"lflags", listing_flags, 0}, /* Listing flags */ {"list", listing_list, 1}, /* Turn listing on */ {"llen", listing_psize, 1}, {"long", cons, 4}, {"lsym", s_lsym, 0}, + {"macro", s_macro, 0}, + {"mexit", s_mexit, 0}, {"noformat", s_ignore, 0}, {"nolist", listing_list, 0}, /* Turn listing off */ {"nopage", listing_nopage, 0}, @@ -319,6 +329,7 @@ static const pseudo_typeS potable[] = {"psize", listing_psize, 0}, /* set paper size */ /* print */ {"quad", cons, 8}, + {"rept", s_rept, 0}, {"sbttl", listing_title, 1}, /* Subtitle of listing */ /* scl */ /* sect */ @@ -457,43 +468,47 @@ read_a_source_file (name) if (input_line_pointer[-1] == '\n') bump_line_counters (); + line_label = NULL; + if (flag_mri #ifdef LABELS_WITHOUT_COLONS || 1 #endif ) { - mri_line_label = NULL; - /* Text at the start of a line must be a label, we run down and stick a colon in. */ if (is_name_beginner (*input_line_pointer)) { char *line_start = input_line_pointer; - char c = get_symbol_end (); + char c; - if (! ignore_input ()) + HANDLE_CONDITIONAL_ASSEMBLY (); + + c = get_symbol_end (); + + /* In MRI mode, the EQU pseudoop must be + handled specially. */ + if (flag_mri) { - /* In MRI mode, the EQU pseudoop must be - handled specially. */ - if (flag_mri) - { - if (((strncasecmp (input_line_pointer + 1, - "EQU", 3) == 0) - || (strncasecmp (input_line_pointer + 1, - "SET", 3) == 0)) - && (input_line_pointer[4] == ' ' - || input_line_pointer[4] == '\t')) - { - input_line_pointer += 4; - equals (line_start); - continue; - } - } + char *rest = input_line_pointer + 1; - mri_line_label = colon (line_start); + if (*rest == ':') + ++rest; + if (*rest == ' ' || *rest == '\t') + ++rest; + if ((strncasecmp (rest, "EQU", 3) == 0 + || strncasecmp (rest, "SET", 3) == 0) + && (rest[3] == ' ' || rest[3] == '\t')) + { + input_line_pointer = rest + 3; + equals (line_start); + continue; + } } + line_label = colon (line_start); + *input_line_pointer = c; if (c == ':') input_line_pointer++; @@ -544,7 +559,27 @@ read_a_source_file (name) */ if (TC_START_LABEL(c, input_line_pointer)) { - colon (s); /* user-defined label */ + if (flag_mri) + { + char *rest = input_line_pointer + 1; + + /* In MRI mode, \tsym: set 0 is permitted. */ + + if (*rest == ':') + ++rest; + if (*rest == ' ' || *rest == '\t') + ++rest; + if ((strncasecmp (rest, "EQU", 3) == 0 + || strncasecmp (rest, "SET", 3) == 0) + && (rest[3] == ' ' || rest[3] == '\t')) + { + input_line_pointer = rest + 3; + equals (s); + continue; + } + } + + line_label = colon (s); /* user-defined label */ *input_line_pointer++ = ':'; /* Put ':' back for error messages' sake. */ /* Input_line_pointer->after ':'. */ SKIP_WHITESPACE (); @@ -591,7 +626,8 @@ read_a_source_file (name) pop = NULL; } - if (pop != NULL || *s == '.') + if (pop != NULL + || (! flag_mri && *s == '.')) { /* * PSEUDO - OP. @@ -684,6 +720,25 @@ read_a_source_file (name) } #endif + if (macro_defined) + { + sb out; + const char *err; + + if (check_macro (s, &out, '\0', &err)) + { + if (err != NULL) + as_bad (err); + *input_line_pointer++ = c; + input_scrub_include_sb (&out, + input_line_pointer); + sb_kill (&out); + buffer_limit = + input_scrub_next_buffer (&input_line_pointer); + continue; + } + } + md_assemble (s); /* Assemble 1 instruction. */ *input_line_pointer++ = c; @@ -1076,12 +1131,12 @@ s_mri_common (small) c = *input_line_pointer; *input_line_pointer = '\0'; - if (mri_line_label != NULL) + if (line_label != NULL) { - alc = (char *) xmalloc (strlen (S_GET_NAME (mri_line_label)) + alc = (char *) xmalloc (strlen (S_GET_NAME (line_label)) + (input_line_pointer - name) + 1); - sprintf (alc, "%s%s", name, S_GET_NAME (mri_line_label)); + sprintf (alc, "%s%s", name, S_GET_NAME (line_label)); name = alc; } } @@ -1119,13 +1174,13 @@ s_mri_common (small) S_SET_ALIGN (sym, align); #endif - if (mri_line_label != NULL) + if (line_label != NULL) { - mri_line_label->sy_value.X_op = O_symbol; - mri_line_label->sy_value.X_add_symbol = sym; - mri_line_label->sy_value.X_add_number = S_GET_VALUE (sym); - mri_line_label->sy_frag = &zero_address_frag; - S_SET_SEGMENT (mri_line_label, expr_section); + line_label->sy_value.X_op = O_symbol; + line_label->sy_value.X_add_symbol = sym; + line_label->sy_value.X_add_number = S_GET_VALUE (sym); + line_label->sy_frag = &zero_address_frag; + S_SET_SEGMENT (line_label, expr_section); } /* FIXME: We just ignore the small argument, which distinguishes @@ -1345,6 +1400,37 @@ s_globl (ignore) demand_empty_rest_of_line (); } +/* Handle the MRI IRP and IRPC pseudo-ops. */ + +void +s_irp (irpc) + int irpc; +{ + char *file; + unsigned int line; + sb s; + const char *err; + sb out; + + as_where (&file, &line); + + sb_new (&s); + while (! is_end_of_line[(unsigned char) *input_line_pointer]) + sb_add_char (&s, *input_line_pointer++); + + sb_new (&out); + + err = expand_irp (irpc, 0, &s, &out, get_line_sb, '\0'); + if (err != NULL) + as_bad_where (file, line, "%s", err); + + sb_kill (&s); + + input_scrub_include_sb (&out, input_line_pointer); + sb_kill (&out); + buffer_limit = input_scrub_next_buffer (&input_line_pointer); +} + void s_lcomm (needs_align) /* 1 if this was a ".bss" directive, which may require a 3rd argument @@ -1569,6 +1655,84 @@ s_lsym (ignore) demand_empty_rest_of_line (); } /* s_lsym() */ +/* Read a line into an sb. */ + +static int +get_line_sb (line) + sb *line; +{ + if (input_line_pointer >= buffer_limit) + { + buffer_limit = input_scrub_next_buffer (&input_line_pointer); + if (buffer_limit == 0) + return 0; + } + + while (! is_end_of_line[(unsigned char) *input_line_pointer]) + sb_add_char (line, *input_line_pointer++); + while (is_end_of_line[(unsigned char) *input_line_pointer]) + { + if (*input_line_pointer == '\n') + { + bump_line_counters (); + LISTING_NEWLINE (); + } + ++input_line_pointer; + } + return 1; +} + +/* Define a macro. This is an interface to macro.c, which is shared + between gas and gasp. */ + +void +s_macro (ignore) + int ignore; +{ + char *file; + unsigned int line; + sb s; + sb label; + const char *err; + + as_where (&file, &line); + + sb_new (&s); + while (! is_end_of_line[(unsigned char) *input_line_pointer]) + sb_add_char (&s, *input_line_pointer++); + + sb_new (&label); + if (line_label != NULL) + sb_add_string (&label, S_GET_NAME (line_label)); + + demand_empty_rest_of_line (); + + err = define_macro (0, &s, &label, get_line_sb); + if (err != NULL) + as_bad_where (file, line, "%s", err); + else + { + if (line_label != NULL) + { + S_SET_SEGMENT (line_label, undefined_section); + S_SET_VALUE (line_label, 0); + line_label->sy_frag = &zero_address_frag; + } + } + + sb_kill (&s); +} + +/* Handle the .mexit pseudo-op, which immediately exits a macro + expansion. */ + +void +s_mexit (ignore) + int ignore; +{ + buffer_limit = input_scrub_next_buffer (&input_line_pointer); +} + /* Handle changing the location counter. */ static void @@ -1735,6 +1899,36 @@ s_mri_sect (type) demand_empty_rest_of_line (); } +/* Handle the .rept pseudo-op. */ + +void +s_rept (ignore) + int ignore; +{ + int count; + sb one; + sb many; + + count = get_absolute_expression (); + + sb_new (&one); + if (! buffer_and_nest ("REPT", "ENDR", &one, get_line_sb)) + { + as_bad ("rept without endr"); + return; + } + + sb_new (&many); + while (count-- > 0) + sb_add_sb (&many, &one); + + sb_kill (&one); + + input_scrub_include_sb (&many, input_line_pointer); + sb_kill (&many); + buffer_limit = input_scrub_next_buffer (&input_line_pointer); +} + void s_set (ignore) int ignore; diff --git a/gas/sb.c b/gas/sb.c new file mode 100644 index 0000000000..b48b07616e --- /dev/null +++ b/gas/sb.c @@ -0,0 +1,283 @@ +/* sb.c - string buffer manipulation routines + Copyright (C) 1994, 1995 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" +#include +#include "sb.h" + +/* These routines are about manipulating strings. + + They are managed in things called `sb's which is an abbreviation + for string buffers. An sb has to be created, things can be glued + on to it, and at the end of it's life it should be freed. The + contents should never be pointed at whilst it is still growing, + since it could be moved at any time + + eg: + sb_new (&foo); + sb_grow... (&foo,...); + use foo->ptr[*]; + sb_kill (&foo); + +*/ + +#define dsize 5 + +static void sb_check PARAMS ((sb *, int)); + +/* Statistics of sb structures. */ + +int string_count[sb_max_power_two]; + +/* Free list of sb structures. */ + +static sb_list_vector free_list; + +/* initializes an sb. */ + +void +sb_build (ptr, size) + sb *ptr; + int size; +{ + /* see if we can find one to allocate */ + sb_element *e; + + if (size > sb_max_power_two) + abort (); + + e = free_list.size[size]; + if (!e) + { + /* nothing there, allocate one and stick into the free list */ + e = (sb_element *) xmalloc (sizeof (sb_element) + (1 << size)); + e->next = free_list.size[size]; + e->size = 1 << size; + free_list.size[size] = e; + string_count[size]++; + } + + /* remove from free list */ + + free_list.size[size] = e->next; + + /* copy into callers world */ + ptr->ptr = e->data; + ptr->pot = size; + ptr->len = 0; + ptr->item = e; +} + + +void +sb_new (ptr) + sb *ptr; +{ + sb_build (ptr, dsize); +} + +/* deallocate the sb at ptr */ + +void +sb_kill (ptr) + sb *ptr; +{ + /* return item to free list */ + ptr->item->next = free_list.size[ptr->pot]; + free_list.size[ptr->pot] = ptr->item; +} + +/* add the sb at s to the end of the sb at ptr */ + +void +sb_add_sb (ptr, s) + sb *ptr; + sb *s; +{ + sb_check (ptr, s->len); + memcpy (ptr->ptr + ptr->len, s->ptr, s->len); + ptr->len += s->len; +} + +/* make sure that the sb at ptr has room for another len characters, + and grow it if it doesn't. */ + +static void +sb_check (ptr, len) + sb *ptr; + int len; +{ + if (ptr->len + len >= 1 << ptr->pot) + { + sb tmp; + int pot = ptr->pot; + while (ptr->len + len >= 1 << pot) + pot++; + sb_build (&tmp, pot); + sb_add_sb (&tmp, ptr); + sb_kill (ptr); + *ptr = tmp; + } +} + +/* make the sb at ptr point back to the beginning. */ + +void +sb_reset (ptr) + sb *ptr; +{ + ptr->len = 0; +} + +/* add character c to the end of the sb at ptr. */ + +void +sb_add_char (ptr, c) + sb *ptr; + int c; +{ + sb_check (ptr, 1); + ptr->ptr[ptr->len++] = c; +} + +/* add null terminated string s to the end of sb at ptr. */ + +void +sb_add_string (ptr, s) + sb *ptr; + const char *s; +{ + int len = strlen (s); + sb_check (ptr, len); + memcpy (ptr->ptr + ptr->len, s, len); + ptr->len += len; +} + +/* add string at s of length len to sb at ptr */ + +void +sb_add_buffer (ptr, s, len) + sb *ptr; + const char *s; + int len; +{ + sb_check (ptr, len); + memcpy (ptr->ptr + ptr->len, s, len); + ptr->len += len; +} + +/* print the sb at ptr to the output file */ + +void +sb_print (outfile, ptr) + FILE *outfile; + sb *ptr; +{ + int i; + int nc = 0; + + for (i = 0; i < ptr->len; i++) + { + if (nc) + { + fprintf (outfile, ","); + } + fprintf (outfile, "%d", ptr->ptr[i]); + nc = 1; + } +} + +void +sb_print_at (outfile, idx, ptr) + FILE *outfile; + int idx; + sb *ptr; +{ + int i; + for (i = idx; i < ptr->len; i++) + putc (ptr->ptr[i], outfile); +} + +/* put a null at the end of the sb at in and return the start of the + string, so that it can be used as an arg to printf %s. */ + +char * +sb_name (in) + sb *in; +{ + /* stick a null on the end of the string */ + sb_add_char (in, 0); + return in->ptr; +} + +/* like sb_name, but don't include the null byte in the string. */ + +char * +sb_terminate (in) + sb *in; +{ + sb_add_char (in, 0); + --in->len; + return in->ptr; +} + +/* start at the index idx into the string in sb at ptr and skip + whitespace. return the index of the first non whitespace character */ + +int +sb_skip_white (idx, ptr) + int idx; + sb *ptr; +{ + while (idx < ptr->len + && (ptr->ptr[idx] == ' ' + || ptr->ptr[idx] == '\t')) + idx++; + return idx; +} + +/* start at the index idx into the sb at ptr. skips whitespace, + a comma and any following whitespace. returnes the index of the + next character. */ + +int +sb_skip_comma (idx, ptr) + int idx; + sb *ptr; +{ + while (idx < ptr->len + && (ptr->ptr[idx] == ' ' + || ptr->ptr[idx] == '\t')) + idx++; + + if (idx < ptr->len + && ptr->ptr[idx] == ',') + idx++; + + while (idx < ptr->len + && (ptr->ptr[idx] == ' ' + || ptr->ptr[idx] == '\t')) + idx++; + + return idx; +}