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