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