diff options
author | H. Peter Anvin <hpa@zytor.com> | 2019-09-30 13:14:29 -0700 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2019-09-30 13:30:15 -0700 |
commit | 1dd926e8cedb2ec9664d28fea4cd929dc006b1cd (patch) | |
tree | 6f24a09fc461a50908fe49b5d53f80cc2b26b9f1 | |
parent | 9781db8906a769507a85280829c42dfe7b02f600 (diff) | |
download | nasm-1dd926e8cedb2ec9664d28fea4cd929dc006b1cd.tar.gz |
pragma: handle default name/fallback handler for NULL list; cleanups
The previous code would fail to process any directive if the directive
list was NULL. However, we also need to process the default name
passed to search_pragma_list() (e.g. "elf32"), as well as the global
name (e.g. "output") and call the default handler in that case.
In the process, improve the handling such that if one handler returns
DIRR_UNKNOWN, try calling subsequent handlers in the list.
Finally, factor out as much as possible to generic handlers.
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r-- | asm/pragma.c | 213 |
1 files changed, 145 insertions, 68 deletions
diff --git a/asm/pragma.c b/asm/pragma.c index 8cfbafb8..42c15ee9 100644 --- a/asm/pragma.c +++ b/asm/pragma.c @@ -47,7 +47,9 @@ #include "error.h" #include "listing.h" +static enum directive_result ignore_pragma(const struct pragma *pragma); static enum directive_result output_pragma(const struct pragma *pragma); +static enum directive_result debug_pragma(const struct pragma *pragma); static enum directive_result limit_pragma(const struct pragma *pragma); /* @@ -90,68 +92,114 @@ static struct pragma_facility global_pragmas[] = { "list", list_pragma }, { "file", NULL }, { "input", NULL }, + { "output", output_pragma }, + { "debug", debug_pragma }, + { "ignore", ignore_pragma }, - /* None of these should actually happen due to special handling */ + /* This will never actually get this far... */ { "preproc", NULL }, /* Handled in the preprocessor by necessity */ - { "output", NULL }, - { "debug", NULL }, - { "ignore", NULL }, { NULL, NULL } }; /* + * Invoke a pragma handler + */ +static enum directive_result +call_pragma(const struct pragma_facility *pf, struct pragma *pragma) +{ + if (!pf || !pf->handler) + return DIRR_UNKNOWN; + + pragma->facility = pf; + return pf->handler(pragma); +} + +/* * Search a pragma list for a known pragma facility and if so, invoke - * the handler. Return true if processing is complete. - * The "default name", if set, matches the final NULL entry (used + * the handler. Return true if processing is complete. The "default + * name", *or def->name*, if set, matches the final NULL entry (used * for backends, so multiple backends can share the same list under - * some circumstances.) + * some circumstances, and the backends can implement common operations.) */ -static bool search_pragma_list(const struct pragma_facility *list, - const char *default_name, - pragma_handler generic_handler, - struct pragma *pragma) +static enum directive_result +search_pragma_list(const struct pragma_facility *list, + const char *defaultname, + const struct pragma_facility *def, + const struct pragma *cpragma) { - const struct pragma_facility *pf; + const struct pragma_facility *pf = NULL; enum directive_result rv; + bool facility_match, is_default; + struct pragma pragma = *cpragma; + const char *facname = pragma.facility_name; - if (!list) - return false; + /* Is there a default facility and we match its name? */ + is_default = def && def->name && !nasm_stricmp(facname, def->name); + facility_match = is_default; - for (pf = list; pf->name; pf++) { - if (!nasm_stricmp(pragma->facility_name, pf->name)) - goto found_it; + /* + * Promote def->name to defaultname if both are set. This handles + * e.g. output -> elf32 so that we can handle elf32-specific + * directives in that handler. + */ + if (defaultname) { + if (is_default) + facname = defaultname; + else + facility_match = !nasm_stricmp(facname, defaultname); } - if (default_name && !nasm_stricmp(pragma->facility_name, default_name)) - goto found_it; - - return false; + if (facname && list) { + for (pf = list; pf->name; pf++) { + if (!nasm_stricmp(facname, pf->name)) { + facility_match = true; + rv = call_pragma(pf, &pragma); + if (rv != DIRR_UNKNOWN) + goto found_it; + } + } -found_it: - pragma->facility = pf; + if (facility_match) { + /* + * Facility name match but no matching directive; handler in NULL + * entry at end of list? + */ + rv = call_pragma(pf, &pragma); + if (rv != DIRR_UNKNOWN) + goto found_it; + } + } - /* If the handler is NULL all pragmas are unknown... */ - if (pf->handler) - rv = pf->handler(pragma); - else - rv = DIRR_UNKNOWN; + if (facility_match) { + /* + * Facility match but still nothing: def->handler if it exists + */ + rv = call_pragma(def, &pragma); + } else { + /* + * No facility matched + */ + return DIRR_UNKNOWN; + } - /* Is there an additional, applicable generic handler? */ - if (rv == DIRR_UNKNOWN && generic_handler) - rv = generic_handler(pragma); + /* + * Otherwise we found the facility but not any supported directive, + * fall through... + */ +found_it: switch (rv) { case DIRR_UNKNOWN: - switch (pragma->opcode) { + switch (pragma.opcode) { case D_none: /*! - *!pragma-bad [off] empty or malformed %pragma + *!pragma-bad [off] malformed %pragma *!=bad-pragma *! warns about a malformed or otherwise unparsable *! \c{%pragma} directive. */ nasm_warn(ERR_PASS2|WARN_PRAGMA_BAD, - "empty %%pragma %s", pragma->facility_name); + "empty %%pragma %s", pragma.facility_name); break; default: /*! @@ -162,9 +210,10 @@ found_it: */ nasm_warn(ERR_PASS2|WARN_PRAGMA_UNKNOWN, "unknown %%pragma %s %s", - pragma->facility_name, pragma->opname); + pragma.facility_name, pragma.opname); break; } + rv = DIRR_ERROR; /* Already printed an error message */ break; case DIRR_OK: @@ -177,13 +226,13 @@ found_it: * would be compromised, as opposed to an inherent error. */ nasm_error(ERR_NONFATAL, "bad argument to %%pragma %s %s", - pragma->facility_name, pragma->opname); + pragma.facility_name, pragma.opname); break; default: panic(); } - return true; + return rv; } /* This warning message is intended for future use */ @@ -194,8 +243,16 @@ found_it: *! this particular assembly session. This is not yet implemented. */ +/* Naked %pragma */ +/*! + *!pragma-empty [off] empty %pragma directive + *! warns about a \c{%pragma} directive containing nothing. + *! This is treated identically to \c{%pragma ignore} except + *! for this optional warning. + */ void process_pragma(char *str) { + const struct pragma_facility *pf; struct pragma pragma; char *p; @@ -203,26 +260,11 @@ void process_pragma(char *str) pragma.facility_name = nasm_get_word(str, &p); if (!pragma.facility_name) { - nasm_warn(ERR_PASS2|WARN_PRAGMA_BAD, - "empty pragma directive"); - return; /* Empty pragma */ - } - - /* - * The facility "ignore" means just that; don't even complain of - * the absence of an operation. - */ - if (!nasm_stricmp(pragma.facility_name, "ignore")) + /* Empty %pragma */ + nasm_warn(ERR_PASS2|WARN_PRAGMA_EMPTY, + "empty %%pragma directive, ignored"); return; - - /* - * The "output" and "debug" facilities are aliases for the - * current output and debug formats, respectively. - */ - if (!nasm_stricmp(pragma.facility_name, "output")) - pragma.facility_name = ofmt->shortname; - if (!nasm_stricmp(pragma.facility_name, "debug")) - pragma.facility_name = dfmt->shortname; + } pragma.opname = nasm_get_word(p, &p); if (!pragma.opname) @@ -232,18 +274,25 @@ void process_pragma(char *str) pragma.tail = nasm_trim_spaces(p); - /* Look for a global pragma namespace */ - if (search_pragma_list(global_pragmas, NULL, NULL, &pragma)) - return; + /* + * Search the global pragma namespaces. This is done + * as a loop rather than than letting search_pragma_list() + * just run, because we don't want to keep searching if + * we have a facility match, thus we want to call + * search_pragma_list() individually for each namespace. + */ + for (pf = global_pragmas; pf->name; pf++) { + if (search_pragma_list(NULL, NULL, pf, &pragma) != DIRR_UNKNOWN) + return; + } - /* Look to see if it is an output backend pragma */ - if (search_pragma_list(ofmt->pragmas, ofmt->shortname, - output_pragma, &pragma)) - return; + /* Is it an output pragma? */ + if (output_pragma(&pragma) != DIRR_UNKNOWN) + return; - /* Look to see if it is a debug format pragma */ - if (search_pragma_list(dfmt->pragmas, dfmt->shortname, NULL, &pragma)) - return; + /* Is it a debug pragma */ + if (debug_pragma(&pragma) != DIRR_UNKNOWN) + return; /* * Note: it would be nice to warn for an unknown namespace, @@ -257,12 +306,31 @@ void process_pragma(char *str) */ } +/* %pragma ignore */ +static enum directive_result ignore_pragma(const struct pragma *pragma) +{ + (void)pragma; + return DIRR_OK; /* Even for D_none! */ +} + /* - * Generic pragmas that apply to all output backends; these are handled - * specially so they can be made selective based on the output format. + * Process output and debug pragmas, by either list name or generic + * name. Note that the output/debug format list can hook the default + * names if they so choose. */ +static enum directive_result output_pragma_common(const struct pragma *); static enum directive_result output_pragma(const struct pragma *pragma) { + static const struct pragma_facility + output_pragma_def = { "output", output_pragma_common }; + + return search_pragma_list(ofmt->pragmas, ofmt->shortname, + &output_pragma_def, pragma); +} + +/* Generic pragmas that apply to all output backends */ +static enum directive_result output_pragma_common(const struct pragma *pragma) +{ switch (pragma->opcode) { case D_PREFIX: case D_GPREFIX: @@ -283,6 +351,15 @@ static enum directive_result output_pragma(const struct pragma *pragma) } } +static enum directive_result debug_pragma(const struct pragma *pragma) +{ + static const struct pragma_facility + debug_pragma_def = { "debug", NULL }; + + return search_pragma_list(dfmt->pragmas, dfmt->shortname, + &debug_pragma_def, pragma); +} + /* * %pragma limit to set resource limits */ |