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