0380543b8846510cae89b5ad599bde3fc2db898d
[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 - 1);
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 if (mri
2181                && (line.ptr[0] == '*'
2182                    || line.ptr[0] == '!'))
2183         {
2184           /* MRI line comment.  */
2185           fprintf (outfile, sb_name (&line));
2186         }
2187       else
2188         {
2189           l = grab_label (&line, &label_in);
2190           sb_reset (&label);              
2191           if (label_in.len)
2192             {
2193               /* Munge any label */
2194
2195               
2196               process_assigns (0, &label_in, &label);
2197             }
2198
2199           if (line.ptr[l] == ':')
2200             l++;
2201           while (ISWHITE (line.ptr[l]) && l < line.len)
2202             l++;
2203
2204           if (l < line.len)
2205             {
2206               if (process_pseudo_op (l, &line, &acc))
2207                 {
2208
2209
2210
2211                 }
2212               else if (condass_on ())
2213                 {
2214                   if (macro_op (l, &line))
2215                     {
2216
2217
2218                     }
2219                   else
2220                     {
2221                       {
2222                         if (label.len)
2223                           {
2224                             fprintf (outfile, "%s:\t", sb_name (&label));
2225                           }
2226                         else
2227                           fprintf (outfile, "\t");
2228                         sb_reset(&t1);
2229                         process_assigns (l, &line, &t1);
2230                         sb_reset (&t2);
2231                         change_base (0, &t1, &t2);
2232                         fprintf (outfile, "%s\n", sb_name (&t2));
2233                       }
2234                     }
2235                 }
2236             }
2237           else {
2238             /* Only a label on this line */
2239             if (label.len && condass_on())
2240               {
2241                 fprintf (outfile, "%s:\n", sb_name (&label));
2242               }
2243           }
2244         }
2245
2246       if (had_end)
2247         break;
2248       sb_reset (&line);
2249       more = get_line (&line);
2250     }
2251
2252   if (!had_end && !mri)
2253     WARNING ((stderr, "END missing from end of file.\n"));
2254 }
2255
2256
2257
2258
2259
2260 static void
2261 free_old_entry (ptr)
2262      hash_entry *ptr;
2263 {
2264   if (ptr)
2265     {
2266       if (ptr->type == hash_string)
2267         sb_kill(&ptr->value.s);
2268     }
2269 }
2270
2271 /* name: .ASSIGNA <value> */
2272
2273 static void
2274 do_assigna (idx, in)
2275      int idx;
2276      sb *in;
2277 {
2278   sb tmp;
2279   int val;
2280   sb_new (&tmp);
2281
2282   process_assigns (idx, in, &tmp);
2283   idx = exp_get_abs (".ASSIGNA needs constant expression argument.\n", 0, &tmp, &val);
2284
2285   if (!label.len)
2286     {
2287       ERROR ((stderr, ".ASSIGNA without label.\n"));
2288     }
2289   else
2290     {
2291       hash_entry *ptr = hash_create (&vars, &label);
2292       free_old_entry (ptr);
2293       ptr->type = hash_integer;
2294       ptr->value.i = val;
2295     }
2296   sb_kill (&tmp);
2297 }
2298
2299 /* name: .ASSIGNC <string> */
2300
2301 static void
2302 do_assignc (idx, in)
2303      int idx;
2304      sb *in;
2305 {
2306   sb acc;
2307   sb_new (&acc);
2308   idx = getstring (idx, in, &acc);
2309
2310   if (!label.len)
2311     {
2312       ERROR ((stderr, ".ASSIGNS without label.\n"));
2313     }
2314   else
2315     {
2316       hash_entry *ptr = hash_create (&vars, &label);
2317       free_old_entry (ptr);
2318       ptr->type = hash_string;
2319       sb_new (&ptr->value.s);
2320       sb_add_sb (&ptr->value.s, &acc);
2321     }
2322   sb_kill (&acc);
2323 }
2324
2325
2326 /* name: .REG (reg) */
2327
2328 static void
2329 do_reg (idx, in)
2330      int idx;
2331      sb *in;
2332 {
2333   /* remove reg stuff from inside parens */
2334   sb what;
2335   if (!mri)
2336     idx = skip_openp (idx, in);
2337   else
2338     idx = sb_skip_white (idx, in);
2339   sb_new (&what);
2340   while (idx < in->len
2341          && (mri
2342              ? ! eol (idx, in)
2343              : in->ptr[idx] != ')'))
2344     {
2345       sb_add_char (&what, in->ptr[idx]);
2346       idx++;
2347     }
2348   hash_add_to_string_table (&assign_hash_table, &label, &what, 1);
2349   sb_kill (&what);
2350 }
2351
2352
2353 static int
2354 condass_lookup_name (inbuf, idx, out, warn)
2355      sb *inbuf;
2356      int idx;
2357      sb *out;
2358      int warn;
2359 {
2360   hash_entry *ptr;
2361   sb condass_acc;
2362   sb_new (&condass_acc);
2363
2364   while (idx < inbuf->len
2365          && ISNEXTCHAR (inbuf->ptr[idx]))
2366     {
2367       sb_add_char (&condass_acc, inbuf->ptr[idx++]);
2368     }
2369
2370   if (inbuf->ptr[idx] == '\'')
2371     idx++;
2372   ptr = hash_lookup (&vars, &condass_acc);
2373
2374
2375   if (!ptr)
2376     {
2377       if (warn) 
2378         {
2379           WARNING ((stderr, "Can't find preprocessor variable %s.\n", sb_name (&condass_acc)));
2380         }
2381       else 
2382         {
2383           sb_add_string (out, "0");
2384         }
2385     }
2386   else
2387     {
2388       if (ptr->type == hash_integer)
2389         {
2390           char buffer[30];
2391           sprintf (buffer, "%d", ptr->value.i);
2392           sb_add_string (out, buffer);
2393         }
2394       else
2395         {
2396           sb_add_sb (out, &ptr->value.s);
2397         }
2398     }
2399   sb_kill (&condass_acc);
2400   return idx;
2401 }
2402
2403 #define EQ 1
2404 #define NE 2
2405 #define GE 3
2406 #define LT 4
2407 #define LE 5
2408 #define GT 6
2409 #define NEVER 7
2410
2411 static int
2412 whatcond (idx, in, val)
2413      int idx;
2414      sb *in;
2415      int *val;
2416 {
2417   int cond;
2418
2419   idx = sb_skip_white (idx, in);
2420   cond = NEVER;
2421   if (idx + 1 < in->len)
2422     {
2423       char *p;
2424       char a, b;
2425
2426       p = in->ptr + idx;
2427       a = toupper ((unsigned char) p[0]);
2428       b = toupper ((unsigned char) p[1]);
2429       if (a == 'E' && b == 'Q')
2430         cond = EQ;
2431       else if (a == 'N' && b == 'E')
2432         cond = NE;
2433       else if (a == 'L' && b == 'T')
2434         cond = LT;
2435       else if (a == 'L' && b == 'E')
2436         cond = LE;
2437       else if (a == 'G' && b == 'T')
2438         cond = GT;
2439       else if (a == 'G' && b == 'E')
2440         cond = GE;
2441     }
2442   if (cond == NEVER)
2443     {
2444       ERROR ((stderr, "Comparison operator must be one of EQ, NE, LT, LE, GT or GE.\n"));
2445       cond = NEVER;
2446     }
2447   idx = sb_skip_white (idx + 2, in);
2448   *val = cond;
2449   return idx;
2450 }
2451
2452 static int
2453 istrue (idx, in)
2454      int idx;
2455      sb *in;
2456 {
2457   int res;
2458   sb acc_a;
2459   sb cond;
2460   sb acc_b;
2461   sb_new (&acc_a);
2462   sb_new (&cond);
2463   sb_new (&acc_b);
2464   idx = sb_skip_white (idx, in);
2465
2466   if (in->ptr[idx] == '"')
2467     {
2468       int cond;
2469       int same;
2470       /* This is a string comparision */
2471       idx = getstring (idx, in, &acc_a);
2472       idx = whatcond (idx, in, &cond);
2473       idx = getstring (idx, in, &acc_b);
2474       same = acc_a.len == acc_b.len && (strncmp (acc_a.ptr, acc_b.ptr, acc_a.len) == 0);
2475
2476       if (cond != EQ && cond != NE)
2477         {
2478           ERROR ((stderr, "Comparison operator for strings must be EQ or NE\n"));
2479           res = 0;
2480         }
2481       else
2482         res = (cond != EQ) ^ same;
2483     }
2484   else
2485     /* This is a numeric expression */
2486     {
2487       int vala;
2488       int valb;
2489       int cond;
2490       idx = exp_get_abs ("Conditional operator must have absolute operands.\n", idx, in, &vala);
2491       idx = whatcond (idx, in, &cond);
2492       idx = sb_skip_white (idx, in);
2493       if (in->ptr[idx] == '"')
2494         {
2495           WARNING ((stderr, "String compared against expression.\n"));
2496           res = 0;
2497         }
2498       else
2499         {
2500           idx = exp_get_abs ("Conditional operator must have absolute operands.\n", idx, in, &valb);
2501           switch (cond)
2502             {
2503             default:
2504               res = 42;
2505               break;
2506             case EQ:
2507               res = vala == valb;
2508               break;
2509             case NE:
2510               res = vala != valb;
2511               break;
2512             case LT:
2513               res = vala < valb;
2514               break;
2515             case LE:
2516               res = vala <= valb;
2517               break;
2518             case GT:
2519               res = vala > valb;
2520               break;
2521             case GE:
2522               res = vala >= valb;
2523               break;
2524             case NEVER:
2525               res = 0;
2526               break;
2527             }
2528         }
2529     }
2530
2531   sb_kill (&acc_a);
2532   sb_kill (&cond);
2533   sb_kill (&acc_b);
2534   return res;
2535 }
2536
2537 /* .AIF */
2538 static void
2539 do_aif (idx, in)
2540      int idx;
2541      sb *in;
2542 {
2543   if (ifi >= IFNESTING)
2544     {
2545       FATAL ((stderr, "AIF nesting unreasonable.\n"));
2546     }
2547   ifi++;
2548   ifstack[ifi].on = ifstack[ifi-1].on ? istrue (idx, in) : 0;
2549   ifstack[ifi].hadelse = 0;
2550 }
2551
2552
2553 /* .AELSE */
2554 static void
2555 do_aelse ()
2556 {
2557   ifstack[ifi].on = ifstack[ifi-1].on ? !ifstack[ifi].on : 0;
2558   if (ifstack[ifi].hadelse)
2559     {
2560       ERROR ((stderr, "Multiple AELSEs in AIF.\n"));
2561     }
2562   ifstack[ifi].hadelse = 1;
2563 }
2564
2565
2566 /* .AENDI */
2567 static void
2568 do_aendi ()
2569 {
2570   if (ifi != 0)
2571     {
2572       ifi--;
2573     }
2574   else
2575     {
2576       ERROR ((stderr, "AENDI without AIF.\n"));
2577     }
2578 }
2579
2580 static int
2581 condass_on ()
2582 {
2583   return ifstack[ifi].on;
2584 }
2585
2586 /* MRI IFEQ, IFNE, IFLT, IFLE, IFGE, IFGT.  */
2587
2588 static void
2589 do_if (idx, in, cond)
2590      int idx;
2591      sb *in;
2592      int cond;
2593 {
2594   int val;
2595   int res;
2596
2597   if (ifi >= IFNESTING)
2598     {
2599       FATAL ((stderr, "IF nesting unreasonable.\n"));
2600     }
2601
2602   idx = exp_get_abs ("Conditional operator must have absolute operands.\n",
2603                      idx, in, &val);
2604   switch (cond)
2605     {
2606     default:
2607     case EQ: res = val == 0; break;
2608     case NE: res = val != 0; break;
2609     case LT: res = val <  0; break;
2610     case LE: res = val <= 0; break;
2611     case GE: res = val >= 0; break;
2612     case GT: res = val >  0; break;
2613     }
2614
2615   ifi++;
2616   ifstack[ifi].on = ifstack[ifi-1].on ? res: 0;
2617   ifstack[ifi].hadelse = 0;
2618 }
2619
2620 /* Get a string for the MRI IFC or IFNC pseudo-ops.  */
2621
2622 static int
2623 get_mri_string (idx, in, val, terminator)
2624      int idx;
2625      sb *in;
2626      sb *val;
2627      int terminator;
2628 {
2629   idx = sb_skip_white (idx, in);
2630
2631   if (idx < in->len
2632       && in->ptr[idx] == '\'')
2633     {
2634       sb_add_char (val, '\'');
2635       for (++idx; idx < in->len; ++idx)
2636         {
2637           sb_add_char (val, in->ptr[idx]);
2638           if (in->ptr[idx] == '\'')
2639             {
2640               ++idx;
2641               if (idx >= in->len
2642                   || in->ptr[idx] != '\'')
2643                 break;
2644             }
2645         }
2646       idx = sb_skip_white (idx, in);
2647     }
2648   else
2649     {
2650       int i;
2651
2652       while (idx < in->len
2653              && in->ptr[idx] != terminator)
2654         {
2655           sb_add_char (val, in->ptr[idx]);
2656           ++idx;
2657         }
2658       i = val->len - 1;
2659       while (i >= 0 && ISWHITE (val->ptr[i]))
2660         --i;
2661       val->len = i + 1;
2662     }
2663
2664   return idx;
2665 }
2666
2667 /* MRI IFC, IFNC.  */
2668
2669 static void
2670 do_ifc (idx, in, ifnc)
2671      int idx;
2672      sb *in;
2673      int ifnc;
2674 {
2675   sb first;
2676   sb second;
2677   int res;
2678
2679   if (ifi >= IFNESTING)
2680     {
2681       FATAL ((stderr, "IF nesting unreasonable.\n"));
2682     }
2683
2684   sb_new (&first);
2685   sb_new (&second);
2686
2687   idx = get_mri_string (idx, in, &first, ',');
2688
2689   if (idx >= in->len || in->ptr[idx] != ',')
2690     {
2691       ERROR ((stderr, "Bad format for IF or IFNC.\n"));
2692       return;
2693     }
2694
2695   idx = get_mri_string (idx + 1, in, &second, ';');
2696
2697   res = (first.len == second.len
2698          && strncmp (first.ptr, second.ptr, first.len) == 0);
2699   res ^= ifnc;
2700
2701   ifi++;
2702   ifstack[ifi].on = ifstack[ifi-1].on ? res : 0;
2703   ifstack[ifi].hadelse = 0;
2704 }
2705
2706 /* Read input lines till we get to a TO string.
2707    Increase nesting depth if we geta FROM string.
2708    Put the results into sb at PTR. */
2709
2710 static void
2711 buffer_and_nest (from, to, ptr)
2712      const char *from;
2713      const char *to;
2714      sb *ptr;
2715 {
2716   int from_len = strlen (from);
2717   int to_len = strlen (to);
2718   int depth = 1;
2719   int line_start = ptr->len;
2720   int line = linecount ();
2721
2722   int more = get_line (ptr);
2723
2724   while (more)
2725     {
2726       /* Try and find the first pseudo op on the line */
2727       int i = line_start;
2728
2729       if (!alternate && !mri)
2730         {
2731           /* With normal syntax we can suck what we want till we get
2732              to the dot.  With the alternate, labels have to start in
2733              the first column, since we cant tell what's a label and
2734              whats a pseudoop */
2735
2736           /* Skip leading whitespace */
2737           while (i < ptr->len
2738                  && ISWHITE (ptr->ptr[i]))
2739             i++;
2740
2741           /* Skip over a label */
2742           while (i < ptr->len
2743                  && ISNEXTCHAR (ptr->ptr[i]))
2744             i++;
2745
2746           /* And a colon */
2747           if (i < ptr->len
2748               && ptr->ptr[i] == ':')
2749             i++;
2750
2751         }
2752       /* Skip trailing whitespace */
2753       while (i < ptr->len
2754              && ISWHITE (ptr->ptr[i]))
2755         i++;
2756
2757       if (i < ptr->len && (ptr->ptr[i] == '.' 
2758                            || alternate
2759                            || mri))
2760         {
2761           if (ptr->ptr[i] == '.')
2762               i++;
2763           if (strncasecmp (ptr->ptr + i, from, from_len) == 0)
2764             depth++;
2765           if (strncasecmp (ptr->ptr + i, to, to_len) == 0)
2766             {
2767               depth--;
2768               if (depth == 0)
2769                 {
2770                   /* Reset the string to not include the ending rune */
2771                   ptr->len = line_start;
2772                   break;
2773                 }
2774             }
2775         }
2776
2777       /* Add a CR to the end and keep running */
2778       sb_add_char (ptr, '\n');
2779       line_start = ptr->len;
2780       more = get_line (ptr);
2781     }
2782
2783
2784   if (depth)
2785     FATAL ((stderr, "End of file whilst inside %s, started on line %d.\n", from, line));
2786 }
2787
2788
2789 /* .ENDR */
2790 static void
2791 do_aendr ()
2792 {
2793   if (!mri)
2794     ERROR ((stderr, "AENDR without a AREPEAT.\n"));
2795   else
2796     ERROR ((stderr, "ENDR without a REPT.\n"));
2797 }
2798
2799 /* .AWHILE */
2800
2801 static
2802 void
2803 do_awhile (idx, in)
2804      int idx;
2805      sb *in;
2806 {
2807   sb exp;
2808
2809   sb sub;
2810
2811   int doit;
2812   sb_new (&sub);
2813   sb_new (&exp);
2814
2815   process_assigns (idx, in, &exp);
2816   doit = istrue (0, &exp);
2817
2818   buffer_and_nest ("AWHILE", "AENDW", &sub);
2819
2820   /* Turn
2821         .AWHILE exp
2822              foo
2823         .AENDW
2824      into
2825         foo
2826         .AWHILE exp
2827         foo
2828         .ENDW
2829    */
2830
2831   if (doit)
2832     {
2833       int index = include_next_index ();
2834
2835       sb copy;
2836       sb_new (&copy);
2837       sb_add_sb (&copy, &sub);
2838       sb_add_sb (&copy, in);
2839       sb_add_string (&copy, "\n");
2840       sb_add_sb (&copy, &sub);
2841       sb_add_string (&copy, "\t.AENDW\n");
2842       /* Push another WHILE */
2843       include_buf (&exp, &copy, include_while, index);
2844       sb_kill (&copy);
2845     }
2846   sb_kill (&exp);
2847   sb_kill (&sub);
2848 }
2849
2850
2851 /* .AENDW */
2852
2853 static void
2854 do_aendw ()
2855 {
2856   ERROR ((stderr, "AENDW without a AENDW.\n"));
2857 }
2858
2859
2860 /* .EXITM
2861    
2862    Pop things off the include stack until the type and index changes */
2863
2864 static void
2865 do_exitm ()
2866 {
2867   include_type type = sp->type;
2868   if (type == include_repeat
2869       || type == include_while
2870       || type == include_macro)
2871     {
2872       int index = sp->index;
2873       include_pop ();
2874       while (sp->index == index
2875              && sp->type == type)
2876         {
2877           include_pop ();
2878         }
2879     }
2880 }
2881
2882 /* .AREPEAT */
2883
2884 static void
2885 do_arepeat (idx, in)
2886      int idx;
2887      sb *in;
2888 {
2889   sb exp;                       /* buffer with expression in it */
2890   sb copy;                      /* expanded repeat block */
2891   sb sub;                       /* contents of AREPEAT */
2892   int rc;
2893   char buffer[30];
2894   sb_new (&exp);
2895   sb_new (&copy);
2896   sb_new (&sub);
2897   process_assigns (idx, in, &exp);
2898   idx = exp_get_abs ("AREPEAT must have absolute operand.\n", 0, &exp, &rc);
2899   if (!mri)
2900     buffer_and_nest ("AREPEAT", "AENDR", &sub);
2901   else
2902     buffer_and_nest ("REPT", "ENDR", &sub);
2903   if (rc > 0)
2904     {
2905       /* Push back the text following the repeat, and another repeat block
2906          so
2907          .AREPEAT 20
2908          foo
2909          .AENDR
2910          gets turned into
2911          foo
2912          .AREPEAT 19
2913          foo
2914          .AENDR
2915          */
2916       int index = include_next_index ();
2917       sb_add_sb (&copy, &sub);
2918       if (rc > 1)
2919         {
2920           if (!mri)
2921             sprintf (buffer, "\t.AREPEAT        %d\n", rc - 1);
2922           else
2923             sprintf (buffer, "\tREPT    %d\n", rc - 1);
2924           sb_add_string (&copy, buffer);
2925           sb_add_sb (&copy, &sub);
2926           if (!mri)
2927             sb_add_string (&copy, "     .AENDR\n");
2928           else
2929             sb_add_string (&copy, "     ENDR\n");
2930         }
2931
2932       include_buf (&exp, &copy, include_repeat, index);
2933     }
2934   sb_kill (&exp);
2935   sb_kill (&sub);
2936   sb_kill (&copy);
2937 }
2938
2939 /* .ENDM */
2940
2941 static void
2942 do_endm ()
2943 {
2944   ERROR ((stderr, ".ENDM without a matching .MACRO.\n"));
2945 }
2946
2947 /* MRI IRP pseudo-op.  */
2948
2949 static void
2950 do_irp (idx, in, irpc)
2951      int idx;
2952      sb *in;
2953      int irpc;
2954 {
2955   const char *mn;
2956   sb sub;
2957   formal_entry f;
2958   hash_table h;
2959   hash_entry *p;
2960   sb name;
2961   sb out;
2962
2963   if (irpc)
2964     mn = "IRPC";
2965   else
2966     mn = "IRP";
2967
2968   idx = sb_skip_white (idx, in);
2969
2970   sb_new (&sub);
2971   buffer_and_nest (mn, "ENDR", &sub);
2972   
2973   sb_new (&f.name);
2974   sb_new (&f.def);
2975   sb_new (&f.actual);
2976
2977   idx = get_token (idx, in, &f.name);
2978   if (f.name.len == 0)
2979     {
2980       ERROR ((stderr, "Missing model parameter in %s", mn));
2981       return;
2982     }
2983
2984   hash_new_table (1, &h);
2985   p = hash_create (&h, &f.name);
2986   p->type = hash_formal;
2987   p->value.f = &f;
2988
2989   f.index = 1;
2990   f.next = NULL;
2991
2992   sb_new (&name);
2993   sb_add_string (&name, mn);
2994
2995   sb_new (&out);
2996
2997   idx = sb_skip_comma (idx, in);
2998   if (eol (idx, in))
2999     {
3000       /* Expand once with a null string.  */
3001       macro_expand_body (&name, &sub, &out, &f, &h);
3002       fprintf (outfile, "%s", sb_name (&out));
3003     }
3004   else
3005     {
3006       while (!eol (idx, in))
3007         {
3008           if (!irpc)
3009             idx = get_any_string (idx, in, &f.actual, 1, 0);
3010           else
3011             {
3012               sb_reset (&f.actual);
3013               sb_add_char (&f.actual, in->ptr[idx]);
3014               ++idx;
3015             }
3016           sb_reset (&out);
3017           macro_expand_body (&name, &sub, &out, &f, &h);
3018           fprintf (outfile, "%s", sb_name (&out));
3019           if (!irpc)
3020             idx = sb_skip_comma (idx, in);
3021           else
3022             idx = sb_skip_white (idx, in);
3023         }
3024     }
3025
3026   sb_kill (&sub);
3027   sb_kill (&name);
3028   sb_kill (&out);
3029 }
3030
3031 /* MACRO PROCESSING */
3032
3033 static int number;
3034 hash_table macro_table;
3035
3036 /* Understand
3037
3038    .MACRO <name>
3039    stuff
3040    .ENDM
3041 */
3042
3043 static int
3044 do_formals (macro, idx, in)
3045      macro_entry *macro;
3046      int idx;
3047      sb *in;
3048 {
3049   formal_entry **p = &macro->formals;
3050   macro->formal_count = 0;
3051   hash_new_table (5, &macro->formal_hash);
3052   while (idx < in->len)
3053     {
3054       formal_entry *formal;
3055
3056       formal = (formal_entry *) xmalloc (sizeof (formal_entry));
3057
3058       sb_new (&formal->name);
3059       sb_new (&formal->def);
3060       sb_new (&formal->actual);
3061
3062       idx = sb_skip_white (idx, in);
3063       idx = get_token (idx, in, &formal->name);
3064       if (formal->name.len == 0)
3065         break;
3066       idx = sb_skip_white (idx, in);
3067       if (formal->name.len)
3068         {
3069           /* This is a formal */
3070           if (idx < in->len && in->ptr[idx] == '=')
3071             {
3072               /* Got a default */
3073               idx = get_any_string (idx + 1, in, &formal->def, 1, 0);
3074             }
3075         }
3076
3077       {
3078         /* Add to macro's hash table */
3079
3080         hash_entry *p = hash_create (&macro->formal_hash, &formal->name);
3081         p->type = hash_formal;
3082         p->value.f = formal;
3083       }
3084
3085       formal->index = macro->formal_count;
3086       idx = sb_skip_comma (idx, in);
3087       macro->formal_count++;
3088       *p = formal;
3089       p = &formal->next;
3090       *p = NULL;
3091     }
3092
3093   if (mri)
3094     {
3095       formal_entry *formal;
3096
3097       /* Add a special NARG formal, which macro_expand will set to the
3098          number of arguments.  */
3099       formal = (formal_entry *) xmalloc (sizeof (formal_entry));
3100
3101       sb_new (&formal->name);
3102       sb_new (&formal->def);
3103       sb_new (&formal->actual);
3104
3105       sb_add_string (&formal->name, "NARG");
3106
3107       {
3108         /* Add to macro's hash table */
3109
3110         hash_entry *p = hash_create (&macro->formal_hash, &formal->name);
3111         p->type = hash_formal;
3112         p->value.f = formal;
3113       }
3114
3115       formal->index = -2;
3116       *p = formal;
3117       formal->next = NULL;
3118     }
3119
3120   return idx;
3121 }
3122
3123 /* Parse off LOCAL n1, n2,... Invent a label name for it */
3124 static
3125 void 
3126 do_local (idx, line)
3127      int idx;
3128      sb *line;
3129 {
3130   static int ln;
3131   sb acc;
3132   sb sub;
3133   char subs[10];
3134   sb_new (&acc);
3135   sb_new (&sub);
3136   idx = sb_skip_white (idx, line);
3137   while (!eol(idx, line))
3138     {
3139       sb_reset (&acc);
3140       sb_reset (&sub);
3141       ln++;
3142       sprintf(subs, "LL%04x", ln);
3143       idx =  get_token(idx, line, &acc);
3144       sb_add_string (&sub, subs);
3145       hash_add_to_string_table (&assign_hash_table, &acc, &sub, 1);
3146       idx = sb_skip_comma (idx, line);
3147     }
3148   sb_kill (&sub);
3149   sb_kill (&acc);
3150 }
3151
3152 static
3153 void
3154 do_macro (idx, in)
3155      int idx;
3156      sb *in;
3157 {
3158   macro_entry *macro;
3159   sb name;
3160
3161   macro = (macro_entry *) xmalloc (sizeof (macro_entry));
3162   sb_new (&macro->sub);
3163   sb_new (&name);
3164
3165   macro->formal_count = 0;
3166   macro->formals = 0;
3167
3168   idx = sb_skip_white (idx, in);
3169   buffer_and_nest ("MACRO", "ENDM", &macro->sub);
3170   if (label.len)
3171     {
3172
3173       sb_add_sb (&name, &label);
3174       if (in->ptr[idx] == '(')
3175         {
3176           /* It's the label: MACRO (formals,...)  sort */
3177           idx = do_formals (macro, idx + 1, in);
3178           if (in->ptr[idx] != ')')
3179             ERROR ((stderr, "Missing ) after formals.\n"));
3180         }
3181       else {
3182         /* It's the label: MACRO formals,...  sort */
3183         idx = do_formals (macro, idx, in);
3184       }
3185     }
3186   else
3187     {
3188       idx = get_token (idx, in, &name);
3189       idx = sb_skip_white (idx, in);
3190       idx = do_formals (macro, idx, in);
3191     }
3192
3193   /* and stick it in the macro hash table */
3194   hash_create (&macro_table, &name)->value.m = macro;
3195 }
3196
3197 static
3198 int
3199 get_token (idx, in, name)
3200      int idx;
3201      sb *in;
3202      sb *name;
3203 {
3204   if (idx < in->len
3205       && ISFIRSTCHAR (in->ptr[idx]))
3206     {
3207       sb_add_char (name, in->ptr[idx++]);
3208       while (idx < in->len
3209              && ISNEXTCHAR (in->ptr[idx]))
3210         {
3211           sb_add_char (name, in->ptr[idx++]);
3212         }
3213     }
3214   /* Ignore trailing & */
3215   if (alternate && idx < in->len && in->ptr[idx] == '&')
3216     idx++;
3217   return idx;
3218 }
3219
3220 /* Scan a token, but stop if a ' is seen */
3221 static int
3222 get_apost_token (idx, in, name, kind)
3223      int idx;
3224      sb *in;
3225      sb *name;
3226      int kind;
3227 {
3228   idx = get_token (idx, in, name);
3229   if (idx < in->len && in->ptr[idx] == kind)
3230     idx++;
3231   return idx;
3232 }
3233
3234 static int
3235 sub_actual (src, in, t, formal_hash, kind, out, copyifnotthere)
3236      int src;
3237      sb *in;
3238      sb *t;
3239      hash_table *formal_hash;
3240      int kind;
3241      sb *out;
3242      int copyifnotthere;
3243 {
3244   /* This is something to take care of */
3245   hash_entry *ptr;
3246   src = get_apost_token (src, in, t, kind);
3247   /* See if it's in the macro's hash table */
3248   ptr = hash_lookup (formal_hash, t);
3249   if (ptr)
3250     {
3251       if (ptr->value.f->actual.len)
3252         {
3253           sb_add_sb (out, &ptr->value.f->actual);
3254         }
3255       else
3256         {
3257           sb_add_sb (out, &ptr->value.f->def);
3258         }
3259     }
3260   else if (copyifnotthere)
3261     {
3262       sb_add_sb (out, t);
3263     }
3264   else 
3265     {
3266       sb_add_char (out, '\\');
3267       sb_add_sb (out, t);
3268     }
3269   return src;
3270 }
3271
3272 /* Copy the body from the macro buffer into a safe place and
3273    substitute any args.  */
3274
3275 static void
3276 macro_expand_body (name, in, out, formals, formal_hash)
3277      sb *name;
3278      sb *in;
3279      sb *out;
3280      formal_entry *formals;
3281      hash_table *formal_hash;
3282 {
3283   sb t;
3284   int src = 0;
3285   int inquote = 0;
3286
3287   sb_new (&t);
3288
3289   while (src < in->len)
3290     {
3291       if (in->ptr[src] == '&')
3292         {
3293           sb_reset (&t);
3294           if (mri && src + 1 < in->len && in->ptr[src + 1] == '&')
3295             {
3296               src = sub_actual (src + 2, in, &t, formal_hash, '\'', out, 1);
3297             }
3298           else
3299             {
3300               src = sub_actual (src + 1, in, &t, formal_hash, '&', out, 0);
3301             }
3302         }
3303       else if (in->ptr[src] == '\\')
3304         {
3305           src++;
3306           if (in->ptr[src] == comment_char)
3307             {
3308               /* This is a comment, just drop the rest of the line */
3309               while (src < in->len
3310                      && in->ptr[src] != '\n')
3311                 src++;
3312
3313             }
3314           else if (in->ptr[src] == '(')
3315             {
3316               /* Sub in till the next ')' literally */
3317               src++;
3318               while (src < in->len && in->ptr[src] != ')')
3319                 {
3320                   sb_add_char (out, in->ptr[src++]);
3321                 }
3322               if (in->ptr[src] == ')')
3323                 src++;
3324               else
3325                 ERROR ((stderr, "Missplaced ).\n"));
3326             }
3327           else if (in->ptr[src] == '@')
3328             {
3329               /* Sub in the macro invocation number */
3330
3331               char buffer[6];
3332               src++;
3333               sprintf (buffer, "%05d", number);
3334               sb_add_string (out, buffer);
3335             }
3336           else if (in->ptr[src] == '&')
3337             {
3338               /* This is a preprocessor variable name, we don't do them
3339                  here */
3340               sb_add_char (out, '\\');
3341               sb_add_char (out, '&');
3342               src++;
3343             }
3344           else if (mri
3345                    && isalnum ((unsigned char) in->ptr[src]))
3346             {
3347               int ind;
3348               formal_entry *f;
3349
3350               if (isdigit ((unsigned char) in->ptr[src]))
3351                 ind = in->ptr[src] - '0';
3352               else if (isupper ((unsigned char) in->ptr[src]))
3353                 ind = in->ptr[src] - 'A' + 10;
3354               else
3355                 ind = in->ptr[src] - 'a' + 10;
3356               ++src;
3357               for (f = formals; f != NULL; f = f->next)
3358                 {
3359                   if (f->index == ind - 1)
3360                     {
3361                       if (f->actual.len != 0)
3362                         sb_add_sb (out, &f->actual);
3363                       else
3364                         sb_add_sb (out, &f->def);
3365                       break;
3366                     }
3367                 }
3368             }
3369           else
3370             {
3371               sb_reset (&t);
3372               src = sub_actual (src, in, &t, formal_hash, '\'', out, 0);
3373             }
3374         }
3375       else if (ISFIRSTCHAR (in->ptr[src]) && (alternate || mri))
3376         {
3377           sb_reset (&t);
3378           src = sub_actual (src, in, &t, formal_hash, '\'', out, 1);
3379         }
3380       else if (ISCOMMENTCHAR (in->ptr[src])
3381                && src + 1 <  in->len
3382                && ISCOMMENTCHAR (in->ptr[src+1])
3383                && !inquote)
3384         {
3385           /* Two comment chars in a row cause the rest of the line to
3386              be dropped.  */
3387           while (src < in->len && in->ptr[src] != '\n')
3388             src++;
3389         }
3390       else if (in->ptr[src] == '"'
3391                || (mri && in->ptr[src] == '\''))
3392         {
3393           inquote = !inquote;
3394           sb_add_char (out, in->ptr[src++]);
3395         }
3396       else if (mri
3397                && in->ptr[src] == '='
3398                && src + 1 < in->len
3399                && in->ptr[src + 1] == '=')
3400         {
3401           hash_entry *ptr;
3402
3403           sb_reset (&t);
3404           src = get_token (src + 2, in, &t);
3405           ptr = hash_lookup (formal_hash, &t);
3406           if (ptr == NULL)
3407             {
3408               ERROR ((stderr, "MACRO formal argument %s does not exist.\n",
3409                       sb_name (&t)));
3410             }
3411           else
3412             {
3413               if (ptr->value.f->actual.len)
3414                 {
3415                   sb_add_string (out, "-1");
3416                 }
3417               else
3418                 {
3419                   sb_add_char (out, '0');
3420                 }
3421             }
3422         }
3423       else
3424         {
3425           sb_add_char (out, in->ptr[src++]);
3426         }
3427     }
3428
3429   sb_kill (&t);
3430 }
3431
3432 static void
3433 macro_expand (name, idx, in, m)
3434      sb *name;
3435      int idx;
3436      sb *in;
3437      macro_entry *m;
3438 {
3439   sb t;
3440   sb out;
3441   hash_entry *ptr;
3442   formal_entry *f;
3443   int is_positional = 0;
3444   int is_keyword = 0;
3445   int narg = 0;
3446
3447   sb_new (&t);
3448   sb_new (&out);
3449   
3450   /* Reset any old value the actuals may have */
3451   for (f = m->formals; f; f = f->next)
3452       sb_reset (&f->actual);
3453   f = m->formals;
3454
3455   if (mri)
3456     {
3457       /* The macro may be called with an optional qualifier, which may
3458          be referred to in the macro body as \0.  */
3459       if (idx < in->len && in->ptr[idx] == '.')
3460         {
3461           formal_entry *n;
3462
3463           n = (formal_entry *) xmalloc (sizeof (formal_entry));
3464           sb_new (&n->name);
3465           sb_new (&n->def);
3466           sb_new (&n->actual);
3467           n->index = -1;
3468
3469           n->next = m->formals;
3470           m->formals = n;
3471
3472           idx = get_any_string (idx + 1, in, &n->actual, 1, 0);
3473         }
3474     }
3475
3476   /* Peel off the actuals and store them away in the hash tables' actuals */
3477   while (!eol(idx, in))
3478     {
3479       int scan;
3480       idx = sb_skip_white (idx, in);
3481       /* Look and see if it's a positional or keyword arg */
3482       scan = idx;
3483       while (scan < in->len
3484              && !ISSEP (in->ptr[scan])
3485              && (!alternate && in->ptr[scan] != '='))
3486         scan++;
3487       if (scan < in->len && (!alternate) && in->ptr[scan] == '=')
3488         {
3489           is_keyword = 1;
3490           if (is_positional)
3491             {
3492               ERROR ((stderr, "Can't mix positional and keyword arguments.\n"));
3493               return;
3494             }
3495           /* This is a keyword arg, fetch the formal name and
3496              then the actual stuff */
3497           sb_reset (&t);
3498           idx = get_token (idx, in, &t);
3499           if (in->ptr[idx] != '=')
3500             ERROR ((stderr, "confused about formal params.\n"));
3501
3502           /* Lookup the formal in the macro's list */
3503           ptr = hash_lookup (&m->formal_hash, &t);
3504           if (!ptr)
3505             {
3506               ERROR ((stderr, "MACRO formal argument %s does not exist.\n", sb_name (&t)));
3507               return;
3508             }
3509           else
3510             {
3511               /* Insert this value into the right place */
3512               sb_reset (&ptr->value.f->actual);
3513               idx = get_any_string (idx + 1, in, &ptr->value.f->actual, 0, 0);
3514               if (ptr->value.f->actual.len > 0)
3515                 ++narg;
3516             }
3517         }
3518       else
3519         {
3520           /* This is a positional arg */
3521           is_positional = 1;
3522           if (is_keyword)
3523             {
3524               ERROR ((stderr, "Can't mix positional and keyword arguments.\n"));
3525               return;
3526             }
3527           if (!f)
3528             {
3529               formal_entry **pf;
3530               int c;
3531
3532               if (!mri)
3533                 {
3534                   ERROR ((stderr, "Too many positional arguments.\n"));
3535                   return;
3536                 }
3537               f = (formal_entry *) xmalloc (sizeof (formal_entry));
3538               sb_new (&f->name);
3539               sb_new (&f->def);
3540               sb_new (&f->actual);
3541               f->next = NULL;
3542
3543               c = -1;
3544               for (pf = &m->formals; *pf != NULL; pf = &(*pf)->next)
3545                 if ((*pf)->index >= c)
3546                   c = (*pf)->index + 1;
3547               *pf = f;
3548               f->index = c;
3549             }
3550
3551           sb_reset (&f->actual);
3552           idx = get_any_string (idx, in, &f->actual, 1, 0);
3553           if (f->actual.len > 0)
3554             ++narg;
3555           do
3556             {
3557               f = f->next;
3558             }
3559           while (f != NULL && f->index < 0);
3560         }
3561
3562       idx = sb_skip_comma (idx, in);
3563     }
3564
3565   if (mri)
3566     {
3567       char buffer[20];
3568
3569       sb_reset (&t);
3570       sb_add_string (&t, "NARG");
3571       ptr = hash_lookup (&m->formal_hash, &t);
3572       sb_reset (&ptr->value.f->actual);
3573       sprintf (buffer, "%d", narg);
3574       sb_add_string (&ptr->value.f->actual, buffer);
3575     }
3576
3577   macro_expand_body (name, &m->sub, &out, m->formals, &m->formal_hash);
3578
3579   include_buf (name, &out, include_macro, include_next_index ());
3580
3581   if (mri)
3582     {
3583       formal_entry **pf;
3584
3585       /* Discard any unnamed formal arguments.  */
3586       pf = &m->formals;
3587       while (*pf != NULL)
3588         {
3589           if ((*pf)->name.len != 0)
3590             pf = &(*pf)->next;
3591           else
3592             {
3593               sb_kill (&(*pf)->name);
3594               sb_kill (&(*pf)->def);
3595               sb_kill (&(*pf)->actual);
3596               f = (*pf)->next;
3597               free (*pf);
3598               *pf = f;
3599             }
3600         }
3601     }
3602
3603   sb_kill (&t);
3604   sb_kill (&out);
3605   number++;
3606 }
3607
3608 static int
3609 macro_op (idx, in)
3610      int idx;
3611      sb *in;
3612 {
3613   int res = 0;
3614   /* The macro name must be the first thing on the line */
3615   if (idx < in->len)
3616     {
3617       sb name;
3618       hash_entry *ptr;
3619       sb_new (&name);
3620       idx = get_token (idx, in, &name);
3621
3622       if (name.len)
3623         {
3624           /* Got a name, look it up */
3625
3626           ptr = hash_lookup (&macro_table, &name);
3627
3628           if (ptr)
3629             {
3630               /* It's in the table, copy out the stuff and convert any macro args */
3631               macro_expand (&name, idx, in, ptr->value.m);
3632               res = 1;
3633             }
3634         }
3635       sb_kill (&name);
3636     }
3637
3638
3639   return res;
3640 }
3641
3642
3643 /* STRING HANDLING */
3644
3645 static int
3646 getstring (idx, in, acc)
3647      int idx;
3648      sb *in;
3649      sb *acc;
3650 {
3651   idx = sb_skip_white (idx, in);
3652
3653   while (idx < in->len
3654          && (in->ptr[idx] == '"' 
3655              || in->ptr[idx] == '<' 
3656              || (in->ptr[idx] == '\'' && alternate)))
3657     {
3658       if (in->ptr[idx] == '<')
3659         {
3660           if (alternate || mri)
3661             {
3662               int nest = 0;
3663               idx++;
3664               while ((in->ptr[idx] != '>' || nest)
3665                      && idx < in->len)
3666                 {
3667                   if (in->ptr[idx] == '!')
3668                     {
3669                       idx++  ;
3670                       sb_add_char (acc, in->ptr[idx++]);
3671                     }
3672                   else {
3673                     if (in->ptr[idx] == '>')
3674                       nest--;
3675                     if (in->ptr[idx] == '<')
3676                       nest++;
3677                     sb_add_char (acc, in->ptr[idx++]);
3678                   }
3679                 }
3680               idx++;
3681             }
3682           else {
3683             int code;
3684             idx++;
3685             idx = exp_get_abs ("Character code in string must be absolute expression.\n",
3686                                idx, in, &code);
3687             sb_add_char (acc, code);
3688
3689             if (in->ptr[idx] != '>')
3690               ERROR ((stderr, "Missing > for character code.\n"));
3691             idx++;
3692           }
3693         }
3694       else if (in->ptr[idx] == '"' || in->ptr[idx] == '\'')
3695         {
3696           char tchar = in->ptr[idx];
3697           idx++;
3698           while (idx < in->len)
3699             {
3700               if (alternate && in->ptr[idx] == '!')
3701                 {
3702                   idx++  ;
3703                   sb_add_char (acc, in->ptr[idx++]);
3704                 }
3705               else {
3706                 if (in->ptr[idx] == tchar)
3707                   {
3708                     idx++;
3709                     if (idx >= in->len || in->ptr[idx] != tchar)
3710                       break;
3711                   }
3712                 sb_add_char (acc, in->ptr[idx]);
3713                 idx++;
3714               }
3715             }
3716         }
3717     }
3718   
3719   return idx;
3720 }
3721
3722 /* .SDATA[C|Z] <string> */
3723
3724 static
3725 void
3726 do_sdata (idx, in, type)
3727      int idx;
3728      sb *in;
3729      int type;
3730 {
3731   int nc = 0;
3732   int pidx = -1;
3733   sb acc;
3734   sb_new (&acc);
3735   fprintf (outfile, ".byte\t");
3736
3737   while (!eol (idx, in))
3738     {
3739       int i;
3740       sb_reset (&acc);
3741       idx = sb_skip_white (idx, in);
3742       while (!eol (idx, in))
3743         {
3744           pidx = idx = get_any_string (idx, in, &acc, 0, 1);
3745           if (type == 'c')
3746             {
3747               if (acc.len > 255)
3748                 {
3749                   ERROR ((stderr, "string for SDATAC longer than 255 characters (%d).\n", acc.len));
3750                 }
3751               fprintf (outfile, "%d", acc.len);
3752               nc = 1;
3753             }
3754
3755           for (i = 0; i < acc.len; i++)
3756             {
3757               if (nc)
3758                 {
3759                   fprintf (outfile, ",");
3760                 }
3761               fprintf (outfile, "%d", acc.ptr[i]);
3762               nc = 1;
3763             }
3764
3765           if (type == 'z')
3766             {
3767               if (nc)
3768                 fprintf (outfile, ",");
3769               fprintf (outfile, "0");
3770             }
3771           idx = sb_skip_comma (idx, in);
3772           if (idx == pidx) break;
3773         }
3774       if (!alternate && in->ptr[idx] != ',' && idx != in->len)
3775         {
3776           fprintf (outfile, "\n");
3777           ERROR ((stderr, "illegal character in SDATA line (0x%x).\n", in->ptr[idx]));
3778           break;
3779         }
3780       idx++;
3781     }
3782   sb_kill (&acc);
3783   fprintf (outfile, "\n");
3784 }
3785
3786 /* .SDATAB <count> <string> */
3787
3788 static void
3789 do_sdatab (idx, in)
3790      int idx;
3791      sb *in;
3792 {
3793   int repeat;
3794   int i;
3795   sb acc;
3796   sb_new (&acc);
3797
3798   idx = exp_get_abs ("Must have absolute SDATAB repeat count.\n", idx, in, &repeat);
3799   if (repeat <= 0)
3800     {
3801       ERROR ((stderr, "Must have positive SDATAB repeat count (%d).\n", repeat));
3802       repeat = 1;
3803     }
3804
3805   idx = sb_skip_comma (idx, in);
3806   idx = getstring (idx, in, &acc);
3807
3808   for (i = 0; i < repeat; i++)
3809     {
3810       if (i)
3811         fprintf (outfile, "\t");
3812       fprintf (outfile, ".byte\t");
3813       sb_print (&acc);
3814       fprintf (outfile, "\n");
3815     }
3816   sb_kill (&acc);
3817
3818 }
3819
3820 static int
3821 new_file (name)
3822      const char *name;
3823 {
3824   FILE *newone = fopen (name, "r");
3825   if (!newone)
3826     return 0;
3827
3828   if (isp == MAX_INCLUDES)
3829     FATAL ((stderr, "Unreasonable include depth (%ld).\n", (long) isp));
3830
3831   sp++;
3832   sp->handle = newone;
3833
3834   sb_new (&sp->name);
3835   sb_add_string (&sp->name, name);
3836
3837   sp->linecount = 1;
3838   sp->pushback_index = 0;
3839   sp->type = include_file;
3840   sp->index = 0;
3841   sb_new (&sp->pushback);
3842   return 1;
3843 }
3844
3845 static void
3846 do_include (idx, in)
3847      int idx;
3848      sb *in;
3849 {
3850   sb t;
3851   sb cat;
3852   include_path *includes;
3853
3854   sb_new (&t);
3855   sb_new (&cat);
3856
3857   if (! mri)
3858     idx = getstring (idx, in, &t);
3859   else
3860     {
3861       idx = sb_skip_white (idx, in);
3862       while (idx < in->len && ! ISWHITE (in->ptr[idx]))
3863         {
3864           sb_add_char (&t, in->ptr[idx]);
3865           ++idx;
3866         }
3867     }
3868
3869   for (includes = paths_head; includes; includes = includes->next)
3870     {
3871       sb_reset (&cat);
3872       sb_add_sb (&cat, &includes->path);
3873       sb_add_char (&cat, '/');
3874       sb_add_sb (&cat, &t);
3875       if (new_file (sb_name (&cat)))
3876         {
3877           break;
3878         }
3879     }
3880   if (!includes)
3881     {
3882       if (! new_file (sb_name (&t)))
3883         FATAL ((stderr, "Can't open include file `%s'.\n", sb_name (&t)));
3884     }
3885   sb_kill (&cat);
3886   sb_kill (&t);
3887 }
3888
3889 static void
3890 include_pop ()
3891 {
3892   if (sp != include_stack)
3893     {
3894       if (sp->handle)
3895         fclose (sp->handle);
3896       sp--;
3897     }
3898 }
3899
3900 /* Get the next character from the include stack.  If there's anything
3901    in the pushback buffer, take that first.  If we're at eof, pop from
3902    the stack and try again.  Keep the linecount up to date. */
3903
3904 static int
3905 get ()
3906 {
3907   int r;
3908
3909   if (sp->pushback.len != sp->pushback_index)
3910     {
3911       r = (char) (sp->pushback.ptr[sp->pushback_index++]);
3912       /* When they've all gone, reset the pointer */
3913       if (sp->pushback_index == sp->pushback.len)
3914         {
3915           sp->pushback.len = 0;
3916           sp->pushback_index = 0;
3917         }
3918     }
3919   else if (sp->handle)
3920     {
3921       r = getc (sp->handle);
3922     }
3923   else
3924     r = EOF;
3925
3926   if (r == EOF && isp)
3927     {
3928       include_pop ();
3929       r = get ();
3930       while (r == EOF && isp)
3931         {
3932           include_pop ();
3933           r = get ();
3934         }
3935       return r;
3936     }
3937   if (r == '\n')
3938     {
3939       sp->linecount++;
3940     }
3941
3942   return r;
3943 }
3944
3945 static int
3946 linecount ()
3947 {
3948   return sp->linecount;
3949 }
3950
3951 static int
3952 include_next_index ()
3953 {
3954   static int index;
3955   if (!unreasonable
3956       && index > MAX_REASONABLE)
3957     FATAL ((stderr, "Unreasonable expansion (-u turns off check).\n"));
3958   return ++index;
3959 }
3960
3961
3962 /* Initialize the chartype vector. */
3963
3964 static void
3965 chartype_init ()
3966 {
3967   int x;
3968   for (x = 0; x < 256; x++)
3969     {
3970       if (isalpha (x) || x == '_' || x == '$')
3971         chartype[x] |= FIRSTBIT;
3972
3973       if (mri && x == '.')
3974         chartype[x] |= FIRSTBIT;
3975
3976       if (isdigit (x) || isalpha (x) || x == '_' || x == '$')
3977         chartype[x] |= NEXTBIT;
3978
3979       if (x == ' ' || x == '\t' || x == ',' || x == '"' || x == ';'
3980           || x == '"' || x == '<' || x == '>' || x == ')' || x == '(')
3981         chartype[x] |= SEPBIT;
3982
3983       if (x == 'b' || x == 'B'
3984           || x == 'q' || x == 'Q'
3985           || x == 'h' || x == 'H'
3986           || x == 'd' || x == 'D')
3987         chartype [x] |= BASEBIT;
3988           
3989       if (x == ' ' || x == '\t')
3990         chartype[x] |= WHITEBIT;
3991
3992       if (x == comment_char)
3993         chartype[x] |= COMMENTBIT;
3994     }
3995 }
3996
3997
3998
3999 /* What to do with all the keywords */
4000 #define PROCESS         0x1000  /* Run substitution over the line */
4001 #define LAB             0x2000  /* Spit out the label */
4002
4003 #define K_EQU           (PROCESS|1)
4004 #define K_ASSIGN        (PROCESS|2)
4005 #define K_REG           (PROCESS|3)
4006 #define K_ORG           (PROCESS|4)
4007 #define K_RADIX         (PROCESS|5)
4008 #define K_DATA          (LAB|PROCESS|6)
4009 #define K_DATAB         (LAB|PROCESS|7)
4010 #define K_SDATA         (LAB|PROCESS|8)
4011 #define K_SDATAB        (LAB|PROCESS|9)
4012 #define K_SDATAC        (LAB|PROCESS|10)
4013 #define K_SDATAZ        (LAB|PROCESS|11)
4014 #define K_RES           (LAB|PROCESS|12)
4015 #define K_SRES          (LAB|PROCESS|13)
4016 #define K_SRESC         (LAB|PROCESS|14)
4017 #define K_SRESZ         (LAB|PROCESS|15)
4018 #define K_EXPORT        (LAB|PROCESS|16)
4019 #define K_GLOBAL        (LAB|PROCESS|17)
4020 #define K_PRINT         (LAB|PROCESS|19)
4021 #define K_FORM          (LAB|PROCESS|20)
4022 #define K_HEADING       (LAB|PROCESS|21)
4023 #define K_PAGE          (LAB|PROCESS|22)
4024 #define K_IMPORT        (LAB|PROCESS|23)
4025 #define K_PROGRAM       (LAB|PROCESS|24)
4026 #define K_END           (PROCESS|25)
4027 #define K_INCLUDE       (PROCESS|26)
4028 #define K_IGNORED       (PROCESS|27)
4029 #define K_ASSIGNA       (PROCESS|28)
4030 #define K_ASSIGNC       (29)
4031 #define K_AIF           (PROCESS|30)
4032 #define K_AELSE         (PROCESS|31)
4033 #define K_AENDI         (PROCESS|32)
4034 #define K_AREPEAT       (PROCESS|33)
4035 #define K_AENDR         (PROCESS|34)
4036 #define K_AWHILE        (35)
4037 #define K_AENDW         (PROCESS|36)
4038 #define K_EXITM         (37)
4039 #define K_MACRO         (PROCESS|38)
4040 #define K_ENDM          (39)
4041 #define K_ALIGN         (PROCESS|LAB|40)
4042 #define K_ALTERNATE     (41)
4043 #define K_DB            (LAB|PROCESS|42)
4044 #define K_DW            (LAB|PROCESS|43)
4045 #define K_DL            (LAB|PROCESS|44)
4046 #define K_LOCAL         (45)
4047 #define K_IFEQ          (PROCESS|46)
4048 #define K_IFNE          (PROCESS|47)
4049 #define K_IFLT          (PROCESS|48)
4050 #define K_IFLE          (PROCESS|49)
4051 #define K_IFGE          (PROCESS|50)
4052 #define K_IFGT          (PROCESS|51)
4053 #define K_IFC           (PROCESS|52)
4054 #define K_IFNC          (PROCESS|53)
4055 #define K_IRP           (PROCESS|54)
4056 #define K_IRPC          (PROCESS|55)
4057
4058
4059 struct keyword
4060 {
4061   char *name;
4062   int code;
4063   int extra;
4064 };
4065
4066 static struct keyword kinfo[] =
4067 {
4068   { "EQU", K_EQU, 0 },
4069   { "ALTERNATE", K_ALTERNATE, 0 },
4070   { "ASSIGN", K_ASSIGN, 0 },
4071   { "REG", K_REG, 0 },
4072   { "ORG", K_ORG, 0 },
4073   { "RADIX", K_RADIX, 0 },
4074   { "DATA", K_DATA, 0 },
4075   { "DB", K_DB, 0 },
4076   { "DW", K_DW, 0 },
4077   { "DL", K_DL, 0 },
4078   { "DATAB", K_DATAB, 0 },
4079   { "SDATA", K_SDATA, 0 },
4080   { "SDATAB", K_SDATAB, 0 },
4081   { "SDATAZ", K_SDATAZ, 0 },
4082   { "SDATAC", K_SDATAC, 0 },
4083   { "RES", K_RES, 0 },
4084   { "SRES", K_SRES, 0 },
4085   { "SRESC", K_SRESC, 0 },
4086   { "SRESZ", K_SRESZ, 0 },
4087   { "EXPORT", K_EXPORT, 0 },
4088   { "GLOBAL", K_GLOBAL, 0 },
4089   { "PRINT", K_PRINT, 0 },
4090   { "FORM", K_FORM, 0 },
4091   { "HEADING", K_HEADING, 0 },
4092   { "PAGE", K_PAGE, 0 },
4093   { "PROGRAM", K_IGNORED, 0 },
4094   { "END", K_END, 0 },
4095   { "INCLUDE", K_INCLUDE, 0 },
4096   { "ASSIGNA", K_ASSIGNA, 0 },
4097   { "ASSIGNC", K_ASSIGNC, 0 },
4098   { "AIF", K_AIF, 0 },
4099   { "AELSE", K_AELSE, 0 },
4100   { "AENDI", K_AENDI, 0 },
4101   { "AREPEAT", K_AREPEAT, 0 },
4102   { "AENDR", K_AENDR, 0 },
4103   { "EXITM", K_EXITM, 0 },
4104   { "MACRO", K_MACRO, 0 },
4105   { "ENDM", K_ENDM, 0 },
4106   { "AWHILE", K_AWHILE, 0 },
4107   { "ALIGN", K_ALIGN, 0 },
4108   { "AENDW", K_AENDW, 0 },
4109   { "ALTERNATE", K_ALTERNATE, 0 },
4110   { "LOCAL", K_LOCAL, 0 },
4111   { NULL, 0, 0 }
4112 };
4113
4114 /* Although the conditional operators are handled by gas, we need to
4115    handle them here as well, in case they are used in a recursive
4116    macro to end the recursion.  */
4117
4118 static struct keyword mrikinfo[] =
4119 {
4120   { "IFEQ", K_IFEQ, 0 },
4121   { "IFNE", K_IFNE, 0 },
4122   { "IFLT", K_IFLT, 0 },
4123   { "IFLE", K_IFLE, 0 },
4124   { "IFGE", K_IFGE, 0 },
4125   { "IFGT", K_IFGT, 0 },
4126   { "IFC", K_IFC, 0 },
4127   { "IFNC", K_IFNC, 0 },
4128   { "ELSEC", K_AELSE, 0 },
4129   { "ENDC", K_AENDI, 0 },
4130   { "MEXIT", K_EXITM, 0 },
4131   { "REPT", K_AREPEAT, 0 },
4132   { "IRP", K_IRP, 0 },
4133   { "IRPC", K_IRPC, 0 },
4134   { "ENDR", K_AENDR, 0 },
4135   { NULL, 0, 0 }
4136 };
4137
4138 /* Look for a pseudo op on the line. If one's there then call
4139    its handler. */
4140
4141 static int
4142 process_pseudo_op (idx, line, acc)
4143      int idx;
4144      sb *line;
4145      sb *acc;
4146 {
4147   int oidx = idx;
4148
4149   if (line->ptr[idx] == '.' || alternate || mri)
4150     {
4151       /* Scan forward and find pseudo name */
4152       char *in;
4153       hash_entry *ptr;
4154
4155       char *s;
4156       char *e;
4157       if (line->ptr[idx] == '.')
4158         idx++;
4159       in = line->ptr + idx;
4160       s = in;
4161       e = s;
4162       sb_reset (acc);
4163
4164       while (idx < line->len && *e && ISFIRSTCHAR (*e))
4165         {
4166           sb_add_char (acc, *e);
4167           e++;
4168           idx++;
4169         }
4170
4171       ptr = hash_lookup (&keyword_hash_table, acc);
4172
4173       if (!ptr)
4174         {
4175 #if 0
4176           /* This one causes lots of pain when trying to preprocess
4177              ordinary code */
4178           WARNING ((stderr, "Unrecognised pseudo op `%s'.\n", sb_name (acc)));
4179 #endif
4180           return 0;
4181         }
4182       if (ptr->value.i & LAB)
4183         {                       /* output the label */
4184           if (label.len)
4185             {
4186               fprintf (outfile, "%s:\t", sb_name (&label));
4187             }
4188           else
4189             fprintf (outfile, "\t");
4190         }
4191
4192       if (mri && ptr->value.i == K_END)
4193         {
4194           sb t;
4195
4196           sb_new (&t);
4197           sb_add_buffer (&t, line->ptr + oidx, idx - oidx);
4198           fprintf (outfile, "\t%s", sb_name (&t));
4199           sb_kill (&t);
4200         }
4201
4202       if (ptr->value.i & PROCESS)
4203         {
4204           /* Polish the rest of the line before handling the pseudo op */
4205 #if 0
4206           strip_comments(line);
4207 #endif
4208           sb_reset (acc);
4209           process_assigns (idx, line, acc);
4210           sb_reset(line);
4211           change_base (0, acc, line);
4212           idx = 0;
4213         }
4214       if (!condass_on ())
4215         {
4216           switch (ptr->value.i)
4217             {
4218             case K_AIF:
4219               do_aif (idx, line);
4220               break;
4221             case K_AELSE:
4222               do_aelse ();
4223               break;
4224             case K_AENDI:
4225               do_aendi ();
4226               break;
4227             }
4228           return 1;
4229         }
4230       else
4231         {
4232           switch (ptr->value.i)
4233             {
4234             case K_ALTERNATE:
4235               alternate = 1;
4236               return 1;
4237             case K_AELSE:
4238               do_aelse ();
4239               return 1;
4240             case K_AENDI:
4241               do_aendi ();
4242               return 1;
4243             case K_ORG:
4244               ERROR ((stderr, "ORG command not allowed.\n"));
4245               break;
4246             case K_RADIX:
4247               do_radix (line);
4248               return 1;
4249             case K_DB:
4250               do_data (idx, line, 1);
4251               return 1;
4252             case K_DW:
4253               do_data (idx, line, 2);
4254               return 1;
4255             case K_DL:
4256               do_data (idx, line, 4);
4257               return 1;
4258             case K_DATA:
4259               do_data (idx, line, 0);
4260               return 1;
4261             case K_DATAB:
4262               do_datab (idx, line);
4263               return 1;
4264             case K_SDATA:
4265               do_sdata (idx, line, 0);
4266               return 1;
4267             case K_SDATAB:
4268               do_sdatab (idx, line);
4269               return 1;
4270             case K_SDATAC:
4271               do_sdata (idx, line, 'c');
4272               return 1;
4273             case K_SDATAZ:
4274               do_sdata (idx, line, 'z');
4275               return 1;
4276             case K_ASSIGN:
4277               do_assign (1, 0, line);
4278               return 1;
4279             case K_AIF:
4280               do_aif (idx, line);
4281               return 1;
4282             case K_AREPEAT:
4283               do_arepeat (idx, line);
4284               return 1;
4285             case K_AENDW:
4286               do_aendw ();
4287               return 1;
4288             case K_AWHILE:
4289               do_awhile (idx, line);
4290               return 1;
4291             case K_AENDR:
4292               do_aendr ();
4293               return 1;
4294             case K_EQU:
4295               do_assign (0, idx, line);
4296               return 1;
4297             case K_ALIGN:
4298               do_align (idx, line);
4299               return 1;
4300             case K_RES:
4301               do_res (idx, line, 0);
4302               return 1;
4303             case K_SRES:
4304               do_res (idx, line, 's');
4305               return 1;
4306             case K_INCLUDE:
4307               do_include (idx, line);
4308               return 1;
4309             case K_LOCAL:
4310               do_local (idx, line);
4311               return 1;
4312             case K_MACRO:
4313               do_macro (idx, line);
4314               return 1;
4315             case K_ENDM:
4316               do_endm ();
4317               return 1;
4318             case K_SRESC:
4319               do_res (idx, line, 'c');
4320               return 1;
4321             case K_PRINT:
4322               do_print (idx, line);
4323               return 1;
4324             case K_FORM:
4325               do_form (idx, line);
4326               return 1;
4327             case K_HEADING:
4328               do_heading (idx, line);
4329               return 1;
4330             case K_PAGE:
4331               do_page ();
4332               return 1;
4333             case K_GLOBAL:
4334             case K_EXPORT:
4335               do_export (line);
4336               return 1;
4337             case K_IMPORT:
4338               return 1;
4339             case K_SRESZ:
4340               do_res (idx, line, 'z');
4341               return 1;
4342             case K_IGNORED:
4343               return 1;
4344             case K_END:
4345               do_end (line);
4346               return 1;
4347             case K_ASSIGNA:
4348               do_assigna (idx, line);
4349               return 1;
4350             case K_ASSIGNC:
4351               do_assignc (idx, line);
4352               return 1;
4353             case K_EXITM:
4354               do_exitm ();
4355               return 1;
4356             case K_REG:
4357               do_reg (idx, line);
4358               return 1;
4359             case K_IFEQ:
4360               do_if (idx, line, EQ);
4361               return 1;
4362             case K_IFNE:
4363               do_if (idx, line, NE);
4364               return 1;
4365             case K_IFLT:
4366               do_if (idx, line, LT);
4367               return 1;
4368             case K_IFLE:
4369               do_if (idx, line, LE);
4370               return 1;
4371             case K_IFGE:
4372               do_if (idx, line, GE);
4373               return 1;
4374             case K_IFGT:
4375               do_if (idx, line, GT);
4376               return 1;
4377             case K_IFC:
4378               do_ifc (idx, line, 0);
4379               return 1;
4380             case K_IFNC:
4381               do_ifc (idx, line, 1);
4382               return 1;
4383             case K_IRP:
4384               do_irp (idx, line, 0);
4385               return 1;
4386             case K_IRPC:
4387               do_irp (idx, line, 1);
4388               return 1;
4389             }
4390         }
4391     }
4392   return 0;
4393 }
4394
4395
4396
4397 /* Add a keyword to the hash table.  */
4398
4399 static void
4400 add_keyword (name, code)
4401      const char *name;
4402      int code;
4403 {
4404   sb label;
4405   int j;
4406
4407   sb_new (&label);
4408   sb_add_string (&label, name);
4409
4410   hash_add_to_int_table (&keyword_hash_table, &label, code);
4411
4412   sb_reset (&label);
4413   for (j = 0; name[j]; j++)
4414     sb_add_char (&label, name[j] - 'A' + 'a');
4415   hash_add_to_int_table (&keyword_hash_table, &label, code);
4416
4417   sb_kill (&label);
4418 }  
4419
4420 /* Build the keyword hash table - put each keyword in the table twice,
4421    once upper and once lower case.*/
4422
4423 static void
4424 process_init ()
4425 {
4426   int i;
4427
4428   for (i = 0; kinfo[i].name; i++)
4429     add_keyword (kinfo[i].name, kinfo[i].code);
4430
4431   if (mri)
4432     {
4433       for (i = 0; mrikinfo[i].name; i++)
4434         add_keyword (mrikinfo[i].name, mrikinfo[i].code);
4435     }
4436 }
4437
4438
4439 static void
4440 do_define (string)
4441      const char *string;
4442 {
4443   sb label;
4444   int res = 1;
4445   hash_entry *ptr;
4446   sb_new (&label);
4447
4448
4449   while (*string)
4450     {
4451       if (*string == '=') 
4452         {
4453           sb value;
4454           sb_new (&value);
4455           string++;
4456           while (*string)
4457             {
4458               sb_add_char (&value, *string);
4459               string++;
4460             }
4461           exp_get_abs ("Invalid expression on command line.\n", 0, &value, &res);
4462           sb_kill (&value);
4463           break;
4464         }
4465       sb_add_char (&label, *string);
4466
4467       string ++;
4468     }
4469
4470   ptr = hash_create (&vars, &label);
4471   free_old_entry (ptr);
4472   ptr->type = hash_integer;
4473   ptr->value.i = res;
4474   sb_kill (&label);
4475 }
4476 char *program_name;
4477
4478 /* The list of long options.  */
4479 static struct option long_options[] =
4480 {
4481   { "alternate", no_argument, 0, 'a' },
4482   { "include", required_argument, 0, 'I' },
4483   { "commentchar", required_argument, 0, 'c' },
4484   { "copysource", no_argument, 0, 's' },
4485   { "debug", no_argument, 0, 'd' },
4486   { "help", no_argument, 0, 'h' },
4487   { "mri", no_argument, 0, 'M' },
4488   { "output", required_argument, 0, 'o' },
4489   { "print", no_argument, 0, 'p' },
4490   { "unreasonable", no_argument, 0, 'u' },
4491   { "version", no_argument, 0, 'v' },
4492   { "define", required_argument, 0, 'd' },
4493   { NULL, no_argument, 0, 0 }
4494 };
4495
4496 /* Show a usage message and exit.  */
4497 static void
4498 show_usage (file, status)
4499      FILE *file;
4500      int status;
4501 {
4502   fprintf (file, "\
4503 Usage: %s \n\
4504   [-a]      [--alternate]         enter alternate macro mode\n\
4505   [-c char] [--commentchar char]  change the comment character from !\n\
4506   [-d]      [--debug]             print some debugging info\n\
4507   [-h]      [--help]              print this message\n\
4508   [-M]      [--mri]               enter MRI compatibility mode\n\
4509   [-o out]  [--output out]        set the output file\n\
4510   [-p]      [--print]             print line numbers\n\
4511   [-s]      [--copysource]        copy source through as comments \n\
4512   [-u]      [--unreasonable]      allow unreasonable nesting\n\
4513   [-v]      [--version]           print the program version\n\
4514   [-Dname=value]                  create preprocessor variable called name, with value\n\
4515   [-Ipath]                        add to include path list\n\
4516   [in-file]\n",   program_name);
4517   exit (status);
4518 }
4519
4520 /* Display a help message and exit.  */
4521 static void
4522 show_help ()
4523 {
4524   printf ("%s: Gnu Assembler Macro Preprocessor\n",
4525           program_name);
4526   show_usage (stdout, 0);
4527 }
4528
4529 int
4530 main (argc, argv)
4531      int argc;
4532      char **argv;
4533 {
4534   int opt;
4535   char *out_name = 0;
4536   sp = include_stack;
4537
4538   ifstack[0].on = 1;
4539   ifi = 0;
4540
4541
4542
4543   program_name = argv[0];
4544   xmalloc_set_program_name (program_name);
4545
4546   hash_new_table (101, &macro_table);
4547   hash_new_table (101, &keyword_hash_table);
4548   hash_new_table (101, &assign_hash_table);
4549   hash_new_table (101, &vars);
4550
4551   sb_new (&label);
4552
4553   while ((opt = getopt_long (argc, argv, "I:sdhavc:upo:D:M", long_options,
4554                              (int *) NULL))
4555          != EOF)
4556     {
4557       switch (opt)
4558         {
4559         case 'o':
4560           out_name = optarg;
4561           break;
4562         case 'u':
4563           unreasonable = 1;
4564           break;
4565         case 'I':
4566           {
4567             include_path *p = (include_path *) xmalloc (sizeof (include_path));
4568             sb_new (&p->path);
4569             sb_add_string (&p->path, optarg);
4570             if (paths_tail)
4571               paths_tail->next = p;
4572             else
4573               paths_head = p;
4574             paths_tail = p;
4575           }
4576           break;
4577         case 'p':
4578           print_line_number = 1;
4579           break;
4580         case 'c':
4581           comment_char = optarg[0];
4582           break;
4583         case 'a':
4584           alternate = 1;
4585           break;
4586         case 's':
4587           copysource = 1;
4588           break;
4589         case 'd':
4590           stats = 1;
4591           break;
4592         case 'D':
4593           do_define (optarg);
4594           break;
4595         case 'M':
4596           mri = 1;
4597           comment_char = ';';
4598           break;
4599         case 'h':
4600           show_help ();
4601           /*NOTREACHED*/
4602         case 'v':
4603           printf ("GNU %s version %s\n", program_name, program_version);
4604           exit (0);
4605           /*NOTREACHED*/
4606         case 0:
4607           break;
4608         default:
4609           show_usage (stderr, 1);
4610           /*NOTREACHED*/
4611         }
4612     }
4613
4614   process_init ();
4615
4616   if (out_name) {
4617     outfile = fopen (out_name, "w");
4618     if (!outfile)
4619       {
4620         fprintf (stderr, "%s: Can't open output file `%s'.\n",
4621                  program_name, out_name);
4622         exit (1);
4623       }
4624   }
4625   else  {
4626     outfile = stdout;
4627   }
4628
4629   chartype_init ();
4630   if (!outfile)
4631     outfile = stdout;
4632
4633   /* Process all the input files */
4634
4635   while (optind < argc)
4636     {
4637       if (new_file (argv[optind]))
4638         {
4639           process_file ();
4640         }
4641       else
4642         {
4643           fprintf (stderr, "%s: Can't open input file `%s'.\n",
4644                    program_name, argv[optind]);
4645           exit (1);
4646         }
4647       optind++;
4648     }
4649
4650   quit ();
4651   return 0;
4652 }