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