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