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