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