aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2019-09-30 13:14:29 -0700
committerH. Peter Anvin <hpa@zytor.com>2019-09-30 13:30:15 -0700
commit1dd926e8cedb2ec9664d28fea4cd929dc006b1cd (patch)
tree6f24a09fc461a50908fe49b5d53f80cc2b26b9f1
parent9781db8906a769507a85280829c42dfe7b02f600 (diff)
downloadnasm-1dd926e8cedb2ec9664d28fea4cd929dc006b1cd.tar.gz
nasm-1dd926e8cedb2ec9664d28fea4cd929dc006b1cd.tar.xz
nasm-1dd926e8cedb2ec9664d28fea4cd929dc006b1cd.zip
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.c213
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
*/