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