* 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.
listing.c
listing.h
literal.c
+macro.c
+macro.h
messages.c
mpw-config.in
mpw-make.in
output-file.h
read.c
read.h
+sb.c
+sb.h
stabs.c
struc-symbol.h
subsegs.c
+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
HEADERS = $(LINKED_HEADERS) $(REAL_HEADERS)
+TE_OBJS=
+
# @target_frag@
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)
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.
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 =
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
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
-*- 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.
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.
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.
#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;
-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\
/* -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. */
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)
flag_keep_locals = 1;
break;
+ case 'M':
+ flag_mri = 1;
+ break;
+
case 'R':
flag_readonly_data_in_text = 1;
break;
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);
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 */
/* 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 '.' */
/* 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));
{ "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 },
++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
struct m68k_op rop;
unsigned long mask;
- if (mri_line_label == NULL)
+ if (line_label == NULL)
{
as_bad ("missing label");
ignore_rest_of_line ();
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 ();
}
#include "ansidecl.h"
#include "libiberty.h"
+#include "sb.h"
+#include "macro.h"
char *program_version = "1.2";
/* 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<<pot */
- struct le *item;
- }
-sb;
-
-/* Structure of the free list object of an sb */
-typedef struct le
- {
- struct le *next;
- int size;
- char data[1];
- }
-sb_element;
-
-/* The free list */
-typedef struct
- {
- sb_element *size[max_power_two];
- } sb_list_vector;
-
-sb_list_vector free_list;
-
-int string_count[max_power_two];
-
/* the attributes of each character are stored as a bit pattern
chartype, which gives us quick tests. */
struct include_stack *sp;
#define isp (sp - include_stack)
-#define dsize 5
-
-
-
/* Include file list */
typedef struct include_path
static void quit PARAMS ((void));
-static void sb_build PARAMS ((sb *, int));
-static void sb_new PARAMS ((sb *));
-static void sb_kill PARAMS ((sb *));
-static void sb_add_sb PARAMS ((sb *, sb *));
-static void sb_check PARAMS ((sb *, int));
-static void sb_reset PARAMS ((sb *));
-static void sb_add_char PARAMS ((sb *, int));
-static void sb_add_string PARAMS ((sb *, const char *));
-static void sb_add_buffer PARAMS ((sb *, const char *, int));
-static void sb_print PARAMS ((sb *));
-static void sb_print_at PARAMS ((int, sb *));
-static char *sb_name PARAMS ((sb *));
-static int sb_skip_white PARAMS ((int, sb *));
-static int sb_skip_comma PARAMS ((int, sb *));
static void hash_new_table PARAMS ((int, hash_table *));
static int hash PARAMS ((sb *));
static hash_entry *hash_create PARAMS ((hash_table *, sb *));
static void do_if PARAMS ((int, sb *, int));
static int get_mri_string PARAMS ((int, sb *, sb *, int));
static void do_ifc PARAMS ((int, sb *, int));
-static void buffer_and_nest PARAMS ((const char *, const char *, sb *));
static void do_aendr PARAMS ((void));
static void do_awhile PARAMS ((int, sb *));
static void do_aendw PARAMS ((void));
static void do_arepeat PARAMS ((int, sb *));
static void do_endm PARAMS ((void));
static void do_irp PARAMS ((int, sb *, int));
-static int do_formals PARAMS ((macro_entry *, int, sb *));
static void do_local PARAMS ((int, sb *));
static void do_macro PARAMS ((int, sb *));
-static int get_token PARAMS ((int, sb *, sb *));
-static int get_apost_token PARAMS ((int, sb *, sb *, int));
-static int sub_actual
- PARAMS ((int, sb *, sb *, hash_table *, int, sb *, int));
-static void macro_expand_body
- PARAMS ((sb *, sb *, sb *, formal_entry *, hash_table *));
-static void macro_expand PARAMS ((sb *, int, sb *, macro_entry *));
static int macro_op PARAMS ((int, sb *));
static int getstring PARAMS ((int, sb *, sb *));
static void do_sdata PARAMS ((int, sb *, int));
if (stats)
{
int i;
- for (i = 0; i < max_power_two; i++)
+ for (i = 0; i < sb_max_power_two; i++)
{
fprintf (stderr, "strings size %8d : %d\n", 1<<i, string_count[i]);
}
exit (exitcode);
}
-
-/* this program is 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);
-
-*/
-
-/* 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. */
}
}
sb_kill (&acc);
- sb_print_at (idx, in);
+ sb_print_at (outfile, idx, in);
fprintf (outfile, "\n");
}
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 ()
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
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
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 <name>
- 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
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;
-
- 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;
-}
+ const char *err;
+ int line = linecount ();
-/* 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;
+ err = define_macro (idx, in, &label, get_line);
+ if (err != NULL)
+ ERROR ((stderr, "macro at line %d: %s\n", line - 1, err));
}
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;
+macro_op (idx, in)
int idx;
sb *in;
- macro_entry *m;
{
- sb t;
+ const char *err;
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);
- }
+ sb name;
- idx = sb_skip_comma (idx, in);
- }
+ if (! macro_defined)
+ return 0;
- 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);
- }
+ sb_terminate (in);
+ if (! check_macro (in->ptr + idx, &out, comment_char, &err))
+ return 0;
- macro_expand_body (name, &m->sub, &out, m->formals, &m->formal_hash);
+ if (err != NULL)
+ ERROR ((stderr, "%s\n", err));
- include_buf (name, &out, include_macro, include_next_index ());
+ sb_new (&name);
+ sb_add_string (&name, "macro expansion");
- if (mri)
- {
- formal_entry **pf;
+ include_buf (&name, &out, include_macro, include_next_index ());
- /* 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 (&name);
sb_kill (&out);
- number++;
-}
-
-static int
-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);
- if (name.len)
- {
- /* Got a name, look it up */
-
- ptr = hash_lookup (¯o_table, &name);
-
- 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);
- }
-
-
- return res;
+ return 1;
}
-
/* STRING HANDLING */
static int
if (i)
fprintf (outfile, "\t");
fprintf (outfile, ".byte\t");
- sb_print (&acc);
+ sb_print (outfile, &acc);
fprintf (outfile, "\n");
}
sb_kill (&acc);
{
case K_ALTERNATE:
alternate = 1;
+ macro_init (1, mri, exp_get_abs);
return 1;
case K_AELSE:
do_aelse ();
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);
process_init ();
+ macro_init (alternate, mri, exp_get_abs);
+
if (out_name) {
outfile = fopen (out_name, "w");
if (!outfile)
/* 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.
#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;
+
+/* If we are reading from an sb structure, this is it. */
+static sb from_sb;
-static char *next_saved_file;
+/* 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
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 */
-};
-
-#if __STDC__ == 1
-static void as_1_char(unsigned int c, FILE *stream);
-#else /* __STDC__ */
-static void as_1_char();
-#endif /* not __STDC__ */
+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 */
+ };
+
+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() */
-
-char *
- input_scrub_pop (arg)
-char *arg;
+ 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;
+ 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;
}
-
\f
+
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);
}
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_close ()
+input_scrub_include_sb (from, position)
+ sb *from;
+ char *position;
{
- input_file_close ();
+ 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_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__);
+ }
+ 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");
}
- 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. */
- }
+ /* 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() */
+ }
+ return (partial_where);
+} /* input_scrub_next_buffer() */
\f
/*
* The remaining part of this file deals with line numbers, error
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;
+ }
}
\f
/*
* 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() */
\f
/*
* 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() */
+\f
-\f
/*
* a s _ h o w m u c h ()
*
* 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 */
--- /dev/null
+/* 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
#include "as.h"
#include "subsegs.h"
+#include "sb.h"
+#include "macro.h"
#include "libiberty.h"
#include "obstack.h"
#include "listing.h"
/* 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
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 *));
\f
void
/* 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},
{"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},
{"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},
{"psize", listing_psize, 0}, /* set paper size */
/* print */
{"quad", cons, 8},
+ {"rept", s_rept, 0},
{"sbttl", listing_title, 1}, /* Subtitle of listing */
/* scl */
/* sect */
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;
+
+ HANDLE_CONDITIONAL_ASSEMBLY ();
- if (! ignore_input ())
+ 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)
+ char *rest = input_line_pointer + 1;
+
+ if (*rest == ':')
+ ++rest;
+ if (*rest == ' ' || *rest == '\t')
+ ++rest;
+ if ((strncasecmp (rest, "EQU", 3) == 0
+ || strncasecmp (rest, "SET", 3) == 0)
+ && (rest[3] == ' ' || rest[3] == '\t'))
{
- 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;
- }
+ input_line_pointer = rest + 3;
+ equals (line_start);
+ continue;
}
-
- mri_line_label = colon (line_start);
}
+ line_label = colon (line_start);
+
*input_line_pointer = c;
if (c == ':')
input_line_pointer++;
*/
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 ();
pop = NULL;
}
- if (pop != NULL || *s == '.')
+ if (pop != NULL
+ || (! flag_mri && *s == '.'))
{
/*
* PSEUDO - OP.
}
#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;
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;
}
}
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
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
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
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;
--- /dev/null
+/* 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;
+}