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