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