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