* gasp.c (process_assigns): Use toupper before comparing against
[deliverable/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
1366 {
1367 /* nothing special, just pass it through */
1368 sb_add_char (out, in->ptr[idx]);
1369 idx++;
1370 }
1371 }
1372
1373 }
1374
1375 /* .end */
1376 static void
1377 do_end ()
1378 {
1379 had_end = 1;
1380 }
1381
1382 /* .assign */
1383
1384 static void
1385 do_assign (again, idx, in)
1386 int again;
1387 int idx;
1388 sb *in;
1389 {
1390 /* stick label in symbol table with following value */
1391 exp_t e;
1392 sb acc;
1393
1394 sb_new (&acc);
1395 idx = exp_parse (idx, in, &e);
1396 exp_string (&e, &acc);
1397 hash_add_to_string_table (&assign_hash_table, &label, &acc, again);
1398 sb_kill (&acc);
1399 }
1400
1401
1402 /* .radix [b|q|d|h] */
1403
1404 static
1405 void
1406 do_radix (ptr)
1407 sb *ptr;
1408 {
1409 int idx = sb_skip_white (0, ptr);
1410 switch (ptr->ptr[idx])
1411 {
1412 case 'B':
1413 case 'b':
1414 radix = 2;
1415 break;
1416 case 'q':
1417 case 'Q':
1418 radix = 8;
1419 break;
1420 case 'd':
1421 case 'D':
1422 radix = 10;
1423 break;
1424 case 'h':
1425 case 'H':
1426 radix = 16;
1427 break;
1428 default:
1429 ERROR ((stderr, "radix is %c must be one of b, q, d or h", radix));
1430 }
1431 }
1432
1433
1434 /* Parse off a .b, .w or .l */
1435
1436 static int
1437 get_opsize (idx, in, size)
1438 int idx;
1439 sb *in;
1440 int *size;
1441 {
1442 *size = 4;
1443 if (in->ptr[idx] == '.')
1444 {
1445 idx++;
1446 }
1447 switch (in->ptr[idx])
1448 {
1449 case 'b':
1450 case 'B':
1451 *size = 1;
1452 break;
1453 case 'w':
1454 case 'W':
1455 *size = 2;
1456 break;
1457 case 'l':
1458 case 'L':
1459 *size = 4;
1460 break;
1461 case ' ':
1462 case '\t':
1463 break;
1464 default:
1465 ERROR ((stderr, "size must be one of b, w or l, is %c.\n", in->ptr[idx]));
1466 break;
1467 }
1468 idx++;
1469
1470 return idx;
1471 }
1472
1473 static
1474 int eol(idx, line)
1475 int idx;
1476 sb *line;
1477 {
1478 idx = sb_skip_white (idx, line);
1479 if (idx < line->len
1480 && ISCOMMENTCHAR(line->ptr[idx]))
1481 return 1;
1482 if (idx >= line->len)
1483 return 1;
1484 return 0;
1485 }
1486
1487 /* .data [.b|.w|.l] <data>*
1488 or d[bwl] <data>* */
1489
1490 static void
1491 do_data (idx, in, size)
1492 int idx;
1493 sb *in;
1494 int size;
1495 {
1496 int opsize = 4;
1497 char *opname = ".yikes!";
1498 sb acc;
1499 sb_new (&acc);
1500
1501 if (!size)
1502 {
1503 idx = get_opsize (idx, in, &opsize);
1504 }
1505 else {
1506 opsize = size;
1507 }
1508 switch (opsize)
1509 {
1510 case 4:
1511 opname = ".long";
1512 break;
1513 case 2:
1514 opname = ".short";
1515 break;
1516 case 1:
1517 opname = ".byte";
1518 break;
1519 }
1520
1521
1522 fprintf (outfile, "%s\t", opname);
1523
1524 idx = sb_skip_white (idx, in);
1525
1526 if (alternate
1527 && idx < in->len
1528 && in->ptr[idx] == '"')
1529 {
1530 int i;
1531 idx = getstring (idx, in, &acc);
1532 for (i = 0; i < acc.len; i++)
1533 {
1534 if (i)
1535 fprintf(outfile,",");
1536 fprintf (outfile, "%d", acc.ptr[i]);
1537 }
1538 }
1539 else
1540 {
1541 while (!eol (idx, in))
1542 {
1543 exp_t e;
1544 idx = exp_parse (idx, in, &e);
1545 exp_string (&e, &acc);
1546 sb_add_char (&acc, 0);
1547 fprintf (outfile, acc.ptr);
1548 if (idx < in->len && in->ptr[idx] == ',')
1549 {
1550 fprintf (outfile, ",");
1551 idx++;
1552 }
1553 }
1554 }
1555 sb_kill (&acc);
1556 sb_print_at (idx, in);
1557 fprintf (outfile, "\n");
1558 }
1559
1560 /* .datab [.b|.w|.l] <repeat>,<fill> */
1561
1562 static void
1563 do_datab (idx, in)
1564 int idx;
1565 sb *in;
1566 {
1567 int opsize;
1568 int repeat;
1569 int fill;
1570
1571 idx = get_opsize (idx, in, &opsize);
1572
1573 idx = exp_get_abs ("datab repeat must be constant.\n", idx, in, &repeat);
1574 idx = sb_skip_comma (idx, in);
1575 idx = exp_get_abs ("datab data must be absolute.\n", idx, in, &fill);
1576
1577 fprintf (outfile, ".fill\t%d,%d,%d\n", repeat, opsize, fill);
1578 }
1579
1580 /* .align <size> */
1581
1582 void
1583 do_align (idx, in)
1584 int idx;
1585 sb *in;
1586 {
1587 int al;
1588 idx = exp_get_abs ("align needs absolute expression.\n", idx, in, &al);
1589
1590 if (al != 1
1591 && al != 2
1592 && al != 4)
1593 WARNING ((stderr, "alignment must be one of 1, 2 or 4.\n"));
1594
1595 fprintf (outfile, ".align %d\n", al);
1596 }
1597
1598 /* .res[.b|.w|.l] <size> */
1599
1600 void
1601 do_res (idx, in, type)
1602 int idx;
1603 sb *in;
1604 char type;
1605 {
1606 int size = 4;
1607 int count = 0;
1608
1609 idx = get_opsize (idx, in, &size);
1610 while (!eol(idx, in))
1611 {
1612 idx = sb_skip_white (idx, in);
1613 if (in->ptr[idx] == ',')
1614 idx++;
1615 idx = exp_get_abs ("res needs absolute expression for fill count.\n", idx, in, &count);
1616
1617 if (type == 'c' || type == 'z')
1618 count++;
1619
1620 fprintf (outfile, ".space %d\n", count * size);
1621 }
1622 }
1623
1624
1625 /* .export */
1626
1627 void
1628 do_export (in)
1629 sb *in;
1630 {
1631 fprintf (outfile, ".global %s\n", sb_name (in));
1632 }
1633
1634 /* .print [list] [nolist] */
1635
1636 void
1637 do_print (idx, in)
1638 int idx;
1639 sb *in;
1640 {
1641 idx = sb_skip_white (idx, in);
1642 while (idx < in->len)
1643 {
1644 if (strncasecmp (in->ptr + idx, "LIST", 4) == 0)
1645 {
1646 fprintf (outfile, ".list\n");
1647 idx += 4;
1648 }
1649 else if (strncasecmp (in->ptr + idx, "NOLIST", 6) == 0)
1650 {
1651 fprintf (outfile, ".nolist\n");
1652 idx += 6;
1653 }
1654 idx++;
1655 }
1656 }
1657
1658 /* .head */
1659 void
1660 do_heading (idx, in)
1661 int idx;
1662 sb *in;
1663 {
1664 sb head;
1665 sb_new (&head);
1666 idx = getstring (idx, in, &head);
1667 fprintf (outfile, ".title \"%s\"\n", sb_name (&head));
1668 sb_kill (&head);
1669 }
1670
1671 /* .page */
1672
1673 void
1674 do_page ()
1675 {
1676 fprintf (outfile, ".eject\n");
1677 }
1678
1679 /* .form [lin=<value>] [col=<value>] */
1680 void
1681 do_form (idx, in)
1682 int idx;
1683 sb *in;
1684 {
1685 int lines = 60;
1686 int columns = 132;
1687 idx = sb_skip_white (idx, in);
1688
1689 while (idx < in->len)
1690 {
1691
1692 if (strncasecmp (in->ptr + idx, "LIN=", 4) == 0)
1693 {
1694 idx += 4;
1695 idx = exp_get_abs ("form LIN= needs absolute expresssion.\n", idx, in, &lines);
1696 }
1697
1698 if (strncasecmp (in->ptr + idx, "COL=", 4) == 0)
1699 {
1700 idx += 4;
1701 idx = exp_get_abs ("form COL= needs absolute expresssion.\n", idx, in, &columns);
1702 }
1703
1704 idx++;
1705 }
1706 fprintf (outfile, ".psize %d,%d\n", lines, columns);
1707
1708 }
1709
1710
1711 /* Fetch string from the input stream,
1712 rules:
1713 'Bxyx<whitespace> -> return 'Bxyza
1714 %<char> -> return string of decimal value of x
1715 "<string>" -> return string
1716 xyx<whitespace> -> return xyz
1717 */
1718 int
1719 get_any_string (idx, in, out, expand, pretend_quoted)
1720 int idx;
1721 sb *in;
1722 sb *out;
1723 int expand;
1724 int pretend_quoted;
1725 {
1726 sb_reset (out);
1727 idx = sb_skip_white (idx, in);
1728
1729 if (idx < in->len)
1730 {
1731 if (in->len > 2 && in->ptr[idx+1] == '\'' && ISBASE (in->ptr[idx]))
1732 {
1733 while (!ISSEP (in->ptr[idx]))
1734 sb_add_char (out, in->ptr[idx++]);
1735 }
1736 else if (in->ptr[idx] == '%'
1737 && alternate
1738 && expand)
1739 {
1740 int val;
1741 char buf[20];
1742 /* Turns the next expression into a string */
1743 idx = exp_get_abs ("% operator needs absolute expression",
1744 idx + 1,
1745 in,
1746 &val);
1747 sprintf(buf, "%d", val);
1748 sb_add_string (out, buf);
1749 }
1750 else if (in->ptr[idx] == '"'
1751 || in->ptr[idx] == '<'
1752 || (alternate && in->ptr[idx] == '\''))
1753 {
1754 if (alternate && expand)
1755 {
1756 /* Keep the quotes */
1757 sb_add_char (out, '\"');
1758
1759 idx = getstring (idx, in, out);
1760 sb_add_char (out, '\"');
1761
1762 }
1763 else {
1764 idx = getstring (idx, in, out);
1765 }
1766 }
1767 else
1768 {
1769 while (idx < in->len
1770 && (in->ptr[idx] == '"'
1771 || in->ptr[idx] == '\''
1772 || pretend_quoted
1773 || !ISSEP (in->ptr[idx])))
1774 {
1775 if (in->ptr[idx] == '"'
1776 || in->ptr[idx] == '\'')
1777 {
1778 char tchar = in->ptr[idx];
1779 sb_add_char (out, in->ptr[idx++]);
1780 while (idx < in->len
1781 && in->ptr[idx] != tchar)
1782 sb_add_char (out, in->ptr[idx++]);
1783 if (idx == in->len)
1784 return idx;
1785 }
1786 sb_add_char (out, in->ptr[idx++]);
1787 }
1788 }
1789 }
1790
1791 return idx;
1792 }
1793
1794
1795 /* skip along sb in starting at idx, suck off whitespace a ( and more
1796 whitespace. return the idx of the next char */
1797
1798 int
1799 skip_openp (idx, in)
1800 int idx;
1801 sb *in;
1802 {
1803 idx = sb_skip_white (idx, in);
1804 if (in->ptr[idx] != '(')
1805 ERROR ((stderr, "misplaced ( .\n"));
1806 idx = sb_skip_white (idx + 1, in);
1807 return idx;
1808 }
1809
1810 /* skip along sb in starting at idx, suck off whitespace a ) and more
1811 whitespace. return the idx of the next char */
1812
1813 int
1814 skip_closep (idx, in)
1815 int idx;
1816 sb *in;
1817 {
1818 idx = sb_skip_white (idx, in);
1819 if (in->ptr[idx] != ')')
1820 ERROR ((stderr, "misplaced ).\n"));
1821 idx = sb_skip_white (idx + 1, in);
1822 return idx;
1823 }
1824
1825 /* .len */
1826
1827 int
1828 dolen (idx, in, out)
1829 int idx;
1830 sb *in;
1831 sb *out;
1832 {
1833
1834 sb stringout;
1835 char buffer[10];
1836
1837 sb_new (&stringout);
1838 idx = skip_openp (idx, in);
1839 idx = get_and_process (idx, in, &stringout);
1840 idx = skip_closep (idx, in);
1841 sprintf (buffer, "%d", stringout.len);
1842 sb_add_string (out, buffer);
1843
1844 sb_kill (&stringout);
1845 return idx;
1846 }
1847
1848
1849 /* .instr */
1850
1851 static
1852 int
1853 doinstr (idx, in, out)
1854 int idx;
1855 sb *in;
1856 sb *out;
1857 {
1858 sb string;
1859 sb search;
1860 int i;
1861 int start;
1862 int res;
1863 char buffer[10];
1864
1865 sb_new (&string);
1866 sb_new (&search);
1867 idx = skip_openp (idx, in);
1868 idx = get_and_process (idx, in, &string);
1869 idx = sb_skip_comma (idx, in);
1870 idx = get_and_process (idx, in, &search);
1871 idx = sb_skip_comma (idx, in);
1872 if (isdigit (in->ptr[idx]))
1873 {
1874 idx = exp_get_abs (".instr needs absolute expresson.\n", idx, in, &start);
1875 }
1876 else
1877 {
1878 start = 0;
1879 }
1880 idx = skip_closep (idx, in);
1881 res = -1;
1882 for (i = start; i < string.len; i++)
1883 {
1884 if (strncmp (string.ptr + i, search.ptr, search.len) == 0)
1885 {
1886 res = i;
1887 break;
1888 }
1889 }
1890 sprintf (buffer, "%d", res);
1891 sb_add_string (out, buffer);
1892 sb_kill (&string);
1893 sb_kill (&search);
1894 return idx;
1895 }
1896
1897
1898 static int
1899 dosubstr (idx, in, out)
1900 int idx;
1901 sb *in;
1902 sb *out;
1903 {
1904 sb string;
1905 int pos;
1906 int len;
1907 sb_new (&string);
1908
1909 idx = skip_openp (idx, in);
1910 idx = get_and_process (idx, in, &string);
1911 idx = sb_skip_comma (idx, in);
1912 idx = exp_get_abs ("need absolute position.\n", idx, in, &pos);
1913 idx = sb_skip_comma (idx, in);
1914 idx = exp_get_abs ("need absolute length.\n", idx, in, &len);
1915 idx = skip_closep (idx, in);
1916
1917
1918 if (len < 0 || pos < 0 ||
1919 pos > string.len
1920 || pos + len > string.len)
1921 {
1922 sb_add_string (out, " ");
1923 }
1924 else
1925 {
1926 sb_add_char (out, '"');
1927 while (len > 0)
1928 {
1929 sb_add_char (out, string.ptr[pos++]);
1930 len--;
1931 }
1932 sb_add_char (out, '"');
1933 }
1934 sb_kill(&string);
1935 return idx;
1936 }
1937
1938 /* scan line, change tokens in the hash table to their replacements */
1939 void
1940 process_assigns (idx, in, buf)
1941 int idx;
1942 sb *in;
1943 sb *buf;
1944 {
1945 while (idx < in->len)
1946 {
1947 hash_entry *ptr;
1948 if (in->ptr[idx] == '\\'
1949 && in->ptr[idx + 1] == '&')
1950 {
1951 idx = condass_lookup_name (in, idx + 2, buf, 1);
1952 }
1953 else if (in->ptr[idx] == '\\'
1954 && in->ptr[idx + 1] == '$')
1955 {
1956 idx = condass_lookup_name (in, idx + 2, buf, 0);
1957 }
1958 else if (idx + 3 < in->len
1959 && in->ptr[idx] == '.'
1960 && toupper ((unsigned char) in->ptr[idx + 1]) == 'L'
1961 && toupper ((unsigned char) in->ptr[idx + 2]) == 'E'
1962 && toupper ((unsigned char) in->ptr[idx + 3]) == 'N')
1963 idx = dolen (idx + 4, in, buf);
1964 else if (idx + 6 < in->len
1965 && in->ptr[idx] == '.'
1966 && toupper ((unsigned char) in->ptr[idx + 1]) == 'I'
1967 && toupper ((unsigned char) in->ptr[idx + 2]) == 'N'
1968 && toupper ((unsigned char) in->ptr[idx + 3]) == 'S'
1969 && toupper ((unsigned char) in->ptr[idx + 4]) == 'T'
1970 && toupper ((unsigned char) in->ptr[idx + 5]) == 'R')
1971 idx = doinstr (idx + 6, in, buf);
1972 else if (idx + 7 < in->len
1973 && in->ptr[idx] == '.'
1974 && toupper ((unsigned char) in->ptr[idx + 1]) == 'S'
1975 && toupper ((unsigned char) in->ptr[idx + 2]) == 'U'
1976 && toupper ((unsigned char) in->ptr[idx + 3]) == 'B'
1977 && toupper ((unsigned char) in->ptr[idx + 4]) == 'S'
1978 && toupper ((unsigned char) in->ptr[idx + 5]) == 'T'
1979 && toupper ((unsigned char) in->ptr[idx + 6]) == 'R')
1980 idx = dosubstr (idx + 7, in, buf);
1981 else if (ISFIRSTCHAR (in->ptr[idx]))
1982 {
1983 /* may be a simple name subsitution, see if we have a word */
1984 sb acc;
1985 int cur = idx + 1;
1986 while (cur < in->len
1987 && (ISNEXTCHAR (in->ptr[cur])))
1988 cur++;
1989
1990 sb_new (&acc);
1991 sb_add_buffer (&acc, in->ptr + idx, cur - idx);
1992 ptr = hash_lookup (&assign_hash_table, &acc);
1993 if (ptr)
1994 {
1995 /* Found a definition for it */
1996 sb_add_sb (buf, &ptr->value.s);
1997 }
1998 else
1999 {
2000 /* No definition, just copy the word */
2001 sb_add_sb (buf, &acc);
2002 }
2003 sb_kill (&acc);
2004 idx = cur;
2005 }
2006 else
2007 {
2008 sb_add_char (buf, in->ptr[idx++]);
2009 }
2010 }
2011 }
2012
2013 static int
2014 get_and_process (idx, in, out)
2015 int idx;
2016 sb *in;
2017 sb *out;
2018 {
2019 sb t;
2020 sb_new (&t);
2021 idx = get_any_string (idx, in, &t, 1, 0);
2022 process_assigns (0, &t, out);
2023 sb_kill (&t);
2024 return idx;
2025 }
2026
2027 static
2028 void
2029 process_file ()
2030 {
2031 sb line;
2032 sb t1, t2;
2033 sb acc;
2034 sb label_in;
2035 int more;
2036
2037 sb_new (&line);
2038 sb_new (&t1);
2039 sb_new (&t2);
2040 sb_new(&acc);
2041 sb_new (&label_in);
2042 sb_reset (&line);
2043 more = get_line (&line);
2044 while (more)
2045 {
2046 /* Find any label and pseudo op that we're intested in */
2047 int l;
2048 if (line.len == 0)
2049 {
2050 if (condass_on ())
2051 fprintf (outfile, "\n");
2052 }
2053 else
2054 {
2055 l = grab_label (&line, &label_in);
2056 sb_reset (&label);
2057 if (label_in.len)
2058 {
2059 /* Munge any label */
2060
2061
2062 process_assigns (0, &label_in, &label);
2063 }
2064
2065 if (line.ptr[l] == ':')
2066 l++;
2067 while (ISWHITE (line.ptr[l]) && l < line.len)
2068 l++;
2069
2070 if (l < line.len)
2071 {
2072 if (process_pseudo_op (l, &line, &acc))
2073 {
2074
2075
2076
2077 }
2078 else if (condass_on ())
2079 {
2080 if (macro_op (l, &line))
2081 {
2082
2083
2084 }
2085 else
2086 {
2087 {
2088 if (label.len)
2089 {
2090 fprintf (outfile, "%s:\t", sb_name (&label));
2091 }
2092 else
2093 fprintf (outfile, "\t");
2094 sb_reset(&t1);
2095 process_assigns (l, &line, &t1);
2096 sb_reset (&t2);
2097 change_base (0, &t1, &t2);
2098 fprintf (outfile, "%s\n", sb_name (&t2));
2099 }
2100 }
2101 }
2102 }
2103 else {
2104 /* Only a label on this line */
2105 if (label.len && condass_on())
2106 {
2107 fprintf (outfile, "%s:\n", sb_name (&label));
2108 }
2109 }
2110 }
2111
2112 if (had_end)
2113 break;
2114 sb_reset (&line);
2115 more = get_line (&line);
2116 }
2117
2118 if (!had_end)
2119 WARNING ((stderr, "END missing from end of file.\n"));
2120 }
2121
2122
2123
2124
2125
2126 static void
2127 free_old_entry (ptr)
2128 hash_entry *ptr;
2129 {
2130 if (ptr)
2131 {
2132 if (ptr->type == hash_string)
2133 sb_kill(&ptr->value.s);
2134 }
2135 }
2136
2137 /* name: .ASSIGNA <value> */
2138
2139 void
2140 do_assigna (idx, in)
2141 int idx;
2142 sb *in;
2143 {
2144 sb tmp;
2145 int val;
2146 sb_new (&tmp);
2147
2148 process_assigns (idx, in, &tmp);
2149 idx = exp_get_abs (".ASSIGNA needs constant expression argument.\n", 0, &tmp, &val);
2150
2151 if (!label.len)
2152 {
2153 ERROR ((stderr, ".ASSIGNA without label.\n"));
2154 }
2155 else
2156 {
2157 hash_entry *ptr = hash_create (&vars, &label);
2158 free_old_entry (ptr);
2159 ptr->type = hash_integer;
2160 ptr->value.i = val;
2161 }
2162 sb_kill (&tmp);
2163 }
2164
2165 /* name: .ASSIGNC <string> */
2166
2167 void
2168 do_assignc (idx, in)
2169 int idx;
2170 sb *in;
2171 {
2172 sb acc;
2173 sb_new (&acc);
2174 idx = getstring (idx, in, &acc);
2175
2176 if (!label.len)
2177 {
2178 ERROR ((stderr, ".ASSIGNS without label.\n"));
2179 }
2180 else
2181 {
2182 hash_entry *ptr = hash_create (&vars, &label);
2183 free_old_entry (ptr);
2184 ptr->type = hash_string;
2185 sb_new (&ptr->value.s);
2186 sb_add_sb (&ptr->value.s, &acc);
2187 }
2188 sb_kill (&acc);
2189 }
2190
2191
2192 /* name: .REG (reg) */
2193
2194 static void
2195 do_reg (idx, in)
2196 int idx;
2197 sb *in;
2198 {
2199 /* remove reg stuff from inside parens */
2200 sb what;
2201 idx = skip_openp (idx, in);
2202 sb_new (&what);
2203 while (idx < in->len && in->ptr[idx] != ')')
2204 {
2205 sb_add_char (&what, in->ptr[idx]);
2206 idx++;
2207 }
2208 hash_add_to_string_table (&assign_hash_table, &label, &what, 1);
2209 sb_kill (&what);
2210 }
2211
2212
2213 static int
2214 condass_lookup_name (inbuf, idx, out, warn)
2215 sb *inbuf;
2216 int idx;
2217 sb *out;
2218 int warn;
2219 {
2220 hash_entry *ptr;
2221 sb condass_acc;
2222 sb_new (&condass_acc);
2223
2224 while (idx < inbuf->len
2225 && ISNEXTCHAR (inbuf->ptr[idx]))
2226 {
2227 sb_add_char (&condass_acc, inbuf->ptr[idx++]);
2228 }
2229
2230 if (inbuf->ptr[idx] == '\'')
2231 idx++;
2232 ptr = hash_lookup (&vars, &condass_acc);
2233
2234
2235 if (!ptr)
2236 {
2237 if (warn)
2238 {
2239 WARNING ((stderr, "Can't find preprocessor variable %s.\n", sb_name (&condass_acc)));
2240 }
2241 else
2242 {
2243 sb_add_string (out, "0");
2244 }
2245 }
2246 else
2247 {
2248 if (ptr->type == hash_integer)
2249 {
2250 char buffer[30];
2251 sprintf (buffer, "%d", ptr->value.i);
2252 sb_add_string (out, buffer);
2253 }
2254 else
2255 {
2256 sb_add_sb (out, &ptr->value.s);
2257 }
2258 }
2259 sb_kill (&condass_acc);
2260 return idx;
2261 }
2262
2263 #define EQ 1
2264 #define NE 2
2265 #define GE 3
2266 #define LT 4
2267 #define LE 5
2268 #define GT 6
2269 #define NEVER 7
2270
2271 int
2272 whatcond (idx, in, val)
2273 int idx;
2274 sb *in;
2275 int *val;
2276 {
2277 int cond;
2278
2279 idx = sb_skip_white (idx, in);
2280 cond = NEVER;
2281 if (idx + 1 < in->len)
2282 {
2283 char *p;
2284 char a, b;
2285
2286 p = in->ptr + idx;
2287 a = toupper ((unsigned char) p[0]);
2288 b = toupper ((unsigned char) p[1]);
2289 if (a == 'E' && b == 'Q')
2290 cond = EQ;
2291 else if (a == 'N' && b == 'E')
2292 cond = NE;
2293 else if (a == 'L' && b == 'T')
2294 cond = LT;
2295 else if (a == 'L' && b == 'E')
2296 cond = LE;
2297 else if (a == 'G' && b == 'T')
2298 cond = GT;
2299 else if (a == 'G' && b == 'E')
2300 cond = GE;
2301 }
2302 if (cond == NEVER)
2303 {
2304 ERROR ((stderr, "Comparison operator must be one of EQ, NE, LT, LE, GT or GE.\n"));
2305 cond = NEVER;
2306 }
2307 idx = sb_skip_white (idx + 2, in);
2308 *val = cond;
2309 return idx;
2310 }
2311
2312 int
2313 istrue (idx, in)
2314 int idx;
2315 sb *in;
2316 {
2317 int res;
2318 sb acc_a;
2319 sb cond;
2320 sb acc_b;
2321 sb_new (&acc_a);
2322 sb_new (&cond);
2323 sb_new (&acc_b);
2324 idx = sb_skip_white (idx, in);
2325
2326 if (in->ptr[idx] == '"')
2327 {
2328 int cond;
2329 int same;
2330 /* This is a string comparision */
2331 idx = getstring (idx, in, &acc_a);
2332 idx = whatcond (idx, in, &cond);
2333 idx = getstring (idx, in, &acc_b);
2334 same = acc_a.len == acc_b.len && (strncmp (acc_a.ptr, acc_b.ptr, acc_a.len) == 0);
2335
2336 if (cond != EQ && cond != NE)
2337 {
2338 ERROR ((stderr, "Comparison operator for strings must be EQ or NE\n"));
2339 res = 0;
2340 }
2341 else
2342 res = (cond != EQ) ^ same;
2343 }
2344 else
2345 /* This is a numeric expression */
2346 {
2347 int vala;
2348 int valb;
2349 int cond;
2350 idx = exp_get_abs ("Conditional operator must have absolute operands.\n", idx, in, &vala);
2351 idx = whatcond (idx, in, &cond);
2352 idx = sb_skip_white (idx, in);
2353 if (in->ptr[idx] == '"')
2354 {
2355 WARNING ((stderr, "String compared against expression.\n"));
2356 res = 0;
2357 }
2358 else
2359 {
2360 idx = exp_get_abs ("Conditional operator must have absolute operands.\n", idx, in, &valb);
2361 switch (cond)
2362 {
2363 default:
2364 res = 42;
2365 break;
2366 case EQ:
2367 res = vala == valb;
2368 break;
2369 case NE:
2370 res = vala != valb;
2371 break;
2372 case LT:
2373 res = vala < valb;
2374 break;
2375 case LE:
2376 res = vala <= valb;
2377 break;
2378 case GT:
2379 res = vala > valb;
2380 break;
2381 case GE:
2382 res = vala >= valb;
2383 break;
2384 case NEVER:
2385 res = 0;
2386 break;
2387 }
2388 }
2389 }
2390
2391 sb_kill (&acc_a);
2392 sb_kill (&cond);
2393 sb_kill (&acc_b);
2394 return res;
2395 }
2396
2397 /* .AIF */
2398 static void
2399 do_aif (idx, in)
2400 int idx;
2401 sb *in;
2402 {
2403 if (ifi >= IFNESTING)
2404 {
2405 FATAL ((stderr, "AIF nesting unreasonable.\n"));
2406 }
2407 ifi++;
2408 ifstack[ifi].on = ifstack[ifi-1].on ? istrue (idx, in) : 0;
2409 ifstack[ifi].hadelse = 0;
2410 }
2411
2412
2413 /* .AELSE */
2414 static void
2415 do_aelse ()
2416 {
2417 ifstack[ifi].on = ifstack[ifi-1].on ? !ifstack[ifi].on : 0;
2418 if (ifstack[ifi].hadelse)
2419 {
2420 ERROR ((stderr, "Multiple AELSEs in AIF.\n"));
2421 }
2422 ifstack[ifi].hadelse = 1;
2423 }
2424
2425
2426 /* .AENDI */
2427 static void
2428 do_aendi ()
2429 {
2430 if (ifi != 0)
2431 {
2432 ifi--;
2433 }
2434 else
2435 {
2436 ERROR ((stderr, "AENDI without AIF.\n"));
2437 }
2438 }
2439
2440 static int
2441 condass_on ()
2442 {
2443 return ifstack[ifi].on;
2444 }
2445
2446
2447 /* Read input lines till we get to a TO string.
2448 Increase nesting depth if we geta FROM string.
2449 Put the results into sb at PTR. */
2450
2451 static void
2452 buffer_and_nest (from, to, ptr)
2453 char *from;
2454 char *to;
2455 sb *ptr;
2456 {
2457 int from_len = strlen (from);
2458 int to_len = strlen (to);
2459 int depth = 1;
2460 int line_start = ptr->len;
2461 int line = linecount ();
2462
2463 int more = get_line (ptr);
2464
2465 while (more)
2466 {
2467 /* Try and find the first pseudo op on the line */
2468 int i = line_start;
2469
2470 if (!alternate)
2471 {
2472 /* With normal syntax we can suck what we want till we get to the dot.
2473 With the alternate, labels have to start in the first column, since
2474 we cant tell what's a label and whats a pseudoop */
2475
2476 /* Skip leading whitespace */
2477 while (i < ptr->len
2478 && ISWHITE (ptr->ptr[i]))
2479 i++;
2480
2481 /* Skip over a label */
2482 while (i < ptr->len
2483 && ISNEXTCHAR (ptr->ptr[i]))
2484 i++;
2485
2486 /* And a colon */
2487 if (i < ptr->len
2488 && ptr->ptr[i] == ':')
2489 i++;
2490
2491 }
2492 /* Skip trailing whitespace */
2493 while (i < ptr->len
2494 && ISWHITE (ptr->ptr[i]))
2495 i++;
2496
2497 if (i < ptr->len && (ptr->ptr[i] == '.'
2498 || alternate))
2499 {
2500 if (ptr->ptr[i] == '.')
2501 i++;
2502 if (strncasecmp (ptr->ptr + i, from, from_len) == 0)
2503 depth++;
2504 if (strncasecmp (ptr->ptr + i, to, to_len) == 0)
2505 {
2506 depth--;
2507 if (depth == 0)
2508 {
2509 /* Reset the string to not include the ending rune */
2510 ptr->len = line_start;
2511 break;
2512 }
2513 }
2514 }
2515
2516 /* Add a CR to the end and keep running */
2517 sb_add_char (ptr, '\n');
2518 line_start = ptr->len;
2519 more = get_line (ptr);
2520 }
2521
2522
2523 if (depth)
2524 FATAL ((stderr, "End of file whilst inside %s, started on line %d.\n", from, line));
2525 }
2526
2527
2528 /* .ENDR */
2529 void
2530 do_aendr ()
2531 {
2532 ERROR ((stderr, "AENDR without a AREPEAT.\n"));
2533 }
2534
2535 /* .AWHILE */
2536
2537 static
2538 void
2539 do_awhile (idx, in)
2540 int idx;
2541 sb *in;
2542 {
2543 sb exp;
2544
2545 sb sub;
2546
2547 int doit;
2548 sb_new (&sub);
2549 sb_new (&exp);
2550
2551 process_assigns (idx, in, &exp);
2552 doit = istrue (0, &exp);
2553
2554 buffer_and_nest ("AWHILE", "AENDW", &sub);
2555
2556 /* Turn
2557 .AWHILE exp
2558 foo
2559 .AENDW
2560 into
2561 foo
2562 .AWHILE exp
2563 foo
2564 .ENDW
2565 */
2566
2567 if (doit)
2568 {
2569 int index = include_next_index ();
2570
2571 sb copy;
2572 sb_new (&copy);
2573 sb_add_sb (&copy, &sub);
2574 sb_add_sb (&copy, in);
2575 sb_add_string (&copy, "\n");
2576 sb_add_sb (&copy, &sub);
2577 sb_add_string (&copy, "\t.AENDW\n");
2578 /* Push another WHILE */
2579 include_buf (&exp, &copy, include_while, index);
2580 sb_kill (&copy);
2581 }
2582 sb_kill (&exp);
2583 sb_kill (&sub);
2584 }
2585
2586
2587 /* .AENDW */
2588
2589 static void
2590 do_aendw ()
2591 {
2592 ERROR ((stderr, "AENDW without a AENDW.\n"));
2593 }
2594
2595
2596 /* .EXITM
2597
2598 Pop things off the include stack until the type and index changes */
2599
2600 static void
2601 do_exitm ()
2602 {
2603 include_type type = sp->type;
2604 if (type == include_repeat
2605 || type == include_while
2606 || type == include_macro)
2607 {
2608 int index = sp->index;
2609 include_pop ();
2610 while (sp->index == index
2611 && sp->type == type)
2612 {
2613 include_pop ();
2614 }
2615 }
2616 }
2617
2618 /* .AREPEAT */
2619
2620 static void
2621 do_arepeat (idx, in)
2622 int idx;
2623 sb *in;
2624 {
2625 sb exp; /* buffer with expression in it */
2626 sb copy; /* expanded repeat block */
2627 sb sub; /* contents of AREPEAT */
2628 int rc;
2629 char buffer[30];
2630 sb_new (&exp);
2631 sb_new (&copy);
2632 sb_new (&sub);
2633 process_assigns (idx, in, &exp);
2634 idx = exp_get_abs ("AREPEAT must have absolute operand.\n", 0, &exp, &rc);
2635 buffer_and_nest ("AREPEAT", "AENDR", &sub);
2636 if (rc > 0)
2637 {
2638 /* Push back the text following the repeat, and another repeat block
2639 so
2640 .AREPEAT 20
2641 foo
2642 .AENDR
2643 gets turned into
2644 foo
2645 .AREPEAT 19
2646 foo
2647 .AENDR
2648 */
2649 int index = include_next_index ();
2650 sb_add_sb (&copy, &sub);
2651 if (rc > 1)
2652 {
2653 sprintf (buffer, "\t.AREPEAT %d\n", rc - 1);
2654 sb_add_string (&copy, buffer);
2655 sb_add_sb (&copy, &sub);
2656 sb_add_string (&copy, " .AENDR\n");
2657 }
2658
2659 include_buf (&exp, &copy, include_repeat, index);
2660 }
2661 sb_kill (&exp);
2662 sb_kill (&sub);
2663 sb_kill (&copy);
2664 }
2665
2666 /* .ENDM */
2667
2668 static void
2669 do_endm ()
2670 {
2671 ERROR ((stderr, ".ENDM without a matching .MACRO.\n"));
2672 }
2673
2674
2675 /* MARRO PROCESSING */
2676
2677 static int number;
2678 hash_table macro_table;
2679
2680 /* Understand
2681
2682 .MACRO <name>
2683 stuff
2684 .ENDM
2685 */
2686
2687 static int
2688 do_formals (macro, idx, in)
2689 macro_entry *macro;
2690 int idx;
2691 sb *in;
2692 {
2693 formal_entry **p = &macro->formals;
2694 macro->formal_count = 0;
2695 hash_new_table (5, &macro->formal_hash);
2696 while (idx < in->len)
2697 {
2698 formal_entry *formal;
2699
2700 formal = (formal_entry *) xmalloc (sizeof (formal_entry));
2701
2702 sb_new (&formal->name);
2703 sb_new (&formal->def);
2704 sb_new (&formal->actual);
2705
2706 idx = sb_skip_white (idx, in);
2707 idx = get_token (idx, in, &formal->name);
2708 if (formal->name.len == 0)
2709 break;
2710 idx = sb_skip_white (idx, in);
2711 if (formal->name.len)
2712 {
2713 /* This is a formal */
2714 if (idx < in->len && in->ptr[idx] == '=')
2715 {
2716 /* Got a default */
2717 idx = get_any_string (idx + 1, in, &formal->def, 1, 0);
2718 }
2719 }
2720
2721 {
2722 /* Add to macro's hash table */
2723
2724 hash_entry *p = hash_create (&macro->formal_hash, &formal->name);
2725 p->type = hash_formal;
2726 p->value.f = formal;
2727 }
2728
2729 formal->index = macro->formal_count;
2730 idx = sb_skip_comma (idx, in);
2731 macro->formal_count++;
2732 *p = formal;
2733 p = &formal->next;
2734 }
2735 return idx;
2736 }
2737
2738 /* Parse off LOCAL n1, n2,... Invent a label name for it */
2739 static
2740 void
2741 do_local (idx, line)
2742 int idx;
2743 sb *line;
2744 {
2745 static int ln;
2746 sb acc;
2747 sb sub;
2748 char subs[10];
2749 sb_new (&acc);
2750 sb_new (&sub);
2751 idx = sb_skip_white (idx, line);
2752 while (!eol(idx, line))
2753 {
2754 sb_reset (&acc);
2755 sb_reset (&sub);
2756 ln++;
2757 sprintf(subs, "LL%04x", ln);
2758 idx = get_token(idx, line, &acc);
2759 sb_add_string (&sub, subs);
2760 hash_add_to_string_table (&assign_hash_table, &acc, &sub, 1);
2761 idx = sb_skip_comma (idx, line);
2762 }
2763 sb_kill (&sub);
2764 sb_kill (&acc);
2765 }
2766
2767 static
2768 void
2769 do_macro (idx, in)
2770 int idx;
2771 sb *in;
2772 {
2773 macro_entry *macro;
2774 sb name;
2775
2776 macro = (macro_entry *) xmalloc (sizeof (macro_entry));
2777 sb_new (&macro->sub);
2778 sb_new (&name);
2779
2780 macro->formal_count = 0;
2781 macro->formals = 0;
2782
2783 idx = sb_skip_white (idx, in);
2784 buffer_and_nest ("MACRO", "ENDM", &macro->sub);
2785 if (label.len)
2786 {
2787
2788 sb_add_sb (&name, &label);
2789 if (in->ptr[idx] == '(')
2790 {
2791 /* It's the label: MACRO (formals,...) sort */
2792 idx = do_formals (macro, idx + 1, in);
2793 if (in->ptr[idx] != ')')
2794 ERROR ((stderr, "Missing ) after formals.\n"));
2795 }
2796 else {
2797 /* It's the label: MACRO formals,... sort */
2798 idx = do_formals (macro, idx, in);
2799 }
2800 }
2801 else
2802 {
2803 idx = get_token (idx, in, &name);
2804 idx = sb_skip_white (idx, in);
2805 idx = do_formals (macro, idx, in);
2806 }
2807
2808 /* and stick it in the macro hash table */
2809 hash_create (&macro_table, &name)->value.m = macro;
2810 }
2811
2812 static
2813 int
2814 get_token (idx, in, name)
2815 int idx;
2816 sb *in;
2817 sb *name;
2818 {
2819 if (idx < in->len
2820 && ISFIRSTCHAR (in->ptr[idx]))
2821 {
2822 sb_add_char (name, in->ptr[idx++]);
2823 while (idx < in->len
2824 && ISNEXTCHAR (in->ptr[idx]))
2825 {
2826 sb_add_char (name, in->ptr[idx++]);
2827 }
2828 }
2829 /* Ignore trailing & */
2830 if (alternate && idx < in->len && in->ptr[idx] == '&')
2831 idx++;
2832 return idx;
2833 }
2834
2835 /* Scan a token, but stop if a ' is seen */
2836 static int
2837 get_apost_token (idx, in, name, kind)
2838 int idx;
2839 sb *in;
2840 sb *name;
2841 int kind;
2842 {
2843 idx = get_token (idx, in, name);
2844 if (idx < in->len && in->ptr[idx] == kind)
2845 idx++;
2846 return idx;
2847 }
2848
2849 static int
2850 sub_actual (src, in, t, m, kind, out, copyifnotthere)
2851 int src;
2852 sb *in;
2853 sb *t;
2854 macro_entry *m;
2855 int kind;
2856 sb *out;
2857 int copyifnotthere;
2858 {
2859 /* This is something to take care of */
2860 hash_entry *ptr;
2861 src = get_apost_token (src, in, t, kind);
2862 /* See if it's in the macro's hash table */
2863 ptr = hash_lookup (&m->formal_hash, t);
2864 if (ptr)
2865 {
2866 if (ptr->value.f->actual.len)
2867 {
2868 sb_add_sb (out, &ptr->value.f->actual);
2869 }
2870 else
2871 {
2872 sb_add_sb (out, &ptr->value.f->def);
2873 }
2874 }
2875 else if (copyifnotthere)
2876 {
2877 sb_add_sb (out, t);
2878 }
2879 else
2880 {
2881 sb_add_char (out, '\\');
2882 sb_add_sb (out, t);
2883 }
2884 return src;
2885 }
2886
2887 static
2888 void
2889 macro_expand (name, idx, in, m)
2890 sb *name;
2891 int idx;
2892 sb *in;
2893 macro_entry *m;
2894 {
2895 sb t;
2896 sb out;
2897 hash_entry *ptr;
2898 formal_entry *f;
2899 int is_positional = 0;
2900 int is_keyword = 0;
2901
2902 sb_new (&t);
2903 sb_new (&out);
2904
2905 /* Reset any old value the actuals may have */
2906 for (f = m->formals; f; f = f->next)
2907 sb_reset (&f->actual);
2908 f = m->formals;
2909 /* Peel off the actuals and store them away in the hash tables' actuals */
2910 while (!eol(idx, in))
2911 {
2912 int scan;
2913 idx = sb_skip_white (idx, in);
2914 /* Look and see if it's a positional or keyword arg */
2915 scan = idx;
2916 while (scan < in->len
2917 && !ISSEP (in->ptr[scan])
2918 && (!alternate && in->ptr[scan] != '='))
2919 scan++;
2920 if (scan < in->len && (!alternate) && in->ptr[scan] == '=')
2921 {
2922 is_keyword = 1;
2923 if (is_positional)
2924 {
2925 ERROR ((stderr, "Can't mix positional and keyword arguments.\n"));
2926 return;
2927 }
2928 /* This is a keyword arg, fetch the formal name and
2929 then the actual stuff */
2930 sb_reset (&t);
2931 idx = get_token (idx, in, &t);
2932 if (in->ptr[idx] != '=')
2933 ERROR ((stderr, "confused about formal params.\n"));
2934
2935 /* Lookup the formal in the macro's list */
2936 ptr = hash_lookup (&m->formal_hash, &t);
2937 if (!ptr)
2938 {
2939 ERROR ((stderr, "MACRO formal argument %s does not exist.\n", sb_name (&t)));
2940 return;
2941 }
2942 else
2943 {
2944 /* Insert this value into the right place */
2945 sb_reset (&ptr->value.f->actual);
2946 idx = get_any_string (idx + 1, in, &ptr->value.f->actual, 0, 0);
2947 }
2948 }
2949 else
2950 {
2951 /* This is a positional arg */
2952 is_positional = 1;
2953 if (is_keyword)
2954 {
2955 ERROR ((stderr, "Can't mix positional and keyword arguments.\n"));
2956 return;
2957 }
2958 if (!f)
2959 {
2960 ERROR ((stderr, "Too many positional arguments.\n"));
2961 return;
2962 }
2963
2964 sb_reset (&f->actual);
2965 idx = get_any_string (idx, in, &f->actual, 1, 0);
2966 f = f->next;
2967 }
2968 idx = sb_skip_comma (idx, in);
2969 }
2970
2971 /* Copy the stuff from the macro buffer into a safe place and substitute any args */
2972
2973 {
2974 int src = 0;
2975 int inquote = 0;
2976 sb *in = &m->sub;
2977 sb_reset (&out);
2978
2979 while (src < in->len)
2980 {
2981 if (in->ptr[src] == '&')
2982 {
2983 sb_reset (&t);
2984 src = sub_actual (src + 1, in, &t, m, '&', &out, 0);
2985 }
2986 else if (in->ptr[src] == '\\')
2987 {
2988 src++;
2989 if (in->ptr[src] == comment_char)
2990 {
2991 /* This is a comment, just drop the rest of the line */
2992 while (src < in->len
2993 && in->ptr[src] != '\n')
2994 src++;
2995
2996 }
2997 else if (in->ptr[src] == '(')
2998 {
2999 /* Sub in till the next ')' literally */
3000 src++;
3001 while (src < in->len && in->ptr[src] != ')')
3002 {
3003 sb_add_char (&out, in->ptr[src++]);
3004 }
3005 if (in->ptr[src] == ')')
3006 src++;
3007 else
3008 ERROR ((stderr, "Missplaced ).\n"));
3009 }
3010 else if (in->ptr[src] == '@')
3011 {
3012 /* Sub in the macro invocation number */
3013
3014 char buffer[6];
3015 src++;
3016 sprintf (buffer, "%05d", number);
3017 sb_add_string (&out, buffer);
3018 }
3019 else if (in->ptr[src] == '&')
3020 {
3021 /* This is a preprocessor variable name, we don't do them
3022 here */
3023 sb_add_char (&out, '\\');
3024 sb_add_char (&out, '&');
3025 src++;
3026 }
3027 else
3028 {
3029 sb_reset (&t);
3030 src = sub_actual (src, in, &t, m, '\'', &out, 0);
3031 }
3032 }
3033 else if (ISFIRSTCHAR (in->ptr[src]) && alternate)
3034 {
3035 sb_reset (&t);
3036 src = sub_actual (src, in, &t, m, '\'', &out, 1);
3037 }
3038 else if (ISCOMMENTCHAR (in->ptr[src])
3039 && src + 1 < in->len
3040 && ISCOMMENTCHAR (in->ptr[src+1])
3041 && !inquote)
3042 {
3043 /* Two comment chars in a row cause the rest of the line to be dropped */
3044 while (src < in->len && in->ptr[src] != '\n')
3045 src++;
3046 }
3047 else if (in->ptr[src] == '"')
3048 {
3049 inquote = !inquote;
3050 sb_add_char (&out, in->ptr[src++]);
3051 }
3052 else
3053 {
3054 sb_add_char (&out, in->ptr[src++]);
3055 }
3056 }
3057 include_buf (name, &out, include_macro, include_next_index ());
3058 }
3059 sb_kill (&t);
3060 sb_kill (&out);
3061 number++;
3062 }
3063
3064 static int
3065 macro_op (idx, in)
3066 int idx;
3067 sb *in;
3068 {
3069 int res = 0;
3070 /* The macro name must be the first thing on the line */
3071 if (idx < in->len)
3072 {
3073 sb name;
3074 hash_entry *ptr;
3075 sb_new (&name);
3076 idx = get_token (idx, in, &name);
3077
3078 if (name.len)
3079 {
3080 /* Got a name, look it up */
3081
3082 ptr = hash_lookup (&macro_table, &name);
3083
3084 if (ptr)
3085 {
3086 /* It's in the table, copy out the stuff and convert any macro args */
3087 macro_expand (&name, idx, in, ptr->value.m);
3088 res = 1;
3089 }
3090 }
3091 sb_kill (&name);
3092 }
3093
3094
3095 return res;
3096 }
3097
3098
3099 /* STRING HANDLING */
3100
3101 static int
3102 getstring (idx, in, acc)
3103 int idx;
3104 sb *in;
3105 sb *acc;
3106 {
3107 idx = sb_skip_white (idx, in);
3108
3109 while (idx < in->len
3110 && (in->ptr[idx] == '"'
3111 || in->ptr[idx] == '<'
3112 || (in->ptr[idx] == '\'' && alternate)))
3113 {
3114 if (in->ptr[idx] == '<')
3115 {
3116 if (alternate)
3117 {
3118 int nest = 0;
3119 idx++;
3120 while ((in->ptr[idx] != '>' || nest)
3121 && idx < in->len)
3122 {
3123 if (in->ptr[idx] == '!')
3124 {
3125 idx++ ;
3126 sb_add_char (acc, in->ptr[idx++]);
3127 }
3128 else {
3129 if (in->ptr[idx] == '>')
3130 nest--;
3131 if (in->ptr[idx] == '<')
3132 nest++;
3133 sb_add_char (acc, in->ptr[idx++]);
3134 }
3135 }
3136 idx++;
3137 }
3138 else {
3139 int code;
3140 idx++;
3141 idx = exp_get_abs ("Character code in string must be absolute expression.\n",
3142 idx, in, &code);
3143 sb_add_char (acc, code);
3144
3145 if (in->ptr[idx] != '>')
3146 ERROR ((stderr, "Missing > for character code.\n"));
3147 idx++;
3148 }
3149 }
3150 else if (in->ptr[idx] == '"' || in->ptr[idx] == '\'')
3151 {
3152 char tchar = in->ptr[idx];
3153 idx++;
3154 while (idx < in->len)
3155 {
3156 if (alternate && in->ptr[idx] == '!')
3157 {
3158 idx++ ;
3159 sb_add_char (acc, in->ptr[idx++]);
3160 }
3161 else {
3162 if (in->ptr[idx] == tchar)
3163 {
3164 idx++;
3165 if (idx >= in->len || in->ptr[idx] != tchar)
3166 break;
3167 }
3168 sb_add_char (acc, in->ptr[idx]);
3169 idx++;
3170 }
3171 }
3172 }
3173 }
3174
3175 return idx;
3176 }
3177
3178 /* .SDATA[C|Z] <string> */
3179
3180 static
3181 void
3182 do_sdata (idx, in, type)
3183 int idx;
3184 sb *in;
3185 char type;
3186 {
3187 int nc = 0;
3188 int pidx = -1;
3189 sb acc;
3190 sb_new (&acc);
3191 fprintf (outfile, ".byte\t");
3192
3193 while (!eol (idx, in))
3194 {
3195 int i;
3196 sb_reset (&acc);
3197 idx = sb_skip_white (idx, in);
3198 while (!eol (idx, in))
3199 {
3200 pidx = idx = get_any_string (idx, in, &acc, 0, 1);
3201 if (type == 'c')
3202 {
3203 if (acc.len > 255)
3204 {
3205 ERROR ((stderr, "string for SDATAC longer than 255 characters (%d).\n", acc.len));
3206 }
3207 fprintf (outfile, "%d", acc.len);
3208 nc = 1;
3209 }
3210
3211 for (i = 0; i < acc.len; i++)
3212 {
3213 if (nc)
3214 {
3215 fprintf (outfile, ",");
3216 }
3217 fprintf (outfile, "%d", acc.ptr[i]);
3218 nc = 1;
3219 }
3220
3221 if (type == 'z')
3222 {
3223 if (nc)
3224 fprintf (outfile, ",");
3225 fprintf (outfile, "0");
3226 }
3227 idx = sb_skip_comma (idx, in);
3228 if (idx == pidx) break;
3229 }
3230 if (!alternate && in->ptr[idx] != ',' && idx != in->len)
3231 {
3232 fprintf (outfile, "\n");
3233 ERROR ((stderr, "illegal character in SDATA line (0x%x).\n", in->ptr[idx]));
3234 break;
3235 }
3236 idx++;
3237 }
3238 sb_kill (&acc);
3239 fprintf (outfile, "\n");
3240 }
3241
3242 /* .SDATAB <count> <string> */
3243
3244 static void
3245 do_sdatab (idx, in)
3246 int idx;
3247 sb *in;
3248 {
3249 int repeat;
3250 int i;
3251 sb acc;
3252 sb_new (&acc);
3253
3254 idx = exp_get_abs ("Must have absolute SDATAB repeat count.\n", idx, in, &repeat);
3255 if (repeat <= 0)
3256 {
3257 ERROR ((stderr, "Must have positive SDATAB repeat count (%d).\n", repeat));
3258 repeat = 1;
3259 }
3260
3261 idx = sb_skip_comma (idx, in);
3262 idx = getstring (idx, in, &acc);
3263
3264 for (i = 0; i < repeat; i++)
3265 {
3266 if (i)
3267 fprintf (outfile, "\t");
3268 fprintf (outfile, ".byte\t");
3269 sb_print (&acc);
3270 fprintf (outfile, "\n");
3271 }
3272 sb_kill (&acc);
3273
3274 }
3275
3276 int
3277 new_file (name)
3278 char *name;
3279 {
3280 FILE *newone = fopen (name, "r");
3281 if (!newone)
3282 return 0;
3283
3284 if (isp == MAX_INCLUDES)
3285 FATAL ((stderr, "Unreasonable include depth (%ld).\n", (long) isp));
3286
3287 sp++;
3288 sp->handle = newone;
3289
3290 sb_new (&sp->name);
3291 sb_add_string (&sp->name, name);
3292
3293 sp->linecount = 1;
3294 sp->pushback_index = 0;
3295 sp->type = include_file;
3296 sp->index = 0;
3297 sb_new (&sp->pushback);
3298 return 1;
3299 }
3300
3301 static void
3302 do_include (idx, in)
3303 int idx;
3304 sb *in;
3305 {
3306 sb t;
3307 char *text;
3308 sb_new (&t);
3309 idx = getstring (idx, in, &t);
3310 text = sb_name (&t);
3311 if (!new_file (text))
3312 {
3313 FATAL ((stderr, "Can't open include file `%s'.\n", text));
3314 }
3315 sb_kill (&t);
3316 }
3317
3318 static void
3319 include_pop ()
3320 {
3321 if (sp != include_stack)
3322 {
3323 if (sp->handle)
3324 fclose (sp->handle);
3325 sp--;
3326 }
3327 }
3328
3329 /* Get the next character from the include stack. If there's anything
3330 in the pushback buffer, take that first. If we're at eof, pop from
3331 the stack and try again. Keep the linecount up to date. */
3332
3333 static int
3334 get ()
3335 {
3336 int r;
3337
3338 if (sp->pushback.len != sp->pushback_index)
3339 {
3340 r = (char) (sp->pushback.ptr[sp->pushback_index++]);
3341 /* When they've all gone, reset the pointer */
3342 if (sp->pushback_index == sp->pushback.len)
3343 {
3344 sp->pushback.len = 0;
3345 sp->pushback_index = 0;
3346 }
3347 }
3348 else if (sp->handle)
3349 {
3350 r = getc (sp->handle);
3351 }
3352 else
3353 r = EOF;
3354
3355 if (r == EOF && isp)
3356 {
3357 include_pop ();
3358 r = get ();
3359 while (r == EOF && isp)
3360 {
3361 include_pop ();
3362 r = get ();
3363 }
3364 return r;
3365 }
3366 if (r == '\n')
3367 {
3368 sp->linecount++;
3369 }
3370
3371 return r;
3372 }
3373
3374 static int
3375 linecount ()
3376 {
3377 return sp->linecount;
3378 }
3379
3380 static int
3381 include_next_index ()
3382 {
3383 static int index;
3384 if (!unreasonable
3385 && index > MAX_REASONABLE)
3386 FATAL ((stderr, "Unreasonable expansion (-u turns off check).\n"));
3387 return ++index;
3388 }
3389
3390
3391 /* Initialize the chartype vector. */
3392
3393 static void
3394 chartype_init ()
3395 {
3396 int x;
3397 for (x = 0; x < 256; x++)
3398 {
3399 if (isalpha (x) || x == '_' || x == '$')
3400 chartype[x] |= FIRSTBIT;
3401
3402 if (isdigit (x) || isalpha (x) || x == '_' || x == '$')
3403 chartype[x] |= NEXTBIT;
3404
3405 if (x == ' ' || x == '\t' || x == ',' || x == '"' || x == ';'
3406 || x == '"' || x == '<' || x == '>' || x == ')' || x == '(')
3407 chartype[x] |= SEPBIT;
3408
3409 if (x == 'b' || x == 'B'
3410 || x == 'q' || x == 'Q'
3411 || x == 'h' || x == 'H'
3412 || x == 'd' || x == 'D')
3413 chartype [x] |= BASEBIT;
3414
3415 if (x == ' ' || x == '\t')
3416 chartype[x] |= WHITEBIT;
3417
3418 if (x == comment_char)
3419 chartype[x] |= COMMENTBIT;
3420 }
3421 }
3422
3423
3424
3425 /* What to do with all the keywords */
3426 #define PROCESS 0x1000 /* Run substitution over the line */
3427 #define LAB 0x2000 /* Spit out the label */
3428
3429 #define K_EQU PROCESS|1
3430 #define K_ASSIGN PROCESS|2
3431 #define K_REG PROCESS|3
3432 #define K_ORG PROCESS|4
3433 #define K_RADIX PROCESS|5
3434 #define K_DATA LAB|PROCESS|6
3435 #define K_DATAB LAB|PROCESS|7
3436 #define K_SDATA LAB|PROCESS|8
3437 #define K_SDATAB LAB|PROCESS|9
3438 #define K_SDATAC LAB|PROCESS|10
3439 #define K_SDATAZ LAB|PROCESS|11
3440 #define K_RES LAB|PROCESS|12
3441 #define K_SRES LAB|PROCESS|13
3442 #define K_SRESC LAB|PROCESS|14
3443 #define K_SRESZ LAB|PROCESS|15
3444 #define K_EXPORT LAB|PROCESS|16
3445 #define K_GLOBAL LAB|PROCESS|17
3446 #define K_PRINT LAB|PROCESS|19
3447 #define K_FORM LAB|PROCESS|20
3448 #define K_HEADING LAB|PROCESS|21
3449 #define K_PAGE LAB|PROCESS|22
3450 #define K_IMPORT LAB|PROCESS|23
3451 #define K_PROGRAM LAB|PROCESS|24
3452 #define K_END PROCESS|25
3453 #define K_INCLUDE PROCESS|26
3454 #define K_IGNORED PROCESS|27
3455 #define K_ASSIGNA PROCESS|28
3456 #define K_ASSIGNC 29
3457 #define K_AIF PROCESS|30
3458 #define K_AELSE PROCESS|31
3459 #define K_AENDI PROCESS|32
3460 #define K_AREPEAT PROCESS|33
3461 #define K_AENDR PROCESS|34
3462 #define K_AWHILE 35
3463 #define K_AENDW PROCESS|36
3464 #define K_EXITM 37
3465 #define K_MACRO PROCESS|38
3466 #define K_ENDM 39
3467 #define K_ALIGN PROCESS|LAB|40
3468 #define K_ALTERNATE 41
3469 #define K_DB LAB|PROCESS|42
3470 #define K_DW LAB|PROCESS|43
3471 #define K_DL LAB|PROCESS|44
3472 #define K_LOCAL 45
3473
3474
3475 static struct
3476 {
3477 char *name;
3478 int code;
3479 int extra;
3480 }
3481 kinfo[] =
3482 {
3483 { "EQU", K_EQU, 0 },
3484 { "ALTERNATE", K_ALTERNATE, 0 },
3485 { "ASSIGN", K_ASSIGN, 0 },
3486 { "REG", K_REG, 0 },
3487 { "ORG", K_ORG, 0 },
3488 { "RADIX", K_RADIX, 0 },
3489 { "DATA", K_DATA, 0 },
3490 { "DB", K_DB, 0 },
3491 { "DW", K_DW, 0 },
3492 { "DL", K_DL, 0 },
3493 { "DATAB", K_DATAB, 0 },
3494 { "SDATA", K_SDATA, 0 },
3495 { "SDATAB", K_SDATAB, 0 },
3496 { "SDATAZ", K_SDATAZ, 0 },
3497 { "SDATAC", K_SDATAC, 0 },
3498 { "RES", K_RES, 0 },
3499 { "SRES", K_SRES, 0 },
3500 { "SRESC", K_SRESC, 0 },
3501 { "SRESZ", K_SRESZ, 0 },
3502 { "EXPORT", K_EXPORT, 0 },
3503 { "GLOBAL", K_GLOBAL, 0 },
3504 { "PRINT", K_PRINT, 0 },
3505 { "FORM", K_FORM, 0 },
3506 { "HEADING", K_HEADING, 0 },
3507 { "PAGE", K_PAGE, 0 },
3508 { "PROGRAM", K_IGNORED, 0 },
3509 { "END", K_END, 0 },
3510 { "INCLUDE", K_INCLUDE, 0 },
3511 { "ASSIGNA", K_ASSIGNA, 0 },
3512 { "ASSIGNC", K_ASSIGNC, 0 },
3513 { "AIF", K_AIF, 0 },
3514 { "AELSE", K_AELSE, 0 },
3515 { "AENDI", K_AENDI, 0 },
3516 { "AREPEAT", K_AREPEAT, 0 },
3517 { "AENDR", K_AENDR, 0 },
3518 { "EXITM", K_EXITM, 0 },
3519 { "MACRO", K_MACRO, 0 },
3520 { "ENDM", K_ENDM, 0 },
3521 { "AWHILE", K_AWHILE, 0 },
3522 { "ALIGN", K_ALIGN, 0 },
3523 { "AENDW", K_AENDW, 0 },
3524 { "ALTERNATE", K_ALTERNATE, 0 },
3525 { "LOCAL", K_LOCAL, 0 },
3526 { NULL, 0, 0 }
3527 };
3528
3529 /* Look for a pseudo op on the line. If one's there then call
3530 its handler. */
3531
3532 static int
3533 process_pseudo_op (idx, line, acc)
3534 int idx;
3535 sb *line;
3536 sb *acc;
3537 {
3538
3539
3540 if (line->ptr[idx] == '.' || alternate)
3541 {
3542 /* Scan forward and find pseudo name */
3543 char *in;
3544 hash_entry *ptr;
3545
3546 char *s;
3547 char *e;
3548 if (line->ptr[idx] == '.')
3549 idx++;
3550 in = line->ptr + idx;
3551 s = in;
3552 e = s;
3553 sb_reset (acc);
3554
3555 while (idx < line->len && *e && ISFIRSTCHAR (*e))
3556 {
3557 sb_add_char (acc, *e);
3558 e++;
3559 idx++;
3560 }
3561
3562 ptr = hash_lookup (&keyword_hash_table, acc);
3563
3564 if (!ptr)
3565 {
3566 #if 0
3567 /* This one causes lots of pain when trying to preprocess
3568 ordinary code */
3569 WARNING ((stderr, "Unrecognised pseudo op `%s'.\n", sb_name (acc)));
3570 #endif
3571 return 0;
3572 }
3573 if (ptr->value.i & LAB)
3574 { /* output the label */
3575 if (label.len)
3576 {
3577 fprintf (outfile, "%s:\t", sb_name (&label));
3578 }
3579 else
3580 fprintf (outfile, "\t");
3581 }
3582
3583 if (ptr->value.i & PROCESS)
3584 {
3585 /* Polish the rest of the line before handling the pseudo op */
3586 #if 0
3587 strip_comments(line);
3588 #endif
3589 sb_reset (acc);
3590 process_assigns (idx, line, acc);
3591 sb_reset(line);
3592 change_base (0, acc, line);
3593 idx = 0;
3594 }
3595 if (!condass_on ())
3596 {
3597 switch (ptr->value.i)
3598 {
3599 case K_AIF:
3600 do_aif (idx, line);
3601 break;
3602 case K_AELSE:
3603 do_aelse ();
3604 break;
3605 case K_AENDI:
3606 do_aendi ();
3607 break;
3608 }
3609 return 1;
3610 }
3611 else
3612 {
3613 switch (ptr->value.i)
3614 {
3615 case K_ALTERNATE:
3616 alternate = 1;
3617 return 1;
3618 case K_AELSE:
3619 do_aelse ();
3620 return 1;
3621 case K_AENDI:
3622 do_aendi ();
3623 return 1;
3624 case K_ORG:
3625 ERROR ((stderr, "ORG command not allowed.\n"));
3626 break;
3627 case K_RADIX:
3628 do_radix (line);
3629 return 1;
3630 case K_DB:
3631 do_data (idx, line, 1);
3632 return 1;
3633 case K_DW:
3634 do_data (idx, line, 2);
3635 return 1;
3636 case K_DL:
3637 do_data (idx, line, 4);
3638 return 1;
3639 case K_DATA:
3640 do_data (idx, line, 0);
3641 return 1;
3642 case K_DATAB:
3643 do_datab (idx, line);
3644 return 1;
3645 case K_SDATA:
3646 do_sdata (idx, line, 0);
3647 return 1;
3648 case K_SDATAB:
3649 do_sdatab (idx, line);
3650 return 1;
3651 case K_SDATAC:
3652 do_sdata (idx, line, 'c');
3653 return 1;
3654 case K_SDATAZ:
3655 do_sdata (idx, line, 'z');
3656 return 1;
3657 case K_ASSIGN:
3658 do_assign (1, 0, line);
3659 return 1;
3660 case K_AIF:
3661 do_aif (idx, line);
3662 return 1;
3663 case K_AREPEAT:
3664 do_arepeat (idx, line);
3665 return 1;
3666 case K_AENDW:
3667 do_aendw ();
3668 return 1;
3669 case K_AWHILE:
3670 do_awhile (idx, line);
3671 return 1;
3672 case K_AENDR:
3673 do_aendr ();
3674 return 1;
3675 case K_EQU:
3676 do_assign (0, idx, line);
3677 return 1;
3678 case K_ALIGN:
3679 do_align (idx, line);
3680 return 1;
3681 case K_RES:
3682 do_res (idx, line, 0);
3683 return 1;
3684 case K_SRES:
3685 do_res (idx, line, 's');
3686 return 1;
3687 case K_INCLUDE:
3688 do_include (idx, line);
3689 return 1;
3690 case K_LOCAL:
3691 do_local (idx, line);
3692 return 1;
3693 case K_MACRO:
3694 do_macro (idx, line);
3695 return 1;
3696 case K_ENDM:
3697 do_endm ();
3698 return 1;
3699 case K_SRESC:
3700 do_res (idx, line, 'c');
3701 return 1;
3702 case K_PRINT:
3703 do_print (idx, line);
3704 return 1;
3705 case K_FORM:
3706 do_form (idx, line);
3707 return 1;
3708 case K_HEADING:
3709 do_heading (idx, line);
3710 return 1;
3711 case K_PAGE:
3712 do_page ();
3713 return 1;
3714 case K_GLOBAL:
3715 case K_EXPORT:
3716 do_export (line);
3717 return 1;
3718 case K_IMPORT:
3719 return 1;
3720 case K_SRESZ:
3721 do_res (idx, line, 'z');
3722 return 1;
3723 case K_IGNORED:
3724 return 1;
3725 case K_END:
3726 do_end ();
3727 return 1;
3728 case K_ASSIGNA:
3729 do_assigna (idx, line);
3730 return 1;
3731 case K_ASSIGNC:
3732 do_assignc (idx, line);
3733 return 1;
3734 case K_EXITM:
3735 do_exitm ();
3736 return 1;
3737 case K_REG:
3738 do_reg (idx, line);
3739 return 1;
3740 }
3741 }
3742 }
3743 return 0;
3744 }
3745
3746
3747
3748 /* Build the keyword hash table - put each keyword in the table twice,
3749 once upper and once lower case.*/
3750
3751 static void
3752 process_init ()
3753 {
3754 int i;
3755
3756 for (i = 0; kinfo[i].name; i++)
3757 {
3758 sb label;
3759 int j;
3760 sb_new (&label);
3761 sb_add_string (&label, kinfo[i].name);
3762
3763 hash_add_to_int_table (&keyword_hash_table, &label, kinfo[i].code);
3764
3765 sb_reset (&label);
3766 for (j = 0; kinfo[i].name[j]; j++)
3767 sb_add_char (&label, kinfo[i].name[j] - 'A' + 'a');
3768 hash_add_to_int_table (&keyword_hash_table, &label, kinfo[i].code);
3769
3770 sb_kill (&label);
3771 }
3772 }
3773
3774
3775 static void
3776 do_define (string)
3777 char *string;
3778 {
3779 sb label;
3780 int res = 1;
3781 hash_entry *ptr;
3782 sb_new (&label);
3783
3784
3785 while (*string)
3786 {
3787 if (*string == '=')
3788 {
3789 sb value;
3790 sb_new (&value);
3791 string++;
3792 while (*string)
3793 {
3794 sb_add_char (&value, *string);
3795 string++;
3796 }
3797 exp_get_abs ("Invalid expression on command line.\n", 0, &value, &res);
3798 sb_kill (&value);
3799 break;
3800 }
3801 sb_add_char (&label, *string);
3802
3803 string ++;
3804 }
3805
3806 ptr = hash_create (&vars, &label);
3807 free_old_entry (ptr);
3808 ptr->type = hash_integer;
3809 ptr->value.i = res;
3810 sb_kill (&label);
3811 }
3812 char *program_name;
3813
3814 /* The list of long options. */
3815 static struct option long_options[] =
3816 {
3817 { "alternate", no_argument, 0, 'a' },
3818 { "commentchar", required_argument, 0, 'c' },
3819 { "copysource", no_argument, 0, 's' },
3820 { "debug", no_argument, 0, 'd' },
3821 { "help", no_argument, 0, 'h' },
3822 { "output", required_argument, 0, 'o' },
3823 { "print", no_argument, 0, 'p' },
3824 { "unreasonable", no_argument, 0, 'u' },
3825 { "version", no_argument, 0, 'v' },
3826 { "define", required_argument, 0, 'd' },
3827 { NULL, no_argument, 0, 0 }
3828 };
3829
3830 /* Show a usage message and exit. */
3831 static void
3832 show_usage (file, status)
3833 FILE *file;
3834 int status;
3835 {
3836 fprintf (file, "\
3837 Usage: %s \n\
3838 [-a] [--alternate] enter alternate macro mode\n\
3839 [-c char] [--commentchar char] change the comment character from !\n\
3840 [-d] [--debug] print some debugging info\n\
3841 [-h] [--help] print this message\n\
3842 [-o out] [--output out] set the output file\n\
3843 [-p] [--print] print line numbers\n\
3844 [-s] [--copysource] copy source through as comments \n\
3845 [-u] [--unreasonable] allow unreasonable nesting\n\
3846 [-v] [--version] print the program version\n\
3847 [-Dname=value] create preprocessor variable called name, with value\n\
3848 [in-file]\n", program_name);
3849 exit (status);
3850 }
3851
3852 /* Display a help message and exit. */
3853 static void
3854 show_help ()
3855 {
3856 printf ("%s: Gnu Assembler Macro Preprocessor\n",
3857 program_name);
3858 show_usage (stdout, 0);
3859 }
3860
3861 int
3862 main (argc, argv)
3863 int argc;
3864 char **argv;
3865 {
3866 int opt;
3867 char *out_name = 0;
3868 sp = include_stack;
3869
3870 ifstack[0].on = 1;
3871 ifi = 0;
3872
3873
3874
3875 program_name = argv[0];
3876 xmalloc_set_program_name (program_name);
3877
3878 hash_new_table (101, &macro_table);
3879 hash_new_table (101, &keyword_hash_table);
3880 hash_new_table (101, &assign_hash_table);
3881 hash_new_table (101, &vars);
3882
3883 sb_new (&label);
3884 process_init ();
3885
3886 while ((opt = getopt_long (argc, argv, "sdhavc:upo:D:", long_options,
3887 (int *) NULL))
3888 != EOF)
3889 {
3890 switch (opt)
3891 {
3892 case 'o':
3893 out_name = optarg;
3894 break;
3895 case 'u':
3896 unreasonable = 1;
3897 break;
3898 case 'p':
3899 print_line_number = 1;
3900 break;
3901 case 'c':
3902 comment_char = optarg[0];
3903 break;
3904 case 'a':
3905 alternate = 1;
3906 break;
3907 case 's':
3908 copysource = 1;
3909 break;
3910 case 'd':
3911 stats = 1;
3912 break;
3913 case 'D':
3914 do_define (optarg);
3915 break;
3916 case 'h':
3917 show_help ();
3918 /*NOTREACHED*/
3919 case 'v':
3920 printf ("GNU %s version %s\n", program_name, program_version);
3921 exit (0);
3922 /*NOTREACHED*/
3923 case 0:
3924 break;
3925 default:
3926 show_usage (stderr, 1);
3927 /*NOTREACHED*/
3928 }
3929 }
3930
3931
3932 if (out_name) {
3933 outfile = fopen (out_name, "w");
3934 if (!outfile)
3935 {
3936 fprintf (stderr, "%s: Can't open output file `%s'.\n",
3937 program_name, out_name);
3938 exit (1);
3939 }
3940 }
3941 else {
3942 outfile = stdout;
3943 }
3944
3945 chartype_init ();
3946 if (!outfile)
3947 outfile = stdout;
3948
3949 /* Process all the input files */
3950
3951 while (optind < argc)
3952 {
3953 if (new_file (argv[optind]))
3954 {
3955 process_file ();
3956 }
3957 else
3958 {
3959 fprintf (stderr, "%s: Can't open input file `%s'.\n",
3960 program_name, argv[optind]);
3961 exit (1);
3962 }
3963 optind++;
3964 }
3965
3966 quit ();
3967 return 0;
3968 }
This page took 0.103723 seconds and 5 git commands to generate.