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