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 Macro arg parameters subsituted by name, don't need the &.
41 String can start with ' too.
42 Strings can be surrounded by <..>
43 A %<exp> in a string evaluates the expression
44 Literal char in a string with !
60 #ifdef NEED_MALLOC_DECLARATION
61 extern char *malloc ();
64 #include "libiberty.h"
66 char *program_version
= "1.2";
68 #define MAX_INCLUDES 30 /* Maximum include depth */
69 #define MAX_REASONABLE 1000 /* Maximum number of expansions */
71 int unreasonable
; /* -u on command line */
72 int stats
; /* -d on command line */
73 int print_line_number
; /* -p flag on command line */
74 int copysource
; /* -c flag on command line */
75 int warnings
; /* Number of WARNINGs generated so far. */
76 int errors
; /* Number of ERRORs generated so far. */
77 int fatals
; /* Number of fatal ERRORs generated so far (either 0 or 1). */
78 int alternate
= 0; /* -a on command line */
79 char comment_char
= '!';
80 int radix
= 10; /* Default radix */
82 int had_end
; /* Seen .END */
84 /* The output stream */
88 /* Forward declarations. */
89 static int condass_lookup_name();
90 static int condass_on();
92 static int get_and_process();
93 static int get_token();
94 static int getstring();
95 static int include_next_index();
96 static int macro_op();
97 static int linecount();
98 static int process_pseudo_op();
99 static void include_pop();
100 static void include_print_where_line();
103 I had a couple of choices when deciding upon this data structure.
104 gas uses null terminated strings for all its internal work. This
105 often means that parts of the program that want to examine
106 substrings have to manipulate the data in the string to do the
107 right thing (a common operation is to single out a bit of text by
108 saving away the character after it, nulling it out, operating on
109 the substring and then replacing the character which was under the
110 null). This is a pain and I remember a load of problems that I had with
111 code in gas which almost got this right. Also, it's harder to grow and
112 allocate null terminated strings efficiently.
114 Obstacks provide all the functionality needed, but are too
115 complicated, hence the sb.
117 An sb is allocated by the caller, and is initialzed to point to an
118 sb_element. sb_elements are kept on a free lists, and used when
119 needed, replaced onto the free list when unused.
122 #define max_power_two 30 /* don't allow strings more than
123 2^max_power_two long */
124 /* structure of an sb */
127 char *ptr
; /* points to the current block. */
128 int len
; /* how much is used. */
129 int pot
; /* the maximum length is 1<<pot */
134 /* Structure of the free list object of an sb */
146 sb_element
*size
[max_power_two
];
149 sb_list_vector free_list
;
151 int string_count
[max_power_two
];
153 /* the attributes of each character are stored as a bit pattern
154 chartype, which gives us quick tests. */
161 #define COMMENTBIT 16
163 #define ISCOMMENTCHAR(x) (chartype[(unsigned)(x)] & COMMENTBIT)
164 #define ISFIRSTCHAR(x) (chartype[(unsigned)(x)] & FIRSTBIT)
165 #define ISNEXTCHAR(x) (chartype[(unsigned)(x)] & NEXTBIT)
166 #define ISSEP(x) (chartype[(unsigned)(x)] & SEPBIT)
167 #define ISWHITE(x) (chartype[(unsigned)(x)] & WHITEBIT)
168 #define ISBASE(x) (chartype[(unsigned)(x)] & BASEBIT)
169 static char chartype
[256];
172 /* Conditional assembly uses the `ifstack'. Each aif pushes another
173 entry onto the stack, and sets the on flag if it should. The aelse
174 sets hadelse, and toggles on. An aend pops a level. We limit to
175 100 levels of nesting, not because we're facists pigs with read
176 only minds, but because more than 100 levels of nesting is probably
177 a bug in the user's macro structure. */
179 #define IFNESTING 100
182 int on
; /* is the level being output */
183 int hadelse
; /* has an aelse been seen */
188 /* The final and intermediate results of expression evaluation are kept in
189 exp_t's. Note that a symbol is not an sb, but a pointer into the input
190 line. It must be coped somewhere safe before the next line is read in. */
201 int value
; /* constant part */
202 symbol add_symbol
; /* name part */
203 symbol sub_symbol
; /* name part */
208 /* Hashing is done in a pretty standard way. A hash_table has a
209 pointer to a vector of pointers to hash_entrys, and the size of the
210 vector. A hash_entry contains a union of all the info we like to
211 store in hash table. If there is a hash collision, hash_entries
212 with the same hash are kept in a chain. */
214 /* What the data in a hash_entry means */
217 hash_integer
, /* name->integer mapping */
218 hash_string
, /* name->string mapping */
219 hash_macro
, /* name is a macro */
220 hash_formal
/* name is a formal argument */
225 sb key
; /* symbol name */
226 hash_type type
; /* symbol meaning */
231 struct macro_struct
*m
;
232 struct formal_struct
*f
;
234 struct hs
*next
; /* next hash_entry with same hash key */
244 /* Structures used to store macros.
246 Each macro knows its name and included text. It gets built with a
247 list of formal arguments, and also keeps a hash table which points
248 into the list to speed up formal search. Each formal knows its
249 name and its default value. Each time the macro is expanded, the
250 formals get the actual values attatched to them. */
252 /* describe the formal arguments to a macro */
254 typedef struct formal_struct
256 struct formal_struct
*next
; /* next formal in list */
257 sb name
; /* name of the formal */
258 sb def
; /* the default value */
259 sb actual
; /* the actual argument (changed on each expansion) */
260 int index
; /* the index of the formal 0..formal_count-1 */
264 /* describe the macro. */
266 typedef struct macro_struct
268 sb sub
; /* substitution text. */
269 int formal_count
; /* number of formal args. */
270 formal_entry
*formals
; /* pointer to list of formal_structs */
271 hash_table formal_hash
; /* hash table of formals. */
275 /* how we nest files and expand macros etc.
277 we keep a stack of of include_stack structs. each include file
278 pushes a new level onto the stack. we keep an sb with a pushback
279 too. unget chars are pushed onto the pushback sb, getchars first
280 checks the pushback sb before reading from the input stream.
282 small things are expanded by adding the text of the item onto the
283 pushback sb. larger items are grown by pushing a new level and
284 allocating the entire pushback buf for the item. each time
285 something like a macro is expanded, the stack index is changed. we
286 can then perform an exitm by popping all entries off the stack with
287 the same stack index. if we're being reasonable, we can detect
288 recusive expansion by checking the index is reasonably small.
293 include_file
, include_repeat
, include_while
, include_macro
298 sb pushback
; /* current pushback stream */
299 int pushback_index
; /* next char to read from stream */
300 FILE *handle
; /* open file */
301 sb name
; /* name of file */
302 int linecount
; /* number of lines read so far */
304 int index
; /* index of this layer */
306 include_stack
[MAX_INCLUDES
];
308 struct include_stack
*sp
;
309 #define isp (sp - include_stack)
314 void include_print_where_line ();
318 do { include_print_where_line (stderr); fprintf x ; fatals++; quit(); } while(0)
320 do { include_print_where_line (stderr); fprintf x; errors++; } while(0)
322 do { include_print_where_line (stderr); fprintf x; warnings++;} while(0)
326 /* exit the program and return the right ERROR code. */
339 for (i
= 0; i
< max_power_two
; i
++)
341 fprintf (stderr
, "strings size %8d : %d\n", 1<<i
, string_count
[i
]);
348 /* this program is about manipulating strings.
349 they are managed in things called `sb's which is an abbreviation
350 for string buffers. an sb has to be created, things can be glued
351 on to it, and at the end of it's life it should be freed. the
352 contents should never be pointed at whilst it is still growing,
353 since it could be moved at any time
357 sb_grow... (&foo,...);
363 /* initializes an sb. */
370 /* see if we can find one to allocate */
373 if (size
> max_power_two
)
375 FATAL ((stderr
, "string longer than %d bytes requested.\n",
376 1 << max_power_two
));
378 e
= free_list
.size
[size
];
381 /* nothing there, allocate one and stick into the free list */
382 e
= (sb_element
*) xmalloc (sizeof (sb_element
) + (1 << size
));
383 e
->next
= free_list
.size
[size
];
385 free_list
.size
[size
] = e
;
386 string_count
[size
]++;
389 /* remove from free list */
391 free_list
.size
[size
] = e
->next
;
393 /* copy into callers world */
405 sb_build (ptr
, dsize
);
408 /* deallocate the sb at ptr */
415 /* return item to free list */
416 ptr
->item
->next
= free_list
.size
[ptr
->pot
];
417 free_list
.size
[ptr
->pot
] = ptr
->item
;
420 /* add the sb at s to the end of the sb at ptr */
422 static void sb_check ();
430 sb_check (ptr
, s
->len
);
431 memcpy (ptr
->ptr
+ ptr
->len
, s
->ptr
, s
->len
);
435 /* make sure that the sb at ptr has room for another len characters,
436 and grow it if it doesn't. */
443 if (ptr
->len
+ len
>= 1 << ptr
->pot
)
447 while (ptr
->len
+ len
>= 1 << pot
)
449 sb_build (&tmp
, pot
);
450 sb_add_sb (&tmp
, ptr
);
456 /* make the sb at ptr point back to the beginning. */
465 /* add character c to the end of the sb at ptr. */
473 ptr
->ptr
[ptr
->len
++] = c
;
476 /* add null terminated string s to the end of sb at ptr. */
479 sb_add_string (ptr
, s
)
483 int len
= strlen (s
);
485 memcpy (ptr
->ptr
+ ptr
->len
, s
, len
);
489 /* add string at s of length len to sb at ptr */
492 sb_add_buffer (ptr
, s
, len
)
498 memcpy (ptr
->ptr
+ ptr
->len
, s
, len
);
503 /* print the sb at ptr to the output file */
513 for (i
= 0; i
< ptr
->len
; i
++)
517 fprintf (outfile
, ",");
519 fprintf (outfile
, "%d", ptr
->ptr
[i
]);
526 sb_print_at (idx
, ptr
)
531 for (i
= idx
; i
< ptr
->len
; i
++)
532 putc (ptr
->ptr
[i
], outfile
);
534 /* put a null at the end of the sb at in and return the start of the
535 string, so that it can be used as an arg to printf %s. */
542 /* stick a null on the end of the string */
547 /* start at the index idx into the string in sb at ptr and skip
548 whitespace. return the index of the first non whitespace character */
551 sb_skip_white (idx
, ptr
)
555 while (idx
< ptr
->len
&& ISWHITE (ptr
->ptr
[idx
]))
560 /* start at the index idx into the sb at ptr. skips whitespace,
561 a comma and any following whitespace. returnes the index of the
565 sb_skip_comma (idx
, ptr
)
569 while (idx
< ptr
->len
&& ISWHITE (ptr
->ptr
[idx
]))
573 && ptr
->ptr
[idx
] == ',')
576 while (idx
< ptr
->len
&& ISWHITE (ptr
->ptr
[idx
]))
583 /* hash table maintenance. */
585 /* build a new hash table with size buckets, and fill in the info at ptr. */
588 hash_new_table (size
, ptr
)
594 ptr
->table
= (hash_entry
**) xmalloc (size
* (sizeof (hash_entry
*)));
595 /* Fill with null-pointer, not zero-bit-pattern. */
596 for (i
= 0; i
< size
; i
++)
600 /* calculate and return the hash value of the sb at key. */
609 for (i
= 0; i
< key
->len
; i
++)
617 /* lookup key in hash_table tab, if present, then return it, otherwise
618 build a new one and fill it with hash_integer. */
622 hash_create (tab
, key
)
626 int k
= hash (key
) % tab
->size
;
628 hash_entry
**table
= tab
->table
;
636 hash_entry
*n
= (hash_entry
*) xmalloc (sizeof (hash_entry
));
639 sb_add_sb (&n
->key
, key
);
641 n
->type
= hash_integer
;
644 if (strncmp (table
[k
]->key
.ptr
, key
->ptr
, key
->len
) == 0)
652 /* add sb name with key into hash_table tab. if replacing old value
653 and again, then ERROR. */
657 hash_add_to_string_table (tab
, key
, name
, again
)
663 hash_entry
*ptr
= hash_create (tab
, key
);
664 if (ptr
->type
== hash_integer
)
666 sb_new (&ptr
->value
.s
);
668 if (ptr
->value
.s
.len
)
671 ERROR ((stderr
, "redefintion not allowed"));
674 ptr
->type
= hash_string
;
675 sb_reset (&ptr
->value
.s
);
677 sb_add_sb (&ptr
->value
.s
, name
);
680 /* add integer name to hash_table tab with sb key. */
684 hash_add_to_int_table (tab
, key
, name
)
689 hash_entry
*ptr
= hash_create (tab
, key
);
693 /* lookup sb key in hash_table tab. if found return hash_entry result,
698 hash_lookup (tab
, key
)
702 int k
= hash (key
) % tab
->size
;
703 hash_entry
**table
= tab
->table
;
704 hash_entry
*p
= table
[k
];
707 if (p
->key
.len
== key
->len
708 && strncmp (p
->key
.ptr
, key
->ptr
, key
->len
) == 0)
718 are handled in a really simple recursive decent way. each bit of
719 the machine takes an index into an sb and a pointer to an exp_t,
720 modifies the *exp_t and returns the index of the first character
721 past the part of the expression parsed.
723 expression precedence:
734 /* make sure that the exp_t at term is constant, if not the give the op ERROR. */
738 checkconst (op
, term
)
742 if (term
->add_symbol
.len
743 || term
->sub_symbol
.len
)
745 ERROR ((stderr
, "the %c operator cannot take non-absolute arguments.\n", op
));
749 /* turn the number in string at idx into a number of base,
750 fill in ptr and return the index of the first character not in the
755 sb_strtol (idx
, string
, base
, ptr
)
762 idx
= sb_skip_white (idx
, string
);
764 while (idx
< string
->len
)
766 int ch
= string
->ptr
[idx
];
770 else if (ch
>= 'a' && ch
<= 'f')
772 else if (ch
>= 'A' && ch
<= 'F')
780 value
= value
* base
+ dig
;
787 static int level_5 ();
790 level_0 (idx
, string
, lhs
)
795 lhs
->add_symbol
.len
= 0;
796 lhs
->add_symbol
.name
= 0;
798 lhs
->sub_symbol
.len
= 0;
799 lhs
->sub_symbol
.name
= 0;
801 idx
= sb_skip_white (idx
, string
);
805 if (isdigit (string
->ptr
[idx
]))
807 idx
= sb_strtol (idx
, string
, 10, &lhs
->value
);
809 else if (ISFIRSTCHAR (string
->ptr
[idx
]))
812 lhs
->add_symbol
.name
= string
->ptr
+ idx
;
813 while (idx
< string
->len
&& ISNEXTCHAR (string
->ptr
[idx
]))
818 lhs
->add_symbol
.len
= len
;
820 else if (string
->ptr
[idx
] == '"')
824 ERROR ((stderr
, "string where expression expected.\n"));
825 idx
= getstring (idx
, string
, &acc
);
830 ERROR ((stderr
, "can't find primary in expression.\n"));
833 return sb_skip_white (idx
, string
);
839 level_1 (idx
, string
, lhs
)
844 idx
= sb_skip_white (idx
, string
);
846 switch (string
->ptr
[idx
])
849 idx
= level_1 (idx
+ 1, string
, lhs
);
852 idx
= level_1 (idx
+ 1, string
, lhs
);
853 checkconst ('~', lhs
);
854 lhs
->value
= ~lhs
->value
;
859 idx
= level_1 (idx
+ 1, string
, lhs
);
860 lhs
->value
= -lhs
->value
;
862 lhs
->add_symbol
= lhs
->sub_symbol
;
868 idx
= level_5 (sb_skip_white (idx
, string
), string
, lhs
);
869 if (string
->ptr
[idx
] != ')')
870 ERROR ((stderr
, "misplaced closing parens.\n"));
875 idx
= level_0 (idx
, string
, lhs
);
878 return sb_skip_white (idx
, string
);
882 level_2 (idx
, string
, lhs
)
889 idx
= level_1 (idx
, string
, lhs
);
891 while (idx
< string
->len
&& (string
->ptr
[idx
] == '*'
892 || string
->ptr
[idx
] == '/'))
894 char op
= string
->ptr
[idx
++];
895 idx
= level_1 (idx
, string
, &rhs
);
899 checkconst ('*', lhs
);
900 checkconst ('*', &rhs
);
901 lhs
->value
*= rhs
.value
;
904 checkconst ('/', lhs
);
905 checkconst ('/', &rhs
);
907 ERROR ((stderr
, "attempt to divide by zero.\n"));
909 lhs
->value
/= rhs
.value
;
913 return sb_skip_white (idx
, string
);
918 level_3 (idx
, string
, lhs
)
925 idx
= level_2 (idx
, string
, lhs
);
927 while (idx
< string
->len
928 && (string
->ptr
[idx
] == '+'
929 || string
->ptr
[idx
] == '-'))
931 char op
= string
->ptr
[idx
++];
932 idx
= level_2 (idx
, string
, &rhs
);
936 lhs
->value
+= rhs
.value
;
937 if (lhs
->add_symbol
.name
&& rhs
.add_symbol
.name
)
939 ERROR ((stderr
, "can't add two relocatable expressions\n"));
941 /* change nn+symbol to symbol + nn */
942 if (rhs
.add_symbol
.name
)
944 lhs
->add_symbol
= rhs
.add_symbol
;
948 lhs
->value
-= rhs
.value
;
949 lhs
->sub_symbol
= rhs
.add_symbol
;
953 return sb_skip_white (idx
, string
);
957 level_4 (idx
, string
, lhs
)
964 idx
= level_3 (idx
, string
, lhs
);
966 while (idx
< string
->len
&&
967 string
->ptr
[idx
] == '&')
969 char op
= string
->ptr
[idx
++];
970 idx
= level_3 (idx
, string
, &rhs
);
974 checkconst ('&', lhs
);
975 checkconst ('&', &rhs
);
976 lhs
->value
&= rhs
.value
;
980 return sb_skip_white (idx
, string
);
984 level_5 (idx
, string
, lhs
)
991 idx
= level_4 (idx
, string
, lhs
);
993 while (idx
< string
->len
994 && (string
->ptr
[idx
] == '|' || string
->ptr
[idx
] == '~'))
996 char op
= string
->ptr
[idx
++];
997 idx
= level_4 (idx
, string
, &rhs
);
1001 checkconst ('|', lhs
);
1002 checkconst ('|', &rhs
);
1003 lhs
->value
|= rhs
.value
;
1006 checkconst ('~', lhs
);
1007 checkconst ('~', &rhs
);
1008 lhs
->value
^= rhs
.value
;
1012 return sb_skip_white (idx
, string
);
1016 /* parse the expression at offset idx into string, fill up res with
1017 the result. return the index of the first char past the expression.
1021 exp_parse (idx
, string
, res
)
1026 return level_5 (sb_skip_white (idx
, string
), string
, res
);
1030 /* turn the expression at exp into text and glue it onto the end of
1034 exp_string (exp
, string
)
1042 if (exp
->add_symbol
.len
)
1044 sb_add_buffer (string
, exp
->add_symbol
.name
, exp
->add_symbol
.len
);
1052 sb_add_char (string
, '+');
1053 sprintf (buf
, "%d", exp
->value
);
1054 sb_add_string (string
, buf
);
1058 if (exp
->sub_symbol
.len
)
1060 sb_add_char (string
, '-');
1061 sb_add_buffer (string
, exp
->add_symbol
.name
, exp
->add_symbol
.len
);
1067 sb_add_char (string
, '0');
1071 /* parse the expression at offset idx into sb in, return the value in val.
1072 if the expression is not constant, give ERROR emsg. returns the index
1073 of the first character past the end of the expression. */
1076 exp_get_abs (emsg
, idx
, in
, val
)
1083 idx
= exp_parse (idx
, in
, &res
);
1084 if (res
.add_symbol
.len
|| res
.sub_symbol
.len
)
1085 ERROR ((stderr
, emsg
));
1091 sb label
; /* current label parsed from line */
1092 hash_table assign_hash_table
; /* hash table for all assigned variables */
1093 hash_table keyword_hash_table
; /* hash table for keyword */
1094 hash_table vars
; /* hash table for eq variables */
1096 #define in_comment ';'
1100 strip_comments (out
)
1105 for (i
= 0; i
< out
->len
; i
++)
1107 if (ISCOMMENTCHAR(s
[i
]))
1116 /* push back character ch so that it can be read again. */
1126 if (sp
->pushback_index
)
1127 sp
->pushback_index
--;
1129 sb_add_char (&sp
->pushback
, ch
);
1132 /* push the sb ptr onto the include stack, with the given name, type and index. */
1136 include_buf (name
, ptr
, type
, index
)
1143 if (sp
- include_stack
>= MAX_INCLUDES
)
1144 FATAL ((stderr
, "unreasonable nesting.\n"));
1146 sb_add_sb (&sp
->name
, name
);
1149 sp
->pushback_index
= 0;
1152 sb_new (&sp
->pushback
);
1153 sb_add_sb (&sp
->pushback
, ptr
);
1157 /* used in ERROR messages, print info on where the include stack is onto file. */
1160 include_print_where_line (file
)
1163 struct include_stack
*p
= include_stack
+ 1;
1167 fprintf (file
, "%s:%d ", sb_name (&p
->name
), p
->linecount
- ((p
== sp
) ? 1 : 0));
1172 /* used in listings, print the line number onto file. */
1174 include_print_line (file
)
1178 struct include_stack
*p
= include_stack
+ 1;
1180 n
= fprintf (file
, "%4d", p
->linecount
);
1184 n
+= fprintf (file
, ".%d", p
->linecount
);
1189 fprintf (file
, " ");
1195 /* read a line from the top of the include stack into sb in. */
1206 putc (comment_char
, outfile
);
1207 if (print_line_number
)
1208 include_print_line (outfile
);
1222 WARNING ((stderr
, "End of file not at start of line.\n"));
1224 putc ('\n', outfile
);
1243 /* continued line */
1246 putc (comment_char
, outfile
);
1247 putc ('+', outfile
);
1260 sb_add_char (in
, ch
);
1268 /* find a label from sb in and put it in out. */
1271 grab_label (in
, out
)
1277 if (ISFIRSTCHAR (in
->ptr
[i
]))
1279 sb_add_char (out
, in
->ptr
[i
]);
1281 while ((ISNEXTCHAR (in
->ptr
[i
])
1282 || in
->ptr
[i
] == '\\'
1283 || in
->ptr
[i
] == '&')
1286 sb_add_char (out
, in
->ptr
[i
]);
1293 /* find all strange base stuff and turn into decimal. also
1294 find all the other numbers and convert them from the default radix */
1297 change_base (idx
, in
, out
)
1304 while (idx
< in
->len
)
1306 if (idx
< in
->len
- 1 && in
->ptr
[idx
+ 1] == '\'')
1310 switch (in
->ptr
[idx
])
1329 ERROR ((stderr
, "Illegal base character %c.\n", in
->ptr
[idx
]));
1334 idx
= sb_strtol (idx
+ 2, in
, base
, &value
);
1335 sprintf (buffer
, "%d", value
);
1336 sb_add_string (out
, buffer
);
1338 else if (ISFIRSTCHAR (in
->ptr
[idx
]))
1340 /* copy entire names through quickly */
1341 sb_add_char (out
, in
->ptr
[idx
]);
1343 while (idx
< in
->len
&& ISNEXTCHAR (in
->ptr
[idx
]))
1345 sb_add_char (out
, in
->ptr
[idx
]);
1349 else if (isdigit (in
->ptr
[idx
]))
1352 /* all numbers must start with a digit, let's chew it and
1354 idx
= sb_strtol (idx
, in
, radix
, &value
);
1355 sprintf (buffer
, "%d", value
);
1356 sb_add_string (out
, buffer
);
1358 /* skip all undigsested letters */
1359 while (idx
< in
->len
&& ISNEXTCHAR (in
->ptr
[idx
]))
1361 sb_add_char (out
, in
->ptr
[idx
]);
1365 else if (in
->ptr
[idx
] == '"' || in
->ptr
[idx
] == '\'')
1367 char tchar
= in
->ptr
[idx
];
1368 /* copy entire names through quickly */
1369 sb_add_char (out
, in
->ptr
[idx
]);
1371 while (idx
< in
->len
&& in
->ptr
[idx
] != tchar
)
1373 sb_add_char (out
, in
->ptr
[idx
]);
1379 /* nothing special, just pass it through */
1380 sb_add_char (out
, in
->ptr
[idx
]);
1397 do_assign (again
, idx
, in
)
1402 /* stick label in symbol table with following value */
1407 idx
= exp_parse (idx
, in
, &e
);
1408 exp_string (&e
, &acc
);
1409 hash_add_to_string_table (&assign_hash_table
, &label
, &acc
, again
);
1414 /* .radix [b|q|d|h] */
1421 int idx
= sb_skip_white (0, ptr
);
1422 switch (ptr
->ptr
[idx
])
1441 ERROR ((stderr
, "radix is %c must be one of b, q, d or h", radix
));
1446 /* Parse off a .b, .w or .l */
1449 get_opsize (idx
, in
, size
)
1455 if (in
->ptr
[idx
] == '.')
1459 switch (in
->ptr
[idx
])
1477 ERROR ((stderr
, "size must be one of b, w or l, is %c.\n", in
->ptr
[idx
]));
1490 idx
= sb_skip_white (idx
, line
);
1492 && ISCOMMENTCHAR(line
->ptr
[idx
]))
1494 if (idx
>= line
->len
)
1499 /* .data [.b|.w|.l] <data>*
1500 or d[bwl] <data>* */
1503 do_data (idx
, in
, size
)
1509 char *opname
= ".yikes!";
1515 idx
= get_opsize (idx
, in
, &opsize
);
1534 fprintf (outfile
, "%s\t", opname
);
1536 idx
= sb_skip_white (idx
, in
);
1540 && in
->ptr
[idx
] == '"')
1543 idx
= getstring (idx
, in
, &acc
);
1544 for (i
= 0; i
< acc
.len
; i
++)
1547 fprintf(outfile
,",");
1548 fprintf (outfile
, "%d", acc
.ptr
[i
]);
1553 while (!eol (idx
, in
))
1556 idx
= exp_parse (idx
, in
, &e
);
1557 exp_string (&e
, &acc
);
1558 sb_add_char (&acc
, 0);
1559 fprintf (outfile
, acc
.ptr
);
1560 if (idx
< in
->len
&& in
->ptr
[idx
] == ',')
1562 fprintf (outfile
, ",");
1568 sb_print_at (idx
, in
);
1569 fprintf (outfile
, "\n");
1572 /* .datab [.b|.w|.l] <repeat>,<fill> */
1583 idx
= get_opsize (idx
, in
, &opsize
);
1585 idx
= exp_get_abs ("datab repeat must be constant.\n", idx
, in
, &repeat
);
1586 idx
= sb_skip_comma (idx
, in
);
1587 idx
= exp_get_abs ("datab data must be absolute.\n", idx
, in
, &fill
);
1589 fprintf (outfile
, ".fill\t%d,%d,%d\n", repeat
, opsize
, fill
);
1600 idx
= exp_get_abs ("align needs absolute expression.\n", idx
, in
, &al
);
1605 WARNING ((stderr
, "alignment must be one of 1, 2 or 4.\n"));
1607 fprintf (outfile
, ".align %d\n", al
);
1610 /* .res[.b|.w|.l] <size> */
1613 do_res (idx
, in
, type
)
1621 idx
= get_opsize (idx
, in
, &size
);
1622 while (!eol(idx
, in
))
1624 idx
= sb_skip_white (idx
, in
);
1625 if (in
->ptr
[idx
] == ',')
1627 idx
= exp_get_abs ("res needs absolute expression for fill count.\n", idx
, in
, &count
);
1629 if (type
== 'c' || type
== 'z')
1632 fprintf (outfile
, ".space %d\n", count
* size
);
1643 fprintf (outfile
, ".global %s\n", sb_name (in
));
1646 /* .print [list] [nolist] */
1653 idx
= sb_skip_white (idx
, in
);
1654 while (idx
< in
->len
)
1656 if (strncasecmp (in
->ptr
+ idx
, "LIST", 4) == 0)
1658 fprintf (outfile
, ".list\n");
1661 else if (strncasecmp (in
->ptr
+ idx
, "NOLIST", 6) == 0)
1663 fprintf (outfile
, ".nolist\n");
1672 do_heading (idx
, in
)
1678 idx
= getstring (idx
, in
, &head
);
1679 fprintf (outfile
, ".title \"%s\"\n", sb_name (&head
));
1688 fprintf (outfile
, ".eject\n");
1691 /* .form [lin=<value>] [col=<value>] */
1699 idx
= sb_skip_white (idx
, in
);
1701 while (idx
< in
->len
)
1704 if (strncasecmp (in
->ptr
+ idx
, "LIN=", 4) == 0)
1707 idx
= exp_get_abs ("form LIN= needs absolute expresssion.\n", idx
, in
, &lines
);
1710 if (strncasecmp (in
->ptr
+ idx
, "COL=", 4) == 0)
1713 idx
= exp_get_abs ("form COL= needs absolute expresssion.\n", idx
, in
, &columns
);
1718 fprintf (outfile
, ".psize %d,%d\n", lines
, columns
);
1723 /* Fetch string from the input stream,
1725 'Bxyx<whitespace> -> return 'Bxyza
1726 %<char> -> return string of decimal value of x
1727 "<string>" -> return string
1728 xyx<whitespace> -> return xyz
1731 get_any_string (idx
, in
, out
, expand
, pretend_quoted
)
1739 idx
= sb_skip_white (idx
, in
);
1743 if (in
->len
> 2 && in
->ptr
[idx
+1] == '\'' && ISBASE (in
->ptr
[idx
]))
1745 while (!ISSEP (in
->ptr
[idx
]))
1746 sb_add_char (out
, in
->ptr
[idx
++]);
1748 else if (in
->ptr
[idx
] == '%'
1754 /* Turns the next expression into a string */
1755 idx
= exp_get_abs ("% operator needs absolute expression",
1759 sprintf(buf
, "%d", val
);
1760 sb_add_string (out
, buf
);
1762 else if (in
->ptr
[idx
] == '"'
1763 || in
->ptr
[idx
] == '<'
1764 || (alternate
&& in
->ptr
[idx
] == '\''))
1766 if (alternate
&& expand
)
1768 /* Keep the quotes */
1769 sb_add_char (out
, '\"');
1771 idx
= getstring (idx
, in
, out
);
1772 sb_add_char (out
, '\"');
1776 idx
= getstring (idx
, in
, out
);
1781 while (idx
< in
->len
1782 && (in
->ptr
[idx
] == '"'
1783 || in
->ptr
[idx
] == '\''
1785 || !ISSEP (in
->ptr
[idx
])))
1787 if (in
->ptr
[idx
] == '"'
1788 || in
->ptr
[idx
] == '\'')
1790 char tchar
= in
->ptr
[idx
];
1791 sb_add_char (out
, in
->ptr
[idx
++]);
1792 while (idx
< in
->len
1793 && in
->ptr
[idx
] != tchar
)
1794 sb_add_char (out
, in
->ptr
[idx
++]);
1798 sb_add_char (out
, in
->ptr
[idx
++]);
1807 /* skip along sb in starting at idx, suck off whitespace a ( and more
1808 whitespace. return the idx of the next char */
1811 skip_openp (idx
, in
)
1815 idx
= sb_skip_white (idx
, in
);
1816 if (in
->ptr
[idx
] != '(')
1817 ERROR ((stderr
, "misplaced ( .\n"));
1818 idx
= sb_skip_white (idx
+ 1, in
);
1822 /* skip along sb in starting at idx, suck off whitespace a ) and more
1823 whitespace. return the idx of the next char */
1826 skip_closep (idx
, in
)
1830 idx
= sb_skip_white (idx
, in
);
1831 if (in
->ptr
[idx
] != ')')
1832 ERROR ((stderr
, "misplaced ).\n"));
1833 idx
= sb_skip_white (idx
+ 1, in
);
1840 dolen (idx
, in
, out
)
1849 sb_new (&stringout
);
1850 idx
= skip_openp (idx
, in
);
1851 idx
= get_and_process (idx
, in
, &stringout
);
1852 idx
= skip_closep (idx
, in
);
1853 sprintf (buffer
, "%d", stringout
.len
);
1854 sb_add_string (out
, buffer
);
1856 sb_kill (&stringout
);
1865 doinstr (idx
, in
, out
)
1879 idx
= skip_openp (idx
, in
);
1880 idx
= get_and_process (idx
, in
, &string
);
1881 idx
= sb_skip_comma (idx
, in
);
1882 idx
= get_and_process (idx
, in
, &search
);
1883 idx
= sb_skip_comma (idx
, in
);
1884 if (isdigit (in
->ptr
[idx
]))
1886 idx
= exp_get_abs (".instr needs absolute expresson.\n", idx
, in
, &start
);
1892 idx
= skip_closep (idx
, in
);
1894 for (i
= start
; i
< string
.len
; i
++)
1896 if (strncmp (string
.ptr
+ i
, search
.ptr
, search
.len
) == 0)
1902 sprintf (buffer
, "%d", res
);
1903 sb_add_string (out
, buffer
);
1911 dosubstr (idx
, in
, out
)
1921 idx
= skip_openp (idx
, in
);
1922 idx
= get_and_process (idx
, in
, &string
);
1923 idx
= sb_skip_comma (idx
, in
);
1924 idx
= exp_get_abs ("need absolute position.\n", idx
, in
, &pos
);
1925 idx
= sb_skip_comma (idx
, in
);
1926 idx
= exp_get_abs ("need absolute length.\n", idx
, in
, &len
);
1927 idx
= skip_closep (idx
, in
);
1930 if (len
< 0 || pos
< 0 ||
1932 || pos
+ len
> string
.len
)
1934 sb_add_string (out
, " ");
1938 sb_add_char (out
, '"');
1941 sb_add_char (out
, string
.ptr
[pos
++]);
1944 sb_add_char (out
, '"');
1950 /* scan line, change tokens in the hash table to their replacements */
1952 process_assigns (idx
, in
, buf
)
1957 while (idx
< in
->len
)
1960 if (in
->ptr
[idx
] == '\\'
1961 && in
->ptr
[idx
+ 1] == '&')
1963 idx
= condass_lookup_name (in
, idx
+ 2, buf
, 1);
1965 else if (in
->ptr
[idx
] == '\\'
1966 && in
->ptr
[idx
+ 1] == '$')
1968 idx
= condass_lookup_name (in
, idx
+ 2, buf
, 0);
1970 else if (idx
+ 3 < in
->len
1971 && in
->ptr
[idx
] == '.'
1972 && toupper ((unsigned char) in
->ptr
[idx
+ 1]) == 'L'
1973 && toupper ((unsigned char) in
->ptr
[idx
+ 2]) == 'E'
1974 && toupper ((unsigned char) in
->ptr
[idx
+ 3]) == 'N')
1975 idx
= dolen (idx
+ 4, in
, buf
);
1976 else if (idx
+ 6 < in
->len
1977 && in
->ptr
[idx
] == '.'
1978 && toupper ((unsigned char) in
->ptr
[idx
+ 1]) == 'I'
1979 && toupper ((unsigned char) in
->ptr
[idx
+ 2]) == 'N'
1980 && toupper ((unsigned char) in
->ptr
[idx
+ 3]) == 'S'
1981 && toupper ((unsigned char) in
->ptr
[idx
+ 4]) == 'T'
1982 && toupper ((unsigned char) in
->ptr
[idx
+ 5]) == 'R')
1983 idx
= doinstr (idx
+ 6, in
, buf
);
1984 else if (idx
+ 7 < in
->len
1985 && in
->ptr
[idx
] == '.'
1986 && toupper ((unsigned char) in
->ptr
[idx
+ 1]) == 'S'
1987 && toupper ((unsigned char) in
->ptr
[idx
+ 2]) == 'U'
1988 && toupper ((unsigned char) in
->ptr
[idx
+ 3]) == 'B'
1989 && toupper ((unsigned char) in
->ptr
[idx
+ 4]) == 'S'
1990 && toupper ((unsigned char) in
->ptr
[idx
+ 5]) == 'T'
1991 && toupper ((unsigned char) in
->ptr
[idx
+ 6]) == 'R')
1992 idx
= dosubstr (idx
+ 7, in
, buf
);
1993 else if (ISFIRSTCHAR (in
->ptr
[idx
]))
1995 /* may be a simple name subsitution, see if we have a word */
1998 while (cur
< in
->len
1999 && (ISNEXTCHAR (in
->ptr
[cur
])))
2003 sb_add_buffer (&acc
, in
->ptr
+ idx
, cur
- idx
);
2004 ptr
= hash_lookup (&assign_hash_table
, &acc
);
2007 /* Found a definition for it */
2008 sb_add_sb (buf
, &ptr
->value
.s
);
2012 /* No definition, just copy the word */
2013 sb_add_sb (buf
, &acc
);
2020 sb_add_char (buf
, in
->ptr
[idx
++]);
2026 get_and_process (idx
, in
, out
)
2033 idx
= get_any_string (idx
, in
, &t
, 1, 0);
2034 process_assigns (0, &t
, out
);
2055 more
= get_line (&line
);
2058 /* Find any label and pseudo op that we're intested in */
2063 fprintf (outfile
, "\n");
2067 l
= grab_label (&line
, &label_in
);
2071 /* Munge any label */
2074 process_assigns (0, &label_in
, &label
);
2077 if (line
.ptr
[l
] == ':')
2079 while (ISWHITE (line
.ptr
[l
]) && l
< line
.len
)
2084 if (process_pseudo_op (l
, &line
, &acc
))
2090 else if (condass_on ())
2092 if (macro_op (l
, &line
))
2102 fprintf (outfile
, "%s:\t", sb_name (&label
));
2105 fprintf (outfile
, "\t");
2107 process_assigns (l
, &line
, &t1
);
2109 change_base (0, &t1
, &t2
);
2110 fprintf (outfile
, "%s\n", sb_name (&t2
));
2116 /* Only a label on this line */
2117 if (label
.len
&& condass_on())
2119 fprintf (outfile
, "%s:\n", sb_name (&label
));
2127 more
= get_line (&line
);
2131 WARNING ((stderr
, "END missing from end of file.\n"));
2139 free_old_entry (ptr
)
2144 if (ptr
->type
== hash_string
)
2145 sb_kill(&ptr
->value
.s
);
2149 /* name: .ASSIGNA <value> */
2152 do_assigna (idx
, in
)
2160 process_assigns (idx
, in
, &tmp
);
2161 idx
= exp_get_abs (".ASSIGNA needs constant expression argument.\n", 0, &tmp
, &val
);
2165 ERROR ((stderr
, ".ASSIGNA without label.\n"));
2169 hash_entry
*ptr
= hash_create (&vars
, &label
);
2170 free_old_entry (ptr
);
2171 ptr
->type
= hash_integer
;
2177 /* name: .ASSIGNC <string> */
2180 do_assignc (idx
, in
)
2186 idx
= getstring (idx
, in
, &acc
);
2190 ERROR ((stderr
, ".ASSIGNS without label.\n"));
2194 hash_entry
*ptr
= hash_create (&vars
, &label
);
2195 free_old_entry (ptr
);
2196 ptr
->type
= hash_string
;
2197 sb_new (&ptr
->value
.s
);
2198 sb_add_sb (&ptr
->value
.s
, &acc
);
2204 /* name: .REG (reg) */
2211 /* remove reg stuff from inside parens */
2213 idx
= skip_openp (idx
, in
);
2215 while (idx
< in
->len
&& in
->ptr
[idx
] != ')')
2217 sb_add_char (&what
, in
->ptr
[idx
]);
2220 hash_add_to_string_table (&assign_hash_table
, &label
, &what
, 1);
2226 condass_lookup_name (inbuf
, idx
, out
, warn
)
2234 sb_new (&condass_acc
);
2236 while (idx
< inbuf
->len
2237 && ISNEXTCHAR (inbuf
->ptr
[idx
]))
2239 sb_add_char (&condass_acc
, inbuf
->ptr
[idx
++]);
2242 if (inbuf
->ptr
[idx
] == '\'')
2244 ptr
= hash_lookup (&vars
, &condass_acc
);
2251 WARNING ((stderr
, "Can't find preprocessor variable %s.\n", sb_name (&condass_acc
)));
2255 sb_add_string (out
, "0");
2260 if (ptr
->type
== hash_integer
)
2263 sprintf (buffer
, "%d", ptr
->value
.i
);
2264 sb_add_string (out
, buffer
);
2268 sb_add_sb (out
, &ptr
->value
.s
);
2271 sb_kill (&condass_acc
);
2284 whatcond (idx
, in
, val
)
2291 idx
= sb_skip_white (idx
, in
);
2293 if (idx
+ 1 < in
->len
)
2299 a
= toupper ((unsigned char) p
[0]);
2300 b
= toupper ((unsigned char) p
[1]);
2301 if (a
== 'E' && b
== 'Q')
2303 else if (a
== 'N' && b
== 'E')
2305 else if (a
== 'L' && b
== 'T')
2307 else if (a
== 'L' && b
== 'E')
2309 else if (a
== 'G' && b
== 'T')
2311 else if (a
== 'G' && b
== 'E')
2316 ERROR ((stderr
, "Comparison operator must be one of EQ, NE, LT, LE, GT or GE.\n"));
2319 idx
= sb_skip_white (idx
+ 2, in
);
2336 idx
= sb_skip_white (idx
, in
);
2338 if (in
->ptr
[idx
] == '"')
2342 /* This is a string comparision */
2343 idx
= getstring (idx
, in
, &acc_a
);
2344 idx
= whatcond (idx
, in
, &cond
);
2345 idx
= getstring (idx
, in
, &acc_b
);
2346 same
= acc_a
.len
== acc_b
.len
&& (strncmp (acc_a
.ptr
, acc_b
.ptr
, acc_a
.len
) == 0);
2348 if (cond
!= EQ
&& cond
!= NE
)
2350 ERROR ((stderr
, "Comparison operator for strings must be EQ or NE\n"));
2354 res
= (cond
!= EQ
) ^ same
;
2357 /* This is a numeric expression */
2362 idx
= exp_get_abs ("Conditional operator must have absolute operands.\n", idx
, in
, &vala
);
2363 idx
= whatcond (idx
, in
, &cond
);
2364 idx
= sb_skip_white (idx
, in
);
2365 if (in
->ptr
[idx
] == '"')
2367 WARNING ((stderr
, "String compared against expression.\n"));
2372 idx
= exp_get_abs ("Conditional operator must have absolute operands.\n", idx
, in
, &valb
);
2415 if (ifi
>= IFNESTING
)
2417 FATAL ((stderr
, "AIF nesting unreasonable.\n"));
2420 ifstack
[ifi
].on
= ifstack
[ifi
-1].on
? istrue (idx
, in
) : 0;
2421 ifstack
[ifi
].hadelse
= 0;
2429 ifstack
[ifi
].on
= ifstack
[ifi
-1].on
? !ifstack
[ifi
].on
: 0;
2430 if (ifstack
[ifi
].hadelse
)
2432 ERROR ((stderr
, "Multiple AELSEs in AIF.\n"));
2434 ifstack
[ifi
].hadelse
= 1;
2448 ERROR ((stderr
, "AENDI without AIF.\n"));
2455 return ifstack
[ifi
].on
;
2459 /* Read input lines till we get to a TO string.
2460 Increase nesting depth if we geta FROM string.
2461 Put the results into sb at PTR. */
2464 buffer_and_nest (from
, to
, ptr
)
2469 int from_len
= strlen (from
);
2470 int to_len
= strlen (to
);
2472 int line_start
= ptr
->len
;
2473 int line
= linecount ();
2475 int more
= get_line (ptr
);
2479 /* Try and find the first pseudo op on the line */
2484 /* With normal syntax we can suck what we want till we get to the dot.
2485 With the alternate, labels have to start in the first column, since
2486 we cant tell what's a label and whats a pseudoop */
2488 /* Skip leading whitespace */
2490 && ISWHITE (ptr
->ptr
[i
]))
2493 /* Skip over a label */
2495 && ISNEXTCHAR (ptr
->ptr
[i
]))
2500 && ptr
->ptr
[i
] == ':')
2504 /* Skip trailing whitespace */
2506 && ISWHITE (ptr
->ptr
[i
]))
2509 if (i
< ptr
->len
&& (ptr
->ptr
[i
] == '.'
2512 if (ptr
->ptr
[i
] == '.')
2514 if (strncasecmp (ptr
->ptr
+ i
, from
, from_len
) == 0)
2516 if (strncasecmp (ptr
->ptr
+ i
, to
, to_len
) == 0)
2521 /* Reset the string to not include the ending rune */
2522 ptr
->len
= line_start
;
2528 /* Add a CR to the end and keep running */
2529 sb_add_char (ptr
, '\n');
2530 line_start
= ptr
->len
;
2531 more
= get_line (ptr
);
2536 FATAL ((stderr
, "End of file whilst inside %s, started on line %d.\n", from
, line
));
2544 ERROR ((stderr
, "AENDR without a AREPEAT.\n"));
2563 process_assigns (idx
, in
, &exp
);
2564 doit
= istrue (0, &exp
);
2566 buffer_and_nest ("AWHILE", "AENDW", &sub
);
2581 int index
= include_next_index ();
2585 sb_add_sb (©
, &sub
);
2586 sb_add_sb (©
, in
);
2587 sb_add_string (©
, "\n");
2588 sb_add_sb (©
, &sub
);
2589 sb_add_string (©
, "\t.AENDW\n");
2590 /* Push another WHILE */
2591 include_buf (&exp
, ©
, include_while
, index
);
2604 ERROR ((stderr
, "AENDW without a AENDW.\n"));
2610 Pop things off the include stack until the type and index changes */
2615 include_type type
= sp
->type
;
2616 if (type
== include_repeat
2617 || type
== include_while
2618 || type
== include_macro
)
2620 int index
= sp
->index
;
2622 while (sp
->index
== index
2623 && sp
->type
== type
)
2633 do_arepeat (idx
, in
)
2637 sb exp
; /* buffer with expression in it */
2638 sb copy
; /* expanded repeat block */
2639 sb sub
; /* contents of AREPEAT */
2645 process_assigns (idx
, in
, &exp
);
2646 idx
= exp_get_abs ("AREPEAT must have absolute operand.\n", 0, &exp
, &rc
);
2647 buffer_and_nest ("AREPEAT", "AENDR", &sub
);
2650 /* Push back the text following the repeat, and another repeat block
2661 int index
= include_next_index ();
2662 sb_add_sb (©
, &sub
);
2665 sprintf (buffer
, "\t.AREPEAT %d\n", rc
- 1);
2666 sb_add_string (©
, buffer
);
2667 sb_add_sb (©
, &sub
);
2668 sb_add_string (©
, " .AENDR\n");
2671 include_buf (&exp
, ©
, include_repeat
, index
);
2683 ERROR ((stderr
, ".ENDM without a matching .MACRO.\n"));
2687 /* MARRO PROCESSING */
2690 hash_table macro_table
;
2700 do_formals (macro
, idx
, in
)
2705 formal_entry
**p
= ¯o
->formals
;
2706 macro
->formal_count
= 0;
2707 hash_new_table (5, ¯o
->formal_hash
);
2708 while (idx
< in
->len
)
2710 formal_entry
*formal
;
2712 formal
= (formal_entry
*) xmalloc (sizeof (formal_entry
));
2714 sb_new (&formal
->name
);
2715 sb_new (&formal
->def
);
2716 sb_new (&formal
->actual
);
2718 idx
= sb_skip_white (idx
, in
);
2719 idx
= get_token (idx
, in
, &formal
->name
);
2720 if (formal
->name
.len
== 0)
2722 idx
= sb_skip_white (idx
, in
);
2723 if (formal
->name
.len
)
2725 /* This is a formal */
2726 if (idx
< in
->len
&& in
->ptr
[idx
] == '=')
2729 idx
= get_any_string (idx
+ 1, in
, &formal
->def
, 1, 0);
2734 /* Add to macro's hash table */
2736 hash_entry
*p
= hash_create (¯o
->formal_hash
, &formal
->name
);
2737 p
->type
= hash_formal
;
2738 p
->value
.f
= formal
;
2741 formal
->index
= macro
->formal_count
;
2742 idx
= sb_skip_comma (idx
, in
);
2743 macro
->formal_count
++;
2750 /* Parse off LOCAL n1, n2,... Invent a label name for it */
2753 do_local (idx
, line
)
2763 idx
= sb_skip_white (idx
, line
);
2764 while (!eol(idx
, line
))
2769 sprintf(subs
, "LL%04x", ln
);
2770 idx
= get_token(idx
, line
, &acc
);
2771 sb_add_string (&sub
, subs
);
2772 hash_add_to_string_table (&assign_hash_table
, &acc
, &sub
, 1);
2773 idx
= sb_skip_comma (idx
, line
);
2788 macro
= (macro_entry
*) xmalloc (sizeof (macro_entry
));
2789 sb_new (¯o
->sub
);
2792 macro
->formal_count
= 0;
2795 idx
= sb_skip_white (idx
, in
);
2796 buffer_and_nest ("MACRO", "ENDM", ¯o
->sub
);
2800 sb_add_sb (&name
, &label
);
2801 if (in
->ptr
[idx
] == '(')
2803 /* It's the label: MACRO (formals,...) sort */
2804 idx
= do_formals (macro
, idx
+ 1, in
);
2805 if (in
->ptr
[idx
] != ')')
2806 ERROR ((stderr
, "Missing ) after formals.\n"));
2809 /* It's the label: MACRO formals,... sort */
2810 idx
= do_formals (macro
, idx
, in
);
2815 idx
= get_token (idx
, in
, &name
);
2816 idx
= sb_skip_white (idx
, in
);
2817 idx
= do_formals (macro
, idx
, in
);
2820 /* and stick it in the macro hash table */
2821 hash_create (¯o_table
, &name
)->value
.m
= macro
;
2826 get_token (idx
, in
, name
)
2832 && ISFIRSTCHAR (in
->ptr
[idx
]))
2834 sb_add_char (name
, in
->ptr
[idx
++]);
2835 while (idx
< in
->len
2836 && ISNEXTCHAR (in
->ptr
[idx
]))
2838 sb_add_char (name
, in
->ptr
[idx
++]);
2841 /* Ignore trailing & */
2842 if (alternate
&& idx
< in
->len
&& in
->ptr
[idx
] == '&')
2847 /* Scan a token, but stop if a ' is seen */
2849 get_apost_token (idx
, in
, name
, kind
)
2855 idx
= get_token (idx
, in
, name
);
2856 if (idx
< in
->len
&& in
->ptr
[idx
] == kind
)
2862 sub_actual (src
, in
, t
, m
, kind
, out
, copyifnotthere
)
2871 /* This is something to take care of */
2873 src
= get_apost_token (src
, in
, t
, kind
);
2874 /* See if it's in the macro's hash table */
2875 ptr
= hash_lookup (&m
->formal_hash
, t
);
2878 if (ptr
->value
.f
->actual
.len
)
2880 sb_add_sb (out
, &ptr
->value
.f
->actual
);
2884 sb_add_sb (out
, &ptr
->value
.f
->def
);
2887 else if (copyifnotthere
)
2893 sb_add_char (out
, '\\');
2901 macro_expand (name
, idx
, in
, m
)
2911 int is_positional
= 0;
2917 /* Reset any old value the actuals may have */
2918 for (f
= m
->formals
; f
; f
= f
->next
)
2919 sb_reset (&f
->actual
);
2921 /* Peel off the actuals and store them away in the hash tables' actuals */
2922 while (!eol(idx
, in
))
2925 idx
= sb_skip_white (idx
, in
);
2926 /* Look and see if it's a positional or keyword arg */
2928 while (scan
< in
->len
2929 && !ISSEP (in
->ptr
[scan
])
2930 && (!alternate
&& in
->ptr
[scan
] != '='))
2932 if (scan
< in
->len
&& (!alternate
) && in
->ptr
[scan
] == '=')
2937 ERROR ((stderr
, "Can't mix positional and keyword arguments.\n"));
2940 /* This is a keyword arg, fetch the formal name and
2941 then the actual stuff */
2943 idx
= get_token (idx
, in
, &t
);
2944 if (in
->ptr
[idx
] != '=')
2945 ERROR ((stderr
, "confused about formal params.\n"));
2947 /* Lookup the formal in the macro's list */
2948 ptr
= hash_lookup (&m
->formal_hash
, &t
);
2951 ERROR ((stderr
, "MACRO formal argument %s does not exist.\n", sb_name (&t
)));
2956 /* Insert this value into the right place */
2957 sb_reset (&ptr
->value
.f
->actual
);
2958 idx
= get_any_string (idx
+ 1, in
, &ptr
->value
.f
->actual
, 0, 0);
2963 /* This is a positional arg */
2967 ERROR ((stderr
, "Can't mix positional and keyword arguments.\n"));
2972 ERROR ((stderr
, "Too many positional arguments.\n"));
2976 sb_reset (&f
->actual
);
2977 idx
= get_any_string (idx
, in
, &f
->actual
, 1, 0);
2980 idx
= sb_skip_comma (idx
, in
);
2983 /* Copy the stuff from the macro buffer into a safe place and substitute any args */
2991 while (src
< in
->len
)
2993 if (in
->ptr
[src
] == '&')
2996 src
= sub_actual (src
+ 1, in
, &t
, m
, '&', &out
, 0);
2998 else if (in
->ptr
[src
] == '\\')
3001 if (in
->ptr
[src
] == comment_char
)
3003 /* This is a comment, just drop the rest of the line */
3004 while (src
< in
->len
3005 && in
->ptr
[src
] != '\n')
3009 else if (in
->ptr
[src
] == '(')
3011 /* Sub in till the next ')' literally */
3013 while (src
< in
->len
&& in
->ptr
[src
] != ')')
3015 sb_add_char (&out
, in
->ptr
[src
++]);
3017 if (in
->ptr
[src
] == ')')
3020 ERROR ((stderr
, "Missplaced ).\n"));
3022 else if (in
->ptr
[src
] == '@')
3024 /* Sub in the macro invocation number */
3028 sprintf (buffer
, "%05d", number
);
3029 sb_add_string (&out
, buffer
);
3031 else if (in
->ptr
[src
] == '&')
3033 /* This is a preprocessor variable name, we don't do them
3035 sb_add_char (&out
, '\\');
3036 sb_add_char (&out
, '&');
3042 src
= sub_actual (src
, in
, &t
, m
, '\'', &out
, 0);
3045 else if (ISFIRSTCHAR (in
->ptr
[src
]) && alternate
)
3048 src
= sub_actual (src
, in
, &t
, m
, '\'', &out
, 1);
3050 else if (ISCOMMENTCHAR (in
->ptr
[src
])
3051 && src
+ 1 < in
->len
3052 && ISCOMMENTCHAR (in
->ptr
[src
+1])
3055 /* Two comment chars in a row cause the rest of the line to be dropped */
3056 while (src
< in
->len
&& in
->ptr
[src
] != '\n')
3059 else if (in
->ptr
[src
] == '"')
3062 sb_add_char (&out
, in
->ptr
[src
++]);
3066 sb_add_char (&out
, in
->ptr
[src
++]);
3069 include_buf (name
, &out
, include_macro
, include_next_index ());
3082 /* The macro name must be the first thing on the line */
3088 idx
= get_token (idx
, in
, &name
);
3092 /* Got a name, look it up */
3094 ptr
= hash_lookup (¯o_table
, &name
);
3098 /* It's in the table, copy out the stuff and convert any macro args */
3099 macro_expand (&name
, idx
, in
, ptr
->value
.m
);
3111 /* STRING HANDLING */
3114 getstring (idx
, in
, acc
)
3119 idx
= sb_skip_white (idx
, in
);
3121 while (idx
< in
->len
3122 && (in
->ptr
[idx
] == '"'
3123 || in
->ptr
[idx
] == '<'
3124 || (in
->ptr
[idx
] == '\'' && alternate
)))
3126 if (in
->ptr
[idx
] == '<')
3132 while ((in
->ptr
[idx
] != '>' || nest
)
3135 if (in
->ptr
[idx
] == '!')
3138 sb_add_char (acc
, in
->ptr
[idx
++]);
3141 if (in
->ptr
[idx
] == '>')
3143 if (in
->ptr
[idx
] == '<')
3145 sb_add_char (acc
, in
->ptr
[idx
++]);
3153 idx
= exp_get_abs ("Character code in string must be absolute expression.\n",
3155 sb_add_char (acc
, code
);
3157 if (in
->ptr
[idx
] != '>')
3158 ERROR ((stderr
, "Missing > for character code.\n"));
3162 else if (in
->ptr
[idx
] == '"' || in
->ptr
[idx
] == '\'')
3164 char tchar
= in
->ptr
[idx
];
3166 while (idx
< in
->len
)
3168 if (alternate
&& in
->ptr
[idx
] == '!')
3171 sb_add_char (acc
, in
->ptr
[idx
++]);
3174 if (in
->ptr
[idx
] == tchar
)
3177 if (idx
>= in
->len
|| in
->ptr
[idx
] != tchar
)
3180 sb_add_char (acc
, in
->ptr
[idx
]);
3190 /* .SDATA[C|Z] <string> */
3194 do_sdata (idx
, in
, type
)
3203 fprintf (outfile
, ".byte\t");
3205 while (!eol (idx
, in
))
3209 idx
= sb_skip_white (idx
, in
);
3210 while (!eol (idx
, in
))
3212 pidx
= idx
= get_any_string (idx
, in
, &acc
, 0, 1);
3217 ERROR ((stderr
, "string for SDATAC longer than 255 characters (%d).\n", acc
.len
));
3219 fprintf (outfile
, "%d", acc
.len
);
3223 for (i
= 0; i
< acc
.len
; i
++)
3227 fprintf (outfile
, ",");
3229 fprintf (outfile
, "%d", acc
.ptr
[i
]);
3236 fprintf (outfile
, ",");
3237 fprintf (outfile
, "0");
3239 idx
= sb_skip_comma (idx
, in
);
3240 if (idx
== pidx
) break;
3242 if (!alternate
&& in
->ptr
[idx
] != ',' && idx
!= in
->len
)
3244 fprintf (outfile
, "\n");
3245 ERROR ((stderr
, "illegal character in SDATA line (0x%x).\n", in
->ptr
[idx
]));
3251 fprintf (outfile
, "\n");
3254 /* .SDATAB <count> <string> */
3266 idx
= exp_get_abs ("Must have absolute SDATAB repeat count.\n", idx
, in
, &repeat
);
3269 ERROR ((stderr
, "Must have positive SDATAB repeat count (%d).\n", repeat
));
3273 idx
= sb_skip_comma (idx
, in
);
3274 idx
= getstring (idx
, in
, &acc
);
3276 for (i
= 0; i
< repeat
; i
++)
3279 fprintf (outfile
, "\t");
3280 fprintf (outfile
, ".byte\t");
3282 fprintf (outfile
, "\n");
3292 FILE *newone
= fopen (name
, "r");
3296 if (isp
== MAX_INCLUDES
)
3297 FATAL ((stderr
, "Unreasonable include depth (%ld).\n", (long) isp
));
3300 sp
->handle
= newone
;
3303 sb_add_string (&sp
->name
, name
);
3306 sp
->pushback_index
= 0;
3307 sp
->type
= include_file
;
3309 sb_new (&sp
->pushback
);
3314 do_include (idx
, in
)
3321 idx
= getstring (idx
, in
, &t
);
3322 text
= sb_name (&t
);
3323 if (!new_file (text
))
3325 FATAL ((stderr
, "Can't open include file `%s'.\n", text
));
3333 if (sp
!= include_stack
)
3336 fclose (sp
->handle
);
3341 /* Get the next character from the include stack. If there's anything
3342 in the pushback buffer, take that first. If we're at eof, pop from
3343 the stack and try again. Keep the linecount up to date. */
3350 if (sp
->pushback
.len
!= sp
->pushback_index
)
3352 r
= (char) (sp
->pushback
.ptr
[sp
->pushback_index
++]);
3353 /* When they've all gone, reset the pointer */
3354 if (sp
->pushback_index
== sp
->pushback
.len
)
3356 sp
->pushback
.len
= 0;
3357 sp
->pushback_index
= 0;
3360 else if (sp
->handle
)
3362 r
= getc (sp
->handle
);
3367 if (r
== EOF
&& isp
)
3371 while (r
== EOF
&& isp
)
3389 return sp
->linecount
;
3393 include_next_index ()
3397 && index
> MAX_REASONABLE
)
3398 FATAL ((stderr
, "Unreasonable expansion (-u turns off check).\n"));
3403 /* Initialize the chartype vector. */
3409 for (x
= 0; x
< 256; x
++)
3411 if (isalpha (x
) || x
== '_' || x
== '$')
3412 chartype
[x
] |= FIRSTBIT
;
3414 if (isdigit (x
) || isalpha (x
) || x
== '_' || x
== '$')
3415 chartype
[x
] |= NEXTBIT
;
3417 if (x
== ' ' || x
== '\t' || x
== ',' || x
== '"' || x
== ';'
3418 || x
== '"' || x
== '<' || x
== '>' || x
== ')' || x
== '(')
3419 chartype
[x
] |= SEPBIT
;
3421 if (x
== 'b' || x
== 'B'
3422 || x
== 'q' || x
== 'Q'
3423 || x
== 'h' || x
== 'H'
3424 || x
== 'd' || x
== 'D')
3425 chartype
[x
] |= BASEBIT
;
3427 if (x
== ' ' || x
== '\t')
3428 chartype
[x
] |= WHITEBIT
;
3430 if (x
== comment_char
)
3431 chartype
[x
] |= COMMENTBIT
;
3437 /* What to do with all the keywords */
3438 #define PROCESS 0x1000 /* Run substitution over the line */
3439 #define LAB 0x2000 /* Spit out the label */
3441 #define K_EQU PROCESS|1
3442 #define K_ASSIGN PROCESS|2
3443 #define K_REG PROCESS|3
3444 #define K_ORG PROCESS|4
3445 #define K_RADIX PROCESS|5
3446 #define K_DATA LAB|PROCESS|6
3447 #define K_DATAB LAB|PROCESS|7
3448 #define K_SDATA LAB|PROCESS|8
3449 #define K_SDATAB LAB|PROCESS|9
3450 #define K_SDATAC LAB|PROCESS|10
3451 #define K_SDATAZ LAB|PROCESS|11
3452 #define K_RES LAB|PROCESS|12
3453 #define K_SRES LAB|PROCESS|13
3454 #define K_SRESC LAB|PROCESS|14
3455 #define K_SRESZ LAB|PROCESS|15
3456 #define K_EXPORT LAB|PROCESS|16
3457 #define K_GLOBAL LAB|PROCESS|17
3458 #define K_PRINT LAB|PROCESS|19
3459 #define K_FORM LAB|PROCESS|20
3460 #define K_HEADING LAB|PROCESS|21
3461 #define K_PAGE LAB|PROCESS|22
3462 #define K_IMPORT LAB|PROCESS|23
3463 #define K_PROGRAM LAB|PROCESS|24
3464 #define K_END PROCESS|25
3465 #define K_INCLUDE PROCESS|26
3466 #define K_IGNORED PROCESS|27
3467 #define K_ASSIGNA PROCESS|28
3468 #define K_ASSIGNC 29
3469 #define K_AIF PROCESS|30
3470 #define K_AELSE PROCESS|31
3471 #define K_AENDI PROCESS|32
3472 #define K_AREPEAT PROCESS|33
3473 #define K_AENDR PROCESS|34
3475 #define K_AENDW PROCESS|36
3477 #define K_MACRO PROCESS|38
3479 #define K_ALIGN PROCESS|LAB|40
3480 #define K_ALTERNATE 41
3481 #define K_DB LAB|PROCESS|42
3482 #define K_DW LAB|PROCESS|43
3483 #define K_DL LAB|PROCESS|44
3495 { "EQU", K_EQU
, 0 },
3496 { "ALTERNATE", K_ALTERNATE
, 0 },
3497 { "ASSIGN", K_ASSIGN
, 0 },
3498 { "REG", K_REG
, 0 },
3499 { "ORG", K_ORG
, 0 },
3500 { "RADIX", K_RADIX
, 0 },
3501 { "DATA", K_DATA
, 0 },
3505 { "DATAB", K_DATAB
, 0 },
3506 { "SDATA", K_SDATA
, 0 },
3507 { "SDATAB", K_SDATAB
, 0 },
3508 { "SDATAZ", K_SDATAZ
, 0 },
3509 { "SDATAC", K_SDATAC
, 0 },
3510 { "RES", K_RES
, 0 },
3511 { "SRES", K_SRES
, 0 },
3512 { "SRESC", K_SRESC
, 0 },
3513 { "SRESZ", K_SRESZ
, 0 },
3514 { "EXPORT", K_EXPORT
, 0 },
3515 { "GLOBAL", K_GLOBAL
, 0 },
3516 { "PRINT", K_PRINT
, 0 },
3517 { "FORM", K_FORM
, 0 },
3518 { "HEADING", K_HEADING
, 0 },
3519 { "PAGE", K_PAGE
, 0 },
3520 { "PROGRAM", K_IGNORED
, 0 },
3521 { "END", K_END
, 0 },
3522 { "INCLUDE", K_INCLUDE
, 0 },
3523 { "ASSIGNA", K_ASSIGNA
, 0 },
3524 { "ASSIGNC", K_ASSIGNC
, 0 },
3525 { "AIF", K_AIF
, 0 },
3526 { "AELSE", K_AELSE
, 0 },
3527 { "AENDI", K_AENDI
, 0 },
3528 { "AREPEAT", K_AREPEAT
, 0 },
3529 { "AENDR", K_AENDR
, 0 },
3530 { "EXITM", K_EXITM
, 0 },
3531 { "MACRO", K_MACRO
, 0 },
3532 { "ENDM", K_ENDM
, 0 },
3533 { "AWHILE", K_AWHILE
, 0 },
3534 { "ALIGN", K_ALIGN
, 0 },
3535 { "AENDW", K_AENDW
, 0 },
3536 { "ALTERNATE", K_ALTERNATE
, 0 },
3537 { "LOCAL", K_LOCAL
, 0 },
3541 /* Look for a pseudo op on the line. If one's there then call
3545 process_pseudo_op (idx
, line
, acc
)
3552 if (line
->ptr
[idx
] == '.' || alternate
)
3554 /* Scan forward and find pseudo name */
3560 if (line
->ptr
[idx
] == '.')
3562 in
= line
->ptr
+ idx
;
3567 while (idx
< line
->len
&& *e
&& ISFIRSTCHAR (*e
))
3569 sb_add_char (acc
, *e
);
3574 ptr
= hash_lookup (&keyword_hash_table
, acc
);
3579 /* This one causes lots of pain when trying to preprocess
3581 WARNING ((stderr
, "Unrecognised pseudo op `%s'.\n", sb_name (acc
)));
3585 if (ptr
->value
.i
& LAB
)
3586 { /* output the label */
3589 fprintf (outfile
, "%s:\t", sb_name (&label
));
3592 fprintf (outfile
, "\t");
3595 if (ptr
->value
.i
& PROCESS
)
3597 /* Polish the rest of the line before handling the pseudo op */
3599 strip_comments(line
);
3602 process_assigns (idx
, line
, acc
);
3604 change_base (0, acc
, line
);
3609 switch (ptr
->value
.i
)
3625 switch (ptr
->value
.i
)
3637 ERROR ((stderr
, "ORG command not allowed.\n"));
3643 do_data (idx
, line
, 1);
3646 do_data (idx
, line
, 2);
3649 do_data (idx
, line
, 4);
3652 do_data (idx
, line
, 0);
3655 do_datab (idx
, line
);
3658 do_sdata (idx
, line
, 0);
3661 do_sdatab (idx
, line
);
3664 do_sdata (idx
, line
, 'c');
3667 do_sdata (idx
, line
, 'z');
3670 do_assign (1, 0, line
);
3676 do_arepeat (idx
, line
);
3682 do_awhile (idx
, line
);
3688 do_assign (0, idx
, line
);
3691 do_align (idx
, line
);
3694 do_res (idx
, line
, 0);
3697 do_res (idx
, line
, 's');
3700 do_include (idx
, line
);
3703 do_local (idx
, line
);
3706 do_macro (idx
, line
);
3712 do_res (idx
, line
, 'c');
3715 do_print (idx
, line
);
3718 do_form (idx
, line
);
3721 do_heading (idx
, line
);
3733 do_res (idx
, line
, 'z');
3741 do_assigna (idx
, line
);
3744 do_assignc (idx
, line
);
3760 /* Build the keyword hash table - put each keyword in the table twice,
3761 once upper and once lower case.*/
3768 for (i
= 0; kinfo
[i
].name
; i
++)
3773 sb_add_string (&label
, kinfo
[i
].name
);
3775 hash_add_to_int_table (&keyword_hash_table
, &label
, kinfo
[i
].code
);
3778 for (j
= 0; kinfo
[i
].name
[j
]; j
++)
3779 sb_add_char (&label
, kinfo
[i
].name
[j
] - 'A' + 'a');
3780 hash_add_to_int_table (&keyword_hash_table
, &label
, kinfo
[i
].code
);
3806 sb_add_char (&value
, *string
);
3809 exp_get_abs ("Invalid expression on command line.\n", 0, &value
, &res
);
3813 sb_add_char (&label
, *string
);
3818 ptr
= hash_create (&vars
, &label
);
3819 free_old_entry (ptr
);
3820 ptr
->type
= hash_integer
;
3826 /* The list of long options. */
3827 static struct option long_options
[] =
3829 { "alternate", no_argument
, 0, 'a' },
3830 { "commentchar", required_argument
, 0, 'c' },
3831 { "copysource", no_argument
, 0, 's' },
3832 { "debug", no_argument
, 0, 'd' },
3833 { "help", no_argument
, 0, 'h' },
3834 { "output", required_argument
, 0, 'o' },
3835 { "print", no_argument
, 0, 'p' },
3836 { "unreasonable", no_argument
, 0, 'u' },
3837 { "version", no_argument
, 0, 'v' },
3838 { "define", required_argument
, 0, 'd' },
3839 { NULL
, no_argument
, 0, 0 }
3842 /* Show a usage message and exit. */
3844 show_usage (file
, status
)
3850 [-a] [--alternate] enter alternate macro mode\n\
3851 [-c char] [--commentchar char] change the comment character from !\n\
3852 [-d] [--debug] print some debugging info\n\
3853 [-h] [--help] print this message\n\
3854 [-o out] [--output out] set the output file\n\
3855 [-p] [--print] print line numbers\n\
3856 [-s] [--copysource] copy source through as comments \n\
3857 [-u] [--unreasonable] allow unreasonable nesting\n\
3858 [-v] [--version] print the program version\n\
3859 [-Dname=value] create preprocessor variable called name, with value\n\
3860 [in-file]\n", program_name
);
3864 /* Display a help message and exit. */
3868 printf ("%s: Gnu Assembler Macro Preprocessor\n",
3870 show_usage (stdout
, 0);
3887 program_name
= argv
[0];
3888 xmalloc_set_program_name (program_name
);
3890 hash_new_table (101, ¯o_table
);
3891 hash_new_table (101, &keyword_hash_table
);
3892 hash_new_table (101, &assign_hash_table
);
3893 hash_new_table (101, &vars
);
3898 while ((opt
= getopt_long (argc
, argv
, "sdhavc:upo:D:", long_options
,
3911 print_line_number
= 1;
3914 comment_char
= optarg
[0];
3932 printf ("GNU %s version %s\n", program_name
, program_version
);
3938 show_usage (stderr
, 1);
3945 outfile
= fopen (out_name
, "w");
3948 fprintf (stderr
, "%s: Can't open output file `%s'.\n",
3949 program_name
, out_name
);
3961 /* Process all the input files */
3963 while (optind
< argc
)
3965 if (new_file (argv
[optind
]))
3971 fprintf (stderr
, "%s: Can't open input file `%s'.\n",
3972 program_name
, argv
[optind
]);