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