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