/* gasp.c - Gnu assembler preprocessor main program.
- Copyright (C) 1994 Free Software Foundation, Inc.
+ Copyright (C) 1994, 95, 1996 Free Software Foundation, Inc.
Written by Steve and Judy Chamberlain of Cygnus Support,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with GASP; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+ along with GASP; see the file COPYING. If not, write to the Free
+ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA. */
/*
suitable for gas to consume.
- gasp [-c] [-o <outfile>] <infile>*
+ gasp [-sdhau] [-c char] [-o <outfile>] <infile>*
+
+ -s copy source to output
+ -c <char> comments are started with <char> instead of !
+ -u allow unreasonable stuff
+ -p print line numbers
+ -d print debugging stats
+ -s semi colons start comments
+ -a use alternate syntax
+ Pseudo ops can start with or without a .
+ Labels have to be in first column.
+ -I specify include dir
+ Macro arg parameters subsituted by name, don't need the &.
+ String can start with ' too.
+ Strings can be surrounded by <..>
+ A %<exp> in a string evaluates the expression
+ Literal char in a string with !
- -c copy source to output
*/
+#include "config.h"
#include <stdio.h>
+#include <string.h>
+#include <getopt.h>
+#include <ctype.h>
+
+#ifdef HAVE_STDLIB_H
#include <stdlib.h>
+#endif
+#ifdef NEED_MALLOC_DECLARATION
extern char *malloc ();
+#endif
+
+#include "ansidecl.h"
+#include "libiberty.h"
+#include "sb.h"
+#include "macro.h"
+
+char *program_version = "1.2";
#define MAX_INCLUDES 30 /* Maximum include depth */
#define MAX_REASONABLE 1000 /* Maximum number of expansions */
int unreasonable; /* -u on command line */
-int stats; /* -s on command line */
+int stats; /* -d on command line */
int print_line_number; /* -p flag on command line */
int copysource; /* -c flag on command line */
int warnings; /* Number of WARNINGs generated so far. */
int errors; /* Number of ERRORs generated so far. */
int fatals; /* Number of fatal ERRORs generated so far (either 0 or 1). */
-
-
-
+int alternate = 0; /* -a on command line */
+int mri = 0; /* -M on command line */
+char comment_char = '!';
int radix = 10; /* Default radix */
int had_end; /* Seen .END */
/* The output stream */
FILE *outfile;
-
-/* Forward declarations. */
-static int condass_lookup_name();
-static int condass_on();
-static int get();
-static int get_and_process();
-static int get_token();
-static int getstring();
-static int include_next_index();
-static int macro_op();
-static int linecount();
-static int process_pseudo_op();
-static void include_pop();
-static void include_print_where_line();
-/* 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. */
#define NEXTBIT 2
#define SEPBIT 4
#define WHITEBIT 8
+#define COMMENTBIT 16
+#define BASEBIT 32
+#define ISCOMMENTCHAR(x) (chartype[(unsigned)(x)] & COMMENTBIT)
#define ISFIRSTCHAR(x) (chartype[(unsigned)(x)] & FIRSTBIT)
#define ISNEXTCHAR(x) (chartype[(unsigned)(x)] & NEXTBIT)
#define ISSEP(x) (chartype[(unsigned)(x)] & SEPBIT)
#define ISWHITE(x) (chartype[(unsigned)(x)] & WHITEBIT)
-
+#define ISBASE(x) (chartype[(unsigned)(x)] & BASEBIT)
static char chartype[256];
struct include_stack *sp;
#define isp (sp - include_stack)
-#define dsize 5
-
-
-void include_print_where_line ();
-
+/* Include file list */
+
+typedef struct include_path
+{
+ struct include_path *next;
+ sb path;
+} include_path;
+
+include_path *paths_head;
+include_path *paths_tail;
+
+
+static void quit PARAMS ((void));
+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 hash_add_to_string_table PARAMS ((hash_table *, sb *, sb *, int));
+static void hash_add_to_int_table PARAMS ((hash_table *, sb *, int));
+static hash_entry *hash_lookup PARAMS ((hash_table *, sb *));
+static void checkconst PARAMS ((int, exp_t *));
+static int sb_strtol PARAMS ((int, sb *, int, int *));
+static int level_0 PARAMS ((int, sb *, exp_t *));
+static int level_1 PARAMS ((int, sb *, exp_t *));
+static int level_2 PARAMS ((int, sb *, exp_t *));
+static int level_3 PARAMS ((int, sb *, exp_t *));
+static int level_4 PARAMS ((int, sb *, exp_t *));
+static int level_5 PARAMS ((int, sb *, exp_t *));
+static int exp_parse PARAMS ((int, sb *, exp_t *));
+static void exp_string PARAMS ((exp_t *, sb *));
+static int exp_get_abs PARAMS ((const char *, int, sb *, int *));
+#if 0
+static void strip_comments PARAMS ((sb *));
+#endif
+static void unget PARAMS ((int));
+static void include_buf PARAMS ((sb *, sb *, include_type, int));
+static void include_print_where_line PARAMS ((FILE *));
+static void include_print_line PARAMS ((FILE *));
+static int get_line PARAMS ((sb *));
+static int grab_label PARAMS ((sb *, sb *));
+static void change_base PARAMS ((int, sb *, sb *));
+static void do_end PARAMS ((sb *));
+static void do_assign PARAMS ((int, int, sb *));
+static void do_radix PARAMS ((sb *));
+static int get_opsize PARAMS ((int, sb *, int *));
+static int eol PARAMS ((int, sb *));
+static void do_data PARAMS ((int, sb *, int));
+static void do_datab PARAMS ((int, sb *));
+static void do_align PARAMS ((int, sb *));
+static void do_res PARAMS ((int, sb *, int));
+static void do_export PARAMS ((sb *));
+static void do_print PARAMS ((int, sb *));
+static void do_heading PARAMS ((int, sb *));
+static void do_page PARAMS ((void));
+static void do_form PARAMS ((int, sb *));
+static int get_any_string PARAMS ((int, sb *, sb *, int, int));
+static int skip_openp PARAMS ((int, sb *));
+static int skip_closep PARAMS ((int, sb *));
+static int dolen PARAMS ((int, sb *, sb *));
+static int doinstr PARAMS ((int, sb *, sb *));
+static int dosubstr PARAMS ((int, sb *, sb *));
+static void process_assigns PARAMS ((int, sb *, sb *));
+static int get_and_process PARAMS ((int, sb *, sb *));
+static void process_file PARAMS ((void));
+static void free_old_entry PARAMS ((hash_entry *));
+static void do_assigna PARAMS ((int, sb *));
+static void do_assignc PARAMS ((int, sb *));
+static void do_reg PARAMS ((int, sb *));
+static int condass_lookup_name PARAMS ((sb *, int, sb *, int));
+static int whatcond PARAMS ((int, sb *, int *));
+static int istrue PARAMS ((int, sb *));
+static void do_aif PARAMS ((int, sb *));
+static void do_aelse PARAMS ((void));
+static void do_aendi PARAMS ((void));
+static int condass_on PARAMS ((void));
+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 do_aendr PARAMS ((void));
+static void do_awhile PARAMS ((int, sb *));
+static void do_aendw PARAMS ((void));
+static void do_exitm PARAMS ((void));
+static void do_arepeat PARAMS ((int, sb *));
+static void do_endm PARAMS ((void));
+static void do_irp PARAMS ((int, sb *, int));
+static void do_local PARAMS ((int, sb *));
+static void do_macro PARAMS ((int, sb *));
+static int macro_op PARAMS ((int, sb *));
+static int getstring PARAMS ((int, sb *, sb *));
+static void do_sdata PARAMS ((int, sb *, int));
+static void do_sdatab PARAMS ((int, sb *));
+static int new_file PARAMS ((const char *));
+static void do_include PARAMS ((int, sb *));
+static void include_pop PARAMS ((void));
+static int get PARAMS ((void));
+static int linecount PARAMS ((void));
+static int include_next_index PARAMS ((void));
+static void chartype_init PARAMS ((void));
+static int process_pseudo_op PARAMS ((int, sb *, sb *));
+static void add_keyword PARAMS ((const char *, int));
+static void process_init PARAMS ((void));
+static void do_define PARAMS ((const char *));
+static void show_usage PARAMS ((FILE *, int));
+static void show_help PARAMS ((void));
#define FATAL(x) \
do { include_print_where_line (stderr); fprintf x ; fatals++; quit(); } while(0)
/* exit the program and return the right ERROR code. */
-void
+static void
quit ()
{
int exitcode;
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);
}
-static
-char *
-xmalloc (x)
- int x;
-{
- char *p = malloc (x);
- if (!p)
- FATAL ((stderr, "out of memory\n"));
- memset (p, 0, x);
- return p;
-}
-
-/* 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. */
-
-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. */
-
-void
-sb_add_char (ptr, c)
- sb *ptr;
- char 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;
- 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;
- 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;
- }
-}
-
-/* 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. */
int size;
hash_table *ptr;
{
+ int i;
ptr->size = size;
ptr->table = (hash_entry **) xmalloc (size * (sizeof (hash_entry *)));
+ /* Fill with null-pointer, not zero-bit-pattern. */
+ for (i = 0; i < size; i++)
+ ptr->table[i] = 0;
}
/* calculate and return the hash value of the sb at key. */
if (!again)
ERROR ((stderr, "redefintion not allowed"));
}
+
+ ptr->type = hash_string;
sb_reset (&ptr->value.s);
+
sb_add_sb (&ptr->value.s, name);
}
expression precedence:
( )
unary + - ~
-* /
-+ -
-&
-| ~
+ * /
+ + -
+ &
+ | ~
*/
static
void
checkconst (op, term)
- char op;
+ int op;
exp_t *term;
{
if (term->add_symbol.len
dig = ch - '0';
else if (ch >= 'a' && ch <= 'f')
dig = ch - 'a' + 10;
- else if (ch >= 'a' && ch <= 'f')
- dig = ch - 'a' + 10;
+ else if (ch >= 'A' && ch <= 'F')
+ dig = ch - 'A' + 10;
else
break;
return idx;
}
-static int level_5 ();
-
-int
+static int
level_0 (idx, string, lhs)
int idx;
sb *string;
static int
exp_get_abs (emsg, idx, in, val)
- char *emsg;
+ const char *emsg;
int idx;
sb *in;
int *val;
#define in_comment ';'
#if 0
-void
+static void
strip_comments (out)
sb *out;
{
int i = 0;
for (i = 0; i < out->len; i++)
{
- if (s[i] == in_comment)
+ if (ISCOMMENTCHAR(s[i]))
{
out->len = i;
return;
/* push back character ch so that it can be read again. */
-void
+static void
unget (ch)
int ch;
{
while (p <= sp)
{
- fprintf (file, "%s:%d ", sb_name (&p->name), p->linecount - ((p == sp) ? 1 : 0));
+ fprintf (file, "%s:%d ", sb_name (&p->name), p->linecount - 1);
p++;
}
}
if (copysource)
{
- putc ('!', outfile);
+ putc (comment_char, outfile);
if (print_line_number)
include_print_line (outfile);
}
{
if (online)
{
- WARNING ((stderr, "end of file not at start of line.\n"));
+ WARNING ((stderr, "End of file not at start of line.\n"));
if (copysource)
putc ('\n', outfile);
+ ch = '\n';
}
- more = 0;
+ else
+ more = 0;
break;
}
/* continued line */
if (copysource)
{
- putc ('!', outfile);
+ putc (comment_char, outfile);
putc ('+', outfile);
}
ch = get ();
{
sb_add_char (out, in->ptr[i]);
i++;
- while (ISNEXTCHAR (in->ptr[i]) && i < in->len)
+ while ((ISNEXTCHAR (in->ptr[i])
+ || in->ptr[i] == '\\'
+ || in->ptr[i] == '&')
+ && i < in->len)
{
sb_add_char (out, in->ptr[i]);
i++;
while (idx < in->len)
{
- if (idx < in->len - 1 && in->ptr[idx + 1] == '\'')
+ if (in->ptr[idx] == '\\'
+ && idx + 1 < in->len
+ && in->ptr[idx + 1] == '(')
+ {
+ idx += 2;
+ while (idx < in->len
+ && in->ptr[idx] != ')')
+ {
+ sb_add_char (out, in->ptr[idx]);
+ idx++;
+ }
+ if (idx < in->len)
+ idx++;
+ }
+ else if (idx < in->len - 1 && in->ptr[idx + 1] == '\'' && ! mri)
{
int base;
int value;
idx++;
}
}
+ else if (in->ptr[idx] == '"' || in->ptr[idx] == '\'')
+ {
+ char tchar = in->ptr[idx];
+ /* copy entire names through quickly */
+ sb_add_char (out, in->ptr[idx]);
+ idx++;
+ while (idx < in->len && in->ptr[idx] != tchar)
+ {
+ sb_add_char (out, in->ptr[idx]);
+ idx++;
+ }
+ }
else
{
/* nothing special, just pass it through */
/* .end */
static void
-do_end ()
+do_end (in)
+ sb *in;
{
had_end = 1;
+ if (mri)
+ fprintf (outfile, "%s\n", sb_name (in));
}
/* .assign */
static int
get_opsize (idx, in, size)
-int idx;
-sb *in;
-int *size;
+ int idx;
+ sb *in;
+ int *size;
{
*size = 4;
if (in->ptr[idx] == '.')
{
idx++;
- switch (in->ptr[idx])
- {
- case 'b':
- case 'B':
- *size = 1;
- break;
- case 'w':
- case 'W':
- *size = 2;
- break;
- case 'l':
- case 'L':
- *size = 4;
- break;
- default:
- ERROR ((stderr, "size must be one of b, w or l, is %c.\n", in->ptr[idx]));
- break;
- }
- idx++;
}
+ switch (in->ptr[idx])
+ {
+ case 'b':
+ case 'B':
+ *size = 1;
+ break;
+ case 'w':
+ case 'W':
+ *size = 2;
+ break;
+ case 'l':
+ case 'L':
+ *size = 4;
+ break;
+ case ' ':
+ case '\t':
+ break;
+ default:
+ ERROR ((stderr, "size must be one of b, w or l, is %c.\n", in->ptr[idx]));
+ break;
+ }
+ idx++;
+
return idx;
}
-/* .data [.b|.w|.l] <data>* */
+static
+int eol(idx, line)
+ int idx;
+ sb *line;
+{
+ idx = sb_skip_white (idx, line);
+ if (idx < line->len
+ && ISCOMMENTCHAR(line->ptr[idx]))
+ return 1;
+ if (idx >= line->len)
+ return 1;
+ return 0;
+}
+
+/* .data [.b|.w|.l] <data>*
+ or d[bwl] <data>* */
static void
-do_data (idx, in)
+do_data (idx, in, size)
int idx;
sb *in;
+ int size;
{
int opsize = 4;
- char *opname;
+ char *opname = ".yikes!";
sb acc;
sb_new (&acc);
- idx = get_opsize (idx, in, &opsize);
-
+ if (!size)
+ {
+ idx = get_opsize (idx, in, &opsize);
+ }
+ else {
+ opsize = size;
+ }
switch (opsize)
{
case 4:
break;
}
+
fprintf (outfile, "%s\t", opname);
- while (idx < in->len)
+
+ idx = sb_skip_white (idx, in);
+
+ if (alternate
+ && idx < in->len
+ && in->ptr[idx] == '"')
{
- exp_t e;
- idx = exp_parse (idx, in, &e);
- exp_string (&e, &acc);
- sb_add_char (&acc, 0);
- fprintf (outfile, acc.ptr);
- if (idx < in->len && in->ptr[idx] == ',')
+ int i;
+ idx = getstring (idx, in, &acc);
+ for (i = 0; i < acc.len; i++)
{
- fprintf (outfile, ",");
- idx++;
+ if (i)
+ fprintf(outfile,",");
+ fprintf (outfile, "%d", acc.ptr[i]);
+ }
+ }
+ else
+ {
+ while (!eol (idx, in))
+ {
+ exp_t e;
+ idx = exp_parse (idx, in, &e);
+ exp_string (&e, &acc);
+ sb_add_char (&acc, 0);
+ fprintf (outfile, acc.ptr);
+ if (idx < in->len && in->ptr[idx] == ',')
+ {
+ fprintf (outfile, ",");
+ idx++;
+ }
}
}
sb_kill (&acc);
+ sb_print_at (outfile, idx, in);
fprintf (outfile, "\n");
}
/* .align <size> */
-void
+static void
do_align (idx, in)
int idx;
sb *in;
{
- int al;
+ int al, have_fill, fill;
+
idx = exp_get_abs ("align needs absolute expression.\n", idx, in, &al);
+ idx = sb_skip_white (idx, in);
+ have_fill = 0;
+ fill = 0;
+ if (! eol (idx, in))
+ {
+ idx = sb_skip_comma (idx, in);
+ idx = exp_get_abs (".align needs absolute fill value.\n", idx, in,
+ &fill);
+ have_fill = 1;
+ }
if (al != 1
&& al != 2
&& al != 4)
WARNING ((stderr, "alignment must be one of 1, 2 or 4.\n"));
- fprintf (outfile, ".align %d\n", al);
+ fprintf (outfile, ".align %d", al);
+ if (have_fill)
+ fprintf (outfile, ",%d", fill);
+ fprintf (outfile, "\n");
}
/* .res[.b|.w|.l] <size> */
-void
+static void
do_res (idx, in, type)
int idx;
sb *in;
- char type;
+ int type;
{
int size = 4;
int count = 0;
idx = get_opsize (idx, in, &size);
- while (idx < in->len)
+ while (!eol(idx, in))
{
idx = sb_skip_white (idx, in);
if (in->ptr[idx] == ',')
/* .export */
-void
+static void
do_export (in)
sb *in;
{
/* .print [list] [nolist] */
-void
+static void
do_print (idx, in)
int idx;
sb *in;
idx = sb_skip_white (idx, in);
while (idx < in->len)
{
- if (strncmp (in->ptr + idx, "LIST", 4) == 0)
+ if (strncasecmp (in->ptr + idx, "LIST", 4) == 0)
{
fprintf (outfile, ".list\n");
idx += 4;
}
- else if (strncmp (in->ptr + idx, "NOLIST", 6) == 0)
+ else if (strncasecmp (in->ptr + idx, "NOLIST", 6) == 0)
{
fprintf (outfile, ".nolist\n");
idx += 6;
}
/* .head */
-void
+static void
do_heading (idx, in)
int idx;
sb *in;
/* .page */
-void
+static void
do_page ()
{
fprintf (outfile, ".eject\n");
}
/* .form [lin=<value>] [col=<value>] */
-void
+static void
do_form (idx, in)
int idx;
sb *in;
while (idx < in->len)
{
- if (strncmp (in->ptr + idx, "LIN=", 4) == 0)
+ if (strncasecmp (in->ptr + idx, "LIN=", 4) == 0)
{
idx += 4;
idx = exp_get_abs ("form LIN= needs absolute expresssion.\n", idx, in, &lines);
}
- if (strncmp (in->ptr + idx, "COL=", 4) == 0)
+ if (strncasecmp (in->ptr + idx, "COL=", 4) == 0)
{
idx += 4;
idx = exp_get_abs ("form COL= needs absolute expresssion.\n", idx, in, &columns);
}
-int
-get_any_string (idx, in, out)
+
+/* Fetch string from the input stream,
+ rules:
+ 'Bxyx<whitespace> -> return 'Bxyza
+ %<char> -> return string of decimal value of x
+ "<string>" -> return string
+ xyx<whitespace> -> return xyz
+*/
+static int
+get_any_string (idx, in, out, expand, pretend_quoted)
int idx;
sb *in;
sb *out;
+ int expand;
+ int pretend_quoted;
{
- idx = sb_skip_white (idx, in);
- if (idx < in->len && (in->ptr[idx] == '"'
- || in->ptr[idx] == '<'))
- return getstring (idx, in, out);
-
sb_reset (out);
+ idx = sb_skip_white (idx, in);
- while (idx < in->len && !ISSEP (in->ptr[idx]))
+ if (idx < in->len)
{
- sb_add_char (out, in->ptr[idx++]);
+ if (in->len > 2 && in->ptr[idx+1] == '\'' && ISBASE (in->ptr[idx]))
+ {
+ while (!ISSEP (in->ptr[idx]))
+ sb_add_char (out, in->ptr[idx++]);
+ }
+ else if (in->ptr[idx] == '%'
+ && alternate
+ && expand)
+ {
+ int val;
+ char buf[20];
+ /* Turns the next expression into a string */
+ idx = exp_get_abs ("% operator needs absolute expression",
+ idx + 1,
+ in,
+ &val);
+ sprintf(buf, "%d", val);
+ sb_add_string (out, buf);
+ }
+ else if (in->ptr[idx] == '"'
+ || in->ptr[idx] == '<'
+ || (alternate && in->ptr[idx] == '\''))
+ {
+ if (alternate && expand)
+ {
+ /* Keep the quotes */
+ sb_add_char (out, '\"');
+
+ idx = getstring (idx, in, out);
+ sb_add_char (out, '\"');
+
+ }
+ else {
+ idx = getstring (idx, in, out);
+ }
+ }
+ else
+ {
+ while (idx < in->len
+ && (in->ptr[idx] == '"'
+ || in->ptr[idx] == '\''
+ || pretend_quoted
+ || !ISSEP (in->ptr[idx])))
+ {
+ if (in->ptr[idx] == '"'
+ || in->ptr[idx] == '\'')
+ {
+ char tchar = in->ptr[idx];
+ sb_add_char (out, in->ptr[idx++]);
+ while (idx < in->len
+ && in->ptr[idx] != tchar)
+ sb_add_char (out, in->ptr[idx++]);
+ if (idx == in->len)
+ return idx;
+ }
+ sb_add_char (out, in->ptr[idx++]);
+ }
+ }
}
+
return idx;
}
/* skip along sb in starting at idx, suck off whitespace a ( and more
whitespace. return the idx of the next char */
-int
+static int
skip_openp (idx, in)
int idx;
sb *in;
/* skip along sb in starting at idx, suck off whitespace a ) and more
whitespace. return the idx of the next char */
-int
+static int
skip_closep (idx, in)
int idx;
sb *in;
/* .len */
-int
+static int
dolen (idx, in, out)
int idx;
sb *in;
}
/* scan line, change tokens in the hash table to their replacements */
-void
+static void
process_assigns (idx, in, buf)
int idx;
sb *in;
{
hash_entry *ptr;
if (in->ptr[idx] == '\\'
+ && idx + 1 < in->len
+ && in->ptr[idx + 1] == '(')
+ {
+ do
+ {
+ sb_add_char (buf, in->ptr[idx]);
+ idx++;
+ }
+ while (idx < in->len && in->ptr[idx - 1] != ')');
+ }
+ else if (in->ptr[idx] == '\\'
+ && idx + 1 < in->len
&& in->ptr[idx + 1] == '&')
{
- idx = condass_lookup_name (in, idx + 2, buf);
+ idx = condass_lookup_name (in, idx + 2, buf, 1);
+ }
+ else if (in->ptr[idx] == '\\'
+ && idx + 1 < in->len
+ && in->ptr[idx + 1] == '$')
+ {
+ idx = condass_lookup_name (in, idx + 2, buf, 0);
}
else if (idx + 3 < in->len
&& in->ptr[idx] == '.'
- && in->ptr[idx + 1] == 'L'
- && in->ptr[idx + 2] == 'E'
- && in->ptr[idx + 3] == 'N')
+ && toupper ((unsigned char) in->ptr[idx + 1]) == 'L'
+ && toupper ((unsigned char) in->ptr[idx + 2]) == 'E'
+ && toupper ((unsigned char) in->ptr[idx + 3]) == 'N')
idx = dolen (idx + 4, in, buf);
else if (idx + 6 < in->len
&& in->ptr[idx] == '.'
- && in->ptr[idx + 1] == 'I'
- && in->ptr[idx + 2] == 'N'
- && in->ptr[idx + 3] == 'S'
- && in->ptr[idx + 4] == 'T'
- && in->ptr[idx + 5] == 'R')
+ && toupper ((unsigned char) in->ptr[idx + 1]) == 'I'
+ && toupper ((unsigned char) in->ptr[idx + 2]) == 'N'
+ && toupper ((unsigned char) in->ptr[idx + 3]) == 'S'
+ && toupper ((unsigned char) in->ptr[idx + 4]) == 'T'
+ && toupper ((unsigned char) in->ptr[idx + 5]) == 'R')
idx = doinstr (idx + 6, in, buf);
else if (idx + 7 < in->len
&& in->ptr[idx] == '.'
- && in->ptr[idx + 1] == 'S'
- && in->ptr[idx + 2] == 'U'
- && in->ptr[idx + 3] == 'B'
- && in->ptr[idx + 4] == 'S'
- && in->ptr[idx + 5] == 'T'
- && in->ptr[idx + 6] == 'R')
+ && toupper ((unsigned char) in->ptr[idx + 1]) == 'S'
+ && toupper ((unsigned char) in->ptr[idx + 2]) == 'U'
+ && toupper ((unsigned char) in->ptr[idx + 3]) == 'B'
+ && toupper ((unsigned char) in->ptr[idx + 4]) == 'S'
+ && toupper ((unsigned char) in->ptr[idx + 5]) == 'T'
+ && toupper ((unsigned char) in->ptr[idx + 6]) == 'R')
idx = dosubstr (idx + 7, in, buf);
else if (ISFIRSTCHAR (in->ptr[idx]))
{
{
sb t;
sb_new (&t);
- idx = get_any_string (idx, in, &t);
+ idx = get_any_string (idx, in, &t, 1, 0);
process_assigns (0, &t, out);
sb_kill (&t);
return idx;
sb line;
sb t1, t2;
sb acc;
+ sb label_in;
int more;
sb_new (&line);
sb_new (&t1);
sb_new (&t2);
sb_new(&acc);
-
+ sb_new (&label_in);
sb_reset (&line);
more = get_line (&line);
while (more)
if (condass_on ())
fprintf (outfile, "\n");
}
+ else if (mri
+ && (line.ptr[0] == '*'
+ || line.ptr[0] == '!'))
+ {
+ /* MRI line comment. */
+ fprintf (outfile, sb_name (&line));
+ }
else
{
+ l = grab_label (&line, &label_in);
+ sb_reset (&label);
+ if (label_in.len)
+ {
+ /* Munge any label */
+
+
+ process_assigns (0, &label_in, &label);
+ }
- l = grab_label (&line, &label);
if (line.ptr[l] == ':')
l++;
while (ISWHITE (line.ptr[l]) && l < line.len)
l++;
- if (line.len)
+ if (l < line.len)
{
if (process_pseudo_op (l, &line, &acc))
{
}
}
}
+ else {
+ /* Only a label on this line */
+ if (label.len && condass_on())
+ {
+ fprintf (outfile, "%s:\n", sb_name (&label));
+ }
+ }
}
if (had_end)
more = get_line (&line);
}
- if (!had_end)
- WARNING ((stderr, ".END missing from end of file.\n"));
+ if (!had_end && !mri)
+ WARNING ((stderr, "END missing from end of file.\n"));
}
/* name: .ASSIGNA <value> */
-void
+static void
do_assigna (idx, in)
int idx;
sb *in;
/* name: .ASSIGNC <string> */
-void
+static void
do_assignc (idx, in)
int idx;
sb *in;
{
/* remove reg stuff from inside parens */
sb what;
- idx = skip_openp (idx, in);
+ if (!mri)
+ idx = skip_openp (idx, in);
+ else
+ idx = sb_skip_white (idx, in);
sb_new (&what);
- while (idx < in->len && in->ptr[idx] != ')')
+ while (idx < in->len
+ && (mri
+ ? ! eol (idx, in)
+ : in->ptr[idx] != ')'))
{
sb_add_char (&what, in->ptr[idx]);
idx++;
static int
-condass_lookup_name (inbuf, idx, out)
+condass_lookup_name (inbuf, idx, out, warn)
sb *inbuf;
int idx;
sb *out;
+ int warn;
{
hash_entry *ptr;
sb condass_acc;
if (inbuf->ptr[idx] == '\'')
idx++;
ptr = hash_lookup (&vars, &condass_acc);
+
+
if (!ptr)
{
- WARNING ((stderr, "Can't find preprocessor variable %s.\n", sb_name (&condass_acc)));
+ if (warn)
+ {
+ WARNING ((stderr, "Can't find preprocessor variable %s.\n", sb_name (&condass_acc)));
+ }
+ else
+ {
+ sb_add_string (out, "0");
+ }
}
else
{
#define GT 6
#define NEVER 7
-int
+static int
whatcond (idx, in, val)
int idx;
sb *in;
int *val;
{
int cond;
- char *p;
+
idx = sb_skip_white (idx, in);
- p = in->ptr + idx;
- if (p[0] == 'E' && p[1] == 'Q')
- cond = EQ;
- else if (p[0] == 'N' && p[1] == 'E')
- cond = NE;
- else if (p[0] == 'L' && p[1] == 'T')
- cond = LT;
- else if (p[0] == 'L' && p[1] == 'E')
- cond = LE;
- else if (p[0] == 'G' && p[1] == 'T')
- cond = GT;
- else if (p[0] == 'G' && p[1] == 'E')
- cond = GE;
- else
- {
- ERROR ((stderr, "Comparison operator must be one of EQ, NE, LT, LE, GT or GE"));
+ cond = NEVER;
+ if (idx + 1 < in->len)
+ {
+ char *p;
+ char a, b;
+
+ p = in->ptr + idx;
+ a = toupper ((unsigned char) p[0]);
+ b = toupper ((unsigned char) p[1]);
+ if (a == 'E' && b == 'Q')
+ cond = EQ;
+ else if (a == 'N' && b == 'E')
+ cond = NE;
+ else if (a == 'L' && b == 'T')
+ cond = LT;
+ else if (a == 'L' && b == 'E')
+ cond = LE;
+ else if (a == 'G' && b == 'T')
+ cond = GT;
+ else if (a == 'G' && b == 'E')
+ cond = GE;
+ }
+ if (cond == NEVER)
+ {
+ ERROR ((stderr, "Comparison operator must be one of EQ, NE, LT, LE, GT or GE.\n"));
cond = NEVER;
}
idx = sb_skip_white (idx + 2, in);
return idx;
}
-int
+static int
istrue (idx, in)
int idx;
sb *in;
if (cond != EQ && cond != NE)
{
- ERROR ((stderr, "Comparison operator for strings must be EQ or NE"));
+ ERROR ((stderr, "Comparison operator for strings must be EQ or NE\n"));
res = 0;
}
else
- res = cond == EQ && same;
+ res = (cond != EQ) ^ same;
}
else
/* This is a numeric expression */
idx = exp_get_abs ("Conditional operator must have absolute operands.\n", idx, in, &valb);
switch (cond)
{
+ default:
+ res = 42;
+ break;
case EQ:
res = vala == valb;
break;
FATAL ((stderr, "AIF nesting unreasonable.\n"));
}
ifi++;
- ifstack[ifi].on = istrue (idx, in);
+ ifstack[ifi].on = ifstack[ifi-1].on ? istrue (idx, in) : 0;
ifstack[ifi].hadelse = 0;
}
static void
do_aelse ()
{
- ifstack[ifi].on = !ifstack[ifi].on;
+ ifstack[ifi].on = ifstack[ifi-1].on ? !ifstack[ifi].on : 0;
if (ifstack[ifi].hadelse)
{
ERROR ((stderr, "Multiple AELSEs in AIF.\n"));
return ifstack[ifi].on;
}
-
-/* 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. */
+/* MRI IFEQ, IFNE, IFLT, IFLE, IFGE, IFGT. */
static void
-buffer_and_nest (from, to, ptr)
- char *from;
- char *to;
- sb *ptr;
+do_if (idx, in, cond)
+ int idx;
+ sb *in;
+ int cond;
{
- 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);
+ int val;
+ int res;
- while (more)
+ if (ifi >= IFNESTING)
{
- /* Try and find the first pseudo op on the line */
- int i = line_start;
+ FATAL ((stderr, "IF nesting unreasonable.\n"));
+ }
- /* Skip leading whitespace */
- while (i < ptr->len
- && ISWHITE (ptr->ptr[i]))
- i++;
+ idx = exp_get_abs ("Conditional operator must have absolute operands.\n",
+ idx, in, &val);
+ switch (cond)
+ {
+ default:
+ case EQ: res = val == 0; break;
+ case NE: res = val != 0; break;
+ case LT: res = val < 0; break;
+ case LE: res = val <= 0; break;
+ case GE: res = val >= 0; break;
+ case GT: res = val > 0; break;
+ }
- /* Skip over a label */
- while (i < ptr->len
- && ISNEXTCHAR (ptr->ptr[i]))
- i++;
+ ifi++;
+ ifstack[ifi].on = ifstack[ifi-1].on ? res: 0;
+ ifstack[ifi].hadelse = 0;
+}
- /* And a colon */
- if (i < ptr->len
- && ptr->ptr[i] == ':')
- i++;
+/* Get a string for the MRI IFC or IFNC pseudo-ops. */
- /* Skip trailing whitespace */
- while (i < ptr->len
- && ISWHITE (ptr->ptr[i]))
- i++;
+static int
+get_mri_string (idx, in, val, terminator)
+ int idx;
+ sb *in;
+ sb *val;
+ int terminator;
+{
+ idx = sb_skip_white (idx, in);
- if (i < ptr->len
- && ptr->ptr[i] == '.')
+ if (idx < in->len
+ && in->ptr[idx] == '\'')
+ {
+ sb_add_char (val, '\'');
+ for (++idx; idx < in->len; ++idx)
{
- if (strncmp (ptr->ptr + i, from, from_len) == 0)
- depth++;
- if (strncmp (ptr->ptr + i, to, to_len) == 0)
+ sb_add_char (val, in->ptr[idx]);
+ if (in->ptr[idx] == '\'')
{
- depth--;
- if (depth == 0)
- {
- /* Reset the string to not include the ending rune */
- ptr->len = line_start;
- break;
- }
+ ++idx;
+ if (idx >= in->len
+ || in->ptr[idx] != '\'')
+ break;
}
}
-
- /* Add a CR to the end and keep running */
- sb_add_char (ptr, '\n');
- line_start = ptr->len;
- more = get_line (ptr);
+ idx = sb_skip_white (idx, in);
}
+ else
+ {
+ int i;
+ while (idx < in->len
+ && in->ptr[idx] != terminator)
+ {
+ sb_add_char (val, in->ptr[idx]);
+ ++idx;
+ }
+ i = val->len - 1;
+ while (i >= 0 && ISWHITE (val->ptr[i]))
+ --i;
+ val->len = i + 1;
+ }
- if (depth)
- FATAL ((stderr, "End of file whilst inside %s, started on line %d.\n", from, line));
+ return idx;
}
+/* MRI IFC, IFNC. */
+
+static void
+do_ifc (idx, in, ifnc)
+ int idx;
+ sb *in;
+ int ifnc;
+{
+ sb first;
+ sb second;
+ int res;
+
+ if (ifi >= IFNESTING)
+ {
+ FATAL ((stderr, "IF nesting unreasonable.\n"));
+ }
+
+ sb_new (&first);
+ sb_new (&second);
+
+ idx = get_mri_string (idx, in, &first, ',');
+
+ if (idx >= in->len || in->ptr[idx] != ',')
+ {
+ ERROR ((stderr, "Bad format for IF or IFNC.\n"));
+ return;
+ }
+
+ idx = get_mri_string (idx + 1, in, &second, ';');
+
+ res = (first.len == second.len
+ && strncmp (first.ptr, second.ptr, first.len) == 0);
+ res ^= ifnc;
+
+ ifi++;
+ ifstack[ifi].on = ifstack[ifi-1].on ? res : 0;
+ ifstack[ifi].hadelse = 0;
+}
/* .ENDR */
-void
+static void
do_aendr ()
{
- ERROR ((stderr, "AENDR without a AREPEAT.\n"));
+ if (!mri)
+ ERROR ((stderr, "AENDR without a AREPEAT.\n"));
+ else
+ ERROR ((stderr, "ENDR without a REPT.\n"));
}
/* .AWHILE */
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);
- buffer_and_nest (".AREPEAT", ".AENDR", &sub);
+ if (!mri)
+ ret = buffer_and_nest ("AREPEAT", "AENDR", &sub, get_line);
+ else
+ 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_add_sb (©, &sub);
if (rc > 1)
{
- sprintf (buffer, "\t.AREPEAT %d\n", rc - 1);
+ if (!mri)
+ sprintf (buffer, "\t.AREPEAT %d\n", rc - 1);
+ else
+ sprintf (buffer, "\tREPT %d\n", rc - 1);
sb_add_string (©, buffer);
sb_add_sb (©, &sub);
- sb_add_string (©, " .AENDR\n");
+ if (!mri)
+ sb_add_string (©, " .AENDR\n");
+ else
+ sb_add_string (©, " ENDR\n");
}
include_buf (&exp, ©, include_repeat, index);
ERROR ((stderr, ".ENDM without a matching .MACRO.\n"));
}
+/* MRI IRP pseudo-op. */
-/* MARRO PROCESSING */
-
-static int number;
-hash_table macro_table;
-
-/* Understand
-
- .MACRO <name>
- stuff
- .ENDM
-*/
-
-static int
-do_formals (macro, idx, in)
- macro_entry *macro;
+static void
+do_irp (idx, in, irpc)
int idx;
sb *in;
+ int irpc;
{
- 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);
+ const char *err;
+ sb out;
- 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);
- }
- }
+ sb_new (&out);
- {
- /* Add to macro's hash table */
+ err = expand_irp (irpc, idx, in, &out, get_line, comment_char);
+ if (err != NULL)
+ ERROR ((stderr, "%s\n", err));
- hash_entry *p = hash_create (¯o->formal_hash, &formal->name);
- p->type = hash_formal;
- p->value.f = formal;
- }
+ fprintf (outfile, "%s", sb_terminate (&out));
- formal->index = macro->formal_count;
- idx = sb_skip_comma (idx, in);
- macro->formal_count++;
- *p = formal;
- p = &formal->next;
- }
- return idx;
+ sb_kill (&out);
}
-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)
- {
- /* It's the label: MACRO (formals,...) sort */
- sb_add_sb (&name, &label);
- if (in->ptr[idx] == '(')
- {
- /* Got some formals */
- idx = do_formals (macro, idx + 1, in);
- if (in->ptr[idx] != ')')
- ERROR ((stderr, "Missing ) after formals.\n"));
- }
- }
- 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;
-}
+/* MACRO PROCESSING */
+/* Parse off LOCAL n1, n2,... Invent a label name for it */
static
-int
-get_token (idx, in, name)
+void
+do_local (idx, line)
int idx;
- sb *in;
- sb *name;
+ sb *line;
{
- 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++]);
- }
- }
- return idx;
+ ERROR ((stderr, "LOCAL outside of MACRO"));
}
-/* Scan a token, but stop if a ' is seen */
-static int
-get_apost_token (idx, in, name, kind)
+static void
+do_macro (idx, in)
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;
-}
+ const char *err;
+ int line = linecount ();
-static int
-sub_actual (src, in, t, m, kind, out)
- int src;
- sb *in;
- sb *t;
- macro_entry *m;
- int kind;
- sb *out;
-{
- /* 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 (&m->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
- {
- sb_add_char (out, '\\');
- sb_add_sb (out, t);
- }
- return src;
+ err = define_macro (idx, in, &label, get_line, (const char **) NULL);
+ if (err != NULL)
+ ERROR ((stderr, "macro at line %d: %s\n", line - 1, err));
}
-static
-void
-macro_expand (name, idx, in, m)
- sb *name;
+static int
+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;
-
- 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;
- /* Peel off the actuals and store them away in the hash tables' actuals */
- while (idx < in->len)
- {
- 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])
- && in->ptr[scan] != '=')
- scan++;
- if (scan < in->len && 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);
- }
- }
- 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)
- {
- ERROR ((stderr, "Too many positional arguments.\n"));
- return;
- }
+ sb name;
- sb_reset (&f->actual);
- idx = get_any_string (idx, in, &f->actual);
- f = f->next;
- }
- idx = sb_skip_comma (idx, in);
- }
+ if (! macro_defined)
+ return 0;
- /* Copy the stuff from the macro buffer into a safe place and substitute any args */
+ sb_terminate (in);
+ if (! check_macro (in->ptr + idx, &out, comment_char, &err))
+ return 0;
- {
- int src = 0;
- sb *in = &m->sub;
- sb_reset (&out);
+ if (err != NULL)
+ ERROR ((stderr, "%s\n", err));
- while (src < in->len)
- {
- if (in->ptr[src] == '&')
- {
- sb_reset (&t);
- src = sub_actual (src + 1, in, &t, m, '&', &out);
- }
- else if (in->ptr[src] == '\\')
- {
- src++;
- if (in->ptr[src] == ';')
- {
- /* This is a comment, just drop the rest of the line */
- while (src < in->len
- && in->ptr[src] != '\n')
- src++;
+ sb_new (&name);
+ sb_add_string (&name, "macro expansion");
- }
- 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 */
+ include_buf (&name, &out, include_macro, include_next_index ());
- 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
- {
- sb_reset (&t);
- src = sub_actual (src, in, &t, m, '\'', &out);
- }
- }
- else
- {
- sb_add_char (&out, in->ptr[src++]);
- }
- }
- include_buf (name, &out, include_macro, include_next_index ());
- }
- 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
idx = sb_skip_white (idx, in);
while (idx < in->len
- && (in->ptr[idx] == '"' || in->ptr[idx] == '<'))
+ && (in->ptr[idx] == '"'
+ || in->ptr[idx] == '<'
+ || (in->ptr[idx] == '\'' && alternate)))
{
if (in->ptr[idx] == '<')
{
- int code;
- idx++;
- idx = exp_get_abs ("Character code in string must be absolute expression.\n",
- idx, in, &code);
- sb_add_char (acc, code);
-
- if (in->ptr[idx] != '>')
- ERROR ((stderr, "Missing > for character code.\n"));
- idx++;
+ if (alternate || mri)
+ {
+ int nest = 0;
+ idx++;
+ while ((in->ptr[idx] != '>' || nest)
+ && idx < in->len)
+ {
+ if (in->ptr[idx] == '!')
+ {
+ idx++ ;
+ sb_add_char (acc, in->ptr[idx++]);
+ }
+ else {
+ if (in->ptr[idx] == '>')
+ nest--;
+ if (in->ptr[idx] == '<')
+ nest++;
+ sb_add_char (acc, in->ptr[idx++]);
+ }
+ }
+ idx++;
+ }
+ else {
+ int code;
+ idx++;
+ idx = exp_get_abs ("Character code in string must be absolute expression.\n",
+ idx, in, &code);
+ sb_add_char (acc, code);
+
+ if (in->ptr[idx] != '>')
+ ERROR ((stderr, "Missing > for character code.\n"));
+ idx++;
+ }
}
- else if (in->ptr[idx] == '"')
+ else if (in->ptr[idx] == '"' || in->ptr[idx] == '\'')
{
+ char tchar = in->ptr[idx];
idx++;
while (idx < in->len)
{
- if (in->ptr[idx] == '"')
+ if (alternate && in->ptr[idx] == '!')
{
- idx++;
- if (idx >= in->len || in->ptr[idx] != '"')
- break;
+ idx++ ;
+ sb_add_char (acc, in->ptr[idx++]);
}
- sb_add_char (acc, in->ptr[idx]);
- idx++;
+ else {
+ if (in->ptr[idx] == tchar)
+ {
+ idx++;
+ if (idx >= in->len || in->ptr[idx] != tchar)
+ break;
+ }
+ sb_add_char (acc, in->ptr[idx]);
+ idx++;
+ }
}
}
}
-
+
return idx;
}
do_sdata (idx, in, type)
int idx;
sb *in;
- char type;
+ int type;
{
int nc = 0;
+ int pidx = -1;
sb acc;
sb_new (&acc);
fprintf (outfile, ".byte\t");
- while (idx < in->len)
+ while (!eol (idx, in))
{
int i;
sb_reset (&acc);
idx = sb_skip_white (idx, in);
- while ((in->ptr[idx] == '"'
- || in->ptr[idx] == '<')
- && idx < in->len)
+ while (!eol (idx, in))
{
- idx = getstring (idx, in, &acc);
+ pidx = idx = get_any_string (idx, in, &acc, 0, 1);
if (type == 'c')
{
if (acc.len > 255)
fprintf (outfile, ",");
fprintf (outfile, "0");
}
- idx = sb_skip_white (idx, in);
+ idx = sb_skip_comma (idx, in);
+ if (idx == pidx) break;
}
- if (in->ptr[idx] != ',' && idx != in->len)
+ if (!alternate && in->ptr[idx] != ',' && idx != in->len)
{
fprintf (outfile, "\n");
ERROR ((stderr, "illegal character in SDATA line (0x%x).\n", in->ptr[idx]));
if (i)
fprintf (outfile, "\t");
fprintf (outfile, ".byte\t");
- sb_print (&acc);
+ sb_print (outfile, &acc);
fprintf (outfile, "\n");
}
sb_kill (&acc);
}
-int
+static int
new_file (name)
- char *name;
+ const char *name;
{
FILE *newone = fopen (name, "r");
if (!newone)
return 0;
if (isp == MAX_INCLUDES)
- FATAL ((stderr, "Unreasonable include depth (%d).\n", isp));
+ FATAL ((stderr, "Unreasonable include depth (%ld).\n", (long) isp));
sp++;
sp->handle = newone;
sb *in;
{
sb t;
- char *text;
+ sb cat;
+ include_path *includes;
+
sb_new (&t);
- idx = getstring (idx, in, &t);
- text = sb_name (&t);
- if (!new_file (text))
+ sb_new (&cat);
+
+ if (! mri)
+ idx = getstring (idx, in, &t);
+ else
+ {
+ idx = sb_skip_white (idx, in);
+ while (idx < in->len && ! ISWHITE (in->ptr[idx]))
+ {
+ sb_add_char (&t, in->ptr[idx]);
+ ++idx;
+ }
+ }
+
+ for (includes = paths_head; includes; includes = includes->next)
+ {
+ sb_reset (&cat);
+ sb_add_sb (&cat, &includes->path);
+ sb_add_char (&cat, '/');
+ sb_add_sb (&cat, &t);
+ if (new_file (sb_name (&cat)))
+ {
+ break;
+ }
+ }
+ if (!includes)
{
- FATAL ((stderr, "Can't open include file `%s'.\n", text));
+ if (! new_file (sb_name (&t)))
+ FATAL ((stderr, "Can't open include file `%s'.\n", sb_name (&t)));
}
+ sb_kill (&cat);
sb_kill (&t);
}
if (isalpha (x) || x == '_' || x == '$')
chartype[x] |= FIRSTBIT;
+ if (mri && x == '.')
+ chartype[x] |= FIRSTBIT;
+
if (isdigit (x) || isalpha (x) || x == '_' || x == '$')
chartype[x] |= NEXTBIT;
|| x == '"' || x == '<' || x == '>' || x == ')' || x == '(')
chartype[x] |= SEPBIT;
+ if (x == 'b' || x == 'B'
+ || x == 'q' || x == 'Q'
+ || x == 'h' || x == 'H'
+ || x == 'd' || x == 'D')
+ chartype [x] |= BASEBIT;
+
if (x == ' ' || x == '\t')
chartype[x] |= WHITEBIT;
+
+ if (x == comment_char)
+ chartype[x] |= COMMENTBIT;
}
}
+
/* What to do with all the keywords */
#define PROCESS 0x1000 /* Run substitution over the line */
#define LAB 0x2000 /* Spit out the label */
-#define K_EQU PROCESS|1
-#define K_ASSIGN PROCESS|2
-#define K_REG PROCESS|3
-#define K_ORG PROCESS|4
-#define K_RADIX PROCESS|5
-#define K_DATA LAB|PROCESS|6
-#define K_DATAB LAB|PROCESS|7
-#define K_SDATA LAB|PROCESS|8
-#define K_SDATAB LAB|PROCESS|9
-#define K_SDATAC LAB|PROCESS|10
-#define K_SDATAZ LAB|PROCESS|11
-#define K_RES LAB|PROCESS|12
-#define K_SRES LAB|PROCESS|13
-#define K_SRESC LAB|PROCESS|14
-#define K_SRESZ LAB|PROCESS|15
-#define K_EXPORT LAB|PROCESS|16
-#define K_GLOBAL LAB|PROCESS|17
-#define K_PRINT LAB|PROCESS|19
-#define K_FORM LAB|PROCESS|20
-#define K_HEADING LAB|PROCESS|21
-#define K_PAGE LAB|PROCESS|22
-#define K_IMPORT LAB|PROCESS|23
-#define K_PROGRAM LAB|PROCESS|24
-#define K_END PROCESS|25
-#define K_INCLUDE PROCESS|26
-#define K_IGNORED PROCESS|27
-#define K_ASSIGNA 28
-#define K_ASSIGNC 29
-#define K_AIF PROCESS|30
-#define K_AELSE PROCESS|31
-#define K_AENDI PROCESS|32
-#define K_AREPEAT PROCESS|33
-#define K_AENDR PROCESS|34
-#define K_AWHILE 35
-#define K_AENDW PROCESS|36
-#define K_EXITM 37
-#define K_MACRO PROCESS|38
-#define K_ENDM 39
-#define K_ALIGN PROCESS|LAB|40
-
-
-static struct
+#define K_EQU (PROCESS|1)
+#define K_ASSIGN (PROCESS|2)
+#define K_REG (PROCESS|3)
+#define K_ORG (PROCESS|4)
+#define K_RADIX (PROCESS|5)
+#define K_DATA (LAB|PROCESS|6)
+#define K_DATAB (LAB|PROCESS|7)
+#define K_SDATA (LAB|PROCESS|8)
+#define K_SDATAB (LAB|PROCESS|9)
+#define K_SDATAC (LAB|PROCESS|10)
+#define K_SDATAZ (LAB|PROCESS|11)
+#define K_RES (LAB|PROCESS|12)
+#define K_SRES (LAB|PROCESS|13)
+#define K_SRESC (LAB|PROCESS|14)
+#define K_SRESZ (LAB|PROCESS|15)
+#define K_EXPORT (LAB|PROCESS|16)
+#define K_GLOBAL (LAB|PROCESS|17)
+#define K_PRINT (LAB|PROCESS|19)
+#define K_FORM (LAB|PROCESS|20)
+#define K_HEADING (LAB|PROCESS|21)
+#define K_PAGE (LAB|PROCESS|22)
+#define K_IMPORT (LAB|PROCESS|23)
+#define K_PROGRAM (LAB|PROCESS|24)
+#define K_END (PROCESS|25)
+#define K_INCLUDE (PROCESS|26)
+#define K_IGNORED (PROCESS|27)
+#define K_ASSIGNA (PROCESS|28)
+#define K_ASSIGNC (29)
+#define K_AIF (PROCESS|30)
+#define K_AELSE (PROCESS|31)
+#define K_AENDI (PROCESS|32)
+#define K_AREPEAT (PROCESS|33)
+#define K_AENDR (PROCESS|34)
+#define K_AWHILE (35)
+#define K_AENDW (PROCESS|36)
+#define K_EXITM (37)
+#define K_MACRO (PROCESS|38)
+#define K_ENDM (39)
+#define K_ALIGN (PROCESS|LAB|40)
+#define K_ALTERNATE (41)
+#define K_DB (LAB|PROCESS|42)
+#define K_DW (LAB|PROCESS|43)
+#define K_DL (LAB|PROCESS|44)
+#define K_LOCAL (45)
+#define K_IFEQ (PROCESS|46)
+#define K_IFNE (PROCESS|47)
+#define K_IFLT (PROCESS|48)
+#define K_IFLE (PROCESS|49)
+#define K_IFGE (PROCESS|50)
+#define K_IFGT (PROCESS|51)
+#define K_IFC (PROCESS|52)
+#define K_IFNC (PROCESS|53)
+#define K_IRP (PROCESS|54)
+#define K_IRPC (PROCESS|55)
+
+
+struct keyword
{
char *name;
int code;
int extra;
-}
-kinfo[] =
-{
- "EQU", K_EQU, 0,
- "ASSIGN", K_ASSIGN, 0,
- "REG", K_REG, 0,
- "ORG", K_ORG, 0,
- "RADIX", K_RADIX, 0,
- "DATA", K_DATA, 0,
- "DATAB", K_DATAB, 0,
- "SDATA", K_SDATA, 0,
- "SDATAB", K_SDATAB, 0,
- "SDATAZ", K_SDATAZ, 0,
- "SDATAC", K_SDATAC, 0,
- "RES", K_RES, 0,
- "SRES", K_SRES, 0,
- "SRESC", K_SRESC, 0,
- "SRESZ", K_SRESZ, 0,
- "EXPORT", K_EXPORT, 0,
- "GLOBAL", K_GLOBAL, 0,
- "PRINT", K_PRINT, 0,
- "FORM", K_FORM, 0,
- "HEADING", K_HEADING, 0,
- "PAGE", K_PAGE, 0,
- "PROGRAM", K_IGNORED, 0,
- "END", K_END, 0,
- "INCLUDE", K_INCLUDE, 0,
- "ASSIGNA", K_ASSIGNA, 0,
- "ASSIGNC", K_ASSIGNC, 0,
- "AIF", K_AIF, 0,
- "AELSE", K_AELSE, 0,
- "AENDI", K_AENDI, 0,
- "AREPEAT", K_AREPEAT, 0,
- "AENDR", K_AENDR, 0,
- "EXITM", K_EXITM, 0,
- "MACRO", K_MACRO, 0,
- "ENDM", K_ENDM, 0,
- "AWHILE", K_AWHILE, 0,
- "ALIGN", K_ALIGN, 0,
- "AENDW", K_AENDW, 0,
- 0
+};
+
+static struct keyword kinfo[] =
+{
+ { "EQU", K_EQU, 0 },
+ { "ALTERNATE", K_ALTERNATE, 0 },
+ { "ASSIGN", K_ASSIGN, 0 },
+ { "REG", K_REG, 0 },
+ { "ORG", K_ORG, 0 },
+ { "RADIX", K_RADIX, 0 },
+ { "DATA", K_DATA, 0 },
+ { "DB", K_DB, 0 },
+ { "DW", K_DW, 0 },
+ { "DL", K_DL, 0 },
+ { "DATAB", K_DATAB, 0 },
+ { "SDATA", K_SDATA, 0 },
+ { "SDATAB", K_SDATAB, 0 },
+ { "SDATAZ", K_SDATAZ, 0 },
+ { "SDATAC", K_SDATAC, 0 },
+ { "RES", K_RES, 0 },
+ { "SRES", K_SRES, 0 },
+ { "SRESC", K_SRESC, 0 },
+ { "SRESZ", K_SRESZ, 0 },
+ { "EXPORT", K_EXPORT, 0 },
+ { "GLOBAL", K_GLOBAL, 0 },
+ { "PRINT", K_PRINT, 0 },
+ { "FORM", K_FORM, 0 },
+ { "HEADING", K_HEADING, 0 },
+ { "PAGE", K_PAGE, 0 },
+ { "PROGRAM", K_IGNORED, 0 },
+ { "END", K_END, 0 },
+ { "INCLUDE", K_INCLUDE, 0 },
+ { "ASSIGNA", K_ASSIGNA, 0 },
+ { "ASSIGNC", K_ASSIGNC, 0 },
+ { "AIF", K_AIF, 0 },
+ { "AELSE", K_AELSE, 0 },
+ { "AENDI", K_AENDI, 0 },
+ { "AREPEAT", K_AREPEAT, 0 },
+ { "AENDR", K_AENDR, 0 },
+ { "EXITM", K_EXITM, 0 },
+ { "MACRO", K_MACRO, 0 },
+ { "ENDM", K_ENDM, 0 },
+ { "AWHILE", K_AWHILE, 0 },
+ { "ALIGN", K_ALIGN, 0 },
+ { "AENDW", K_AENDW, 0 },
+ { "ALTERNATE", K_ALTERNATE, 0 },
+ { "LOCAL", K_LOCAL, 0 },
+ { NULL, 0, 0 }
+};
+
+/* Although the conditional operators are handled by gas, we need to
+ handle them here as well, in case they are used in a recursive
+ macro to end the recursion. */
+
+static struct keyword mrikinfo[] =
+{
+ { "IFEQ", K_IFEQ, 0 },
+ { "IFNE", K_IFNE, 0 },
+ { "IFLT", K_IFLT, 0 },
+ { "IFLE", K_IFLE, 0 },
+ { "IFGE", K_IFGE, 0 },
+ { "IFGT", K_IFGT, 0 },
+ { "IFC", K_IFC, 0 },
+ { "IFNC", K_IFNC, 0 },
+ { "ELSEC", K_AELSE, 0 },
+ { "ENDC", K_AENDI, 0 },
+ { "MEXIT", K_EXITM, 0 },
+ { "REPT", K_AREPEAT, 0 },
+ { "IRP", K_IRP, 0 },
+ { "IRPC", K_IRPC, 0 },
+ { "ENDR", K_AENDR, 0 },
+ { NULL, 0, 0 }
};
/* Look for a pseudo op on the line. If one's there then call
sb *line;
sb *acc;
{
- char *in = line->ptr + idx;
+ int oidx = idx;
- if (in[0] == '.')
+ if (line->ptr[idx] == '.' || alternate || mri)
{
/* Scan forward and find pseudo name */
+ char *in;
hash_entry *ptr;
- char *s = in + 1;
- char *e = s;
+ char *s;
+ char *e;
+ if (line->ptr[idx] == '.')
+ idx++;
+ in = line->ptr + idx;
+ s = in;
+ e = s;
sb_reset (acc);
- idx++;
+
while (idx < line->len && *e && ISFIRSTCHAR (*e))
{
sb_add_char (acc, *e);
if (!ptr)
{
+#if 0
+ /* This one causes lots of pain when trying to preprocess
+ ordinary code */
WARNING ((stderr, "Unrecognised pseudo op `%s'.\n", sb_name (acc)));
+#endif
return 0;
}
if (ptr->value.i & LAB)
fprintf (outfile, "\t");
}
+ if (mri && ptr->value.i == K_END)
+ {
+ sb t;
+
+ sb_new (&t);
+ sb_add_buffer (&t, line->ptr + oidx, idx - oidx);
+ fprintf (outfile, "\t%s", sb_name (&t));
+ sb_kill (&t);
+ }
+
if (ptr->value.i & PROCESS)
{
/* Polish the rest of the line before handling the pseudo op */
-/* strip_comments(line);*/
+#if 0
+ strip_comments(line);
+#endif
sb_reset (acc);
process_assigns (idx, line, acc);
sb_reset(line);
{
switch (ptr->value.i)
{
+ case K_AIF:
+ do_aif (idx, line);
+ break;
case K_AELSE:
do_aelse ();
break;
{
switch (ptr->value.i)
{
+ case K_ALTERNATE:
+ alternate = 1;
+ macro_init (1, mri, 0, exp_get_abs);
+ return 1;
case K_AELSE:
do_aelse ();
return 1;
case K_RADIX:
do_radix (line);
return 1;
+ case K_DB:
+ do_data (idx, line, 1);
+ return 1;
+ case K_DW:
+ do_data (idx, line, 2);
+ return 1;
+ case K_DL:
+ do_data (idx, line, 4);
+ return 1;
case K_DATA:
- do_data (idx, line);
+ do_data (idx, line, 0);
return 1;
case K_DATAB:
do_datab (idx, line);
case K_INCLUDE:
do_include (idx, line);
return 1;
+ case K_LOCAL:
+ do_local (idx, line);
+ return 1;
case K_MACRO:
do_macro (idx, line);
return 1;
case K_IGNORED:
return 1;
case K_END:
- do_end ();
+ do_end (line);
return 1;
case K_ASSIGNA:
do_assigna (idx, line);
case K_REG:
do_reg (idx, line);
return 1;
+ case K_IFEQ:
+ do_if (idx, line, EQ);
+ return 1;
+ case K_IFNE:
+ do_if (idx, line, NE);
+ return 1;
+ case K_IFLT:
+ do_if (idx, line, LT);
+ return 1;
+ case K_IFLE:
+ do_if (idx, line, LE);
+ return 1;
+ case K_IFGE:
+ do_if (idx, line, GE);
+ return 1;
+ case K_IFGT:
+ do_if (idx, line, GT);
+ return 1;
+ case K_IFC:
+ do_ifc (idx, line, 0);
+ return 1;
+ case K_IFNC:
+ do_ifc (idx, line, 1);
+ return 1;
+ case K_IRP:
+ do_irp (idx, line, 0);
+ return 1;
+ case K_IRPC:
+ do_irp (idx, line, 1);
+ return 1;
}
}
}
+/* Add a keyword to the hash table. */
+
+static void
+add_keyword (name, code)
+ const char *name;
+ int code;
+{
+ sb label;
+ int j;
+
+ sb_new (&label);
+ sb_add_string (&label, name);
+
+ hash_add_to_int_table (&keyword_hash_table, &label, code);
+
+ sb_reset (&label);
+ for (j = 0; name[j]; j++)
+ sb_add_char (&label, name[j] - 'A' + 'a');
+ hash_add_to_int_table (&keyword_hash_table, &label, code);
+
+ sb_kill (&label);
+}
+
/* Build the keyword hash table - put each keyword in the table twice,
once upper and once lower case.*/
int i;
for (i = 0; kinfo[i].name; i++)
+ add_keyword (kinfo[i].name, kinfo[i].code);
+
+ if (mri)
{
- sb label;
- int j;
- sb_new (&label);
- sb_add_string (&label, kinfo[i].name);
+ for (i = 0; mrikinfo[i].name; i++)
+ add_keyword (mrikinfo[i].name, mrikinfo[i].code);
+ }
+}
+
+
+static void
+do_define (string)
+ const char *string;
+{
+ sb label;
+ int res = 1;
+ hash_entry *ptr;
+ sb_new (&label);
- hash_add_to_int_table (&keyword_hash_table, &label, kinfo[i].code);
- sb_reset (&label);
- for (j = 0; kinfo[i].name[j]; j++)
- sb_add_char (&label, kinfo[i].name[j] - 'A' + 'a');
- hash_add_to_int_table (&keyword_hash_table, &label, kinfo[i].code);
+ while (*string)
+ {
+ if (*string == '=')
+ {
+ sb value;
+ sb_new (&value);
+ string++;
+ while (*string)
+ {
+ sb_add_char (&value, *string);
+ string++;
+ }
+ exp_get_abs ("Invalid expression on command line.\n", 0, &value, &res);
+ sb_kill (&value);
+ break;
+ }
+ sb_add_char (&label, *string);
+
+ string ++;
+ }
+
+ ptr = hash_create (&vars, &label);
+ free_old_entry (ptr);
+ ptr->type = hash_integer;
+ ptr->value.i = res;
+ sb_kill (&label);
+}
+char *program_name;
+
+/* The list of long options. */
+static struct option long_options[] =
+{
+ { "alternate", no_argument, 0, 'a' },
+ { "include", required_argument, 0, 'I' },
+ { "commentchar", required_argument, 0, 'c' },
+ { "copysource", no_argument, 0, 's' },
+ { "debug", no_argument, 0, 'd' },
+ { "help", no_argument, 0, 'h' },
+ { "mri", no_argument, 0, 'M' },
+ { "output", required_argument, 0, 'o' },
+ { "print", no_argument, 0, 'p' },
+ { "unreasonable", no_argument, 0, 'u' },
+ { "version", no_argument, 0, 'v' },
+ { "define", required_argument, 0, 'd' },
+ { NULL, no_argument, 0, 0 }
+};
- sb_kill (&label);
- }
+/* Show a usage message and exit. */
+static void
+show_usage (file, status)
+ FILE *file;
+ int status;
+{
+ fprintf (file, "\
+Usage: %s \n\
+ [-a] [--alternate] enter alternate macro mode\n\
+ [-c char] [--commentchar char] change the comment character from !\n\
+ [-d] [--debug] print some debugging info\n\
+ [-h] [--help] print this message\n\
+ [-M] [--mri] enter MRI compatibility mode\n\
+ [-o out] [--output out] set the output file\n\
+ [-p] [--print] print line numbers\n", program_name);
+ fprintf (file, "\
+ [-s] [--copysource] copy source through as comments \n\
+ [-u] [--unreasonable] allow unreasonable nesting\n\
+ [-v] [--version] print the program version\n\
+ [-Dname=value] create preprocessor variable called name, with value\n\
+ [-Ipath] add to include path list\n\
+ [in-file]\n");
+ if (status == 0)
+ exit (status);
+}
+
+/* Display a help message and exit. */
+static void
+show_help ()
+{
+ printf ("%s: Gnu Assembler Macro Preprocessor\n",
+ program_name);
+ show_usage (stdout, 0);
}
int
-main (ac, av)
- int ac;
- char **av;
+main (argc, argv)
+ int argc;
+ char **argv;
{
- int i;
-
+ int opt;
+ char *out_name = 0;
sp = include_stack;
ifstack[0].on = 1;
ifi = 0;
- chartype_init ();
- hash_new_table (101, ¯o_table);
+
+ program_name = argv[0];
+ xmalloc_set_program_name (program_name);
+
hash_new_table (101, &keyword_hash_table);
hash_new_table (101, &assign_hash_table);
hash_new_table (101, &vars);
sb_new (&label);
- process_init ();
- /* Find the output file */
- for (i = 1; i < ac; i++)
+ while ((opt = getopt_long (argc, argv, "I:sdhavc:upo:D:M", long_options,
+ (int *) NULL))
+ != EOF)
{
- if (av[i][0] == '-')
+ switch (opt)
{
- if (av[i][1] == 'c' && av[i][2] == 0)
- {
- copysource = 1;
- }
- else if (av[i][1] == 'p' && av[i][2] == 0)
- {
- print_line_number = 1;
- }
- else if (av[i][1] == 'u' && av[i][2] == 0)
- {
- unreasonable = 1;
- }
- else if (av[i][1] == 's' && av[i][2] == 0)
- {
- stats = 1;
- }
- else if (av[i][1] == 'o' && av[i][2] == 0 & i + 1 < ac)
- {
- /* Got output file name */
- i++;
- outfile = fopen (av[i], "w");
- if (!outfile)
- {
- fprintf (stderr, "%s: Can't open output file `%s'.\n",
- av[0], av[i]);
- exit (1);
- }
- }
- else
- {
- fprintf (stderr, "Usage: %s [-o filename] infile1 infile2...\n",
- av[0]);
- exit (1);
- }
+ case 'o':
+ out_name = optarg;
+ break;
+ case 'u':
+ unreasonable = 1;
+ break;
+ case 'I':
+ {
+ include_path *p = (include_path *) xmalloc (sizeof (include_path));
+ sb_new (&p->path);
+ sb_add_string (&p->path, optarg);
+ if (paths_tail)
+ paths_tail->next = p;
+ else
+ paths_head = p;
+ paths_tail = p;
+ }
+ break;
+ case 'p':
+ print_line_number = 1;
+ break;
+ case 'c':
+ comment_char = optarg[0];
+ break;
+ case 'a':
+ alternate = 1;
+ break;
+ case 's':
+ copysource = 1;
+ break;
+ case 'd':
+ stats = 1;
+ break;
+ case 'D':
+ do_define (optarg);
+ break;
+ case 'M':
+ mri = 1;
+ comment_char = ';';
+ break;
+ case 'h':
+ show_help ();
+ /*NOTREACHED*/
+ case 'v':
+ /* This output is intended to follow the GNU standards document. */
+ printf ("GNU assembler pre-processor %s\n", program_version);
+ printf ("Copyright 1996 Free Software Foundation, Inc.\n");
+ printf ("\
+This program is free software; you may redistribute it under the terms of\n\
+the GNU General Public License. This program has absolutely no warranty.\n");
+ exit (0);
+ /*NOTREACHED*/
+ case 0:
+ break;
+ default:
+ show_usage (stderr, 1);
+ /*NOTREACHED*/
}
}
+ process_init ();
+
+ macro_init (alternate, mri, 0, exp_get_abs);
+
+ if (out_name) {
+ outfile = fopen (out_name, "w");
+ if (!outfile)
+ {
+ fprintf (stderr, "%s: Can't open output file `%s'.\n",
+ program_name, out_name);
+ exit (1);
+ }
+ }
+ else {
+ outfile = stdout;
+ }
+
+ chartype_init ();
if (!outfile)
outfile = stdout;
/* Process all the input files */
- for (i = 1; i < ac; i++)
+ while (optind < argc)
{
- if (av[i][0] == '-')
+ if (new_file (argv[optind]))
{
- if (av[i][1] == 'o')
- i++;
+ process_file ();
}
else
{
- if (new_file (av[i]))
- {
- process_file ();
- }
- else
- {
- fprintf (stderr, "%s: Can't open input file `%s'.\n",
- av[0], av[i]);
- exit (1);
- }
+ fprintf (stderr, "%s: Can't open input file `%s'.\n",
+ program_name, argv[optind]);
+ exit (1);
}
+ optind++;
}
+
quit ();
return 0;
}
+
+/* This function is used because an abort in some of the other files
+ may be compiled into as_abort because they include as.h. */
+
+void
+as_abort (file, line, fn)
+ const char *file, *fn;
+ int line;
+{
+ fprintf (stderr, "Internal error, aborting at %s line %d", file, line);
+ if (fn)
+ fprintf (stderr, " in %s", fn);
+ fprintf (stderr, "\nPlease report this bug.\n");
+ exit (1);
+}