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