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