static const char * macro_expand (int idx, sb *in, macro_entry *m, sb *out) { sb t; formal_entry *ptr; formal_entry *f; int is_keyword = 0; int narg = 0; const char *err = NULL; sb_new (&t); /* Reset any old value the actuals may have. */ for (f = m->formals; f; f = f->next) sb_reset (&f->actual); f = m->formals; while (f != NULL && f->index < 0) f = f->next; if (macro_mri) { /* The macro may be called with an optional qualifier, which may be referred to in the macro body as \0. */ if (idx < in->len && in->ptr[idx] == '.') { /* The Microtec assembler ignores this if followed by a white space. (Macro invocation with empty extension) */ idx++; if ( idx < in->len && in->ptr[idx] != ' ' && in->ptr[idx] != '\t') { formal_entry *n = new_formal (); n->index = QUAL_INDEX; n->next = m->formals; m->formals = n; idx = get_any_string (idx, in, &n->actual); } } } /* Peel off the actuals and store them away in the hash tables' actuals. */ idx = sb_skip_white (idx, in); while (idx < in->len) { int scan; /* Look and see if it's a positional or keyword arg. */ scan = idx; while (scan < in->len && !ISSEP (in->ptr[scan]) && !(macro_mri && in->ptr[scan] == '\'') && (!macro_alternate && in->ptr[scan] != '=')) scan++; if (scan < in->len && !macro_alternate && in->ptr[scan] == '=') { is_keyword = 1; /* It's OK to go from positional to keyword. */ /* This is a keyword arg, fetch the formal name and then the actual stuff. */ sb_reset (&t); idx = get_token (idx, in, &t); if (in->ptr[idx] != '=') { err = _("confusion in formal parameters"); break; } /* Lookup the formal in the macro's list. */ ptr = (formal_entry *) hash_find (m->formal_hash, sb_terminate (&t)); if (!ptr) as_bad (_("Parameter named `%s' does not exist for macro `%s'"), t.ptr, m->name); else { /* Insert this value into the right place. */ if (ptr->actual.len) { as_warn (_("Value for parameter `%s' of macro `%s' was already specified"), ptr->name.ptr, m->name); sb_reset (&ptr->actual); } idx = get_any_string (idx + 1, in, &ptr->actual); if (ptr->actual.len > 0) ++narg; } } else { if (is_keyword) { err = _("can't mix positional and keyword arguments"); break; } if (!f) { formal_entry **pf; int c; if (!macro_mri) { err = _("too many positional arguments"); break; } f = new_formal (); c = -1; for (pf = &m->formals; *pf != NULL; pf = &(*pf)->next) if ((*pf)->index >= c) c = (*pf)->index + 1; if (c == -1) c = 0; *pf = f; f->index = c; } if (f->type != FORMAL_VARARG) idx = get_any_string (idx, in, &f->actual); else { sb_add_buffer (&f->actual, in->ptr + idx, in->len - idx); idx = in->len; } if (f->actual.len > 0) ++narg; do { f = f->next; } while (f != NULL && f->index < 0); } if (! macro_mri) idx = sb_skip_comma (idx, in); else { if (in->ptr[idx] == ',') ++idx; if (ISWHITE (in->ptr[idx])) break; } } if (! err) { for (ptr = m->formals; ptr; ptr = ptr->next) { if (ptr->type == FORMAL_REQUIRED && ptr->actual.len == 0) as_bad (_("Missing value for required parameter `%s' of macro `%s'"), ptr->name.ptr, m->name); } if (macro_mri) { char buffer[20]; sb_reset (&t); sb_add_string (&t, macro_strip_at ? "$NARG" : "NARG"); ptr = (formal_entry *) hash_find (m->formal_hash, sb_terminate (&t)); sprintf (buffer, "%d", narg); sb_add_string (&ptr->actual, buffer); } err = macro_expand_body (&m->sub, out, m->formals, m->formal_hash, m); } /* Discard any unnamed formal arguments. */ if (macro_mri) { formal_entry **pf; pf = &m->formals; while (*pf != NULL) { if ((*pf)->name.len != 0) pf = &(*pf)->next; else { f = (*pf)->next; del_formal (*pf); *pf = f; } } } sb_kill (&t); if (!err) macro_number++; return err; }
const char * expand_irp (int irpc, int idx, sb *in, sb *out, int (*get_line) (sb *)) { sb sub; formal_entry f; struct hash_control *h; const char *err; idx = sb_skip_white (idx, in); sb_new (&sub); if (! buffer_and_nest (NULL, "ENDR", &sub, get_line)) return _("unexpected end of file in irp or irpc"); sb_new (&f.name); sb_new (&f.def); sb_new (&f.actual); idx = get_token (idx, in, &f.name); if (f.name.len == 0) return _("missing model parameter"); h = hash_new (); err = hash_jam (h, sb_terminate (&f.name), &f); if (err != NULL) return err; f.index = 1; f.next = NULL; f.type = FORMAL_OPTIONAL; sb_reset (out); idx = sb_skip_comma (idx, in); if (idx >= in->len) { /* Expand once with a null string. */ err = macro_expand_body (&sub, out, &f, h, 0); } else { bfd_boolean in_quotes = FALSE; if (irpc && in->ptr[idx] == '"') { in_quotes = TRUE; ++idx; } while (idx < in->len) { if (!irpc) idx = get_any_string (idx, in, &f.actual); else { if (in->ptr[idx] == '"') { int nxt; if (irpc) in_quotes = ! in_quotes; nxt = sb_skip_white (idx + 1, in); if (nxt >= in->len) { idx = nxt; break; } } sb_reset (&f.actual); sb_add_char (&f.actual, in->ptr[idx]); ++idx; } err = macro_expand_body (&sub, out, &f, h, 0); if (err != NULL) break; if (!irpc) idx = sb_skip_comma (idx, in); else if (! in_quotes) idx = sb_skip_white (idx, in); } } hash_die (h); sb_kill (&f.actual); sb_kill (&f.def); sb_kill (&f.name); sb_kill (&sub); return err; }
static int do_formals (macro_entry *macro, int idx, sb *in) { formal_entry **p = ¯o->formals; const char *name; idx = sb_skip_white (idx, in); while (idx < in->len) { formal_entry *formal = new_formal (); int cidx; idx = get_token (idx, in, &formal->name); if (formal->name.len == 0) { if (macro->formal_count) --idx; break; } idx = sb_skip_white (idx, in); /* This is a formal. */ name = sb_terminate (&formal->name); if (! macro_mri && idx < in->len && in->ptr[idx] == ':' && (! is_name_beginner (':') || idx + 1 >= in->len || ! is_part_of_name (in->ptr[idx + 1]))) { /* Got a qualifier. */ sb qual; sb_new (&qual); idx = get_token (sb_skip_white (idx + 1, in), in, &qual); sb_terminate (&qual); if (qual.len == 0) as_bad_where (macro->file, macro->line, _("Missing parameter qualifier for `%s' in macro `%s'"), name, macro->name); else if (strcmp (qual.ptr, "req") == 0) formal->type = FORMAL_REQUIRED; else if (strcmp (qual.ptr, "vararg") == 0) formal->type = FORMAL_VARARG; else as_bad_where (macro->file, macro->line, _("`%s' is not a valid parameter qualifier for `%s' in macro `%s'"), qual.ptr, name, macro->name); sb_kill (&qual); idx = sb_skip_white (idx, in); } if (idx < in->len && in->ptr[idx] == '=') { /* Got a default. */ idx = get_any_string (idx + 1, in, &formal->def); idx = sb_skip_white (idx, in); if (formal->type == FORMAL_REQUIRED) { sb_reset (&formal->def); as_warn_where (macro->file, macro->line, _("Pointless default value for required parameter `%s' in macro `%s'"), name, macro->name); } } /* Add to macro's hash table. */ if (! hash_find (macro->formal_hash, name)) hash_jam (macro->formal_hash, name, formal); else as_bad_where (macro->file, macro->line, _("A parameter named `%s' already exists for macro `%s'"), name, macro->name); formal->index = macro->formal_count++; *p = formal; p = &formal->next; if (formal->type == FORMAL_VARARG) break; cidx = idx; idx = sb_skip_comma (idx, in); if (idx != cidx && idx >= in->len) { idx = cidx; break; } } if (macro_mri) { formal_entry *formal = new_formal (); /* Add a special NARG formal, which macro_expand will set to the number of arguments. */ /* The same MRI assemblers which treat '@' characters also use the name $NARG. At least until we find an exception. */ if (macro_strip_at) name = "$NARG"; else name = "NARG"; sb_add_string (&formal->name, name); /* Add to macro's hash table. */ if (hash_find (macro->formal_hash, name)) as_bad_where (macro->file, macro->line, _("Reserved word `%s' used as parameter in macro `%s'"), name, macro->name); hash_jam (macro->formal_hash, name, formal); formal->index = NARG_INDEX; *p = formal; } return idx; }
static int do_formals (macro_entry *macro, int idx, sb *in) { formal_entry **p = ¯o->formals; macro->formal_count = 0; macro->formal_hash = hash_new (); while (idx < in->len) { formal_entry *formal; formal = (formal_entry *) xmalloc (sizeof (formal_entry)); sb_new (&formal->name); sb_new (&formal->def); sb_new (&formal->actual); idx = sb_skip_white (idx, in); idx = get_token (idx, in, &formal->name); if (formal->name.len == 0) break; idx = sb_skip_white (idx, in); if (formal->name.len) { /* This is a formal. */ if (idx < in->len && in->ptr[idx] == '=') { /* Got a default. */ idx = get_any_string (idx + 1, in, &formal->def, 1, 0); } } /* Add to macro's hash table. */ hash_jam (macro->formal_hash, sb_terminate (&formal->name), formal); formal->index = macro->formal_count; idx = sb_skip_comma (idx, in); macro->formal_count++; *p = formal; p = &formal->next; *p = NULL; } if (macro_mri) { formal_entry *formal; const char *name; /* Add a special NARG formal, which macro_expand will set to the number of arguments. */ formal = (formal_entry *) xmalloc (sizeof (formal_entry)); sb_new (&formal->name); sb_new (&formal->def); sb_new (&formal->actual); /* The same MRI assemblers which treat '@' characters also use the name $NARG. At least until we find an exception. */ if (macro_strip_at) name = "$NARG"; else name = "NARG"; sb_add_string (&formal->name, name); /* Add to macro's hash table. */ hash_jam (macro->formal_hash, name, formal); formal->index = NARG_INDEX; *p = formal; formal->next = NULL; } return idx; }