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