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