/src/binutils-gdb/gas/macro.c
Line | Count | Source |
1 | | /* macro.c - macro support for gas |
2 | | Copyright (C) 1994-2026 Free Software Foundation, Inc. |
3 | | |
4 | | Written by Steve and Judy Chamberlain of Cygnus Support, |
5 | | sac@cygnus.com |
6 | | |
7 | | This file is part of GAS, the GNU Assembler. |
8 | | |
9 | | GAS 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 3, or (at your option) |
12 | | any later version. |
13 | | |
14 | | GAS is distributed in the hope that it will be useful, |
15 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | | GNU General Public License for more details. |
18 | | |
19 | | You should have received a copy of the GNU General Public License |
20 | | along with GAS; see the file COPYING. If not, write to the Free |
21 | | Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA |
22 | | 02110-1301, USA. */ |
23 | | |
24 | | #include "as.h" |
25 | | #include "safe-ctype.h" |
26 | | #include "sb.h" |
27 | | #include "macro.h" |
28 | | |
29 | | /* The routines in this file handle macro definition and expansion. |
30 | | They are called by gas. */ |
31 | | |
32 | | /* The macro hash table. */ |
33 | | |
34 | | htab_t macro_hash; |
35 | | |
36 | | /* Whether any macros have been defined. */ |
37 | | |
38 | | int macro_defined; |
39 | | |
40 | | /* Whether we should strip '@' characters. */ |
41 | | |
42 | 1.04M | #define macro_strip_at false |
43 | | |
44 | | /* Number of macro expansions that have been done. */ |
45 | | |
46 | | static unsigned int macro_number; |
47 | | |
48 | | static void free_macro (macro_entry *); |
49 | | |
50 | | static void |
51 | | macro_del_f (void *ent) |
52 | 1 | { |
53 | 1 | string_tuple_t *tuple = ent; |
54 | 1 | free_macro ((macro_entry *) tuple->value); |
55 | 1 | } |
56 | | |
57 | | /* Initialize macro processing. */ |
58 | | |
59 | | void |
60 | | macro_init (void) |
61 | 207 | { |
62 | 207 | macro_hash = htab_create_alloc (16, hash_string_tuple, eq_string_tuple, |
63 | 207 | macro_del_f, notes_calloc, NULL); |
64 | 207 | macro_defined = 0; |
65 | 207 | } |
66 | | |
67 | | void |
68 | | macro_end (void) |
69 | 207 | { |
70 | 207 | if (ENABLE_LEAK_CHECK) |
71 | 207 | htab_delete (macro_hash); |
72 | 207 | } |
73 | | |
74 | | /* Read input lines till we get to a TO string. |
75 | | Increase nesting depth if we get a FROM string. |
76 | | Put the results into sb at PTR. |
77 | | FROM may be NULL (or will be ignored) if TO is "ENDR". |
78 | | Add a new input line to an sb using GET_LINE. |
79 | | Return 1 on success, 0 on unexpected EOF. */ |
80 | | |
81 | | int |
82 | | buffer_and_nest (const char *from, const char *to, sb *ptr, |
83 | | size_t (*get_line) (sb *)) |
84 | 152 | { |
85 | 152 | size_t from_len; |
86 | 152 | size_t to_len = strlen (to); |
87 | 152 | int depth = 1; |
88 | 152 | size_t line_start, more; |
89 | | |
90 | 152 | if (to_len == 4 && strcasecmp (to, "ENDR") == 0) |
91 | 147 | { |
92 | 147 | from = NULL; |
93 | 147 | from_len = 0; |
94 | 147 | } |
95 | 5 | else |
96 | 5 | from_len = strlen (from); |
97 | | |
98 | | /* Record the present source position, such that diagnostics and debug info |
99 | | can be properly associated with the respective original lines, rather |
100 | | than with the line of the ending directive (TO). */ |
101 | 152 | { |
102 | 152 | unsigned int line; |
103 | 152 | char *linefile; |
104 | | |
105 | 152 | const char *prefix = flag_m68k_mri ? "" : "."; |
106 | 152 | const char *file = as_where_top (&line); |
107 | | |
108 | 152 | if (*input_line_pointer == '\n') |
109 | 84 | line++; |
110 | 152 | if (file) |
111 | 152 | linefile = xasprintf ("\t%slinefile %u \"%s\"", prefix, line, file); |
112 | 0 | else |
113 | 0 | linefile = xasprintf ("\t%slinefile %u .", prefix, line); |
114 | 152 | sb_add_string (ptr, linefile); |
115 | 152 | xfree (linefile); |
116 | 152 | } |
117 | | |
118 | 152 | line_start = ptr->len; |
119 | 152 | more = get_line (ptr); |
120 | 2.22k | while (more) |
121 | 2.15k | { |
122 | | /* Try to find the first pseudo op on the line. */ |
123 | 2.15k | size_t i = line_start; |
124 | 2.15k | bool had_colon = false; |
125 | | |
126 | | /* With normal syntax we can suck what we want till we get |
127 | | to the dot. With the alternate, labels have to start in |
128 | | the first column, since we can't tell what's a label and |
129 | | what's a pseudoop. */ |
130 | | |
131 | 2.15k | if (! LABELS_WITHOUT_COLONS) |
132 | 2.15k | { |
133 | | /* Skip leading whitespace. */ |
134 | 2.15k | i = sb_skip_white (i, ptr); |
135 | 2.15k | } |
136 | | |
137 | 2.15k | for (;;) |
138 | 2.16k | { |
139 | | /* Skip over a label, if any. */ |
140 | 2.16k | if (i >= ptr->len || ! is_name_beginner (ptr->ptr[i])) |
141 | 726 | break; |
142 | 1.43k | i++; |
143 | 5.93k | while (i < ptr->len && is_part_of_name (ptr->ptr[i])) |
144 | 4.49k | i++; |
145 | 1.43k | if (i < ptr->len && is_name_ender (ptr->ptr[i])) |
146 | 0 | i++; |
147 | | /* Skip whitespace. */ |
148 | 1.43k | i = sb_skip_white (i, ptr); |
149 | | /* Check for the colon. */ |
150 | 1.43k | if (i >= ptr->len || ptr->ptr[i] != ':') |
151 | 1.42k | { |
152 | | /* LABELS_WITHOUT_COLONS doesn't mean we cannot have a |
153 | | colon after a label. If we do have a colon on the |
154 | | first label then handle more than one label on the |
155 | | line, assuming that each label has a colon. */ |
156 | 1.42k | if (LABELS_WITHOUT_COLONS && !had_colon) |
157 | 0 | break; |
158 | 1.42k | i = line_start; |
159 | 1.42k | break; |
160 | 1.42k | } |
161 | 9 | i++; |
162 | 9 | line_start = i; |
163 | 9 | had_colon = true; |
164 | 9 | } |
165 | | |
166 | | /* Skip trailing whitespace. */ |
167 | 2.15k | i = sb_skip_white (i, ptr); |
168 | | |
169 | 2.15k | if (i < ptr->len && (ptr->ptr[i] == '.' |
170 | 1.05k | || NO_PSEUDO_DOT |
171 | 1.05k | || flag_mri)) |
172 | 719 | { |
173 | 719 | if (! flag_m68k_mri && ptr->ptr[i] == '.') |
174 | 638 | i++; |
175 | 719 | size_t len = ptr->len - i; |
176 | 719 | if (from == NULL) |
177 | 698 | { |
178 | 698 | if (len >= 5 && strncasecmp (ptr->ptr + i, "IREPC", 5) == 0) |
179 | 0 | from_len = 5; |
180 | 698 | else if (len >= 4 && strncasecmp (ptr->ptr + i, "IREP", 4) == 0) |
181 | 1 | from_len = 4; |
182 | 697 | else if (len >= 4 && strncasecmp (ptr->ptr + i, "IRPC", 4) == 0) |
183 | 8 | from_len = 4; |
184 | 689 | else if (len >= 4 && strncasecmp (ptr->ptr + i, "REPT", 4) == 0) |
185 | 0 | from_len = 4; |
186 | 689 | else if (len >= 3 && strncasecmp (ptr->ptr + i, "IRP", 3) == 0) |
187 | 0 | from_len = 3; |
188 | 689 | else if (len >= 3 && strncasecmp (ptr->ptr + i, "REP", 3) == 0) |
189 | 0 | from_len = 3; |
190 | 689 | else |
191 | 689 | from_len = 0; |
192 | 698 | } |
193 | 719 | if ((from != NULL |
194 | 719 | ? (len >= from_len |
195 | 15 | && strncasecmp (ptr->ptr + i, from, from_len) == 0) |
196 | 719 | : from_len > 0) |
197 | 10 | && (len == from_len |
198 | 10 | || ! (is_part_of_name (ptr->ptr[i + from_len]) |
199 | 9 | || is_name_ender (ptr->ptr[i + from_len])))) |
200 | 9 | depth++; |
201 | 719 | if (len >= to_len |
202 | 690 | && strncasecmp (ptr->ptr + i, to, to_len) == 0 |
203 | 94 | && (len == to_len |
204 | 22 | || ! (is_part_of_name (ptr->ptr[i + to_len]) |
205 | 14 | || is_name_ender (ptr->ptr[i + to_len])))) |
206 | 86 | { |
207 | 86 | depth--; |
208 | 86 | if (depth == 0) |
209 | 78 | { |
210 | | /* Reset the string to not include the ending rune. */ |
211 | 78 | ptr->len = line_start; |
212 | | |
213 | | /* With the ending directive consumed here, announce the |
214 | | line for macro-expanded listings. */ |
215 | 78 | if (listing & LISTING_MACEXP) |
216 | 0 | listing_newline (NULL); |
217 | 78 | break; |
218 | 78 | } |
219 | 86 | } |
220 | | |
221 | | /* PR gas/16908 |
222 | | Apply .linefile directives that appear within the macro, alongside |
223 | | keeping them for later expansion of the macro. */ |
224 | 641 | if (from != NULL && strcasecmp (from, "MACRO") == 0 |
225 | 20 | && len >= 8 && strncasecmp (ptr->ptr + i, "linefile", 8) == 0) |
226 | 0 | { |
227 | 0 | sb_add_char (ptr, more); |
228 | 0 | temp_ilp (sb_terminate (ptr) + i + 8); |
229 | 0 | s_linefile (0); |
230 | 0 | restore_ilp (); |
231 | 0 | line_start = ptr->len; |
232 | 0 | more = get_line (ptr); |
233 | 0 | continue; |
234 | 0 | } |
235 | 641 | } |
236 | | |
237 | | /* Add the original end-of-line char to the end and keep running. */ |
238 | 2.07k | sb_add_char (ptr, more); |
239 | 2.07k | line_start = ptr->len; |
240 | 2.07k | more = get_line (ptr); |
241 | 2.07k | } |
242 | | |
243 | | /* Return 1 on success, 0 on unexpected EOF. */ |
244 | 152 | return depth == 0; |
245 | 152 | } |
246 | | |
247 | | /* Pick up a token. */ |
248 | | |
249 | | static size_t |
250 | | get_token (size_t idx, sb *in, sb *name) |
251 | 10.2k | { |
252 | 10.2k | if (idx < in->len |
253 | 10.2k | && is_name_beginner (in->ptr[idx])) |
254 | 9.62k | { |
255 | 9.62k | sb_add_char (name, in->ptr[idx++]); |
256 | 44.1k | while (idx < in->len |
257 | 44.1k | && is_part_of_name (in->ptr[idx])) |
258 | 34.5k | { |
259 | 34.5k | sb_add_char (name, in->ptr[idx++]); |
260 | 34.5k | } |
261 | 9.62k | if (idx < in->len |
262 | 9.62k | && is_name_ender (in->ptr[idx])) |
263 | 0 | { |
264 | 0 | sb_add_char (name, in->ptr[idx++]); |
265 | 0 | } |
266 | 9.62k | } |
267 | | /* Ignore trailing &. */ |
268 | 10.2k | if (flag_macro_alternate && idx < in->len && in->ptr[idx] == '&') |
269 | 0 | idx++; |
270 | 10.2k | return idx; |
271 | 10.2k | } |
272 | | |
273 | | /* Pick up a string. */ |
274 | | |
275 | | static size_t |
276 | | getstring (size_t idx, sb *in, sb *acc) |
277 | 1 | { |
278 | 2 | while (idx < in->len |
279 | 1 | && (in->ptr[idx] == '"' |
280 | 0 | || (in->ptr[idx] == '<' && (flag_macro_alternate || flag_mri)) |
281 | 0 | || (in->ptr[idx] == '\'' && flag_macro_alternate))) |
282 | 1 | { |
283 | 1 | if (in->ptr[idx] == '<') |
284 | 0 | { |
285 | 0 | int nest = 0; |
286 | 0 | idx++; |
287 | 0 | while (idx < in->len) |
288 | 0 | { |
289 | 0 | if (in->ptr[idx] == '!' && idx + 1 < in->len) |
290 | 0 | idx++; |
291 | 0 | else if (in->ptr[idx] == '>') |
292 | 0 | { |
293 | 0 | if (nest == 0) |
294 | 0 | { |
295 | 0 | idx++; |
296 | 0 | break; |
297 | 0 | } |
298 | 0 | nest--; |
299 | 0 | } |
300 | 0 | else if (in->ptr[idx] == '<') |
301 | 0 | nest++; |
302 | | |
303 | 0 | sb_add_char (acc, in->ptr[idx]); |
304 | 0 | idx++; |
305 | 0 | } |
306 | 0 | } |
307 | 1 | else if (in->ptr[idx] == '"' || in->ptr[idx] == '\'') |
308 | 1 | { |
309 | 1 | char tchar = in->ptr[idx]; |
310 | 1 | int escaped = 0; |
311 | | |
312 | 1 | idx++; |
313 | 2 | while (idx < in->len) |
314 | 1 | { |
315 | 1 | if (in->ptr[idx - 1] == '\\') |
316 | 0 | escaped ^= 1; |
317 | 1 | else |
318 | 1 | escaped = 0; |
319 | | |
320 | 1 | if (flag_macro_alternate |
321 | 0 | && in->ptr[idx] == '!' && idx + 1 < in->len) |
322 | 0 | { |
323 | 0 | idx++; |
324 | 0 | } |
325 | 1 | else if (!escaped && in->ptr[idx] == tchar) |
326 | 0 | { |
327 | 0 | idx++; |
328 | 0 | if (idx >= in->len || in->ptr[idx] != tchar) |
329 | 0 | break; |
330 | 0 | } |
331 | 1 | sb_add_char (acc, in->ptr[idx]); |
332 | 1 | idx++; |
333 | 1 | } |
334 | 1 | } |
335 | 1 | } |
336 | | |
337 | 1 | return idx; |
338 | 1 | } |
339 | | |
340 | | /* Fetch string from the input stream, |
341 | | rules: |
342 | | %<expr> -> return string of decimal value of <expr> |
343 | | "string" -> return string |
344 | | (string) -> return (string-including-whitespaces) |
345 | | xyx<whitespace> -> return xyz. */ |
346 | | |
347 | | static size_t |
348 | | get_any_string (size_t idx, sb *in, sb *out) |
349 | 154 | { |
350 | 154 | sb_reset (out); |
351 | 154 | idx = sb_skip_white (idx, in); |
352 | | |
353 | 154 | if (idx < in->len) |
354 | 154 | { |
355 | 154 | if (in->ptr[idx] == '%' && flag_macro_alternate) |
356 | 0 | { |
357 | | /* Turn the following expression into a string. */ |
358 | 0 | expressionS ex; |
359 | 0 | char buf[64]; |
360 | |
|
361 | 0 | sb_terminate (in); |
362 | |
|
363 | 0 | temp_ilp (in->ptr + idx + 1); |
364 | 0 | expression_and_evaluate (&ex); |
365 | 0 | idx = input_line_pointer - in->ptr; |
366 | 0 | restore_ilp (); |
367 | |
|
368 | 0 | if (ex.X_op != O_constant) |
369 | 0 | as_bad (_("%% operator needs absolute expression")); |
370 | |
|
371 | 0 | sprintf (buf, "%" PRId64, (int64_t) ex.X_add_number); |
372 | 0 | sb_add_string (out, buf); |
373 | 0 | } |
374 | 154 | else if (in->ptr[idx] == '"' |
375 | 153 | || (in->ptr[idx] == '<' && (flag_macro_alternate || flag_mri)) |
376 | 153 | || (flag_macro_alternate && in->ptr[idx] == '\'')) |
377 | 1 | { |
378 | 1 | if (flag_macro_alternate && ! macro_strip_at && in->ptr[idx] != '<') |
379 | 0 | { |
380 | | /* Keep the quotes. */ |
381 | 0 | sb_add_char (out, '"'); |
382 | 0 | idx = getstring (idx, in, out); |
383 | 0 | sb_add_char (out, '"'); |
384 | 0 | } |
385 | 1 | else |
386 | 1 | { |
387 | 1 | idx = getstring (idx, in, out); |
388 | 1 | } |
389 | 1 | } |
390 | 153 | else |
391 | 153 | { |
392 | 153 | char *br_buf = XNEWVEC (char, 1); |
393 | 153 | char *in_br = br_buf; |
394 | | |
395 | 153 | *in_br = '\0'; |
396 | 1.06k | while (idx < in->len |
397 | 1.05k | && (*in_br || !is_whitespace (in->ptr[idx])) |
398 | 1.04k | && in->ptr[idx] != ',' |
399 | 914 | && (in->ptr[idx] != '<' |
400 | 8 | || (! flag_macro_alternate && ! flag_mri))) |
401 | 914 | { |
402 | 914 | char tchar = in->ptr[idx]; |
403 | | |
404 | 914 | switch (tchar) |
405 | 914 | { |
406 | 1 | case '"': |
407 | 1 | case '\'': |
408 | 1 | sb_add_char (out, in->ptr[idx++]); |
409 | 4 | while (idx < in->len |
410 | 4 | && in->ptr[idx] != tchar) |
411 | 3 | sb_add_char (out, in->ptr[idx++]); |
412 | 1 | if (idx == in->len) |
413 | 0 | { |
414 | 0 | free (br_buf); |
415 | 0 | return idx; |
416 | 0 | } |
417 | 1 | break; |
418 | 13 | case '(': |
419 | 13 | case '[': |
420 | 13 | if (in_br > br_buf) |
421 | 0 | --in_br; |
422 | 13 | else |
423 | 13 | { |
424 | 13 | br_buf = XNEWVEC (char, strlen (in_br) + 2); |
425 | 13 | strcpy (br_buf + 1, in_br); |
426 | 13 | free (in_br); |
427 | 13 | in_br = br_buf; |
428 | 13 | } |
429 | 13 | *in_br = tchar; |
430 | 13 | break; |
431 | 10 | case ')': |
432 | 10 | if (*in_br == '(') |
433 | 2 | ++in_br; |
434 | 10 | break; |
435 | 1 | case ']': |
436 | 1 | if (*in_br == '[') |
437 | 0 | ++in_br; |
438 | 1 | break; |
439 | 914 | } |
440 | 914 | sb_add_char (out, tchar); |
441 | 914 | ++idx; |
442 | 914 | } |
443 | 153 | free (br_buf); |
444 | 153 | } |
445 | 154 | } |
446 | | |
447 | 154 | return idx; |
448 | 154 | } |
449 | | |
450 | | /* Allocate a new formal. */ |
451 | | |
452 | | static formal_entry * |
453 | | new_formal (void) |
454 | 7 | { |
455 | 7 | formal_entry *formal; |
456 | | |
457 | 7 | formal = XNEW (formal_entry); |
458 | | |
459 | 7 | sb_new (&formal->name); |
460 | 7 | sb_new (&formal->def); |
461 | 7 | sb_new (&formal->actual); |
462 | 7 | formal->next = NULL; |
463 | 7 | formal->type = FORMAL_OPTIONAL; |
464 | 7 | return formal; |
465 | 7 | } |
466 | | |
467 | | /* Free a formal. */ |
468 | | |
469 | | static void |
470 | | del_formal (formal_entry *formal) |
471 | 7 | { |
472 | 7 | sb_kill (&formal->actual); |
473 | 7 | sb_kill (&formal->def); |
474 | 7 | sb_kill (&formal->name); |
475 | 7 | free (formal); |
476 | 7 | } |
477 | | |
478 | | /* Pick up the formal parameters of a macro definition. */ |
479 | | |
480 | | static size_t |
481 | | do_formals (macro_entry *macro, size_t idx, sb *in) |
482 | 5 | { |
483 | 5 | formal_entry **p = ¯o->formals; |
484 | 5 | const char *name; |
485 | | |
486 | 5 | idx = sb_skip_white (idx, in); |
487 | 7 | while (idx < in->len) |
488 | 4 | { |
489 | 4 | formal_entry *formal = new_formal (); |
490 | 4 | size_t cidx; |
491 | | |
492 | 4 | idx = get_token (idx, in, &formal->name); |
493 | 4 | if (formal->name.len == 0) |
494 | 2 | { |
495 | 2 | if (macro->formal_count) |
496 | 0 | --idx; |
497 | 2 | del_formal (formal); /* 'formal' goes out of scope. */ |
498 | 2 | break; |
499 | 2 | } |
500 | 2 | idx = sb_skip_white (idx, in); |
501 | | /* This is a formal. */ |
502 | 2 | name = sb_terminate (&formal->name); |
503 | 2 | if (! flag_mri |
504 | 2 | && idx < in->len |
505 | 0 | && in->ptr[idx] == ':' |
506 | 0 | && (! is_name_beginner (':') |
507 | 0 | || idx + 1 >= in->len |
508 | 0 | || ! is_part_of_name (in->ptr[idx + 1]))) |
509 | 0 | { |
510 | | /* Got a qualifier. */ |
511 | 0 | sb qual; |
512 | |
|
513 | 0 | sb_new (&qual); |
514 | 0 | idx = get_token (sb_skip_white (idx + 1, in), in, &qual); |
515 | 0 | sb_terminate (&qual); |
516 | 0 | if (qual.len == 0) |
517 | 0 | as_bad_where (macro->file, |
518 | 0 | macro->line, |
519 | 0 | _("Missing parameter qualifier for `%s' in macro `%s'"), |
520 | 0 | name, |
521 | 0 | macro->name); |
522 | 0 | else if (strcmp (qual.ptr, "req") == 0) |
523 | 0 | formal->type = FORMAL_REQUIRED; |
524 | 0 | else if (strcmp (qual.ptr, "vararg") == 0) |
525 | 0 | formal->type = FORMAL_VARARG; |
526 | 0 | else |
527 | 0 | as_bad_where (macro->file, |
528 | 0 | macro->line, |
529 | 0 | _("`%s' is not a valid parameter qualifier for `%s' in macro `%s'"), |
530 | 0 | qual.ptr, |
531 | 0 | name, |
532 | 0 | macro->name); |
533 | 0 | sb_kill (&qual); |
534 | 0 | idx = sb_skip_white (idx, in); |
535 | 0 | } |
536 | 2 | if (idx < in->len && in->ptr[idx] == '=') |
537 | 0 | { |
538 | | /* Got a default. */ |
539 | 0 | idx = get_any_string (idx + 1, in, &formal->def); |
540 | 0 | idx = sb_skip_white (idx, in); |
541 | 0 | if (formal->type == FORMAL_REQUIRED) |
542 | 0 | { |
543 | 0 | sb_reset (&formal->def); |
544 | 0 | as_warn_where (macro->file, |
545 | 0 | macro->line, |
546 | 0 | _("Pointless default value for required parameter `%s' in macro `%s'"), |
547 | 0 | name, |
548 | 0 | macro->name); |
549 | 0 | } |
550 | 0 | } |
551 | | |
552 | | /* Add to macro's hash table. */ |
553 | 2 | if (str_hash_insert (macro->formal_hash, name, formal, 0) != NULL) |
554 | 0 | { |
555 | 0 | as_bad_where (macro->file, macro->line, |
556 | 0 | _("A parameter named `%s' " |
557 | 0 | "already exists for macro `%s'"), |
558 | 0 | name, macro->name); |
559 | 0 | } |
560 | | |
561 | 2 | formal->index = macro->formal_count++; |
562 | 2 | *p = formal; |
563 | 2 | p = &formal->next; |
564 | 2 | if (formal->type == FORMAL_VARARG) |
565 | 0 | break; |
566 | 2 | cidx = idx; |
567 | 2 | idx = sb_skip_comma (idx, in); |
568 | 2 | if (idx != cidx && idx >= in->len) |
569 | 0 | { |
570 | 0 | idx = cidx; |
571 | 0 | break; |
572 | 0 | } |
573 | 2 | } |
574 | | |
575 | 5 | if (flag_mri) |
576 | 3 | { |
577 | 3 | formal_entry *formal = new_formal (); |
578 | | |
579 | | /* Add a special NARG formal, which macro_expand will set to the |
580 | | number of arguments. */ |
581 | | /* The same MRI assemblers which treat '@' characters also use |
582 | | the name $NARG. At least until we find an exception. */ |
583 | 3 | if (macro_strip_at) |
584 | 0 | name = "$NARG"; |
585 | 3 | else |
586 | 3 | name = "NARG"; |
587 | | |
588 | 3 | sb_add_string (&formal->name, name); |
589 | | |
590 | | /* Add to macro's hash table. */ |
591 | 3 | if (str_hash_insert (macro->formal_hash, name, formal, 0) != NULL) |
592 | 0 | { |
593 | 0 | as_bad_where (macro->file, macro->line, |
594 | 0 | _("Reserved word `%s' used as parameter in macro `%s'"), |
595 | 0 | name, macro->name); |
596 | 0 | } |
597 | | |
598 | 3 | formal->index = NARG_INDEX; |
599 | 3 | *p = formal; |
600 | 3 | } |
601 | | |
602 | 5 | return idx; |
603 | 5 | } |
604 | | |
605 | | /* Free the memory allocated to a macro. */ |
606 | | |
607 | | static void |
608 | | free_macro (macro_entry *macro) |
609 | 5 | { |
610 | 5 | formal_entry *formal; |
611 | | |
612 | 10 | for (formal = macro->formals; formal; ) |
613 | 5 | { |
614 | 5 | formal_entry *f; |
615 | | |
616 | 5 | f = formal; |
617 | 5 | formal = formal->next; |
618 | 5 | del_formal (f); |
619 | 5 | } |
620 | 5 | htab_delete (macro->formal_hash); |
621 | 5 | sb_kill (¯o->sub); |
622 | 5 | free ((char *) macro->name); |
623 | 5 | free (macro); |
624 | 5 | } |
625 | | |
626 | | /* Define a new macro. */ |
627 | | |
628 | | macro_entry * |
629 | | define_macro (sb *in, sb *label, size_t (*get_line) (sb *)) |
630 | 5 | { |
631 | 5 | macro_entry *macro; |
632 | 5 | sb name; |
633 | 5 | size_t idx; |
634 | 5 | const char *error = NULL; |
635 | | |
636 | 5 | macro = XNEW (macro_entry); |
637 | 5 | sb_new (¯o->sub); |
638 | 5 | sb_new (&name); |
639 | 5 | macro->file = as_where (¯o->line); |
640 | | |
641 | 5 | macro->formal_count = 0; |
642 | 5 | macro->formals = 0; |
643 | 5 | macro->formal_hash = str_htab_create (); |
644 | 5 | macro->count = 0; |
645 | | |
646 | 5 | idx = sb_skip_white (0, in); |
647 | 5 | if (! buffer_and_nest ("MACRO", "ENDM", ¯o->sub, get_line)) |
648 | 4 | error = _("unexpected end of file in macro `%s' definition"); |
649 | 5 | if (label != NULL && label->len != 0) |
650 | 0 | { |
651 | 0 | sb_add_sb (&name, label); |
652 | 0 | macro->name = sb_terminate (&name); |
653 | 0 | if (idx < in->len && in->ptr[idx] == '(') |
654 | 0 | { |
655 | | /* It's the label: MACRO (formals,...) sort */ |
656 | 0 | idx = do_formals (macro, idx + 1, in); |
657 | 0 | if (idx < in->len && in->ptr[idx] == ')') |
658 | 0 | idx = sb_skip_white (idx + 1, in); |
659 | 0 | else if (!error) |
660 | 0 | error = _("missing `)' after formals in macro definition `%s'"); |
661 | 0 | } |
662 | 0 | else |
663 | 0 | { |
664 | | /* It's the label: MACRO formals,... sort */ |
665 | 0 | idx = do_formals (macro, idx, in); |
666 | 0 | } |
667 | 0 | } |
668 | 5 | else |
669 | 5 | { |
670 | 5 | size_t cidx; |
671 | | |
672 | 5 | idx = get_token (idx, in, &name); |
673 | 5 | macro->name = sb_terminate (&name); |
674 | 5 | if (name.len == 0) |
675 | 0 | error = _("Missing macro name"); |
676 | 5 | cidx = sb_skip_white (idx, in); |
677 | 5 | idx = sb_skip_comma (cidx, in); |
678 | 5 | if (idx == cidx || idx < in->len) |
679 | 5 | idx = do_formals (macro, idx, in); |
680 | 0 | else |
681 | 0 | idx = cidx; |
682 | 5 | } |
683 | 5 | if (!error && idx < in->len) |
684 | 0 | error = _("Bad parameter list for macro `%s'"); |
685 | | |
686 | | /* And stick it in the macro hash table. */ |
687 | 24 | for (idx = 0; idx < name.len; idx++) |
688 | 19 | name.ptr[idx] = TOLOWER (name.ptr[idx]); |
689 | 5 | if (!error) |
690 | 1 | { |
691 | 1 | if (str_hash_insert (macro_hash, macro->name, macro, 0) != NULL) |
692 | 0 | error = _("Macro `%s' was already defined"); |
693 | 1 | } |
694 | | |
695 | 5 | if (!error) |
696 | 1 | macro_defined = 1; |
697 | 4 | else |
698 | 4 | { |
699 | 4 | as_bad_where (macro->file, macro->line, error, macro->name); |
700 | 4 | free_macro (macro); |
701 | 4 | macro = NULL; |
702 | 4 | } |
703 | | |
704 | 5 | return macro; |
705 | 5 | } |
706 | | |
707 | | /* Scan a token, and then skip KIND. */ |
708 | | |
709 | | static size_t |
710 | | get_apost_token (size_t idx, sb *in, sb *name, int kind) |
711 | 10.1k | { |
712 | 10.1k | idx = get_token (idx, in, name); |
713 | 10.1k | if (idx < in->len |
714 | 10.1k | && in->ptr[idx] == kind |
715 | 0 | && (! flag_mri || macro_strip_at) |
716 | 0 | && (! macro_strip_at || kind == '@')) |
717 | 0 | idx++; |
718 | 10.1k | return idx; |
719 | 10.1k | } |
720 | | |
721 | | /* Substitute the actual value for a formal parameter. */ |
722 | | |
723 | | static size_t |
724 | | sub_actual (size_t start, sb *in, sb *t, struct htab *formal_hash, |
725 | | int kind, sb *out, int copyifnotthere) |
726 | 10.1k | { |
727 | 10.1k | size_t src; |
728 | 10.1k | formal_entry *ptr; |
729 | | |
730 | 10.1k | src = get_apost_token (start, in, t, kind); |
731 | | /* See if it's in the macro's hash table, unless this is |
732 | | macro_strip_at and kind is '@' and the token did not end in '@'. */ |
733 | 10.1k | if (macro_strip_at |
734 | 0 | && kind == '@' |
735 | 0 | && (src == start || in->ptr[src - 1] != '@')) |
736 | 0 | ptr = NULL; |
737 | 10.1k | else |
738 | 10.1k | ptr = str_hash_find (formal_hash, sb_terminate (t)); |
739 | 10.1k | if (ptr) |
740 | 21 | { |
741 | 21 | if (ptr->actual.len) |
742 | 12 | { |
743 | 12 | sb_add_sb (out, &ptr->actual); |
744 | 12 | } |
745 | 9 | else |
746 | 9 | { |
747 | 9 | sb_add_sb (out, &ptr->def); |
748 | 9 | } |
749 | 21 | } |
750 | 10.1k | else if (kind == '&') |
751 | 781 | { |
752 | | /* Doing this permits people to use & in macro bodies. */ |
753 | 781 | sb_add_char (out, '&'); |
754 | 781 | sb_add_sb (out, t); |
755 | 781 | if (src != start && in->ptr[src - 1] == '&') |
756 | 0 | sb_add_char (out, '&'); |
757 | 781 | } |
758 | 9.35k | else if (copyifnotthere) |
759 | 4.06k | { |
760 | 4.06k | sb_add_sb (out, t); |
761 | 4.06k | } |
762 | 5.28k | else |
763 | 5.28k | { |
764 | 5.28k | sb_add_char (out, '\\'); |
765 | 5.28k | sb_add_sb (out, t); |
766 | 5.28k | } |
767 | 10.1k | return src; |
768 | 10.1k | } |
769 | | |
770 | | /* Expand the body of a macro. */ |
771 | | |
772 | | static const char * |
773 | | macro_expand_body (sb *in, sb *out, formal_entry *formals, |
774 | | struct htab *formal_hash, const macro_entry *macro, |
775 | | unsigned int instance) |
776 | 2.05k | { |
777 | 2.05k | sb t; |
778 | 2.05k | size_t src = 0; |
779 | 2.05k | int inquote = 0, macro_line = 0; |
780 | 2.05k | formal_entry *loclist = NULL; |
781 | 2.05k | const char *err = NULL; |
782 | | |
783 | 2.05k | sb_new (&t); |
784 | | |
785 | 1.06M | while (src < in->len && !err) |
786 | 1.06M | { |
787 | 1.06M | if (in->ptr[src] == '&') |
788 | 896 | { |
789 | 896 | sb_reset (&t); |
790 | 896 | if (flag_mri) |
791 | 115 | { |
792 | 115 | if (src + 1 < in->len && in->ptr[src + 1] == '&') |
793 | 0 | src = sub_actual (src + 2, in, &t, formal_hash, '\'', out, 1); |
794 | 115 | else |
795 | 115 | sb_add_char (out, in->ptr[src++]); |
796 | 115 | } |
797 | 781 | else |
798 | 781 | { |
799 | | /* Permit macro parameter substitution delineated with |
800 | | an '&' prefix and optional '&' suffix. */ |
801 | 781 | src = sub_actual (src + 1, in, &t, formal_hash, '&', out, 0); |
802 | 781 | } |
803 | 896 | } |
804 | 1.05M | else if (in->ptr[src] == '\\') |
805 | 5.29k | { |
806 | 5.29k | src++; |
807 | 5.29k | if (src < in->len && in->ptr[src] == '(') |
808 | 0 | { |
809 | | /* Sub in till the next ')' literally. */ |
810 | 0 | src++; |
811 | 0 | while (src < in->len && in->ptr[src] != ')') |
812 | 0 | { |
813 | 0 | sb_add_char (out, in->ptr[src++]); |
814 | 0 | } |
815 | 0 | if (src < in->len) |
816 | 0 | src++; |
817 | 0 | else if (!macro) |
818 | 0 | err = _("missing `)'"); |
819 | 0 | else |
820 | 0 | as_bad_where (macro->file, macro->line + macro_line, _("missing `)'")); |
821 | 0 | } |
822 | 5.29k | else if (src < in->len && in->ptr[src] == '@') |
823 | 4 | { |
824 | | /* Sub in the total macro invocation number. */ |
825 | | |
826 | 4 | char buffer[12]; |
827 | 4 | src++; |
828 | 4 | sprintf (buffer, "%u", macro_number); |
829 | 4 | sb_add_string (out, buffer); |
830 | 4 | } |
831 | 5.29k | else if (src < in->len && in->ptr[src] == '+') |
832 | 0 | { |
833 | | /* Sub in the current macro invocation number. */ |
834 | |
|
835 | 0 | char buffer[12]; |
836 | 0 | src++; |
837 | 0 | sprintf (buffer, "%d", instance); |
838 | 0 | sb_add_string (out, buffer); |
839 | 0 | } |
840 | 5.29k | else if (src < in->len && in->ptr[src] == '&') |
841 | 0 | { |
842 | | /* This is a preprocessor variable name, we don't do them |
843 | | here. */ |
844 | 0 | sb_add_char (out, '\\'); |
845 | 0 | sb_add_char (out, '&'); |
846 | 0 | src++; |
847 | 0 | } |
848 | 5.29k | else if (flag_mri && src < in->len && ISALNUM (in->ptr[src])) |
849 | 3 | { |
850 | 3 | int ind; |
851 | 3 | formal_entry *f; |
852 | | |
853 | 3 | if (ISDIGIT (in->ptr[src])) |
854 | 0 | ind = in->ptr[src] - '0'; |
855 | 3 | else if (ISUPPER (in->ptr[src])) |
856 | 3 | ind = in->ptr[src] - 'A' + 10; |
857 | 0 | else |
858 | 0 | ind = in->ptr[src] - 'a' + 10; |
859 | 3 | ++src; |
860 | 6 | for (f = formals; f != NULL; f = f->next) |
861 | 3 | { |
862 | 3 | if (f->index == ind - 1) |
863 | 0 | { |
864 | 0 | if (f->actual.len != 0) |
865 | 0 | sb_add_sb (out, &f->actual); |
866 | 0 | else |
867 | 0 | sb_add_sb (out, &f->def); |
868 | 0 | break; |
869 | 0 | } |
870 | 3 | } |
871 | 3 | } |
872 | 5.28k | else |
873 | 5.28k | { |
874 | 5.28k | sb_reset (&t); |
875 | 5.28k | src = sub_actual (src, in, &t, formal_hash, '\'', out, 0); |
876 | 5.28k | } |
877 | 5.29k | } |
878 | 1.05M | else if ((flag_macro_alternate || flag_mri) |
879 | 15.1k | && is_name_beginner (in->ptr[src]) |
880 | 4.08k | && (! inquote |
881 | 1.39k | || ! macro_strip_at |
882 | 0 | || (src > 0 && in->ptr[src - 1] == '@'))) |
883 | 4.08k | { |
884 | 4.08k | if (! macro |
885 | 0 | || src + 5 >= in->len |
886 | 0 | || strncasecmp (in->ptr + src, "LOCAL", 5) != 0 |
887 | 0 | || ! is_whitespace (in->ptr[src + 5]) |
888 | | /* PR 11507: Skip keyword LOCAL if it is found inside a quoted string. */ |
889 | 0 | || inquote) |
890 | 4.08k | { |
891 | 4.08k | sb_reset (&t); |
892 | 4.08k | src = sub_actual (src, in, &t, formal_hash, |
893 | 4.08k | (macro_strip_at && inquote) ? '@' : '\'', |
894 | 4.08k | out, 1); |
895 | 4.08k | } |
896 | 0 | else |
897 | 0 | { |
898 | 0 | src = sb_skip_white (src + 5, in); |
899 | 0 | while (in->ptr[src] != '\n') |
900 | 0 | { |
901 | 0 | const char *name; |
902 | 0 | formal_entry *f = new_formal (); |
903 | |
|
904 | 0 | src = get_token (src, in, &f->name); |
905 | 0 | name = sb_terminate (&f->name); |
906 | 0 | if (str_hash_insert (formal_hash, name, f, 0) != NULL) |
907 | 0 | { |
908 | 0 | as_bad_where (macro->file, macro->line + macro_line, |
909 | 0 | _("`%s' was already used as parameter " |
910 | 0 | "(or another local) name"), name); |
911 | 0 | del_formal (f); |
912 | 0 | } |
913 | 0 | else |
914 | 0 | { |
915 | 0 | static int loccnt; |
916 | 0 | char buf[20]; |
917 | |
|
918 | 0 | f->index = LOCAL_INDEX; |
919 | 0 | f->next = loclist; |
920 | 0 | loclist = f; |
921 | |
|
922 | 0 | sprintf (buf, IS_ELF ? ".LL%04x" : "LL%04x", ++loccnt); |
923 | 0 | sb_add_string (&f->actual, buf); |
924 | 0 | } |
925 | |
|
926 | 0 | src = sb_skip_comma (src, in); |
927 | 0 | } |
928 | 0 | } |
929 | 4.08k | } |
930 | 1.05M | else if (in->ptr[src] == '"' |
931 | 1.02M | || (flag_mri && in->ptr[src] == '\'')) |
932 | 25.3k | { |
933 | 25.3k | inquote = !inquote; |
934 | 25.3k | sb_add_char (out, in->ptr[src++]); |
935 | 25.3k | } |
936 | 1.02M | else if (in->ptr[src] == '@' && macro_strip_at) |
937 | 0 | { |
938 | 0 | ++src; |
939 | 0 | if (src < in->len |
940 | 0 | && in->ptr[src] == '@') |
941 | 0 | { |
942 | 0 | sb_add_char (out, '@'); |
943 | 0 | ++src; |
944 | 0 | } |
945 | 0 | } |
946 | 1.02M | else if (flag_mri |
947 | 10.5k | && in->ptr[src] == '=' |
948 | 57 | && src + 1 < in->len |
949 | 57 | && in->ptr[src + 1] == '=') |
950 | 24 | { |
951 | 24 | formal_entry *ptr; |
952 | | |
953 | 24 | sb_reset (&t); |
954 | 24 | src = get_token (src + 2, in, &t); |
955 | 24 | ptr = str_hash_find (formal_hash, sb_terminate (&t)); |
956 | 24 | if (ptr == NULL) |
957 | 24 | { |
958 | | /* FIXME: We should really return a warning string here, |
959 | | but we can't, because the == might be in the MRI |
960 | | comment field, and, since the nature of the MRI |
961 | | comment field depends upon the exact instruction |
962 | | being used, we don't have enough information here to |
963 | | figure out whether it is or not. Instead, we leave |
964 | | the == in place, which should cause a syntax error if |
965 | | it is not in a comment. */ |
966 | 24 | sb_add_char (out, '='); |
967 | 24 | sb_add_char (out, '='); |
968 | 24 | sb_add_sb (out, &t); |
969 | 24 | } |
970 | 0 | else |
971 | 0 | { |
972 | 0 | if (ptr->actual.len) |
973 | 0 | { |
974 | 0 | sb_add_string (out, "-1"); |
975 | 0 | } |
976 | 0 | else |
977 | 0 | { |
978 | 0 | sb_add_char (out, '0'); |
979 | 0 | } |
980 | 0 | } |
981 | 24 | } |
982 | 1.02M | else |
983 | 1.02M | { |
984 | 1.02M | if (in->ptr[src] == '\n') |
985 | 46.2k | ++macro_line; |
986 | 1.02M | sb_add_char (out, in->ptr[src++]); |
987 | 1.02M | } |
988 | 1.06M | } |
989 | | |
990 | 2.05k | sb_kill (&t); |
991 | | |
992 | 2.05k | while (loclist != NULL) |
993 | 0 | { |
994 | 0 | formal_entry *f; |
995 | 0 | const char *name; |
996 | |
|
997 | 0 | f = loclist->next; |
998 | 0 | name = sb_terminate (&loclist->name); |
999 | 0 | str_hash_delete (formal_hash, name); |
1000 | 0 | del_formal (loclist); |
1001 | 0 | loclist = f; |
1002 | 0 | } |
1003 | | |
1004 | 2.05k | if (!err && (out->len == 0 || out->ptr[out->len - 1] != '\n')) |
1005 | 0 | sb_add_char (out, '\n'); |
1006 | 2.05k | return err; |
1007 | 2.05k | } |
1008 | | |
1009 | | /* Assign values to the formal parameters of a macro, and expand the |
1010 | | body. */ |
1011 | | |
1012 | | static const char * |
1013 | | macro_expand (size_t idx, sb *in, macro_entry *m, sb *out) |
1014 | 2 | { |
1015 | 2 | sb t; |
1016 | 2 | formal_entry *ptr; |
1017 | 2 | formal_entry *f; |
1018 | 2 | int is_keyword = 0; |
1019 | 2 | int narg = 0; |
1020 | 2 | const char *err = NULL; |
1021 | | |
1022 | 2 | sb_new (&t); |
1023 | | |
1024 | | /* Reset any old value the actuals may have. */ |
1025 | 4 | for (f = m->formals; f; f = f->next) |
1026 | 2 | sb_reset (&f->actual); |
1027 | 2 | f = m->formals; |
1028 | 2 | while (f != NULL && f->index < 0) |
1029 | 0 | f = f->next; |
1030 | | |
1031 | 2 | if (flag_mri) |
1032 | 0 | { |
1033 | | /* The macro may be called with an optional qualifier, which may |
1034 | | be referred to in the macro body as \0. */ |
1035 | 0 | if (idx < in->len && in->ptr[idx] == '.') |
1036 | 0 | { |
1037 | | /* The Microtec assembler ignores this if followed by a white space. |
1038 | | (Macro invocation with empty extension) */ |
1039 | 0 | idx++; |
1040 | 0 | if (idx < in->len && !is_whitespace (in->ptr[idx])) |
1041 | 0 | { |
1042 | 0 | formal_entry *n = new_formal (); |
1043 | |
|
1044 | 0 | n->index = QUAL_INDEX; |
1045 | |
|
1046 | 0 | n->next = m->formals; |
1047 | 0 | m->formals = n; |
1048 | |
|
1049 | 0 | idx = get_any_string (idx, in, &n->actual); |
1050 | 0 | } |
1051 | 0 | } |
1052 | 0 | } |
1053 | | |
1054 | | /* Peel off the actuals and store them away in the hash tables' actuals. */ |
1055 | 2 | idx = sb_skip_white (idx, in); |
1056 | 3 | while (idx < in->len) |
1057 | 1 | { |
1058 | | /* Look and see if it's a positional or keyword arg. */ |
1059 | 1 | size_t scan; |
1060 | | |
1061 | 1 | sb_reset (&t); |
1062 | 1 | scan = !flag_macro_alternate ? get_token (idx, in, &t) : idx; |
1063 | | |
1064 | 1 | if (scan > idx && scan < in->len && in->ptr[scan] == '=') |
1065 | 0 | { |
1066 | 0 | is_keyword = 1; |
1067 | | |
1068 | | /* It's OK to go from positional to keyword. */ |
1069 | | |
1070 | | /* Lookup the formal in the macro's list. */ |
1071 | 0 | ptr = str_hash_find (m->formal_hash, sb_terminate (&t)); |
1072 | 0 | if (!ptr) |
1073 | 0 | { |
1074 | 0 | as_bad (_("Parameter named `%s' does not exist for macro `%s'"), |
1075 | 0 | t.ptr, |
1076 | 0 | m->name); |
1077 | 0 | sb_reset (&t); |
1078 | | /* Skip what would be the actual stuff. */ |
1079 | 0 | idx = get_any_string (scan + 1, in, &t); |
1080 | 0 | } |
1081 | 0 | else |
1082 | 0 | { |
1083 | | /* Insert this value into the right place. */ |
1084 | 0 | if (ptr->actual.len) |
1085 | 0 | { |
1086 | 0 | as_warn (_("Value for parameter `%s' of macro `%s' was already specified"), |
1087 | 0 | ptr->name.ptr, |
1088 | 0 | m->name); |
1089 | 0 | sb_reset (&ptr->actual); |
1090 | 0 | } |
1091 | | /* Fetch the actual stuff. */ |
1092 | 0 | idx = get_any_string (scan + 1, in, &ptr->actual); |
1093 | 0 | if (ptr->actual.len > 0) |
1094 | 0 | ++narg; |
1095 | 0 | } |
1096 | 0 | } |
1097 | 1 | else |
1098 | 1 | { |
1099 | 1 | if (is_keyword) |
1100 | 0 | { |
1101 | 0 | err = _("can't mix positional and keyword arguments"); |
1102 | 0 | break; |
1103 | 0 | } |
1104 | | |
1105 | 1 | if (!f) |
1106 | 0 | { |
1107 | 0 | formal_entry **pf; |
1108 | 0 | int c; |
1109 | |
|
1110 | 0 | if (!flag_mri) |
1111 | 0 | { |
1112 | 0 | err = _("too many positional arguments"); |
1113 | 0 | break; |
1114 | 0 | } |
1115 | | |
1116 | 0 | f = new_formal (); |
1117 | |
|
1118 | 0 | c = -1; |
1119 | 0 | for (pf = &m->formals; *pf != NULL; pf = &(*pf)->next) |
1120 | 0 | if ((*pf)->index >= c) |
1121 | 0 | c = (*pf)->index + 1; |
1122 | 0 | if (c == -1) |
1123 | 0 | c = 0; |
1124 | 0 | *pf = f; |
1125 | 0 | f->index = c; |
1126 | 0 | } |
1127 | | |
1128 | 1 | if (f->type != FORMAL_VARARG) |
1129 | 1 | idx = get_any_string (idx, in, &f->actual); |
1130 | 0 | else if (idx < in->len) |
1131 | 0 | { |
1132 | 0 | sb_add_buffer (&f->actual, in->ptr + idx, in->len - idx); |
1133 | 0 | idx = in->len; |
1134 | 0 | } |
1135 | 1 | if (f->actual.len > 0) |
1136 | 1 | ++narg; |
1137 | 1 | do |
1138 | 1 | { |
1139 | 1 | f = f->next; |
1140 | 1 | } |
1141 | 1 | while (f != NULL && f->index < 0); |
1142 | 1 | } |
1143 | | |
1144 | 1 | if (! flag_mri) |
1145 | 1 | idx = sb_skip_comma (idx, in); |
1146 | 0 | else |
1147 | 0 | { |
1148 | 0 | if (idx < in->len && in->ptr[idx] == ',') |
1149 | 0 | ++idx; |
1150 | 0 | if (idx < in->len && is_whitespace (in->ptr[idx])) |
1151 | 0 | break; |
1152 | 0 | } |
1153 | 1 | } |
1154 | | |
1155 | 2 | if (! err) |
1156 | 2 | { |
1157 | 4 | for (ptr = m->formals; ptr; ptr = ptr->next) |
1158 | 2 | { |
1159 | 2 | if (ptr->type == FORMAL_REQUIRED && ptr->actual.len == 0) |
1160 | 0 | as_bad (_("Missing value for required parameter `%s' of macro `%s'"), |
1161 | 0 | ptr->name.ptr, |
1162 | 0 | m->name); |
1163 | 2 | } |
1164 | | |
1165 | 2 | if (flag_mri) |
1166 | 0 | { |
1167 | 0 | ptr = str_hash_find (m->formal_hash, |
1168 | 0 | macro_strip_at ? "$NARG" : "NARG"); |
1169 | 0 | if (ptr) |
1170 | 0 | { |
1171 | 0 | char buffer[20]; |
1172 | 0 | sprintf (buffer, "%d", narg); |
1173 | 0 | sb_add_string (&ptr->actual, buffer); |
1174 | 0 | } |
1175 | 0 | } |
1176 | | |
1177 | 2 | err = macro_expand_body (&m->sub, out, m->formals, m->formal_hash, m, |
1178 | 2 | m->count); |
1179 | 2 | } |
1180 | | |
1181 | | /* Discard any unnamed formal arguments. */ |
1182 | 2 | if (flag_mri) |
1183 | 0 | { |
1184 | 0 | formal_entry **pf; |
1185 | |
|
1186 | 0 | pf = &m->formals; |
1187 | 0 | while (*pf != NULL) |
1188 | 0 | { |
1189 | 0 | if ((*pf)->name.len != 0) |
1190 | 0 | pf = &(*pf)->next; |
1191 | 0 | else |
1192 | 0 | { |
1193 | 0 | f = (*pf)->next; |
1194 | 0 | del_formal (*pf); |
1195 | 0 | *pf = f; |
1196 | 0 | } |
1197 | 0 | } |
1198 | 0 | } |
1199 | | |
1200 | 2 | sb_kill (&t); |
1201 | 2 | if (!err) |
1202 | 2 | { |
1203 | 2 | macro_number++; |
1204 | 2 | m->count++; |
1205 | 2 | } |
1206 | | |
1207 | 2 | return err; |
1208 | 2 | } |
1209 | | |
1210 | | /* Check for a macro. If one is found, put the expansion into |
1211 | | *EXPAND. Return 1 if a macro is found, 0 otherwise. */ |
1212 | | |
1213 | | int |
1214 | | check_macro (const char *line, sb *expand, |
1215 | | const char **error, macro_entry **info) |
1216 | 92 | { |
1217 | 92 | const char *s; |
1218 | 92 | char *copy, *cls; |
1219 | 92 | macro_entry *macro; |
1220 | 92 | sb line_sb; |
1221 | | |
1222 | 92 | if (! is_name_beginner (*line) |
1223 | 0 | && (! flag_mri || *line != '.')) |
1224 | 0 | return 0; |
1225 | | |
1226 | 92 | s = line + 1; |
1227 | 335 | while (is_part_of_name (*s)) |
1228 | 243 | ++s; |
1229 | 92 | if (is_name_ender (*s)) |
1230 | 0 | ++s; |
1231 | | |
1232 | 92 | copy = xmemdup0 (line, s - line); |
1233 | 427 | for (cls = copy; *cls != '\0'; cls ++) |
1234 | 335 | *cls = TOLOWER (*cls); |
1235 | | |
1236 | 92 | macro = str_hash_find (macro_hash, copy); |
1237 | 92 | free (copy); |
1238 | | |
1239 | 92 | if (macro == NULL) |
1240 | 90 | return 0; |
1241 | | |
1242 | | /* Wrap the line up in an sb. */ |
1243 | 2 | sb_new (&line_sb); |
1244 | 4 | while (*s != '\0' && *s != '\n' && *s != '\r') |
1245 | 2 | sb_add_char (&line_sb, *s++); |
1246 | | |
1247 | 2 | sb_new (expand); |
1248 | 2 | *error = macro_expand (0, &line_sb, macro, expand); |
1249 | | |
1250 | 2 | sb_kill (&line_sb); |
1251 | | |
1252 | | /* Export the macro information if requested. */ |
1253 | 2 | if (info) |
1254 | 2 | *info = macro; |
1255 | | |
1256 | 2 | return 1; |
1257 | 92 | } |
1258 | | |
1259 | | /* Delete a macro. */ |
1260 | | |
1261 | | void |
1262 | | delete_macro (const char *name) |
1263 | 1 | { |
1264 | 1 | char *copy; |
1265 | 1 | size_t i, len; |
1266 | 1 | macro_entry *macro; |
1267 | | |
1268 | 1 | len = strlen (name); |
1269 | 1 | copy = XNEWVEC (char, len + 1); |
1270 | 1 | for (i = 0; i < len; ++i) |
1271 | 0 | copy[i] = TOLOWER (name[i]); |
1272 | 1 | copy[i] = '\0'; |
1273 | | |
1274 | 1 | macro = str_hash_find (macro_hash, copy); |
1275 | 1 | if (macro != NULL) |
1276 | 0 | str_hash_delete (macro_hash, copy); |
1277 | 1 | else |
1278 | 1 | as_warn (_("Attempt to purge non-existing macro `%s'"), copy); |
1279 | 1 | free (copy); |
1280 | 1 | } |
1281 | | |
1282 | | /* Handle the MRI IRP and IRPC pseudo-ops. These are handled as a |
1283 | | combined macro definition and execution. This returns NULL on |
1284 | | success, or an error message otherwise. */ |
1285 | | |
1286 | | const char * |
1287 | | expand_irp (int irpc, size_t idx, sb *in, sb *out, size_t (*get_line) (sb *)) |
1288 | 84 | { |
1289 | 84 | sb sub; |
1290 | 84 | formal_entry f; |
1291 | 84 | struct htab *h; |
1292 | 84 | const char *err = NULL; |
1293 | | |
1294 | 84 | idx = sb_skip_white (idx, in); |
1295 | | |
1296 | 84 | sb_new (&sub); |
1297 | 84 | if (! buffer_and_nest (NULL, "ENDR", &sub, get_line)) |
1298 | 22 | { |
1299 | 22 | err = _("unexpected end of file in irp or irpc"); |
1300 | 22 | goto out2; |
1301 | 22 | } |
1302 | | |
1303 | 62 | sb_new (&f.name); |
1304 | 62 | sb_new (&f.def); |
1305 | 62 | sb_new (&f.actual); |
1306 | | |
1307 | 62 | idx = get_token (idx, in, &f.name); |
1308 | 62 | if (f.name.len == 0) |
1309 | 1 | { |
1310 | 1 | err = _("missing model parameter"); |
1311 | 1 | goto out1; |
1312 | 1 | } |
1313 | | |
1314 | 61 | h = str_htab_create (); |
1315 | | |
1316 | 61 | str_hash_insert (h, sb_terminate (&f.name), &f, 0); |
1317 | | |
1318 | 61 | f.index = 1; |
1319 | 61 | f.next = NULL; |
1320 | 61 | f.type = FORMAL_OPTIONAL; |
1321 | | |
1322 | 61 | sb_reset (out); |
1323 | | |
1324 | 61 | idx = sb_skip_comma (idx, in); |
1325 | 61 | if (idx >= in->len) |
1326 | 0 | { |
1327 | | /* Expand once with a null string. */ |
1328 | 0 | err = macro_expand_body (&sub, out, &f, h, NULL, 0); |
1329 | 0 | } |
1330 | 61 | else |
1331 | 61 | { |
1332 | 61 | bool in_quotes = false; |
1333 | 61 | unsigned int instance = 0; |
1334 | | |
1335 | 2.12k | while (idx < in->len) |
1336 | 2.06k | { |
1337 | 2.06k | if (!irpc) |
1338 | 153 | idx = get_any_string (idx, in, &f.actual); |
1339 | 1.90k | else |
1340 | 1.90k | { |
1341 | 1.90k | if (in->ptr[idx] == '"') |
1342 | 7 | { |
1343 | 7 | in_quotes = ! in_quotes; |
1344 | 7 | ++idx; |
1345 | | |
1346 | 7 | if (! in_quotes) |
1347 | 3 | { |
1348 | 3 | idx = sb_skip_white (idx, in); |
1349 | 3 | if (idx >= in->len) |
1350 | 0 | break; |
1351 | 3 | } |
1352 | 7 | continue; |
1353 | 7 | } |
1354 | 1.90k | sb_reset (&f.actual); |
1355 | 1.90k | sb_add_char (&f.actual, in->ptr[idx]); |
1356 | 1.90k | ++idx; |
1357 | 1.90k | } |
1358 | | |
1359 | 2.05k | err = macro_expand_body (&sub, out, &f, h, NULL, instance); |
1360 | 2.05k | ++instance; |
1361 | 2.05k | if (err != NULL) |
1362 | 0 | break; |
1363 | 2.05k | if (!irpc) |
1364 | 153 | idx = sb_skip_comma (idx, in); |
1365 | 1.90k | else if (! in_quotes) |
1366 | 1.81k | idx = sb_skip_white (idx, in); |
1367 | 2.05k | } |
1368 | 61 | } |
1369 | | |
1370 | 61 | htab_delete (h); |
1371 | 62 | out1: |
1372 | 62 | sb_kill (&f.actual); |
1373 | 62 | sb_kill (&f.def); |
1374 | 62 | sb_kill (&f.name); |
1375 | 84 | out2: |
1376 | 84 | sb_kill (&sub); |
1377 | | |
1378 | 84 | return err; |
1379 | 62 | } |