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.
This commit is contained in:
Ian Lance Taylor 1995-08-21 18:35:11 +00:00
parent 7172e2266f
commit 7e047ac2c1
12 changed files with 1102 additions and 1398 deletions

View File

@ -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

View File

@ -1,3 +1,67 @@
Mon Aug 21 13:57:20 1995 Ian Lance Taylor <ian@cygnus.com>
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 <meissner@cygnus.com>
* config/tc-ppc.c (md_assemble): Allow @HA, @L, and @H suffixes on

View File

@ -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

View File

@ -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.

View File

@ -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 */

View File

@ -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 '.' */

View File

@ -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 ();
}

1106
gas/gasp.c

File diff suppressed because it is too large Load Diff

View File

@ -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 <errno.h> /* Need this to make errno declaration right */
#include <errno.h> /* 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 */

46
gas/macro.h Normal file
View File

@ -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

View File

@ -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;

283
gas/sb.c Normal file
View File

@ -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 <stdio.h>
#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;
}