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