diff options
author | polwex <polwex@sortug.com> | 2025-10-05 21:56:51 +0700 |
---|---|---|
committer | polwex <polwex@sortug.com> | 2025-10-05 21:56:51 +0700 |
commit | fcedfddf00b3f994e4f4e40332ac7fc192c63244 (patch) | |
tree | 51d38e62c7bdfcc5f9a5e9435fe820c93cfc9a3d /vere/ext/nasm/asm/pragma.c |
claude is gud
Diffstat (limited to 'vere/ext/nasm/asm/pragma.c')
-rw-r--r-- | vere/ext/nasm/asm/pragma.c | 369 |
1 files changed, 369 insertions, 0 deletions
diff --git a/vere/ext/nasm/asm/pragma.c b/vere/ext/nasm/asm/pragma.c new file mode 100644 index 0000000..0049c06 --- /dev/null +++ b/vere/ext/nasm/asm/pragma.c @@ -0,0 +1,369 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 1996-2019 The NASM Authors - All Rights Reserved + * See the file AUTHORS included with the NASM distribution for + * the specific copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following + * conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ----------------------------------------------------------------------- */ + +/* + * Parse and handle [pragma] directives. The preprocessor handles + * %pragma preproc directives separately, all other namespaces are + * simply converted to [pragma]. + */ + +#include "compiler.h" + +#include "nctype.h" + +#include "nasm.h" +#include "nasmlib.h" +#include "assemble.h" +#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); + +/* + * Handle [pragma] directives. [pragma] is generally produced by + * the %pragma preprocessor directive, which simply passes on any + * string that it finds *except* %pragma preproc. The idea is + * that pragmas are of the form: + * + * %pragma <facility> <opname> [<options>...] + * + * ... where "facility" can be either a generic facility or a backend + * name. + * + * The following names are currently reserved for global facilities; + * so far none of these have any defined pragmas at all: + * + * preproc - preprocessor + * limit - limit setting + * asm - assembler + * list - listing generator + * file - generic file handling + * input - input file handling + * output - backend-independent output handling + * debug - backend-independent debug handling + * ignore - dummy pragma (can be used to "comment out") + * + * This function should generally not error out if it doesn't understand + * what a pragma is for, for unknown arguments, etc; the whole point of + * a pragma is that future releases might add new ones that should be + * ignored rather than be an error. Erroring out is acceptable for + * known pragmas suffering from parsing errors and so on. + * + * Adding default-suppressed warnings would, however, be a good idea + * at some point. + */ +static struct pragma_facility global_pragmas[] = +{ + { "asm", NULL }, + { "limit", limit_pragma }, + { "list", list_pragma }, + { "file", NULL }, + { "input", NULL }, + { "output", output_pragma }, + { "debug", debug_pragma }, + { "ignore", ignore_pragma }, + + /* This will never actually get this far... */ + { "preproc", NULL }, /* Handled in the preprocessor by necessity */ + { 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", *or def->name*, if set, matches the final NULL entry (used + * for backends, so multiple backends can share the same list under + * some circumstances, and the backends can implement common operations.) + */ +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 = NULL; + enum directive_result rv; + bool facility_match, is_default; + struct pragma pragma = *cpragma; + const char *facname = pragma.facility_name; + + /* Is there a default facility and we match its name? */ + is_default = def && def->name && !nasm_stricmp(facname, def->name); + facility_match = is_default; + + /* + * 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 (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; + } + } + + 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 (facility_match) { + /* + * Facility match but still nothing: def->handler if it exists + */ + rv = call_pragma(def, &pragma); + } else { + /* + * No facility matched + */ + return DIRR_UNKNOWN; + } + + /* + * Otherwise we found the facility but not any supported directive, + * fall through... + */ + +found_it: + switch (rv) { + case DIRR_UNKNOWN: + switch (pragma.opcode) { + case D_none: + /*! + *!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); + break; + default: + /*! + *!pragma-unknown [off] unknown %pragma facility or directive + *!=unknown-pragma + *! warns about an unknown \c{%pragma} directive. + *! This is not yet implemented for most cases. + */ + nasm_warn(ERR_PASS2|WARN_PRAGMA_UNKNOWN, + "unknown %%pragma %s %s", + pragma.facility_name, pragma.opname); + break; + } + rv = DIRR_ERROR; /* Already printed an error message */ + break; + + case DIRR_OK: + case DIRR_ERROR: + break; /* Nothing to do */ + + case DIRR_BADPARAM: + /* + * This one is an error. Don't use it if forward compatibility + * would be compromised, as opposed to an inherent error. + */ + nasm_error(ERR_NONFATAL, "bad argument to %%pragma %s %s", + pragma.facility_name, pragma.opname); + break; + + default: + panic(); + } + return rv; +} + +/* This warning message is intended for future use */ +/*! + *!pragma-na [off] %pragma not applicable to this compilation + *!=not-my-pragma + *! warns about a \c{%pragma} directive which is not applicable to + *! 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; + + nasm_zero(pragma); + + pragma.facility_name = nasm_get_word(str, &p); + if (!pragma.facility_name) { + /* Empty %pragma */ + nasm_warn(ERR_PASS2|WARN_PRAGMA_EMPTY, + "empty %%pragma directive, ignored"); + return; + } + + pragma.opname = nasm_get_word(p, &p); + if (!pragma.opname) + pragma.opcode = D_none; + else + pragma.opcode = directive_find(pragma.opname); + + pragma.tail = nasm_trim_spaces(p); + + /* + * Search the global pragma namespaces. This is done + * as a loop rather 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; + } + + /* Is it an output pragma? */ + if (output_pragma(&pragma) != DIRR_UNKNOWN) + return; + + /* Is it a debug pragma */ + if (debug_pragma(&pragma) != DIRR_UNKNOWN) + return; + + /* + * Note: it would be nice to warn for an unknown namespace, + * but in order to do so we need to walk *ALL* the backends + * in order to make sure we aren't dealing with a pragma that + * is for another backend. On the other hand, that could + * also be a warning with a separate warning flag. + * + * Leave this for the future, however, the warning classes are + * already defined for future compatibility. + */ +} + +/* %pragma ignore */ +static enum directive_result ignore_pragma(const struct pragma *pragma) +{ + (void)pragma; + return DIRR_OK; /* Even for D_none! */ +} + +/* + * 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: + set_label_mangle(LM_GPREFIX, pragma->tail); + return DIRR_OK; + case D_SUFFIX: + case D_GSUFFIX: + set_label_mangle(LM_GSUFFIX, pragma->tail); + return DIRR_OK; + case D_LPREFIX: + set_label_mangle(LM_LPREFIX, pragma->tail); + return DIRR_OK; + case D_LSUFFIX: + set_label_mangle(LM_LSUFFIX, pragma->tail); + return DIRR_OK; + default: + return DIRR_UNKNOWN; + } +} + +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 + */ +static enum directive_result limit_pragma(const struct pragma *pragma) +{ + return nasm_set_limit(pragma->opname, pragma->tail); +} |