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