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