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