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