1 /* gasp.c - Gnu assembler preprocessor main program.
2 Copyright (C) 1994 Free Software Foundation, Inc.
4 Written by Steve and Judy Chamberlain of Cygnus Support,
7 This file is part of GASP, the GNU Assembler Preprocessor.
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)
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.
19 You should have received a copy of the GNU General Public License
20 along with GASP; see the file COPYING. If not, write to
21 the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
25 This program translates the input macros and stuff into a form
26 suitable for gas to consume.
29 gasp [-sdhau] [-c char] [-o <outfile>] <infile>*
31 -s copy source to output
32 -c <char> comments are started with <char> instead of !
33 -u allow unreasonable stuff
35 -d print debugging stats
36 -s semi colons start comments
37 -a use alternate syntax
38 Pseudo ops can start with or without a .
39 Labels have to be in first column.
40 -I specify include dir
41 Macro arg parameters subsituted by name, don't need the &.
42 String can start with ' too.
43 Strings can be surrounded by <..>
44 A %<exp> in a string evaluates the expression
45 Literal char in a string with !
61 #ifdef NEED_MALLOC_DECLARATION
62 extern char *malloc ();
65 #include "libiberty.h"
67 char *program_version
= "1.2";
69 #define MAX_INCLUDES 30 /* Maximum include depth */
70 #define MAX_REASONABLE 1000 /* Maximum number of expansions */
72 int unreasonable
; /* -u on command line */
73 int stats
; /* -d on command line */
74 int print_line_number
; /* -p flag on command line */
75 int copysource
; /* -c flag on command line */
76 int warnings
; /* Number of WARNINGs generated so far. */
77 int errors
; /* Number of ERRORs generated so far. */
78 int fatals
; /* Number of fatal ERRORs generated so far (either 0 or 1). */
79 int alternate
= 0; /* -a on command line */
80 char comment_char
= '!';
81 int radix
= 10; /* Default radix */
83 int had_end
; /* Seen .END */
85 /* The output stream */
89 /* Forward declarations. */
90 static int condass_lookup_name();
91 static int condass_on();
93 static int get_and_process();
94 static int get_token();
95 static int getstring();
96 static int include_next_index();
97 static int macro_op();
98 static int linecount();
99 static int process_pseudo_op();
100 static void include_pop();
101 static void include_print_where_line();
104 I had a couple of choices when deciding upon this data structure.
105 gas uses null terminated strings for all its internal work. This
106 often means that parts of the program that want to examine
107 substrings have to manipulate the data in the string to do the
108 right thing (a common operation is to single out a bit of text by
109 saving away the character after it, nulling it out, operating on
110 the substring and then replacing the character which was under the
111 null). This is a pain and I remember a load of problems that I had with
112 code in gas which almost got this right. Also, it's harder to grow and
113 allocate null terminated strings efficiently.
115 Obstacks provide all the functionality needed, but are too
116 complicated, hence the sb.
118 An sb is allocated by the caller, and is initialzed to point to an
119 sb_element. sb_elements are kept on a free lists, and used when
120 needed, replaced onto the free list when unused.
123 #define max_power_two 30 /* don't allow strings more than
124 2^max_power_two long */
125 /* structure of an sb */
128 char *ptr
; /* points to the current block. */
129 int len
; /* how much is used. */
130 int pot
; /* the maximum length is 1<<pot */
135 /* Structure of the free list object of an sb */
147 sb_element
*size
[max_power_two
];
150 sb_list_vector free_list
;
152 int string_count
[max_power_two
];
154 /* the attributes of each character are stored as a bit pattern
155 chartype, which gives us quick tests. */
162 #define COMMENTBIT 16
164 #define ISCOMMENTCHAR(x) (chartype[(unsigned)(x)] & COMMENTBIT)
165 #define ISFIRSTCHAR(x) (chartype[(unsigned)(x)] & FIRSTBIT)
166 #define ISNEXTCHAR(x) (chartype[(unsigned)(x)] & NEXTBIT)
167 #define ISSEP(x) (chartype[(unsigned)(x)] & SEPBIT)
168 #define ISWHITE(x) (chartype[(unsigned)(x)] & WHITEBIT)
169 #define ISBASE(x) (chartype[(unsigned)(x)] & BASEBIT)
170 static char chartype
[256];
173 /* Conditional assembly uses the `ifstack'. Each aif pushes another
174 entry onto the stack, and sets the on flag if it should. The aelse
175 sets hadelse, and toggles on. An aend pops a level. We limit to
176 100 levels of nesting, not because we're facists pigs with read
177 only minds, but because more than 100 levels of nesting is probably
178 a bug in the user's macro structure. */
180 #define IFNESTING 100
183 int on
; /* is the level being output */
184 int hadelse
; /* has an aelse been seen */
189 /* The final and intermediate results of expression evaluation are kept in
190 exp_t's. Note that a symbol is not an sb, but a pointer into the input
191 line. It must be coped somewhere safe before the next line is read in. */
202 int value
; /* constant part */
203 symbol add_symbol
; /* name part */
204 symbol sub_symbol
; /* name part */
209 /* Hashing is done in a pretty standard way. A hash_table has a
210 pointer to a vector of pointers to hash_entrys, and the size of the
211 vector. A hash_entry contains a union of all the info we like to
212 store in hash table. If there is a hash collision, hash_entries
213 with the same hash are kept in a chain. */
215 /* What the data in a hash_entry means */
218 hash_integer
, /* name->integer mapping */
219 hash_string
, /* name->string mapping */
220 hash_macro
, /* name is a macro */
221 hash_formal
/* name is a formal argument */
226 sb key
; /* symbol name */
227 hash_type type
; /* symbol meaning */
232 struct macro_struct
*m
;
233 struct formal_struct
*f
;
235 struct hs
*next
; /* next hash_entry with same hash key */
245 /* Structures used to store macros.
247 Each macro knows its name and included text. It gets built with a
248 list of formal arguments, and also keeps a hash table which points
249 into the list to speed up formal search. Each formal knows its
250 name and its default value. Each time the macro is expanded, the
251 formals get the actual values attatched to them. */
253 /* describe the formal arguments to a macro */
255 typedef struct formal_struct
257 struct formal_struct
*next
; /* next formal in list */
258 sb name
; /* name of the formal */
259 sb def
; /* the default value */
260 sb actual
; /* the actual argument (changed on each expansion) */
261 int index
; /* the index of the formal 0..formal_count-1 */
265 /* describe the macro. */
267 typedef struct macro_struct
269 sb sub
; /* substitution text. */
270 int formal_count
; /* number of formal args. */
271 formal_entry
*formals
; /* pointer to list of formal_structs */
272 hash_table formal_hash
; /* hash table of formals. */
276 /* how we nest files and expand macros etc.
278 we keep a stack of of include_stack structs. each include file
279 pushes a new level onto the stack. we keep an sb with a pushback
280 too. unget chars are pushed onto the pushback sb, getchars first
281 checks the pushback sb before reading from the input stream.
283 small things are expanded by adding the text of the item onto the
284 pushback sb. larger items are grown by pushing a new level and
285 allocating the entire pushback buf for the item. each time
286 something like a macro is expanded, the stack index is changed. we
287 can then perform an exitm by popping all entries off the stack with
288 the same stack index. if we're being reasonable, we can detect
289 recusive expansion by checking the index is reasonably small.
294 include_file
, include_repeat
, include_while
, include_macro
299 sb pushback
; /* current pushback stream */
300 int pushback_index
; /* next char to read from stream */
301 FILE *handle
; /* open file */
302 sb name
; /* name of file */
303 int linecount
; /* number of lines read so far */
305 int index
; /* index of this layer */
307 include_stack
[MAX_INCLUDES
];
309 struct include_stack
*sp
;
310 #define isp (sp - include_stack)
316 /* Include file list */
318 typedef struct include_path
320 struct include_path
*next
;
324 include_path
*paths_head
;
325 include_path
*paths_tail
;
328 void include_print_where_line ();
332 do { include_print_where_line (stderr); fprintf x ; fatals++; quit(); } while(0)
334 do { include_print_where_line (stderr); fprintf x; errors++; } while(0)
336 do { include_print_where_line (stderr); fprintf x; warnings++;} while(0)
340 /* exit the program and return the right ERROR code. */
353 for (i
= 0; i
< max_power_two
; i
++)
355 fprintf (stderr
, "strings size %8d : %d\n", 1<<i
, string_count
[i
]);
362 /* this program is about manipulating strings.
363 they are managed in things called `sb's which is an abbreviation
364 for string buffers. an sb has to be created, things can be glued
365 on to it, and at the end of it's life it should be freed. the
366 contents should never be pointed at whilst it is still growing,
367 since it could be moved at any time
371 sb_grow... (&foo,...);
377 /* initializes an sb. */
384 /* see if we can find one to allocate */
387 if (size
> max_power_two
)
389 FATAL ((stderr
, "string longer than %d bytes requested.\n",
390 1 << max_power_two
));
392 e
= free_list
.size
[size
];
395 /* nothing there, allocate one and stick into the free list */
396 e
= (sb_element
*) xmalloc (sizeof (sb_element
) + (1 << size
));
397 e
->next
= free_list
.size
[size
];
399 free_list
.size
[size
] = e
;
400 string_count
[size
]++;
403 /* remove from free list */
405 free_list
.size
[size
] = e
->next
;
407 /* copy into callers world */
419 sb_build (ptr
, dsize
);
422 /* deallocate the sb at ptr */
429 /* return item to free list */
430 ptr
->item
->next
= free_list
.size
[ptr
->pot
];
431 free_list
.size
[ptr
->pot
] = ptr
->item
;
434 /* add the sb at s to the end of the sb at ptr */
436 static void sb_check ();
444 sb_check (ptr
, s
->len
);
445 memcpy (ptr
->ptr
+ ptr
->len
, s
->ptr
, s
->len
);
449 /* make sure that the sb at ptr has room for another len characters,
450 and grow it if it doesn't. */
457 if (ptr
->len
+ len
>= 1 << ptr
->pot
)
461 while (ptr
->len
+ len
>= 1 << pot
)
463 sb_build (&tmp
, pot
);
464 sb_add_sb (&tmp
, ptr
);
470 /* make the sb at ptr point back to the beginning. */
479 /* add character c to the end of the sb at ptr. */
487 ptr
->ptr
[ptr
->len
++] = c
;
490 /* add null terminated string s to the end of sb at ptr. */
493 sb_add_string (ptr
, s
)
497 int len
= strlen (s
);
499 memcpy (ptr
->ptr
+ ptr
->len
, s
, len
);
503 /* add string at s of length len to sb at ptr */
506 sb_add_buffer (ptr
, s
, len
)
512 memcpy (ptr
->ptr
+ ptr
->len
, s
, len
);
517 /* print the sb at ptr to the output file */
527 for (i
= 0; i
< ptr
->len
; i
++)
531 fprintf (outfile
, ",");
533 fprintf (outfile
, "%d", ptr
->ptr
[i
]);
540 sb_print_at (idx
, ptr
)
545 for (i
= idx
; i
< ptr
->len
; i
++)
546 putc (ptr
->ptr
[i
], outfile
);
548 /* put a null at the end of the sb at in and return the start of the
549 string, so that it can be used as an arg to printf %s. */
556 /* stick a null on the end of the string */
561 /* start at the index idx into the string in sb at ptr and skip
562 whitespace. return the index of the first non whitespace character */
565 sb_skip_white (idx
, ptr
)
569 while (idx
< ptr
->len
&& ISWHITE (ptr
->ptr
[idx
]))
574 /* start at the index idx into the sb at ptr. skips whitespace,
575 a comma and any following whitespace. returnes the index of the
579 sb_skip_comma (idx
, ptr
)
583 while (idx
< ptr
->len
&& ISWHITE (ptr
->ptr
[idx
]))
587 && ptr
->ptr
[idx
] == ',')
590 while (idx
< ptr
->len
&& ISWHITE (ptr
->ptr
[idx
]))
597 /* hash table maintenance. */
599 /* build a new hash table with size buckets, and fill in the info at ptr. */
602 hash_new_table (size
, ptr
)
608 ptr
->table
= (hash_entry
**) xmalloc (size
* (sizeof (hash_entry
*)));
609 /* Fill with null-pointer, not zero-bit-pattern. */
610 for (i
= 0; i
< size
; i
++)
614 /* calculate and return the hash value of the sb at key. */
623 for (i
= 0; i
< key
->len
; i
++)
631 /* lookup key in hash_table tab, if present, then return it, otherwise
632 build a new one and fill it with hash_integer. */
636 hash_create (tab
, key
)
640 int k
= hash (key
) % tab
->size
;
642 hash_entry
**table
= tab
->table
;
650 hash_entry
*n
= (hash_entry
*) xmalloc (sizeof (hash_entry
));
653 sb_add_sb (&n
->key
, key
);
655 n
->type
= hash_integer
;
658 if (strncmp (table
[k
]->key
.ptr
, key
->ptr
, key
->len
) == 0)
666 /* add sb name with key into hash_table tab. if replacing old value
667 and again, then ERROR. */
671 hash_add_to_string_table (tab
, key
, name
, again
)
677 hash_entry
*ptr
= hash_create (tab
, key
);
678 if (ptr
->type
== hash_integer
)
680 sb_new (&ptr
->value
.s
);
682 if (ptr
->value
.s
.len
)
685 ERROR ((stderr
, "redefintion not allowed"));
688 ptr
->type
= hash_string
;
689 sb_reset (&ptr
->value
.s
);
691 sb_add_sb (&ptr
->value
.s
, name
);
694 /* add integer name to hash_table tab with sb key. */
698 hash_add_to_int_table (tab
, key
, name
)
703 hash_entry
*ptr
= hash_create (tab
, key
);
707 /* lookup sb key in hash_table tab. if found return hash_entry result,
712 hash_lookup (tab
, key
)
716 int k
= hash (key
) % tab
->size
;
717 hash_entry
**table
= tab
->table
;
718 hash_entry
*p
= table
[k
];
721 if (p
->key
.len
== key
->len
722 && strncmp (p
->key
.ptr
, key
->ptr
, key
->len
) == 0)
732 are handled in a really simple recursive decent way. each bit of
733 the machine takes an index into an sb and a pointer to an exp_t,
734 modifies the *exp_t and returns the index of the first character
735 past the part of the expression parsed.
737 expression precedence:
748 /* make sure that the exp_t at term is constant, if not the give the op ERROR. */
752 checkconst (op
, term
)
756 if (term
->add_symbol
.len
757 || term
->sub_symbol
.len
)
759 ERROR ((stderr
, "the %c operator cannot take non-absolute arguments.\n", op
));
763 /* turn the number in string at idx into a number of base,
764 fill in ptr and return the index of the first character not in the
769 sb_strtol (idx
, string
, base
, ptr
)
776 idx
= sb_skip_white (idx
, string
);
778 while (idx
< string
->len
)
780 int ch
= string
->ptr
[idx
];
784 else if (ch
>= 'a' && ch
<= 'f')
786 else if (ch
>= 'A' && ch
<= 'F')
794 value
= value
* base
+ dig
;
801 static int level_5 ();
804 level_0 (idx
, string
, lhs
)
809 lhs
->add_symbol
.len
= 0;
810 lhs
->add_symbol
.name
= 0;
812 lhs
->sub_symbol
.len
= 0;
813 lhs
->sub_symbol
.name
= 0;
815 idx
= sb_skip_white (idx
, string
);
819 if (isdigit (string
->ptr
[idx
]))
821 idx
= sb_strtol (idx
, string
, 10, &lhs
->value
);
823 else if (ISFIRSTCHAR (string
->ptr
[idx
]))
826 lhs
->add_symbol
.name
= string
->ptr
+ idx
;
827 while (idx
< string
->len
&& ISNEXTCHAR (string
->ptr
[idx
]))
832 lhs
->add_symbol
.len
= len
;
834 else if (string
->ptr
[idx
] == '"')
838 ERROR ((stderr
, "string where expression expected.\n"));
839 idx
= getstring (idx
, string
, &acc
);
844 ERROR ((stderr
, "can't find primary in expression.\n"));
847 return sb_skip_white (idx
, string
);
853 level_1 (idx
, string
, lhs
)
858 idx
= sb_skip_white (idx
, string
);
860 switch (string
->ptr
[idx
])
863 idx
= level_1 (idx
+ 1, string
, lhs
);
866 idx
= level_1 (idx
+ 1, string
, lhs
);
867 checkconst ('~', lhs
);
868 lhs
->value
= ~lhs
->value
;
873 idx
= level_1 (idx
+ 1, string
, lhs
);
874 lhs
->value
= -lhs
->value
;
876 lhs
->add_symbol
= lhs
->sub_symbol
;
882 idx
= level_5 (sb_skip_white (idx
, string
), string
, lhs
);
883 if (string
->ptr
[idx
] != ')')
884 ERROR ((stderr
, "misplaced closing parens.\n"));
889 idx
= level_0 (idx
, string
, lhs
);
892 return sb_skip_white (idx
, string
);
896 level_2 (idx
, string
, lhs
)
903 idx
= level_1 (idx
, string
, lhs
);
905 while (idx
< string
->len
&& (string
->ptr
[idx
] == '*'
906 || string
->ptr
[idx
] == '/'))
908 char op
= string
->ptr
[idx
++];
909 idx
= level_1 (idx
, string
, &rhs
);
913 checkconst ('*', lhs
);
914 checkconst ('*', &rhs
);
915 lhs
->value
*= rhs
.value
;
918 checkconst ('/', lhs
);
919 checkconst ('/', &rhs
);
921 ERROR ((stderr
, "attempt to divide by zero.\n"));
923 lhs
->value
/= rhs
.value
;
927 return sb_skip_white (idx
, string
);
932 level_3 (idx
, string
, lhs
)
939 idx
= level_2 (idx
, string
, lhs
);
941 while (idx
< string
->len
942 && (string
->ptr
[idx
] == '+'
943 || string
->ptr
[idx
] == '-'))
945 char op
= string
->ptr
[idx
++];
946 idx
= level_2 (idx
, string
, &rhs
);
950 lhs
->value
+= rhs
.value
;
951 if (lhs
->add_symbol
.name
&& rhs
.add_symbol
.name
)
953 ERROR ((stderr
, "can't add two relocatable expressions\n"));
955 /* change nn+symbol to symbol + nn */
956 if (rhs
.add_symbol
.name
)
958 lhs
->add_symbol
= rhs
.add_symbol
;
962 lhs
->value
-= rhs
.value
;
963 lhs
->sub_symbol
= rhs
.add_symbol
;
967 return sb_skip_white (idx
, string
);
971 level_4 (idx
, string
, lhs
)
978 idx
= level_3 (idx
, string
, lhs
);
980 while (idx
< string
->len
&&
981 string
->ptr
[idx
] == '&')
983 char op
= string
->ptr
[idx
++];
984 idx
= level_3 (idx
, string
, &rhs
);
988 checkconst ('&', lhs
);
989 checkconst ('&', &rhs
);
990 lhs
->value
&= rhs
.value
;
994 return sb_skip_white (idx
, string
);
998 level_5 (idx
, string
, lhs
)
1005 idx
= level_4 (idx
, string
, lhs
);
1007 while (idx
< string
->len
1008 && (string
->ptr
[idx
] == '|' || string
->ptr
[idx
] == '~'))
1010 char op
= string
->ptr
[idx
++];
1011 idx
= level_4 (idx
, string
, &rhs
);
1015 checkconst ('|', lhs
);
1016 checkconst ('|', &rhs
);
1017 lhs
->value
|= rhs
.value
;
1020 checkconst ('~', lhs
);
1021 checkconst ('~', &rhs
);
1022 lhs
->value
^= rhs
.value
;
1026 return sb_skip_white (idx
, string
);
1030 /* parse the expression at offset idx into string, fill up res with
1031 the result. return the index of the first char past the expression.
1035 exp_parse (idx
, string
, res
)
1040 return level_5 (sb_skip_white (idx
, string
), string
, res
);
1044 /* turn the expression at exp into text and glue it onto the end of
1048 exp_string (exp
, string
)
1056 if (exp
->add_symbol
.len
)
1058 sb_add_buffer (string
, exp
->add_symbol
.name
, exp
->add_symbol
.len
);
1066 sb_add_char (string
, '+');
1067 sprintf (buf
, "%d", exp
->value
);
1068 sb_add_string (string
, buf
);
1072 if (exp
->sub_symbol
.len
)
1074 sb_add_char (string
, '-');
1075 sb_add_buffer (string
, exp
->add_symbol
.name
, exp
->add_symbol
.len
);
1081 sb_add_char (string
, '0');
1085 /* parse the expression at offset idx into sb in, return the value in val.
1086 if the expression is not constant, give ERROR emsg. returns the index
1087 of the first character past the end of the expression. */
1090 exp_get_abs (emsg
, idx
, in
, val
)
1097 idx
= exp_parse (idx
, in
, &res
);
1098 if (res
.add_symbol
.len
|| res
.sub_symbol
.len
)
1099 ERROR ((stderr
, emsg
));
1105 sb label
; /* current label parsed from line */
1106 hash_table assign_hash_table
; /* hash table for all assigned variables */
1107 hash_table keyword_hash_table
; /* hash table for keyword */
1108 hash_table vars
; /* hash table for eq variables */
1110 #define in_comment ';'
1114 strip_comments (out
)
1119 for (i
= 0; i
< out
->len
; i
++)
1121 if (ISCOMMENTCHAR(s
[i
]))
1130 /* push back character ch so that it can be read again. */
1140 if (sp
->pushback_index
)
1141 sp
->pushback_index
--;
1143 sb_add_char (&sp
->pushback
, ch
);
1146 /* push the sb ptr onto the include stack, with the given name, type and index. */
1150 include_buf (name
, ptr
, type
, index
)
1157 if (sp
- include_stack
>= MAX_INCLUDES
)
1158 FATAL ((stderr
, "unreasonable nesting.\n"));
1160 sb_add_sb (&sp
->name
, name
);
1163 sp
->pushback_index
= 0;
1166 sb_new (&sp
->pushback
);
1167 sb_add_sb (&sp
->pushback
, ptr
);
1171 /* used in ERROR messages, print info on where the include stack is onto file. */
1174 include_print_where_line (file
)
1177 struct include_stack
*p
= include_stack
+ 1;
1181 fprintf (file
, "%s:%d ", sb_name (&p
->name
), p
->linecount
- ((p
== sp
) ? 1 : 0));
1186 /* used in listings, print the line number onto file. */
1188 include_print_line (file
)
1192 struct include_stack
*p
= include_stack
+ 1;
1194 n
= fprintf (file
, "%4d", p
->linecount
);
1198 n
+= fprintf (file
, ".%d", p
->linecount
);
1203 fprintf (file
, " ");
1209 /* read a line from the top of the include stack into sb in. */
1220 putc (comment_char
, outfile
);
1221 if (print_line_number
)
1222 include_print_line (outfile
);
1236 WARNING ((stderr
, "End of file not at start of line.\n"));
1238 putc ('\n', outfile
);
1257 /* continued line */
1260 putc (comment_char
, outfile
);
1261 putc ('+', outfile
);
1274 sb_add_char (in
, ch
);
1282 /* find a label from sb in and put it in out. */
1285 grab_label (in
, out
)
1291 if (ISFIRSTCHAR (in
->ptr
[i
]))
1293 sb_add_char (out
, in
->ptr
[i
]);
1295 while ((ISNEXTCHAR (in
->ptr
[i
])
1296 || in
->ptr
[i
] == '\\'
1297 || in
->ptr
[i
] == '&')
1300 sb_add_char (out
, in
->ptr
[i
]);
1307 /* find all strange base stuff and turn into decimal. also
1308 find all the other numbers and convert them from the default radix */
1311 change_base (idx
, in
, out
)
1318 while (idx
< in
->len
)
1320 if (idx
< in
->len
- 1 && in
->ptr
[idx
+ 1] == '\'')
1324 switch (in
->ptr
[idx
])
1343 ERROR ((stderr
, "Illegal base character %c.\n", in
->ptr
[idx
]));
1348 idx
= sb_strtol (idx
+ 2, in
, base
, &value
);
1349 sprintf (buffer
, "%d", value
);
1350 sb_add_string (out
, buffer
);
1352 else if (ISFIRSTCHAR (in
->ptr
[idx
]))
1354 /* copy entire names through quickly */
1355 sb_add_char (out
, in
->ptr
[idx
]);
1357 while (idx
< in
->len
&& ISNEXTCHAR (in
->ptr
[idx
]))
1359 sb_add_char (out
, in
->ptr
[idx
]);
1363 else if (isdigit (in
->ptr
[idx
]))
1366 /* all numbers must start with a digit, let's chew it and
1368 idx
= sb_strtol (idx
, in
, radix
, &value
);
1369 sprintf (buffer
, "%d", value
);
1370 sb_add_string (out
, buffer
);
1372 /* skip all undigsested letters */
1373 while (idx
< in
->len
&& ISNEXTCHAR (in
->ptr
[idx
]))
1375 sb_add_char (out
, in
->ptr
[idx
]);
1379 else if (in
->ptr
[idx
] == '"' || in
->ptr
[idx
] == '\'')
1381 char tchar
= in
->ptr
[idx
];
1382 /* copy entire names through quickly */
1383 sb_add_char (out
, in
->ptr
[idx
]);
1385 while (idx
< in
->len
&& in
->ptr
[idx
] != tchar
)
1387 sb_add_char (out
, in
->ptr
[idx
]);
1393 /* nothing special, just pass it through */
1394 sb_add_char (out
, in
->ptr
[idx
]);
1411 do_assign (again
, idx
, in
)
1416 /* stick label in symbol table with following value */
1421 idx
= exp_parse (idx
, in
, &e
);
1422 exp_string (&e
, &acc
);
1423 hash_add_to_string_table (&assign_hash_table
, &label
, &acc
, again
);
1428 /* .radix [b|q|d|h] */
1435 int idx
= sb_skip_white (0, ptr
);
1436 switch (ptr
->ptr
[idx
])
1455 ERROR ((stderr
, "radix is %c must be one of b, q, d or h", radix
));
1460 /* Parse off a .b, .w or .l */
1463 get_opsize (idx
, in
, size
)
1469 if (in
->ptr
[idx
] == '.')
1473 switch (in
->ptr
[idx
])
1491 ERROR ((stderr
, "size must be one of b, w or l, is %c.\n", in
->ptr
[idx
]));
1504 idx
= sb_skip_white (idx
, line
);
1506 && ISCOMMENTCHAR(line
->ptr
[idx
]))
1508 if (idx
>= line
->len
)
1513 /* .data [.b|.w|.l] <data>*
1514 or d[bwl] <data>* */
1517 do_data (idx
, in
, size
)
1523 char *opname
= ".yikes!";
1529 idx
= get_opsize (idx
, in
, &opsize
);
1548 fprintf (outfile
, "%s\t", opname
);
1550 idx
= sb_skip_white (idx
, in
);
1554 && in
->ptr
[idx
] == '"')
1557 idx
= getstring (idx
, in
, &acc
);
1558 for (i
= 0; i
< acc
.len
; i
++)
1561 fprintf(outfile
,",");
1562 fprintf (outfile
, "%d", acc
.ptr
[i
]);
1567 while (!eol (idx
, in
))
1570 idx
= exp_parse (idx
, in
, &e
);
1571 exp_string (&e
, &acc
);
1572 sb_add_char (&acc
, 0);
1573 fprintf (outfile
, acc
.ptr
);
1574 if (idx
< in
->len
&& in
->ptr
[idx
] == ',')
1576 fprintf (outfile
, ",");
1582 sb_print_at (idx
, in
);
1583 fprintf (outfile
, "\n");
1586 /* .datab [.b|.w|.l] <repeat>,<fill> */
1597 idx
= get_opsize (idx
, in
, &opsize
);
1599 idx
= exp_get_abs ("datab repeat must be constant.\n", idx
, in
, &repeat
);
1600 idx
= sb_skip_comma (idx
, in
);
1601 idx
= exp_get_abs ("datab data must be absolute.\n", idx
, in
, &fill
);
1603 fprintf (outfile
, ".fill\t%d,%d,%d\n", repeat
, opsize
, fill
);
1614 idx
= exp_get_abs ("align needs absolute expression.\n", idx
, in
, &al
);
1619 WARNING ((stderr
, "alignment must be one of 1, 2 or 4.\n"));
1621 fprintf (outfile
, ".align %d\n", al
);
1624 /* .res[.b|.w|.l] <size> */
1627 do_res (idx
, in
, type
)
1635 idx
= get_opsize (idx
, in
, &size
);
1636 while (!eol(idx
, in
))
1638 idx
= sb_skip_white (idx
, in
);
1639 if (in
->ptr
[idx
] == ',')
1641 idx
= exp_get_abs ("res needs absolute expression for fill count.\n", idx
, in
, &count
);
1643 if (type
== 'c' || type
== 'z')
1646 fprintf (outfile
, ".space %d\n", count
* size
);
1657 fprintf (outfile
, ".global %s\n", sb_name (in
));
1660 /* .print [list] [nolist] */
1667 idx
= sb_skip_white (idx
, in
);
1668 while (idx
< in
->len
)
1670 if (strncasecmp (in
->ptr
+ idx
, "LIST", 4) == 0)
1672 fprintf (outfile
, ".list\n");
1675 else if (strncasecmp (in
->ptr
+ idx
, "NOLIST", 6) == 0)
1677 fprintf (outfile
, ".nolist\n");
1686 do_heading (idx
, in
)
1692 idx
= getstring (idx
, in
, &head
);
1693 fprintf (outfile
, ".title \"%s\"\n", sb_name (&head
));
1702 fprintf (outfile
, ".eject\n");
1705 /* .form [lin=<value>] [col=<value>] */
1713 idx
= sb_skip_white (idx
, in
);
1715 while (idx
< in
->len
)
1718 if (strncasecmp (in
->ptr
+ idx
, "LIN=", 4) == 0)
1721 idx
= exp_get_abs ("form LIN= needs absolute expresssion.\n", idx
, in
, &lines
);
1724 if (strncasecmp (in
->ptr
+ idx
, "COL=", 4) == 0)
1727 idx
= exp_get_abs ("form COL= needs absolute expresssion.\n", idx
, in
, &columns
);
1732 fprintf (outfile
, ".psize %d,%d\n", lines
, columns
);
1737 /* Fetch string from the input stream,
1739 'Bxyx<whitespace> -> return 'Bxyza
1740 %<char> -> return string of decimal value of x
1741 "<string>" -> return string
1742 xyx<whitespace> -> return xyz
1745 get_any_string (idx
, in
, out
, expand
, pretend_quoted
)
1753 idx
= sb_skip_white (idx
, in
);
1757 if (in
->len
> 2 && in
->ptr
[idx
+1] == '\'' && ISBASE (in
->ptr
[idx
]))
1759 while (!ISSEP (in
->ptr
[idx
]))
1760 sb_add_char (out
, in
->ptr
[idx
++]);
1762 else if (in
->ptr
[idx
] == '%'
1768 /* Turns the next expression into a string */
1769 idx
= exp_get_abs ("% operator needs absolute expression",
1773 sprintf(buf
, "%d", val
);
1774 sb_add_string (out
, buf
);
1776 else if (in
->ptr
[idx
] == '"'
1777 || in
->ptr
[idx
] == '<'
1778 || (alternate
&& in
->ptr
[idx
] == '\''))
1780 if (alternate
&& expand
)
1782 /* Keep the quotes */
1783 sb_add_char (out
, '\"');
1785 idx
= getstring (idx
, in
, out
);
1786 sb_add_char (out
, '\"');
1790 idx
= getstring (idx
, in
, out
);
1795 while (idx
< in
->len
1796 && (in
->ptr
[idx
] == '"'
1797 || in
->ptr
[idx
] == '\''
1799 || !ISSEP (in
->ptr
[idx
])))
1801 if (in
->ptr
[idx
] == '"'
1802 || in
->ptr
[idx
] == '\'')
1804 char tchar
= in
->ptr
[idx
];
1805 sb_add_char (out
, in
->ptr
[idx
++]);
1806 while (idx
< in
->len
1807 && in
->ptr
[idx
] != tchar
)
1808 sb_add_char (out
, in
->ptr
[idx
++]);
1812 sb_add_char (out
, in
->ptr
[idx
++]);
1821 /* skip along sb in starting at idx, suck off whitespace a ( and more
1822 whitespace. return the idx of the next char */
1825 skip_openp (idx
, in
)
1829 idx
= sb_skip_white (idx
, in
);
1830 if (in
->ptr
[idx
] != '(')
1831 ERROR ((stderr
, "misplaced ( .\n"));
1832 idx
= sb_skip_white (idx
+ 1, in
);
1836 /* skip along sb in starting at idx, suck off whitespace a ) and more
1837 whitespace. return the idx of the next char */
1840 skip_closep (idx
, in
)
1844 idx
= sb_skip_white (idx
, in
);
1845 if (in
->ptr
[idx
] != ')')
1846 ERROR ((stderr
, "misplaced ).\n"));
1847 idx
= sb_skip_white (idx
+ 1, in
);
1854 dolen (idx
, in
, out
)
1863 sb_new (&stringout
);
1864 idx
= skip_openp (idx
, in
);
1865 idx
= get_and_process (idx
, in
, &stringout
);
1866 idx
= skip_closep (idx
, in
);
1867 sprintf (buffer
, "%d", stringout
.len
);
1868 sb_add_string (out
, buffer
);
1870 sb_kill (&stringout
);
1879 doinstr (idx
, in
, out
)
1893 idx
= skip_openp (idx
, in
);
1894 idx
= get_and_process (idx
, in
, &string
);
1895 idx
= sb_skip_comma (idx
, in
);
1896 idx
= get_and_process (idx
, in
, &search
);
1897 idx
= sb_skip_comma (idx
, in
);
1898 if (isdigit (in
->ptr
[idx
]))
1900 idx
= exp_get_abs (".instr needs absolute expresson.\n", idx
, in
, &start
);
1906 idx
= skip_closep (idx
, in
);
1908 for (i
= start
; i
< string
.len
; i
++)
1910 if (strncmp (string
.ptr
+ i
, search
.ptr
, search
.len
) == 0)
1916 sprintf (buffer
, "%d", res
);
1917 sb_add_string (out
, buffer
);
1925 dosubstr (idx
, in
, out
)
1935 idx
= skip_openp (idx
, in
);
1936 idx
= get_and_process (idx
, in
, &string
);
1937 idx
= sb_skip_comma (idx
, in
);
1938 idx
= exp_get_abs ("need absolute position.\n", idx
, in
, &pos
);
1939 idx
= sb_skip_comma (idx
, in
);
1940 idx
= exp_get_abs ("need absolute length.\n", idx
, in
, &len
);
1941 idx
= skip_closep (idx
, in
);
1944 if (len
< 0 || pos
< 0 ||
1946 || pos
+ len
> string
.len
)
1948 sb_add_string (out
, " ");
1952 sb_add_char (out
, '"');
1955 sb_add_char (out
, string
.ptr
[pos
++]);
1958 sb_add_char (out
, '"');
1964 /* scan line, change tokens in the hash table to their replacements */
1966 process_assigns (idx
, in
, buf
)
1971 while (idx
< in
->len
)
1974 if (in
->ptr
[idx
] == '\\'
1975 && in
->ptr
[idx
+ 1] == '&')
1977 idx
= condass_lookup_name (in
, idx
+ 2, buf
, 1);
1979 else if (in
->ptr
[idx
] == '\\'
1980 && in
->ptr
[idx
+ 1] == '$')
1982 idx
= condass_lookup_name (in
, idx
+ 2, buf
, 0);
1984 else if (idx
+ 3 < in
->len
1985 && in
->ptr
[idx
] == '.'
1986 && toupper ((unsigned char) in
->ptr
[idx
+ 1]) == 'L'
1987 && toupper ((unsigned char) in
->ptr
[idx
+ 2]) == 'E'
1988 && toupper ((unsigned char) in
->ptr
[idx
+ 3]) == 'N')
1989 idx
= dolen (idx
+ 4, in
, buf
);
1990 else if (idx
+ 6 < in
->len
1991 && in
->ptr
[idx
] == '.'
1992 && toupper ((unsigned char) in
->ptr
[idx
+ 1]) == 'I'
1993 && toupper ((unsigned char) in
->ptr
[idx
+ 2]) == 'N'
1994 && toupper ((unsigned char) in
->ptr
[idx
+ 3]) == 'S'
1995 && toupper ((unsigned char) in
->ptr
[idx
+ 4]) == 'T'
1996 && toupper ((unsigned char) in
->ptr
[idx
+ 5]) == 'R')
1997 idx
= doinstr (idx
+ 6, in
, buf
);
1998 else if (idx
+ 7 < in
->len
1999 && in
->ptr
[idx
] == '.'
2000 && toupper ((unsigned char) in
->ptr
[idx
+ 1]) == 'S'
2001 && toupper ((unsigned char) in
->ptr
[idx
+ 2]) == 'U'
2002 && toupper ((unsigned char) in
->ptr
[idx
+ 3]) == 'B'
2003 && toupper ((unsigned char) in
->ptr
[idx
+ 4]) == 'S'
2004 && toupper ((unsigned char) in
->ptr
[idx
+ 5]) == 'T'
2005 && toupper ((unsigned char) in
->ptr
[idx
+ 6]) == 'R')
2006 idx
= dosubstr (idx
+ 7, in
, buf
);
2007 else if (ISFIRSTCHAR (in
->ptr
[idx
]))
2009 /* may be a simple name subsitution, see if we have a word */
2012 while (cur
< in
->len
2013 && (ISNEXTCHAR (in
->ptr
[cur
])))
2017 sb_add_buffer (&acc
, in
->ptr
+ idx
, cur
- idx
);
2018 ptr
= hash_lookup (&assign_hash_table
, &acc
);
2021 /* Found a definition for it */
2022 sb_add_sb (buf
, &ptr
->value
.s
);
2026 /* No definition, just copy the word */
2027 sb_add_sb (buf
, &acc
);
2034 sb_add_char (buf
, in
->ptr
[idx
++]);
2040 get_and_process (idx
, in
, out
)
2047 idx
= get_any_string (idx
, in
, &t
, 1, 0);
2048 process_assigns (0, &t
, out
);
2069 more
= get_line (&line
);
2072 /* Find any label and pseudo op that we're intested in */
2077 fprintf (outfile
, "\n");
2081 l
= grab_label (&line
, &label_in
);
2085 /* Munge any label */
2088 process_assigns (0, &label_in
, &label
);
2091 if (line
.ptr
[l
] == ':')
2093 while (ISWHITE (line
.ptr
[l
]) && l
< line
.len
)
2098 if (process_pseudo_op (l
, &line
, &acc
))
2104 else if (condass_on ())
2106 if (macro_op (l
, &line
))
2116 fprintf (outfile
, "%s:\t", sb_name (&label
));
2119 fprintf (outfile
, "\t");
2121 process_assigns (l
, &line
, &t1
);
2123 change_base (0, &t1
, &t2
);
2124 fprintf (outfile
, "%s\n", sb_name (&t2
));
2130 /* Only a label on this line */
2131 if (label
.len
&& condass_on())
2133 fprintf (outfile
, "%s:\n", sb_name (&label
));
2141 more
= get_line (&line
);
2145 WARNING ((stderr
, "END missing from end of file.\n"));
2153 free_old_entry (ptr
)
2158 if (ptr
->type
== hash_string
)
2159 sb_kill(&ptr
->value
.s
);
2163 /* name: .ASSIGNA <value> */
2166 do_assigna (idx
, in
)
2174 process_assigns (idx
, in
, &tmp
);
2175 idx
= exp_get_abs (".ASSIGNA needs constant expression argument.\n", 0, &tmp
, &val
);
2179 ERROR ((stderr
, ".ASSIGNA without label.\n"));
2183 hash_entry
*ptr
= hash_create (&vars
, &label
);
2184 free_old_entry (ptr
);
2185 ptr
->type
= hash_integer
;
2191 /* name: .ASSIGNC <string> */
2194 do_assignc (idx
, in
)
2200 idx
= getstring (idx
, in
, &acc
);
2204 ERROR ((stderr
, ".ASSIGNS without label.\n"));
2208 hash_entry
*ptr
= hash_create (&vars
, &label
);
2209 free_old_entry (ptr
);
2210 ptr
->type
= hash_string
;
2211 sb_new (&ptr
->value
.s
);
2212 sb_add_sb (&ptr
->value
.s
, &acc
);
2218 /* name: .REG (reg) */
2225 /* remove reg stuff from inside parens */
2227 idx
= skip_openp (idx
, in
);
2229 while (idx
< in
->len
&& in
->ptr
[idx
] != ')')
2231 sb_add_char (&what
, in
->ptr
[idx
]);
2234 hash_add_to_string_table (&assign_hash_table
, &label
, &what
, 1);
2240 condass_lookup_name (inbuf
, idx
, out
, warn
)
2248 sb_new (&condass_acc
);
2250 while (idx
< inbuf
->len
2251 && ISNEXTCHAR (inbuf
->ptr
[idx
]))
2253 sb_add_char (&condass_acc
, inbuf
->ptr
[idx
++]);
2256 if (inbuf
->ptr
[idx
] == '\'')
2258 ptr
= hash_lookup (&vars
, &condass_acc
);
2265 WARNING ((stderr
, "Can't find preprocessor variable %s.\n", sb_name (&condass_acc
)));
2269 sb_add_string (out
, "0");
2274 if (ptr
->type
== hash_integer
)
2277 sprintf (buffer
, "%d", ptr
->value
.i
);
2278 sb_add_string (out
, buffer
);
2282 sb_add_sb (out
, &ptr
->value
.s
);
2285 sb_kill (&condass_acc
);
2298 whatcond (idx
, in
, val
)
2305 idx
= sb_skip_white (idx
, in
);
2307 if (idx
+ 1 < in
->len
)
2313 a
= toupper ((unsigned char) p
[0]);
2314 b
= toupper ((unsigned char) p
[1]);
2315 if (a
== 'E' && b
== 'Q')
2317 else if (a
== 'N' && b
== 'E')
2319 else if (a
== 'L' && b
== 'T')
2321 else if (a
== 'L' && b
== 'E')
2323 else if (a
== 'G' && b
== 'T')
2325 else if (a
== 'G' && b
== 'E')
2330 ERROR ((stderr
, "Comparison operator must be one of EQ, NE, LT, LE, GT or GE.\n"));
2333 idx
= sb_skip_white (idx
+ 2, in
);
2350 idx
= sb_skip_white (idx
, in
);
2352 if (in
->ptr
[idx
] == '"')
2356 /* This is a string comparision */
2357 idx
= getstring (idx
, in
, &acc_a
);
2358 idx
= whatcond (idx
, in
, &cond
);
2359 idx
= getstring (idx
, in
, &acc_b
);
2360 same
= acc_a
.len
== acc_b
.len
&& (strncmp (acc_a
.ptr
, acc_b
.ptr
, acc_a
.len
) == 0);
2362 if (cond
!= EQ
&& cond
!= NE
)
2364 ERROR ((stderr
, "Comparison operator for strings must be EQ or NE\n"));
2368 res
= (cond
!= EQ
) ^ same
;
2371 /* This is a numeric expression */
2376 idx
= exp_get_abs ("Conditional operator must have absolute operands.\n", idx
, in
, &vala
);
2377 idx
= whatcond (idx
, in
, &cond
);
2378 idx
= sb_skip_white (idx
, in
);
2379 if (in
->ptr
[idx
] == '"')
2381 WARNING ((stderr
, "String compared against expression.\n"));
2386 idx
= exp_get_abs ("Conditional operator must have absolute operands.\n", idx
, in
, &valb
);
2429 if (ifi
>= IFNESTING
)
2431 FATAL ((stderr
, "AIF nesting unreasonable.\n"));
2434 ifstack
[ifi
].on
= ifstack
[ifi
-1].on
? istrue (idx
, in
) : 0;
2435 ifstack
[ifi
].hadelse
= 0;
2443 ifstack
[ifi
].on
= ifstack
[ifi
-1].on
? !ifstack
[ifi
].on
: 0;
2444 if (ifstack
[ifi
].hadelse
)
2446 ERROR ((stderr
, "Multiple AELSEs in AIF.\n"));
2448 ifstack
[ifi
].hadelse
= 1;
2462 ERROR ((stderr
, "AENDI without AIF.\n"));
2469 return ifstack
[ifi
].on
;
2473 /* Read input lines till we get to a TO string.
2474 Increase nesting depth if we geta FROM string.
2475 Put the results into sb at PTR. */
2478 buffer_and_nest (from
, to
, ptr
)
2483 int from_len
= strlen (from
);
2484 int to_len
= strlen (to
);
2486 int line_start
= ptr
->len
;
2487 int line
= linecount ();
2489 int more
= get_line (ptr
);
2493 /* Try and find the first pseudo op on the line */
2498 /* With normal syntax we can suck what we want till we get to the dot.
2499 With the alternate, labels have to start in the first column, since
2500 we cant tell what's a label and whats a pseudoop */
2502 /* Skip leading whitespace */
2504 && ISWHITE (ptr
->ptr
[i
]))
2507 /* Skip over a label */
2509 && ISNEXTCHAR (ptr
->ptr
[i
]))
2514 && ptr
->ptr
[i
] == ':')
2518 /* Skip trailing whitespace */
2520 && ISWHITE (ptr
->ptr
[i
]))
2523 if (i
< ptr
->len
&& (ptr
->ptr
[i
] == '.'
2526 if (ptr
->ptr
[i
] == '.')
2528 if (strncasecmp (ptr
->ptr
+ i
, from
, from_len
) == 0)
2530 if (strncasecmp (ptr
->ptr
+ i
, to
, to_len
) == 0)
2535 /* Reset the string to not include the ending rune */
2536 ptr
->len
= line_start
;
2542 /* Add a CR to the end and keep running */
2543 sb_add_char (ptr
, '\n');
2544 line_start
= ptr
->len
;
2545 more
= get_line (ptr
);
2550 FATAL ((stderr
, "End of file whilst inside %s, started on line %d.\n", from
, line
));
2558 ERROR ((stderr
, "AENDR without a AREPEAT.\n"));
2577 process_assigns (idx
, in
, &exp
);
2578 doit
= istrue (0, &exp
);
2580 buffer_and_nest ("AWHILE", "AENDW", &sub
);
2595 int index
= include_next_index ();
2599 sb_add_sb (©
, &sub
);
2600 sb_add_sb (©
, in
);
2601 sb_add_string (©
, "\n");
2602 sb_add_sb (©
, &sub
);
2603 sb_add_string (©
, "\t.AENDW\n");
2604 /* Push another WHILE */
2605 include_buf (&exp
, ©
, include_while
, index
);
2618 ERROR ((stderr
, "AENDW without a AENDW.\n"));
2624 Pop things off the include stack until the type and index changes */
2629 include_type type
= sp
->type
;
2630 if (type
== include_repeat
2631 || type
== include_while
2632 || type
== include_macro
)
2634 int index
= sp
->index
;
2636 while (sp
->index
== index
2637 && sp
->type
== type
)
2647 do_arepeat (idx
, in
)
2651 sb exp
; /* buffer with expression in it */
2652 sb copy
; /* expanded repeat block */
2653 sb sub
; /* contents of AREPEAT */
2659 process_assigns (idx
, in
, &exp
);
2660 idx
= exp_get_abs ("AREPEAT must have absolute operand.\n", 0, &exp
, &rc
);
2661 buffer_and_nest ("AREPEAT", "AENDR", &sub
);
2664 /* Push back the text following the repeat, and another repeat block
2675 int index
= include_next_index ();
2676 sb_add_sb (©
, &sub
);
2679 sprintf (buffer
, "\t.AREPEAT %d\n", rc
- 1);
2680 sb_add_string (©
, buffer
);
2681 sb_add_sb (©
, &sub
);
2682 sb_add_string (©
, " .AENDR\n");
2685 include_buf (&exp
, ©
, include_repeat
, index
);
2697 ERROR ((stderr
, ".ENDM without a matching .MACRO.\n"));
2701 /* MARRO PROCESSING */
2704 hash_table macro_table
;
2714 do_formals (macro
, idx
, in
)
2719 formal_entry
**p
= ¯o
->formals
;
2720 macro
->formal_count
= 0;
2721 hash_new_table (5, ¯o
->formal_hash
);
2722 while (idx
< in
->len
)
2724 formal_entry
*formal
;
2726 formal
= (formal_entry
*) xmalloc (sizeof (formal_entry
));
2728 sb_new (&formal
->name
);
2729 sb_new (&formal
->def
);
2730 sb_new (&formal
->actual
);
2732 idx
= sb_skip_white (idx
, in
);
2733 idx
= get_token (idx
, in
, &formal
->name
);
2734 if (formal
->name
.len
== 0)
2736 idx
= sb_skip_white (idx
, in
);
2737 if (formal
->name
.len
)
2739 /* This is a formal */
2740 if (idx
< in
->len
&& in
->ptr
[idx
] == '=')
2743 idx
= get_any_string (idx
+ 1, in
, &formal
->def
, 1, 0);
2748 /* Add to macro's hash table */
2750 hash_entry
*p
= hash_create (¯o
->formal_hash
, &formal
->name
);
2751 p
->type
= hash_formal
;
2752 p
->value
.f
= formal
;
2755 formal
->index
= macro
->formal_count
;
2756 idx
= sb_skip_comma (idx
, in
);
2757 macro
->formal_count
++;
2764 /* Parse off LOCAL n1, n2,... Invent a label name for it */
2767 do_local (idx
, line
)
2777 idx
= sb_skip_white (idx
, line
);
2778 while (!eol(idx
, line
))
2783 sprintf(subs
, "LL%04x", ln
);
2784 idx
= get_token(idx
, line
, &acc
);
2785 sb_add_string (&sub
, subs
);
2786 hash_add_to_string_table (&assign_hash_table
, &acc
, &sub
, 1);
2787 idx
= sb_skip_comma (idx
, line
);
2802 macro
= (macro_entry
*) xmalloc (sizeof (macro_entry
));
2803 sb_new (¯o
->sub
);
2806 macro
->formal_count
= 0;
2809 idx
= sb_skip_white (idx
, in
);
2810 buffer_and_nest ("MACRO", "ENDM", ¯o
->sub
);
2814 sb_add_sb (&name
, &label
);
2815 if (in
->ptr
[idx
] == '(')
2817 /* It's the label: MACRO (formals,...) sort */
2818 idx
= do_formals (macro
, idx
+ 1, in
);
2819 if (in
->ptr
[idx
] != ')')
2820 ERROR ((stderr
, "Missing ) after formals.\n"));
2823 /* It's the label: MACRO formals,... sort */
2824 idx
= do_formals (macro
, idx
, in
);
2829 idx
= get_token (idx
, in
, &name
);
2830 idx
= sb_skip_white (idx
, in
);
2831 idx
= do_formals (macro
, idx
, in
);
2834 /* and stick it in the macro hash table */
2835 hash_create (¯o_table
, &name
)->value
.m
= macro
;
2840 get_token (idx
, in
, name
)
2846 && ISFIRSTCHAR (in
->ptr
[idx
]))
2848 sb_add_char (name
, in
->ptr
[idx
++]);
2849 while (idx
< in
->len
2850 && ISNEXTCHAR (in
->ptr
[idx
]))
2852 sb_add_char (name
, in
->ptr
[idx
++]);
2855 /* Ignore trailing & */
2856 if (alternate
&& idx
< in
->len
&& in
->ptr
[idx
] == '&')
2861 /* Scan a token, but stop if a ' is seen */
2863 get_apost_token (idx
, in
, name
, kind
)
2869 idx
= get_token (idx
, in
, name
);
2870 if (idx
< in
->len
&& in
->ptr
[idx
] == kind
)
2876 sub_actual (src
, in
, t
, m
, kind
, out
, copyifnotthere
)
2885 /* This is something to take care of */
2887 src
= get_apost_token (src
, in
, t
, kind
);
2888 /* See if it's in the macro's hash table */
2889 ptr
= hash_lookup (&m
->formal_hash
, t
);
2892 if (ptr
->value
.f
->actual
.len
)
2894 sb_add_sb (out
, &ptr
->value
.f
->actual
);
2898 sb_add_sb (out
, &ptr
->value
.f
->def
);
2901 else if (copyifnotthere
)
2907 sb_add_char (out
, '\\');
2915 macro_expand (name
, idx
, in
, m
)
2925 int is_positional
= 0;
2931 /* Reset any old value the actuals may have */
2932 for (f
= m
->formals
; f
; f
= f
->next
)
2933 sb_reset (&f
->actual
);
2935 /* Peel off the actuals and store them away in the hash tables' actuals */
2936 while (!eol(idx
, in
))
2939 idx
= sb_skip_white (idx
, in
);
2940 /* Look and see if it's a positional or keyword arg */
2942 while (scan
< in
->len
2943 && !ISSEP (in
->ptr
[scan
])
2944 && (!alternate
&& in
->ptr
[scan
] != '='))
2946 if (scan
< in
->len
&& (!alternate
) && in
->ptr
[scan
] == '=')
2951 ERROR ((stderr
, "Can't mix positional and keyword arguments.\n"));
2954 /* This is a keyword arg, fetch the formal name and
2955 then the actual stuff */
2957 idx
= get_token (idx
, in
, &t
);
2958 if (in
->ptr
[idx
] != '=')
2959 ERROR ((stderr
, "confused about formal params.\n"));
2961 /* Lookup the formal in the macro's list */
2962 ptr
= hash_lookup (&m
->formal_hash
, &t
);
2965 ERROR ((stderr
, "MACRO formal argument %s does not exist.\n", sb_name (&t
)));
2970 /* Insert this value into the right place */
2971 sb_reset (&ptr
->value
.f
->actual
);
2972 idx
= get_any_string (idx
+ 1, in
, &ptr
->value
.f
->actual
, 0, 0);
2977 /* This is a positional arg */
2981 ERROR ((stderr
, "Can't mix positional and keyword arguments.\n"));
2986 ERROR ((stderr
, "Too many positional arguments.\n"));
2990 sb_reset (&f
->actual
);
2991 idx
= get_any_string (idx
, in
, &f
->actual
, 1, 0);
2994 idx
= sb_skip_comma (idx
, in
);
2997 /* Copy the stuff from the macro buffer into a safe place and substitute any args */
3005 while (src
< in
->len
)
3007 if (in
->ptr
[src
] == '&')
3010 src
= sub_actual (src
+ 1, in
, &t
, m
, '&', &out
, 0);
3012 else if (in
->ptr
[src
] == '\\')
3015 if (in
->ptr
[src
] == comment_char
)
3017 /* This is a comment, just drop the rest of the line */
3018 while (src
< in
->len
3019 && in
->ptr
[src
] != '\n')
3023 else if (in
->ptr
[src
] == '(')
3025 /* Sub in till the next ')' literally */
3027 while (src
< in
->len
&& in
->ptr
[src
] != ')')
3029 sb_add_char (&out
, in
->ptr
[src
++]);
3031 if (in
->ptr
[src
] == ')')
3034 ERROR ((stderr
, "Missplaced ).\n"));
3036 else if (in
->ptr
[src
] == '@')
3038 /* Sub in the macro invocation number */
3042 sprintf (buffer
, "%05d", number
);
3043 sb_add_string (&out
, buffer
);
3045 else if (in
->ptr
[src
] == '&')
3047 /* This is a preprocessor variable name, we don't do them
3049 sb_add_char (&out
, '\\');
3050 sb_add_char (&out
, '&');
3056 src
= sub_actual (src
, in
, &t
, m
, '\'', &out
, 0);
3059 else if (ISFIRSTCHAR (in
->ptr
[src
]) && alternate
)
3062 src
= sub_actual (src
, in
, &t
, m
, '\'', &out
, 1);
3064 else if (ISCOMMENTCHAR (in
->ptr
[src
])
3065 && src
+ 1 < in
->len
3066 && ISCOMMENTCHAR (in
->ptr
[src
+1])
3069 /* Two comment chars in a row cause the rest of the line to be dropped */
3070 while (src
< in
->len
&& in
->ptr
[src
] != '\n')
3073 else if (in
->ptr
[src
] == '"')
3076 sb_add_char (&out
, in
->ptr
[src
++]);
3080 sb_add_char (&out
, in
->ptr
[src
++]);
3083 include_buf (name
, &out
, include_macro
, include_next_index ());
3096 /* The macro name must be the first thing on the line */
3102 idx
= get_token (idx
, in
, &name
);
3106 /* Got a name, look it up */
3108 ptr
= hash_lookup (¯o_table
, &name
);
3112 /* It's in the table, copy out the stuff and convert any macro args */
3113 macro_expand (&name
, idx
, in
, ptr
->value
.m
);
3125 /* STRING HANDLING */
3128 getstring (idx
, in
, acc
)
3133 idx
= sb_skip_white (idx
, in
);
3135 while (idx
< in
->len
3136 && (in
->ptr
[idx
] == '"'
3137 || in
->ptr
[idx
] == '<'
3138 || (in
->ptr
[idx
] == '\'' && alternate
)))
3140 if (in
->ptr
[idx
] == '<')
3146 while ((in
->ptr
[idx
] != '>' || nest
)
3149 if (in
->ptr
[idx
] == '!')
3152 sb_add_char (acc
, in
->ptr
[idx
++]);
3155 if (in
->ptr
[idx
] == '>')
3157 if (in
->ptr
[idx
] == '<')
3159 sb_add_char (acc
, in
->ptr
[idx
++]);
3167 idx
= exp_get_abs ("Character code in string must be absolute expression.\n",
3169 sb_add_char (acc
, code
);
3171 if (in
->ptr
[idx
] != '>')
3172 ERROR ((stderr
, "Missing > for character code.\n"));
3176 else if (in
->ptr
[idx
] == '"' || in
->ptr
[idx
] == '\'')
3178 char tchar
= in
->ptr
[idx
];
3180 while (idx
< in
->len
)
3182 if (alternate
&& in
->ptr
[idx
] == '!')
3185 sb_add_char (acc
, in
->ptr
[idx
++]);
3188 if (in
->ptr
[idx
] == tchar
)
3191 if (idx
>= in
->len
|| in
->ptr
[idx
] != tchar
)
3194 sb_add_char (acc
, in
->ptr
[idx
]);
3204 /* .SDATA[C|Z] <string> */
3208 do_sdata (idx
, in
, type
)
3217 fprintf (outfile
, ".byte\t");
3219 while (!eol (idx
, in
))
3223 idx
= sb_skip_white (idx
, in
);
3224 while (!eol (idx
, in
))
3226 pidx
= idx
= get_any_string (idx
, in
, &acc
, 0, 1);
3231 ERROR ((stderr
, "string for SDATAC longer than 255 characters (%d).\n", acc
.len
));
3233 fprintf (outfile
, "%d", acc
.len
);
3237 for (i
= 0; i
< acc
.len
; i
++)
3241 fprintf (outfile
, ",");
3243 fprintf (outfile
, "%d", acc
.ptr
[i
]);
3250 fprintf (outfile
, ",");
3251 fprintf (outfile
, "0");
3253 idx
= sb_skip_comma (idx
, in
);
3254 if (idx
== pidx
) break;
3256 if (!alternate
&& in
->ptr
[idx
] != ',' && idx
!= in
->len
)
3258 fprintf (outfile
, "\n");
3259 ERROR ((stderr
, "illegal character in SDATA line (0x%x).\n", in
->ptr
[idx
]));
3265 fprintf (outfile
, "\n");
3268 /* .SDATAB <count> <string> */
3280 idx
= exp_get_abs ("Must have absolute SDATAB repeat count.\n", idx
, in
, &repeat
);
3283 ERROR ((stderr
, "Must have positive SDATAB repeat count (%d).\n", repeat
));
3287 idx
= sb_skip_comma (idx
, in
);
3288 idx
= getstring (idx
, in
, &acc
);
3290 for (i
= 0; i
< repeat
; i
++)
3293 fprintf (outfile
, "\t");
3294 fprintf (outfile
, ".byte\t");
3296 fprintf (outfile
, "\n");
3306 FILE *newone
= fopen (name
, "r");
3310 if (isp
== MAX_INCLUDES
)
3311 FATAL ((stderr
, "Unreasonable include depth (%ld).\n", (long) isp
));
3314 sp
->handle
= newone
;
3317 sb_add_string (&sp
->name
, name
);
3320 sp
->pushback_index
= 0;
3321 sp
->type
= include_file
;
3323 sb_new (&sp
->pushback
);
3328 do_include (idx
, in
)
3335 include_path
*includes
;
3339 idx
= getstring (idx
, in
, &t
);
3341 for (includes
= paths_head
; includes
; includes
= includes
->next
)
3344 sb_add_sb (&cat
, &includes
->path
);
3345 sb_add_char (&cat
, '/');
3346 sb_add_sb (&cat
, &t
);
3347 if (new_file (sb_name (&cat
)))
3354 FATAL ((stderr
, "Can't open include file `%s'.\n", text
));
3363 if (sp
!= include_stack
)
3366 fclose (sp
->handle
);
3371 /* Get the next character from the include stack. If there's anything
3372 in the pushback buffer, take that first. If we're at eof, pop from
3373 the stack and try again. Keep the linecount up to date. */
3380 if (sp
->pushback
.len
!= sp
->pushback_index
)
3382 r
= (char) (sp
->pushback
.ptr
[sp
->pushback_index
++]);
3383 /* When they've all gone, reset the pointer */
3384 if (sp
->pushback_index
== sp
->pushback
.len
)
3386 sp
->pushback
.len
= 0;
3387 sp
->pushback_index
= 0;
3390 else if (sp
->handle
)
3392 r
= getc (sp
->handle
);
3397 if (r
== EOF
&& isp
)
3401 while (r
== EOF
&& isp
)
3419 return sp
->linecount
;
3423 include_next_index ()
3427 && index
> MAX_REASONABLE
)
3428 FATAL ((stderr
, "Unreasonable expansion (-u turns off check).\n"));
3433 /* Initialize the chartype vector. */
3439 for (x
= 0; x
< 256; x
++)
3441 if (isalpha (x
) || x
== '_' || x
== '$')
3442 chartype
[x
] |= FIRSTBIT
;
3444 if (isdigit (x
) || isalpha (x
) || x
== '_' || x
== '$')
3445 chartype
[x
] |= NEXTBIT
;
3447 if (x
== ' ' || x
== '\t' || x
== ',' || x
== '"' || x
== ';'
3448 || x
== '"' || x
== '<' || x
== '>' || x
== ')' || x
== '(')
3449 chartype
[x
] |= SEPBIT
;
3451 if (x
== 'b' || x
== 'B'
3452 || x
== 'q' || x
== 'Q'
3453 || x
== 'h' || x
== 'H'
3454 || x
== 'd' || x
== 'D')
3455 chartype
[x
] |= BASEBIT
;
3457 if (x
== ' ' || x
== '\t')
3458 chartype
[x
] |= WHITEBIT
;
3460 if (x
== comment_char
)
3461 chartype
[x
] |= COMMENTBIT
;
3467 /* What to do with all the keywords */
3468 #define PROCESS 0x1000 /* Run substitution over the line */
3469 #define LAB 0x2000 /* Spit out the label */
3471 #define K_EQU PROCESS|1
3472 #define K_ASSIGN PROCESS|2
3473 #define K_REG PROCESS|3
3474 #define K_ORG PROCESS|4
3475 #define K_RADIX PROCESS|5
3476 #define K_DATA LAB|PROCESS|6
3477 #define K_DATAB LAB|PROCESS|7
3478 #define K_SDATA LAB|PROCESS|8
3479 #define K_SDATAB LAB|PROCESS|9
3480 #define K_SDATAC LAB|PROCESS|10
3481 #define K_SDATAZ LAB|PROCESS|11
3482 #define K_RES LAB|PROCESS|12
3483 #define K_SRES LAB|PROCESS|13
3484 #define K_SRESC LAB|PROCESS|14
3485 #define K_SRESZ LAB|PROCESS|15
3486 #define K_EXPORT LAB|PROCESS|16
3487 #define K_GLOBAL LAB|PROCESS|17
3488 #define K_PRINT LAB|PROCESS|19
3489 #define K_FORM LAB|PROCESS|20
3490 #define K_HEADING LAB|PROCESS|21
3491 #define K_PAGE LAB|PROCESS|22
3492 #define K_IMPORT LAB|PROCESS|23
3493 #define K_PROGRAM LAB|PROCESS|24
3494 #define K_END PROCESS|25
3495 #define K_INCLUDE PROCESS|26
3496 #define K_IGNORED PROCESS|27
3497 #define K_ASSIGNA PROCESS|28
3498 #define K_ASSIGNC 29
3499 #define K_AIF PROCESS|30
3500 #define K_AELSE PROCESS|31
3501 #define K_AENDI PROCESS|32
3502 #define K_AREPEAT PROCESS|33
3503 #define K_AENDR PROCESS|34
3505 #define K_AENDW PROCESS|36
3507 #define K_MACRO PROCESS|38
3509 #define K_ALIGN PROCESS|LAB|40
3510 #define K_ALTERNATE 41
3511 #define K_DB LAB|PROCESS|42
3512 #define K_DW LAB|PROCESS|43
3513 #define K_DL LAB|PROCESS|44
3525 { "EQU", K_EQU
, 0 },
3526 { "ALTERNATE", K_ALTERNATE
, 0 },
3527 { "ASSIGN", K_ASSIGN
, 0 },
3528 { "REG", K_REG
, 0 },
3529 { "ORG", K_ORG
, 0 },
3530 { "RADIX", K_RADIX
, 0 },
3531 { "DATA", K_DATA
, 0 },
3535 { "DATAB", K_DATAB
, 0 },
3536 { "SDATA", K_SDATA
, 0 },
3537 { "SDATAB", K_SDATAB
, 0 },
3538 { "SDATAZ", K_SDATAZ
, 0 },
3539 { "SDATAC", K_SDATAC
, 0 },
3540 { "RES", K_RES
, 0 },
3541 { "SRES", K_SRES
, 0 },
3542 { "SRESC", K_SRESC
, 0 },
3543 { "SRESZ", K_SRESZ
, 0 },
3544 { "EXPORT", K_EXPORT
, 0 },
3545 { "GLOBAL", K_GLOBAL
, 0 },
3546 { "PRINT", K_PRINT
, 0 },
3547 { "FORM", K_FORM
, 0 },
3548 { "HEADING", K_HEADING
, 0 },
3549 { "PAGE", K_PAGE
, 0 },
3550 { "PROGRAM", K_IGNORED
, 0 },
3551 { "END", K_END
, 0 },
3552 { "INCLUDE", K_INCLUDE
, 0 },
3553 { "ASSIGNA", K_ASSIGNA
, 0 },
3554 { "ASSIGNC", K_ASSIGNC
, 0 },
3555 { "AIF", K_AIF
, 0 },
3556 { "AELSE", K_AELSE
, 0 },
3557 { "AENDI", K_AENDI
, 0 },
3558 { "AREPEAT", K_AREPEAT
, 0 },
3559 { "AENDR", K_AENDR
, 0 },
3560 { "EXITM", K_EXITM
, 0 },
3561 { "MACRO", K_MACRO
, 0 },
3562 { "ENDM", K_ENDM
, 0 },
3563 { "AWHILE", K_AWHILE
, 0 },
3564 { "ALIGN", K_ALIGN
, 0 },
3565 { "AENDW", K_AENDW
, 0 },
3566 { "ALTERNATE", K_ALTERNATE
, 0 },
3567 { "LOCAL", K_LOCAL
, 0 },
3571 /* Look for a pseudo op on the line. If one's there then call
3575 process_pseudo_op (idx
, line
, acc
)
3582 if (line
->ptr
[idx
] == '.' || alternate
)
3584 /* Scan forward and find pseudo name */
3590 if (line
->ptr
[idx
] == '.')
3592 in
= line
->ptr
+ idx
;
3597 while (idx
< line
->len
&& *e
&& ISFIRSTCHAR (*e
))
3599 sb_add_char (acc
, *e
);
3604 ptr
= hash_lookup (&keyword_hash_table
, acc
);
3609 /* This one causes lots of pain when trying to preprocess
3611 WARNING ((stderr
, "Unrecognised pseudo op `%s'.\n", sb_name (acc
)));
3615 if (ptr
->value
.i
& LAB
)
3616 { /* output the label */
3619 fprintf (outfile
, "%s:\t", sb_name (&label
));
3622 fprintf (outfile
, "\t");
3625 if (ptr
->value
.i
& PROCESS
)
3627 /* Polish the rest of the line before handling the pseudo op */
3629 strip_comments(line
);
3632 process_assigns (idx
, line
, acc
);
3634 change_base (0, acc
, line
);
3639 switch (ptr
->value
.i
)
3655 switch (ptr
->value
.i
)
3667 ERROR ((stderr
, "ORG command not allowed.\n"));
3673 do_data (idx
, line
, 1);
3676 do_data (idx
, line
, 2);
3679 do_data (idx
, line
, 4);
3682 do_data (idx
, line
, 0);
3685 do_datab (idx
, line
);
3688 do_sdata (idx
, line
, 0);
3691 do_sdatab (idx
, line
);
3694 do_sdata (idx
, line
, 'c');
3697 do_sdata (idx
, line
, 'z');
3700 do_assign (1, 0, line
);
3706 do_arepeat (idx
, line
);
3712 do_awhile (idx
, line
);
3718 do_assign (0, idx
, line
);
3721 do_align (idx
, line
);
3724 do_res (idx
, line
, 0);
3727 do_res (idx
, line
, 's');
3730 do_include (idx
, line
);
3733 do_local (idx
, line
);
3736 do_macro (idx
, line
);
3742 do_res (idx
, line
, 'c');
3745 do_print (idx
, line
);
3748 do_form (idx
, line
);
3751 do_heading (idx
, line
);
3763 do_res (idx
, line
, 'z');
3771 do_assigna (idx
, line
);
3774 do_assignc (idx
, line
);
3790 /* Build the keyword hash table - put each keyword in the table twice,
3791 once upper and once lower case.*/
3798 for (i
= 0; kinfo
[i
].name
; i
++)
3803 sb_add_string (&label
, kinfo
[i
].name
);
3805 hash_add_to_int_table (&keyword_hash_table
, &label
, kinfo
[i
].code
);
3808 for (j
= 0; kinfo
[i
].name
[j
]; j
++)
3809 sb_add_char (&label
, kinfo
[i
].name
[j
] - 'A' + 'a');
3810 hash_add_to_int_table (&keyword_hash_table
, &label
, kinfo
[i
].code
);
3836 sb_add_char (&value
, *string
);
3839 exp_get_abs ("Invalid expression on command line.\n", 0, &value
, &res
);
3843 sb_add_char (&label
, *string
);
3848 ptr
= hash_create (&vars
, &label
);
3849 free_old_entry (ptr
);
3850 ptr
->type
= hash_integer
;
3856 /* The list of long options. */
3857 static struct option long_options
[] =
3859 { "alternate", no_argument
, 0, 'a' },
3860 { "include", required_argument
, 0, 'I' },
3861 { "commentchar", required_argument
, 0, 'c' },
3862 { "copysource", no_argument
, 0, 's' },
3863 { "debug", no_argument
, 0, 'd' },
3864 { "help", no_argument
, 0, 'h' },
3865 { "output", required_argument
, 0, 'o' },
3866 { "print", no_argument
, 0, 'p' },
3867 { "unreasonable", no_argument
, 0, 'u' },
3868 { "version", no_argument
, 0, 'v' },
3869 { "define", required_argument
, 0, 'd' },
3870 { NULL
, no_argument
, 0, 0 }
3873 /* Show a usage message and exit. */
3875 show_usage (file
, status
)
3881 [-a] [--alternate] enter alternate macro mode\n\
3882 [-c char] [--commentchar char] change the comment character from !\n\
3883 [-d] [--debug] print some debugging info\n\
3884 [-h] [--help] print this message\n\
3885 [-o out] [--output out] set the output file\n\
3886 [-p] [--print] print line numbers\n\
3887 [-s] [--copysource] copy source through as comments \n\
3888 [-u] [--unreasonable] allow unreasonable nesting\n\
3889 [-v] [--version] print the program version\n\
3890 [-Dname=value] create preprocessor variable called name, with value\n\
3891 [-Ipath] add to include path list\n\
3892 [in-file]\n", program_name
);
3896 /* Display a help message and exit. */
3900 printf ("%s: Gnu Assembler Macro Preprocessor\n",
3902 show_usage (stdout
, 0);
3919 program_name
= argv
[0];
3920 xmalloc_set_program_name (program_name
);
3922 hash_new_table (101, ¯o_table
);
3923 hash_new_table (101, &keyword_hash_table
);
3924 hash_new_table (101, &assign_hash_table
);
3925 hash_new_table (101, &vars
);
3930 while ((opt
= getopt_long (argc
, argv
, "I:sdhavc:upo:D:", long_options
,
3944 include_path
*p
= (include_path
*) xmalloc (sizeof (include_path
));
3946 sb_add_string (&p
->path
, optarg
);
3948 paths_tail
->next
= p
;
3955 print_line_number
= 1;
3958 comment_char
= optarg
[0];
3976 printf ("GNU %s version %s\n", program_name
, program_version
);
3982 show_usage (stderr
, 1);
3989 outfile
= fopen (out_name
, "w");
3992 fprintf (stderr
, "%s: Can't open output file `%s'.\n",
3993 program_name
, out_name
);
4005 /* Process all the input files */
4007 while (optind
< argc
)
4009 if (new_file (argv
[optind
]))
4015 fprintf (stderr
, "%s: Can't open input file `%s'.\n",
4016 program_name
, argv
[optind
]);