* gas/lib/gas-defs.exp (gas_finish): Call "close" and "wait"
[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
SC
152#define COMMENTBIT 16
153
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)
159
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 + - ~
717* /
718+ -
719&
720| ~
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
1701int
1702get_any_string (idx, in, out)
1703 int idx;
1704 sb *in;
1705 sb *out;
1706{
fa1a86f3 1707 sb_reset (out);
b0f2092b 1708 idx = sb_skip_white (idx, in);
b0f2092b 1709
b0f2092b 1710
fa1a86f3 1711 if (idx < in->len)
b0f2092b 1712 {
fa1a86f3
SC
1713 if (in->ptr[idx] == '%'
1714 && alternate)
1715 {
1716 int val;
1717 char buf[20];
1718 /* Turns the next expression into a string */
1719 idx = exp_get_abs ("% operator needs absolute expression",
1720 idx + 1,
1721 in,
1722 &val);
1723 sprintf(buf, "\"%d\"", val);
1724 sb_add_string (out, buf);
1725 }
1726 else if (in->ptr[idx] == '"'
1727 || in->ptr[idx] == '<'
1728 || (alternate && in->ptr[idx] == '\''))
1729 {
1730 if (alternate)
1731 {
1732 /* Keep the quotes */
1733 sb_add_char (out, '\"');
1734 idx = getstring (idx, in, out);
1735 sb_add_char (out, '\"');
1736
1737 }
1738 else {
1739 idx = getstring (idx, in, out);
1740 }
1741 }
1742 else
1743 {
1744 while (idx < in->len
1745 && (in->ptr[idx] == '"'
1746 || in->ptr[idx] == '\''
1747 || !ISSEP (in->ptr[idx])))
1748 {
1749 if (in->ptr[idx] == '"'
1750 || in->ptr[idx] == '\'')
1751 {
1752 char tchar = in->ptr[idx];
1753 sb_add_char (out, in->ptr[idx++]);
1754 while (idx < in->len
1755 && in->ptr[idx] != tchar)
1756 sb_add_char (out, in->ptr[idx++]);
1757 }
1758 sb_add_char (out, in->ptr[idx++]);
1759
1760 }
1761 }
b0f2092b
SC
1762 }
1763 return idx;
1764}
1765
1766
1767/* skip along sb in starting at idx, suck off whitespace a ( and more
1768 whitespace. return the idx of the next char */
1769
1770int
1771skip_openp (idx, in)
1772 int idx;
1773 sb *in;
1774{
1775 idx = sb_skip_white (idx, in);
1776 if (in->ptr[idx] != '(')
1777 ERROR ((stderr, "misplaced ( .\n"));
1778 idx = sb_skip_white (idx + 1, in);
1779 return idx;
1780}
1781
1782/* skip along sb in starting at idx, suck off whitespace a ) and more
1783 whitespace. return the idx of the next char */
1784
1785int
1786skip_closep (idx, in)
1787 int idx;
1788 sb *in;
1789{
1790 idx = sb_skip_white (idx, in);
1791 if (in->ptr[idx] != ')')
1792 ERROR ((stderr, "misplaced ).\n"));
1793 idx = sb_skip_white (idx + 1, in);
1794 return idx;
1795}
1796
1797/* .len */
1798
1799int
1800dolen (idx, in, out)
1801 int idx;
1802 sb *in;
1803 sb *out;
1804{
1805
1806 sb stringout;
1807 char buffer[10];
1808
1809 sb_new (&stringout);
1810 idx = skip_openp (idx, in);
1811 idx = get_and_process (idx, in, &stringout);
1812 idx = skip_closep (idx, in);
1813 sprintf (buffer, "%d", stringout.len);
1814 sb_add_string (out, buffer);
1815
1816 sb_kill (&stringout);
1817 return idx;
1818}
1819
1820
1821/* .instr */
1822
1823static
1824int
1825doinstr (idx, in, out)
1826 int idx;
1827 sb *in;
1828 sb *out;
1829{
1830 sb string;
1831 sb search;
1832 int i;
1833 int start;
1834 int res;
1835 char buffer[10];
1836
1837 sb_new (&string);
1838 sb_new (&search);
1839 idx = skip_openp (idx, in);
1840 idx = get_and_process (idx, in, &string);
1841 idx = sb_skip_comma (idx, in);
1842 idx = get_and_process (idx, in, &search);
1843 idx = sb_skip_comma (idx, in);
1844 if (isdigit (in->ptr[idx]))
1845 {
1846 idx = exp_get_abs (".instr needs absolute expresson.\n", idx, in, &start);
1847 }
1848 else
1849 {
1850 start = 0;
1851 }
1852 idx = skip_closep (idx, in);
1853 res = -1;
1854 for (i = start; i < string.len; i++)
1855 {
1856 if (strncmp (string.ptr + i, search.ptr, search.len) == 0)
1857 {
1858 res = i;
1859 break;
1860 }
1861 }
1862 sprintf (buffer, "%d", res);
1863 sb_add_string (out, buffer);
1864 sb_kill (&string);
1865 sb_kill (&search);
1866 return idx;
1867}
1868
1869
1870static int
1871dosubstr (idx, in, out)
1872 int idx;
1873 sb *in;
1874 sb *out;
1875{
1876 sb string;
1877 int pos;
1878 int len;
1879 sb_new (&string);
1880
1881 idx = skip_openp (idx, in);
1882 idx = get_and_process (idx, in, &string);
1883 idx = sb_skip_comma (idx, in);
1884 idx = exp_get_abs ("need absolute position.\n", idx, in, &pos);
1885 idx = sb_skip_comma (idx, in);
1886 idx = exp_get_abs ("need absolute length.\n", idx, in, &len);
1887 idx = skip_closep (idx, in);
1888
1889
1890 if (len < 0 || pos < 0 ||
1891 pos > string.len
1892 || pos + len > string.len)
1893 {
1894 sb_add_string (out, " ");
1895 }
1896 else
1897 {
1898 sb_add_char (out, '"');
1899 while (len > 0)
1900 {
1901 sb_add_char (out, string.ptr[pos++]);
1902 len--;
1903 }
1904 sb_add_char (out, '"');
1905 }
1906 sb_kill(&string);
1907 return idx;
1908}
1909
1910/* scan line, change tokens in the hash table to their replacements */
1911void
1912process_assigns (idx, in, buf)
1913 int idx;
1914 sb *in;
1915 sb *buf;
1916{
1917 while (idx < in->len)
1918 {
1919 hash_entry *ptr;
1920 if (in->ptr[idx] == '\\'
1921 && in->ptr[idx + 1] == '&')
1922 {
fa1a86f3
SC
1923 idx = condass_lookup_name (in, idx + 2, buf, 1);
1924 }
1925 else if (in->ptr[idx] == '\\'
1926 && in->ptr[idx + 1] == '$')
1927 {
1928 idx = condass_lookup_name (in, idx + 2, buf, 0);
b0f2092b
SC
1929 }
1930 else if (idx + 3 < in->len
1931 && in->ptr[idx] == '.'
1932 && in->ptr[idx + 1] == 'L'
1933 && in->ptr[idx + 2] == 'E'
1934 && in->ptr[idx + 3] == 'N')
1935 idx = dolen (idx + 4, in, buf);
1936 else if (idx + 6 < in->len
1937 && in->ptr[idx] == '.'
1938 && in->ptr[idx + 1] == 'I'
1939 && in->ptr[idx + 2] == 'N'
1940 && in->ptr[idx + 3] == 'S'
1941 && in->ptr[idx + 4] == 'T'
1942 && in->ptr[idx + 5] == 'R')
1943 idx = doinstr (idx + 6, in, buf);
1944 else if (idx + 7 < in->len
1945 && in->ptr[idx] == '.'
1946 && in->ptr[idx + 1] == 'S'
1947 && in->ptr[idx + 2] == 'U'
1948 && in->ptr[idx + 3] == 'B'
1949 && in->ptr[idx + 4] == 'S'
1950 && in->ptr[idx + 5] == 'T'
1951 && in->ptr[idx + 6] == 'R')
1952 idx = dosubstr (idx + 7, in, buf);
1953 else if (ISFIRSTCHAR (in->ptr[idx]))
1954 {
1955 /* may be a simple name subsitution, see if we have a word */
1956 sb acc;
1957 int cur = idx + 1;
1958 while (cur < in->len
1959 && (ISNEXTCHAR (in->ptr[cur])))
1960 cur++;
1961
1962 sb_new (&acc);
1963 sb_add_buffer (&acc, in->ptr + idx, cur - idx);
1964 ptr = hash_lookup (&assign_hash_table, &acc);
1965 if (ptr)
1966 {
1967 /* Found a definition for it */
1968 sb_add_sb (buf, &ptr->value.s);
1969 }
1970 else
1971 {
1972 /* No definition, just copy the word */
1973 sb_add_sb (buf, &acc);
1974 }
1975 sb_kill (&acc);
1976 idx = cur;
1977 }
1978 else
1979 {
1980 sb_add_char (buf, in->ptr[idx++]);
1981 }
1982 }
1983}
1984
1985static int
1986get_and_process (idx, in, out)
1987 int idx;
1988 sb *in;
1989 sb *out;
1990{
1991 sb t;
1992 sb_new (&t);
1993 idx = get_any_string (idx, in, &t);
1994 process_assigns (0, &t, out);
1995 sb_kill (&t);
1996 return idx;
1997}
1998
1999static
2000void
2001process_file ()
2002{
2003 sb line;
2004 sb t1, t2;
2005 sb acc;
fa1a86f3 2006 sb label_in;
b0f2092b
SC
2007 int more;
2008
2009 sb_new (&line);
2010 sb_new (&t1);
2011 sb_new (&t2);
2012 sb_new(&acc);
fa1a86f3 2013 sb_new (&label_in);
b0f2092b
SC
2014 sb_reset (&line);
2015 more = get_line (&line);
2016 while (more)
2017 {
2018 /* Find any label and pseudo op that we're intested in */
2019 int l;
2020 if (line.len == 0)
2021 {
2022 if (condass_on ())
2023 fprintf (outfile, "\n");
2024 }
2025 else
2026 {
fa1a86f3
SC
2027 l = grab_label (&line, &label_in);
2028 sb_reset (&label);
2029 if (label_in.len)
2030 {
2031 /* Munge any label */
2032
2033
2034 process_assigns (0, &label_in, &label);
2035 }
b0f2092b 2036
b0f2092b
SC
2037 if (line.ptr[l] == ':')
2038 l++;
2039 while (ISWHITE (line.ptr[l]) && l < line.len)
2040 l++;
2041
fa1a86f3 2042 if (l < line.len)
b0f2092b
SC
2043 {
2044 if (process_pseudo_op (l, &line, &acc))
2045 {
2046
2047
2048
2049 }
2050 else if (condass_on ())
2051 {
2052 if (macro_op (l, &line))
2053 {
2054
2055
2056 }
2057 else
2058 {
2059 {
2060 if (label.len)
2061 {
2062 fprintf (outfile, "%s:\t", sb_name (&label));
2063 }
2064 else
2065 fprintf (outfile, "\t");
2066 sb_reset(&t1);
2067 process_assigns (l, &line, &t1);
2068 sb_reset (&t2);
2069 change_base (0, &t1, &t2);
2070 fprintf (outfile, "%s\n", sb_name (&t2));
2071 }
2072 }
2073 }
2074 }
fa1a86f3
SC
2075 else {
2076 /* Only a label on this line */
2077 if (label.len && condass_on())
2078 {
2079 fprintf (outfile, "%s:\n", sb_name (&label));
2080 }
2081 }
b0f2092b
SC
2082 }
2083
2084 if (had_end)
2085 break;
2086 sb_reset (&line);
2087 more = get_line (&line);
2088 }
2089
2090 if (!had_end)
fa1a86f3 2091 WARNING ((stderr, "END missing from end of file.\n"));
b0f2092b
SC
2092}
2093
2094
2095
2096
2097
2098static void
2099free_old_entry (ptr)
2100 hash_entry *ptr;
2101{
2102 if (ptr)
2103 {
2104 if (ptr->type == hash_string)
2105 sb_kill(&ptr->value.s);
2106 }
2107}
2108
2109/* name: .ASSIGNA <value> */
2110
2111void
2112do_assigna (idx, in)
2113 int idx;
2114 sb *in;
2115{
2116 sb tmp;
2117 int val;
2118 sb_new (&tmp);
2119
2120 process_assigns (idx, in, &tmp);
2121 idx = exp_get_abs (".ASSIGNA needs constant expression argument.\n", 0, &tmp, &val);
2122
2123 if (!label.len)
2124 {
2125 ERROR ((stderr, ".ASSIGNA without label.\n"));
2126 }
2127 else
2128 {
2129 hash_entry *ptr = hash_create (&vars, &label);
2130 free_old_entry (ptr);
2131 ptr->type = hash_integer;
2132 ptr->value.i = val;
2133 }
2134 sb_kill (&tmp);
2135}
2136
2137/* name: .ASSIGNC <string> */
2138
2139void
2140do_assignc (idx, in)
2141 int idx;
2142 sb *in;
2143{
2144 sb acc;
2145 sb_new (&acc);
2146 idx = getstring (idx, in, &acc);
2147
2148 if (!label.len)
2149 {
2150 ERROR ((stderr, ".ASSIGNS without label.\n"));
2151 }
2152 else
2153 {
2154 hash_entry *ptr = hash_create (&vars, &label);
2155 free_old_entry (ptr);
2156 ptr->type = hash_string;
2157 sb_new (&ptr->value.s);
2158 sb_add_sb (&ptr->value.s, &acc);
2159 }
2160 sb_kill (&acc);
2161}
2162
2163
2164/* name: .REG (reg) */
2165
2166static void
2167do_reg (idx, in)
2168 int idx;
2169 sb *in;
2170{
2171 /* remove reg stuff from inside parens */
2172 sb what;
2173 idx = skip_openp (idx, in);
2174 sb_new (&what);
2175 while (idx < in->len && in->ptr[idx] != ')')
2176 {
2177 sb_add_char (&what, in->ptr[idx]);
2178 idx++;
2179 }
2180 hash_add_to_string_table (&assign_hash_table, &label, &what, 1);
2181 sb_kill (&what);
2182}
2183
2184
2185static int
fa1a86f3 2186condass_lookup_name (inbuf, idx, out, warn)
b0f2092b
SC
2187 sb *inbuf;
2188 int idx;
2189 sb *out;
fa1a86f3 2190 int warn;
b0f2092b
SC
2191{
2192 hash_entry *ptr;
2193 sb condass_acc;
2194 sb_new (&condass_acc);
2195
2196 while (idx < inbuf->len
2197 && ISNEXTCHAR (inbuf->ptr[idx]))
2198 {
2199 sb_add_char (&condass_acc, inbuf->ptr[idx++]);
2200 }
2201
2202 if (inbuf->ptr[idx] == '\'')
2203 idx++;
2204 ptr = hash_lookup (&vars, &condass_acc);
fa1a86f3
SC
2205
2206
b0f2092b
SC
2207 if (!ptr)
2208 {
fa1a86f3
SC
2209 if (warn)
2210 {
2211 WARNING ((stderr, "Can't find preprocessor variable %s.\n", sb_name (&condass_acc)));
2212 }
2213 else
2214 {
2215 sb_add_string (out, "0");
2216 }
b0f2092b
SC
2217 }
2218 else
2219 {
2220 if (ptr->type == hash_integer)
2221 {
2222 char buffer[30];
2223 sprintf (buffer, "%d", ptr->value.i);
2224 sb_add_string (out, buffer);
2225 }
2226 else
2227 {
2228 sb_add_sb (out, &ptr->value.s);
2229 }
2230 }
2231 sb_kill (&condass_acc);
2232 return idx;
2233}
2234
2235#define EQ 1
2236#define NE 2
2237#define GE 3
2238#define LT 4
2239#define LE 5
2240#define GT 6
2241#define NEVER 7
2242
2243int
2244whatcond (idx, in, val)
2245 int idx;
2246 sb *in;
2247 int *val;
2248{
2249 int cond;
2250 char *p;
2251 idx = sb_skip_white (idx, in);
2252 p = in->ptr + idx;
2253 if (p[0] == 'E' && p[1] == 'Q')
2254 cond = EQ;
2255 else if (p[0] == 'N' && p[1] == 'E')
2256 cond = NE;
2257 else if (p[0] == 'L' && p[1] == 'T')
2258 cond = LT;
2259 else if (p[0] == 'L' && p[1] == 'E')
2260 cond = LE;
2261 else if (p[0] == 'G' && p[1] == 'T')
2262 cond = GT;
2263 else if (p[0] == 'G' && p[1] == 'E')
2264 cond = GE;
2265 else
2266 {
fa1a86f3 2267 ERROR ((stderr, "Comparison operator must be one of EQ, NE, LT, LE, GT or GE.\n"));
b0f2092b
SC
2268 cond = NEVER;
2269 }
2270 idx = sb_skip_white (idx + 2, in);
2271 *val = cond;
2272 return idx;
2273}
2274
2275int
2276istrue (idx, in)
2277 int idx;
2278 sb *in;
2279{
2280 int res;
2281 sb acc_a;
2282 sb cond;
2283 sb acc_b;
2284 sb_new (&acc_a);
2285 sb_new (&cond);
2286 sb_new (&acc_b);
2287 idx = sb_skip_white (idx, in);
2288
2289 if (in->ptr[idx] == '"')
2290 {
2291 int cond;
2292 int same;
2293 /* This is a string comparision */
2294 idx = getstring (idx, in, &acc_a);
2295 idx = whatcond (idx, in, &cond);
2296 idx = getstring (idx, in, &acc_b);
2297 same = acc_a.len == acc_b.len && (strncmp (acc_a.ptr, acc_b.ptr, acc_a.len) == 0);
2298
2299 if (cond != EQ && cond != NE)
2300 {
fa1a86f3 2301 ERROR ((stderr, "Comparison operator for strings must be EQ or NE\n"));
b0f2092b
SC
2302 res = 0;
2303 }
2304 else
2305 res = cond == EQ && same;
2306 }
2307 else
2308 /* This is a numeric expression */
2309 {
2310 int vala;
2311 int valb;
2312 int cond;
2313 idx = exp_get_abs ("Conditional operator must have absolute operands.\n", idx, in, &vala);
2314 idx = whatcond (idx, in, &cond);
2315 idx = sb_skip_white (idx, in);
2316 if (in->ptr[idx] == '"')
2317 {
2318 WARNING ((stderr, "String compared against expression.\n"));
2319 res = 0;
2320 }
2321 else
2322 {
2323 idx = exp_get_abs ("Conditional operator must have absolute operands.\n", idx, in, &valb);
2324 switch (cond)
2325 {
2326 case EQ:
2327 res = vala == valb;
2328 break;
2329 case NE:
2330 res = vala != valb;
2331 break;
2332 case LT:
2333 res = vala < valb;
2334 break;
2335 case LE:
2336 res = vala <= valb;
2337 break;
2338 case GT:
2339 res = vala > valb;
2340 break;
2341 case GE:
2342 res = vala >= valb;
2343 break;
2344 case NEVER:
2345 res = 0;
2346 break;
2347 }
2348 }
2349 }
2350
2351 sb_kill (&acc_a);
2352 sb_kill (&cond);
2353 sb_kill (&acc_b);
2354 return res;
2355}
2356
2357/* .AIF */
2358static void
2359do_aif (idx, in)
2360 int idx;
2361 sb *in;
2362{
2363 if (ifi >= IFNESTING)
2364 {
2365 FATAL ((stderr, "AIF nesting unreasonable.\n"));
2366 }
2367 ifi++;
2368 ifstack[ifi].on = istrue (idx, in);
2369 ifstack[ifi].hadelse = 0;
2370}
2371
2372
2373/* .AELSE */
2374static void
2375do_aelse ()
2376{
2377 ifstack[ifi].on = !ifstack[ifi].on;
2378 if (ifstack[ifi].hadelse)
2379 {
2380 ERROR ((stderr, "Multiple AELSEs in AIF.\n"));
2381 }
2382 ifstack[ifi].hadelse = 1;
2383}
2384
2385
2386/* .AENDI */
2387static void
2388do_aendi ()
2389{
2390 if (ifi != 0)
2391 {
2392 ifi--;
2393 }
2394 else
2395 {
2396 ERROR ((stderr, "AENDI without AIF.\n"));
2397 }
2398}
2399
2400static int
2401condass_on ()
2402{
2403 return ifstack[ifi].on;
2404}
2405
2406
2407/* Read input lines till we get to a TO string.
2408 Increase nesting depth if we geta FROM string.
2409 Put the results into sb at PTR. */
2410
2411static void
2412buffer_and_nest (from, to, ptr)
2413 char *from;
2414 char *to;
2415 sb *ptr;
2416{
2417 int from_len = strlen (from);
2418 int to_len = strlen (to);
2419 int depth = 1;
2420 int line_start = ptr->len;
2421 int line = linecount ();
2422
2423 int more = get_line (ptr);
2424
2425 while (more)
2426 {
2427 /* Try and find the first pseudo op on the line */
2428 int i = line_start;
2429
fa1a86f3
SC
2430 if (!alternate)
2431 {
2432 /* With normal syntax we can suck what we want till we get to the dot.
2433 With the alternate, labels have to start in the first column, since
2434 we cant tell what's a label and whats a pseudoop */
2435
b0f2092b
SC
2436 /* Skip leading whitespace */
2437 while (i < ptr->len
2438 && ISWHITE (ptr->ptr[i]))
2439 i++;
2440
2441 /* Skip over a label */
2442 while (i < ptr->len
2443 && ISNEXTCHAR (ptr->ptr[i]))
2444 i++;
2445
2446 /* And a colon */
2447 if (i < ptr->len
2448 && ptr->ptr[i] == ':')
2449 i++;
2450
fa1a86f3 2451 }
b0f2092b
SC
2452 /* Skip trailing whitespace */
2453 while (i < ptr->len
2454 && ISWHITE (ptr->ptr[i]))
2455 i++;
2456
fa1a86f3
SC
2457 if (i < ptr->len && (ptr->ptr[i] == '.'
2458 || alternate))
b0f2092b 2459 {
fa1a86f3
SC
2460 if (ptr->ptr[i] == '.')
2461 i++;
b0f2092b
SC
2462 if (strncmp (ptr->ptr + i, from, from_len) == 0)
2463 depth++;
2464 if (strncmp (ptr->ptr + i, to, to_len) == 0)
2465 {
2466 depth--;
2467 if (depth == 0)
2468 {
2469 /* Reset the string to not include the ending rune */
2470 ptr->len = line_start;
2471 break;
2472 }
2473 }
2474 }
2475
2476 /* Add a CR to the end and keep running */
2477 sb_add_char (ptr, '\n');
2478 line_start = ptr->len;
2479 more = get_line (ptr);
2480 }
2481
2482
2483 if (depth)
2484 FATAL ((stderr, "End of file whilst inside %s, started on line %d.\n", from, line));
2485}
2486
2487
2488/* .ENDR */
2489void
2490do_aendr ()
2491{
2492 ERROR ((stderr, "AENDR without a AREPEAT.\n"));
2493}
2494
2495/* .AWHILE */
2496
2497static
2498void
2499do_awhile (idx, in)
2500 int idx;
2501 sb *in;
2502{
2503 sb exp;
2504
2505 sb sub;
2506
2507 int doit;
2508 sb_new (&sub);
2509 sb_new (&exp);
2510
2511 process_assigns (idx, in, &exp);
2512 doit = istrue (0, &exp);
2513
fa1a86f3 2514 buffer_and_nest ("AWHILE", "AENDW", &sub);
b0f2092b
SC
2515
2516 /* Turn
2517 .AWHILE exp
2518 foo
2519 .AENDW
2520 into
2521 foo
2522 .AWHILE exp
2523 foo
2524 .ENDW
2525 */
2526
2527 if (doit)
2528 {
2529 int index = include_next_index ();
2530
2531 sb copy;
2532 sb_new (&copy);
2533 sb_add_sb (&copy, &sub);
2534 sb_add_sb (&copy, in);
2535 sb_add_string (&copy, "\n");
2536 sb_add_sb (&copy, &sub);
2537 sb_add_string (&copy, "\t.AENDW\n");
2538 /* Push another WHILE */
2539 include_buf (&exp, &copy, include_while, index);
2540 sb_kill (&copy);
2541 }
2542 sb_kill (&exp);
2543 sb_kill (&sub);
2544}
2545
2546
2547/* .AENDW */
2548
2549static void
2550do_aendw ()
2551{
2552 ERROR ((stderr, "AENDW without a AENDW.\n"));
2553}
2554
2555
2556/* .EXITM
2557
2558 Pop things off the include stack until the type and index changes */
2559
2560static void
2561do_exitm ()
2562{
2563 include_type type = sp->type;
2564 if (type == include_repeat
2565 || type == include_while
2566 || type == include_macro)
2567 {
2568 int index = sp->index;
2569 include_pop ();
2570 while (sp->index == index
2571 && sp->type == type)
2572 {
2573 include_pop ();
2574 }
2575 }
2576}
2577
2578/* .AREPEAT */
2579
2580static void
2581do_arepeat (idx, in)
2582 int idx;
2583 sb *in;
2584{
2585 sb exp; /* buffer with expression in it */
2586 sb copy; /* expanded repeat block */
2587 sb sub; /* contents of AREPEAT */
2588 int rc;
2589 char buffer[30];
2590 sb_new (&exp);
2591 sb_new (&copy);
2592 sb_new (&sub);
2593 process_assigns (idx, in, &exp);
2594 idx = exp_get_abs ("AREPEAT must have absolute operand.\n", 0, &exp, &rc);
fa1a86f3 2595 buffer_and_nest ("AREPEAT", "AENDR", &sub);
b0f2092b
SC
2596 if (rc > 0)
2597 {
2598 /* Push back the text following the repeat, and another repeat block
2599 so
2600 .AREPEAT 20
2601 foo
2602 .AENDR
2603 gets turned into
2604 foo
2605 .AREPEAT 19
2606 foo
2607 .AENDR
2608 */
2609 int index = include_next_index ();
2610 sb_add_sb (&copy, &sub);
2611 if (rc > 1)
2612 {
2613 sprintf (buffer, "\t.AREPEAT %d\n", rc - 1);
2614 sb_add_string (&copy, buffer);
2615 sb_add_sb (&copy, &sub);
2616 sb_add_string (&copy, " .AENDR\n");
2617 }
2618
2619 include_buf (&exp, &copy, include_repeat, index);
2620 }
2621 sb_kill (&exp);
2622 sb_kill (&sub);
2623 sb_kill (&copy);
2624}
2625
2626/* .ENDM */
2627
2628static void
2629do_endm ()
2630{
2631 ERROR ((stderr, ".ENDM without a matching .MACRO.\n"));
2632}
2633
2634
2635/* MARRO PROCESSING */
2636
2637static int number;
2638hash_table macro_table;
2639
2640/* Understand
2641
2642 .MACRO <name>
2643 stuff
2644 .ENDM
2645*/
2646
2647static int
2648do_formals (macro, idx, in)
2649 macro_entry *macro;
2650 int idx;
2651 sb *in;
2652{
2653 formal_entry **p = &macro->formals;
2654 macro->formal_count = 0;
2655 hash_new_table (5, &macro->formal_hash);
2656 while (idx < in->len)
2657 {
2658 formal_entry *formal;
2659
2660 formal = (formal_entry *) xmalloc (sizeof (formal_entry));
2661
2662 sb_new (&formal->name);
2663 sb_new (&formal->def);
2664 sb_new (&formal->actual);
2665
2666 idx = sb_skip_white (idx, in);
2667 idx = get_token (idx, in, &formal->name);
2668 if (formal->name.len == 0)
2669 break;
2670 idx = sb_skip_white (idx, in);
2671 if (formal->name.len)
2672 {
2673 /* This is a formal */
2674 if (idx < in->len && in->ptr[idx] == '=')
2675 {
2676 /* Got a default */
2677 idx = get_any_string (idx + 1, in, &formal->def);
2678 }
2679 }
2680
2681 {
2682 /* Add to macro's hash table */
2683
2684 hash_entry *p = hash_create (&macro->formal_hash, &formal->name);
2685 p->type = hash_formal;
2686 p->value.f = formal;
2687 }
2688
2689 formal->index = macro->formal_count;
2690 idx = sb_skip_comma (idx, in);
2691 macro->formal_count++;
2692 *p = formal;
2693 p = &formal->next;
2694 }
2695 return idx;
2696}
2697
fa1a86f3
SC
2698/* Parse off LOCAL n1, n2,... Invent a label name for it */
2699static
2700void
2701do_local (idx, line)
2702 int idx;
2703 sb *line;
2704{
2705 static int ln;
2706 sb acc;
2707 sb sub;
2708 char subs[10];
2709 sb_new (&acc);
2710 sb_new (&sub);
2711 idx = sb_skip_white (idx, line);
2712 while (!eol(idx, line))
2713 {
2714 sb_reset (&acc);
2715 sb_reset (&sub);
2716 ln++;
2717 sprintf(subs, "LL%04x", ln);
2718 idx = get_token(idx, line, &acc);
2719 sb_add_string (&sub, subs);
2720 hash_add_to_string_table (&assign_hash_table, &acc, &sub, 1);
2721 idx = sb_skip_comma (idx, line);
2722 }
2723 sb_kill (&sub);
2724 sb_kill (&acc);
2725}
2726
b0f2092b
SC
2727static
2728void
2729do_macro (idx, in)
2730 int idx;
2731 sb *in;
2732{
2733 macro_entry *macro;
2734 sb name;
2735
2736 macro = (macro_entry *) xmalloc (sizeof (macro_entry));
2737 sb_new (&macro->sub);
2738 sb_new (&name);
2739
2740 macro->formal_count = 0;
2741 macro->formals = 0;
2742
2743 idx = sb_skip_white (idx, in);
fa1a86f3 2744 buffer_and_nest ("MACRO", "ENDM", &macro->sub);
b0f2092b
SC
2745 if (label.len)
2746 {
fa1a86f3 2747
b0f2092b
SC
2748 sb_add_sb (&name, &label);
2749 if (in->ptr[idx] == '(')
2750 {
fa1a86f3 2751 /* It's the label: MACRO (formals,...) sort */
b0f2092b
SC
2752 idx = do_formals (macro, idx + 1, in);
2753 if (in->ptr[idx] != ')')
2754 ERROR ((stderr, "Missing ) after formals.\n"));
2755 }
fa1a86f3
SC
2756 else {
2757 /* It's the label: MACRO formals,... sort */
2758 idx = do_formals (macro, idx, in);
2759 }
b0f2092b
SC
2760 }
2761 else
2762 {
2763 idx = get_token (idx, in, &name);
2764 idx = sb_skip_white (idx, in);
2765 idx = do_formals (macro, idx, in);
2766 }
2767
2768 /* and stick it in the macro hash table */
2769 hash_create (&macro_table, &name)->value.m = macro;
2770}
2771
2772static
2773int
2774get_token (idx, in, name)
2775 int idx;
2776 sb *in;
2777 sb *name;
2778{
2779 if (idx < in->len
2780 && ISFIRSTCHAR (in->ptr[idx]))
2781 {
2782 sb_add_char (name, in->ptr[idx++]);
2783 while (idx < in->len
2784 && ISNEXTCHAR (in->ptr[idx]))
2785 {
2786 sb_add_char (name, in->ptr[idx++]);
2787 }
2788 }
2789 return idx;
2790}
2791
2792/* Scan a token, but stop if a ' is seen */
2793static int
2794get_apost_token (idx, in, name, kind)
2795 int idx;
2796 sb *in;
2797 sb *name;
2798 int kind;
2799{
2800 idx = get_token (idx, in, name);
2801 if (idx < in->len && in->ptr[idx] == kind)
2802 idx++;
2803 return idx;
2804}
2805
2806static int
fa1a86f3 2807sub_actual (src, in, t, m, kind, out, copyifnotthere)
b0f2092b
SC
2808 int src;
2809 sb *in;
2810 sb *t;
2811 macro_entry *m;
2812 int kind;
2813 sb *out;
fa1a86f3 2814 int copyifnotthere;
b0f2092b
SC
2815{
2816 /* This is something to take care of */
2817 hash_entry *ptr;
2818 src = get_apost_token (src, in, t, kind);
2819 /* See if it's in the macro's hash table */
2820 ptr = hash_lookup (&m->formal_hash, t);
2821 if (ptr)
2822 {
2823 if (ptr->value.f->actual.len)
2824 {
2825 sb_add_sb (out, &ptr->value.f->actual);
2826 }
2827 else
2828 {
2829 sb_add_sb (out, &ptr->value.f->def);
2830 }
2831 }
fa1a86f3
SC
2832 else if (copyifnotthere)
2833 {
2834 sb_add_sb (out, t);
2835 }
2836 else
b0f2092b
SC
2837 {
2838 sb_add_char (out, '\\');
2839 sb_add_sb (out, t);
2840 }
2841 return src;
2842}
2843
2844static
2845void
2846macro_expand (name, idx, in, m)
2847 sb *name;
2848 int idx;
2849 sb *in;
2850 macro_entry *m;
2851{
2852 sb t;
2853 sb out;
2854 hash_entry *ptr;
2855 formal_entry *f;
b0f2092b
SC
2856 int is_positional = 0;
2857 int is_keyword = 0;
2858
2859 sb_new (&t);
2860 sb_new (&out);
2861
2862 /* Reset any old value the actuals may have */
2863 for (f = m->formals; f; f = f->next)
2864 sb_reset (&f->actual);
2865 f = m->formals;
2866 /* Peel off the actuals and store them away in the hash tables' actuals */
fa1a86f3 2867 while (!eol(idx, in))
b0f2092b
SC
2868 {
2869 int scan;
2870 idx = sb_skip_white (idx, in);
2871 /* Look and see if it's a positional or keyword arg */
2872 scan = idx;
2873 while (scan < in->len
2874 && !ISSEP (in->ptr[scan])
2875 && in->ptr[scan] != '=')
2876 scan++;
2877 if (scan < in->len && in->ptr[scan] == '=')
2878 {
2879 is_keyword = 1;
2880 if (is_positional)
2881 {
2882 ERROR ((stderr, "Can't mix positional and keyword arguments.\n"));
2883 return;
2884 }
2885 /* This is a keyword arg, fetch the formal name and
2886 then the actual stuff */
2887 sb_reset (&t);
2888 idx = get_token (idx, in, &t);
2889 if (in->ptr[idx] != '=')
2890 ERROR ((stderr, "confused about formal params.\n"));
2891
2892 /* Lookup the formal in the macro's list */
2893 ptr = hash_lookup (&m->formal_hash, &t);
2894 if (!ptr)
2895 {
2896 ERROR ((stderr, "MACRO formal argument %s does not exist.\n", sb_name (&t)));
2897 return;
2898 }
2899 else
2900 {
2901 /* Insert this value into the right place */
2902 sb_reset (&ptr->value.f->actual);
2903 idx = get_any_string (idx + 1, in, &ptr->value.f->actual);
2904 }
2905 }
2906 else
2907 {
2908 /* This is a positional arg */
2909 is_positional = 1;
2910 if (is_keyword)
2911 {
2912 ERROR ((stderr, "Can't mix positional and keyword arguments.\n"));
2913 return;
2914 }
2915 if (!f)
2916 {
2917 ERROR ((stderr, "Too many positional arguments.\n"));
2918 return;
2919 }
2920
2921 sb_reset (&f->actual);
2922 idx = get_any_string (idx, in, &f->actual);
2923 f = f->next;
2924 }
2925 idx = sb_skip_comma (idx, in);
2926 }
2927
2928 /* Copy the stuff from the macro buffer into a safe place and substitute any args */
2929
2930 {
2931 int src = 0;
fa1a86f3 2932 int inquote = 0;
b0f2092b
SC
2933 sb *in = &m->sub;
2934 sb_reset (&out);
2935
2936 while (src < in->len)
2937 {
2938 if (in->ptr[src] == '&')
2939 {
2940 sb_reset (&t);
fa1a86f3 2941 src = sub_actual (src + 1, in, &t, m, '&', &out, 0);
b0f2092b
SC
2942 }
2943 else if (in->ptr[src] == '\\')
2944 {
2945 src++;
fa1a86f3 2946 if (in->ptr[src] == comment_char)
b0f2092b
SC
2947 {
2948 /* This is a comment, just drop the rest of the line */
2949 while (src < in->len
2950 && in->ptr[src] != '\n')
2951 src++;
2952
2953 }
2954 else if (in->ptr[src] == '(')
2955 {
2956 /* Sub in till the next ')' literally */
2957 src++;
2958 while (src < in->len && in->ptr[src] != ')')
2959 {
2960 sb_add_char (&out, in->ptr[src++]);
2961 }
2962 if (in->ptr[src] == ')')
2963 src++;
2964 else
2965 ERROR ((stderr, "Missplaced ).\n"));
2966 }
2967 else if (in->ptr[src] == '@')
2968 {
2969 /* Sub in the macro invocation number */
2970
2971 char buffer[6];
2972 src++;
2973 sprintf (buffer, "%05d", number);
2974 sb_add_string (&out, buffer);
2975 }
2976 else if (in->ptr[src] == '&')
2977 {
2978 /* This is a preprocessor variable name, we don't do them
2979 here */
2980 sb_add_char (&out, '\\');
2981 sb_add_char (&out, '&');
2982 src++;
2983 }
2984 else
2985 {
2986 sb_reset (&t);
fa1a86f3 2987 src = sub_actual (src, in, &t, m, '\'', &out, 0);
b0f2092b
SC
2988 }
2989 }
fa1a86f3
SC
2990 else if (ISFIRSTCHAR (in->ptr[src]) && alternate)
2991 {
2992 sb_reset (&t);
2993 src = sub_actual (src, in, &t, m, '\'', &out, 1);
2994 }
2995 else if (ISCOMMENTCHAR (in->ptr[src])
2996 && src + 1 < in->len
2997 && ISCOMMENTCHAR (in->ptr[src+1])
2998 && !inquote)
2999 {
3000 /* Two comment chars in a row cause the rest of the line to be dropped */
3001 while (src < in->len && in->ptr[src] != '\n')
3002 src++;
3003 }
3004 else if (in->ptr[src] == '"')
3005 {
3006 inquote = !inquote;
3007 sb_add_char (&out, in->ptr[src++]);
3008 }
b0f2092b
SC
3009 else
3010 {
3011 sb_add_char (&out, in->ptr[src++]);
3012 }
3013 }
3014 include_buf (name, &out, include_macro, include_next_index ());
3015 }
3016 sb_kill (&t);
3017 sb_kill (&out);
3018 number++;
3019}
3020
3021static int
3022macro_op (idx, in)
3023 int idx;
3024 sb *in;
3025{
3026 int res = 0;
3027 /* The macro name must be the first thing on the line */
3028 if (idx < in->len)
3029 {
3030 sb name;
3031 hash_entry *ptr;
3032 sb_new (&name);
3033 idx = get_token (idx, in, &name);
3034
3035 if (name.len)
3036 {
3037 /* Got a name, look it up */
3038
3039 ptr = hash_lookup (&macro_table, &name);
3040
3041 if (ptr)
3042 {
3043 /* It's in the table, copy out the stuff and convert any macro args */
3044 macro_expand (&name, idx, in, ptr->value.m);
3045 res = 1;
3046 }
3047 }
3048 sb_kill (&name);
3049 }
3050
3051
3052 return res;
3053}
3054
3055
3056/* STRING HANDLING */
3057
3058static int
3059getstring (idx, in, acc)
3060 int idx;
3061 sb *in;
3062 sb *acc;
3063{
3064 idx = sb_skip_white (idx, in);
3065
3066 while (idx < in->len
fa1a86f3
SC
3067 && (in->ptr[idx] == '"'
3068 || in->ptr[idx] == '<'
3069 || (in->ptr[idx] == '\'' && alternate)))
b0f2092b
SC
3070 {
3071 if (in->ptr[idx] == '<')
3072 {
fa1a86f3
SC
3073 if (alternate)
3074 {
3075 int nest = 0;
3076 idx++;
3077 while ((in->ptr[idx] != '>' || nest)
3078 && idx < in->len)
3079 {
3080 if (in->ptr[idx] == '!')
3081 {
3082 idx++ ;
3083 sb_add_char (acc, in->ptr[idx++]);
3084 }
3085 else {
3086 if (in->ptr[idx] == '>')
3087 nest--;
3088 if (in->ptr[idx] == '<')
3089 nest++;
3090 sb_add_char (acc, in->ptr[idx++]);
3091 }
3092 }
3093 idx++;
3094 }
3095 else {
3096 int code;
3097 idx++;
3098 idx = exp_get_abs ("Character code in string must be absolute expression.\n",
3099 idx, in, &code);
3100 sb_add_char (acc, code);
3101
3102 if (in->ptr[idx] != '>')
3103 ERROR ((stderr, "Missing > for character code.\n"));
3104 idx++;
3105 }
b0f2092b 3106 }
fa1a86f3 3107 else if (in->ptr[idx] == '"' || in->ptr[idx] == '\'')
b0f2092b 3108 {
fa1a86f3 3109 char tchar = in->ptr[idx];
b0f2092b
SC
3110 idx++;
3111 while (idx < in->len)
3112 {
fa1a86f3 3113 if (alternate && in->ptr[idx] == '!')
b0f2092b 3114 {
fa1a86f3
SC
3115 idx++ ;
3116 sb_add_char (acc, in->ptr[idx++]);
b0f2092b 3117 }
fa1a86f3
SC
3118 else {
3119 if (in->ptr[idx] == tchar)
3120 {
3121 idx++;
3122 if (idx >= in->len || in->ptr[idx] != tchar)
3123 break;
3124 }
3125 sb_add_char (acc, in->ptr[idx]);
3126 idx++;
3127 }
b0f2092b
SC
3128 }
3129 }
3130 }
fa1a86f3 3131
b0f2092b
SC
3132 return idx;
3133}
3134
3135/* .SDATA[C|Z] <string> */
3136
3137static
3138void
3139do_sdata (idx, in, type)
3140 int idx;
3141 sb *in;
3142 char type;
3143{
3144 int nc = 0;
fa1a86f3 3145 int pidx = -1;
b0f2092b
SC
3146 sb acc;
3147 sb_new (&acc);
3148 fprintf (outfile, ".byte\t");
3149
fa1a86f3 3150 while (!eol (idx, in))
b0f2092b
SC
3151 {
3152 int i;
3153 sb_reset (&acc);
3154 idx = sb_skip_white (idx, in);
fa1a86f3 3155 while (!eol (idx, in))
b0f2092b 3156 {
fa1a86f3 3157 pidx = idx = get_any_string (idx, in, &acc);
b0f2092b
SC
3158 if (type == 'c')
3159 {
3160 if (acc.len > 255)
3161 {
3162 ERROR ((stderr, "string for SDATAC longer than 255 characters (%d).\n", acc.len));
3163 }
3164 fprintf (outfile, "%d", acc.len);
3165 nc = 1;
3166 }
3167
3168 for (i = 0; i < acc.len; i++)
3169 {
3170 if (nc)
3171 {
3172 fprintf (outfile, ",");
3173 }
3174 fprintf (outfile, "%d", acc.ptr[i]);
3175 nc = 1;
3176 }
3177
3178 if (type == 'z')
3179 {
3180 if (nc)
3181 fprintf (outfile, ",");
3182 fprintf (outfile, "0");
3183 }
fa1a86f3
SC
3184 idx = sb_skip_comma (idx, in);
3185 if (idx == pidx) break;
b0f2092b 3186 }
fa1a86f3 3187 if (!alternate && in->ptr[idx] != ',' && idx != in->len)
b0f2092b
SC
3188 {
3189 fprintf (outfile, "\n");
3190 ERROR ((stderr, "illegal character in SDATA line (0x%x).\n", in->ptr[idx]));
3191 break;
3192 }
3193 idx++;
3194 }
3195 sb_kill (&acc);
3196 fprintf (outfile, "\n");
3197}
3198
3199/* .SDATAB <count> <string> */
3200
3201static void
3202do_sdatab (idx, in)
3203 int idx;
3204 sb *in;
3205{
3206 int repeat;
3207 int i;
3208 sb acc;
3209 sb_new (&acc);
3210
3211 idx = exp_get_abs ("Must have absolute SDATAB repeat count.\n", idx, in, &repeat);
3212 if (repeat <= 0)
3213 {
3214 ERROR ((stderr, "Must have positive SDATAB repeat count (%d).\n", repeat));
3215 repeat = 1;
3216 }
3217
3218 idx = sb_skip_comma (idx, in);
3219 idx = getstring (idx, in, &acc);
3220
3221 for (i = 0; i < repeat; i++)
3222 {
3223 if (i)
3224 fprintf (outfile, "\t");
3225 fprintf (outfile, ".byte\t");
3226 sb_print (&acc);
3227 fprintf (outfile, "\n");
3228 }
3229 sb_kill (&acc);
3230
3231}
3232
3233int
3234new_file (name)
3235 char *name;
3236{
3237 FILE *newone = fopen (name, "r");
3238 if (!newone)
3239 return 0;
3240
3241 if (isp == MAX_INCLUDES)
3242 FATAL ((stderr, "Unreasonable include depth (%d).\n", isp));
3243
3244 sp++;
3245 sp->handle = newone;
3246
3247 sb_new (&sp->name);
3248 sb_add_string (&sp->name, name);
3249
3250 sp->linecount = 1;
3251 sp->pushback_index = 0;
3252 sp->type = include_file;
3253 sp->index = 0;
3254 sb_new (&sp->pushback);
3255 return 1;
3256}
3257
3258static void
3259do_include (idx, in)
3260 int idx;
3261 sb *in;
3262{
3263 sb t;
3264 char *text;
3265 sb_new (&t);
3266 idx = getstring (idx, in, &t);
3267 text = sb_name (&t);
3268 if (!new_file (text))
3269 {
3270 FATAL ((stderr, "Can't open include file `%s'.\n", text));
3271 }
3272 sb_kill (&t);
3273}
3274
3275static void
3276include_pop ()
3277{
3278 if (sp != include_stack)
3279 {
3280 if (sp->handle)
3281 fclose (sp->handle);
3282 sp--;
3283 }
3284}
3285
3286/* Get the next character from the include stack. If there's anything
3287 in the pushback buffer, take that first. If we're at eof, pop from
3288 the stack and try again. Keep the linecount up to date. */
3289
3290static int
3291get ()
3292{
3293 int r;
3294
3295 if (sp->pushback.len != sp->pushback_index)
3296 {
3297 r = (char) (sp->pushback.ptr[sp->pushback_index++]);
3298 /* When they've all gone, reset the pointer */
3299 if (sp->pushback_index == sp->pushback.len)
3300 {
3301 sp->pushback.len = 0;
3302 sp->pushback_index = 0;
3303 }
3304 }
3305 else if (sp->handle)
3306 {
3307 r = getc (sp->handle);
3308 }
3309 else
3310 r = EOF;
3311
3312 if (r == EOF && isp)
3313 {
3314 include_pop ();
3315 r = get ();
3316 while (r == EOF && isp)
3317 {
3318 include_pop ();
3319 r = get ();
3320 }
3321 return r;
3322 }
3323 if (r == '\n')
3324 {
3325 sp->linecount++;
3326 }
3327
3328 return r;
3329}
3330
3331static int
3332linecount ()
3333{
3334 return sp->linecount;
3335}
3336
3337static int
3338include_next_index ()
3339{
3340 static int index;
3341 if (!unreasonable
3342 && index > MAX_REASONABLE)
3343 FATAL ((stderr, "Unreasonable expansion (-u turns off check).\n"));
3344 return ++index;
3345}
3346
3347
3348/* Initialize the chartype vector. */
3349
3350static void
3351chartype_init ()
3352{
3353 int x;
3354 for (x = 0; x < 256; x++)
3355 {
3356 if (isalpha (x) || x == '_' || x == '$')
3357 chartype[x] |= FIRSTBIT;
3358
3359 if (isdigit (x) || isalpha (x) || x == '_' || x == '$')
3360 chartype[x] |= NEXTBIT;
3361
3362 if (x == ' ' || x == '\t' || x == ',' || x == '"' || x == ';'
3363 || x == '"' || x == '<' || x == '>' || x == ')' || x == '(')
3364 chartype[x] |= SEPBIT;
3365
3366 if (x == ' ' || x == '\t')
3367 chartype[x] |= WHITEBIT;
fa1a86f3
SC
3368
3369 if (x == comment_char)
3370 chartype[x] |= COMMENTBIT;
b0f2092b
SC
3371 }
3372}
3373
3374
fa1a86f3 3375
b0f2092b
SC
3376/* What to do with all the keywords */
3377#define PROCESS 0x1000 /* Run substitution over the line */
3378#define LAB 0x2000 /* Spit out the label */
3379
3380#define K_EQU PROCESS|1
3381#define K_ASSIGN PROCESS|2
3382#define K_REG PROCESS|3
3383#define K_ORG PROCESS|4
3384#define K_RADIX PROCESS|5
3385#define K_DATA LAB|PROCESS|6
3386#define K_DATAB LAB|PROCESS|7
3387#define K_SDATA LAB|PROCESS|8
3388#define K_SDATAB LAB|PROCESS|9
3389#define K_SDATAC LAB|PROCESS|10
3390#define K_SDATAZ LAB|PROCESS|11
3391#define K_RES LAB|PROCESS|12
3392#define K_SRES LAB|PROCESS|13
3393#define K_SRESC LAB|PROCESS|14
3394#define K_SRESZ LAB|PROCESS|15
3395#define K_EXPORT LAB|PROCESS|16
3396#define K_GLOBAL LAB|PROCESS|17
3397#define K_PRINT LAB|PROCESS|19
3398#define K_FORM LAB|PROCESS|20
3399#define K_HEADING LAB|PROCESS|21
3400#define K_PAGE LAB|PROCESS|22
3401#define K_IMPORT LAB|PROCESS|23
3402#define K_PROGRAM LAB|PROCESS|24
3403#define K_END PROCESS|25
3404#define K_INCLUDE PROCESS|26
3405#define K_IGNORED PROCESS|27
fa1a86f3 3406#define K_ASSIGNA PROCESS|28
b0f2092b
SC
3407#define K_ASSIGNC 29
3408#define K_AIF PROCESS|30
3409#define K_AELSE PROCESS|31
3410#define K_AENDI PROCESS|32
3411#define K_AREPEAT PROCESS|33
3412#define K_AENDR PROCESS|34
3413#define K_AWHILE 35
3414#define K_AENDW PROCESS|36
3415#define K_EXITM 37
3416#define K_MACRO PROCESS|38
3417#define K_ENDM 39
3418#define K_ALIGN PROCESS|LAB|40
fa1a86f3
SC
3419#define K_ALTERNATE 41
3420#define K_DB LAB|PROCESS|42
3421#define K_DW LAB|PROCESS|43
3422#define K_DL LAB|PROCESS|44
3423#define K_LOCAL 45
b0f2092b
SC
3424
3425
3426static struct
3427{
3428 char *name;
3429 int code;
3430 int extra;
3431}
3432kinfo[] =
3433{
950df421 3434 { "EQU", K_EQU, 0 },
fa1a86f3 3435 { "ALTERNATE", K_ALTERNATE, 0 },
950df421
ILT
3436 { "ASSIGN", K_ASSIGN, 0 },
3437 { "REG", K_REG, 0 },
3438 { "ORG", K_ORG, 0 },
3439 { "RADIX", K_RADIX, 0 },
3440 { "DATA", K_DATA, 0 },
fa1a86f3
SC
3441 { "DB", K_DB, 0 },
3442 { "DW", K_DW, 0 },
3443 { "DL", K_DL, 0 },
950df421
ILT
3444 { "DATAB", K_DATAB, 0 },
3445 { "SDATA", K_SDATA, 0 },
3446 { "SDATAB", K_SDATAB, 0 },
3447 { "SDATAZ", K_SDATAZ, 0 },
3448 { "SDATAC", K_SDATAC, 0 },
3449 { "RES", K_RES, 0 },
3450 { "SRES", K_SRES, 0 },
3451 { "SRESC", K_SRESC, 0 },
3452 { "SRESZ", K_SRESZ, 0 },
3453 { "EXPORT", K_EXPORT, 0 },
3454 { "GLOBAL", K_GLOBAL, 0 },
3455 { "PRINT", K_PRINT, 0 },
3456 { "FORM", K_FORM, 0 },
3457 { "HEADING", K_HEADING, 0 },
3458 { "PAGE", K_PAGE, 0 },
3459 { "PROGRAM", K_IGNORED, 0 },
3460 { "END", K_END, 0 },
3461 { "INCLUDE", K_INCLUDE, 0 },
3462 { "ASSIGNA", K_ASSIGNA, 0 },
3463 { "ASSIGNC", K_ASSIGNC, 0 },
3464 { "AIF", K_AIF, 0 },
3465 { "AELSE", K_AELSE, 0 },
3466 { "AENDI", K_AENDI, 0 },
3467 { "AREPEAT", K_AREPEAT, 0 },
3468 { "AENDR", K_AENDR, 0 },
3469 { "EXITM", K_EXITM, 0 },
3470 { "MACRO", K_MACRO, 0 },
3471 { "ENDM", K_ENDM, 0 },
3472 { "AWHILE", K_AWHILE, 0 },
3473 { "ALIGN", K_ALIGN, 0 },
3474 { "AENDW", K_AENDW, 0 },
fa1a86f3
SC
3475 { "ALTERNATE", K_ALTERNATE, 0 },
3476 { "LOCAL", K_LOCAL, 0 },
950df421 3477 { NULL, 0, 0 }
b0f2092b
SC
3478};
3479
3480/* Look for a pseudo op on the line. If one's there then call
3481 its handler. */
3482
3483static int
3484process_pseudo_op (idx, line, acc)
3485 int idx;
3486 sb *line;
3487 sb *acc;
3488{
b0f2092b 3489
fa1a86f3
SC
3490
3491 if (line->ptr[idx] == '.' || alternate)
b0f2092b
SC
3492 {
3493 /* Scan forward and find pseudo name */
fa1a86f3 3494 char *in;
b0f2092b
SC
3495 hash_entry *ptr;
3496
fa1a86f3
SC
3497 char *s;
3498 char *e;
3499 if (line->ptr[idx] == '.')
3500 idx++;
3501 in = line->ptr + idx;
3502 s = in;
3503 e = s;
b0f2092b 3504 sb_reset (acc);
fa1a86f3 3505
b0f2092b
SC
3506 while (idx < line->len && *e && ISFIRSTCHAR (*e))
3507 {
3508 sb_add_char (acc, *e);
3509 e++;
3510 idx++;
3511 }
3512
3513 ptr = hash_lookup (&keyword_hash_table, acc);
3514
3515 if (!ptr)
3516 {
fa1a86f3
SC
3517#if 0
3518 /* This one causes lots of pain when trying to preprocess
3519 ordinary code */
b0f2092b 3520 WARNING ((stderr, "Unrecognised pseudo op `%s'.\n", sb_name (acc)));
fa1a86f3 3521#endif
b0f2092b
SC
3522 return 0;
3523 }
3524 if (ptr->value.i & LAB)
3525 { /* output the label */
3526 if (label.len)
3527 {
3528 fprintf (outfile, "%s:\t", sb_name (&label));
3529 }
3530 else
3531 fprintf (outfile, "\t");
3532 }
3533
3534 if (ptr->value.i & PROCESS)
3535 {
3536 /* Polish the rest of the line before handling the pseudo op */
fa1a86f3
SC
3537#if 0
3538 strip_comments(line);
3539#endif
b0f2092b
SC
3540 sb_reset (acc);
3541 process_assigns (idx, line, acc);
3542 sb_reset(line);
3543 change_base (0, acc, line);
3544 idx = 0;
3545 }
3546 if (!condass_on ())
3547 {
3548 switch (ptr->value.i)
3549 {
3550 case K_AELSE:
3551 do_aelse ();
3552 break;
3553 case K_AENDI:
3554 do_aendi ();
3555 break;
3556 }
3557 return 1;
3558 }
3559 else
3560 {
3561 switch (ptr->value.i)
3562 {
fa1a86f3
SC
3563 case K_ALTERNATE:
3564 alternate = 1;
3565 return 1;
b0f2092b
SC
3566 case K_AELSE:
3567 do_aelse ();
3568 return 1;
3569 case K_AENDI:
3570 do_aendi ();
3571 return 1;
3572 case K_ORG:
3573 ERROR ((stderr, "ORG command not allowed.\n"));
3574 break;
3575 case K_RADIX:
3576 do_radix (line);
3577 return 1;
fa1a86f3
SC
3578 case K_DB:
3579 do_data (idx, line, 1);
3580 return 1;
3581 case K_DW:
3582 do_data (idx, line, 2);
3583 return 1;
3584 case K_DL:
3585 do_data (idx, line, 4);
3586 return 1;
b0f2092b 3587 case K_DATA:
fa1a86f3 3588 do_data (idx, line, 0);
b0f2092b
SC
3589 return 1;
3590 case K_DATAB:
3591 do_datab (idx, line);
3592 return 1;
3593 case K_SDATA:
3594 do_sdata (idx, line, 0);
3595 return 1;
3596 case K_SDATAB:
3597 do_sdatab (idx, line);
3598 return 1;
3599 case K_SDATAC:
3600 do_sdata (idx, line, 'c');
3601 return 1;
3602 case K_SDATAZ:
3603 do_sdata (idx, line, 'z');
3604 return 1;
3605 case K_ASSIGN:
3606 do_assign (1, 0, line);
3607 return 1;
3608 case K_AIF:
3609 do_aif (idx, line);
3610 return 1;
3611 case K_AREPEAT:
3612 do_arepeat (idx, line);
3613 return 1;
3614 case K_AENDW:
3615 do_aendw ();
3616 return 1;
3617 case K_AWHILE:
3618 do_awhile (idx, line);
3619 return 1;
3620 case K_AENDR:
3621 do_aendr ();
3622 return 1;
3623 case K_EQU:
3624 do_assign (0, idx, line);
3625 return 1;
3626 case K_ALIGN:
3627 do_align (idx, line);
3628 return 1;
3629 case K_RES:
3630 do_res (idx, line, 0);
3631 return 1;
3632 case K_SRES:
3633 do_res (idx, line, 's');
3634 return 1;
3635 case K_INCLUDE:
3636 do_include (idx, line);
3637 return 1;
fa1a86f3
SC
3638 case K_LOCAL:
3639 do_local (idx, line);
3640 return 1;
b0f2092b
SC
3641 case K_MACRO:
3642 do_macro (idx, line);
3643 return 1;
3644 case K_ENDM:
3645 do_endm ();
3646 return 1;
3647 case K_SRESC:
3648 do_res (idx, line, 'c');
3649 return 1;
3650 case K_PRINT:
3651 do_print (idx, line);
3652 return 1;
3653 case K_FORM:
3654 do_form (idx, line);
3655 return 1;
3656 case K_HEADING:
3657 do_heading (idx, line);
3658 return 1;
3659 case K_PAGE:
3660 do_page ();
3661 return 1;
3662 case K_GLOBAL:
3663 case K_EXPORT:
3664 do_export (line);
3665 return 1;
3666 case K_IMPORT:
3667 return 1;
3668 case K_SRESZ:
3669 do_res (idx, line, 'z');
3670 return 1;
3671 case K_IGNORED:
3672 return 1;
3673 case K_END:
3674 do_end ();
3675 return 1;
3676 case K_ASSIGNA:
3677 do_assigna (idx, line);
3678 return 1;
3679 case K_ASSIGNC:
3680 do_assignc (idx, line);
3681 return 1;
3682 case K_EXITM:
3683 do_exitm ();
3684 return 1;
3685 case K_REG:
3686 do_reg (idx, line);
3687 return 1;
3688 }
3689 }
3690 }
3691 return 0;
3692}
3693
3694
3695
3696/* Build the keyword hash table - put each keyword in the table twice,
3697 once upper and once lower case.*/
3698
3699static void
3700process_init ()
3701{
3702 int i;
3703
3704 for (i = 0; kinfo[i].name; i++)
3705 {
3706 sb label;
3707 int j;
3708 sb_new (&label);
3709 sb_add_string (&label, kinfo[i].name);
3710
3711 hash_add_to_int_table (&keyword_hash_table, &label, kinfo[i].code);
3712
3713 sb_reset (&label);
3714 for (j = 0; kinfo[i].name[j]; j++)
3715 sb_add_char (&label, kinfo[i].name[j] - 'A' + 'a');
3716 hash_add_to_int_table (&keyword_hash_table, &label, kinfo[i].code);
3717
3718 sb_kill (&label);
3719 }
3720}
3721
fa1a86f3
SC
3722
3723static void
3724do_define (string)
3725char *string;
3726{
3727 sb label;
3728 int res = 1;
3729 hash_entry *ptr;
3730 sb_new (&label);
3731
3732
3733 while (*string)
3734 {
3735 if (*string == '=')
3736 {
3737 sb value;
3738 sb_new (&value);
3739 string++;
3740 while (*string)
3741 {
3742 sb_add_char (&value, *string);
3743 string++;
3744 }
3745 exp_get_abs ("Invalid expression on command line.\n", 0, &value, &res);
3746 sb_kill (&value);
3747 break;
3748 }
3749 sb_add_char (&label, *string);
3750
3751 string ++;
3752 }
3753
3754 ptr = hash_create (&vars, &label);
3755 free_old_entry (ptr);
3756 ptr->type = hash_integer;
3757 ptr->value.i = res;
3758 sb_kill (&label);
3759}
3760char *program_name;
3761
3762/* The list of long options. */
3763static struct option long_options[] =
3764{
3765 { "alternate", no_argument, 0, 'a' },
3766 { "commentchar", required_argument, 0, 'c' },
3767 { "copysource", no_argument, 0, 's' },
3768 { "debug", no_argument, 0, 'd' },
3769 { "help", no_argument, 0, 'h' },
3770 { "output", required_argument, 0, 'o' },
3771 { "print", no_argument, 0, 'p' },
3772 { "unreasonable", no_argument, 0, 'u' },
3773 { "version", no_argument, 0, 'v' },
3774 { "define", required_argument, 0, 'd' },
3775 { NULL, no_argument, 0, 0 }
3776};
3777
3778/* Show a usage message and exit. */
3779static void
3780show_usage (file, status)
3781 FILE *file;
3782 int status;
3783{
3784 fprintf (file, "\
3785Usage: %s \n\
3786 [-a] [--alternate] enter alternate macro mode\n\
3787 [-c char] [--commentchar char] change the comment character from !\n\
3788 [-d] [--debug] print some debugging info\n\
3789 [-h] [--help] print this message\n\
3790 [-o out] [--output out] set the output file\n\
3791 [-p] [--print] print line numbers\n\
3792 [-s] [--copysource] copy source through as comments \n\
3793 [-u] [--unreasonable] allow unreasonable nesting\n\
3794 [-v] [--version] print the program version\n\
3795 [-Dname=value] create preprocessor variable called name, with value\n\
3796 [in-file]\n", program_name);
3797 exit (status);
3798}
3799
3800/* Display a help message and exit. */
3801static void
3802show_help ()
3803{
3804 printf ("%s: Gnu Assembler Macro Preprocessor\n",
3805 program_name);
3806 show_usage (stdout, 0);
3807}
3808
b0f2092b 3809int
fa1a86f3
SC
3810main (argc, argv)
3811 int argc;
3812 char **argv;
b0f2092b 3813{
fa1a86f3
SC
3814 int opt;
3815 char *out_name = 0;
b0f2092b
SC
3816 sp = include_stack;
3817
3818 ifstack[0].on = 1;
3819 ifi = 0;
3820
fa1a86f3
SC
3821
3822
3823 program_name = argv[0];
3824 xmalloc_set_program_name (program_name);
b0f2092b
SC
3825
3826 hash_new_table (101, &macro_table);
3827 hash_new_table (101, &keyword_hash_table);
3828 hash_new_table (101, &assign_hash_table);
3829 hash_new_table (101, &vars);
3830
3831 sb_new (&label);
3832 process_init ();
3833
fa1a86f3
SC
3834 while ((opt = getopt_long (argc, argv, "sdhavc:upo:D:", long_options,
3835 (int *) NULL))
3836 != EOF)
b0f2092b 3837 {
fa1a86f3 3838 switch (opt)
b0f2092b 3839 {
fa1a86f3
SC
3840 case 'o':
3841 out_name = optarg;
3842 break;
3843 case 'u':
3844 unreasonable = 1;
3845 break;
3846 case 'p':
3847 print_line_number = 1;
3848 break;
3849 case 'c':
3850 comment_char = optarg[0];
3851 break;
3852 case 'a':
3853 alternate = 1;
3854 break;
3855 case 's':
3856 copysource = 1;
3857 break;
3858 case 'd':
3859 stats = 1;
3860 break;
3861 case 'D':
3862 do_define (optarg);
3863 break;
3864 case 'h':
3865 show_help ();
3866 /*NOTREACHED*/
3867 case 'v':
3868 printf ("GNU %s version %s\n", program_name, program_version);
3869 exit (0);
3870 /*NOTREACHED*/
3871 case 0:
3872 break;
3873 default:
3874 show_usage (stderr, 1);
3875 /*NOTREACHED*/
b0f2092b
SC
3876 }
3877 }
3878
fa1a86f3
SC
3879
3880 if (out_name) {
3881 outfile = fopen (out_name, "w");
3882 if (!outfile)
3883 {
3884 fprintf (stderr, "%s: Can't open output file `%s'.\n",
3885 program_name, out_name);
3886 exit (1);
3887 }
3888 }
3889 else {
3890 outfile = stdout;
3891 }
3892
3893 chartype_init ();
b0f2092b
SC
3894 if (!outfile)
3895 outfile = stdout;
3896
3897 /* Process all the input files */
3898
fa1a86f3 3899 while (optind < argc)
b0f2092b 3900 {
fa1a86f3 3901 if (new_file (argv[optind]))
b0f2092b 3902 {
fa1a86f3 3903 process_file ();
b0f2092b
SC
3904 }
3905 else
3906 {
fa1a86f3
SC
3907 fprintf (stderr, "%s: Can't open input file `%s'.\n",
3908 program_name, argv[optind]);
3909 exit (1);
b0f2092b 3910 }
fa1a86f3 3911 optind++;
b0f2092b 3912 }
fa1a86f3 3913
b0f2092b
SC
3914 quit ();
3915 return 0;
3916}
This page took 0.193115 seconds and 4 git commands to generate.