* gasp.c (do_align, get_any_string): Mark as static.
[external/binutils.git] / gas / gasp.c
1 /* gasp.c - Gnu assembler preprocessor main program.
2    Copyright (C) 1994, 1995 Free Software Foundation, Inc.
3
4    Written by Steve and Judy Chamberlain of Cygnus Support,
5       sac@cygnus.com
6
7    This file is part of GASP, the GNU Assembler Preprocessor.
8
9    GASP is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2, or (at your option)
12    any later version.
13
14    GASP is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with GASP; see the file COPYING.  If not, write to the Free
21    Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22    02111-1307, USA. */
23
24 /*
25
26 This program translates the input macros and stuff into a form
27 suitable for gas to consume.
28
29
30   gasp [-sdhau] [-c char] [-o <outfile>] <infile>*
31
32   -s copy source to output
33   -c <char> comments are started with <char> instead of !
34   -u allow unreasonable stuff
35   -p print line numbers
36   -d print debugging stats
37   -s semi colons start comments
38   -a use alternate syntax
39      Pseudo ops can start with or without a .
40      Labels have to be in first column.
41   -I specify include dir
42     Macro arg parameters subsituted by name, don't need the &.
43      String can start with ' too.
44      Strings can be surrounded by <..>
45      A %<exp> in a string evaluates the expression 
46      Literal char in a string with !
47
48
49 */
50
51 #include "config.h"
52
53 #include <stdio.h>
54 #include <string.h>
55 #include <getopt.h>
56 #include <ctype.h>
57
58 #ifdef HAVE_STDLIB_H
59 #include <stdlib.h>
60 #endif
61
62 #ifdef NEED_MALLOC_DECLARATION
63 extern char *malloc ();
64 #endif
65
66 #include "ansidecl.h"
67 #include "libiberty.h"
68
69 char *program_version = "1.2";
70
71 #define MAX_INCLUDES 30         /* Maximum include depth */
72 #define MAX_REASONABLE 1000     /* Maximum number of expansions */
73
74 int unreasonable;               /* -u on command line */
75 int stats;                      /* -d on command line */
76 int print_line_number;          /* -p flag on command line */
77 int copysource;                 /* -c flag on command line */
78 int warnings;                   /* Number of WARNINGs generated so far. */
79 int errors;                     /* Number of ERRORs generated so far. */
80 int fatals;                     /* Number of fatal ERRORs generated so far (either 0 or 1). */
81 int alternate = 0;              /* -a on command line */
82 int mri = 0;                    /* -M on command line */
83 char comment_char = '!';
84 int radix = 10;                 /* Default radix */
85
86 int had_end; /* Seen .END */
87
88 /* The output stream */
89 FILE *outfile;
90
91 /* string blocks
92
93    I had a couple of choices when deciding upon this data structure.
94    gas uses null terminated strings for all its internal work.  This
95    often means that parts of the program that want to examine
96    substrings have to manipulate the data in the string to do the
97    right thing (a common operation is to single out a bit of text by
98    saving away the character after it, nulling it out, operating on
99    the substring and then replacing the character which was under the
100    null).  This is a pain and I remember a load of problems that I had with
101    code in gas which almost got this right.  Also, it's harder to grow and
102    allocate null terminated strings efficiently.
103
104    Obstacks provide all the functionality needed, but are too
105    complicated, hence the sb.
106
107    An sb is allocated by the caller, and is initialzed to point to an
108    sb_element.  sb_elements are kept on a free lists, and used when
109    needed, replaced onto the free list when unused.
110  */
111
112 #define max_power_two    30     /* don't allow strings more than
113                                    2^max_power_two long */
114 /* structure of an sb */
115 typedef struct sb
116   {
117     char *ptr;                  /* points to the current block. */
118     int len;                    /* how much is used. */
119     int pot;                    /* the maximum length is 1<<pot */
120     struct le *item;
121   }
122 sb;
123
124 /* Structure of the free list object of an sb */
125 typedef struct le
126   {
127     struct le *next;
128     int size;
129     char data[1];
130   }
131 sb_element;
132
133 /* The free list */
134 typedef struct
135   {
136     sb_element *size[max_power_two];
137   } sb_list_vector;
138
139 sb_list_vector free_list;
140
141 int string_count[max_power_two];
142
143 /* the attributes of each character are stored as a bit pattern
144    chartype, which gives us quick tests. */
145
146
147 #define FIRSTBIT 1
148 #define NEXTBIT  2
149 #define SEPBIT   4
150 #define WHITEBIT 8
151 #define COMMENTBIT 16
152 #define BASEBIT  32
153 #define ISCOMMENTCHAR(x) (chartype[(unsigned)(x)] & COMMENTBIT)
154 #define ISFIRSTCHAR(x)  (chartype[(unsigned)(x)] & FIRSTBIT)
155 #define ISNEXTCHAR(x)   (chartype[(unsigned)(x)] & NEXTBIT)
156 #define ISSEP(x)        (chartype[(unsigned)(x)] & SEPBIT)
157 #define ISWHITE(x)      (chartype[(unsigned)(x)] & WHITEBIT)
158 #define ISBASE(x)       (chartype[(unsigned)(x)] & BASEBIT)
159 static char chartype[256];
160
161
162 /* Conditional assembly uses the `ifstack'.  Each aif pushes another
163    entry onto the stack, and sets the on flag if it should.  The aelse
164    sets hadelse, and toggles on.  An aend pops a level.  We limit to
165    100 levels of nesting, not because we're facists pigs with read
166    only minds, but because more than 100 levels of nesting is probably
167    a bug in the user's macro structure.  */
168
169 #define IFNESTING 100
170 struct
171   {
172     int on;                     /* is the level being output */
173     int hadelse;                /* has an aelse been seen */
174   }
175 ifstack[IFNESTING];
176 int ifi;
177
178 /* The final and intermediate results of expression evaluation are kept in
179    exp_t's.  Note that a symbol is not an sb, but a pointer into the input
180    line.  It must be coped somewhere safe before the next line is read in. */
181
182 typedef struct
183   {
184     char *name;
185     int len;
186   }
187 symbol;
188
189 typedef struct
190   {
191     int value;                  /* constant part */
192     symbol add_symbol;          /* name part */
193     symbol sub_symbol;          /* name part */
194   }
195 exp_t;
196
197
198 /* Hashing is done in a pretty standard way.  A hash_table has a
199    pointer to a vector of pointers to hash_entrys, and the size of the
200    vector.  A hash_entry contains a union of all the info we like to
201    store in hash table.  If there is a hash collision, hash_entries
202    with the same hash are kept in a chain. */
203
204 /* What the data in a hash_entry means */
205 typedef enum
206   {
207     hash_integer,               /* name->integer mapping */
208     hash_string,                /* name->string mapping */
209     hash_macro,                 /* name is a macro */
210     hash_formal                 /* name is a formal argument */
211   } hash_type;
212
213 typedef struct hs
214   {
215     sb key;                     /* symbol name */
216     hash_type type;             /* symbol meaning */
217     union
218       {
219         sb s;
220         int i;
221         struct macro_struct *m;
222         struct formal_struct *f;
223       } value;
224     struct hs *next;            /* next hash_entry with same hash key */
225   } hash_entry;
226
227 typedef struct
228   {
229     hash_entry **table;
230     int size;
231   } hash_table;
232
233
234 /* Structures used to store macros. 
235
236    Each macro knows its name and included text.  It gets built with a
237    list of formal arguments, and also keeps a hash table which points
238    into the list to speed up formal search.  Each formal knows its
239    name and its default value.  Each time the macro is expanded, the
240    formals get the actual values attatched to them. */
241
242 /* describe the formal arguments to a macro */
243
244 typedef struct formal_struct
245   {
246     struct formal_struct *next; /* next formal in list */
247     sb name;                    /* name of the formal */
248     sb def;                     /* the default value */
249     sb actual;                  /* the actual argument (changed on each expansion) */
250     int index;                  /* the index of the formal 0..formal_count-1 */
251   }
252 formal_entry;
253
254 /* describe the macro. */
255
256 typedef struct macro_struct
257   {
258     sb sub;                     /* substitution text. */
259     int formal_count;           /* number of formal args. */
260     formal_entry *formals;      /* pointer to list of formal_structs */
261     hash_table formal_hash;     /* hash table of formals. */
262   }
263 macro_entry;
264
265 /* how we nest files and expand macros etc.
266
267    we keep a stack of of include_stack structs.  each include file
268    pushes a new level onto the stack.  we keep an sb with a pushback
269    too.  unget chars are pushed onto the pushback sb, getchars first
270    checks the pushback sb before reading from the input stream.
271
272    small things are expanded by adding the text of the item onto the
273    pushback sb.  larger items are grown by pushing a new level and
274    allocating the entire pushback buf for the item.  each time
275    something like a macro is expanded, the stack index is changed. we
276    can then perform an exitm by popping all entries off the stack with
277    the same stack index.  if we're being reasonable, we can detect
278    recusive expansion by checking the index is reasonably small.
279  */
280
281 typedef enum
282   {
283     include_file, include_repeat, include_while, include_macro
284   } include_type;
285
286 struct include_stack
287   {
288     sb pushback;                /* current pushback stream */
289     int pushback_index;         /* next char to read from stream */
290     FILE *handle;               /* open file */
291     sb name;                    /* name of file */
292     int linecount;              /* number of lines read so far */
293     include_type type;
294     int index;                  /* index of this layer */
295   }
296 include_stack[MAX_INCLUDES];
297
298 struct include_stack *sp;
299 #define isp (sp - include_stack)
300
301 #define dsize 5
302
303
304
305 /* Include file list */
306
307 typedef struct include_path 
308 {
309   struct include_path *next;
310   sb path;
311 }  include_path;
312
313 include_path *paths_head;
314 include_path *paths_tail;
315
316
317 static void quit PARAMS ((void));
318 static void sb_build PARAMS ((sb *, int));
319 static void sb_new PARAMS ((sb *));
320 static void sb_kill PARAMS ((sb *));
321 static void sb_add_sb PARAMS ((sb *, sb *));
322 static void sb_check PARAMS ((sb *, int));
323 static void sb_reset PARAMS ((sb *));
324 static void sb_add_char PARAMS ((sb *, int));
325 static void sb_add_string PARAMS ((sb *, const char *));
326 static void sb_add_buffer PARAMS ((sb *, const char *, int));
327 static void sb_print PARAMS ((sb *));
328 static void sb_print_at PARAMS ((int, sb *));
329 static char *sb_name PARAMS ((sb *));
330 static int sb_skip_white PARAMS ((int, sb *));
331 static int sb_skip_comma PARAMS ((int, sb *));
332 static void hash_new_table PARAMS ((int, hash_table *));
333 static int hash PARAMS ((sb *));
334 static hash_entry *hash_create PARAMS ((hash_table *, sb *));
335 static void hash_add_to_string_table PARAMS ((hash_table *, sb *, sb *, int));
336 static void hash_add_to_int_table PARAMS ((hash_table *, sb *, int));
337 static hash_entry *hash_lookup PARAMS ((hash_table *, sb *));
338 static void checkconst PARAMS ((int, exp_t *));
339 static int sb_strtol PARAMS ((int, sb *, int, int *));
340 static int level_0 PARAMS ((int, sb *, exp_t *));
341 static int level_1 PARAMS ((int, sb *, exp_t *));
342 static int level_2 PARAMS ((int, sb *, exp_t *));
343 static int level_3 PARAMS ((int, sb *, exp_t *));
344 static int level_4 PARAMS ((int, sb *, exp_t *));
345 static int level_5 PARAMS ((int, sb *, exp_t *));
346 static int exp_parse PARAMS ((int, sb *, exp_t *));
347 static void exp_string PARAMS ((exp_t *, sb *));
348 static int exp_get_abs PARAMS ((const char *, int, sb *, int *));
349 #if 0
350 static void strip_comments PARAMS ((sb *));
351 #endif
352 static void unget PARAMS ((int));
353 static void include_buf PARAMS ((sb *, sb *, include_type, int));
354 static void include_print_where_line PARAMS ((FILE *));
355 static void include_print_line PARAMS ((FILE *));
356 static int get_line PARAMS ((sb *));
357 static int grab_label PARAMS ((sb *, sb *));
358 static void change_base PARAMS ((int, sb *, sb *));
359 static void do_end PARAMS ((sb *));
360 static void do_assign PARAMS ((int, int, sb *));
361 static void do_radix PARAMS ((sb *));
362 static int get_opsize PARAMS ((int, sb *, int *));
363 static int eol PARAMS ((int, sb *));
364 static void do_data PARAMS ((int, sb *, int));
365 static void do_datab PARAMS ((int, sb *));
366 static void do_align PARAMS ((int, sb *));
367 static void do_res PARAMS ((int, sb *, int));
368 static void do_export PARAMS ((sb *));
369 static void do_print PARAMS ((int, sb *));
370 static void do_heading PARAMS ((int, sb *));
371 static void do_page PARAMS ((void));
372 static void do_form PARAMS ((int, sb *));
373 static int get_any_string PARAMS ((int, sb *, sb *, int, int));
374 static int skip_openp PARAMS ((int, sb *));
375 static int skip_closep PARAMS ((int, sb *));
376 static int dolen PARAMS ((int, sb *, sb *));
377 static int doinstr PARAMS ((int, sb *, sb *));
378 static int dosubstr PARAMS ((int, sb *, sb *));
379 static void process_assigns PARAMS ((int, sb *, sb *));
380 static int get_and_process PARAMS ((int, sb *, sb *));
381 static void process_file PARAMS ((void));
382 static void free_old_entry PARAMS ((hash_entry *));
383 static void do_assigna PARAMS ((int, sb *));
384 static void do_assignc PARAMS ((int, sb *));
385 static void do_reg PARAMS ((int, sb *));
386 static int condass_lookup_name PARAMS ((sb *, int, sb *, int));
387 static int whatcond PARAMS ((int, sb *, int *));
388 static int istrue PARAMS ((int, sb *));
389 static void do_aif PARAMS ((int, sb *));
390 static void do_aelse PARAMS ((void));
391 static void do_aendi PARAMS ((void));
392 static int condass_on PARAMS ((void));
393 static void do_if PARAMS ((int, sb *, int));
394 static int get_mri_string PARAMS ((int, sb *, sb *, int));
395 static void do_ifc PARAMS ((int, sb *, int));
396 static void buffer_and_nest PARAMS ((const char *, const char *, sb *));
397 static void do_aendr PARAMS ((void));
398 static void do_awhile PARAMS ((int, sb *));
399 static void do_aendw PARAMS ((void));
400 static void do_exitm PARAMS ((void));
401 static void do_arepeat PARAMS ((int, sb *));
402 static void do_endm PARAMS ((void));
403 static void do_irp PARAMS ((int, sb *, int));
404 static int do_formals PARAMS ((macro_entry *, int, sb *));
405 static void do_local PARAMS ((int, sb *));
406 static void do_macro PARAMS ((int, sb *));
407 static int get_token PARAMS ((int, sb *, sb *));
408 static int get_apost_token PARAMS ((int, sb *, sb *, int));
409 static int sub_actual
410   PARAMS ((int, sb *, sb *, hash_table *, int, sb *, int));
411 static void macro_expand_body
412   PARAMS ((sb *, sb *, sb *, formal_entry *, hash_table *));
413 static void macro_expand PARAMS ((sb *, int, sb *, macro_entry *));
414 static int macro_op PARAMS ((int, sb *));
415 static int getstring PARAMS ((int, sb *, sb *));
416 static void do_sdata PARAMS ((int, sb *, int));
417 static void do_sdatab PARAMS ((int, sb *));
418 static int new_file PARAMS ((const char *));
419 static void do_include PARAMS ((int, sb *));
420 static void include_pop PARAMS ((void));
421 static int get PARAMS ((void));
422 static int linecount PARAMS ((void));
423 static int include_next_index PARAMS ((void));
424 static void chartype_init PARAMS ((void));
425 static int process_pseudo_op PARAMS ((int, sb *, sb *));
426 static void add_keyword PARAMS ((const char *, int));
427 static void process_init PARAMS ((void));
428 static void do_define PARAMS ((const char *));
429 static void show_usage PARAMS ((FILE *, int));
430 static void show_help PARAMS ((void));
431
432 #define FATAL(x) \
433   do { include_print_where_line (stderr); fprintf x ; fatals++; quit(); } while(0) 
434 #define ERROR(x) \
435   do { include_print_where_line (stderr); fprintf x; errors++; } while(0)
436 #define WARNING(x) \
437   do { include_print_where_line (stderr); fprintf x; warnings++;} while(0) 
438
439
440
441 /* exit the program and return the right ERROR code. */
442 static void
443 quit ()
444 {
445   int exitcode;
446   if (fatals + errors)
447     exitcode = 1;
448   else
449     exitcode = 0;
450
451   if (stats) 
452     {
453       int i;
454       for (i = 0; i < max_power_two; i++) 
455         {
456           fprintf (stderr, "strings size %8d : %d\n", 1<<i, string_count[i]);
457         }
458     }
459   exit (exitcode);
460 }
461
462
463 /* this program is about manipulating strings.
464    they are managed in things called `sb's which is an abbreviation
465    for string buffers.  an sb has to be created, things can be glued
466    on to it, and at the end of it's life it should be freed.  the
467    contents should never be pointed at whilst it is still growing,
468    since it could be moved at any time
469
470    eg:
471    sb_new (&foo);
472    sb_grow... (&foo,...);
473    use foo->ptr[*];
474    sb_kill (&foo);
475
476 */
477
478 /* initializes an sb. */
479
480 static void
481 sb_build (ptr, size)
482      sb *ptr;
483      int size;
484 {
485   /* see if we can find one to allocate */
486   sb_element *e;
487
488   if (size > max_power_two)
489     {
490       FATAL ((stderr, "string longer than %d bytes requested.\n",
491               1 << max_power_two));
492     }
493   e = free_list.size[size];
494   if (!e)
495     {
496       /* nothing there, allocate one and stick into the free list */
497       e = (sb_element *) xmalloc (sizeof (sb_element) + (1 << size));
498       e->next = free_list.size[size];
499       e->size = 1 << size;
500       free_list.size[size] = e;
501       string_count[size]++;
502     }
503
504   /* remove from free list */
505
506   free_list.size[size] = e->next;
507
508   /* copy into callers world */
509   ptr->ptr = e->data;
510   ptr->pot = size;
511   ptr->len = 0;
512   ptr->item = e;
513 }
514
515
516 static void
517 sb_new (ptr)
518      sb *ptr;
519 {
520   sb_build (ptr, dsize);
521 }
522
523 /* deallocate the sb at ptr */
524
525 static
526 void
527 sb_kill (ptr)
528      sb *ptr;
529 {
530   /* return item to free list */
531   ptr->item->next = free_list.size[ptr->pot];
532   free_list.size[ptr->pot] = ptr->item;
533 }
534
535 /* add the sb at s to the end of the sb at ptr */
536
537 static void sb_check ();
538
539 static
540 void
541 sb_add_sb (ptr, s)
542      sb *ptr;
543      sb *s;
544 {
545   sb_check (ptr, s->len);
546   memcpy (ptr->ptr + ptr->len, s->ptr, s->len);
547   ptr->len += s->len;
548 }
549
550 /* make sure that the sb at ptr has room for another len characters,
551    and grow it if it doesn't. */
552
553 static void
554 sb_check (ptr, len)
555      sb *ptr;
556      int len;
557 {
558   if (ptr->len + len >= 1 << ptr->pot)
559     {
560       sb tmp;
561       int pot = ptr->pot;
562       while (ptr->len + len >= 1 << pot)
563         pot++;
564       sb_build (&tmp, pot);
565       sb_add_sb (&tmp, ptr);
566       sb_kill (ptr);
567       *ptr = tmp;
568     }
569 }
570
571 /* make the sb at ptr point back to the beginning.  */
572
573 static void
574 sb_reset (ptr)
575      sb *ptr;
576 {
577   ptr->len = 0;
578 }
579
580 /* add character c to the end of the sb at ptr. */
581
582 static void
583 sb_add_char (ptr, c)
584      sb *ptr;
585      int c;
586 {
587   sb_check (ptr, 1);
588   ptr->ptr[ptr->len++] = c;
589 }
590
591 /* add null terminated string s to the end of sb at ptr. */
592
593 static void
594 sb_add_string (ptr, s)
595      sb *ptr;
596      const char *s;
597 {
598   int len = strlen (s);
599   sb_check (ptr, len);
600   memcpy (ptr->ptr + ptr->len, s, len);
601   ptr->len += len;
602 }
603
604 /* add string at s of length len to sb at ptr */
605
606 static void
607 sb_add_buffer (ptr, s, len)
608      sb *ptr;
609      const char *s;
610      int len;
611 {
612   sb_check (ptr, len);
613   memcpy (ptr->ptr + ptr->len, s, len);
614   ptr->len += len;
615 }
616
617
618 /* print the sb at ptr to the output file */
619
620 static
621 void
622 sb_print (ptr)
623      sb *ptr;
624 {
625   int i;
626   int nc = 0;
627
628   for (i = 0; i < ptr->len; i++)
629     {
630       if (nc)
631         {
632           fprintf (outfile, ",");
633         }
634       fprintf (outfile, "%d", ptr->ptr[i]);
635       nc = 1;
636     }
637 }
638
639 static void 
640 sb_print_at (idx, ptr)
641      int idx;
642      sb *ptr;
643 {
644   int i;
645   for (i = idx; i < ptr->len; i++)
646     putc (ptr->ptr[i], outfile);
647 }
648 /* put a null at the end of the sb at in and return the start of the
649    string, so that it can be used as an arg to printf %s. */
650
651 static
652 char *
653 sb_name (in)
654      sb *in;
655 {
656   /* stick a null on the end of the string */
657   sb_add_char (in, 0);
658   return in->ptr;
659 }
660
661 /* start at the index idx into the string in sb at ptr and skip
662    whitespace. return the index of the first non whitespace character */
663
664 static int
665 sb_skip_white (idx, ptr)
666      int idx;
667      sb *ptr;
668 {
669   while (idx < ptr->len && ISWHITE (ptr->ptr[idx]))
670     idx++;
671   return idx;
672 }
673
674 /* start at the index idx into the sb at ptr. skips whitespace,
675    a comma and any following whitespace. returnes the index of the
676    next character. */
677
678 static int
679 sb_skip_comma (idx, ptr)
680      int idx;
681      sb *ptr;
682 {
683   while (idx < ptr->len && ISWHITE (ptr->ptr[idx]))
684     idx++;
685
686   if (idx < ptr->len
687       && ptr->ptr[idx] == ',')
688     idx++;
689
690   while (idx < ptr->len && ISWHITE (ptr->ptr[idx]))
691     idx++;
692
693   return idx;
694 }
695
696
697 /* hash table maintenance. */
698
699 /* build a new hash table with size buckets, and fill in the info at ptr. */
700
701 static void
702 hash_new_table (size, ptr)
703      int size;
704      hash_table *ptr;
705 {
706   int i;
707   ptr->size = size;
708   ptr->table = (hash_entry **) xmalloc (size * (sizeof (hash_entry *)));
709   /* Fill with null-pointer, not zero-bit-pattern.  */
710   for (i = 0; i < size; i++)
711     ptr->table[i] = 0;
712 }
713
714 /* calculate and return the hash value of the sb at key. */
715
716 static int
717 hash (key)
718      sb *key;
719 {
720   int k = 0x1234;
721   int i;
722   char *p = key->ptr;
723   for (i = 0; i < key->len; i++)
724     {
725       k ^= (k << 2) ^ *p;
726       p++;
727     }
728   return k & 0xf0fff;
729 }
730
731 /* lookup key in hash_table tab, if present, then return it, otherwise
732    build a new one and fill it with hash_integer. */
733
734 static
735 hash_entry *
736 hash_create (tab, key)
737      hash_table *tab;
738      sb *key;
739 {
740   int k = hash (key) % tab->size;
741   hash_entry *p;
742   hash_entry **table = tab->table;
743
744   p = table[k];
745
746   while (1)
747     {
748       if (!p)
749         {
750           hash_entry *n = (hash_entry *) xmalloc (sizeof (hash_entry));
751           n->next = table[k];
752           sb_new (&n->key);
753           sb_add_sb (&n->key, key);
754           table[k] = n;
755           n->type = hash_integer;
756           return n;
757         }
758       if (strncmp (table[k]->key.ptr, key->ptr, key->len) == 0)
759         {
760           return p;
761         }
762       p = p->next;
763     }
764 }
765
766 /* add sb name with key into hash_table tab.  if replacing old value
767    and again, then ERROR. */
768
769 static
770 void
771 hash_add_to_string_table (tab, key, name, again)
772      hash_table *tab;
773      sb *key;
774      sb *name;
775      int again;
776 {
777   hash_entry *ptr = hash_create (tab, key);
778   if (ptr->type == hash_integer)
779     {
780       sb_new (&ptr->value.s);
781     }
782   if (ptr->value.s.len)
783     {
784       if (!again)
785         ERROR ((stderr, "redefintion not allowed"));
786     }
787
788   ptr->type = hash_string;
789   sb_reset (&ptr->value.s);
790   
791   sb_add_sb (&ptr->value.s, name);
792 }
793
794 /* add integer name to hash_table tab with sb key. */
795
796 static
797 void
798 hash_add_to_int_table (tab, key, name)
799      hash_table *tab;
800      sb *key;
801      int name;
802 {
803   hash_entry *ptr = hash_create (tab, key);
804   ptr->value.i = name;
805 }
806
807 /* lookup sb key in hash_table tab.  if found return hash_entry result,
808    else 0. */
809    
810 static
811 hash_entry *
812 hash_lookup (tab, key)
813      hash_table *tab;
814      sb *key;
815 {
816   int k = hash (key) % tab->size;
817   hash_entry **table = tab->table;
818   hash_entry *p = table[k];
819   while (p)
820     {
821       if (p->key.len == key->len
822           && strncmp (p->key.ptr, key->ptr, key->len) == 0)
823         return p;
824       p = p->next;
825     }
826   return 0;
827 }
828
829
830 /* expressions
831
832    are handled in a really simple recursive decent way. each bit of
833    the machine takes an index into an sb and a pointer to an exp_t,
834    modifies the *exp_t and returns the index of the first character
835    past the part of the expression parsed.
836
837  expression precedence:
838   ( )
839  unary + - ~
840   * /
841   + -
842   &
843   | ~
844
845 */
846
847
848 /* make sure that the exp_t at term is constant, if not the give the op ERROR. */
849
850 static
851 void
852 checkconst (op, term)
853      int op;
854      exp_t *term;
855 {
856   if (term->add_symbol.len
857       || term->sub_symbol.len)
858     {
859       ERROR ((stderr, "the %c operator cannot take non-absolute arguments.\n", op));
860     }
861 }
862
863 /* turn the number in string at idx into a number of base,
864    fill in ptr and return the index of the first character not in the
865    number. */
866
867 static
868 int
869 sb_strtol (idx, string, base, ptr)
870      int idx;
871      sb *string;
872      int base;
873      int *ptr;
874 {
875   int value = 0;
876   idx = sb_skip_white (idx, string);
877
878   while (idx < string->len)
879     {
880       int ch = string->ptr[idx];
881       int dig = 0;
882       if (isdigit (ch))
883         dig = ch - '0';
884       else if (ch >= 'a' && ch <= 'f')
885         dig = ch - 'a' + 10;
886       else if (ch >= 'A' && ch <= 'F')
887         dig = ch - 'A' + 10;
888       else
889         break;
890
891       if (dig >= base)
892         break;
893
894       value = value * base + dig;
895       idx++;
896     }
897   *ptr = value;
898   return idx;
899 }
900
901 static int
902 level_0 (idx, string, lhs)
903      int idx;
904      sb *string;
905      exp_t *lhs;
906 {
907   lhs->add_symbol.len = 0;
908   lhs->add_symbol.name = 0;
909
910   lhs->sub_symbol.len = 0;
911   lhs->sub_symbol.name = 0;
912
913   idx = sb_skip_white (idx, string);
914
915   lhs->value = 0;
916
917   if (isdigit (string->ptr[idx]))
918     {
919       idx = sb_strtol (idx, string, 10, &lhs->value);
920     }
921   else if (ISFIRSTCHAR (string->ptr[idx]))
922     {
923       int len = 0;
924       lhs->add_symbol.name = string->ptr + idx;
925       while (idx < string->len && ISNEXTCHAR (string->ptr[idx]))
926         {
927           idx++;
928           len++;
929         }
930       lhs->add_symbol.len = len;
931     }
932   else if (string->ptr[idx] == '"')
933     {
934       sb acc;
935       sb_new (&acc);
936       ERROR ((stderr, "string where expression expected.\n"));
937       idx = getstring (idx, string, &acc);
938       sb_kill (&acc);
939     }
940   else
941     {
942       ERROR ((stderr, "can't find primary in expression.\n"));
943       idx++;
944     }
945   return sb_skip_white (idx, string);
946 }
947
948
949
950 static int
951 level_1 (idx, string, lhs)
952      int idx;
953      sb *string;
954      exp_t *lhs;
955 {
956   idx = sb_skip_white (idx, string);
957
958   switch (string->ptr[idx])
959     {
960     case '+':
961       idx = level_1 (idx + 1, string, lhs);
962       break;
963     case '~':
964       idx = level_1 (idx + 1, string, lhs);
965       checkconst ('~', lhs);
966       lhs->value = ~lhs->value;
967       break;
968     case '-':
969       {
970         symbol t;
971         idx = level_1 (idx + 1, string, lhs);
972         lhs->value = -lhs->value;
973         t = lhs->add_symbol;
974         lhs->add_symbol = lhs->sub_symbol;
975         lhs->sub_symbol = t;
976         break;
977       }
978     case '(':
979       idx++;
980       idx = level_5 (sb_skip_white (idx, string), string, lhs);
981       if (string->ptr[idx] != ')')
982         ERROR ((stderr, "misplaced closing parens.\n"));
983       else
984         idx++;
985       break;
986     default:
987       idx = level_0 (idx, string, lhs);
988       break;
989     }
990   return sb_skip_white (idx, string);
991 }
992
993 static int
994 level_2 (idx, string, lhs)
995      int idx;
996      sb *string;
997      exp_t *lhs;
998 {
999   exp_t rhs;
1000
1001   idx = level_1 (idx, string, lhs);
1002
1003   while (idx < string->len && (string->ptr[idx] == '*'
1004                                || string->ptr[idx] == '/'))
1005     {
1006       char op = string->ptr[idx++];
1007       idx = level_1 (idx, string, &rhs);
1008       switch (op)
1009         {
1010         case '*':
1011           checkconst ('*', lhs);
1012           checkconst ('*', &rhs);
1013           lhs->value *= rhs.value;
1014           break;
1015         case '/':
1016           checkconst ('/', lhs);
1017           checkconst ('/', &rhs);
1018           if (rhs.value == 0)
1019             ERROR ((stderr, "attempt to divide by zero.\n"));
1020           else
1021             lhs->value /= rhs.value;
1022           break;
1023         }
1024     }
1025   return sb_skip_white (idx, string);
1026 }
1027
1028
1029 static int
1030 level_3 (idx, string, lhs)
1031      int idx;
1032      sb *string;
1033      exp_t *lhs;
1034 {
1035   exp_t rhs;
1036
1037   idx = level_2 (idx, string, lhs);
1038
1039   while (idx < string->len
1040          && (string->ptr[idx] == '+'
1041              || string->ptr[idx] == '-'))
1042     {
1043       char op = string->ptr[idx++];
1044       idx = level_2 (idx, string, &rhs);
1045       switch (op)
1046         {
1047         case '+':
1048           lhs->value += rhs.value;
1049           if (lhs->add_symbol.name && rhs.add_symbol.name)
1050             {
1051               ERROR ((stderr, "can't add two relocatable expressions\n"));
1052             }
1053           /* change nn+symbol to symbol + nn */
1054           if (rhs.add_symbol.name)
1055             {
1056               lhs->add_symbol = rhs.add_symbol;
1057             }
1058           break;
1059         case '-':
1060           lhs->value -= rhs.value;
1061           lhs->sub_symbol = rhs.add_symbol;
1062           break;
1063         }
1064     }
1065   return sb_skip_white (idx, string);
1066 }
1067
1068 static int
1069 level_4 (idx, string, lhs)
1070      int idx;
1071      sb *string;
1072      exp_t *lhs;
1073 {
1074   exp_t rhs;
1075
1076   idx = level_3 (idx, string, lhs);
1077
1078   while (idx < string->len &&
1079          string->ptr[idx] == '&')
1080     {
1081       char op = string->ptr[idx++];
1082       idx = level_3 (idx, string, &rhs);
1083       switch (op)
1084         {
1085         case '&':
1086           checkconst ('&', lhs);
1087           checkconst ('&', &rhs);
1088           lhs->value &= rhs.value;
1089           break;
1090         }
1091     }
1092   return sb_skip_white (idx, string);
1093 }
1094
1095 static int
1096 level_5 (idx, string, lhs)
1097      int idx;
1098      sb *string;
1099      exp_t *lhs;
1100 {
1101   exp_t rhs;
1102
1103   idx = level_4 (idx, string, lhs);
1104
1105   while (idx < string->len
1106          && (string->ptr[idx] == '|' || string->ptr[idx] == '~'))
1107     {
1108       char op = string->ptr[idx++];
1109       idx = level_4 (idx, string, &rhs);
1110       switch (op)
1111         {
1112         case '|':
1113           checkconst ('|', lhs);
1114           checkconst ('|', &rhs);
1115           lhs->value |= rhs.value;
1116           break;
1117         case '~':
1118           checkconst ('~', lhs);
1119           checkconst ('~', &rhs);
1120           lhs->value ^= rhs.value;
1121           break;
1122         }
1123     }
1124   return sb_skip_white (idx, string);
1125 }
1126
1127
1128 /* parse the expression at offset idx into string, fill up res with
1129    the result. return the index of the first char past the expression.
1130    */
1131
1132 static int
1133 exp_parse (idx, string, res)
1134      int idx;
1135      sb *string;
1136      exp_t *res;
1137 {
1138   return level_5 (sb_skip_white (idx, string), string, res);
1139 }
1140
1141
1142 /* turn the expression at exp into text and glue it onto the end of
1143    string. */
1144
1145 static void
1146 exp_string (exp, string)
1147      exp_t *exp;
1148      sb *string;
1149 {
1150   int np = 0;
1151   int ad = 0;
1152   sb_reset (string);
1153
1154   if (exp->add_symbol.len)
1155     {
1156       sb_add_buffer (string, exp->add_symbol.name, exp->add_symbol.len);
1157       np = 1;
1158       ad = 1;
1159     }
1160   if (exp->value)
1161     {
1162       char buf[20];
1163       if (np)
1164         sb_add_char (string, '+');
1165       sprintf (buf, "%d", exp->value);
1166       sb_add_string (string, buf);
1167       np = 1;
1168       ad = 1;
1169     }
1170   if (exp->sub_symbol.len)
1171     {
1172       sb_add_char (string, '-');
1173       sb_add_buffer (string, exp->add_symbol.name, exp->add_symbol.len);
1174       np = 0;
1175       ad = 1;
1176     }
1177
1178   if (!ad)
1179     sb_add_char (string, '0');
1180 }
1181
1182
1183 /* parse the expression at offset idx into sb in, return the value in val.  
1184    if the expression is not constant, give ERROR emsg.  returns the index
1185    of the first character past the end of the expression. */
1186
1187 static int
1188 exp_get_abs (emsg, idx, in, val)
1189      const char *emsg;
1190      int idx;
1191      sb *in;
1192      int *val;
1193 {
1194   exp_t res;
1195   idx = exp_parse (idx, in, &res);
1196   if (res.add_symbol.len || res.sub_symbol.len)
1197     ERROR ((stderr, emsg));
1198   *val = res.value;
1199   return idx;
1200 }
1201
1202
1203 sb label; /* current label parsed from line */
1204 hash_table assign_hash_table;   /* hash table for all assigned variables */
1205 hash_table keyword_hash_table;  /* hash table for keyword */
1206 hash_table vars;  /* hash table for  eq variables */
1207
1208 #define in_comment ';'
1209
1210 #if 0
1211 static void
1212 strip_comments (out)
1213      sb *out;
1214 {
1215   char *s = out->ptr;
1216   int i = 0;
1217   for (i = 0; i < out->len; i++)
1218     {
1219       if (ISCOMMENTCHAR(s[i]))
1220         {
1221           out->len = i;
1222           return;
1223         }
1224     }
1225 }
1226 #endif
1227
1228 /* push back character ch so that it can be read again. */
1229
1230 static void
1231 unget (ch)
1232      int ch;
1233 {
1234   if (ch == '\n')
1235     {
1236       sp->linecount--;
1237     }
1238   if (sp->pushback_index)
1239     sp->pushback_index--;
1240   else
1241     sb_add_char (&sp->pushback, ch);
1242 }
1243
1244 /* push the sb ptr onto the include stack, with the given name, type and index. */
1245
1246 static
1247 void
1248 include_buf (name, ptr, type, index)
1249      sb *name;
1250      sb *ptr;
1251      include_type type;
1252      int index;
1253 {
1254   sp++;
1255   if (sp - include_stack >= MAX_INCLUDES)
1256     FATAL ((stderr, "unreasonable nesting.\n"));
1257   sb_new (&sp->name);
1258   sb_add_sb (&sp->name, name);
1259   sp->handle = 0;
1260   sp->linecount = 1;
1261   sp->pushback_index = 0;
1262   sp->type = type;
1263   sp->index = index;
1264   sb_new (&sp->pushback);
1265   sb_add_sb (&sp->pushback, ptr);
1266 }
1267
1268
1269 /* used in ERROR messages, print info on where the include stack is onto file. */
1270 static 
1271 void
1272 include_print_where_line (file)
1273      FILE *file;
1274 {
1275   struct include_stack *p = include_stack + 1;
1276
1277   while (p <= sp)
1278     {
1279       fprintf (file, "%s:%d ", sb_name (&p->name), p->linecount - ((p == sp) ? 1 : 0));
1280       p++;
1281     }
1282 }
1283
1284 /* used in listings, print the line number onto file. */
1285 static void
1286 include_print_line (file)
1287      FILE *file;
1288 {
1289   int n;
1290   struct include_stack *p = include_stack + 1;
1291
1292   n = fprintf (file, "%4d", p->linecount);
1293   p++;
1294   while (p <= sp)
1295     {
1296       n += fprintf (file, ".%d", p->linecount);
1297       p++;
1298     }
1299   while (n < 8 * 3)
1300     {
1301       fprintf (file, " ");
1302       n++;
1303     }
1304 }
1305
1306
1307 /* read a line from the top of the include stack into sb in. */
1308
1309 static int
1310 get_line (in)
1311      sb *in;
1312 {
1313   int online = 0;
1314   int more = 1;
1315
1316   if (copysource)
1317     {
1318       putc (comment_char, outfile);
1319       if (print_line_number)
1320         include_print_line (outfile);
1321     }
1322
1323   while (1)
1324     {
1325       int ch = get ();
1326
1327       while (ch == '\r')
1328         ch = get ();
1329
1330       if (ch == EOF)
1331         {
1332           if (online)
1333             {
1334               WARNING ((stderr, "End of file not at start of line.\n"));
1335               if (copysource)
1336                 putc ('\n', outfile);
1337               ch = '\n';
1338             }
1339           else
1340             more = 0;
1341           break;
1342         }
1343
1344       if (copysource)
1345         {
1346           putc (ch, outfile);
1347         }
1348
1349       if (ch == '\n')
1350         {
1351           ch = get ();
1352           online = 0;
1353           if (ch == '+')
1354             {
1355               /* continued line */
1356               if (copysource)
1357                 {
1358                   putc (comment_char, outfile);
1359                   putc ('+', outfile);
1360                 }
1361               ch = get ();
1362             }
1363           else
1364             {
1365               if (ch != EOF)
1366                 unget (ch);
1367               break;
1368             }
1369         }
1370       else
1371         {
1372           sb_add_char (in, ch);
1373         }
1374       online++;
1375     }
1376
1377   return more;
1378 }
1379
1380 /* find a label from sb in and put it in out. */
1381
1382 static int
1383 grab_label (in, out)
1384      sb *in;
1385      sb *out;
1386 {
1387   int i = 0;
1388   sb_reset (out);
1389   if (ISFIRSTCHAR (in->ptr[i]))
1390     {
1391       sb_add_char (out, in->ptr[i]);
1392       i++;
1393       while ((ISNEXTCHAR (in->ptr[i]) 
1394               || in->ptr[i] == '\\'
1395               || in->ptr[i] == '&') 
1396              && i < in->len)
1397         {
1398           sb_add_char (out, in->ptr[i]);
1399           i++;
1400         }
1401     }
1402   return i;
1403 }
1404
1405 /* find all strange base stuff and turn into decimal. also
1406    find all the other numbers and convert them from the default radix */
1407
1408 static void
1409 change_base (idx, in, out)
1410      int idx;
1411      sb *in;
1412      sb *out;
1413 {
1414   char buffer[20];
1415
1416   while (idx < in->len)
1417     {
1418       if (idx < in->len - 1 && in->ptr[idx + 1] == '\'' && ! mri)
1419         {
1420           int base;
1421           int value;
1422           switch (in->ptr[idx])
1423             {
1424             case 'b':
1425             case 'B':
1426               base = 2;
1427               break;
1428             case 'q':
1429             case 'Q':
1430               base = 8;
1431               break;
1432             case 'h':
1433             case 'H':
1434               base = 16;
1435               break;
1436             case 'd':
1437             case 'D':
1438               base = 10;
1439               break;
1440             default:
1441               ERROR ((stderr, "Illegal base character %c.\n", in->ptr[idx]));
1442               base = 10;
1443               break;
1444             }
1445
1446           idx = sb_strtol (idx + 2, in, base, &value);
1447           sprintf (buffer, "%d", value);
1448           sb_add_string (out, buffer);
1449         }
1450       else if (ISFIRSTCHAR (in->ptr[idx]))
1451         {
1452           /* copy entire names through quickly */
1453           sb_add_char (out, in->ptr[idx]);
1454           idx++;
1455           while (idx < in->len && ISNEXTCHAR (in->ptr[idx]))
1456             {
1457               sb_add_char (out, in->ptr[idx]);
1458               idx++;
1459             }
1460         }
1461       else if (isdigit (in->ptr[idx]))
1462         {
1463           int value;
1464           /* all numbers must start with a digit, let's chew it and
1465              spit out decimal */
1466           idx = sb_strtol (idx, in, radix, &value);
1467           sprintf (buffer, "%d", value);
1468           sb_add_string (out, buffer);
1469
1470           /* skip all undigsested letters */
1471           while (idx < in->len && ISNEXTCHAR (in->ptr[idx]))
1472             {
1473               sb_add_char (out, in->ptr[idx]);
1474               idx++;
1475             }
1476         }
1477       else if (in->ptr[idx] == '"' || in->ptr[idx] == '\'')
1478         {
1479           char tchar = in->ptr[idx];
1480           /* copy entire names through quickly */
1481           sb_add_char (out, in->ptr[idx]);
1482           idx++;
1483           while (idx < in->len && in->ptr[idx] != tchar)
1484             {
1485               sb_add_char (out, in->ptr[idx]);
1486               idx++;
1487             }
1488         }
1489       else
1490         {
1491           /* nothing special, just pass it through */
1492           sb_add_char (out, in->ptr[idx]);
1493           idx++;
1494         }
1495     }
1496
1497 }
1498
1499 /* .end */
1500 static void
1501 do_end (in)
1502      sb *in;
1503 {
1504   had_end = 1;
1505   if (mri)
1506     fprintf (outfile, "%s\n", sb_name (in));
1507 }
1508
1509 /* .assign */
1510
1511 static void
1512 do_assign (again, idx, in)
1513      int again;
1514      int idx;
1515      sb *in;
1516 {
1517   /* stick label in symbol table with following value */
1518   exp_t e;
1519   sb acc;
1520
1521   sb_new (&acc);
1522   idx = exp_parse (idx, in, &e);
1523   exp_string (&e, &acc);
1524   hash_add_to_string_table (&assign_hash_table, &label, &acc, again);
1525   sb_kill (&acc);
1526 }
1527
1528
1529 /* .radix [b|q|d|h] */
1530
1531 static
1532 void
1533 do_radix (ptr)
1534      sb *ptr;
1535 {
1536   int idx = sb_skip_white (0, ptr);
1537   switch (ptr->ptr[idx])
1538     {
1539     case 'B':
1540     case 'b':
1541       radix = 2;
1542       break;
1543     case 'q':
1544     case 'Q':
1545       radix = 8;
1546       break;
1547     case 'd':
1548     case 'D':
1549       radix = 10;
1550       break;
1551     case 'h':
1552     case 'H':
1553       radix = 16;
1554       break;
1555     default:
1556       ERROR ((stderr, "radix is %c must be one of b, q, d or h", radix));
1557     }
1558 }
1559
1560
1561 /* Parse off a .b, .w or .l */
1562
1563 static int
1564 get_opsize (idx, in, size)
1565      int idx;
1566      sb *in;
1567      int *size;
1568 {
1569   *size = 4;
1570   if (in->ptr[idx] == '.')
1571     {
1572       idx++;
1573     }
1574   switch (in->ptr[idx])
1575     {
1576     case 'b':
1577     case 'B':
1578       *size = 1;
1579       break;
1580     case 'w':
1581     case 'W':
1582       *size = 2;
1583       break;
1584     case 'l':
1585     case 'L':
1586       *size = 4;
1587       break;
1588     case ' ':
1589     case '\t':
1590       break;
1591     default:
1592       ERROR ((stderr, "size must be one of b, w or l, is %c.\n", in->ptr[idx]));
1593       break;
1594     }
1595   idx++;
1596
1597   return idx;
1598 }
1599
1600 static 
1601 int eol(idx, line)
1602      int idx;
1603      sb *line;
1604 {
1605   idx = sb_skip_white (idx, line);
1606   if (idx < line->len 
1607       && ISCOMMENTCHAR(line->ptr[idx]))
1608     return 1;
1609   if (idx >= line->len)
1610     return 1;
1611   return 0;
1612 }
1613
1614 /* .data [.b|.w|.l] <data>* 
1615     or d[bwl] <data>* */
1616
1617 static void
1618 do_data (idx, in, size)
1619      int idx;
1620      sb *in;
1621      int size;
1622 {
1623   int opsize = 4;
1624   char *opname = ".yikes!";
1625   sb acc;
1626   sb_new (&acc);
1627
1628   if (!size) 
1629     {
1630       idx = get_opsize (idx, in, &opsize);
1631     }
1632   else {
1633     opsize = size;
1634   }
1635   switch (opsize)
1636     {
1637     case 4:
1638       opname = ".long";
1639       break;
1640     case 2:
1641       opname = ".short";
1642       break;
1643     case 1:
1644       opname = ".byte";
1645       break;
1646     }
1647
1648
1649   fprintf (outfile, "%s\t", opname);
1650
1651   idx =   sb_skip_white (idx, in);
1652
1653   if (alternate 
1654       && idx < in->len 
1655       && in->ptr[idx] == '"')
1656     {
1657       int i;
1658       idx = getstring (idx, in, &acc);
1659       for (i = 0; i < acc.len; i++)
1660         {
1661           if (i)
1662             fprintf(outfile,",");
1663           fprintf (outfile, "%d", acc.ptr[i]);
1664         }
1665     }
1666   else 
1667     {
1668       while (!eol (idx, in))
1669         {
1670           exp_t e;
1671           idx = exp_parse (idx, in, &e);
1672           exp_string (&e, &acc);
1673           sb_add_char (&acc, 0);
1674           fprintf (outfile, acc.ptr);
1675           if (idx < in->len && in->ptr[idx] == ',')
1676             {
1677               fprintf (outfile, ",");
1678               idx++;
1679             }
1680         }
1681     }
1682   sb_kill (&acc);
1683   sb_print_at (idx, in);
1684   fprintf (outfile, "\n");
1685 }
1686
1687 /* .datab [.b|.w|.l] <repeat>,<fill> */
1688
1689 static void
1690 do_datab (idx, in)
1691      int idx;
1692      sb *in;
1693 {
1694   int opsize;
1695   int repeat;
1696   int fill;
1697
1698   idx = get_opsize (idx, in, &opsize);
1699
1700   idx = exp_get_abs ("datab repeat must be constant.\n", idx, in, &repeat);
1701   idx = sb_skip_comma (idx, in);
1702   idx = exp_get_abs ("datab data must be absolute.\n", idx, in, &fill);
1703
1704   fprintf (outfile, ".fill\t%d,%d,%d\n", repeat, opsize, fill);
1705 }
1706
1707 /* .align <size> */
1708
1709 static void
1710 do_align (idx, in)
1711      int idx;
1712      sb *in;
1713 {
1714   int al;
1715   idx = exp_get_abs ("align needs absolute expression.\n", idx, in, &al);
1716
1717   if (al != 1
1718       && al != 2
1719       && al != 4)
1720     WARNING ((stderr, "alignment must be one of 1, 2 or 4.\n"));
1721
1722   fprintf (outfile, ".align     %d\n", al);
1723 }
1724
1725 /* .res[.b|.w|.l] <size> */
1726
1727 static void
1728 do_res (idx, in, type)
1729      int idx;
1730      sb *in;
1731      int type;
1732 {
1733   int size = 4;
1734   int count = 0;
1735
1736   idx = get_opsize (idx, in, &size);
1737   while (!eol(idx, in))
1738     {
1739       idx = sb_skip_white (idx, in);
1740       if (in->ptr[idx] == ',')
1741         idx++;
1742       idx = exp_get_abs ("res needs absolute expression for fill count.\n", idx, in, &count);
1743
1744       if (type == 'c' || type == 'z')
1745         count++;
1746
1747       fprintf (outfile, ".space %d\n", count * size);
1748     }
1749 }
1750
1751
1752 /* .export */
1753
1754 static void
1755 do_export (in)
1756      sb *in;
1757 {
1758   fprintf (outfile, ".global    %s\n", sb_name (in));
1759 }
1760
1761 /* .print [list] [nolist] */
1762
1763 static void
1764 do_print (idx, in)
1765      int idx;
1766      sb *in;
1767 {
1768   idx = sb_skip_white (idx, in);
1769   while (idx < in->len)
1770     {
1771       if (strncasecmp (in->ptr + idx, "LIST", 4) == 0)
1772         {
1773           fprintf (outfile, ".list\n");
1774           idx += 4;
1775         }
1776       else if (strncasecmp (in->ptr + idx, "NOLIST", 6) == 0)
1777         {
1778           fprintf (outfile, ".nolist\n");
1779           idx += 6;
1780         }
1781       idx++;
1782     }
1783 }
1784
1785 /* .head */
1786 static void
1787 do_heading (idx, in)
1788      int idx;
1789      sb *in;
1790 {
1791   sb head;
1792   sb_new (&head);
1793   idx = getstring (idx, in, &head);
1794   fprintf (outfile, ".title     \"%s\"\n", sb_name (&head));
1795   sb_kill (&head);
1796 }
1797
1798 /* .page */
1799
1800 static void
1801 do_page ()
1802 {
1803   fprintf (outfile, ".eject\n");
1804 }
1805
1806 /* .form [lin=<value>] [col=<value>] */
1807 static void
1808 do_form (idx, in)
1809      int idx;
1810      sb *in;
1811 {
1812   int lines = 60;
1813   int columns = 132;
1814   idx = sb_skip_white (idx, in);
1815
1816   while (idx < in->len)
1817     {
1818
1819       if (strncasecmp (in->ptr + idx, "LIN=", 4) == 0)
1820         {
1821           idx += 4;
1822           idx = exp_get_abs ("form LIN= needs absolute expresssion.\n", idx, in, &lines);
1823         }
1824
1825       if (strncasecmp (in->ptr + idx, "COL=", 4) == 0)
1826         {
1827           idx += 4;
1828           idx = exp_get_abs ("form COL= needs absolute expresssion.\n", idx, in, &columns);
1829         }
1830
1831       idx++;
1832     }
1833   fprintf (outfile, ".psize %d,%d\n", lines, columns);
1834
1835 }
1836
1837
1838 /* Fetch string from the input stream,
1839    rules:
1840     'Bxyx<whitespace>   -> return 'Bxyza
1841     %<char>             -> return string of decimal value of x
1842     "<string>"          -> return string
1843     xyx<whitespace>     -> return xyz
1844 */
1845 static int
1846 get_any_string (idx, in, out, expand, pretend_quoted)
1847      int idx;
1848      sb *in;
1849      sb *out;
1850      int expand;
1851      int pretend_quoted;
1852 {
1853   sb_reset (out);
1854   idx = sb_skip_white (idx, in);
1855
1856   if (idx < in->len)
1857     {
1858       if (in->len > 2 && in->ptr[idx+1] == '\'' && ISBASE (in->ptr[idx]))
1859         {
1860           while (!ISSEP (in->ptr[idx]))
1861             sb_add_char (out, in->ptr[idx++]);
1862         }
1863       else if (in->ptr[idx] == '%'
1864                && alternate
1865                && expand)
1866         {
1867           int val;
1868           char buf[20];
1869           /* Turns the next expression into a string */
1870           idx = exp_get_abs ("% operator needs absolute expression",
1871                              idx + 1,
1872                              in,
1873                              &val);
1874           sprintf(buf, "%d", val);
1875           sb_add_string (out, buf);
1876         }
1877       else if (in->ptr[idx] == '"'
1878                || in->ptr[idx] == '<'
1879                || (alternate && in->ptr[idx] == '\''))
1880         {
1881           if (alternate && expand)
1882             {
1883               /* Keep the quotes */
1884               sb_add_char (out,  '\"');
1885                     
1886               idx =  getstring (idx, in, out);
1887               sb_add_char (out,  '\"');
1888
1889             }
1890           else {
1891             idx = getstring (idx, in, out);
1892           }
1893         }
1894       else 
1895         {
1896           while (idx < in->len 
1897                  && (in->ptr[idx] == '"'
1898                      || in->ptr[idx] == '\''
1899                      || pretend_quoted 
1900                      || !ISSEP (in->ptr[idx])))
1901             {
1902               if (in->ptr[idx] == '"' 
1903                   || in->ptr[idx] == '\'')
1904                 {
1905                   char tchar = in->ptr[idx];
1906                   sb_add_char (out, in->ptr[idx++]);
1907                   while (idx < in->len
1908                          && in->ptr[idx] != tchar)
1909                     sb_add_char (out, in->ptr[idx++]);              
1910                   if (idx == in->len)
1911                     return idx;       
1912                 }
1913               sb_add_char (out, in->ptr[idx++]);
1914             }
1915         }
1916     }
1917
1918   return idx;
1919 }
1920
1921
1922 /* skip along sb in starting at idx, suck off whitespace a ( and more
1923    whitespace.  return the idx of the next char */
1924
1925 static int
1926 skip_openp (idx, in)
1927      int idx;
1928      sb *in;
1929 {
1930   idx = sb_skip_white (idx, in);
1931   if (in->ptr[idx] != '(')
1932     ERROR ((stderr, "misplaced ( .\n"));
1933   idx = sb_skip_white (idx + 1, in);
1934   return idx;
1935 }
1936
1937 /* skip along sb in starting at idx, suck off whitespace a ) and more
1938    whitespace.  return the idx of the next char */
1939
1940 static int
1941 skip_closep (idx, in)
1942      int idx;
1943      sb *in;
1944 {
1945   idx = sb_skip_white (idx, in);
1946   if (in->ptr[idx] != ')')
1947     ERROR ((stderr, "misplaced ).\n"));
1948   idx = sb_skip_white (idx + 1, in);
1949   return idx;
1950 }
1951
1952 /* .len */
1953
1954 static int
1955 dolen (idx, in, out)
1956      int idx;
1957      sb *in;
1958      sb *out;
1959 {
1960
1961   sb stringout;
1962   char buffer[10];
1963
1964   sb_new (&stringout);
1965   idx = skip_openp (idx, in);
1966   idx = get_and_process (idx, in, &stringout);
1967   idx = skip_closep (idx, in);
1968   sprintf (buffer, "%d", stringout.len);
1969   sb_add_string (out, buffer);
1970
1971   sb_kill (&stringout);
1972   return idx;
1973 }
1974
1975
1976 /* .instr */
1977
1978 static
1979 int
1980 doinstr (idx, in, out)
1981      int idx;
1982      sb *in;
1983      sb *out;
1984 {
1985   sb string;
1986   sb search;
1987   int i;
1988   int start;
1989   int res;
1990   char buffer[10];
1991
1992   sb_new (&string);
1993   sb_new (&search);
1994   idx = skip_openp (idx, in);
1995   idx = get_and_process (idx, in, &string);
1996   idx = sb_skip_comma (idx, in);
1997   idx = get_and_process (idx, in, &search);
1998   idx = sb_skip_comma (idx, in);
1999   if (isdigit (in->ptr[idx]))
2000     {
2001       idx = exp_get_abs (".instr needs absolute expresson.\n", idx, in, &start);
2002     }
2003   else
2004     {
2005       start = 0;
2006     }
2007   idx = skip_closep (idx, in);
2008   res = -1;
2009   for (i = start; i < string.len; i++)
2010     {
2011       if (strncmp (string.ptr + i, search.ptr, search.len) == 0)
2012         {
2013           res = i;
2014           break;
2015         }
2016     }
2017   sprintf (buffer, "%d", res);
2018   sb_add_string (out, buffer);
2019   sb_kill (&string);
2020   sb_kill (&search);
2021   return idx;
2022 }
2023
2024
2025 static int
2026 dosubstr (idx, in, out)
2027      int idx;
2028      sb *in;
2029      sb *out;
2030 {
2031   sb string;
2032   int pos;
2033   int len;
2034   sb_new (&string);
2035
2036   idx = skip_openp (idx, in);
2037   idx = get_and_process (idx, in, &string);
2038   idx = sb_skip_comma (idx, in);
2039   idx = exp_get_abs ("need absolute position.\n", idx, in, &pos);
2040   idx = sb_skip_comma (idx, in);
2041   idx = exp_get_abs ("need absolute length.\n", idx, in, &len);
2042   idx = skip_closep (idx, in);
2043
2044
2045   if (len < 0 || pos < 0 ||
2046       pos > string.len
2047       || pos + len > string.len)
2048     {
2049       sb_add_string (out, " ");
2050     }
2051   else 
2052     {
2053       sb_add_char (out, '"');
2054       while (len > 0)
2055         {
2056           sb_add_char (out, string.ptr[pos++]);
2057           len--;
2058         }
2059       sb_add_char (out, '"');
2060     }
2061   sb_kill(&string);
2062   return idx;
2063 }
2064
2065 /* scan line, change tokens in the hash table to their replacements */
2066 static void
2067 process_assigns (idx, in, buf)
2068      int idx;
2069      sb *in;
2070      sb *buf;
2071 {
2072   while (idx < in->len)
2073     {
2074       hash_entry *ptr;
2075       if (in->ptr[idx] == '\\'
2076           && in->ptr[idx + 1] == '&')
2077         {
2078           idx = condass_lookup_name (in, idx + 2, buf, 1);
2079         }
2080       else if (in->ptr[idx] == '\\'
2081                && in->ptr[idx + 1] == '$')
2082         {
2083           idx = condass_lookup_name (in, idx + 2, buf, 0);
2084         }
2085       else if (idx + 3 < in->len
2086                && in->ptr[idx] == '.'
2087                && toupper ((unsigned char) in->ptr[idx + 1]) == 'L'
2088                && toupper ((unsigned char) in->ptr[idx + 2]) == 'E'
2089                && toupper ((unsigned char) in->ptr[idx + 3]) == 'N')
2090         idx = dolen (idx + 4, in, buf);
2091       else if (idx + 6 < in->len
2092                && in->ptr[idx] == '.'
2093                && toupper ((unsigned char) in->ptr[idx + 1]) == 'I'
2094                && toupper ((unsigned char) in->ptr[idx + 2]) == 'N'
2095                && toupper ((unsigned char) in->ptr[idx + 3]) == 'S'
2096                && toupper ((unsigned char) in->ptr[idx + 4]) == 'T'
2097                && toupper ((unsigned char) in->ptr[idx + 5]) == 'R')
2098         idx = doinstr (idx + 6, in, buf);
2099       else if (idx + 7 < in->len
2100                && in->ptr[idx] == '.'
2101                && toupper ((unsigned char) in->ptr[idx + 1]) == 'S'
2102                && toupper ((unsigned char) in->ptr[idx + 2]) == 'U'
2103                && toupper ((unsigned char) in->ptr[idx + 3]) == 'B'
2104                && toupper ((unsigned char) in->ptr[idx + 4]) == 'S'
2105                && toupper ((unsigned char) in->ptr[idx + 5]) == 'T'
2106                && toupper ((unsigned char) in->ptr[idx + 6]) == 'R')
2107         idx = dosubstr (idx + 7, in, buf);
2108       else if (ISFIRSTCHAR (in->ptr[idx]))
2109         {
2110           /* may be a simple name subsitution, see if we have a word */
2111           sb acc;
2112           int cur = idx + 1;
2113           while (cur < in->len
2114                  && (ISNEXTCHAR (in->ptr[cur])))
2115             cur++;
2116
2117           sb_new (&acc);
2118           sb_add_buffer (&acc, in->ptr + idx, cur - idx);
2119           ptr = hash_lookup (&assign_hash_table, &acc);
2120           if (ptr)
2121             {
2122               /* Found a definition for it */
2123               sb_add_sb (buf, &ptr->value.s);
2124             }
2125           else
2126             {
2127               /* No definition, just copy the word */
2128               sb_add_sb (buf, &acc);
2129             }
2130           sb_kill (&acc);
2131           idx = cur;
2132         }
2133       else
2134         {
2135           sb_add_char (buf, in->ptr[idx++]);
2136         }
2137     }
2138 }
2139
2140 static int
2141 get_and_process (idx, in, out)
2142      int idx;
2143      sb *in;
2144      sb *out;
2145 {
2146   sb t;
2147   sb_new (&t);
2148   idx = get_any_string (idx, in, &t, 1, 0);
2149   process_assigns (0, &t, out);
2150   sb_kill (&t);
2151   return idx;
2152 }
2153
2154 static
2155 void
2156 process_file ()
2157 {
2158   sb line;
2159   sb t1, t2;
2160   sb acc;
2161   sb label_in;
2162   int more;
2163
2164   sb_new (&line);
2165   sb_new (&t1);
2166   sb_new (&t2);
2167   sb_new(&acc);
2168   sb_new (&label_in);
2169   sb_reset (&line);
2170   more = get_line (&line);
2171   while (more)
2172     {
2173       /* Find any label and pseudo op that we're intested in */
2174       int l;
2175       if (line.len == 0)
2176         {
2177           if (condass_on ())
2178             fprintf (outfile, "\n");
2179         }
2180       else
2181         {
2182           l = grab_label (&line, &label_in);
2183           sb_reset (&label);              
2184           if (label_in.len)
2185             {
2186               /* Munge any label */
2187
2188               
2189               process_assigns (0, &label_in, &label);
2190             }
2191
2192           if (line.ptr[l] == ':')
2193             l++;
2194           while (ISWHITE (line.ptr[l]) && l < line.len)
2195             l++;
2196
2197           if (l < line.len)
2198             {
2199               if (process_pseudo_op (l, &line, &acc))
2200                 {
2201
2202
2203
2204                 }
2205               else if (condass_on ())
2206                 {
2207                   if (macro_op (l, &line))
2208                     {
2209
2210
2211                     }
2212                   else
2213                     {
2214                       {
2215                         if (label.len)
2216                           {
2217                             fprintf (outfile, "%s:\t", sb_name (&label));
2218                           }
2219                         else
2220                           fprintf (outfile, "\t");
2221                         sb_reset(&t1);
2222                         process_assigns (l, &line, &t1);
2223                         sb_reset (&t2);
2224                         change_base (0, &t1, &t2);
2225                         fprintf (outfile, "%s\n", sb_name (&t2));
2226                       }
2227                     }
2228                 }
2229             }
2230           else {
2231             /* Only a label on this line */
2232             if (label.len && condass_on())
2233               {
2234                 fprintf (outfile, "%s:\n", sb_name (&label));
2235               }
2236           }
2237         }
2238
2239       if (had_end)
2240         break;
2241       sb_reset (&line);
2242       more = get_line (&line);
2243     }
2244
2245   if (!had_end && !mri)
2246     WARNING ((stderr, "END missing from end of file.\n"));
2247 }
2248
2249
2250
2251
2252
2253 static void
2254 free_old_entry (ptr)
2255      hash_entry *ptr;
2256 {
2257   if (ptr)
2258     {
2259       if (ptr->type == hash_string)
2260         sb_kill(&ptr->value.s);
2261     }
2262 }
2263
2264 /* name: .ASSIGNA <value> */
2265
2266 static void
2267 do_assigna (idx, in)
2268      int idx;
2269      sb *in;
2270 {
2271   sb tmp;
2272   int val;
2273   sb_new (&tmp);
2274
2275   process_assigns (idx, in, &tmp);
2276   idx = exp_get_abs (".ASSIGNA needs constant expression argument.\n", 0, &tmp, &val);
2277
2278   if (!label.len)
2279     {
2280       ERROR ((stderr, ".ASSIGNA without label.\n"));
2281     }
2282   else
2283     {
2284       hash_entry *ptr = hash_create (&vars, &label);
2285       free_old_entry (ptr);
2286       ptr->type = hash_integer;
2287       ptr->value.i = val;
2288     }
2289   sb_kill (&tmp);
2290 }
2291
2292 /* name: .ASSIGNC <string> */
2293
2294 static void
2295 do_assignc (idx, in)
2296      int idx;
2297      sb *in;
2298 {
2299   sb acc;
2300   sb_new (&acc);
2301   idx = getstring (idx, in, &acc);
2302
2303   if (!label.len)
2304     {
2305       ERROR ((stderr, ".ASSIGNS without label.\n"));
2306     }
2307   else
2308     {
2309       hash_entry *ptr = hash_create (&vars, &label);
2310       free_old_entry (ptr);
2311       ptr->type = hash_string;
2312       sb_new (&ptr->value.s);
2313       sb_add_sb (&ptr->value.s, &acc);
2314     }
2315   sb_kill (&acc);
2316 }
2317
2318
2319 /* name: .REG (reg) */
2320
2321 static void
2322 do_reg (idx, in)
2323      int idx;
2324      sb *in;
2325 {
2326   /* remove reg stuff from inside parens */
2327   sb what;
2328   idx = skip_openp (idx, in);
2329   sb_new (&what);
2330   while (idx < in->len && in->ptr[idx] != ')')
2331     {
2332       sb_add_char (&what, in->ptr[idx]);
2333       idx++;
2334     }
2335   hash_add_to_string_table (&assign_hash_table, &label, &what, 1);
2336   sb_kill (&what);
2337 }
2338
2339
2340 static int
2341 condass_lookup_name (inbuf, idx, out, warn)
2342      sb *inbuf;
2343      int idx;
2344      sb *out;
2345      int warn;
2346 {
2347   hash_entry *ptr;
2348   sb condass_acc;
2349   sb_new (&condass_acc);
2350
2351   while (idx < inbuf->len
2352          && ISNEXTCHAR (inbuf->ptr[idx]))
2353     {
2354       sb_add_char (&condass_acc, inbuf->ptr[idx++]);
2355     }
2356
2357   if (inbuf->ptr[idx] == '\'')
2358     idx++;
2359   ptr = hash_lookup (&vars, &condass_acc);
2360
2361
2362   if (!ptr)
2363     {
2364       if (warn) 
2365         {
2366           WARNING ((stderr, "Can't find preprocessor variable %s.\n", sb_name (&condass_acc)));
2367         }
2368       else 
2369         {
2370           sb_add_string (out, "0");
2371         }
2372     }
2373   else
2374     {
2375       if (ptr->type == hash_integer)
2376         {
2377           char buffer[30];
2378           sprintf (buffer, "%d", ptr->value.i);
2379           sb_add_string (out, buffer);
2380         }
2381       else
2382         {
2383           sb_add_sb (out, &ptr->value.s);
2384         }
2385     }
2386   sb_kill (&condass_acc);
2387   return idx;
2388 }
2389
2390 #define EQ 1
2391 #define NE 2
2392 #define GE 3
2393 #define LT 4
2394 #define LE 5
2395 #define GT 6
2396 #define NEVER 7
2397
2398 static int
2399 whatcond (idx, in, val)
2400      int idx;
2401      sb *in;
2402      int *val;
2403 {
2404   int cond;
2405
2406   idx = sb_skip_white (idx, in);
2407   cond = NEVER;
2408   if (idx + 1 < in->len)
2409     {
2410       char *p;
2411       char a, b;
2412
2413       p = in->ptr + idx;
2414       a = toupper ((unsigned char) p[0]);
2415       b = toupper ((unsigned char) p[1]);
2416       if (a == 'E' && b == 'Q')
2417         cond = EQ;
2418       else if (a == 'N' && b == 'E')
2419         cond = NE;
2420       else if (a == 'L' && b == 'T')
2421         cond = LT;
2422       else if (a == 'L' && b == 'E')
2423         cond = LE;
2424       else if (a == 'G' && b == 'T')
2425         cond = GT;
2426       else if (a == 'G' && b == 'E')
2427         cond = GE;
2428     }
2429   if (cond == NEVER)
2430     {
2431       ERROR ((stderr, "Comparison operator must be one of EQ, NE, LT, LE, GT or GE.\n"));
2432       cond = NEVER;
2433     }
2434   idx = sb_skip_white (idx + 2, in);
2435   *val = cond;
2436   return idx;
2437 }
2438
2439 static int
2440 istrue (idx, in)
2441      int idx;
2442      sb *in;
2443 {
2444   int res;
2445   sb acc_a;
2446   sb cond;
2447   sb acc_b;
2448   sb_new (&acc_a);
2449   sb_new (&cond);
2450   sb_new (&acc_b);
2451   idx = sb_skip_white (idx, in);
2452
2453   if (in->ptr[idx] == '"')
2454     {
2455       int cond;
2456       int same;
2457       /* This is a string comparision */
2458       idx = getstring (idx, in, &acc_a);
2459       idx = whatcond (idx, in, &cond);
2460       idx = getstring (idx, in, &acc_b);
2461       same = acc_a.len == acc_b.len && (strncmp (acc_a.ptr, acc_b.ptr, acc_a.len) == 0);
2462
2463       if (cond != EQ && cond != NE)
2464         {
2465           ERROR ((stderr, "Comparison operator for strings must be EQ or NE\n"));
2466           res = 0;
2467         }
2468       else
2469         res = (cond != EQ) ^ same;
2470     }
2471   else
2472     /* This is a numeric expression */
2473     {
2474       int vala;
2475       int valb;
2476       int cond;
2477       idx = exp_get_abs ("Conditional operator must have absolute operands.\n", idx, in, &vala);
2478       idx = whatcond (idx, in, &cond);
2479       idx = sb_skip_white (idx, in);
2480       if (in->ptr[idx] == '"')
2481         {
2482           WARNING ((stderr, "String compared against expression.\n"));
2483           res = 0;
2484         }
2485       else
2486         {
2487           idx = exp_get_abs ("Conditional operator must have absolute operands.\n", idx, in, &valb);
2488           switch (cond)
2489             {
2490             default:
2491               res = 42;
2492               break;
2493             case EQ:
2494               res = vala == valb;
2495               break;
2496             case NE:
2497               res = vala != valb;
2498               break;
2499             case LT:
2500               res = vala < valb;
2501               break;
2502             case LE:
2503               res = vala <= valb;
2504               break;
2505             case GT:
2506               res = vala > valb;
2507               break;
2508             case GE:
2509               res = vala >= valb;
2510               break;
2511             case NEVER:
2512               res = 0;
2513               break;
2514             }
2515         }
2516     }
2517
2518   sb_kill (&acc_a);
2519   sb_kill (&cond);
2520   sb_kill (&acc_b);
2521   return res;
2522 }
2523
2524 /* .AIF */
2525 static void
2526 do_aif (idx, in)
2527      int idx;
2528      sb *in;
2529 {
2530   if (ifi >= IFNESTING)
2531     {
2532       FATAL ((stderr, "AIF nesting unreasonable.\n"));
2533     }
2534   ifi++;
2535   ifstack[ifi].on = ifstack[ifi-1].on ? istrue (idx, in) : 0;
2536   ifstack[ifi].hadelse = 0;
2537 }
2538
2539
2540 /* .AELSE */
2541 static void
2542 do_aelse ()
2543 {
2544   ifstack[ifi].on = ifstack[ifi-1].on ? !ifstack[ifi].on : 0;
2545   if (ifstack[ifi].hadelse)
2546     {
2547       ERROR ((stderr, "Multiple AELSEs in AIF.\n"));
2548     }
2549   ifstack[ifi].hadelse = 1;
2550 }
2551
2552
2553 /* .AENDI */
2554 static void
2555 do_aendi ()
2556 {
2557   if (ifi != 0)
2558     {
2559       ifi--;
2560     }
2561   else
2562     {
2563       ERROR ((stderr, "AENDI without AIF.\n"));
2564     }
2565 }
2566
2567 static int
2568 condass_on ()
2569 {
2570   return ifstack[ifi].on;
2571 }
2572
2573 /* MRI IFEQ, IFNE, IFLT, IFLE, IFGE, IFGT.  */
2574
2575 static void
2576 do_if (idx, in, cond)
2577      int idx;
2578      sb *in;
2579      int cond;
2580 {
2581   int val;
2582   int res;
2583
2584   if (ifi >= IFNESTING)
2585     {
2586       FATAL ((stderr, "IF nesting unreasonable.\n"));
2587     }
2588
2589   idx = exp_get_abs ("Conditional operator must have absolute operands.\n",
2590                      idx, in, &val);
2591   switch (cond)
2592     {
2593     default:
2594     case EQ: res = val == 0; break;
2595     case NE: res = val != 0; break;
2596     case LT: res = val <  0; break;
2597     case LE: res = val <= 0; break;
2598     case GE: res = val >= 0; break;
2599     case GT: res = val >  0; break;
2600     }
2601
2602   ifi++;
2603   ifstack[ifi].on = ifstack[ifi-1].on ? res: 0;
2604   ifstack[ifi].hadelse = 0;
2605 }
2606
2607 /* Get a string for the MRI IFC or IFNC pseudo-ops.  */
2608
2609 static int
2610 get_mri_string (idx, in, val, terminator)
2611      int idx;
2612      sb *in;
2613      sb *val;
2614      int terminator;
2615 {
2616   idx = sb_skip_white (idx, in);
2617
2618   if (idx < in->len
2619       && in->ptr[idx] == '\'')
2620     {
2621       sb_add_char (val, '\'');
2622       for (++idx; idx < in->len; ++idx)
2623         {
2624           sb_add_char (val, in->ptr[idx]);
2625           if (in->ptr[idx] == '\'')
2626             {
2627               ++idx;
2628               if (idx >= in->len
2629                   || in->ptr[idx] != '\'')
2630                 break;
2631             }
2632         }
2633       idx = sb_skip_white (idx, in);
2634     }
2635   else
2636     {
2637       int i;
2638
2639       while (idx < in->len
2640              && in->ptr[idx] != terminator)
2641         {
2642           sb_add_char (val, in->ptr[idx]);
2643           ++idx;
2644         }
2645       i = val->len - 1;
2646       while (i >= 0 && ISWHITE (val->ptr[i]))
2647         --i;
2648       val->len = i + 1;
2649     }
2650
2651   return idx;
2652 }
2653
2654 /* MRI IFC, IFNC.  */
2655
2656 static void
2657 do_ifc (idx, in, ifnc)
2658      int idx;
2659      sb *in;
2660      int ifnc;
2661 {
2662   sb first;
2663   sb second;
2664   int res;
2665
2666   if (ifi >= IFNESTING)
2667     {
2668       FATAL ((stderr, "IF nesting unreasonable.\n"));
2669     }
2670
2671   sb_new (&first);
2672   sb_new (&second);
2673
2674   idx = get_mri_string (idx, in, &first, ',');
2675
2676   if (idx >= in->len || in->ptr[idx] != ',')
2677     {
2678       ERROR ((stderr, "Bad format for IF or IFNC.\n"));
2679       return;
2680     }
2681
2682   idx = get_mri_string (idx + 1, in, &second, ';');
2683
2684   res = (first.len == second.len
2685          && strncmp (first.ptr, second.ptr, first.len) == 0);
2686   res ^= ifnc;
2687
2688   ifi++;
2689   ifstack[ifi].on = ifstack[ifi-1].on ? res : 0;
2690   ifstack[ifi].hadelse = 0;
2691 }
2692
2693 /* Read input lines till we get to a TO string.
2694    Increase nesting depth if we geta FROM string.
2695    Put the results into sb at PTR. */
2696
2697 static void
2698 buffer_and_nest (from, to, ptr)
2699      const char *from;
2700      const char *to;
2701      sb *ptr;
2702 {
2703   int from_len = strlen (from);
2704   int to_len = strlen (to);
2705   int depth = 1;
2706   int line_start = ptr->len;
2707   int line = linecount ();
2708
2709   int more = get_line (ptr);
2710
2711   while (more)
2712     {
2713       /* Try and find the first pseudo op on the line */
2714       int i = line_start;
2715
2716       if (!alternate && !mri)
2717         {
2718           /* With normal syntax we can suck what we want till we get
2719              to the dot.  With the alternate, labels have to start in
2720              the first column, since we cant tell what's a label and
2721              whats a pseudoop */
2722
2723           /* Skip leading whitespace */
2724           while (i < ptr->len
2725                  && ISWHITE (ptr->ptr[i]))
2726             i++;
2727
2728           /* Skip over a label */
2729           while (i < ptr->len
2730                  && ISNEXTCHAR (ptr->ptr[i]))
2731             i++;
2732
2733           /* And a colon */
2734           if (i < ptr->len
2735               && ptr->ptr[i] == ':')
2736             i++;
2737
2738         }
2739       /* Skip trailing whitespace */
2740       while (i < ptr->len
2741              && ISWHITE (ptr->ptr[i]))
2742         i++;
2743
2744       if (i < ptr->len && (ptr->ptr[i] == '.' 
2745                            || alternate
2746                            || mri))
2747         {
2748           if (ptr->ptr[i] == '.')
2749               i++;
2750           if (strncasecmp (ptr->ptr + i, from, from_len) == 0)
2751             depth++;
2752           if (strncasecmp (ptr->ptr + i, to, to_len) == 0)
2753             {
2754               depth--;
2755               if (depth == 0)
2756                 {
2757                   /* Reset the string to not include the ending rune */
2758                   ptr->len = line_start;
2759                   break;
2760                 }
2761             }
2762         }
2763
2764       /* Add a CR to the end and keep running */
2765       sb_add_char (ptr, '\n');
2766       line_start = ptr->len;
2767       more = get_line (ptr);
2768     }
2769
2770
2771   if (depth)
2772     FATAL ((stderr, "End of file whilst inside %s, started on line %d.\n", from, line));
2773 }
2774
2775
2776 /* .ENDR */
2777 static void
2778 do_aendr ()
2779 {
2780   if (!mri)
2781     ERROR ((stderr, "AENDR without a AREPEAT.\n"));
2782   else
2783     ERROR ((stderr, "ENDR without a REPT.\n"));
2784 }
2785
2786 /* .AWHILE */
2787
2788 static
2789 void
2790 do_awhile (idx, in)
2791      int idx;
2792      sb *in;
2793 {
2794   sb exp;
2795
2796   sb sub;
2797
2798   int doit;
2799   sb_new (&sub);
2800   sb_new (&exp);
2801
2802   process_assigns (idx, in, &exp);
2803   doit = istrue (0, &exp);
2804
2805   buffer_and_nest ("AWHILE", "AENDW", &sub);
2806
2807   /* Turn
2808         .AWHILE exp
2809              foo
2810         .AENDW
2811      into
2812         foo
2813         .AWHILE exp
2814         foo
2815         .ENDW
2816    */
2817
2818   if (doit)
2819     {
2820       int index = include_next_index ();
2821
2822       sb copy;
2823       sb_new (&copy);
2824       sb_add_sb (&copy, &sub);
2825       sb_add_sb (&copy, in);
2826       sb_add_string (&copy, "\n");
2827       sb_add_sb (&copy, &sub);
2828       sb_add_string (&copy, "\t.AENDW\n");
2829       /* Push another WHILE */
2830       include_buf (&exp, &copy, include_while, index);
2831       sb_kill (&copy);
2832     }
2833   sb_kill (&exp);
2834   sb_kill (&sub);
2835 }
2836
2837
2838 /* .AENDW */
2839
2840 static void
2841 do_aendw ()
2842 {
2843   ERROR ((stderr, "AENDW without a AENDW.\n"));
2844 }
2845
2846
2847 /* .EXITM
2848    
2849    Pop things off the include stack until the type and index changes */
2850
2851 static void
2852 do_exitm ()
2853 {
2854   include_type type = sp->type;
2855   if (type == include_repeat
2856       || type == include_while
2857       || type == include_macro)
2858     {
2859       int index = sp->index;
2860       include_pop ();
2861       while (sp->index == index
2862              && sp->type == type)
2863         {
2864           include_pop ();
2865         }
2866     }
2867 }
2868
2869 /* .AREPEAT */
2870
2871 static void
2872 do_arepeat (idx, in)
2873      int idx;
2874      sb *in;
2875 {
2876   sb exp;                       /* buffer with expression in it */
2877   sb copy;                      /* expanded repeat block */
2878   sb sub;                       /* contents of AREPEAT */
2879   int rc;
2880   char buffer[30];
2881   sb_new (&exp);
2882   sb_new (&copy);
2883   sb_new (&sub);
2884   process_assigns (idx, in, &exp);
2885   idx = exp_get_abs ("AREPEAT must have absolute operand.\n", 0, &exp, &rc);
2886   if (!mri)
2887     buffer_and_nest ("AREPEAT", "AENDR", &sub);
2888   else
2889     buffer_and_nest ("REPT", "ENDR", &sub);
2890   if (rc > 0)
2891     {
2892       /* Push back the text following the repeat, and another repeat block
2893          so
2894          .AREPEAT 20
2895          foo
2896          .AENDR
2897          gets turned into
2898          foo
2899          .AREPEAT 19
2900          foo
2901          .AENDR
2902          */
2903       int index = include_next_index ();
2904       sb_add_sb (&copy, &sub);
2905       if (rc > 1)
2906         {
2907           if (!mri)
2908             sprintf (buffer, "\t.AREPEAT        %d\n", rc - 1);
2909           else
2910             sprintf (buffer, "\tREPT    %d\n", rc - 1);
2911           sb_add_string (&copy, buffer);
2912           sb_add_sb (&copy, &sub);
2913           if (!mri)
2914             sb_add_string (&copy, "     .AENDR\n");
2915           else
2916             sb_add_string (&copy, "     ENDR\n");
2917         }
2918
2919       include_buf (&exp, &copy, include_repeat, index);
2920     }
2921   sb_kill (&exp);
2922   sb_kill (&sub);
2923   sb_kill (&copy);
2924 }
2925
2926 /* .ENDM */
2927
2928 static void
2929 do_endm ()
2930 {
2931   ERROR ((stderr, ".ENDM without a matching .MACRO.\n"));
2932 }
2933
2934 /* MRI IRP pseudo-op.  */
2935
2936 static void
2937 do_irp (idx, in, irpc)
2938      int idx;
2939      sb *in;
2940      int irpc;
2941 {
2942   const char *mn;
2943   sb sub;
2944   formal_entry f;
2945   hash_table h;
2946   hash_entry *p;
2947   sb name;
2948   sb out;
2949
2950   if (irpc)
2951     mn = "IRPC";
2952   else
2953     mn = "IRP";
2954
2955   idx = sb_skip_white (idx, in);
2956
2957   sb_new (&sub);
2958   buffer_and_nest (mn, "ENDR", &sub);
2959   
2960   sb_new (&f.name);
2961   sb_new (&f.def);
2962   sb_new (&f.actual);
2963
2964   idx = get_token (idx, in, &f.name);
2965   if (f.name.len == 0)
2966     {
2967       ERROR ((stderr, "Missing model parameter in %s", mn));
2968       return;
2969     }
2970
2971   hash_new_table (1, &h);
2972   p = hash_create (&h, &f.name);
2973   p->type = hash_formal;
2974   p->value.f = &f;
2975
2976   f.index = 1;
2977   f.next = NULL;
2978
2979   sb_new (&name);
2980   sb_add_string (&name, mn);
2981
2982   sb_new (&out);
2983
2984   idx = sb_skip_comma (idx, in);
2985   if (eol (idx, in))
2986     {
2987       /* Expand once with a null string.  */
2988       macro_expand_body (&name, &sub, &out, &f, &h);
2989       fprintf (outfile, "%s", sb_name (&out));
2990     }
2991   else
2992     {
2993       while (!eol (idx, in))
2994         {
2995           if (!irpc)
2996             idx = get_any_string (idx, in, &f.actual, 1, 0);
2997           else
2998             {
2999               sb_reset (&f.actual);
3000               sb_add_char (&f.actual, in->ptr[idx]);
3001               ++idx;
3002             }
3003           sb_reset (&out);
3004           macro_expand_body (&name, &sub, &out, &f, &h);
3005           fprintf (outfile, "%s", sb_name (&out));
3006           if (!irpc)
3007             idx = sb_skip_comma (idx, in);
3008           else
3009             idx = sb_skip_white (idx, in);
3010         }
3011     }
3012
3013   sb_kill (&sub);
3014   sb_kill (&name);
3015   sb_kill (&out);
3016 }
3017
3018 /* MACRO PROCESSING */
3019
3020 static int number;
3021 hash_table macro_table;
3022
3023 /* Understand
3024
3025    .MACRO <name>
3026    stuff
3027    .ENDM
3028 */
3029
3030 static int
3031 do_formals (macro, idx, in)
3032      macro_entry *macro;
3033      int idx;
3034      sb *in;
3035 {
3036   formal_entry **p = &macro->formals;
3037   macro->formal_count = 0;
3038   hash_new_table (5, &macro->formal_hash);
3039   while (idx < in->len)
3040     {
3041       formal_entry *formal;
3042
3043       formal = (formal_entry *) xmalloc (sizeof (formal_entry));
3044
3045       sb_new (&formal->name);
3046       sb_new (&formal->def);
3047       sb_new (&formal->actual);
3048
3049       idx = sb_skip_white (idx, in);
3050       idx = get_token (idx, in, &formal->name);
3051       if (formal->name.len == 0)
3052         break;
3053       idx = sb_skip_white (idx, in);
3054       if (formal->name.len)
3055         {
3056           /* This is a formal */
3057           if (idx < in->len && in->ptr[idx] == '=')
3058             {
3059               /* Got a default */
3060               idx = get_any_string (idx + 1, in, &formal->def, 1, 0);
3061             }
3062         }
3063
3064       {
3065         /* Add to macro's hash table */
3066
3067         hash_entry *p = hash_create (&macro->formal_hash, &formal->name);
3068         p->type = hash_formal;
3069         p->value.f = formal;
3070       }
3071
3072       formal->index = macro->formal_count;
3073       idx = sb_skip_comma (idx, in);
3074       macro->formal_count++;
3075       *p = formal;
3076       p = &formal->next;
3077       *p = NULL;
3078     }
3079
3080   if (mri)
3081     {
3082       formal_entry *formal;
3083
3084       /* Add a special NARG formal, which macro_expand will set to the
3085          number of arguments.  */
3086       formal = (formal_entry *) xmalloc (sizeof (formal_entry));
3087
3088       sb_new (&formal->name);
3089       sb_new (&formal->def);
3090       sb_new (&formal->actual);
3091
3092       sb_add_string (&formal->name, "NARG");
3093
3094       {
3095         /* Add to macro's hash table */
3096
3097         hash_entry *p = hash_create (&macro->formal_hash, &formal->name);
3098         p->type = hash_formal;
3099         p->value.f = formal;
3100       }
3101
3102       formal->index = -2;
3103       *p = formal;
3104       formal->next = NULL;
3105     }
3106
3107   return idx;
3108 }
3109
3110 /* Parse off LOCAL n1, n2,... Invent a label name for it */
3111 static
3112 void 
3113 do_local (idx, line)
3114      int idx;
3115      sb *line;
3116 {
3117   static int ln;
3118   sb acc;
3119   sb sub;
3120   char subs[10];
3121   sb_new (&acc);
3122   sb_new (&sub);
3123   idx = sb_skip_white (idx, line);
3124   while (!eol(idx, line))
3125     {
3126       sb_reset (&acc);
3127       sb_reset (&sub);
3128       ln++;
3129       sprintf(subs, "LL%04x", ln);
3130       idx =  get_token(idx, line, &acc);
3131       sb_add_string (&sub, subs);
3132       hash_add_to_string_table (&assign_hash_table, &acc, &sub, 1);
3133       idx = sb_skip_comma (idx, line);
3134     }
3135   sb_kill (&sub);
3136   sb_kill (&acc);
3137 }
3138
3139 static
3140 void
3141 do_macro (idx, in)
3142      int idx;
3143      sb *in;
3144 {
3145   macro_entry *macro;
3146   sb name;
3147
3148   macro = (macro_entry *) xmalloc (sizeof (macro_entry));
3149   sb_new (&macro->sub);
3150   sb_new (&name);
3151
3152   macro->formal_count = 0;
3153   macro->formals = 0;
3154
3155   idx = sb_skip_white (idx, in);
3156   buffer_and_nest ("MACRO", "ENDM", &macro->sub);
3157   if (label.len)
3158     {
3159
3160       sb_add_sb (&name, &label);
3161       if (in->ptr[idx] == '(')
3162         {
3163           /* It's the label: MACRO (formals,...)  sort */
3164           idx = do_formals (macro, idx + 1, in);
3165           if (in->ptr[idx] != ')')
3166             ERROR ((stderr, "Missing ) after formals.\n"));
3167         }
3168       else {
3169         /* It's the label: MACRO formals,...  sort */
3170         idx = do_formals (macro, idx, in);
3171       }
3172     }
3173   else
3174     {
3175       idx = get_token (idx, in, &name);
3176       idx = sb_skip_white (idx, in);
3177       idx = do_formals (macro, idx, in);
3178     }
3179
3180   /* and stick it in the macro hash table */
3181   hash_create (&macro_table, &name)->value.m = macro;
3182 }
3183
3184 static
3185 int
3186 get_token (idx, in, name)
3187      int idx;
3188      sb *in;
3189      sb *name;
3190 {
3191   if (idx < in->len
3192       && ISFIRSTCHAR (in->ptr[idx]))
3193     {
3194       sb_add_char (name, in->ptr[idx++]);
3195       while (idx < in->len
3196              && ISNEXTCHAR (in->ptr[idx]))
3197         {
3198           sb_add_char (name, in->ptr[idx++]);
3199         }
3200     }
3201   /* Ignore trailing & */
3202   if (alternate && idx < in->len && in->ptr[idx] == '&')
3203     idx++;
3204   return idx;
3205 }
3206
3207 /* Scan a token, but stop if a ' is seen */
3208 static int
3209 get_apost_token (idx, in, name, kind)
3210      int idx;
3211      sb *in;
3212      sb *name;
3213      int kind;
3214 {
3215   idx = get_token (idx, in, name);
3216   if (idx < in->len && in->ptr[idx] == kind)
3217     idx++;
3218   return idx;
3219 }
3220
3221 static int
3222 sub_actual (src, in, t, formal_hash, kind, out, copyifnotthere)
3223      int src;
3224      sb *in;
3225      sb *t;
3226      hash_table *formal_hash;
3227      int kind;
3228      sb *out;
3229      int copyifnotthere;
3230 {
3231   /* This is something to take care of */
3232   hash_entry *ptr;
3233   src = get_apost_token (src, in, t, kind);
3234   /* See if it's in the macro's hash table */
3235   ptr = hash_lookup (formal_hash, t);
3236   if (ptr)
3237     {
3238       if (ptr->value.f->actual.len)
3239         {
3240           sb_add_sb (out, &ptr->value.f->actual);
3241         }
3242       else
3243         {
3244           sb_add_sb (out, &ptr->value.f->def);
3245         }
3246     }
3247   else if (copyifnotthere)
3248     {
3249       sb_add_sb (out, t);
3250     }
3251   else 
3252     {
3253       sb_add_char (out, '\\');
3254       sb_add_sb (out, t);
3255     }
3256   return src;
3257 }
3258
3259 /* Copy the body from the macro buffer into a safe place and
3260    substitute any args.  */
3261
3262 static void
3263 macro_expand_body (name, in, out, formals, formal_hash)
3264      sb *name;
3265      sb *in;
3266      sb *out;
3267      formal_entry *formals;
3268      hash_table *formal_hash;
3269 {
3270   sb t;
3271   int src = 0;
3272   int inquote = 0;
3273
3274   sb_new (&t);
3275
3276   while (src < in->len)
3277     {
3278       if (in->ptr[src] == '&')
3279         {
3280           sb_reset (&t);
3281           if (mri && src + 1 < in->len && in->ptr[src + 1] == '&')
3282             {
3283               src = sub_actual (src + 2, in, &t, formal_hash, '\'', out, 1);
3284             }
3285           else
3286             {
3287               src = sub_actual (src + 1, in, &t, formal_hash, '&', out, 0);
3288             }
3289         }
3290       else if (in->ptr[src] == '\\')
3291         {
3292           src++;
3293           if (in->ptr[src] == comment_char)
3294             {
3295               /* This is a comment, just drop the rest of the line */
3296               while (src < in->len
3297                      && in->ptr[src] != '\n')
3298                 src++;
3299
3300             }
3301           else if (in->ptr[src] == '(')
3302             {
3303               /* Sub in till the next ')' literally */
3304               src++;
3305               while (src < in->len && in->ptr[src] != ')')
3306                 {
3307                   sb_add_char (out, in->ptr[src++]);
3308                 }
3309               if (in->ptr[src] == ')')
3310                 src++;
3311               else
3312                 ERROR ((stderr, "Missplaced ).\n"));
3313             }
3314           else if (in->ptr[src] == '@')
3315             {
3316               /* Sub in the macro invocation number */
3317
3318               char buffer[6];
3319               src++;
3320               sprintf (buffer, "%05d", number);
3321               sb_add_string (out, buffer);
3322             }
3323           else if (in->ptr[src] == '&')
3324             {
3325               /* This is a preprocessor variable name, we don't do them
3326                  here */
3327               sb_add_char (out, '\\');
3328               sb_add_char (out, '&');
3329               src++;
3330             }
3331           else if (mri
3332                    && isalnum ((unsigned char) in->ptr[src]))
3333             {
3334               int ind;
3335               formal_entry *f;
3336
3337               if (isdigit ((unsigned char) in->ptr[src]))
3338                 ind = in->ptr[src] - '0';
3339               else if (isupper ((unsigned char) in->ptr[src]))
3340                 ind = in->ptr[src] - 'A' + 10;
3341               else
3342                 ind = in->ptr[src] - 'a' + 10;
3343               ++src;
3344               for (f = formals; f != NULL; f = f->next)
3345                 {
3346                   if (f->index == ind - 1)
3347                     {
3348                       if (f->actual.len != 0)
3349                         sb_add_sb (out, &f->actual);
3350                       else
3351                         sb_add_sb (out, &f->def);
3352                       break;
3353                     }
3354                 }
3355             }
3356           else
3357             {
3358               sb_reset (&t);
3359               src = sub_actual (src, in, &t, formal_hash, '\'', out, 0);
3360             }
3361         }
3362       else if (ISFIRSTCHAR (in->ptr[src]) && (alternate || mri))
3363         {
3364           sb_reset (&t);
3365           src = sub_actual (src, in, &t, formal_hash, '\'', out, 1);
3366         }
3367       else if (ISCOMMENTCHAR (in->ptr[src])
3368                && src + 1 <  in->len
3369                && ISCOMMENTCHAR (in->ptr[src+1])
3370                && !inquote)
3371         {
3372           /* Two comment chars in a row cause the rest of the line to
3373              be dropped.  */
3374           while (src < in->len && in->ptr[src] != '\n')
3375             src++;
3376         }
3377       else if (in->ptr[src] == '"'
3378                || (mri && in->ptr[src] == '\''))
3379         {
3380           inquote = !inquote;
3381           sb_add_char (out, in->ptr[src++]);
3382         }
3383       else if (mri
3384                && in->ptr[src] == '='
3385                && src + 1 < in->len
3386                && in->ptr[src + 1] == '=')
3387         {
3388           hash_entry *ptr;
3389
3390           sb_reset (&t);
3391           src = get_token (src + 2, in, &t);
3392           ptr = hash_lookup (formal_hash, &t);
3393           if (ptr == NULL)
3394             {
3395               ERROR ((stderr, "MACRO formal argument %s does not exist.\n",
3396                       sb_name (&t)));
3397             }
3398           else
3399             {
3400               if (ptr->value.f->actual.len)
3401                 {
3402                   sb_add_string (out, "-1");
3403                 }
3404               else
3405                 {
3406                   sb_add_char (out, '0');
3407                 }
3408             }
3409         }
3410       else
3411         {
3412           sb_add_char (out, in->ptr[src++]);
3413         }
3414     }
3415
3416   sb_kill (&t);
3417 }
3418
3419 static void
3420 macro_expand (name, idx, in, m)
3421      sb *name;
3422      int idx;
3423      sb *in;
3424      macro_entry *m;
3425 {
3426   sb t;
3427   sb out;
3428   hash_entry *ptr;
3429   formal_entry *f;
3430   int is_positional = 0;
3431   int is_keyword = 0;
3432   int narg = 0;
3433
3434   sb_new (&t);
3435   sb_new (&out);
3436   
3437   /* Reset any old value the actuals may have */
3438   for (f = m->formals; f; f = f->next)
3439       sb_reset (&f->actual);
3440   f = m->formals;
3441
3442   if (mri)
3443     {
3444       /* The macro may be called with an optional qualifier, which may
3445          be referred to in the macro body as \0.  */
3446       if (idx < in->len && in->ptr[idx] == '.')
3447         {
3448           formal_entry *n;
3449
3450           n = (formal_entry *) xmalloc (sizeof (formal_entry));
3451           sb_new (&n->name);
3452           sb_new (&n->def);
3453           sb_new (&n->actual);
3454           n->index = -1;
3455
3456           n->next = m->formals;
3457           m->formals = n;
3458
3459           idx = get_any_string (idx + 1, in, &n->actual, 1, 0);
3460         }
3461     }
3462
3463   /* Peel off the actuals and store them away in the hash tables' actuals */
3464   while (!eol(idx, in))
3465     {
3466       int scan;
3467       idx = sb_skip_white (idx, in);
3468       /* Look and see if it's a positional or keyword arg */
3469       scan = idx;
3470       while (scan < in->len
3471              && !ISSEP (in->ptr[scan])
3472              && (!alternate && in->ptr[scan] != '='))
3473         scan++;
3474       if (scan < in->len && (!alternate) && in->ptr[scan] == '=')
3475         {
3476           is_keyword = 1;
3477           if (is_positional)
3478             {
3479               ERROR ((stderr, "Can't mix positional and keyword arguments.\n"));
3480               return;
3481             }
3482           /* This is a keyword arg, fetch the formal name and
3483              then the actual stuff */
3484           sb_reset (&t);
3485           idx = get_token (idx, in, &t);
3486           if (in->ptr[idx] != '=')
3487             ERROR ((stderr, "confused about formal params.\n"));
3488
3489           /* Lookup the formal in the macro's list */
3490           ptr = hash_lookup (&m->formal_hash, &t);
3491           if (!ptr)
3492             {
3493               ERROR ((stderr, "MACRO formal argument %s does not exist.\n", sb_name (&t)));
3494               return;
3495             }
3496           else
3497             {
3498               /* Insert this value into the right place */
3499               sb_reset (&ptr->value.f->actual);
3500               idx = get_any_string (idx + 1, in, &ptr->value.f->actual, 0, 0);
3501               if (ptr->value.f->actual.len > 0)
3502                 ++narg;
3503             }
3504         }
3505       else
3506         {
3507           /* This is a positional arg */
3508           is_positional = 1;
3509           if (is_keyword)
3510             {
3511               ERROR ((stderr, "Can't mix positional and keyword arguments.\n"));
3512               return;
3513             }
3514           if (!f)
3515             {
3516               formal_entry **pf;
3517               int c;
3518
3519               if (!mri)
3520                 {
3521                   ERROR ((stderr, "Too many positional arguments.\n"));
3522                   return;
3523                 }
3524               f = (formal_entry *) xmalloc (sizeof (formal_entry));
3525               sb_new (&f->name);
3526               sb_new (&f->def);
3527               sb_new (&f->actual);
3528               f->next = NULL;
3529
3530               c = -1;
3531               for (pf = &m->formals; *pf != NULL; pf = &(*pf)->next)
3532                 if ((*pf)->index >= c)
3533                   c = (*pf)->index + 1;
3534               *pf = f;
3535               f->index = c;
3536             }
3537
3538           sb_reset (&f->actual);
3539           idx = get_any_string (idx, in, &f->actual, 1, 0);
3540           if (f->actual.len > 0)
3541             ++narg;
3542           do
3543             {
3544               f = f->next;
3545             }
3546           while (f != NULL && f->index < 0);
3547         }
3548
3549       idx = sb_skip_comma (idx, in);
3550     }
3551
3552   if (mri)
3553     {
3554       char buffer[20];
3555
3556       sb_reset (&t);
3557       sb_add_string (&t, "NARG");
3558       ptr = hash_lookup (&m->formal_hash, &t);
3559       sb_reset (&ptr->value.f->actual);
3560       sprintf (buffer, "%d", narg);
3561       sb_add_string (&ptr->value.f->actual, buffer);
3562     }
3563
3564   macro_expand_body (name, &m->sub, &out, m->formals, &m->formal_hash);
3565
3566   include_buf (name, &out, include_macro, include_next_index ());
3567
3568   if (mri)
3569     {
3570       formal_entry **pf;
3571
3572       /* Discard any unnamed formal arguments.  */
3573       pf = &m->formals;
3574       while (*pf != NULL)
3575         {
3576           if ((*pf)->name.len != 0)
3577             pf = &(*pf)->next;
3578           else
3579             {
3580               sb_kill (&(*pf)->name);
3581               sb_kill (&(*pf)->def);
3582               sb_kill (&(*pf)->actual);
3583               f = (*pf)->next;
3584               free (*pf);
3585               *pf = f;
3586             }
3587         }
3588     }
3589
3590   sb_kill (&t);
3591   sb_kill (&out);
3592   number++;
3593 }
3594
3595 static int
3596 macro_op (idx, in)
3597      int idx;
3598      sb *in;
3599 {
3600   int res = 0;
3601   /* The macro name must be the first thing on the line */
3602   if (idx < in->len)
3603     {
3604       sb name;
3605       hash_entry *ptr;
3606       sb_new (&name);
3607       idx = get_token (idx, in, &name);
3608
3609       if (name.len)
3610         {
3611           /* Got a name, look it up */
3612
3613           ptr = hash_lookup (&macro_table, &name);
3614
3615           if (ptr)
3616             {
3617               /* It's in the table, copy out the stuff and convert any macro args */
3618               macro_expand (&name, idx, in, ptr->value.m);
3619               res = 1;
3620             }
3621         }
3622       sb_kill (&name);
3623     }
3624
3625
3626   return res;
3627 }
3628
3629
3630 /* STRING HANDLING */
3631
3632 static int
3633 getstring (idx, in, acc)
3634      int idx;
3635      sb *in;
3636      sb *acc;
3637 {
3638   idx = sb_skip_white (idx, in);
3639
3640   while (idx < in->len
3641          && (in->ptr[idx] == '"' 
3642              || in->ptr[idx] == '<' 
3643              || (in->ptr[idx] == '\'' && alternate)))
3644     {
3645       if (in->ptr[idx] == '<')
3646         {
3647           if (alternate || mri)
3648             {
3649               int nest = 0;
3650               idx++;
3651               while ((in->ptr[idx] != '>' || nest)
3652                      && idx < in->len)
3653                 {
3654                   if (in->ptr[idx] == '!')
3655                     {
3656                       idx++  ;
3657                       sb_add_char (acc, in->ptr[idx++]);
3658                     }
3659                   else {
3660                     if (in->ptr[idx] == '>')
3661                       nest--;
3662                     if (in->ptr[idx] == '<')
3663                       nest++;
3664                     sb_add_char (acc, in->ptr[idx++]);
3665                   }
3666                 }
3667               idx++;
3668             }
3669           else {
3670             int code;
3671             idx++;
3672             idx = exp_get_abs ("Character code in string must be absolute expression.\n",
3673                                idx, in, &code);
3674             sb_add_char (acc, code);
3675
3676             if (in->ptr[idx] != '>')
3677               ERROR ((stderr, "Missing > for character code.\n"));
3678             idx++;
3679           }
3680         }
3681       else if (in->ptr[idx] == '"' || in->ptr[idx] == '\'')
3682         {
3683           char tchar = in->ptr[idx];
3684           idx++;
3685           while (idx < in->len)
3686             {
3687               if (alternate && in->ptr[idx] == '!')
3688                 {
3689                   idx++  ;
3690                   sb_add_char (acc, in->ptr[idx++]);
3691                 }
3692               else {
3693                 if (in->ptr[idx] == tchar)
3694                   {
3695                     idx++;
3696                     if (idx >= in->len || in->ptr[idx] != tchar)
3697                       break;
3698                   }
3699                 sb_add_char (acc, in->ptr[idx]);
3700                 idx++;
3701               }
3702             }
3703         }
3704     }
3705   
3706   return idx;
3707 }
3708
3709 /* .SDATA[C|Z] <string> */
3710
3711 static
3712 void
3713 do_sdata (idx, in, type)
3714      int idx;
3715      sb *in;
3716      int type;
3717 {
3718   int nc = 0;
3719   int pidx = -1;
3720   sb acc;
3721   sb_new (&acc);
3722   fprintf (outfile, ".byte\t");
3723
3724   while (!eol (idx, in))
3725     {
3726       int i;
3727       sb_reset (&acc);
3728       idx = sb_skip_white (idx, in);
3729       while (!eol (idx, in))
3730         {
3731           pidx = idx = get_any_string (idx, in, &acc, 0, 1);
3732           if (type == 'c')
3733             {
3734               if (acc.len > 255)
3735                 {
3736                   ERROR ((stderr, "string for SDATAC longer than 255 characters (%d).\n", acc.len));
3737                 }
3738               fprintf (outfile, "%d", acc.len);
3739               nc = 1;
3740             }
3741
3742           for (i = 0; i < acc.len; i++)
3743             {
3744               if (nc)
3745                 {
3746                   fprintf (outfile, ",");
3747                 }
3748               fprintf (outfile, "%d", acc.ptr[i]);
3749               nc = 1;
3750             }
3751
3752           if (type == 'z')
3753             {
3754               if (nc)
3755                 fprintf (outfile, ",");
3756               fprintf (outfile, "0");
3757             }
3758           idx = sb_skip_comma (idx, in);
3759           if (idx == pidx) break;
3760         }
3761       if (!alternate && in->ptr[idx] != ',' && idx != in->len)
3762         {
3763           fprintf (outfile, "\n");
3764           ERROR ((stderr, "illegal character in SDATA line (0x%x).\n", in->ptr[idx]));
3765           break;
3766         }
3767       idx++;
3768     }
3769   sb_kill (&acc);
3770   fprintf (outfile, "\n");
3771 }
3772
3773 /* .SDATAB <count> <string> */
3774
3775 static void
3776 do_sdatab (idx, in)
3777      int idx;
3778      sb *in;
3779 {
3780   int repeat;
3781   int i;
3782   sb acc;
3783   sb_new (&acc);
3784
3785   idx = exp_get_abs ("Must have absolute SDATAB repeat count.\n", idx, in, &repeat);
3786   if (repeat <= 0)
3787     {
3788       ERROR ((stderr, "Must have positive SDATAB repeat count (%d).\n", repeat));
3789       repeat = 1;
3790     }
3791
3792   idx = sb_skip_comma (idx, in);
3793   idx = getstring (idx, in, &acc);
3794
3795   for (i = 0; i < repeat; i++)
3796     {
3797       if (i)
3798         fprintf (outfile, "\t");
3799       fprintf (outfile, ".byte\t");
3800       sb_print (&acc);
3801       fprintf (outfile, "\n");
3802     }
3803   sb_kill (&acc);
3804
3805 }
3806
3807 static int
3808 new_file (name)
3809      const char *name;
3810 {
3811   FILE *newone = fopen (name, "r");
3812   if (!newone)
3813     return 0;
3814
3815   if (isp == MAX_INCLUDES)
3816     FATAL ((stderr, "Unreasonable include depth (%ld).\n", (long) isp));
3817
3818   sp++;
3819   sp->handle = newone;
3820
3821   sb_new (&sp->name);
3822   sb_add_string (&sp->name, name);
3823
3824   sp->linecount = 1;
3825   sp->pushback_index = 0;
3826   sp->type = include_file;
3827   sp->index = 0;
3828   sb_new (&sp->pushback);
3829   return 1;
3830 }
3831
3832 static void
3833 do_include (idx, in)
3834      int idx;
3835      sb *in;
3836 {
3837   sb t;
3838   sb cat;
3839   char *text;
3840   include_path *includes;
3841   sb_new (&t);
3842   sb_new (&cat);
3843
3844   idx = getstring (idx, in, &t);
3845
3846   for (includes = paths_head; includes; includes = includes->next)
3847     {
3848       sb_reset (&cat);
3849       sb_add_sb (&cat, &includes->path);
3850       sb_add_char (&cat, '/');
3851       sb_add_sb (&cat, &t);
3852       if (new_file (sb_name (&cat)))
3853         {
3854           break;
3855         }
3856     }
3857   if (!includes)
3858     {
3859       FATAL ((stderr, "Can't open include file `%s'.\n", text));
3860     }
3861   sb_kill (&cat);
3862   sb_kill (&t);
3863 }
3864
3865 static void
3866 include_pop ()
3867 {
3868   if (sp != include_stack)
3869     {
3870       if (sp->handle)
3871         fclose (sp->handle);
3872       sp--;
3873     }
3874 }
3875
3876 /* Get the next character from the include stack.  If there's anything
3877    in the pushback buffer, take that first.  If we're at eof, pop from
3878    the stack and try again.  Keep the linecount up to date. */
3879
3880 static int
3881 get ()
3882 {
3883   int r;
3884
3885   if (sp->pushback.len != sp->pushback_index)
3886     {
3887       r = (char) (sp->pushback.ptr[sp->pushback_index++]);
3888       /* When they've all gone, reset the pointer */
3889       if (sp->pushback_index == sp->pushback.len)
3890         {
3891           sp->pushback.len = 0;
3892           sp->pushback_index = 0;
3893         }
3894     }
3895   else if (sp->handle)
3896     {
3897       r = getc (sp->handle);
3898     }
3899   else
3900     r = EOF;
3901
3902   if (r == EOF && isp)
3903     {
3904       include_pop ();
3905       r = get ();
3906       while (r == EOF && isp)
3907         {
3908           include_pop ();
3909           r = get ();
3910         }
3911       return r;
3912     }
3913   if (r == '\n')
3914     {
3915       sp->linecount++;
3916     }
3917
3918   return r;
3919 }
3920
3921 static int
3922 linecount ()
3923 {
3924   return sp->linecount;
3925 }
3926
3927 static int
3928 include_next_index ()
3929 {
3930   static int index;
3931   if (!unreasonable
3932       && index > MAX_REASONABLE)
3933     FATAL ((stderr, "Unreasonable expansion (-u turns off check).\n"));
3934   return ++index;
3935 }
3936
3937
3938 /* Initialize the chartype vector. */
3939
3940 static void
3941 chartype_init ()
3942 {
3943   int x;
3944   for (x = 0; x < 256; x++)
3945     {
3946       if (isalpha (x) || x == '_' || x == '$')
3947         chartype[x] |= FIRSTBIT;
3948
3949       if (isdigit (x) || isalpha (x) || x == '_' || x == '$')
3950         chartype[x] |= NEXTBIT;
3951
3952       if (x == ' ' || x == '\t' || x == ',' || x == '"' || x == ';'
3953           || x == '"' || x == '<' || x == '>' || x == ')' || x == '(')
3954         chartype[x] |= SEPBIT;
3955
3956       if (x == 'b' || x == 'B'
3957           || x == 'q' || x == 'Q'
3958           || x == 'h' || x == 'H'
3959           || x == 'd' || x == 'D')
3960         chartype [x] |= BASEBIT;
3961           
3962       if (x == ' ' || x == '\t')
3963         chartype[x] |= WHITEBIT;
3964
3965       if (x == comment_char)
3966         chartype[x] |= COMMENTBIT;
3967     }
3968 }
3969
3970
3971
3972 /* What to do with all the keywords */
3973 #define PROCESS         0x1000  /* Run substitution over the line */
3974 #define LAB             0x2000  /* Spit out the label */
3975
3976 #define K_EQU           (PROCESS|1)
3977 #define K_ASSIGN        (PROCESS|2)
3978 #define K_REG           (PROCESS|3)
3979 #define K_ORG           (PROCESS|4)
3980 #define K_RADIX         (PROCESS|5)
3981 #define K_DATA          (LAB|PROCESS|6)
3982 #define K_DATAB         (LAB|PROCESS|7)
3983 #define K_SDATA         (LAB|PROCESS|8)
3984 #define K_SDATAB        (LAB|PROCESS|9)
3985 #define K_SDATAC        (LAB|PROCESS|10)
3986 #define K_SDATAZ        (LAB|PROCESS|11)
3987 #define K_RES           (LAB|PROCESS|12)
3988 #define K_SRES          (LAB|PROCESS|13)
3989 #define K_SRESC         (LAB|PROCESS|14)
3990 #define K_SRESZ         (LAB|PROCESS|15)
3991 #define K_EXPORT        (LAB|PROCESS|16)
3992 #define K_GLOBAL        (LAB|PROCESS|17)
3993 #define K_PRINT         (LAB|PROCESS|19)
3994 #define K_FORM          (LAB|PROCESS|20)
3995 #define K_HEADING       (LAB|PROCESS|21)
3996 #define K_PAGE          (LAB|PROCESS|22)
3997 #define K_IMPORT        (LAB|PROCESS|23)
3998 #define K_PROGRAM       (LAB|PROCESS|24)
3999 #define K_END           (PROCESS|25)
4000 #define K_INCLUDE       (PROCESS|26)
4001 #define K_IGNORED       (PROCESS|27)
4002 #define K_ASSIGNA       (PROCESS|28)
4003 #define K_ASSIGNC       (29)
4004 #define K_AIF           (PROCESS|30)
4005 #define K_AELSE         (PROCESS|31)
4006 #define K_AENDI         (PROCESS|32)
4007 #define K_AREPEAT       (PROCESS|33)
4008 #define K_AENDR         (PROCESS|34)
4009 #define K_AWHILE        (35)
4010 #define K_AENDW         (PROCESS|36)
4011 #define K_EXITM         (37)
4012 #define K_MACRO         (PROCESS|38)
4013 #define K_ENDM          (39)
4014 #define K_ALIGN         (PROCESS|LAB|40)
4015 #define K_ALTERNATE     (41)
4016 #define K_DB            (LAB|PROCESS|42)
4017 #define K_DW            (LAB|PROCESS|43)
4018 #define K_DL            (LAB|PROCESS|44)
4019 #define K_LOCAL         (45)
4020 #define K_IFEQ          (PROCESS|46)
4021 #define K_IFNE          (PROCESS|47)
4022 #define K_IFLT          (PROCESS|48)
4023 #define K_IFLE          (PROCESS|49)
4024 #define K_IFGE          (PROCESS|50)
4025 #define K_IFGT          (PROCESS|51)
4026 #define K_IFC           (PROCESS|52)
4027 #define K_IFNC          (PROCESS|53)
4028 #define K_IRP           (PROCESS|54)
4029 #define K_IRPC          (PROCESS|55)
4030
4031
4032 struct keyword
4033 {
4034   char *name;
4035   int code;
4036   int extra;
4037 };
4038
4039 static struct keyword kinfo[] =
4040 {
4041   { "EQU", K_EQU, 0 },
4042   { "ALTERNATE", K_ALTERNATE, 0 },
4043   { "ASSIGN", K_ASSIGN, 0 },
4044   { "REG", K_REG, 0 },
4045   { "ORG", K_ORG, 0 },
4046   { "RADIX", K_RADIX, 0 },
4047   { "DATA", K_DATA, 0 },
4048   { "DB", K_DB, 0 },
4049   { "DW", K_DW, 0 },
4050   { "DL", K_DL, 0 },
4051   { "DATAB", K_DATAB, 0 },
4052   { "SDATA", K_SDATA, 0 },
4053   { "SDATAB", K_SDATAB, 0 },
4054   { "SDATAZ", K_SDATAZ, 0 },
4055   { "SDATAC", K_SDATAC, 0 },
4056   { "RES", K_RES, 0 },
4057   { "SRES", K_SRES, 0 },
4058   { "SRESC", K_SRESC, 0 },
4059   { "SRESZ", K_SRESZ, 0 },
4060   { "EXPORT", K_EXPORT, 0 },
4061   { "GLOBAL", K_GLOBAL, 0 },
4062   { "PRINT", K_PRINT, 0 },
4063   { "FORM", K_FORM, 0 },
4064   { "HEADING", K_HEADING, 0 },
4065   { "PAGE", K_PAGE, 0 },
4066   { "PROGRAM", K_IGNORED, 0 },
4067   { "END", K_END, 0 },
4068   { "INCLUDE", K_INCLUDE, 0 },
4069   { "ASSIGNA", K_ASSIGNA, 0 },
4070   { "ASSIGNC", K_ASSIGNC, 0 },
4071   { "AIF", K_AIF, 0 },
4072   { "AELSE", K_AELSE, 0 },
4073   { "AENDI", K_AENDI, 0 },
4074   { "AREPEAT", K_AREPEAT, 0 },
4075   { "AENDR", K_AENDR, 0 },
4076   { "EXITM", K_EXITM, 0 },
4077   { "MACRO", K_MACRO, 0 },
4078   { "ENDM", K_ENDM, 0 },
4079   { "AWHILE", K_AWHILE, 0 },
4080   { "ALIGN", K_ALIGN, 0 },
4081   { "AENDW", K_AENDW, 0 },
4082   { "ALTERNATE", K_ALTERNATE, 0 },
4083   { "LOCAL", K_LOCAL, 0 },
4084   { NULL, 0, 0 }
4085 };
4086
4087 /* Although the conditional operators are handled by gas, we need to
4088    handle them here as well, in case they are used in a recursive
4089    macro to end the recursion.  */
4090
4091 static struct keyword mrikinfo[] =
4092 {
4093   { "IF", K_IFNE, 0 },
4094   { "IFEQ", K_IFEQ, 0 },
4095   { "IFNE", K_IFNE, 0 },
4096   { "IFLT", K_IFLT, 0 },
4097   { "IFLE", K_IFLE, 0 },
4098   { "IFGE", K_IFGE, 0 },
4099   { "IFGT", K_IFGT, 0 },
4100   { "IFC", K_IFC, 0 },
4101   { "IFNC", K_IFNC, 0 },
4102   { "ELSEC", K_AELSE, 0 },
4103   { "ENDC", K_AENDI, 0 },
4104   { "MEXIT", K_EXITM, 0 },
4105   { "REPT", K_AREPEAT, 0 },
4106   { "IRP", K_IRP, 0 },
4107   { "IRPC", K_IRPC, 0 },
4108   { "ENDR", K_AENDR, 0 },
4109   { NULL, 0, 0 }
4110 };
4111
4112 /* Look for a pseudo op on the line. If one's there then call
4113    its handler. */
4114
4115 static int
4116 process_pseudo_op (idx, line, acc)
4117      int idx;
4118      sb *line;
4119      sb *acc;
4120 {
4121   int oidx = idx;
4122
4123   if (line->ptr[idx] == '.' || alternate || mri)
4124     {
4125       /* Scan forward and find pseudo name */
4126       char *in;
4127       hash_entry *ptr;
4128
4129       char *s;
4130       char *e;
4131       if (line->ptr[idx] == '.')
4132         idx++;
4133       in = line->ptr + idx;
4134       s = in;
4135       e = s;
4136       sb_reset (acc);
4137
4138       while (idx < line->len && *e && ISFIRSTCHAR (*e))
4139         {
4140           sb_add_char (acc, *e);
4141           e++;
4142           idx++;
4143         }
4144
4145       ptr = hash_lookup (&keyword_hash_table, acc);
4146
4147       if (!ptr)
4148         {
4149 #if 0
4150           /* This one causes lots of pain when trying to preprocess
4151              ordinary code */
4152           WARNING ((stderr, "Unrecognised pseudo op `%s'.\n", sb_name (acc)));
4153 #endif
4154           return 0;
4155         }
4156       if (ptr->value.i & LAB)
4157         {                       /* output the label */
4158           if (label.len)
4159             {
4160               fprintf (outfile, "%s:\t", sb_name (&label));
4161             }
4162           else
4163             fprintf (outfile, "\t");
4164         }
4165
4166       if (mri && ptr->value.i == K_END)
4167         {
4168           sb t;
4169
4170           sb_new (&t);
4171           sb_add_buffer (&t, line->ptr + oidx, idx - oidx);
4172           fprintf (outfile, "\t%s", sb_name (&t));
4173           sb_kill (&t);
4174         }
4175
4176       if (ptr->value.i & PROCESS)
4177         {
4178           /* Polish the rest of the line before handling the pseudo op */
4179 #if 0
4180           strip_comments(line);
4181 #endif
4182           sb_reset (acc);
4183           process_assigns (idx, line, acc);
4184           sb_reset(line);
4185           change_base (0, acc, line);
4186           idx = 0;
4187         }
4188       if (!condass_on ())
4189         {
4190           switch (ptr->value.i)
4191             {
4192             case K_AIF:
4193               do_aif (idx, line);
4194               break;
4195             case K_AELSE:
4196               do_aelse ();
4197               break;
4198             case K_AENDI:
4199               do_aendi ();
4200               break;
4201             }
4202           return 1;
4203         }
4204       else
4205         {
4206           switch (ptr->value.i)
4207             {
4208             case K_ALTERNATE:
4209               alternate = 1;
4210               return 1;
4211             case K_AELSE:
4212               do_aelse ();
4213               return 1;
4214             case K_AENDI:
4215               do_aendi ();
4216               return 1;
4217             case K_ORG:
4218               ERROR ((stderr, "ORG command not allowed.\n"));
4219               break;
4220             case K_RADIX:
4221               do_radix (line);
4222               return 1;
4223             case K_DB:
4224               do_data (idx, line, 1);
4225               return 1;
4226             case K_DW:
4227               do_data (idx, line, 2);
4228               return 1;
4229             case K_DL:
4230               do_data (idx, line, 4);
4231               return 1;
4232             case K_DATA:
4233               do_data (idx, line, 0);
4234               return 1;
4235             case K_DATAB:
4236               do_datab (idx, line);
4237               return 1;
4238             case K_SDATA:
4239               do_sdata (idx, line, 0);
4240               return 1;
4241             case K_SDATAB:
4242               do_sdatab (idx, line);
4243               return 1;
4244             case K_SDATAC:
4245               do_sdata (idx, line, 'c');
4246               return 1;
4247             case K_SDATAZ:
4248               do_sdata (idx, line, 'z');
4249               return 1;
4250             case K_ASSIGN:
4251               do_assign (1, 0, line);
4252               return 1;
4253             case K_AIF:
4254               do_aif (idx, line);
4255               return 1;
4256             case K_AREPEAT:
4257               do_arepeat (idx, line);
4258               return 1;
4259             case K_AENDW:
4260               do_aendw ();
4261               return 1;
4262             case K_AWHILE:
4263               do_awhile (idx, line);
4264               return 1;
4265             case K_AENDR:
4266               do_aendr ();
4267               return 1;
4268             case K_EQU:
4269               do_assign (0, idx, line);
4270               return 1;
4271             case K_ALIGN:
4272               do_align (idx, line);
4273               return 1;
4274             case K_RES:
4275               do_res (idx, line, 0);
4276               return 1;
4277             case K_SRES:
4278               do_res (idx, line, 's');
4279               return 1;
4280             case K_INCLUDE:
4281               do_include (idx, line);
4282               return 1;
4283             case K_LOCAL:
4284               do_local (idx, line);
4285               return 1;
4286             case K_MACRO:
4287               do_macro (idx, line);
4288               return 1;
4289             case K_ENDM:
4290               do_endm ();
4291               return 1;
4292             case K_SRESC:
4293               do_res (idx, line, 'c');
4294               return 1;
4295             case K_PRINT:
4296               do_print (idx, line);
4297               return 1;
4298             case K_FORM:
4299               do_form (idx, line);
4300               return 1;
4301             case K_HEADING:
4302               do_heading (idx, line);
4303               return 1;
4304             case K_PAGE:
4305               do_page ();
4306               return 1;
4307             case K_GLOBAL:
4308             case K_EXPORT:
4309               do_export (line);
4310               return 1;
4311             case K_IMPORT:
4312               return 1;
4313             case K_SRESZ:
4314               do_res (idx, line, 'z');
4315               return 1;
4316             case K_IGNORED:
4317               return 1;
4318             case K_END:
4319               do_end (line);
4320               return 1;
4321             case K_ASSIGNA:
4322               do_assigna (idx, line);
4323               return 1;
4324             case K_ASSIGNC:
4325               do_assignc (idx, line);
4326               return 1;
4327             case K_EXITM:
4328               do_exitm ();
4329               return 1;
4330             case K_REG:
4331               do_reg (idx, line);
4332               return 1;
4333             case K_IFEQ:
4334               do_if (idx, line, EQ);
4335               return 1;
4336             case K_IFNE:
4337               do_if (idx, line, NE);
4338               return 1;
4339             case K_IFLT:
4340               do_if (idx, line, LT);
4341               return 1;
4342             case K_IFLE:
4343               do_if (idx, line, LE);
4344               return 1;
4345             case K_IFGE:
4346               do_if (idx, line, GE);
4347               return 1;
4348             case K_IFGT:
4349               do_if (idx, line, GT);
4350               return 1;
4351             case K_IFC:
4352               do_ifc (idx, line, 0);
4353               return 1;
4354             case K_IFNC:
4355               do_ifc (idx, line, 1);
4356               return 1;
4357             case K_IRP:
4358               do_irp (idx, line, 0);
4359               return 1;
4360             case K_IRPC:
4361               do_irp (idx, line, 1);
4362               return 1;
4363             }
4364         }
4365     }
4366   return 0;
4367 }
4368
4369
4370
4371 /* Add a keyword to the hash table.  */
4372
4373 static void
4374 add_keyword (name, code)
4375      const char *name;
4376      int code;
4377 {
4378   sb label;
4379   int j;
4380
4381   sb_new (&label);
4382   sb_add_string (&label, name);
4383
4384   hash_add_to_int_table (&keyword_hash_table, &label, code);
4385
4386   sb_reset (&label);
4387   for (j = 0; name[j]; j++)
4388     sb_add_char (&label, name[j] - 'A' + 'a');
4389   hash_add_to_int_table (&keyword_hash_table, &label, code);
4390
4391   sb_kill (&label);
4392 }  
4393
4394 /* Build the keyword hash table - put each keyword in the table twice,
4395    once upper and once lower case.*/
4396
4397 static void
4398 process_init ()
4399 {
4400   int i;
4401
4402   for (i = 0; kinfo[i].name; i++)
4403     add_keyword (kinfo[i].name, kinfo[i].code);
4404
4405   if (mri)
4406     {
4407       for (i = 0; mrikinfo[i].name; i++)
4408         add_keyword (mrikinfo[i].name, mrikinfo[i].code);
4409     }
4410 }
4411
4412
4413 static void
4414 do_define (string)
4415      const char *string;
4416 {
4417   sb label;
4418   int res = 1;
4419   hash_entry *ptr;
4420   sb_new (&label);
4421
4422
4423   while (*string)
4424     {
4425       if (*string == '=') 
4426         {
4427           sb value;
4428           sb_new (&value);
4429           string++;
4430           while (*string)
4431             {
4432               sb_add_char (&value, *string);
4433               string++;
4434             }
4435           exp_get_abs ("Invalid expression on command line.\n", 0, &value, &res);
4436           sb_kill (&value);
4437           break;
4438         }
4439       sb_add_char (&label, *string);
4440
4441       string ++;
4442     }
4443
4444   ptr = hash_create (&vars, &label);
4445   free_old_entry (ptr);
4446   ptr->type = hash_integer;
4447   ptr->value.i = res;
4448   sb_kill (&label);
4449 }
4450 char *program_name;
4451
4452 /* The list of long options.  */
4453 static struct option long_options[] =
4454 {
4455   { "alternate", no_argument, 0, 'a' },
4456   { "include", required_argument, 0, 'I' },
4457   { "commentchar", required_argument, 0, 'c' },
4458   { "copysource", no_argument, 0, 's' },
4459   { "debug", no_argument, 0, 'd' },
4460   { "help", no_argument, 0, 'h' },
4461   { "mri", no_argument, 0, 'M' },
4462   { "output", required_argument, 0, 'o' },
4463   { "print", no_argument, 0, 'p' },
4464   { "unreasonable", no_argument, 0, 'u' },
4465   { "version", no_argument, 0, 'v' },
4466   { "define", required_argument, 0, 'd' },
4467   { NULL, no_argument, 0, 0 }
4468 };
4469
4470 /* Show a usage message and exit.  */
4471 static void
4472 show_usage (file, status)
4473      FILE *file;
4474      int status;
4475 {
4476   fprintf (file, "\
4477 Usage: %s \n\
4478   [-a]      [--alternate]         enter alternate macro mode\n\
4479   [-c char] [--commentchar char]  change the comment character from !\n\
4480   [-d]      [--debug]             print some debugging info\n\
4481   [-h]      [--help]              print this message\n\
4482   [-M]      [--mri]               enter MRI compatibility mode\n\
4483   [-o out]  [--output out]        set the output file\n\
4484   [-p]      [--print]             print line numbers\n\
4485   [-s]      [--copysource]        copy source through as comments \n\
4486   [-u]      [--unreasonable]      allow unreasonable nesting\n\
4487   [-v]      [--version]           print the program version\n\
4488   [-Dname=value]                  create preprocessor variable called name, with value\n\
4489   [-Ipath]                        add to include path list\n\
4490   [in-file]\n",   program_name);
4491   exit (status);
4492 }
4493
4494 /* Display a help message and exit.  */
4495 static void
4496 show_help ()
4497 {
4498   printf ("%s: Gnu Assembler Macro Preprocessor\n",
4499           program_name);
4500   show_usage (stdout, 0);
4501 }
4502
4503 int
4504 main (argc, argv)
4505      int argc;
4506      char **argv;
4507 {
4508   int opt;
4509   char *out_name = 0;
4510   sp = include_stack;
4511
4512   ifstack[0].on = 1;
4513   ifi = 0;
4514
4515
4516
4517   program_name = argv[0];
4518   xmalloc_set_program_name (program_name);
4519
4520   hash_new_table (101, &macro_table);
4521   hash_new_table (101, &keyword_hash_table);
4522   hash_new_table (101, &assign_hash_table);
4523   hash_new_table (101, &vars);
4524
4525   sb_new (&label);
4526
4527   while ((opt = getopt_long (argc, argv, "I:sdhavc:upo:D:M", long_options,
4528                              (int *) NULL))
4529          != EOF)
4530     {
4531       switch (opt)
4532         {
4533         case 'o':
4534           out_name = optarg;
4535           break;
4536         case 'u':
4537           unreasonable = 1;
4538           break;
4539         case 'I':
4540           {
4541             include_path *p = (include_path *) xmalloc (sizeof (include_path));
4542             sb_new (&p->path);
4543             sb_add_string (&p->path, optarg);
4544             if (paths_tail)
4545               paths_tail->next = p;
4546             else
4547               paths_head = p;
4548             paths_tail = p;
4549           }
4550           break;
4551         case 'p':
4552           print_line_number = 1;
4553           break;
4554         case 'c':
4555           comment_char = optarg[0];
4556           break;
4557         case 'a':
4558           alternate = 1;
4559           break;
4560         case 's':
4561           copysource = 1;
4562           break;
4563         case 'd':
4564           stats = 1;
4565           break;
4566         case 'D':
4567           do_define (optarg);
4568           break;
4569         case 'M':
4570           mri = 1;
4571           break;
4572         case 'h':
4573           show_help ();
4574           /*NOTREACHED*/
4575         case 'v':
4576           printf ("GNU %s version %s\n", program_name, program_version);
4577           exit (0);
4578           /*NOTREACHED*/
4579         case 0:
4580           break;
4581         default:
4582           show_usage (stderr, 1);
4583           /*NOTREACHED*/
4584         }
4585     }
4586
4587   process_init ();
4588
4589   if (out_name) {
4590     outfile = fopen (out_name, "w");
4591     if (!outfile)
4592       {
4593         fprintf (stderr, "%s: Can't open output file `%s'.\n",
4594                  program_name, out_name);
4595         exit (1);
4596       }
4597   }
4598   else  {
4599     outfile = stdout;
4600   }
4601
4602   chartype_init ();
4603   if (!outfile)
4604     outfile = stdout;
4605
4606   /* Process all the input files */
4607
4608   while (optind < argc)
4609     {
4610       if (new_file (argv[optind]))
4611         {
4612           process_file ();
4613         }
4614       else
4615         {
4616           fprintf (stderr, "%s: Can't open input file `%s'.\n",
4617                    program_name, argv[optind]);
4618           exit (1);
4619         }
4620       optind++;
4621     }
4622
4623   quit ();
4624   return 0;
4625 }