* xcofflink.c (_bfd_xcoff_bfd_final_link): Call bfd_malloc rather
[deliverable/binutils-gdb.git] / gas / gasp.c
CommitLineData
b0f2092b 1/* gasp.c - Gnu assembler preprocessor main program.
0f68bf0a 2 Copyright (C) 1994, 95, 96, 1997 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)
0f68bf0a 473 ERROR ((stderr, "redefinition not allowed\n"));
b0f2092b 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 {
5ba7c0be
ILT
1106 if (in->ptr[idx] == '\\'
1107 && idx + 1 < in->len
1108 && in->ptr[idx + 1] == '(')
1109 {
1110 idx += 2;
1111 while (idx < in->len
1112 && in->ptr[idx] != ')')
1113 {
1114 sb_add_char (out, in->ptr[idx]);
1115 idx++;
1116 }
1117 if (idx < in->len)
1118 idx++;
1119 }
1120 else if (idx < in->len - 1 && in->ptr[idx + 1] == '\'' && ! mri)
b0f2092b
SC
1121 {
1122 int base;
1123 int value;
1124 switch (in->ptr[idx])
1125 {
1126 case 'b':
1127 case 'B':
1128 base = 2;
1129 break;
1130 case 'q':
1131 case 'Q':
1132 base = 8;
1133 break;
1134 case 'h':
1135 case 'H':
1136 base = 16;
1137 break;
1138 case 'd':
1139 case 'D':
1140 base = 10;
1141 break;
1142 default:
1143 ERROR ((stderr, "Illegal base character %c.\n", in->ptr[idx]));
1144 base = 10;
1145 break;
1146 }
1147
1148 idx = sb_strtol (idx + 2, in, base, &value);
1149 sprintf (buffer, "%d", value);
1150 sb_add_string (out, buffer);
1151 }
1152 else if (ISFIRSTCHAR (in->ptr[idx]))
1153 {
1154 /* copy entire names through quickly */
1155 sb_add_char (out, in->ptr[idx]);
1156 idx++;
1157 while (idx < in->len && ISNEXTCHAR (in->ptr[idx]))
1158 {
1159 sb_add_char (out, in->ptr[idx]);
1160 idx++;
1161 }
1162 }
1163 else if (isdigit (in->ptr[idx]))
1164 {
1165 int value;
1166 /* all numbers must start with a digit, let's chew it and
1167 spit out decimal */
1168 idx = sb_strtol (idx, in, radix, &value);
1169 sprintf (buffer, "%d", value);
1170 sb_add_string (out, buffer);
1171
1172 /* skip all undigsested letters */
1173 while (idx < in->len && ISNEXTCHAR (in->ptr[idx]))
1174 {
1175 sb_add_char (out, in->ptr[idx]);
1176 idx++;
1177 }
1178 }
5f57cea3
SC
1179 else if (in->ptr[idx] == '"' || in->ptr[idx] == '\'')
1180 {
1181 char tchar = in->ptr[idx];
1182 /* copy entire names through quickly */
1183 sb_add_char (out, in->ptr[idx]);
1184 idx++;
1185 while (idx < in->len && in->ptr[idx] != tchar)
1186 {
1187 sb_add_char (out, in->ptr[idx]);
1188 idx++;
1189 }
1190 }
b0f2092b
SC
1191 else
1192 {
1193 /* nothing special, just pass it through */
1194 sb_add_char (out, in->ptr[idx]);
1195 idx++;
1196 }
1197 }
1198
1199}
1200
1201/* .end */
1202static void
7f5adcba
ILT
1203do_end (in)
1204 sb *in;
b0f2092b
SC
1205{
1206 had_end = 1;
7f5adcba
ILT
1207 if (mri)
1208 fprintf (outfile, "%s\n", sb_name (in));
b0f2092b
SC
1209}
1210
1211/* .assign */
1212
1213static void
1214do_assign (again, idx, in)
1215 int again;
1216 int idx;
1217 sb *in;
1218{
1219 /* stick label in symbol table with following value */
1220 exp_t e;
1221 sb acc;
1222
1223 sb_new (&acc);
1224 idx = exp_parse (idx, in, &e);
1225 exp_string (&e, &acc);
1226 hash_add_to_string_table (&assign_hash_table, &label, &acc, again);
1227 sb_kill (&acc);
1228}
1229
1230
1231/* .radix [b|q|d|h] */
1232
1233static
1234void
1235do_radix (ptr)
1236 sb *ptr;
1237{
1238 int idx = sb_skip_white (0, ptr);
1239 switch (ptr->ptr[idx])
1240 {
1241 case 'B':
1242 case 'b':
1243 radix = 2;
1244 break;
1245 case 'q':
1246 case 'Q':
1247 radix = 8;
1248 break;
1249 case 'd':
1250 case 'D':
1251 radix = 10;
1252 break;
1253 case 'h':
1254 case 'H':
1255 radix = 16;
1256 break;
1257 default:
1258 ERROR ((stderr, "radix is %c must be one of b, q, d or h", radix));
1259 }
1260}
1261
1262
1263/* Parse off a .b, .w or .l */
1264
1265static int
1266get_opsize (idx, in, size)
19be7c08
ILT
1267 int idx;
1268 sb *in;
1269 int *size;
b0f2092b
SC
1270{
1271 *size = 4;
1272 if (in->ptr[idx] == '.')
1273 {
1274 idx++;
b0f2092b 1275 }
fa1a86f3
SC
1276 switch (in->ptr[idx])
1277 {
1278 case 'b':
1279 case 'B':
1280 *size = 1;
1281 break;
1282 case 'w':
1283 case 'W':
1284 *size = 2;
1285 break;
1286 case 'l':
1287 case 'L':
1288 *size = 4;
1289 break;
1290 case ' ':
1291 case '\t':
1292 break;
1293 default:
1294 ERROR ((stderr, "size must be one of b, w or l, is %c.\n", in->ptr[idx]));
1295 break;
1296 }
1297 idx++;
1298
b0f2092b
SC
1299 return idx;
1300}
1301
fa1a86f3
SC
1302static
1303int eol(idx, line)
19be7c08
ILT
1304 int idx;
1305 sb *line;
fa1a86f3
SC
1306{
1307 idx = sb_skip_white (idx, line);
1308 if (idx < line->len
1309 && ISCOMMENTCHAR(line->ptr[idx]))
1310 return 1;
1311 if (idx >= line->len)
1312 return 1;
1313 return 0;
1314}
1315
1316/* .data [.b|.w|.l] <data>*
1317 or d[bwl] <data>* */
b0f2092b
SC
1318
1319static void
fa1a86f3 1320do_data (idx, in, size)
b0f2092b
SC
1321 int idx;
1322 sb *in;
fa1a86f3 1323 int size;
b0f2092b
SC
1324{
1325 int opsize = 4;
11618ce8 1326 char *opname = ".yikes!";
b0f2092b
SC
1327 sb acc;
1328 sb_new (&acc);
1329
fa1a86f3
SC
1330 if (!size)
1331 {
1332 idx = get_opsize (idx, in, &opsize);
1333 }
1334 else {
1335 opsize = size;
1336 }
b0f2092b
SC
1337 switch (opsize)
1338 {
1339 case 4:
1340 opname = ".long";
1341 break;
1342 case 2:
1343 opname = ".short";
1344 break;
1345 case 1:
1346 opname = ".byte";
1347 break;
1348 }
1349
fa1a86f3 1350
b0f2092b 1351 fprintf (outfile, "%s\t", opname);
fa1a86f3
SC
1352
1353 idx = sb_skip_white (idx, in);
1354
1355 if (alternate
1356 && idx < in->len
1357 && in->ptr[idx] == '"')
b0f2092b 1358 {
fa1a86f3
SC
1359 int i;
1360 idx = getstring (idx, in, &acc);
1361 for (i = 0; i < acc.len; i++)
b0f2092b 1362 {
fa1a86f3
SC
1363 if (i)
1364 fprintf(outfile,",");
1365 fprintf (outfile, "%d", acc.ptr[i]);
1366 }
1367 }
1368 else
1369 {
1370 while (!eol (idx, in))
1371 {
1372 exp_t e;
1373 idx = exp_parse (idx, in, &e);
1374 exp_string (&e, &acc);
1375 sb_add_char (&acc, 0);
1376 fprintf (outfile, acc.ptr);
1377 if (idx < in->len && in->ptr[idx] == ',')
1378 {
1379 fprintf (outfile, ",");
1380 idx++;
1381 }
b0f2092b
SC
1382 }
1383 }
1384 sb_kill (&acc);
7e047ac2 1385 sb_print_at (outfile, idx, in);
b0f2092b
SC
1386 fprintf (outfile, "\n");
1387}
1388
1389/* .datab [.b|.w|.l] <repeat>,<fill> */
1390
1391static void
1392do_datab (idx, in)
1393 int idx;
1394 sb *in;
1395{
1396 int opsize;
1397 int repeat;
1398 int fill;
1399
1400 idx = get_opsize (idx, in, &opsize);
1401
1402 idx = exp_get_abs ("datab repeat must be constant.\n", idx, in, &repeat);
1403 idx = sb_skip_comma (idx, in);
1404 idx = exp_get_abs ("datab data must be absolute.\n", idx, in, &fill);
1405
1406 fprintf (outfile, ".fill\t%d,%d,%d\n", repeat, opsize, fill);
1407}
1408
1409/* .align <size> */
1410
e15126c4 1411static void
b0f2092b
SC
1412do_align (idx, in)
1413 int idx;
1414 sb *in;
1415{
1ba76615
ILT
1416 int al, have_fill, fill;
1417
b0f2092b 1418 idx = exp_get_abs ("align needs absolute expression.\n", idx, in, &al);
1ba76615
ILT
1419 idx = sb_skip_white (idx, in);
1420 have_fill = 0;
1421 fill = 0;
1422 if (! eol (idx, in))
1423 {
1424 idx = sb_skip_comma (idx, in);
1425 idx = exp_get_abs (".align needs absolute fill value.\n", idx, in,
1426 &fill);
1427 have_fill = 1;
1428 }
b0f2092b
SC
1429
1430 if (al != 1
1431 && al != 2
1432 && al != 4)
1433 WARNING ((stderr, "alignment must be one of 1, 2 or 4.\n"));
1434
1ba76615
ILT
1435 fprintf (outfile, ".align %d", al);
1436 if (have_fill)
1437 fprintf (outfile, ",%d", fill);
1438 fprintf (outfile, "\n");
b0f2092b
SC
1439}
1440
1441/* .res[.b|.w|.l] <size> */
1442
19be7c08 1443static void
b0f2092b
SC
1444do_res (idx, in, type)
1445 int idx;
1446 sb *in;
19be7c08 1447 int type;
b0f2092b
SC
1448{
1449 int size = 4;
1450 int count = 0;
1451
1452 idx = get_opsize (idx, in, &size);
fa1a86f3 1453 while (!eol(idx, in))
b0f2092b
SC
1454 {
1455 idx = sb_skip_white (idx, in);
1456 if (in->ptr[idx] == ',')
1457 idx++;
1458 idx = exp_get_abs ("res needs absolute expression for fill count.\n", idx, in, &count);
1459
1460 if (type == 'c' || type == 'z')
1461 count++;
1462
1463 fprintf (outfile, ".space %d\n", count * size);
1464 }
1465}
1466
1467
1468/* .export */
1469
19be7c08 1470static void
b0f2092b
SC
1471do_export (in)
1472 sb *in;
1473{
1474 fprintf (outfile, ".global %s\n", sb_name (in));
1475}
1476
1477/* .print [list] [nolist] */
1478
19be7c08 1479static void
b0f2092b
SC
1480do_print (idx, in)
1481 int idx;
1482 sb *in;
1483{
1484 idx = sb_skip_white (idx, in);
1485 while (idx < in->len)
1486 {
85b369b3 1487 if (strncasecmp (in->ptr + idx, "LIST", 4) == 0)
b0f2092b
SC
1488 {
1489 fprintf (outfile, ".list\n");
1490 idx += 4;
1491 }
85b369b3 1492 else if (strncasecmp (in->ptr + idx, "NOLIST", 6) == 0)
b0f2092b
SC
1493 {
1494 fprintf (outfile, ".nolist\n");
1495 idx += 6;
1496 }
1497 idx++;
1498 }
1499}
1500
1501/* .head */
19be7c08 1502static void
b0f2092b
SC
1503do_heading (idx, in)
1504 int idx;
1505 sb *in;
1506{
1507 sb head;
1508 sb_new (&head);
1509 idx = getstring (idx, in, &head);
1510 fprintf (outfile, ".title \"%s\"\n", sb_name (&head));
1511 sb_kill (&head);
1512}
1513
1514/* .page */
1515
19be7c08 1516static void
b0f2092b
SC
1517do_page ()
1518{
1519 fprintf (outfile, ".eject\n");
1520}
1521
1522/* .form [lin=<value>] [col=<value>] */
19be7c08 1523static void
b0f2092b
SC
1524do_form (idx, in)
1525 int idx;
1526 sb *in;
1527{
1528 int lines = 60;
1529 int columns = 132;
1530 idx = sb_skip_white (idx, in);
1531
1532 while (idx < in->len)
1533 {
1534
85b369b3 1535 if (strncasecmp (in->ptr + idx, "LIN=", 4) == 0)
b0f2092b
SC
1536 {
1537 idx += 4;
1538 idx = exp_get_abs ("form LIN= needs absolute expresssion.\n", idx, in, &lines);
1539 }
1540
85b369b3 1541 if (strncasecmp (in->ptr + idx, "COL=", 4) == 0)
b0f2092b
SC
1542 {
1543 idx += 4;
1544 idx = exp_get_abs ("form COL= needs absolute expresssion.\n", idx, in, &columns);
1545 }
1546
1547 idx++;
1548 }
1549 fprintf (outfile, ".psize %d,%d\n", lines, columns);
1550
1551}
1552
6f15d409
SC
1553
1554/* Fetch string from the input stream,
1555 rules:
1556 'Bxyx<whitespace> -> return 'Bxyza
1557 %<char> -> return string of decimal value of x
1558 "<string>" -> return string
1559 xyx<whitespace> -> return xyz
1560*/
e15126c4 1561static int
6f15d409 1562get_any_string (idx, in, out, expand, pretend_quoted)
b0f2092b
SC
1563 int idx;
1564 sb *in;
1565 sb *out;
40b559d2 1566 int expand;
6f15d409 1567 int pretend_quoted;
b0f2092b 1568{
fa1a86f3 1569 sb_reset (out);
b0f2092b 1570 idx = sb_skip_white (idx, in);
b0f2092b 1571
fa1a86f3 1572 if (idx < in->len)
b0f2092b 1573 {
13d9fd33
SC
1574 if (in->len > 2 && in->ptr[idx+1] == '\'' && ISBASE (in->ptr[idx]))
1575 {
1576 while (!ISSEP (in->ptr[idx]))
1577 sb_add_char (out, in->ptr[idx++]);
1578 }
1579 else if (in->ptr[idx] == '%'
1580 && alternate
1581 && expand)
fa1a86f3
SC
1582 {
1583 int val;
1584 char buf[20];
1585 /* Turns the next expression into a string */
1586 idx = exp_get_abs ("% operator needs absolute expression",
1587 idx + 1,
1588 in,
1589 &val);
40b559d2 1590 sprintf(buf, "%d", val);
fa1a86f3
SC
1591 sb_add_string (out, buf);
1592 }
13d9fd33
SC
1593 else if (in->ptr[idx] == '"'
1594 || in->ptr[idx] == '<'
1595 || (alternate && in->ptr[idx] == '\''))
fa1a86f3 1596 {
6f15d409 1597 if (alternate && expand)
fa1a86f3
SC
1598 {
1599 /* Keep the quotes */
19be7c08 1600 sb_add_char (out, '\"');
6f15d409 1601
fa1a86f3 1602 idx = getstring (idx, in, out);
19be7c08 1603 sb_add_char (out, '\"');
fa1a86f3
SC
1604
1605 }
1606 else {
1607 idx = getstring (idx, in, out);
1608 }
1609 }
1610 else
1611 {
1612 while (idx < in->len
1613 && (in->ptr[idx] == '"'
1614 || in->ptr[idx] == '\''
6f15d409 1615 || pretend_quoted
fa1a86f3
SC
1616 || !ISSEP (in->ptr[idx])))
1617 {
1618 if (in->ptr[idx] == '"'
1619 || in->ptr[idx] == '\'')
1620 {
1621 char tchar = in->ptr[idx];
1622 sb_add_char (out, in->ptr[idx++]);
1623 while (idx < in->len
1624 && in->ptr[idx] != tchar)
1625 sb_add_char (out, in->ptr[idx++]);
13d9fd33
SC
1626 if (idx == in->len)
1627 return idx;
fa1a86f3
SC
1628 }
1629 sb_add_char (out, in->ptr[idx++]);
fa1a86f3
SC
1630 }
1631 }
b0f2092b 1632 }
13d9fd33 1633
b0f2092b
SC
1634 return idx;
1635}
1636
1637
1638/* skip along sb in starting at idx, suck off whitespace a ( and more
1639 whitespace. return the idx of the next char */
1640
19be7c08 1641static int
b0f2092b
SC
1642skip_openp (idx, in)
1643 int idx;
1644 sb *in;
1645{
1646 idx = sb_skip_white (idx, in);
1647 if (in->ptr[idx] != '(')
1648 ERROR ((stderr, "misplaced ( .\n"));
1649 idx = sb_skip_white (idx + 1, in);
1650 return idx;
1651}
1652
1653/* skip along sb in starting at idx, suck off whitespace a ) and more
1654 whitespace. return the idx of the next char */
1655
19be7c08 1656static int
b0f2092b
SC
1657skip_closep (idx, in)
1658 int idx;
1659 sb *in;
1660{
1661 idx = sb_skip_white (idx, in);
1662 if (in->ptr[idx] != ')')
1663 ERROR ((stderr, "misplaced ).\n"));
1664 idx = sb_skip_white (idx + 1, in);
1665 return idx;
1666}
1667
1668/* .len */
1669
19be7c08 1670static int
b0f2092b
SC
1671dolen (idx, in, out)
1672 int idx;
1673 sb *in;
1674 sb *out;
1675{
1676
1677 sb stringout;
1678 char buffer[10];
1679
1680 sb_new (&stringout);
1681 idx = skip_openp (idx, in);
1682 idx = get_and_process (idx, in, &stringout);
1683 idx = skip_closep (idx, in);
1684 sprintf (buffer, "%d", stringout.len);
1685 sb_add_string (out, buffer);
1686
1687 sb_kill (&stringout);
1688 return idx;
1689}
1690
1691
1692/* .instr */
1693
1694static
1695int
1696doinstr (idx, in, out)
1697 int idx;
1698 sb *in;
1699 sb *out;
1700{
1701 sb string;
1702 sb search;
1703 int i;
1704 int start;
1705 int res;
1706 char buffer[10];
1707
1708 sb_new (&string);
1709 sb_new (&search);
1710 idx = skip_openp (idx, in);
1711 idx = get_and_process (idx, in, &string);
1712 idx = sb_skip_comma (idx, in);
1713 idx = get_and_process (idx, in, &search);
1714 idx = sb_skip_comma (idx, in);
1715 if (isdigit (in->ptr[idx]))
1716 {
1717 idx = exp_get_abs (".instr needs absolute expresson.\n", idx, in, &start);
1718 }
1719 else
1720 {
1721 start = 0;
1722 }
1723 idx = skip_closep (idx, in);
1724 res = -1;
1725 for (i = start; i < string.len; i++)
1726 {
1727 if (strncmp (string.ptr + i, search.ptr, search.len) == 0)
1728 {
1729 res = i;
1730 break;
1731 }
1732 }
1733 sprintf (buffer, "%d", res);
1734 sb_add_string (out, buffer);
1735 sb_kill (&string);
1736 sb_kill (&search);
1737 return idx;
1738}
1739
1740
1741static int
1742dosubstr (idx, in, out)
1743 int idx;
1744 sb *in;
1745 sb *out;
1746{
1747 sb string;
1748 int pos;
1749 int len;
1750 sb_new (&string);
1751
1752 idx = skip_openp (idx, in);
1753 idx = get_and_process (idx, in, &string);
1754 idx = sb_skip_comma (idx, in);
1755 idx = exp_get_abs ("need absolute position.\n", idx, in, &pos);
1756 idx = sb_skip_comma (idx, in);
1757 idx = exp_get_abs ("need absolute length.\n", idx, in, &len);
1758 idx = skip_closep (idx, in);
1759
1760
1761 if (len < 0 || pos < 0 ||
1762 pos > string.len
1763 || pos + len > string.len)
1764 {
1765 sb_add_string (out, " ");
1766 }
1767 else
1768 {
1769 sb_add_char (out, '"');
1770 while (len > 0)
1771 {
1772 sb_add_char (out, string.ptr[pos++]);
1773 len--;
1774 }
1775 sb_add_char (out, '"');
1776 }
1777 sb_kill(&string);
1778 return idx;
1779}
1780
1781/* scan line, change tokens in the hash table to their replacements */
19be7c08 1782static void
b0f2092b
SC
1783process_assigns (idx, in, buf)
1784 int idx;
1785 sb *in;
1786 sb *buf;
1787{
1788 while (idx < in->len)
1789 {
1790 hash_entry *ptr;
1791 if (in->ptr[idx] == '\\'
5ba7c0be
ILT
1792 && idx + 1 < in->len
1793 && in->ptr[idx + 1] == '(')
1794 {
1795 do
1796 {
1797 sb_add_char (buf, in->ptr[idx]);
1798 idx++;
1799 }
1800 while (idx < in->len && in->ptr[idx - 1] != ')');
1801 }
1802 else if (in->ptr[idx] == '\\'
1803 && idx + 1 < in->len
b0f2092b
SC
1804 && in->ptr[idx + 1] == '&')
1805 {
fa1a86f3
SC
1806 idx = condass_lookup_name (in, idx + 2, buf, 1);
1807 }
1808 else if (in->ptr[idx] == '\\'
5ba7c0be 1809 && idx + 1 < in->len
fa1a86f3
SC
1810 && in->ptr[idx + 1] == '$')
1811 {
1812 idx = condass_lookup_name (in, idx + 2, buf, 0);
b0f2092b
SC
1813 }
1814 else if (idx + 3 < in->len
1815 && in->ptr[idx] == '.'
fe98e22d
ILT
1816 && toupper ((unsigned char) in->ptr[idx + 1]) == 'L'
1817 && toupper ((unsigned char) in->ptr[idx + 2]) == 'E'
1818 && toupper ((unsigned char) in->ptr[idx + 3]) == 'N')
b0f2092b
SC
1819 idx = dolen (idx + 4, in, buf);
1820 else if (idx + 6 < in->len
1821 && in->ptr[idx] == '.'
fe98e22d
ILT
1822 && toupper ((unsigned char) in->ptr[idx + 1]) == 'I'
1823 && toupper ((unsigned char) in->ptr[idx + 2]) == 'N'
1824 && toupper ((unsigned char) in->ptr[idx + 3]) == 'S'
1825 && toupper ((unsigned char) in->ptr[idx + 4]) == 'T'
1826 && toupper ((unsigned char) in->ptr[idx + 5]) == 'R')
b0f2092b
SC
1827 idx = doinstr (idx + 6, in, buf);
1828 else if (idx + 7 < in->len
1829 && in->ptr[idx] == '.'
fe98e22d
ILT
1830 && toupper ((unsigned char) in->ptr[idx + 1]) == 'S'
1831 && toupper ((unsigned char) in->ptr[idx + 2]) == 'U'
1832 && toupper ((unsigned char) in->ptr[idx + 3]) == 'B'
1833 && toupper ((unsigned char) in->ptr[idx + 4]) == 'S'
1834 && toupper ((unsigned char) in->ptr[idx + 5]) == 'T'
1835 && toupper ((unsigned char) in->ptr[idx + 6]) == 'R')
b0f2092b
SC
1836 idx = dosubstr (idx + 7, in, buf);
1837 else if (ISFIRSTCHAR (in->ptr[idx]))
1838 {
1839 /* may be a simple name subsitution, see if we have a word */
1840 sb acc;
1841 int cur = idx + 1;
1842 while (cur < in->len
1843 && (ISNEXTCHAR (in->ptr[cur])))
1844 cur++;
1845
1846 sb_new (&acc);
1847 sb_add_buffer (&acc, in->ptr + idx, cur - idx);
1848 ptr = hash_lookup (&assign_hash_table, &acc);
1849 if (ptr)
1850 {
1851 /* Found a definition for it */
1852 sb_add_sb (buf, &ptr->value.s);
1853 }
1854 else
1855 {
1856 /* No definition, just copy the word */
1857 sb_add_sb (buf, &acc);
1858 }
1859 sb_kill (&acc);
1860 idx = cur;
1861 }
1862 else
1863 {
1864 sb_add_char (buf, in->ptr[idx++]);
1865 }
1866 }
1867}
1868
1869static int
1870get_and_process (idx, in, out)
1871 int idx;
1872 sb *in;
1873 sb *out;
1874{
1875 sb t;
1876 sb_new (&t);
6f15d409 1877 idx = get_any_string (idx, in, &t, 1, 0);
b0f2092b
SC
1878 process_assigns (0, &t, out);
1879 sb_kill (&t);
1880 return idx;
1881}
1882
1883static
1884void
1885process_file ()
1886{
1887 sb line;
1888 sb t1, t2;
1889 sb acc;
fa1a86f3 1890 sb label_in;
b0f2092b
SC
1891 int more;
1892
1893 sb_new (&line);
1894 sb_new (&t1);
1895 sb_new (&t2);
1896 sb_new(&acc);
fa1a86f3 1897 sb_new (&label_in);
b0f2092b
SC
1898 sb_reset (&line);
1899 more = get_line (&line);
1900 while (more)
1901 {
1902 /* Find any label and pseudo op that we're intested in */
1903 int l;
1904 if (line.len == 0)
1905 {
1906 if (condass_on ())
1907 fprintf (outfile, "\n");
1908 }
f8d6e6cd
ILT
1909 else if (mri
1910 && (line.ptr[0] == '*'
1911 || line.ptr[0] == '!'))
1912 {
1913 /* MRI line comment. */
1914 fprintf (outfile, sb_name (&line));
1915 }
b0f2092b
SC
1916 else
1917 {
fa1a86f3
SC
1918 l = grab_label (&line, &label_in);
1919 sb_reset (&label);
b0f2092b 1920
b0f2092b
SC
1921 if (line.ptr[l] == ':')
1922 l++;
1923 while (ISWHITE (line.ptr[l]) && l < line.len)
1924 l++;
1925
0f68bf0a
ILT
1926 if (label_in.len)
1927 {
1928 int do_assigns;
1929
1930 /* Munge the label, unless this is EQU or ASSIGN. */
1931 do_assigns = 1;
1932 if (l < line.len
1933 && (line.ptr[l] == '.' || alternate || mri))
1934 {
1935 int lx = l;
1936
1937 if (line.ptr[lx] == '.')
1938 ++lx;
1939 if (lx + 3 <= line.len
1940 && strncasecmp ("EQU", line.ptr + lx, 3) == 0
1941 && (lx + 3 == line.len
1942 || ! ISFIRSTCHAR (line.ptr[lx + 3])))
1943 do_assigns = 0;
1944 else if (lx + 6 <= line.len
1945 && strncasecmp ("ASSIGN", line.ptr + lx, 6) == 0
1946 && (lx + 6 == line.len
1947 || ! ISFIRSTCHAR (line.ptr[lx + 6])))
1948 do_assigns = 0;
1949 }
1950
1951 if (do_assigns)
1952 process_assigns (0, &label_in, &label);
1953 else
1954 sb_add_sb (&label, &label_in);
1955 }
1956
fa1a86f3 1957 if (l < line.len)
b0f2092b
SC
1958 {
1959 if (process_pseudo_op (l, &line, &acc))
1960 {
1961
1962
1963
1964 }
1965 else if (condass_on ())
1966 {
1967 if (macro_op (l, &line))
1968 {
1969
1970
1971 }
1972 else
1973 {
1974 {
1975 if (label.len)
1976 {
1977 fprintf (outfile, "%s:\t", sb_name (&label));
1978 }
1979 else
1980 fprintf (outfile, "\t");
1981 sb_reset(&t1);
1982 process_assigns (l, &line, &t1);
1983 sb_reset (&t2);
1984 change_base (0, &t1, &t2);
1985 fprintf (outfile, "%s\n", sb_name (&t2));
1986 }
1987 }
1988 }
1989 }
fa1a86f3
SC
1990 else {
1991 /* Only a label on this line */
1992 if (label.len && condass_on())
1993 {
1994 fprintf (outfile, "%s:\n", sb_name (&label));
1995 }
1996 }
b0f2092b
SC
1997 }
1998
1999 if (had_end)
2000 break;
2001 sb_reset (&line);
2002 more = get_line (&line);
2003 }
2004
19be7c08 2005 if (!had_end && !mri)
fa1a86f3 2006 WARNING ((stderr, "END missing from end of file.\n"));
b0f2092b
SC
2007}
2008
2009
2010
2011
2012
2013static void
2014free_old_entry (ptr)
2015 hash_entry *ptr;
2016{
2017 if (ptr)
2018 {
2019 if (ptr->type == hash_string)
2020 sb_kill(&ptr->value.s);
2021 }
2022}
2023
2024/* name: .ASSIGNA <value> */
2025
e15126c4 2026static void
b0f2092b
SC
2027do_assigna (idx, in)
2028 int idx;
2029 sb *in;
2030{
2031 sb tmp;
2032 int val;
2033 sb_new (&tmp);
2034
2035 process_assigns (idx, in, &tmp);
2036 idx = exp_get_abs (".ASSIGNA needs constant expression argument.\n", 0, &tmp, &val);
2037
2038 if (!label.len)
2039 {
2040 ERROR ((stderr, ".ASSIGNA without label.\n"));
2041 }
2042 else
2043 {
2044 hash_entry *ptr = hash_create (&vars, &label);
2045 free_old_entry (ptr);
2046 ptr->type = hash_integer;
2047 ptr->value.i = val;
2048 }
2049 sb_kill (&tmp);
2050}
2051
2052/* name: .ASSIGNC <string> */
2053
e15126c4 2054static void
b0f2092b
SC
2055do_assignc (idx, in)
2056 int idx;
2057 sb *in;
2058{
2059 sb acc;
2060 sb_new (&acc);
2061 idx = getstring (idx, in, &acc);
2062
2063 if (!label.len)
2064 {
2065 ERROR ((stderr, ".ASSIGNS without label.\n"));
2066 }
2067 else
2068 {
2069 hash_entry *ptr = hash_create (&vars, &label);
2070 free_old_entry (ptr);
2071 ptr->type = hash_string;
2072 sb_new (&ptr->value.s);
2073 sb_add_sb (&ptr->value.s, &acc);
2074 }
2075 sb_kill (&acc);
2076}
2077
2078
2079/* name: .REG (reg) */
2080
2081static void
2082do_reg (idx, in)
2083 int idx;
2084 sb *in;
2085{
2086 /* remove reg stuff from inside parens */
2087 sb what;
f8d6e6cd
ILT
2088 if (!mri)
2089 idx = skip_openp (idx, in);
2090 else
2091 idx = sb_skip_white (idx, in);
b0f2092b 2092 sb_new (&what);
f8d6e6cd
ILT
2093 while (idx < in->len
2094 && (mri
2095 ? ! eol (idx, in)
2096 : in->ptr[idx] != ')'))
b0f2092b
SC
2097 {
2098 sb_add_char (&what, in->ptr[idx]);
2099 idx++;
2100 }
2101 hash_add_to_string_table (&assign_hash_table, &label, &what, 1);
2102 sb_kill (&what);
2103}
2104
2105
2106static int
fa1a86f3 2107condass_lookup_name (inbuf, idx, out, warn)
b0f2092b
SC
2108 sb *inbuf;
2109 int idx;
2110 sb *out;
fa1a86f3 2111 int warn;
b0f2092b
SC
2112{
2113 hash_entry *ptr;
2114 sb condass_acc;
2115 sb_new (&condass_acc);
2116
2117 while (idx < inbuf->len
2118 && ISNEXTCHAR (inbuf->ptr[idx]))
2119 {
2120 sb_add_char (&condass_acc, inbuf->ptr[idx++]);
2121 }
2122
2123 if (inbuf->ptr[idx] == '\'')
2124 idx++;
2125 ptr = hash_lookup (&vars, &condass_acc);
fa1a86f3
SC
2126
2127
b0f2092b
SC
2128 if (!ptr)
2129 {
fa1a86f3
SC
2130 if (warn)
2131 {
2132 WARNING ((stderr, "Can't find preprocessor variable %s.\n", sb_name (&condass_acc)));
2133 }
2134 else
2135 {
2136 sb_add_string (out, "0");
2137 }
b0f2092b
SC
2138 }
2139 else
2140 {
2141 if (ptr->type == hash_integer)
2142 {
2143 char buffer[30];
2144 sprintf (buffer, "%d", ptr->value.i);
2145 sb_add_string (out, buffer);
2146 }
2147 else
2148 {
2149 sb_add_sb (out, &ptr->value.s);
2150 }
2151 }
2152 sb_kill (&condass_acc);
2153 return idx;
2154}
2155
2156#define EQ 1
2157#define NE 2
2158#define GE 3
2159#define LT 4
2160#define LE 5
2161#define GT 6
2162#define NEVER 7
2163
19be7c08 2164static int
b0f2092b
SC
2165whatcond (idx, in, val)
2166 int idx;
2167 sb *in;
2168 int *val;
2169{
2170 int cond;
fe98e22d 2171
b0f2092b 2172 idx = sb_skip_white (idx, in);
fe98e22d
ILT
2173 cond = NEVER;
2174 if (idx + 1 < in->len)
2175 {
2176 char *p;
2177 char a, b;
2178
2179 p = in->ptr + idx;
2180 a = toupper ((unsigned char) p[0]);
2181 b = toupper ((unsigned char) p[1]);
2182 if (a == 'E' && b == 'Q')
2183 cond = EQ;
2184 else if (a == 'N' && b == 'E')
2185 cond = NE;
2186 else if (a == 'L' && b == 'T')
2187 cond = LT;
2188 else if (a == 'L' && b == 'E')
2189 cond = LE;
2190 else if (a == 'G' && b == 'T')
2191 cond = GT;
2192 else if (a == 'G' && b == 'E')
2193 cond = GE;
2194 }
2195 if (cond == NEVER)
b0f2092b 2196 {
fa1a86f3 2197 ERROR ((stderr, "Comparison operator must be one of EQ, NE, LT, LE, GT or GE.\n"));
b0f2092b
SC
2198 cond = NEVER;
2199 }
2200 idx = sb_skip_white (idx + 2, in);
2201 *val = cond;
2202 return idx;
2203}
2204
19be7c08 2205static int
b0f2092b
SC
2206istrue (idx, in)
2207 int idx;
2208 sb *in;
2209{
2210 int res;
2211 sb acc_a;
2212 sb cond;
2213 sb acc_b;
2214 sb_new (&acc_a);
2215 sb_new (&cond);
2216 sb_new (&acc_b);
2217 idx = sb_skip_white (idx, in);
2218
2219 if (in->ptr[idx] == '"')
2220 {
2221 int cond;
2222 int same;
2223 /* This is a string comparision */
2224 idx = getstring (idx, in, &acc_a);
2225 idx = whatcond (idx, in, &cond);
2226 idx = getstring (idx, in, &acc_b);
2227 same = acc_a.len == acc_b.len && (strncmp (acc_a.ptr, acc_b.ptr, acc_a.len) == 0);
2228
2229 if (cond != EQ && cond != NE)
2230 {
fa1a86f3 2231 ERROR ((stderr, "Comparison operator for strings must be EQ or NE\n"));
b0f2092b
SC
2232 res = 0;
2233 }
2234 else
078d1a5a 2235 res = (cond != EQ) ^ same;
b0f2092b
SC
2236 }
2237 else
2238 /* This is a numeric expression */
2239 {
2240 int vala;
2241 int valb;
2242 int cond;
2243 idx = exp_get_abs ("Conditional operator must have absolute operands.\n", idx, in, &vala);
2244 idx = whatcond (idx, in, &cond);
2245 idx = sb_skip_white (idx, in);
2246 if (in->ptr[idx] == '"')
2247 {
2248 WARNING ((stderr, "String compared against expression.\n"));
2249 res = 0;
2250 }
2251 else
2252 {
2253 idx = exp_get_abs ("Conditional operator must have absolute operands.\n", idx, in, &valb);
2254 switch (cond)
2255 {
11618ce8
KR
2256 default:
2257 res = 42;
2258 break;
b0f2092b
SC
2259 case EQ:
2260 res = vala == valb;
2261 break;
2262 case NE:
2263 res = vala != valb;
2264 break;
2265 case LT:
2266 res = vala < valb;
2267 break;
2268 case LE:
2269 res = vala <= valb;
2270 break;
2271 case GT:
2272 res = vala > valb;
2273 break;
2274 case GE:
2275 res = vala >= valb;
2276 break;
2277 case NEVER:
2278 res = 0;
2279 break;
2280 }
2281 }
2282 }
2283
2284 sb_kill (&acc_a);
2285 sb_kill (&cond);
2286 sb_kill (&acc_b);
2287 return res;
2288}
2289
2290/* .AIF */
2291static void
2292do_aif (idx, in)
2293 int idx;
2294 sb *in;
2295{
2296 if (ifi >= IFNESTING)
2297 {
2298 FATAL ((stderr, "AIF nesting unreasonable.\n"));
2299 }
2300 ifi++;
13d9fd33 2301 ifstack[ifi].on = ifstack[ifi-1].on ? istrue (idx, in) : 0;
b0f2092b
SC
2302 ifstack[ifi].hadelse = 0;
2303}
2304
2305
2306/* .AELSE */
2307static void
2308do_aelse ()
2309{
13d9fd33 2310 ifstack[ifi].on = ifstack[ifi-1].on ? !ifstack[ifi].on : 0;
b0f2092b
SC
2311 if (ifstack[ifi].hadelse)
2312 {
2313 ERROR ((stderr, "Multiple AELSEs in AIF.\n"));
2314 }
2315 ifstack[ifi].hadelse = 1;
2316}
2317
2318
2319/* .AENDI */
2320static void
2321do_aendi ()
2322{
2323 if (ifi != 0)
2324 {
2325 ifi--;
2326 }
2327 else
2328 {
2329 ERROR ((stderr, "AENDI without AIF.\n"));
2330 }
2331}
2332
2333static int
2334condass_on ()
2335{
2336 return ifstack[ifi].on;
2337}
2338
19be7c08
ILT
2339/* MRI IFEQ, IFNE, IFLT, IFLE, IFGE, IFGT. */
2340
2341static void
2342do_if (idx, in, cond)
2343 int idx;
2344 sb *in;
2345 int cond;
2346{
2347 int val;
2348 int res;
2349
2350 if (ifi >= IFNESTING)
2351 {
2352 FATAL ((stderr, "IF nesting unreasonable.\n"));
2353 }
2354
2355 idx = exp_get_abs ("Conditional operator must have absolute operands.\n",
2356 idx, in, &val);
2357 switch (cond)
2358 {
2359 default:
2360 case EQ: res = val == 0; break;
2361 case NE: res = val != 0; break;
2362 case LT: res = val < 0; break;
2363 case LE: res = val <= 0; break;
2364 case GE: res = val >= 0; break;
2365 case GT: res = val > 0; break;
2366 }
2367
2368 ifi++;
2369 ifstack[ifi].on = ifstack[ifi-1].on ? res: 0;
2370 ifstack[ifi].hadelse = 0;
2371}
2372
2373/* Get a string for the MRI IFC or IFNC pseudo-ops. */
2374
2375static int
2376get_mri_string (idx, in, val, terminator)
2377 int idx;
2378 sb *in;
2379 sb *val;
2380 int terminator;
2381{
2382 idx = sb_skip_white (idx, in);
2383
2384 if (idx < in->len
2385 && in->ptr[idx] == '\'')
2386 {
2387 sb_add_char (val, '\'');
2388 for (++idx; idx < in->len; ++idx)
2389 {
2390 sb_add_char (val, in->ptr[idx]);
2391 if (in->ptr[idx] == '\'')
2392 {
2393 ++idx;
2394 if (idx >= in->len
2395 || in->ptr[idx] != '\'')
2396 break;
2397 }
2398 }
2399 idx = sb_skip_white (idx, in);
2400 }
2401 else
2402 {
2403 int i;
2404
2405 while (idx < in->len
2406 && in->ptr[idx] != terminator)
2407 {
2408 sb_add_char (val, in->ptr[idx]);
2409 ++idx;
2410 }
2411 i = val->len - 1;
2412 while (i >= 0 && ISWHITE (val->ptr[i]))
2413 --i;
2414 val->len = i + 1;
2415 }
2416
2417 return idx;
2418}
2419
2420/* MRI IFC, IFNC. */
2421
2422static void
2423do_ifc (idx, in, ifnc)
2424 int idx;
2425 sb *in;
2426 int ifnc;
2427{
2428 sb first;
2429 sb second;
2430 int res;
2431
2432 if (ifi >= IFNESTING)
2433 {
2434 FATAL ((stderr, "IF nesting unreasonable.\n"));
2435 }
2436
2437 sb_new (&first);
2438 sb_new (&second);
2439
2440 idx = get_mri_string (idx, in, &first, ',');
2441
2442 if (idx >= in->len || in->ptr[idx] != ',')
2443 {
2444 ERROR ((stderr, "Bad format for IF or IFNC.\n"));
2445 return;
2446 }
2447
2448 idx = get_mri_string (idx + 1, in, &second, ';');
2449
2450 res = (first.len == second.len
2451 && strncmp (first.ptr, second.ptr, first.len) == 0);
2452 res ^= ifnc;
2453
2454 ifi++;
2455 ifstack[ifi].on = ifstack[ifi-1].on ? res : 0;
2456 ifstack[ifi].hadelse = 0;
2457}
b0f2092b 2458
b0f2092b 2459/* .ENDR */
19be7c08 2460static void
b0f2092b
SC
2461do_aendr ()
2462{
19be7c08
ILT
2463 if (!mri)
2464 ERROR ((stderr, "AENDR without a AREPEAT.\n"));
2465 else
2466 ERROR ((stderr, "ENDR without a REPT.\n"));
b0f2092b
SC
2467}
2468
2469/* .AWHILE */
2470
2471static
2472void
2473do_awhile (idx, in)
2474 int idx;
2475 sb *in;
2476{
7e047ac2 2477 int line = linecount ();
b0f2092b 2478 sb exp;
b0f2092b 2479 sb sub;
b0f2092b 2480 int doit;
7e047ac2 2481
b0f2092b
SC
2482 sb_new (&sub);
2483 sb_new (&exp);
2484
2485 process_assigns (idx, in, &exp);
2486 doit = istrue (0, &exp);
2487
7e047ac2
ILT
2488 if (! buffer_and_nest ("AWHILE", "AENDW", &sub, get_line))
2489 FATAL ((stderr, "AWHILE without a AENDW at %d.\n", line - 1));
b0f2092b
SC
2490
2491 /* Turn
2492 .AWHILE exp
2493 foo
2494 .AENDW
2495 into
2496 foo
2497 .AWHILE exp
2498 foo
2499 .ENDW
2500 */
2501
2502 if (doit)
2503 {
2504 int index = include_next_index ();
2505
2506 sb copy;
2507 sb_new (&copy);
2508 sb_add_sb (&copy, &sub);
2509 sb_add_sb (&copy, in);
2510 sb_add_string (&copy, "\n");
2511 sb_add_sb (&copy, &sub);
2512 sb_add_string (&copy, "\t.AENDW\n");
2513 /* Push another WHILE */
2514 include_buf (&exp, &copy, include_while, index);
2515 sb_kill (&copy);
2516 }
2517 sb_kill (&exp);
2518 sb_kill (&sub);
2519}
2520
2521
2522/* .AENDW */
2523
2524static void
2525do_aendw ()
2526{
2527 ERROR ((stderr, "AENDW without a AENDW.\n"));
2528}
2529
2530
2531/* .EXITM
2532
2533 Pop things off the include stack until the type and index changes */
2534
2535static void
2536do_exitm ()
2537{
2538 include_type type = sp->type;
2539 if (type == include_repeat
2540 || type == include_while
2541 || type == include_macro)
2542 {
2543 int index = sp->index;
2544 include_pop ();
2545 while (sp->index == index
2546 && sp->type == type)
2547 {
2548 include_pop ();
2549 }
2550 }
2551}
2552
2553/* .AREPEAT */
2554
2555static void
2556do_arepeat (idx, in)
2557 int idx;
2558 sb *in;
2559{
7e047ac2 2560 int line = linecount ();
b0f2092b
SC
2561 sb exp; /* buffer with expression in it */
2562 sb copy; /* expanded repeat block */
2563 sb sub; /* contents of AREPEAT */
2564 int rc;
7e047ac2 2565 int ret;
b0f2092b 2566 char buffer[30];
7e047ac2 2567
b0f2092b
SC
2568 sb_new (&exp);
2569 sb_new (&copy);
2570 sb_new (&sub);
2571 process_assigns (idx, in, &exp);
2572 idx = exp_get_abs ("AREPEAT must have absolute operand.\n", 0, &exp, &rc);
19be7c08 2573 if (!mri)
7e047ac2 2574 ret = buffer_and_nest ("AREPEAT", "AENDR", &sub, get_line);
19be7c08 2575 else
7e047ac2
ILT
2576 ret = buffer_and_nest ("REPT", "ENDR", &sub, get_line);
2577 if (! ret)
2578 FATAL ((stderr, "AREPEAT without a AENDR at %d.\n", line - 1));
b0f2092b
SC
2579 if (rc > 0)
2580 {
2581 /* Push back the text following the repeat, and another repeat block
2582 so
2583 .AREPEAT 20
2584 foo
2585 .AENDR
2586 gets turned into
2587 foo
2588 .AREPEAT 19
2589 foo
2590 .AENDR
2591 */
2592 int index = include_next_index ();
2593 sb_add_sb (&copy, &sub);
2594 if (rc > 1)
2595 {
19be7c08
ILT
2596 if (!mri)
2597 sprintf (buffer, "\t.AREPEAT %d\n", rc - 1);
2598 else
2599 sprintf (buffer, "\tREPT %d\n", rc - 1);
b0f2092b
SC
2600 sb_add_string (&copy, buffer);
2601 sb_add_sb (&copy, &sub);
19be7c08
ILT
2602 if (!mri)
2603 sb_add_string (&copy, " .AENDR\n");
2604 else
2605 sb_add_string (&copy, " ENDR\n");
b0f2092b
SC
2606 }
2607
2608 include_buf (&exp, &copy, include_repeat, index);
2609 }
2610 sb_kill (&exp);
2611 sb_kill (&sub);
2612 sb_kill (&copy);
2613}
2614
2615/* .ENDM */
2616
2617static void
2618do_endm ()
2619{
2620 ERROR ((stderr, ".ENDM without a matching .MACRO.\n"));
2621}
2622
7f5adcba
ILT
2623/* MRI IRP pseudo-op. */
2624
2625static void
2626do_irp (idx, in, irpc)
2627 int idx;
2628 sb *in;
2629 int irpc;
2630{
7e047ac2 2631 const char *err;
7f5adcba
ILT
2632 sb out;
2633
7f5adcba
ILT
2634 sb_new (&out);
2635
7e047ac2
ILT
2636 err = expand_irp (irpc, idx, in, &out, get_line, comment_char);
2637 if (err != NULL)
2638 ERROR ((stderr, "%s\n", err));
2639
2640 fprintf (outfile, "%s", sb_terminate (&out));
7f5adcba 2641
7f5adcba
ILT
2642 sb_kill (&out);
2643}
b0f2092b 2644
7f5adcba 2645/* MACRO PROCESSING */
b0f2092b 2646
fa1a86f3
SC
2647/* Parse off LOCAL n1, n2,... Invent a label name for it */
2648static
2649void
2650do_local (idx, line)
2651 int idx;
2652 sb *line;
2653{
7e047ac2 2654 ERROR ((stderr, "LOCAL outside of MACRO"));
fa1a86f3
SC
2655}
2656
7e047ac2 2657static void
b0f2092b
SC
2658do_macro (idx, in)
2659 int idx;
2660 sb *in;
2661{
7e047ac2
ILT
2662 const char *err;
2663 int line = linecount ();
b0f2092b 2664
a69e5977 2665 err = define_macro (idx, in, &label, get_line, (const char **) NULL);
7e047ac2
ILT
2666 if (err != NULL)
2667 ERROR ((stderr, "macro at line %d: %s\n", line - 1, err));
b0f2092b
SC
2668}
2669
2670static int
7e047ac2 2671macro_op (idx, in)
b0f2092b
SC
2672 int idx;
2673 sb *in;
b0f2092b 2674{
7e047ac2 2675 const char *err;
b0f2092b 2676 sb out;
7e047ac2 2677 sb name;
19be7c08 2678
7e047ac2
ILT
2679 if (! macro_defined)
2680 return 0;
b0f2092b 2681
7e047ac2
ILT
2682 sb_terminate (in);
2683 if (! check_macro (in->ptr + idx, &out, comment_char, &err))
2684 return 0;
19be7c08 2685
7e047ac2
ILT
2686 if (err != NULL)
2687 ERROR ((stderr, "%s\n", err));
b0f2092b 2688
7e047ac2
ILT
2689 sb_new (&name);
2690 sb_add_string (&name, "macro expansion");
19be7c08 2691
7e047ac2 2692 include_buf (&name, &out, include_macro, include_next_index ());
19be7c08 2693
7e047ac2 2694 sb_kill (&name);
b0f2092b 2695 sb_kill (&out);
b0f2092b 2696
7e047ac2 2697 return 1;
b0f2092b
SC
2698}
2699
b0f2092b
SC
2700/* STRING HANDLING */
2701
2702static int
2703getstring (idx, in, acc)
2704 int idx;
2705 sb *in;
2706 sb *acc;
2707{
2708 idx = sb_skip_white (idx, in);
2709
2710 while (idx < in->len
fa1a86f3
SC
2711 && (in->ptr[idx] == '"'
2712 || in->ptr[idx] == '<'
2713 || (in->ptr[idx] == '\'' && alternate)))
b0f2092b
SC
2714 {
2715 if (in->ptr[idx] == '<')
2716 {
19be7c08 2717 if (alternate || mri)
fa1a86f3
SC
2718 {
2719 int nest = 0;
2720 idx++;
2721 while ((in->ptr[idx] != '>' || nest)
2722 && idx < in->len)
2723 {
2724 if (in->ptr[idx] == '!')
2725 {
2726 idx++ ;
2727 sb_add_char (acc, in->ptr[idx++]);
2728 }
2729 else {
2730 if (in->ptr[idx] == '>')
2731 nest--;
2732 if (in->ptr[idx] == '<')
2733 nest++;
2734 sb_add_char (acc, in->ptr[idx++]);
2735 }
2736 }
2737 idx++;
2738 }
2739 else {
2740 int code;
2741 idx++;
2742 idx = exp_get_abs ("Character code in string must be absolute expression.\n",
2743 idx, in, &code);
2744 sb_add_char (acc, code);
2745
2746 if (in->ptr[idx] != '>')
2747 ERROR ((stderr, "Missing > for character code.\n"));
2748 idx++;
2749 }
b0f2092b 2750 }
fa1a86f3 2751 else if (in->ptr[idx] == '"' || in->ptr[idx] == '\'')
b0f2092b 2752 {
fa1a86f3 2753 char tchar = in->ptr[idx];
b0f2092b
SC
2754 idx++;
2755 while (idx < in->len)
2756 {
fa1a86f3 2757 if (alternate && in->ptr[idx] == '!')
b0f2092b 2758 {
fa1a86f3
SC
2759 idx++ ;
2760 sb_add_char (acc, in->ptr[idx++]);
b0f2092b 2761 }
fa1a86f3
SC
2762 else {
2763 if (in->ptr[idx] == tchar)
2764 {
2765 idx++;
2766 if (idx >= in->len || in->ptr[idx] != tchar)
2767 break;
2768 }
2769 sb_add_char (acc, in->ptr[idx]);
2770 idx++;
2771 }
b0f2092b
SC
2772 }
2773 }
2774 }
fa1a86f3 2775
b0f2092b
SC
2776 return idx;
2777}
2778
2779/* .SDATA[C|Z] <string> */
2780
2781static
2782void
2783do_sdata (idx, in, type)
2784 int idx;
2785 sb *in;
19be7c08 2786 int type;
b0f2092b
SC
2787{
2788 int nc = 0;
fa1a86f3 2789 int pidx = -1;
b0f2092b
SC
2790 sb acc;
2791 sb_new (&acc);
2792 fprintf (outfile, ".byte\t");
2793
fa1a86f3 2794 while (!eol (idx, in))
b0f2092b
SC
2795 {
2796 int i;
2797 sb_reset (&acc);
2798 idx = sb_skip_white (idx, in);
fa1a86f3 2799 while (!eol (idx, in))
b0f2092b 2800 {
6f15d409 2801 pidx = idx = get_any_string (idx, in, &acc, 0, 1);
b0f2092b
SC
2802 if (type == 'c')
2803 {
2804 if (acc.len > 255)
2805 {
2806 ERROR ((stderr, "string for SDATAC longer than 255 characters (%d).\n", acc.len));
2807 }
2808 fprintf (outfile, "%d", acc.len);
2809 nc = 1;
2810 }
2811
2812 for (i = 0; i < acc.len; i++)
2813 {
2814 if (nc)
2815 {
2816 fprintf (outfile, ",");
2817 }
2818 fprintf (outfile, "%d", acc.ptr[i]);
2819 nc = 1;
2820 }
2821
2822 if (type == 'z')
2823 {
2824 if (nc)
2825 fprintf (outfile, ",");
2826 fprintf (outfile, "0");
2827 }
fa1a86f3
SC
2828 idx = sb_skip_comma (idx, in);
2829 if (idx == pidx) break;
b0f2092b 2830 }
fa1a86f3 2831 if (!alternate && in->ptr[idx] != ',' && idx != in->len)
b0f2092b
SC
2832 {
2833 fprintf (outfile, "\n");
2834 ERROR ((stderr, "illegal character in SDATA line (0x%x).\n", in->ptr[idx]));
2835 break;
2836 }
2837 idx++;
2838 }
2839 sb_kill (&acc);
2840 fprintf (outfile, "\n");
2841}
2842
2843/* .SDATAB <count> <string> */
2844
2845static void
2846do_sdatab (idx, in)
2847 int idx;
2848 sb *in;
2849{
2850 int repeat;
2851 int i;
2852 sb acc;
2853 sb_new (&acc);
2854
2855 idx = exp_get_abs ("Must have absolute SDATAB repeat count.\n", idx, in, &repeat);
2856 if (repeat <= 0)
2857 {
2858 ERROR ((stderr, "Must have positive SDATAB repeat count (%d).\n", repeat));
2859 repeat = 1;
2860 }
2861
2862 idx = sb_skip_comma (idx, in);
2863 idx = getstring (idx, in, &acc);
2864
2865 for (i = 0; i < repeat; i++)
2866 {
2867 if (i)
2868 fprintf (outfile, "\t");
2869 fprintf (outfile, ".byte\t");
7e047ac2 2870 sb_print (outfile, &acc);
b0f2092b
SC
2871 fprintf (outfile, "\n");
2872 }
2873 sb_kill (&acc);
2874
2875}
2876
e15126c4 2877static int
b0f2092b 2878new_file (name)
19be7c08 2879 const char *name;
b0f2092b
SC
2880{
2881 FILE *newone = fopen (name, "r");
2882 if (!newone)
2883 return 0;
2884
2885 if (isp == MAX_INCLUDES)
a2a1a548 2886 FATAL ((stderr, "Unreasonable include depth (%ld).\n", (long) isp));
b0f2092b
SC
2887
2888 sp++;
2889 sp->handle = newone;
2890
2891 sb_new (&sp->name);
2892 sb_add_string (&sp->name, name);
2893
2894 sp->linecount = 1;
2895 sp->pushback_index = 0;
2896 sp->type = include_file;
2897 sp->index = 0;
2898 sb_new (&sp->pushback);
2899 return 1;
2900}
2901
2902static void
2903do_include (idx, in)
2904 int idx;
2905 sb *in;
2906{
2907 sb t;
4f2f3011 2908 sb cat;
4f2f3011 2909 include_path *includes;
f8d6e6cd 2910
b0f2092b 2911 sb_new (&t);
4f2f3011
SC
2912 sb_new (&cat);
2913
f8d6e6cd
ILT
2914 if (! mri)
2915 idx = getstring (idx, in, &t);
2916 else
2917 {
2918 idx = sb_skip_white (idx, in);
2919 while (idx < in->len && ! ISWHITE (in->ptr[idx]))
2920 {
2921 sb_add_char (&t, in->ptr[idx]);
2922 ++idx;
2923 }
2924 }
4f2f3011
SC
2925
2926 for (includes = paths_head; includes; includes = includes->next)
2927 {
2928 sb_reset (&cat);
2929 sb_add_sb (&cat, &includes->path);
2930 sb_add_char (&cat, '/');
2931 sb_add_sb (&cat, &t);
2932 if (new_file (sb_name (&cat)))
2933 {
2934 break;
2935 }
2936 }
2937 if (!includes)
b0f2092b 2938 {
f8d6e6cd
ILT
2939 if (! new_file (sb_name (&t)))
2940 FATAL ((stderr, "Can't open include file `%s'.\n", sb_name (&t)));
b0f2092b 2941 }
4f2f3011 2942 sb_kill (&cat);
b0f2092b
SC
2943 sb_kill (&t);
2944}
2945
2946static void
2947include_pop ()
2948{
2949 if (sp != include_stack)
2950 {
2951 if (sp->handle)
2952 fclose (sp->handle);
2953 sp--;
2954 }
2955}
2956
2957/* Get the next character from the include stack. If there's anything
2958 in the pushback buffer, take that first. If we're at eof, pop from
2959 the stack and try again. Keep the linecount up to date. */
2960
2961static int
2962get ()
2963{
2964 int r;
2965
2966 if (sp->pushback.len != sp->pushback_index)
2967 {
2968 r = (char) (sp->pushback.ptr[sp->pushback_index++]);
2969 /* When they've all gone, reset the pointer */
2970 if (sp->pushback_index == sp->pushback.len)
2971 {
2972 sp->pushback.len = 0;
2973 sp->pushback_index = 0;
2974 }
2975 }
2976 else if (sp->handle)
2977 {
2978 r = getc (sp->handle);
2979 }
2980 else
2981 r = EOF;
2982
2983 if (r == EOF && isp)
2984 {
2985 include_pop ();
2986 r = get ();
2987 while (r == EOF && isp)
2988 {
2989 include_pop ();
2990 r = get ();
2991 }
2992 return r;
2993 }
2994 if (r == '\n')
2995 {
2996 sp->linecount++;
2997 }
2998
2999 return r;
3000}
3001
3002static int
3003linecount ()
3004{
3005 return sp->linecount;
3006}
3007
3008static int
3009include_next_index ()
3010{
3011 static int index;
3012 if (!unreasonable
3013 && index > MAX_REASONABLE)
3014 FATAL ((stderr, "Unreasonable expansion (-u turns off check).\n"));
3015 return ++index;
3016}
3017
3018
3019/* Initialize the chartype vector. */
3020
3021static void
3022chartype_init ()
3023{
3024 int x;
3025 for (x = 0; x < 256; x++)
3026 {
3027 if (isalpha (x) || x == '_' || x == '$')
3028 chartype[x] |= FIRSTBIT;
3029
f8d6e6cd
ILT
3030 if (mri && x == '.')
3031 chartype[x] |= FIRSTBIT;
3032
b0f2092b
SC
3033 if (isdigit (x) || isalpha (x) || x == '_' || x == '$')
3034 chartype[x] |= NEXTBIT;
3035
3036 if (x == ' ' || x == '\t' || x == ',' || x == '"' || x == ';'
3037 || x == '"' || x == '<' || x == '>' || x == ')' || x == '(')
3038 chartype[x] |= SEPBIT;
3039
13d9fd33
SC
3040 if (x == 'b' || x == 'B'
3041 || x == 'q' || x == 'Q'
3042 || x == 'h' || x == 'H'
3043 || x == 'd' || x == 'D')
3044 chartype [x] |= BASEBIT;
3045
b0f2092b
SC
3046 if (x == ' ' || x == '\t')
3047 chartype[x] |= WHITEBIT;
fa1a86f3
SC
3048
3049 if (x == comment_char)
3050 chartype[x] |= COMMENTBIT;
b0f2092b
SC
3051 }
3052}
3053
3054
fa1a86f3 3055
b0f2092b
SC
3056/* What to do with all the keywords */
3057#define PROCESS 0x1000 /* Run substitution over the line */
3058#define LAB 0x2000 /* Spit out the label */
3059
7f5adcba
ILT
3060#define K_EQU (PROCESS|1)
3061#define K_ASSIGN (PROCESS|2)
3062#define K_REG (PROCESS|3)
3063#define K_ORG (PROCESS|4)
3064#define K_RADIX (PROCESS|5)
3065#define K_DATA (LAB|PROCESS|6)
3066#define K_DATAB (LAB|PROCESS|7)
3067#define K_SDATA (LAB|PROCESS|8)
3068#define K_SDATAB (LAB|PROCESS|9)
3069#define K_SDATAC (LAB|PROCESS|10)
3070#define K_SDATAZ (LAB|PROCESS|11)
3071#define K_RES (LAB|PROCESS|12)
3072#define K_SRES (LAB|PROCESS|13)
3073#define K_SRESC (LAB|PROCESS|14)
3074#define K_SRESZ (LAB|PROCESS|15)
3075#define K_EXPORT (LAB|PROCESS|16)
3076#define K_GLOBAL (LAB|PROCESS|17)
3077#define K_PRINT (LAB|PROCESS|19)
3078#define K_FORM (LAB|PROCESS|20)
3079#define K_HEADING (LAB|PROCESS|21)
3080#define K_PAGE (LAB|PROCESS|22)
3081#define K_IMPORT (LAB|PROCESS|23)
3082#define K_PROGRAM (LAB|PROCESS|24)
3083#define K_END (PROCESS|25)
3084#define K_INCLUDE (PROCESS|26)
3085#define K_IGNORED (PROCESS|27)
3086#define K_ASSIGNA (PROCESS|28)
3087#define K_ASSIGNC (29)
3088#define K_AIF (PROCESS|30)
3089#define K_AELSE (PROCESS|31)
3090#define K_AENDI (PROCESS|32)
3091#define K_AREPEAT (PROCESS|33)
3092#define K_AENDR (PROCESS|34)
3093#define K_AWHILE (35)
3094#define K_AENDW (PROCESS|36)
3095#define K_EXITM (37)
3096#define K_MACRO (PROCESS|38)
3097#define K_ENDM (39)
3098#define K_ALIGN (PROCESS|LAB|40)
3099#define K_ALTERNATE (41)
3100#define K_DB (LAB|PROCESS|42)
3101#define K_DW (LAB|PROCESS|43)
3102#define K_DL (LAB|PROCESS|44)
3103#define K_LOCAL (45)
3104#define K_IFEQ (PROCESS|46)
3105#define K_IFNE (PROCESS|47)
3106#define K_IFLT (PROCESS|48)
3107#define K_IFLE (PROCESS|49)
3108#define K_IFGE (PROCESS|50)
3109#define K_IFGT (PROCESS|51)
3110#define K_IFC (PROCESS|52)
3111#define K_IFNC (PROCESS|53)
3112#define K_IRP (PROCESS|54)
3113#define K_IRPC (PROCESS|55)
b0f2092b
SC
3114
3115
19be7c08 3116struct keyword
b0f2092b
SC
3117{
3118 char *name;
3119 int code;
3120 int extra;
19be7c08
ILT
3121};
3122
3123static struct keyword kinfo[] =
b0f2092b 3124{
950df421 3125 { "EQU", K_EQU, 0 },
fa1a86f3 3126 { "ALTERNATE", K_ALTERNATE, 0 },
950df421
ILT
3127 { "ASSIGN", K_ASSIGN, 0 },
3128 { "REG", K_REG, 0 },
3129 { "ORG", K_ORG, 0 },
3130 { "RADIX", K_RADIX, 0 },
3131 { "DATA", K_DATA, 0 },
fa1a86f3
SC
3132 { "DB", K_DB, 0 },
3133 { "DW", K_DW, 0 },
3134 { "DL", K_DL, 0 },
950df421
ILT
3135 { "DATAB", K_DATAB, 0 },
3136 { "SDATA", K_SDATA, 0 },
3137 { "SDATAB", K_SDATAB, 0 },
3138 { "SDATAZ", K_SDATAZ, 0 },
3139 { "SDATAC", K_SDATAC, 0 },
3140 { "RES", K_RES, 0 },
3141 { "SRES", K_SRES, 0 },
3142 { "SRESC", K_SRESC, 0 },
3143 { "SRESZ", K_SRESZ, 0 },
3144 { "EXPORT", K_EXPORT, 0 },
3145 { "GLOBAL", K_GLOBAL, 0 },
3146 { "PRINT", K_PRINT, 0 },
3147 { "FORM", K_FORM, 0 },
3148 { "HEADING", K_HEADING, 0 },
3149 { "PAGE", K_PAGE, 0 },
3150 { "PROGRAM", K_IGNORED, 0 },
3151 { "END", K_END, 0 },
3152 { "INCLUDE", K_INCLUDE, 0 },
3153 { "ASSIGNA", K_ASSIGNA, 0 },
3154 { "ASSIGNC", K_ASSIGNC, 0 },
3155 { "AIF", K_AIF, 0 },
3156 { "AELSE", K_AELSE, 0 },
3157 { "AENDI", K_AENDI, 0 },
3158 { "AREPEAT", K_AREPEAT, 0 },
3159 { "AENDR", K_AENDR, 0 },
3160 { "EXITM", K_EXITM, 0 },
3161 { "MACRO", K_MACRO, 0 },
3162 { "ENDM", K_ENDM, 0 },
3163 { "AWHILE", K_AWHILE, 0 },
3164 { "ALIGN", K_ALIGN, 0 },
3165 { "AENDW", K_AENDW, 0 },
fa1a86f3
SC
3166 { "ALTERNATE", K_ALTERNATE, 0 },
3167 { "LOCAL", K_LOCAL, 0 },
950df421 3168 { NULL, 0, 0 }
b0f2092b
SC
3169};
3170
19be7c08
ILT
3171/* Although the conditional operators are handled by gas, we need to
3172 handle them here as well, in case they are used in a recursive
3173 macro to end the recursion. */
3174
3175static struct keyword mrikinfo[] =
3176{
19be7c08
ILT
3177 { "IFEQ", K_IFEQ, 0 },
3178 { "IFNE", K_IFNE, 0 },
3179 { "IFLT", K_IFLT, 0 },
3180 { "IFLE", K_IFLE, 0 },
3181 { "IFGE", K_IFGE, 0 },
3182 { "IFGT", K_IFGT, 0 },
3183 { "IFC", K_IFC, 0 },
3184 { "IFNC", K_IFNC, 0 },
3185 { "ELSEC", K_AELSE, 0 },
3186 { "ENDC", K_AENDI, 0 },
3187 { "MEXIT", K_EXITM, 0 },
3188 { "REPT", K_AREPEAT, 0 },
7f5adcba
ILT
3189 { "IRP", K_IRP, 0 },
3190 { "IRPC", K_IRPC, 0 },
19be7c08
ILT
3191 { "ENDR", K_AENDR, 0 },
3192 { NULL, 0, 0 }
3193};
3194
b0f2092b
SC
3195/* Look for a pseudo op on the line. If one's there then call
3196 its handler. */
3197
3198static int
3199process_pseudo_op (idx, line, acc)
3200 int idx;
3201 sb *line;
3202 sb *acc;
3203{
7f5adcba 3204 int oidx = idx;
fa1a86f3 3205
19be7c08 3206 if (line->ptr[idx] == '.' || alternate || mri)
b0f2092b
SC
3207 {
3208 /* Scan forward and find pseudo name */
fa1a86f3 3209 char *in;
b0f2092b
SC
3210 hash_entry *ptr;
3211
fa1a86f3
SC
3212 char *s;
3213 char *e;
3214 if (line->ptr[idx] == '.')
3215 idx++;
3216 in = line->ptr + idx;
3217 s = in;
3218 e = s;
b0f2092b 3219 sb_reset (acc);
fa1a86f3 3220
b0f2092b
SC
3221 while (idx < line->len && *e && ISFIRSTCHAR (*e))
3222 {
3223 sb_add_char (acc, *e);
3224 e++;
3225 idx++;
3226 }
3227
3228 ptr = hash_lookup (&keyword_hash_table, acc);
3229
3230 if (!ptr)
3231 {
fa1a86f3
SC
3232#if 0
3233 /* This one causes lots of pain when trying to preprocess
3234 ordinary code */
b0f2092b 3235 WARNING ((stderr, "Unrecognised pseudo op `%s'.\n", sb_name (acc)));
fa1a86f3 3236#endif
b0f2092b
SC
3237 return 0;
3238 }
3239 if (ptr->value.i & LAB)
3240 { /* output the label */
3241 if (label.len)
3242 {
3243 fprintf (outfile, "%s:\t", sb_name (&label));
3244 }
3245 else
3246 fprintf (outfile, "\t");
3247 }
3248
7f5adcba
ILT
3249 if (mri && ptr->value.i == K_END)
3250 {
3251 sb t;
3252
3253 sb_new (&t);
3254 sb_add_buffer (&t, line->ptr + oidx, idx - oidx);
3255 fprintf (outfile, "\t%s", sb_name (&t));
3256 sb_kill (&t);
3257 }
3258
b0f2092b
SC
3259 if (ptr->value.i & PROCESS)
3260 {
3261 /* Polish the rest of the line before handling the pseudo op */
fa1a86f3
SC
3262#if 0
3263 strip_comments(line);
3264#endif
b0f2092b
SC
3265 sb_reset (acc);
3266 process_assigns (idx, line, acc);
3267 sb_reset(line);
3268 change_base (0, acc, line);
3269 idx = 0;
3270 }
3271 if (!condass_on ())
3272 {
3273 switch (ptr->value.i)
3274 {
13d9fd33 3275 case K_AIF:
6f15d409 3276 do_aif (idx, line);
13d9fd33 3277 break;
b0f2092b
SC
3278 case K_AELSE:
3279 do_aelse ();
3280 break;
3281 case K_AENDI:
3282 do_aendi ();
3283 break;
3284 }
3285 return 1;
3286 }
3287 else
3288 {
3289 switch (ptr->value.i)
3290 {
fa1a86f3
SC
3291 case K_ALTERNATE:
3292 alternate = 1;
987013cd 3293 macro_init (1, mri, 0, exp_get_abs);
fa1a86f3 3294 return 1;
b0f2092b
SC
3295 case K_AELSE:
3296 do_aelse ();
3297 return 1;
3298 case K_AENDI:
3299 do_aendi ();
3300 return 1;
3301 case K_ORG:
3302 ERROR ((stderr, "ORG command not allowed.\n"));
3303 break;
3304 case K_RADIX:
3305 do_radix (line);
3306 return 1;
fa1a86f3
SC
3307 case K_DB:
3308 do_data (idx, line, 1);
3309 return 1;
3310 case K_DW:
3311 do_data (idx, line, 2);
3312 return 1;
3313 case K_DL:
3314 do_data (idx, line, 4);
3315 return 1;
b0f2092b 3316 case K_DATA:
fa1a86f3 3317 do_data (idx, line, 0);
b0f2092b
SC
3318 return 1;
3319 case K_DATAB:
3320 do_datab (idx, line);
3321 return 1;
3322 case K_SDATA:
3323 do_sdata (idx, line, 0);
3324 return 1;
3325 case K_SDATAB:
3326 do_sdatab (idx, line);
3327 return 1;
3328 case K_SDATAC:
3329 do_sdata (idx, line, 'c');
3330 return 1;
3331 case K_SDATAZ:
3332 do_sdata (idx, line, 'z');
3333 return 1;
3334 case K_ASSIGN:
0f68bf0a 3335 do_assign (0, 0, line);
b0f2092b
SC
3336 return 1;
3337 case K_AIF:
3338 do_aif (idx, line);
3339 return 1;
3340 case K_AREPEAT:
3341 do_arepeat (idx, line);
3342 return 1;
3343 case K_AENDW:
3344 do_aendw ();
3345 return 1;
3346 case K_AWHILE:
3347 do_awhile (idx, line);
3348 return 1;
3349 case K_AENDR:
3350 do_aendr ();
3351 return 1;
3352 case K_EQU:
0f68bf0a 3353 do_assign (1, idx, line);
b0f2092b
SC
3354 return 1;
3355 case K_ALIGN:
3356 do_align (idx, line);
3357 return 1;
3358 case K_RES:
3359 do_res (idx, line, 0);
3360 return 1;
3361 case K_SRES:
3362 do_res (idx, line, 's');
3363 return 1;
3364 case K_INCLUDE:
3365 do_include (idx, line);
3366 return 1;
fa1a86f3
SC
3367 case K_LOCAL:
3368 do_local (idx, line);
3369 return 1;
b0f2092b
SC
3370 case K_MACRO:
3371 do_macro (idx, line);
3372 return 1;
3373 case K_ENDM:
3374 do_endm ();
3375 return 1;
3376 case K_SRESC:
3377 do_res (idx, line, 'c');
3378 return 1;
3379 case K_PRINT:
3380 do_print (idx, line);
3381 return 1;
3382 case K_FORM:
3383 do_form (idx, line);
3384 return 1;
3385 case K_HEADING:
3386 do_heading (idx, line);
3387 return 1;
3388 case K_PAGE:
3389 do_page ();
3390 return 1;
3391 case K_GLOBAL:
3392 case K_EXPORT:
3393 do_export (line);
3394 return 1;
3395 case K_IMPORT:
3396 return 1;
3397 case K_SRESZ:
3398 do_res (idx, line, 'z');
3399 return 1;
3400 case K_IGNORED:
3401 return 1;
3402 case K_END:
7f5adcba 3403 do_end (line);
b0f2092b
SC
3404 return 1;
3405 case K_ASSIGNA:
3406 do_assigna (idx, line);
3407 return 1;
3408 case K_ASSIGNC:
3409 do_assignc (idx, line);
3410 return 1;
3411 case K_EXITM:
3412 do_exitm ();
3413 return 1;
3414 case K_REG:
3415 do_reg (idx, line);
3416 return 1;
19be7c08
ILT
3417 case K_IFEQ:
3418 do_if (idx, line, EQ);
3419 return 1;
3420 case K_IFNE:
3421 do_if (idx, line, NE);
3422 return 1;
3423 case K_IFLT:
3424 do_if (idx, line, LT);
3425 return 1;
3426 case K_IFLE:
3427 do_if (idx, line, LE);
3428 return 1;
3429 case K_IFGE:
3430 do_if (idx, line, GE);
3431 return 1;
3432 case K_IFGT:
3433 do_if (idx, line, GT);
3434 return 1;
3435 case K_IFC:
3436 do_ifc (idx, line, 0);
3437 return 1;
3438 case K_IFNC:
3439 do_ifc (idx, line, 1);
3440 return 1;
7f5adcba
ILT
3441 case K_IRP:
3442 do_irp (idx, line, 0);
3443 return 1;
3444 case K_IRPC:
3445 do_irp (idx, line, 1);
3446 return 1;
b0f2092b
SC
3447 }
3448 }
3449 }
3450 return 0;
3451}
3452
3453
3454
19be7c08
ILT
3455/* Add a keyword to the hash table. */
3456
3457static void
3458add_keyword (name, code)
3459 const char *name;
3460 int code;
3461{
3462 sb label;
3463 int j;
3464
3465 sb_new (&label);
3466 sb_add_string (&label, name);
3467
3468 hash_add_to_int_table (&keyword_hash_table, &label, code);
3469
3470 sb_reset (&label);
3471 for (j = 0; name[j]; j++)
3472 sb_add_char (&label, name[j] - 'A' + 'a');
3473 hash_add_to_int_table (&keyword_hash_table, &label, code);
3474
3475 sb_kill (&label);
3476}
3477
b0f2092b
SC
3478/* Build the keyword hash table - put each keyword in the table twice,
3479 once upper and once lower case.*/
3480
3481static void
3482process_init ()
3483{
3484 int i;
3485
3486 for (i = 0; kinfo[i].name; i++)
19be7c08 3487 add_keyword (kinfo[i].name, kinfo[i].code);
b0f2092b 3488
19be7c08
ILT
3489 if (mri)
3490 {
3491 for (i = 0; mrikinfo[i].name; i++)
3492 add_keyword (mrikinfo[i].name, mrikinfo[i].code);
b0f2092b
SC
3493 }
3494}
3495
fa1a86f3
SC
3496
3497static void
3498do_define (string)
19be7c08 3499 const char *string;
fa1a86f3
SC
3500{
3501 sb label;
3502 int res = 1;
3503 hash_entry *ptr;
3504 sb_new (&label);
3505
3506
3507 while (*string)
3508 {
3509 if (*string == '=')
3510 {
3511 sb value;
3512 sb_new (&value);
3513 string++;
3514 while (*string)
3515 {
3516 sb_add_char (&value, *string);
3517 string++;
3518 }
3519 exp_get_abs ("Invalid expression on command line.\n", 0, &value, &res);
3520 sb_kill (&value);
3521 break;
3522 }
3523 sb_add_char (&label, *string);
3524
3525 string ++;
3526 }
3527
3528 ptr = hash_create (&vars, &label);
3529 free_old_entry (ptr);
3530 ptr->type = hash_integer;
3531 ptr->value.i = res;
3532 sb_kill (&label);
3533}
3534char *program_name;
3535
3536/* The list of long options. */
3537static struct option long_options[] =
3538{
3539 { "alternate", no_argument, 0, 'a' },
4f2f3011 3540 { "include", required_argument, 0, 'I' },
fa1a86f3
SC
3541 { "commentchar", required_argument, 0, 'c' },
3542 { "copysource", no_argument, 0, 's' },
3543 { "debug", no_argument, 0, 'd' },
3544 { "help", no_argument, 0, 'h' },
19be7c08 3545 { "mri", no_argument, 0, 'M' },
fa1a86f3
SC
3546 { "output", required_argument, 0, 'o' },
3547 { "print", no_argument, 0, 'p' },
3548 { "unreasonable", no_argument, 0, 'u' },
3549 { "version", no_argument, 0, 'v' },
3550 { "define", required_argument, 0, 'd' },
3551 { NULL, no_argument, 0, 0 }
3552};
3553
3554/* Show a usage message and exit. */
3555static void
3556show_usage (file, status)
3557 FILE *file;
3558 int status;
3559{
3560 fprintf (file, "\
3561Usage: %s \n\
3562 [-a] [--alternate] enter alternate macro mode\n\
3563 [-c char] [--commentchar char] change the comment character from !\n\
3564 [-d] [--debug] print some debugging info\n\
3565 [-h] [--help] print this message\n\
19be7c08 3566 [-M] [--mri] enter MRI compatibility mode\n\
fa1a86f3 3567 [-o out] [--output out] set the output file\n\
1359db1b 3568 [-p] [--print] print line numbers\n", program_name);
dcf62f73 3569 fprintf (file, "\
fa1a86f3
SC
3570 [-s] [--copysource] copy source through as comments \n\
3571 [-u] [--unreasonable] allow unreasonable nesting\n\
3572 [-v] [--version] print the program version\n\
3573 [-Dname=value] create preprocessor variable called name, with value\n\
4f2f3011 3574 [-Ipath] add to include path list\n\
1359db1b 3575 [in-file]\n");
bfc94743
ILT
3576 if (status == 0)
3577 printf ("\nReport bugs to bug-gnu-utils@prep.ai.mit.edu\n");
fa1a86f3
SC
3578 exit (status);
3579}
3580
3581/* Display a help message and exit. */
3582static void
3583show_help ()
3584{
3585 printf ("%s: Gnu Assembler Macro Preprocessor\n",
3586 program_name);
3587 show_usage (stdout, 0);
3588}
3589
b0f2092b 3590int
fa1a86f3
SC
3591main (argc, argv)
3592 int argc;
3593 char **argv;
b0f2092b 3594{
fa1a86f3
SC
3595 int opt;
3596 char *out_name = 0;
b0f2092b
SC
3597 sp = include_stack;
3598
3599 ifstack[0].on = 1;
3600 ifi = 0;
3601
fa1a86f3
SC
3602
3603
3604 program_name = argv[0];
3605 xmalloc_set_program_name (program_name);
b0f2092b 3606
b0f2092b
SC
3607 hash_new_table (101, &keyword_hash_table);
3608 hash_new_table (101, &assign_hash_table);
3609 hash_new_table (101, &vars);
3610
3611 sb_new (&label);
b0f2092b 3612
19be7c08 3613 while ((opt = getopt_long (argc, argv, "I:sdhavc:upo:D:M", long_options,
fa1a86f3
SC
3614 (int *) NULL))
3615 != EOF)
b0f2092b 3616 {
fa1a86f3 3617 switch (opt)
b0f2092b 3618 {
fa1a86f3
SC
3619 case 'o':
3620 out_name = optarg;
3621 break;
3622 case 'u':
3623 unreasonable = 1;
3624 break;
4f2f3011
SC
3625 case 'I':
3626 {
3627 include_path *p = (include_path *) xmalloc (sizeof (include_path));
3628 sb_new (&p->path);
3629 sb_add_string (&p->path, optarg);
3630 if (paths_tail)
3631 paths_tail->next = p;
3632 else
3633 paths_head = p;
3634 paths_tail = p;
3635 }
3636 break;
fa1a86f3
SC
3637 case 'p':
3638 print_line_number = 1;
3639 break;
3640 case 'c':
3641 comment_char = optarg[0];
3642 break;
3643 case 'a':
3644 alternate = 1;
3645 break;
3646 case 's':
3647 copysource = 1;
3648 break;
3649 case 'd':
3650 stats = 1;
3651 break;
3652 case 'D':
3653 do_define (optarg);
3654 break;
19be7c08
ILT
3655 case 'M':
3656 mri = 1;
f8d6e6cd 3657 comment_char = ';';
19be7c08 3658 break;
fa1a86f3
SC
3659 case 'h':
3660 show_help ();
3661 /*NOTREACHED*/
3662 case 'v':
bfc94743
ILT
3663 /* This output is intended to follow the GNU standards document. */
3664 printf ("GNU assembler pre-processor %s\n", program_version);
3665 printf ("Copyright 1996 Free Software Foundation, Inc.\n");
3666 printf ("\
3667This program is free software; you may redistribute it under the terms of\n\
3668the GNU General Public License. This program has absolutely no warranty.\n");
fa1a86f3
SC
3669 exit (0);
3670 /*NOTREACHED*/
3671 case 0:
3672 break;
3673 default:
3674 show_usage (stderr, 1);
3675 /*NOTREACHED*/
b0f2092b
SC
3676 }
3677 }
3678
19be7c08 3679 process_init ();
fa1a86f3 3680
987013cd 3681 macro_init (alternate, mri, 0, exp_get_abs);
7e047ac2 3682
fa1a86f3
SC
3683 if (out_name) {
3684 outfile = fopen (out_name, "w");
3685 if (!outfile)
3686 {
3687 fprintf (stderr, "%s: Can't open output file `%s'.\n",
3688 program_name, out_name);
3689 exit (1);
3690 }
3691 }
3692 else {
3693 outfile = stdout;
3694 }
3695
3696 chartype_init ();
b0f2092b
SC
3697 if (!outfile)
3698 outfile = stdout;
3699
3700 /* Process all the input files */
3701
fa1a86f3 3702 while (optind < argc)
b0f2092b 3703 {
fa1a86f3 3704 if (new_file (argv[optind]))
b0f2092b 3705 {
fa1a86f3 3706 process_file ();
b0f2092b
SC
3707 }
3708 else
3709 {
fa1a86f3
SC
3710 fprintf (stderr, "%s: Can't open input file `%s'.\n",
3711 program_name, argv[optind]);
3712 exit (1);
b0f2092b 3713 }
fa1a86f3 3714 optind++;
b0f2092b 3715 }
fa1a86f3 3716
b0f2092b
SC
3717 quit ();
3718 return 0;
3719}
69cc18d2
ILT
3720
3721/* This function is used because an abort in some of the other files
3722 may be compiled into as_abort because they include as.h. */
3723
3724void
3725as_abort (file, line, fn)
3726 const char *file, *fn;
3727 int line;
3728{
3729 fprintf (stderr, "Internal error, aborting at %s line %d", file, line);
3730 if (fn)
3731 fprintf (stderr, " in %s", fn);
3732 fprintf (stderr, "\nPlease report this bug.\n");
3733 exit (1);
3734}
This page took 0.285296 seconds and 4 git commands to generate.