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