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