]> granicus.if.org Git - yasm/commitdiff
Clean up directive handling. This standardizes error/warning messages and
authorPeter Johnson <peter@tortall.net>
Sat, 26 May 2007 17:56:36 +0000 (17:56 -0000)
committerPeter Johnson <peter@tortall.net>
Sat, 26 May 2007 17:56:36 +0000 (17:56 -0000)
makes value/parameters more well-defined and flexible enough to handle
string parameters.  Value/parameters would now be better called name/values,
but avoid changing the name for now.

svn path=/trunk/yasm/; revision=1851

25 files changed:
libyasm/section.c
libyasm/valparam.c
libyasm/valparam.h
modules/arch/x86/x86arch.c
modules/dbgfmts/dwarf2/dwarf2-line.c
modules/dbgfmts/dwarf2/tests/pass32/Makefile.inc
modules/dbgfmts/dwarf2/tests/pass32/dwarf32-err.asm [new file with mode: 0644]
modules/dbgfmts/dwarf2/tests/pass32/dwarf32-err.errwarn [new file with mode: 0644]
modules/dbgfmts/dwarf2/tests/passwin64/dwarfwin64_testhd.hex
modules/objfmts/bin/bin-objfmt.c
modules/objfmts/coff/coff-objfmt.c
modules/objfmts/dbg/dbg-objfmt.c
modules/objfmts/elf/elf-objfmt.c
modules/objfmts/macho/macho-objfmt.c
modules/objfmts/rdf/rdf-objfmt.c
modules/objfmts/rdf/tests/rdfext.asm
modules/objfmts/xdf/tests/Makefile.inc
modules/objfmts/xdf/tests/xdfsect-err.asm [new file with mode: 0644]
modules/objfmts/xdf/tests/xdfsect-err.errwarn [new file with mode: 0644]
modules/objfmts/xdf/tests/xdfsect.asm [new file with mode: 0644]
modules/objfmts/xdf/tests/xdfsect.hex [new file with mode: 0644]
modules/objfmts/xdf/xdf-objfmt.c
modules/parsers/gas/gas-parse.c
modules/parsers/nasm/nasm-parse.c
modules/parsers/nasm/nasm-token.re

index 15549c967c0930df2faad9dcad5aa6500fcd75ce..2b5d4342652c2705a0aa00f3497832cc97a8c850 100644 (file)
@@ -103,7 +103,8 @@ dir_extern(yasm_object *object, yasm_valparamhead *valparams,
 {
     yasm_valparam *vp = yasm_vps_first(valparams);
     yasm_symrec *sym;
-    sym = yasm_symtab_declare(object->symtab, vp->val, YASM_SYM_EXTERN, line);
+    sym = yasm_symtab_declare(object->symtab, yasm_vp_id(vp), YASM_SYM_EXTERN,
+                              line);
     if (objext_valparams) {
         yasm_valparamhead *vps = yasm_vps_create();
         *vps = *objext_valparams;   /* structure copy */
@@ -118,7 +119,8 @@ dir_global(yasm_object *object, yasm_valparamhead *valparams,
 {
     yasm_valparam *vp = yasm_vps_first(valparams);
     yasm_symrec *sym;
-    sym = yasm_symtab_declare(object->symtab, vp->val, YASM_SYM_GLOBAL, line);
+    sym = yasm_symtab_declare(object->symtab, yasm_vp_id(vp), YASM_SYM_GLOBAL,
+                              line);
     if (objext_valparams) {
         yasm_valparamhead *vps = yasm_vps_create();
         *vps = *objext_valparams;   /* structure copy */
@@ -141,7 +143,8 @@ dir_common(yasm_object *object, yasm_valparamhead *valparams,
                        N_("no size specified in %s declaration"), "COMMON");
         return;
     }
-    sym = yasm_symtab_declare(object->symtab, vp->val, YASM_SYM_COMMON, line);
+    sym = yasm_symtab_declare(object->symtab, yasm_vp_id(vp), YASM_SYM_COMMON,
+                              line);
     yasm_symrec_set_common_size(sym, size);
     if (objext_valparams) {
         yasm_valparamhead *vps = yasm_vps_create();
index 336ae9e718f348a067111156b89eed75301849c5..84cf984dd4c8542b7569d6d7c3d1ae394ccea2f9 100644 (file)
 #include "valparam.h"
 
 #include "errwarn.h"
+#include "intnum.h"
 #include "expr.h"
 #include "symrec.h"
 
+#include "section.h"
 
 void
 yasm_call_directive(const yasm_directive *directive, yasm_object *object,
@@ -53,7 +55,8 @@ yasm_call_directive(const yasm_directive *directive, yasm_object *object,
     }
     if (valparams) {
         vp = yasm_vps_first(valparams);
-        if ((directive->flags & YASM_DIR_ID_REQUIRED) && !vp->val) {
+        if ((directive->flags & YASM_DIR_ID_REQUIRED) &&
+            vp->type != YASM_PARAM_ID) {
             yasm_error_set(YASM_ERROR_SYNTAX,
                 N_("directive `%s' requires an identifier parameter"),
                 directive->name);
@@ -64,28 +67,81 @@ yasm_call_directive(const yasm_directive *directive, yasm_object *object,
 }
 
 yasm_valparam *
-yasm_vp_create(/*@keep@*/ char *v, /*@keep@*/ yasm_expr *p)
+yasm_vp_create_id(/*@keep@*/ char *v, /*@keep@*/ char *p, int id_prefix)
 {
     yasm_valparam *r = yasm_xmalloc(sizeof(yasm_valparam));
     r->val = v;
-    r->param = p;
+    r->type = YASM_PARAM_ID;
+    r->param.id = p;
+    r->id_prefix = (char)id_prefix;
+    return r;
+}
+
+yasm_valparam *
+yasm_vp_create_string(/*@keep@*/ char *v, /*@keep@*/ char *p)
+{
+    yasm_valparam *r = yasm_xmalloc(sizeof(yasm_valparam));
+    r->val = v;
+    r->type = YASM_PARAM_STRING;
+    r->param.str = p;
+    r->id_prefix = '\0';
+    return r;
+}
+
+yasm_valparam *
+yasm_vp_create_expr(/*@keep@*/ char *v, /*@keep@*/ yasm_expr *p)
+{
+    yasm_valparam *r = yasm_xmalloc(sizeof(yasm_valparam));
+    r->val = v;
+    r->type = YASM_PARAM_EXPR;
+    r->param.e = p;
+    r->id_prefix = '\0';
     return r;
 }
 
 /*@null@*/ /*@only@*/ yasm_expr *
-yasm_vp_expr(yasm_valparam *vp, yasm_symtab *symtab, unsigned long line)
+yasm_vp_expr(const yasm_valparam *vp, yasm_symtab *symtab, unsigned long line)
 {
     if (!vp)
         return NULL;
-    if (vp->val) {
-        return yasm_expr_create_ident(yasm_expr_sym(
-            yasm_symtab_use(symtab, vp->val, line)), line);
-    } else if (vp->param) {
-        yasm_expr *e = vp->param;
-        vp->param = NULL;   /* to avoid double-free */
-        return e;
-    } else
+    switch (vp->type) {
+        case YASM_PARAM_ID:
+            return yasm_expr_create_ident(yasm_expr_sym(
+                yasm_symtab_use(symtab, yasm_vp_id(vp), line)), line);
+        case YASM_PARAM_EXPR:
+            return yasm_expr_copy(vp->param.e);
+        default:
+            return NULL;
+    }
+}
+
+/*@null@*/ /*@dependent@*/ const char *
+yasm_vp_string(const yasm_valparam *vp)
+{
+    if (!vp)
+        return NULL;
+    switch (vp->type) {
+        case YASM_PARAM_ID:
+            return vp->param.id;
+        case YASM_PARAM_STRING:
+            return vp->param.str;
+        default:
+            return NULL;
+    }
+}
+
+/*@null@*/ /*@dependent@*/ const char *
+yasm_vp_id(const yasm_valparam *vp)
+{
+    if (!vp)
         return NULL;
+    if (vp->type == YASM_PARAM_ID) {
+        if (vp->param.id[0] == vp->id_prefix)
+            return &vp->param.id[1];
+        else
+            return vp->param.id;
+    }
+    return NULL;
 }
 
 void
@@ -98,8 +154,17 @@ yasm_vps_delete(yasm_valparamhead *headp)
         next = STAILQ_NEXT(cur, link);
         if (cur->val)
             yasm_xfree(cur->val);
-        if (cur->param)
-            yasm_expr_destroy(cur->param);
+        switch (cur->type) {
+            case YASM_PARAM_ID:
+                yasm_xfree(cur->param.id);
+                break;
+            case YASM_PARAM_STRING:
+                yasm_xfree(cur->param.str);
+                break;
+            case YASM_PARAM_EXPR:
+                yasm_expr_destroy(cur->param.e);
+                break;
+        }
         yasm_xfree(cur);
         cur = next;
     }
@@ -121,10 +186,17 @@ yasm_vps_print(const yasm_valparamhead *headp, FILE *f)
             fprintf(f, "(\"%s\",", vp->val);
         else
             fprintf(f, "((nil),");
-        if (vp->param)
-            yasm_expr_print(vp->param, f);
-        else
-            fprintf(f, "(nil)");
+        switch (vp->type) {
+            case YASM_PARAM_ID:
+                fprintf(f, "%s", vp->param.id);
+                break;
+            case YASM_PARAM_STRING:
+                fprintf(f, "\"%s\"", vp->param.str);
+                break;
+            case YASM_PARAM_EXPR:
+                yasm_expr_print(vp->param.e, f);
+                break;
+        }
         fprintf(f, ")");
         if (yasm_vps_next(vp))
             fprintf(f, ",");
@@ -170,3 +242,135 @@ yasm_vps_next(yasm_valparam *cur)
 {
     return STAILQ_NEXT(cur, link);
 }
+
+int
+yasm_dir_helper(void *obj, yasm_valparam *vp_first, unsigned long line,
+                const yasm_dir_help *help, size_t nhelp, void *data,
+                int (*helper_valparam) (void *obj, yasm_valparam *vp,
+                                        unsigned long line, void *data))
+{
+    yasm_valparam *vp = vp_first;
+    int anymatched = 0;
+    int matched;
+
+    if (!vp)
+        return 0;
+
+    do {
+        const char *s;
+        size_t i;
+
+        matched = 0;
+        if (!vp->val && (s = yasm_vp_id(vp))) {
+            for (i=0; i<nhelp; i++) {
+                if (help[i].needsparam == 0 &&
+                    yasm__strcasecmp(s, help[i].name) == 0) {
+                    if (help[i].helper(obj, vp, line,
+                                       ((char *)data)+help[i].off,
+                                       help[i].arg) != 0)
+                        return -1;
+                    matched = 1;
+                    anymatched = 1;
+                    break;
+                }
+            }
+        } else if (vp->val) {
+            for (i=0; i<nhelp; i++) {
+                if (help[i].needsparam == 1 &&
+                    yasm__strcasecmp(vp->val, help[i].name) == 0) {
+                    if (help[i].helper(obj, vp, line,
+                                       ((char *)data)+help[i].off,
+                                       help[i].arg) != 0)
+                        return -1;
+                    matched = 1;
+                    anymatched = 1;
+                    break;
+                }
+            }
+        }
+
+        if (!matched) {
+            int final = helper_valparam(obj, vp, line, data);
+            if (final < 0)
+                return -1;
+            if (final > 0)
+                anymatched = 1;
+        }
+    } while((vp = yasm_vps_next(vp)));
+
+    return anymatched;
+}
+
+int
+yasm_dir_helper_flag_or(void *obj, yasm_valparam *vp, unsigned long line,
+                        void *d, uintptr_t flag)
+{
+    unsigned long *flags = (unsigned long *)d;
+    *flags |= flag;
+    return 0;
+}
+
+int
+yasm_dir_helper_flag_and(void *obj, yasm_valparam *vp, unsigned long line,
+                         void *d, uintptr_t flag)
+{
+    unsigned long *flags = (unsigned long *)d;
+    *flags &= ~flag;
+    return 0;
+}
+
+int
+yasm_dir_helper_flag_set(void *obj, yasm_valparam *vp, unsigned long line,
+                         void *d, uintptr_t flag)
+{
+    unsigned long *flags = (unsigned long *)d;
+    *flags = flag;
+    return 0;
+}
+
+int
+yasm_dir_helper_intn(void *obj, yasm_valparam *vp, unsigned long line,
+                     void *data, uintptr_t arg)
+{
+    yasm_object *object = (yasm_object *)obj;
+    /*@only@*/ /*@null@*/ yasm_expr *e;
+    /*@dependent@*/ /*@null@*/ yasm_intnum *local;
+    yasm_intnum **intn = (yasm_intnum **)data;
+
+    if (*intn)
+        yasm_intnum_destroy(*intn);
+    if (!(e = yasm_vp_expr(vp, object->symtab, line)) ||
+        !(local = yasm_expr_get_intnum(&e, 0))) {
+        yasm_error_set(YASM_ERROR_NOT_CONSTANT,
+                       N_("argument to `%s' is not an integer"),
+                       vp->val);
+        if (e)
+            yasm_expr_destroy(e);
+        return -1;
+    }
+    *intn = yasm_intnum_copy(local);
+    yasm_expr_destroy(e);
+    return 0;
+}
+
+int
+yasm_dir_helper_valparam_warn(void *obj, yasm_valparam *vp,
+                              unsigned long line, void *data)
+{
+    const char *s;
+
+    if (vp->val) {
+        yasm_warn_set(YASM_WARN_GENERAL, N_("Unrecognized qualifier `%s'"),
+                      vp->val);
+        return 0;
+    }
+
+    if ((s = yasm_vp_id(vp)))
+        yasm_warn_set(YASM_WARN_GENERAL, N_("Unrecognized qualifier `%s'"), s);
+    else if (vp->type == YASM_PARAM_STRING)
+        yasm_warn_set(YASM_WARN_GENERAL, N_("Unrecognized string qualifier"));
+    else
+        yasm_warn_set(YASM_WARN_GENERAL, N_("Unrecognized numeric qualifier"));
+
+    return 0;
+}
index ee5d23fa98e8c4d748c3244f3963bee4482e0777..9a2a1303b5ed5a993719c9cd2cf8007fef0f5c77 100644 (file)
 struct yasm_valparam {
     /*@reldef@*/ STAILQ_ENTRY(yasm_valparam) link;  /**< Next pair in list */
     /*@owned@*/ /*@null@*/ char *val;           /**< Value */
-    /*@owned@*/ /*@null@*/ yasm_expr *param;    /**< Parameter */
+
+    enum yasm_param_type {
+        YASM_PARAM_ID,                          /**< Identifier */
+        YASM_PARAM_STRING,                      /**< String */
+        YASM_PARAM_EXPR                         /**< Expression */
+    } type;                                     /**< Parameter type */
+
+    union yasm_param {
+        /*@owned@*/ char *id;                   /**< Identifier */
+        /*@owned@*/ char *str;                  /**< String */
+        /*@owned@*/ yasm_expr *e;               /**< Expression */
+    } param;                                    /**< Parameter */
+
+    /* Prefix character that indicates a raw identifier.  When yasm_vp_string()
+     * is called on a #YASM_PARAM_ID, all characters are returned.  When
+     * yasm_vp_id() is called on a #YASM_PARAM_ID, if the identifier begins
+     * with this character, this character is stripped from the returned
+     * value.
+     */
+    char id_prefix;
 };
 
 /** Linked list of value/parameter pairs.  \internal */
@@ -87,23 +106,55 @@ void yasm_call_directive(const yasm_directive *directive, yasm_object *object,
                          yasm_valparamhead *objext_valparams,
                          unsigned long line);
 
-/** Create a new valparam.
+/** Create a new valparam with identifier parameter.
+ * \param v             value
+ * \param p             parameter
+ * \param id_prefix     identifier prefix for raw identifiers
+ * \return Newly allocated valparam.
+ */
+yasm_valparam *yasm_vp_create_id(/*@keep@*/ char *v, /*@keep@*/ char *p,
+                                 int id_prefix);
+
+/** Create a new valparam with string parameter.
+ * \param v     value
+ * \param p     parameter
+ * \return Newly allocated valparam.
+ */
+yasm_valparam *yasm_vp_create_string(/*@keep@*/ char *v, /*@keep@*/ char *p);
+
+/** Create a new valparam with expression parameter.
  * \param v     value
  * \param p     parameter
  * \return Newly allocated valparam.
  */
-yasm_valparam *yasm_vp_create(/*@keep@*/ char *v, /*@keep@*/ yasm_expr *p);
+yasm_valparam *yasm_vp_create_expr(/*@keep@*/ char *v,
+                                   /*@keep@*/ yasm_expr *p);
 
-/** Get a valparam as an expr.  If the valparam is a value, it's treated
- * as a symbol (yasm_symtab_use() is called to convert it).  The valparam
- * is modified as necessary to avoid double-frees.
+/** Get a valparam parameter as an expr.  If the parameter is an identifier,
+ * it's treated as a symbol (yasm_symtab_use() is called to convert it).
  * \param vp            valparam
  * \param symtab        symbol table
  * \param line          virtual line
- * \return Expression, or NULL if vp is NULL or if val and param are both NULL.
+ * \return Expression, or NULL if vp is NULL or the parameter cannot be
+ *         converted to an expression.
  */
 /*@null@*/ /*@only@*/ yasm_expr *yasm_vp_expr
-    (yasm_valparam *vp, yasm_symtab *symtab, unsigned long line);
+    (const yasm_valparam *vp, yasm_symtab *symtab, unsigned long line);
+
+/** Get a valparam parameter as a string.  If the parameter is an identifier,
+ * it's treated as a string.
+ * \param vp            valparam
+ * \return String, or NULL if vp is NULL or the parameter cannot be realized
+ *         as a string.
+ */
+/*@null@*/ /*@dependent@*/ const char *yasm_vp_string(const yasm_valparam *vp);
+
+/** Get a valparam parameter as an identifier.
+ * \param vp            valparam
+ * \return Identifier (string), or NULL if vp is NULL or the parameter is not
+ *         an identifier.
+ */
+/*@null@*/ /*@dependent@*/ const char *yasm_vp_id(const yasm_valparam *vp);
 
 /** Create a new linked list of valparams.
  * \return Newly allocated valparam list.
@@ -173,4 +224,130 @@ void yasm_vps_append(yasm_valparamhead *headp, /*@keep@*/ yasm_valparam *vp);
  */
 void yasm_vps_print(/*@null@*/ const yasm_valparamhead *headp, FILE *f);
 
+/** Directive valparam parse helper structure. */
+typedef struct yasm_dir_help {
+    /** Value portion of val=param (if needsparam=1), or standalone identifier
+     * (if needsparam=0).
+     */
+    const char *name;
+
+    /** 1 if value requires parameter, 0 if it must not have a parameter. */
+    int needsparam;
+
+    /** Helper callback function if name and parameter existence match.
+     * \param obj       obj passed into yasm_dir_helper()
+     * \param vp        value/parameter
+     * \param line      line passed into yasm_dir_helper()
+     * \param data      data passed into yasm_dir_helper() plus
+                        #yasm_dir_help.off offset
+     * \param arg       #yasm_dir_help.arg argument
+     * \return -1 on error, 0 otherwise.
+     */
+    int (*helper) (void *obj, yasm_valparam *vp, unsigned long line,
+                   void *data, uintptr_t arg);
+
+    /** Offset added to data pointer passed into yasm_dir_helper() before
+     * data pointer is given to #yasm_dir_help.helper().  This is so that
+     * a structure can be passed into yasm_dir_helper() and this can be an
+     * offsetof() to point the helper function to a specific structure
+     * member.
+     */
+    size_t off;
+
+    /** Argument to pass in as the arg parameter to #yasm_dir_help.helper().
+     */
+    uintptr_t arg;
+} yasm_dir_help;
+
+/** Help parse a list of directive value/parameters.  Takes an array of
+ * #yasm_dir_help structures and tries to match val=param (or just val)
+ * against the passed value/parameters.  When no match is found in the
+ * array of help structures, calls helper_valparam.
+ * \param obj       object to be passed to yasm_dir_help.helper() or
+ *                  helper_valparam() callback
+ * \param vp_first  first value/parameter to examine
+ * \param line      virtual line number; passed down to helper callback
+ * \param help      array of #yasm_dir_help structures
+ * \param nhelp     number of array elements
+ * \param data      base data pointer; if a match is found,
+ *                  the respective #yasm_dir_help.off is added to this
+ *                  prior to it being passed to the helper callback
+ * \param helper_valparam   catch-all callback; should return -1 on error,
+ *                          0 if not matched, 1 if matched.
+ * \return -1 on error, 1 if any arguments matched (including via
+ *         catch-all callback), 0 if no match.
+ */
+int yasm_dir_helper(void *obj, yasm_valparam *vp_first, unsigned long line,
+                    const yasm_dir_help *help, size_t nhelp, void *data,
+                    int (*helper_valparam) (void *object,
+                                            yasm_valparam *vp,
+                                            unsigned long line,
+                                            void *data));
+
+/** Standard helper for yasm_dir_helper() that simply sets a flag when called.
+ * It does not look at the vp; rather, it uses the value of the arg parameter,
+ * and stores an unsigned long value to data.
+ * \param obj   unused
+ * \param vp    unused
+ * \param line  unused
+ * \param data  pointer to an unsigned long
+ * \param arg   flag to set
+ * \return 0
+ */
+int yasm_dir_helper_flag_set(void *obj, yasm_valparam *vp, unsigned long line,
+                             void *data, uintptr_t arg);
+
+/** Standard helper for yasm_dir_helper() that simply ORs a flag when called.
+ * It does not look at the vp; rather, it uses the value of the arg parameter,
+ * and ORs it with the unsigned long value in data.
+ * \param obj   unused
+ * \param vp    unused
+ * \param line  unused
+ * \param data  pointer to an unsigned long
+ * \param arg   flag to OR
+ * \return 0
+ */
+int yasm_dir_helper_flag_or(void *obj, yasm_valparam *vp, unsigned long line,
+                            void *data, uintptr_t arg);
+
+/** Standard helper for yasm_dir_helper() that simply ANDs a flag when called.
+ * It does not look at the vp; rather, it uses the value of the arg parameter,
+ * and ANDs its inverse (~) with the unsigned long value in data.
+ * \param obj   unused
+ * \param vp    unused
+ * \param line  unused
+ * \param data  pointer to an unsigned long
+ * \param arg   flag to AND
+ * \return 0
+ */
+int yasm_dir_helper_flag_and(void *obj, yasm_valparam *vp, unsigned long line,
+                             void *data, uintptr_t arg);
+
+/** Standard helper for yasm_dir_helper() that parses an intnum parameter.
+ * The #yasm_dir_help structure that uses this function should have
+ * needsparam=1.  The obj parameter to yasm_dir_helper() when this helper
+ * is used MUST point to a #yasm_object.  In addition, the data parameter
+ * that is ultimately passed to this function (e.g. yasm_dir_helper() data
+ * parameter plus #yasm_dir_help.off) must point to a #yasm_intnum *
+ * initialized to NULL.
+ * \param obj   object; must be #yasm_object
+ * \param vp    valparam
+ * \param line  virtual line number
+ * \param data  pointer to #yasm_intnum *
+ * \param arg   unused argument
+ * \return -1 on error, 0 otherwise.
+ */
+int yasm_dir_helper_intn(void *obj, yasm_valparam *vp, unsigned long line,
+                         void *data, uintptr_t arg);
+
+/** Standard catch-all callback fro yasm_dir_helper().  Generates standard
+ * warning for all valparams.
+ * \param obj   unused
+ * \param vp    valparam
+ * \param line  unused
+ * \param data  unused
+ * \return 0
+ */
+int yasm_dir_helper_valparam_warn(void *obj, yasm_valparam *vp,
+                                  unsigned long line, void *data);
 #endif
index 371e5b4797e1f49e0044bd4fd3f0eb9474048fe0..42a953892b58c7cdfd8aed2273fc01b4dd41d433 100644 (file)
@@ -126,11 +126,12 @@ x86_dir_cpu(yasm_object *object, yasm_valparamhead *valparams,
 
     yasm_valparam *vp;
     yasm_vps_foreach(vp, valparams) {
-        if (vp->val)
-            yasm_x86__parse_cpu(arch_x86, vp->val, strlen(vp->val));
-        else if (vp->param) {
+        /*@null@*/ /*@dependent@*/ const char *s = yasm_vp_string(vp);
+        if (s)
+            yasm_x86__parse_cpu(arch_x86, s, strlen(s));
+        else if (vp->type == YASM_PARAM_EXPR) {
             const yasm_intnum *intcpu;
-            intcpu = yasm_expr_get_intnum(&vp->param, 0);
+            intcpu = yasm_expr_get_intnum(&vp->param.e, 0);
             if (!intcpu)
                 yasm_error_set(YASM_ERROR_SYNTAX,
                                N_("invalid argument to [%s]"), "CPU");
@@ -139,7 +140,9 @@ x86_dir_cpu(yasm_object *object, yasm_valparamhead *valparams,
                 sprintf(strcpu, "%lu", yasm_intnum_get_uint(intcpu));
                 yasm_x86__parse_cpu(arch_x86, strcpu, strlen(strcpu));
             }
-        }
+        } else
+            yasm_error_set(YASM_ERROR_SYNTAX, N_("invalid argument to [%s]"),
+                           "CPU");
     }
 }
 
@@ -149,17 +152,21 @@ x86_dir_bits(yasm_object *object, yasm_valparamhead *valparams,
 {
     yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)object->arch;
     yasm_valparam *vp;
+    /*@only@*/ /*@null@*/ yasm_expr *e = NULL;
     const yasm_intnum *intn;
     long lval;
 
-    if ((vp = yasm_vps_first(valparams)) && !vp->val && vp->param != NULL &&
-        (intn = yasm_expr_get_intnum(&vp->param, 0)) != NULL &&
+    if ((vp = yasm_vps_first(valparams)) && !vp->val &&
+        (e = yasm_vp_expr(vp, object->symtab, line)) != NULL &&
+        (intn = yasm_expr_get_intnum(&e, 0)) != NULL &&
         (lval = yasm_intnum_get_int(intn)) &&
         (lval == 16 || lval == 32 || lval == 64))
         arch_x86->mode_bits = (unsigned char)lval;
     else
         yasm_error_set(YASM_ERROR_VALUE, N_("invalid argument to [%s]"),
                        "BITS");
+    if (e)
+        yasm_expr_destroy(e);
 }
 
 static void
index c85763cf3f16953072e4d4f9f8a3a9e2f43c5cfc..6e77ceb4a105915b70cecda7b0ca083fe9dedc9a 100644 (file)
@@ -831,18 +831,20 @@ yasm_dwarf2__dir_loc(yasm_object *object, yasm_valparamhead *valparams,
                      yasm_valparamhead *objext_valparams, unsigned long line)
 {
     yasm_valparam *vp;
+    int in_is_stmt = 0, in_isa = 0;
 
     /*@dependent@*/ /*@null@*/ const yasm_intnum *intn;
     dwarf2_section_data *dsd;
     dwarf2_loc *loc = yasm_xmalloc(sizeof(dwarf2_loc));
 
     /* File number (required) */
-    if (!valparams || !(vp = yasm_vps_first(valparams)) || !vp->param) {
+    if (!valparams || !(vp = yasm_vps_first(valparams)) ||
+        vp->val || vp->type != YASM_PARAM_EXPR) {
         yasm_error_set(YASM_ERROR_SYNTAX, N_("file number required"));
         yasm_xfree(loc);
         return;
     }
-    intn = yasm_expr_get_intnum(&vp->param, 0);
+    intn = yasm_expr_get_intnum(&vp->param.e, 0);
     if (!intn) {
         yasm_error_set(YASM_ERROR_NOT_CONSTANT,
                        N_("file number is not a constant"));
@@ -858,15 +860,15 @@ yasm_dwarf2__dir_loc(yasm_object *object, yasm_valparamhead *valparams,
 
     /* Line number (required) */
     vp = yasm_vps_next(vp);
-    if (!vp || !vp->param) {
+    if (!vp || vp->val || vp->type != YASM_PARAM_EXPR) {
         yasm_error_set(YASM_ERROR_SYNTAX, N_("line number required"));
         yasm_xfree(loc);
         return;
     }
-    intn = yasm_expr_get_intnum(&vp->param, 0);
+    intn = yasm_expr_get_intnum(&vp->param.e, 0);
     if (!intn) {
         yasm_error_set(YASM_ERROR_NOT_CONSTANT,
-                       N_("file number is not a constant"));
+                       N_("line number is not a constant"));
         yasm_xfree(loc);
         return;
     }
@@ -899,8 +901,8 @@ yasm_dwarf2__dir_loc(yasm_object *object, yasm_valparamhead *valparams,
 
     /* Optional column number */
     vp = yasm_vps_next(vp);
-    if (vp && vp->param) {
-        intn = yasm_expr_get_intnum(&vp->param, 0);
+    if (vp && !vp->val && vp->type == YASM_PARAM_EXPR) {
+        intn = yasm_expr_get_intnum(&vp->param.e, 0);
         if (!intn) {
             yasm_error_set(YASM_ERROR_NOT_CONSTANT,
                            N_("column number is not a constant"));
@@ -911,26 +913,24 @@ yasm_dwarf2__dir_loc(yasm_object *object, yasm_valparamhead *valparams,
         vp = yasm_vps_next(vp);
     }
 
-    /* Other options */
-    while (vp && vp->val) {
-        if (yasm__strcasecmp(vp->val, "basic_block") == 0)
-            loc->basic_block = 1;
-        else if (yasm__strcasecmp(vp->val, "prologue_end") == 0)
-            loc->prologue_end = 1;
-        else if (yasm__strcasecmp(vp->val, "epilogue_begin") == 0)
-            loc->epilogue_begin = 1;
-        else if (yasm__strcasecmp(vp->val, "is_stmt") == 0) {
-            if (!vp->param) {
-                yasm_error_set(YASM_ERROR_SYNTAX,
-                               N_("is_stmt requires value"));
-                yasm_xfree(loc);
-                return;
-            }
-            intn = yasm_expr_get_intnum(&vp->param, 0);
-            if (!intn) {
+    /* Other options; note for GAS compatibility we need to support both:
+     * is_stmt=1 (NASM) and
+     * is_stmt 1 (GAS)
+     */
+    while (vp) {
+        /*@null@*/ /*@dependent@*/ const char *s;
+        /*@null@*/ /*@only@*/ yasm_expr *e;
+
+restart:
+        if (in_is_stmt) {
+            in_is_stmt = 0;
+            if (!(e = yasm_vp_expr(vp, object->symtab, line)) ||
+                !(intn = yasm_expr_get_intnum(&e, 0))) {
                 yasm_error_set(YASM_ERROR_NOT_CONSTANT,
                                N_("is_stmt value is not a constant"));
                 yasm_xfree(loc);
+                if (e)
+                    yasm_expr_destroy(e);
                 return;
             }
             if (yasm_intnum_is_zero(intn))
@@ -941,32 +941,65 @@ yasm_dwarf2__dir_loc(yasm_object *object, yasm_valparamhead *valparams,
                 yasm_error_set(YASM_ERROR_VALUE,
                                N_("is_stmt value not 0 or 1"));
                 yasm_xfree(loc);
+                yasm_expr_destroy(e);
                 return;
             }
-        } else if (yasm__strcasecmp(vp->val, "isa") == 0) {
-            if (!vp->param) {
-                yasm_error_set(YASM_ERROR_SYNTAX, N_("isa requires value"));
-                yasm_xfree(loc);
-                return;
-            }
-            intn = yasm_expr_get_intnum(&vp->param, 0);
-            if (!intn) {
+            yasm_expr_destroy(e);
+        } else if (in_isa) {
+            in_isa = 0;
+            if (!(e = yasm_vp_expr(vp, object->symtab, line)) ||
+                !(intn = yasm_expr_get_intnum(&e, 0))) {
                 yasm_error_set(YASM_ERROR_NOT_CONSTANT,
                                N_("isa value is not a constant"));
                 yasm_xfree(loc);
+                if (e)
+                    yasm_expr_destroy(e);
                 return;
             }
             if (yasm_intnum_sign(intn) < 0) {
                 yasm_error_set(YASM_ERROR_VALUE,
                                N_("isa value less than zero"));
                 yasm_xfree(loc);
+                yasm_expr_destroy(e);
                 return;
             }
             loc->isa_change = 1;
             loc->isa = yasm_intnum_get_uint(intn);
+            yasm_expr_destroy(e);
+        } else if (!vp->val && (s = yasm_vp_id(vp))) {
+            if (yasm__strcasecmp(s, "is_stmt") == 0)
+                in_is_stmt = 1;
+            else if (yasm__strcasecmp(s, "isa") == 0)
+                in_isa = 1;
+            else if (yasm__strcasecmp(s, "basic_block") == 0)
+                loc->basic_block = 1;
+            else if (yasm__strcasecmp(s, "prologue_end") == 0)
+                loc->prologue_end = 1;
+            else if (yasm__strcasecmp(s, "epilogue_begin") == 0)
+                loc->epilogue_begin = 1;
+            else
+                yasm_warn_set(YASM_WARN_GENERAL,
+                              N_("unrecognized loc option `%s'"), s);
+        } else if (!vp->val) {
+            yasm_warn_set(YASM_WARN_GENERAL,
+                          N_("unrecognized numeric qualifier"));
+        } else if (yasm__strcasecmp(vp->val, "is_stmt") == 0) {
+            in_is_stmt = 1;
+            goto restart; /* don't go to the next valparam */
+        } else if (yasm__strcasecmp(vp->val, "isa") == 0) {
+            in_isa = 1;
+            goto restart; /* don't go to the next valparam */
         } else
             yasm_warn_set(YASM_WARN_GENERAL,
                           N_("unrecognized loc option `%s'"), vp->val);
+        vp = yasm_vps_next(vp);
+    }
+
+    if (in_is_stmt || in_isa) {
+        yasm_error_set(YASM_ERROR_SYNTAX, N_("%s requires value"),
+                       in_is_stmt ? "is_stmt" : "isa");
+        yasm_xfree(loc);
+        return;
     }
 
     /* Append new location */
@@ -992,15 +1025,15 @@ yasm_dwarf2__dir_file(yasm_object *object, yasm_valparamhead *valparams,
     }
 
     vp = yasm_vps_first(valparams);
-    if (vp->val) {
+    if (yasm_vp_string(vp)) {
         /* Just a bare filename */
-        yasm_object_set_source_fn(object, vp->val);
+        yasm_object_set_source_fn(object, yasm_vp_string(vp));
         return;
     }
 
     /* Otherwise.. first vp is the file number */
-    file_intn = yasm_expr_get_intnum(&vp->param, 0);
-    if (!file_intn) {
+    if (vp->type != YASM_PARAM_EXPR ||
+        !(file_intn = yasm_expr_get_intnum(&vp->param.e, 0))) {
         yasm_error_set(YASM_ERROR_NOT_CONSTANT,
                        N_("file number is not a constant"));
         return;
@@ -1008,11 +1041,11 @@ yasm_dwarf2__dir_file(yasm_object *object, yasm_valparamhead *valparams,
     filenum = yasm_intnum_get_uint(file_intn);
 
     vp = yasm_vps_next(vp);
-    if (!vp || !vp->val) {
+    if (!yasm_vp_string(vp)) {
         yasm_error_set(YASM_ERROR_SYNTAX,
                        N_("file number given but no filename"));
         return;
     }
 
-    dwarf2_dbgfmt_add_file(dbgfmt_dwarf2, filenum, vp->val);
+    dwarf2_dbgfmt_add_file(dbgfmt_dwarf2, filenum, yasm_vp_string(vp));
 }
index 5637c3ea5ed076e00a6c7ba8266c9723f7fc8fcf..4c3fabc9040d6667f829d0c484dc8b65dfd357e3 100644 (file)
@@ -3,6 +3,8 @@
 TESTS += modules/dbgfmts/dwarf2/tests/pass32/dwarf2_pass32_test.sh
 
 EXTRA_DIST += modules/dbgfmts/dwarf2/tests/pass32/dwarf2_pass32_test.sh
+EXTRA_DIST += modules/dbgfmts/dwarf2/tests/pass32/dwarf32-err.asm
+EXTRA_DIST += modules/dbgfmts/dwarf2/tests/pass32/dwarf32-err.errwarn
 EXTRA_DIST += modules/dbgfmts/dwarf2/tests/pass32/dwarf32_testhd.asm
 EXTRA_DIST += modules/dbgfmts/dwarf2/tests/pass32/dwarf32_testhd.hex
 
diff --git a/modules/dbgfmts/dwarf2/tests/pass32/dwarf32-err.asm b/modules/dbgfmts/dwarf2/tests/pass32/dwarf32-err.asm
new file mode 100644 (file)
index 0000000..97f7ae5
--- /dev/null
@@ -0,0 +1,34 @@
+.loc
+.loc "foo"
+.loc bar
+.loc -5
+#.loc foo=1
+.loc 1
+.loc 1 "foo"
+.loc 1 bar
+.loc 1 2
+#.loc 1 bar=2
+.loc 1 bar 2
+.loc 1 2 "foo"
+.loc 1 2 bar+1
+.loc 1 2 is_stmt
+.loc 1 2 is_stmt 1
+#.loc 1 2 is_stmt="foo"
+.loc 1 2 is_stmt "foo"
+#.loc 1 2 is_stmt=bar
+.loc 1 2 is_stmt bar
+.loc 1 2 is_stmt (bar)
+#.loc 1 2 is_stmt=2
+.loc 1 2 is_stmt 2
+.loc 1 2 isa
+.loc 1 2 isa 1
+#.loc 1 2 isa="foo"
+.loc 1 2 isa "foo"
+#.loc 1 2 isa=bar
+.loc 1 2 isa bar
+#.loc 1 2 isa=-2
+.loc 1 2 isa (-2)
+.loc 1 2 isa -2
+#.loc 1 2 foo=1
+.loc 1 2 foo 1
+#.loc 1 2 bar
diff --git a/modules/dbgfmts/dwarf2/tests/pass32/dwarf32-err.errwarn b/modules/dbgfmts/dwarf2/tests/pass32/dwarf32-err.errwarn
new file mode 100644 (file)
index 0000000..d22fdf9
--- /dev/null
@@ -0,0 +1,22 @@
+-:1: directive `.loc' requires an argument
+-:2: file number required
+-:3: file number required
+-:4: file number less than one
+-:6: line number required
+-:7: line number required
+-:8: line number required
+-:11: line number required
+-:12: warning: unrecognized numeric qualifier
+-:13: column number is not a constant
+-:14: is_stmt requires value
+-:17: is_stmt value is not a constant
+-:19: is_stmt value is not a constant
+-:20: is_stmt value is not a constant
+-:22: is_stmt value not 0 or 1
+-:23: isa requires value
+-:26: isa value is not a constant
+-:28: isa value is not a constant
+-:30: isa value less than zero
+-:31: column number is not a constant
+-:33: warning: unrecognized loc option `foo'
+-:33: warning: unrecognized numeric qualifier
index dd90b3aa7e4c539421b8595255fed41130ee789d..fdf74cc50f8c57bc229990493820ca1e008e7e53 100644 (file)
@@ -297,7 +297,7 @@ e2
 20 
 00 
 40 
-6
+c
 2f 
 38 
 30 
@@ -537,7 +537,7 @@ f4
 20 
 00 
 00 
-6
+c
 48 
 89 
 6c 
index 1524ac6cb46528b54977ed8ad0fdab7e4e50b6a4..1a0c9ec2ad5612a0b30693125875ffb2aa1678af 100644 (file)
@@ -412,87 +412,73 @@ bin_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams,
     yasm_section *retval;
     int isnew;
     unsigned long start;
-    char *sectname;
+    const char *sectname;
     int resonly = 0;
+    /*@only@*/ /*@null@*/ yasm_intnum *align_intn = NULL;
     unsigned long align = 4;
     int have_align = 0;
 
-    if ((vp = yasm_vps_first(valparams)) && !vp->param && vp->val != NULL) {
-        /* If it's the first section output (.text) start at 0, otherwise
-         * make sure the start is > 128.
-         */
-        sectname = vp->val;
-        if (strcmp(sectname, ".text") == 0)
-            start = 0;
-        else if (strcmp(sectname, ".data") == 0)
-            start = 200;
-        else if (strcmp(sectname, ".bss") == 0) {
-            start = 200;
-            resonly = 1;
-        } else {
-            /* other section names not recognized. */
-            yasm_error_set(YASM_ERROR_GENERAL,
-                           N_("segment name `%s' not recognized"), sectname);
-            return NULL;
-        }
+    static const yasm_dir_help help[] = {
+        { "align", 1, yasm_dir_helper_intn, 0, 0 }
+    };
 
-        /* Check for ALIGN qualifier */
-        while ((vp = yasm_vps_next(vp))) {
-            if (!vp->val) {
-                yasm_warn_set(YASM_WARN_GENERAL,
-                              N_("Unrecognized numeric qualifier"));
-                continue;
-            }
+    vp = yasm_vps_first(valparams);
+    sectname = yasm_vp_string(vp);
+    if (!sectname)
+        return NULL;
+    vp = yasm_vps_next(vp);
 
-            if (yasm__strcasecmp(vp->val, "align") == 0 && vp->param) {
-                /*@dependent@*/ /*@null@*/ const yasm_intnum *align_expr;
-
-                if (strcmp(sectname, ".text") == 0) {
-                    yasm_error_set(YASM_ERROR_GENERAL,
-                        N_("cannot specify an alignment to the `%s' section"),
-                        sectname);
-                    return NULL;
-                }
-                
-                align_expr = yasm_expr_get_intnum(&vp->param, 0);
-                if (!align_expr) {
-                    yasm_error_set(YASM_ERROR_VALUE,
-                                N_("argument to `%s' is not an integer"),
-                                vp->val);
-                    return NULL;
-                }
-                align = yasm_intnum_get_uint(align_expr);
-
-                /* Alignments must be a power of two. */
-                if (!is_exp2(align)) {
-                    yasm_error_set(YASM_ERROR_VALUE,
-                                N_("argument to `%s' is not a power of two"),
-                                vp->val);
-                    return NULL;
-                }
-
-                have_align = 1;
-            }
+    /* If it's the first section output (.text) start at 0, otherwise
+     * make sure the start is > 128.
+     */
+    if (strcmp(sectname, ".text") == 0)
+        start = 0;
+    else if (strcmp(sectname, ".data") == 0)
+        start = 200;
+    else if (strcmp(sectname, ".bss") == 0) {
+        start = 200;
+        resonly = 1;
+    } else {
+        /* other section names not recognized. */
+        yasm_error_set(YASM_ERROR_GENERAL,
+                       N_("segment name `%s' not recognized"), sectname);
+        return NULL;
+    }
+
+    have_align = yasm_dir_helper(object, vp, line, help, NELEMS(help),
+                                 &align_intn, yasm_dir_helper_valparam_warn);
+    if (have_align < 0)
+        return NULL;    /* error occurred */
+
+    if (align_intn) {
+        align = yasm_intnum_get_uint(align_intn);
+        yasm_intnum_destroy(align_intn);
+
+        /* Alignments must be a power of two. */
+        if (!is_exp2(align)) {
+            yasm_error_set(YASM_ERROR_VALUE,
+                           N_("argument to `%s' is not a power of two"),
+                           "align");
+            return NULL;
         }
+    }
 
-        retval = yasm_object_get_general(object, sectname,
-            yasm_expr_create_ident(
-                yasm_expr_int(yasm_intnum_create_uint(start)), line), align,
-            strcmp(sectname, ".text") == 0, resonly, &isnew, line);
+    retval = yasm_object_get_general(object, sectname,
+        yasm_expr_create_ident(
+            yasm_expr_int(yasm_intnum_create_uint(start)), line), align,
+        strcmp(sectname, ".text") == 0, resonly, &isnew, line);
 
-        if (isnew)
-            bin_objfmt_init_new_section(object, retval, sectname, line);
+    if (isnew)
+        bin_objfmt_init_new_section(object, retval, sectname, line);
 
-        if (isnew || yasm_section_is_default(retval)) {
-            yasm_section_set_default(retval, 0);
-            yasm_section_set_align(retval, align, line);
-        } else if (have_align)
-            yasm_warn_set(YASM_WARN_GENERAL,
-                N_("alignment value ignored on section redeclaration"));
+    if (isnew || yasm_section_is_default(retval)) {
+        yasm_section_set_default(retval, 0);
+        yasm_section_set_align(retval, align, line);
+    } else if (have_align)
+        yasm_warn_set(YASM_WARN_GENERAL,
+            N_("alignment value ignored on section redeclaration"));
 
-        return retval;
-    } else
-        return NULL;
+    return retval;
 }
 
 static void
@@ -503,25 +489,11 @@ bin_objfmt_dir_org(yasm_object *object,
 {
     yasm_section *sect;
     yasm_valparam *vp;
-
-    /*@null@*/ yasm_expr *start = NULL;
-
-    if (!valparams) {
-        yasm_error_set(YASM_ERROR_SYNTAX, N_("[%s] requires an argument"),
-                       "ORG");
-        return;
-    }
+    /*@only@*/ /*@null@*/ yasm_expr *start;
 
     /* ORG takes just a simple integer as param */
     vp = yasm_vps_first(valparams);
-    if (vp->val)
-        start = yasm_expr_create_ident(yasm_expr_sym(yasm_symtab_use(
-            object->symtab, vp->val, line)), line);
-    else if (vp->param) {
-        start = vp->param;
-        vp->param = NULL;       /* Don't let valparams delete it */
-    }
-
+    start = yasm_vp_expr(vp, object->symtab, line);
     if (!start) {
         yasm_error_set(YASM_ERROR_SYNTAX,
                        N_("argument to ORG must be expression"));
index b7208fa7d8085ba2da299ee4a380f3c62ff34c03..1df7c4cf37fbfb4388a1a2822a63909d1e69a012 100644 (file)
@@ -1266,6 +1266,90 @@ coff_objfmt_add_default_section(yasm_object *object)
     return retval;
 }
 
+struct coff_section_switch_data {
+    int isdefault;
+    int gasflags;
+    unsigned long flags;
+    unsigned long flags2;
+    /*@only@*/ /*@null@*/ yasm_intnum *align_intn;
+};
+
+/* GAS-style flags */
+static int
+coff_helper_gasflags(void *obj, yasm_valparam *vp, unsigned long line, void *d,
+                     /*@unused@*/ uintptr_t arg)
+{
+    struct coff_section_switch_data *data =
+        (struct coff_section_switch_data *)d;
+    int alloc = 0, load = 0, readonly = 0, code = 0, datasect = 0;
+    int shared = 0;
+    const char *s = yasm_vp_string(vp);
+    size_t i;
+
+    if (!s) {
+        yasm_error_set(YASM_ERROR_VALUE, N_("non-string section attribute"));
+        return -1;
+    }
+
+    /* For GAS, default to read/write data */
+    if (data->isdefault)
+        data->flags = COFF_STYP_TEXT | COFF_STYP_READ | COFF_STYP_WRITE;
+
+    for (i=0; i<strlen(s); i++) {
+        switch (s[i]) {
+            case 'a':
+                break;
+            case 'b':
+                alloc = 1;
+                load = 0;
+                break;
+            case 'n':
+                load = 0;
+                break;
+            case 's':
+                shared = 1;
+                /*@fallthrough@*/
+            case 'd':
+                datasect = 1;
+                load = 1;
+                readonly = 0;
+            case 'x':
+                code = 1;
+                load = 1;
+                break;
+            case 'r':
+                datasect = 1;
+                load = 1;
+                readonly = 1;
+                break;
+            case 'w':
+                readonly = 0;
+                break;
+            default:
+                yasm_warn_set(YASM_WARN_GENERAL,
+                              N_("unrecognized section attribute: `%c'"),
+                              s[i]);
+        }
+    }
+
+    if (code)
+        data->flags = COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ;
+    else if (datasect)
+        data->flags = COFF_STYP_DATA | COFF_STYP_READ | COFF_STYP_WRITE;
+    else if (readonly)
+        data->flags = COFF_STYP_DATA | COFF_STYP_READ;
+    else if (load)
+        data->flags = COFF_STYP_TEXT;
+    else if (alloc)
+        data->flags = COFF_STYP_BSS;
+
+    if (shared)
+        data->flags |= COFF_STYP_SHARED;
+
+    data->gasflags = 1;
+    return 0;
+}
+
 static /*@observer@*/ /*@null@*/ yasm_section *
 coff_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams,
                             /*@unused@*/ /*@null@*/
@@ -1273,79 +1357,99 @@ coff_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams,
                             unsigned long line)
 {
     yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
-    yasm_valparam *vp = yasm_vps_first(valparams);
+    yasm_valparam *vp;
     yasm_section *retval;
     int isnew;
     int iscode = 0;
-    unsigned long flags;
-    unsigned long flags2 = 0;
-    int flags_override = 0;
-    char *sectname;
+    int flags_override;
+    const char *sectname;
+    char *realname;
     int resonly = 0;
     unsigned long align = 0;
     coff_section_data *csd;
 
-    static const struct {
-        const char *name;
-        unsigned long stdflags; /* if 0, win32 only qualifier */
-        unsigned long win32flags;
-        unsigned long flags2;
-        /* Mode: 0 => clear specified bits
-         *       1 => set specified bits
-         *       2 => clear all bits, then set specified bits
-         */
-        int mode;
-    } flagquals[] = {
-        { "code", COFF_STYP_TEXT, COFF_STYP_EXECUTE | COFF_STYP_READ, 0, 2 },
-        { "text", COFF_STYP_TEXT, COFF_STYP_EXECUTE | COFF_STYP_READ, 0, 2 },
-        { "data", COFF_STYP_DATA, COFF_STYP_READ | COFF_STYP_WRITE, 0, 2 },
-        { "bss", COFF_STYP_BSS, COFF_STYP_READ | COFF_STYP_WRITE, 0, 2 },
-        { "info", COFF_STYP_INFO, COFF_STYP_DISCARD | COFF_STYP_READ, 0, 2 },
-        { "discard", 0, COFF_STYP_DISCARD, 0, 1 },
-        { "nodiscard", 0, COFF_STYP_DISCARD, 0, 0 },
-        { "cache", 0, COFF_STYP_NOCACHE, 0, 0 },
-        { "nocache", 0, COFF_STYP_NOCACHE, 0, 1 },
-        { "page", 0, COFF_STYP_NOPAGE, 0, 0 },
-        { "nopage", 0, COFF_STYP_NOPAGE, 0, 1 },
-        { "share", 0, COFF_STYP_SHARED, 0, 1 },
-        { "noshare", 0, COFF_STYP_SHARED, 0, 0 },
-        { "execute", 0, COFF_STYP_EXECUTE, 0, 1 },
-        { "noexecute", 0, COFF_STYP_EXECUTE, 0, 0 },
-        { "read", 0, COFF_STYP_READ, 0, 1 },
-        { "noread", 0, COFF_STYP_READ, 0, 0 },
-        { "write", 0, COFF_STYP_WRITE, 0, 1 },
-        { "nowrite", 0, COFF_STYP_WRITE, 0, 0 },
-        { "base", 0, 0, COFF_FLAG_NOBASE, 0 },
-        { "nobase", 0, 0, COFF_FLAG_NOBASE, 1 },
+    struct coff_section_switch_data data;
+
+    static const yasm_dir_help help[] = {
+        { "code", 0, yasm_dir_helper_flag_set,
+          offsetof(struct coff_section_switch_data, flags),
+          COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ },
+        { "text", 0, yasm_dir_helper_flag_set,
+          offsetof(struct coff_section_switch_data, flags),
+          COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ },
+        { "data", 0, yasm_dir_helper_flag_set,
+          offsetof(struct coff_section_switch_data, flags),
+          COFF_STYP_DATA | COFF_STYP_READ | COFF_STYP_WRITE },
+        { "rdata", 0, yasm_dir_helper_flag_set,
+          offsetof(struct coff_section_switch_data, flags),
+          COFF_STYP_DATA | COFF_STYP_READ },
+        { "bss", 0, yasm_dir_helper_flag_set,
+          offsetof(struct coff_section_switch_data, flags),
+          COFF_STYP_BSS | COFF_STYP_READ | COFF_STYP_WRITE },
+        { "info", 0, yasm_dir_helper_flag_set,
+          offsetof(struct coff_section_switch_data, flags),
+          COFF_STYP_INFO | COFF_STYP_DISCARD | COFF_STYP_READ },
+        { "gasflags", 1, coff_helper_gasflags, 0, 0 },
+        /* Win32 only below this point */
+        { "discard", 0, yasm_dir_helper_flag_or,
+          offsetof(struct coff_section_switch_data, flags), COFF_STYP_DISCARD},
+        { "nodiscard", 0, yasm_dir_helper_flag_and,
+          offsetof(struct coff_section_switch_data, flags), COFF_STYP_DISCARD},
+        { "cache", 0, yasm_dir_helper_flag_and,
+          offsetof(struct coff_section_switch_data, flags), COFF_STYP_NOCACHE},
+        { "nocache", 0, yasm_dir_helper_flag_or,
+          offsetof(struct coff_section_switch_data, flags), COFF_STYP_NOCACHE},
+        { "page", 0, yasm_dir_helper_flag_and,
+          offsetof(struct coff_section_switch_data, flags), COFF_STYP_NOPAGE },
+        { "nopage", 0, yasm_dir_helper_flag_or,
+          offsetof(struct coff_section_switch_data, flags), COFF_STYP_NOPAGE },
+        { "share", 0, yasm_dir_helper_flag_or,
+          offsetof(struct coff_section_switch_data, flags), COFF_STYP_SHARED },
+        { "noshare", 0, yasm_dir_helper_flag_and,
+          offsetof(struct coff_section_switch_data, flags), COFF_STYP_SHARED },
+        { "execute", 0, yasm_dir_helper_flag_or,
+          offsetof(struct coff_section_switch_data, flags), COFF_STYP_EXECUTE},
+        { "noexecute", 0, yasm_dir_helper_flag_and,
+          offsetof(struct coff_section_switch_data, flags), COFF_STYP_EXECUTE},
+        { "read", 0, yasm_dir_helper_flag_or,
+          offsetof(struct coff_section_switch_data, flags), COFF_STYP_READ },
+        { "noread", 0, yasm_dir_helper_flag_and,
+          offsetof(struct coff_section_switch_data, flags), COFF_STYP_READ },
+        { "write", 0, yasm_dir_helper_flag_or,
+          offsetof(struct coff_section_switch_data, flags), COFF_STYP_WRITE },
+        { "nowrite", 0, yasm_dir_helper_flag_and,
+          offsetof(struct coff_section_switch_data, flags), COFF_STYP_WRITE },
+        { "base", 0, yasm_dir_helper_flag_and,
+          offsetof(struct coff_section_switch_data, flags2), COFF_FLAG_NOBASE},
+        { "nobase", 0, yasm_dir_helper_flag_or,
+          offsetof(struct coff_section_switch_data, flags2), COFF_FLAG_NOBASE},
+        { "align", 1, yasm_dir_helper_intn,
+          offsetof(struct coff_section_switch_data, align_intn), 0 }
     };
 
-    if (!vp || vp->param || !vp->val)
+    vp = yasm_vps_first(valparams);
+    sectname = yasm_vp_string(vp);
+    if (!sectname)
         return NULL;
+    vp = yasm_vps_next(vp);
 
-    sectname = vp->val;
-    if (strlen(sectname) > 8 && !objfmt_coff->win32) {
-        /* win32 format supports >8 character section names in object
-         * files via "/nnnn" (where nnnn is decimal offset into string table),
-         * so only warn for regular COFF.
-         */
-        yasm_warn_set(YASM_WARN_GENERAL,
-            N_("COFF section names limited to 8 characters: truncating"));
-        sectname[8] = '\0';
-    }
+    data.isdefault = 0;
+    data.gasflags = 0;
+    data.flags = 0;
+    data.flags2 = 0;
+    data.align_intn = NULL;
 
     if (strcmp(sectname, ".data") == 0) {
-        flags = COFF_STYP_DATA;
+        data.flags = COFF_STYP_DATA | COFF_STYP_READ | COFF_STYP_WRITE;
         if (objfmt_coff->win32) {
-            flags |= COFF_STYP_READ | COFF_STYP_WRITE;
             if (objfmt_coff->machine == COFF_MACHINE_AMD64)
                 align = 16;
             else
                 align = 4;
         }
     } else if (strcmp(sectname, ".bss") == 0) {
-        flags = COFF_STYP_BSS;
+        data.flags = COFF_STYP_BSS | COFF_STYP_READ | COFF_STYP_WRITE;
         if (objfmt_coff->win32) {
-            flags |= COFF_STYP_READ | COFF_STYP_WRITE;
             if (objfmt_coff->machine == COFF_MACHINE_AMD64)
                 align = 16;
             else
@@ -1353,215 +1457,101 @@ coff_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams,
         }
         resonly = 1;
     } else if (strcmp(sectname, ".text") == 0) {
-        flags = COFF_STYP_TEXT;
-        if (objfmt_coff->win32) {
-            flags |= COFF_STYP_EXECUTE | COFF_STYP_READ;
+        data.flags = COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ;
+        if (objfmt_coff->win32)
             align = 16;
-        }
-        iscode = 1;
     } else if (strcmp(sectname, ".rdata") == 0
                || strncmp(sectname, ".rodata", 7) == 0
                || strncmp(sectname, ".rdata$", 7) == 0) {
-        flags = COFF_STYP_DATA;
-        if (objfmt_coff->win32) {
-            flags |= COFF_STYP_READ;
+        data.flags = COFF_STYP_DATA | COFF_STYP_READ;
+        if (objfmt_coff->win32)
             align = 8;
-        else
+        else
             yasm_warn_set(YASM_WARN_GENERAL,
                 N_("Standard COFF does not support read-only data sections"));
     } else if (strcmp(sectname, ".drectve") == 0) {
-        flags = COFF_STYP_INFO;
+        data.flags = COFF_STYP_INFO;
         if (objfmt_coff->win32)
-            flags |= COFF_STYP_DISCARD | COFF_STYP_READ;
+            data.flags |= COFF_STYP_DISCARD | COFF_STYP_READ;
     } else if (objfmt_coff->win64 && strcmp(sectname, ".pdata") == 0) {
-        flags = COFF_STYP_DATA | COFF_STYP_READ;
+        data.flags = COFF_STYP_DATA | COFF_STYP_READ;
         align = 4;
-        flags2 = COFF_FLAG_NOBASE;
+        data.flags2 = COFF_FLAG_NOBASE;
     } else if (objfmt_coff->win64 && strcmp(sectname, ".xdata") == 0) {
-        flags = COFF_STYP_DATA | COFF_STYP_READ;
+        data.flags = COFF_STYP_DATA | COFF_STYP_READ;
         align = 8;
     } else if (strcmp(sectname, ".comment") == 0) {
-        flags = COFF_STYP_INFO;
-        if (objfmt_coff->win32)
-            flags |= COFF_STYP_DISCARD | COFF_STYP_READ;
+        data.flags = COFF_STYP_INFO | COFF_STYP_DISCARD | COFF_STYP_READ;
     } else if (yasm__strncasecmp(sectname, ".debug", 6)==0) {
-        flags = COFF_STYP_DATA;
-        if (objfmt_coff->win32)
-            flags |= COFF_STYP_DISCARD|COFF_STYP_READ;
+        data.flags = COFF_STYP_DATA | COFF_STYP_DISCARD | COFF_STYP_READ;
         align = 1;
     } else {
-        /* Default to code */
-        flags = COFF_STYP_TEXT;
-        if (objfmt_coff->win32)
-            flags |= COFF_STYP_EXECUTE | COFF_STYP_READ;
-        iscode = 1;
+        /* Default to code, but set a flag so if we get gasflags we can
+         * change it (NASM and GAS have different defaults).
+         */
+        data.isdefault = 1;
+        data.flags = COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ;
     }
 
-    while ((vp = yasm_vps_next(vp))) {
-        size_t i;
-        int match, win32warn;
-
-        win32warn = 0;
-
-        if (!vp->val) {
-            yasm_warn_set(YASM_WARN_GENERAL,
-                          N_("Unrecognized numeric qualifier"));
-            continue;
-        }
+    flags_override = yasm_dir_helper(object, vp, line, help,
+                                     objfmt_coff->win32 ? NELEMS(help) : 7,
+                                     &data, yasm_dir_helper_valparam_warn);
+    if (flags_override < 0)
+        return NULL;    /* error occurred */
 
-        match = 0;
-        for (i=0; i<NELEMS(flagquals) && !match; i++) {
-            if (yasm__strcasecmp(vp->val, flagquals[i].name) == 0) {
-                if (!objfmt_coff->win32 && flagquals[i].stdflags == 0)
-                    win32warn = 1;
-                else switch (flagquals[i].mode) {
-                    case 0:
-                        flags &= ~flagquals[i].stdflags;
-                        flags2 &= ~flagquals[i].flags2;
-                        if (objfmt_coff->win32)
-                            flags &= ~flagquals[i].win32flags;
-                        if (flagquals[i].win32flags & COFF_STYP_EXECUTE)
-                            iscode = 0;
-                        break;
-                    case 1:
-                        flags |= flagquals[i].stdflags;
-                        flags2 |= flagquals[i].flags2;
-                        if (objfmt_coff->win32)
-                            flags |= flagquals[i].win32flags;
-                        if (flagquals[i].win32flags & COFF_STYP_EXECUTE)
-                            iscode = 1;
-                        break;
-                    case 2:
-                        flags &= ~COFF_STYP_STD_MASK;
-                        flags |= flagquals[i].stdflags;
-                        flags2 = flagquals[i].flags2;
-                        if (objfmt_coff->win32) {
-                            flags &= ~COFF_STYP_WIN32_MASK;
-                            flags |= flagquals[i].win32flags;
-                        }
-                        if (flagquals[i].win32flags & COFF_STYP_EXECUTE)
-                            iscode = 1;
-                        break;
-                }
-                flags_override = 1;
-                match = 1;
-            }
-        }
+    if (data.flags & COFF_STYP_EXECUTE)
+        iscode = 1;
 
-        if (match)
-            ;
-        else if (yasm__strncasecmp(vp->val, "gas_", 4) == 0) {
-            /* GAS-style flags */
-            int alloc = 0, load = 0, readonly = 0, code = 0, data = 0;
-            int shared = 0;
-            iscode = 0;
-            for (i=4; i<strlen(vp->val); i++) {
-                switch (vp->val[i]) {
-                    case 'a':
-                        break;
-                    case 'b':
-                        alloc = 1;
-                        load = 0;
-                        break;
-                    case 'n':
-                        load = 0;
-                        break;
-                    case 's':
-                        shared = 1;
-                        /*@fallthrough@*/
-                    case 'd':
-                        data = 1;
-                        load = 1;
-                        readonly = 0;
-                    case 'x':
-                        code = 1;
-                        load = 1;
-                        break;
-                    case 'r':
-                        data = 1;
-                        load = 1;
-                        readonly = 1;
-                        break;
-                    case 'w':
-                        readonly = 0;
-                        break;
-                    default:
-                        yasm_warn_set(YASM_WARN_GENERAL,
-                                      N_("unrecognized section attribute: `%c'"),
-                                      vp->val[i]);
-                }
-            }
-            if (code) {
-                flags = COFF_STYP_TEXT;
-                if (objfmt_coff->win32)
-                    flags |= COFF_STYP_EXECUTE | COFF_STYP_READ;
-                iscode = 1;
-            } else if (data) {
-                flags = COFF_STYP_DATA;
-                if (objfmt_coff->win32)
-                    flags |= COFF_STYP_READ | COFF_STYP_WRITE;
-            } else if (readonly) {
-                flags = COFF_STYP_DATA;
-                if (objfmt_coff->win32)
-                    flags |= COFF_STYP_READ;
-            } else if (load)
-                flags = COFF_STYP_TEXT;
-            else if (alloc)
-                flags = COFF_STYP_BSS;
-            if (shared && objfmt_coff->win32)
-                flags |= COFF_STYP_SHARED;
-        } else if (yasm__strcasecmp(vp->val, "align") == 0 && vp->param) {
-            if (objfmt_coff->win32) {
-                /*@dependent@*/ /*@null@*/ const yasm_intnum *align_expr;
-                align_expr = yasm_expr_get_intnum(&vp->param, 0);
-                if (!align_expr) {
-                    yasm_error_set(YASM_ERROR_VALUE,
-                                   N_("argument to `%s' is not an integer"),
-                                   vp->val);
-                    return NULL;
-                }
-                align = yasm_intnum_get_uint(align_expr);
+    if (!objfmt_coff->win32)
+        data.flags &= ~COFF_STYP_WIN32_MASK;
 
-                /* Alignments must be a power of two. */
-                if (!is_exp2(align)) {
-                    yasm_error_set(YASM_ERROR_VALUE,
-                                   N_("argument to `%s' is not a power of two"),
-                                   vp->val);
-                    return NULL;
-                }
+    if (data.align_intn) {
+        align = yasm_intnum_get_uint(data.align_intn);
+        yasm_intnum_destroy(data.align_intn);
 
-                /* Check to see if alignment is supported size */
-                if (align > 8192) {
-                    yasm_error_set(YASM_ERROR_VALUE,
-                        N_("Win32 does not support alignments > 8192"));
-                    return NULL;
-                }
+        /* Alignments must be a power of two. */
+        if (!is_exp2(align)) {
+            yasm_error_set(YASM_ERROR_VALUE,
+                           N_("argument to `%s' is not a power of two"),
+                           "align");
+            return NULL;
+        }
 
-            } else
-                win32warn = 1;
-        } else
-            yasm_warn_set(YASM_WARN_GENERAL, N_("Unrecognized qualifier `%s'"),
-                          vp->val);
+        /* Check to see if alignment is supported size */
+        if (align > 8192) {
+            yasm_error_set(YASM_ERROR_VALUE,
+                N_("Win32 does not support alignments > 8192"));
+            return NULL;
+        }
+    }
 
-        if (win32warn)
-            yasm_warn_set(YASM_WARN_GENERAL,
-                N_("Standard COFF does not support qualifier `%s'"), vp->val);
+    realname = yasm__xstrdup(sectname);
+    if (strlen(sectname) > 8 && !objfmt_coff->win32) {
+        /* win32 format supports >8 character section names in object
+         * files via "/nnnn" (where nnnn is decimal offset into string table),
+         * so only warn for regular COFF.
+         */
+        yasm_warn_set(YASM_WARN_GENERAL,
+            N_("COFF section names limited to 8 characters: truncating"));
+        realname[8] = '\0';
     }
 
-    retval = yasm_object_get_general(object, sectname, 0, align, iscode,
+    retval = yasm_object_get_general(object, realname, 0, align, iscode,
                                      resonly, &isnew, line);
 
     if (isnew)
-        csd = coff_objfmt_init_new_section(object, retval, sectname, line);
+        csd = coff_objfmt_init_new_section(object, retval, realname, line);
     else
         csd = yasm_section_get_data(retval, &coff_section_data_cb);
 
+    yasm_xfree(realname);
+
     if (isnew || yasm_section_is_default(retval)) {
         yasm_section_set_default(retval, 0);
-        csd->flags = flags;
-        csd->flags2 = flags2;
+        csd->flags = data.flags;
+        csd->flags2 = data.flags2;
         yasm_section_set_align(retval, align, line);
-    } else if (flags_override)
+    } else if (flags_override && !data.gasflags)
         yasm_warn_set(YASM_WARN_GENERAL,
                       N_("section flags ignored on section redeclaration"));
     return retval;
@@ -1624,14 +1614,16 @@ dir_export(yasm_object *object, yasm_valparamhead *valparams,
            yasm_valparamhead *objext_valparams, unsigned long line)
 {
     yasm_valparam *vp;
+    /*@null@*/ const char *symname;
     int isnew;
     yasm_section *sect;
     yasm_datavalhead dvs;
 
     /* Reference exported symbol (to generate error if not declared) */
     vp = yasm_vps_first(valparams);
-    if (vp->val)
-        yasm_symtab_use(object->symtab, vp->val, line);
+    symname = yasm_vp_id(vp);
+    if (symname)
+        yasm_symtab_use(object->symtab, symname, line);
     else {
         yasm_error_set(YASM_ERROR_SYNTAX,
                        N_("argument to EXPORT must be symbol name"));
@@ -1654,8 +1646,8 @@ dir_export(yasm_object *object, yasm_valparamhead *valparams,
     yasm_dvs_initialize(&dvs);
     yasm_dvs_append(&dvs, yasm_dv_create_string(yasm__xstrdup("-export:"),
                                                 strlen("-export:")));
-    yasm_dvs_append(&dvs, yasm_dv_create_string(yasm__xstrdup(vp->val),
-                                                strlen(vp->val)));
+    yasm_dvs_append(&dvs, yasm_dv_create_string(yasm__xstrdup(symname),
+                                                strlen(symname)));
     yasm_dvs_append(&dvs, yasm_dv_create_string(yasm__xstrdup(" "), 1));
     yasm_section_bcs_append(sect, yasm_bc_create_data(&dvs, 1, 0, NULL, line));
 }
@@ -1689,7 +1681,7 @@ dir_ident(yasm_object *object, yasm_valparamhead *valparams,
         sectname = ".comment";
     }
     yasm_vps_initialize(&sect_vps);
-    vp2 = yasm_vp_create(yasm__xstrdup(sectname), NULL);
+    vp2 = yasm_vp_create_id(NULL, yasm__xstrdup(sectname), '\0');
     yasm_vps_append(&sect_vps, vp2);
     comment = coff_objfmt_section_switch(object, &sect_vps, NULL, line);
     yasm_vps_delete(&sect_vps);
@@ -1708,8 +1700,15 @@ dir_ident(yasm_object *object, yasm_valparamhead *valparams,
 
     yasm_dvs_initialize(&dvs);
     do {
-        yasm_dvs_append(&dvs, yasm_dv_create_string(vp->val, strlen(vp->val)));
-        vp->val = NULL;
+        const char *s = yasm_vp_string(vp);
+        if (!s) {
+            yasm_error_set(YASM_ERROR_VALUE,
+                           N_(".comment requires string parameters"));
+            yasm_dvs_delete(&dvs);
+            return;
+        }
+        yasm_dvs_append(&dvs,
+                        yasm_dv_create_string(yasm__xstrdup(s), strlen(s)));
     } while ((vp = yasm_vps_next(vp)));
 
     yasm_section_bcs_append(comment,
@@ -1722,6 +1721,8 @@ dir_proc_frame(yasm_object *object, /*@null@*/ yasm_valparamhead *valparams,
 {
     yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
     yasm_valparam *vp = yasm_vps_first(valparams);
+    const char *name = yasm_vp_id(vp);
+
     if (objfmt_coff->proc_frame) {
         yasm_error_set_xref(objfmt_coff->proc_frame,
                             N_("previous procedure started here"));
@@ -1729,23 +1730,17 @@ dir_proc_frame(yasm_object *object, /*@null@*/ yasm_valparamhead *valparams,
             N_("nested procedures not supported (didn't use [ENDPROC_FRAME]?)"));
         return;
     }
-    if (!vp || !vp->val) {
-        yasm_error_set(YASM_ERROR_SYNTAX,
-                       N_("[%s] requires a procedure symbol name"),
-                       "PROC_FRAME");
-        return;
-    }
     objfmt_coff->proc_frame = line;
     objfmt_coff->done_prolog = 0;
     objfmt_coff->unwind = yasm_win64__uwinfo_create();
-    objfmt_coff->unwind->proc = yasm_symtab_use(object->symtab, vp->val, line);
+    objfmt_coff->unwind->proc = yasm_symtab_use(object->symtab, name, line);
 
     /* Optional error handler */
     vp = yasm_vps_next(vp);
-    if (!vp || !vp->val)
+    if (!vp || !(name = yasm_vp_id(vp)))
         return;
     objfmt_coff->unwind->ehandler =
-        yasm_symtab_use(object->symtab, vp->val, line);
+        yasm_symtab_use(object->symtab, name, line);
 }
 
 static int
@@ -1796,7 +1791,8 @@ dir_pushreg(yasm_object *object, yasm_valparamhead *valparams,
     if (!procframe_checkstate(objfmt_coff, "PUSHREG"))
         return;
 
-    if (!vp || !vp->param || !(reg = yasm_expr_get_reg(&vp->param, 0))) {
+    if (vp->type != YASM_PARAM_EXPR ||
+        !(reg = yasm_expr_get_reg(&vp->param.e, 0))) {
         yasm_error_set(YASM_ERROR_SYNTAX,
                        N_("[%s] requires a register as the first parameter"),
                        "PUSHREG");
@@ -1826,7 +1822,8 @@ dir_setframe(yasm_object *object, yasm_valparamhead *valparams,
     if (!procframe_checkstate(objfmt_coff, "SETFRAME"))
         return;
 
-    if (!vp || !vp->param || !(reg = yasm_expr_get_reg(&vp->param, 0))) {
+    if (vp->type != YASM_PARAM_EXPR ||
+        !(reg = yasm_expr_get_reg(&vp->param.e, 0))) {
         yasm_error_set(YASM_ERROR_SYNTAX,
                        N_("[%s] requires a register as the first parameter"),
                        "SETFRAME");
@@ -1834,10 +1831,8 @@ dir_setframe(yasm_object *object, yasm_valparamhead *valparams,
     }
 
     vp = yasm_vps_next(vp);
-    if (vp && vp->param) {
-        off = vp->param;
-        vp->param = NULL;
-    }
+    if (vp)
+        off = yasm_vp_expr(vp, object->symtab, line);
 
     /* Set the frame fields in the unwind info */
     objfmt_coff->unwind->framereg = (unsigned long)(*reg);
@@ -1859,18 +1854,14 @@ dir_allocstack(yasm_object *object, yasm_valparamhead *valparams,
 {
     yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
     yasm_valparam *vp = yasm_vps_first(valparams);
+    /*@null@*/ /*@only@*/ yasm_expr *size;
     coff_unwind_code *code;
 
     if (!procframe_checkstate(objfmt_coff, "ALLOCSTACK"))
         return;
 
-    /* Transform ID to expression if needed */
-    if (vp && vp->val && !vp->param) {
-        vp->param = yasm_expr_create_ident(yasm_expr_sym(
-            yasm_symtab_use(object->symtab, vp->val, line)), line);
-    }
-
-    if (!vp || !vp->param) {
+    size = yasm_vp_expr(vp, object->symtab, line);
+    if (!size) {
         yasm_error_set(YASM_ERROR_SYNTAX, N_("[%s] requires a size"),
                        "ALLOCSTACK");
         return;
@@ -1884,8 +1875,7 @@ dir_allocstack(yasm_object *object, yasm_valparamhead *valparams,
     code->loc = get_curpos(object, "ALLOCSTACK", line);
     code->opcode = UWOP_ALLOC_SMALL;
     code->info = 0;
-    yasm_value_initialize(&code->off, vp->param, 7);
-    vp->param = NULL;
+    yasm_value_initialize(&code->off, size, 7);
     SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link);
 }
 
@@ -1897,11 +1887,13 @@ dir_save_common(yasm_object *object, yasm_valparamhead *valparams,
     yasm_valparam *vp = yasm_vps_first(valparams);
     coff_unwind_code *code;
     const uintptr_t *reg;
+    /*@only@*/ /*@null@*/ yasm_expr *offset;
 
     if (!procframe_checkstate(objfmt_coff, name))
         return;
 
-    if (!vp || !vp->param || !(reg = yasm_expr_get_reg(&vp->param, 0))) {
+    if (vp->type != YASM_PARAM_EXPR ||
+        !(reg = yasm_expr_get_reg(&vp->param.e, 0))) {
         yasm_error_set(YASM_ERROR_SYNTAX,
                        N_("[%s] requires a register as the first parameter"),
                        name);
@@ -1909,14 +1901,8 @@ dir_save_common(yasm_object *object, yasm_valparamhead *valparams,
     }
 
     vp = yasm_vps_next(vp);
-
-    /* Transform ID to expression if needed */
-    if (vp && vp->val && !vp->param) {
-        vp->param = yasm_expr_create_ident(yasm_expr_sym(
-            yasm_symtab_use(object->symtab, vp->val, line)), line);
-    }
-
-    if (!vp || !vp->param) {
+    offset = yasm_vp_expr(vp, object->symtab, line);
+    if (!offset) {
         yasm_error_set(YASM_ERROR_SYNTAX,
                        N_("[%s] requires an offset as the second parameter"),
                        name);
@@ -1931,8 +1917,7 @@ dir_save_common(yasm_object *object, yasm_valparamhead *valparams,
     code->loc = get_curpos(object, name, line);
     code->opcode = op;
     code->info = (unsigned int)(*reg & 0xF);
-    yasm_value_initialize(&code->off, vp->param, 16);
-    vp->param = NULL;
+    yasm_value_initialize(&code->off, offset, 16);
     SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link);
 }
 
@@ -1968,7 +1953,7 @@ dir_pushframe(yasm_object *object, /*@null@*/ yasm_valparamhead *valparams,
     code->proc = objfmt_coff->unwind->proc;
     code->loc = get_curpos(object, "PUSHFRAME", line);
     code->opcode = UWOP_PUSH_MACHFRAME;
-    code->info = vp && (vp->val || vp->param);
+    code->info = vp != NULL;
     yasm_value_initialize(&code->off, NULL, 0);
     SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link);
 }
@@ -2141,7 +2126,7 @@ static const yasm_directive win64_objfmt_directives[] = {
     { "ident",          "nasm", dir_ident,      YASM_DIR_ANY },
     { ".export",        "gas",  dir_export,     YASM_DIR_ID_REQUIRED },
     { "export",         "nasm", dir_export,     YASM_DIR_ID_REQUIRED },
-    { "proc_frame",     "nasm", dir_proc_frame, YASM_DIR_ANY },
+    { "proc_frame",     "nasm", dir_proc_frame, YASM_DIR_ID_REQUIRED },
     { "pushreg",        "nasm", dir_pushreg,    YASM_DIR_ARG_REQUIRED },
     { "setframe",       "nasm", dir_setframe,   YASM_DIR_ARG_REQUIRED },
     { "allocstack",     "nasm", dir_allocstack, YASM_DIR_ARG_REQUIRED },
index b2e8d4510fa3cf251e444db05ea0b2f1842c9537..e1aad7adffbbd2aa04c33584c5e3291187969a5a 100644 (file)
@@ -126,22 +126,22 @@ dbg_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams,
     yasm_vps_print(objext_valparams, objfmt_dbg->dbgfile);
     fprintf(objfmt_dbg->dbgfile, ", %lu), returning ", line);
 
-    if ((vp = yasm_vps_first(valparams)) && !vp->param && vp->val != NULL) {
-        retval = yasm_object_get_general(object, vp->val,
-            yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(200)),
-                                   line), 0, 0, 0, &isnew, line);
-        if (isnew) {
-            fprintf(objfmt_dbg->dbgfile, "(new) ");
-            yasm_symtab_define_label(object->symtab, vp->val,
-                yasm_section_bcs_first(retval), 1, line);
-        }
-        yasm_section_set_default(retval, 0);
-        fprintf(objfmt_dbg->dbgfile, "\"%s\" section\n", vp->val);
-        return retval;
-    } else {
+    vp = yasm_vps_first(valparams);
+    if (!yasm_vp_string(vp)) {
         fprintf(objfmt_dbg->dbgfile, "NULL\n");
         return NULL;
     }
+    retval = yasm_object_get_general(object, yasm_vp_string(vp),
+        yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(200)),
+                               line), 0, 0, 0, &isnew, line);
+    if (isnew) {
+        fprintf(objfmt_dbg->dbgfile, "(new) ");
+        yasm_symtab_define_label(object->symtab, vp->val,
+                                 yasm_section_bcs_first(retval), 1, line);
+    }
+    yasm_section_set_default(retval, 0);
+    fprintf(objfmt_dbg->dbgfile, "\"%s\" section\n", vp->val);
+    return retval;
 }
 
 /* Define valid debug formats to use with this object format */
index 84a27e3bddd521758667e220f30f4f8246e7b6ac..d53e24308681fa43061fe354b8434c55d14d0b76 100644 (file)
@@ -74,6 +74,7 @@ typedef struct {
 } elf_objfmt_output_info;
 
 typedef struct {
+    yasm_object *object;
     yasm_objfmt_elf *objfmt_elf;
     yasm_errwarns *errwarns;
     int local_names;
@@ -119,9 +120,10 @@ build_extern(yasm_objfmt_elf *objfmt_elf, yasm_symrec *sym)
     if (objext_valparams) {
         yasm_valparam *vp = yasm_vps_first(objext_valparams);
         for (; vp; vp = yasm_vps_next(vp)) {
-            if (vp->val)
+            if (yasm_vp_string(vp))
                 yasm_error_set(YASM_ERROR_TYPE,
-                               N_("unrecognized symbol type `%s'"), vp->val);
+                               N_("unrecognized symbol type `%s'"),
+                               yasm_vp_string(vp));
         }
     }
 
@@ -129,60 +131,84 @@ build_extern(yasm_objfmt_elf *objfmt_elf, yasm_symrec *sym)
                                     STV_DEFAULT, NULL, NULL);
 }
 
+struct elf_build_global_data {
+    yasm_expr *size;
+    unsigned long type; /* elf_symbol_type */
+    elf_symbol_vis vis;
+    unsigned int vis_overrides;
+};
+
+static int
+elf_global_helper_valparam(void *obj, yasm_valparam *vp, unsigned long line,
+                           void *d)
+
+{
+    struct elf_build_global_data *data = (struct elf_build_global_data *)d;
+    const char *s;
+
+    if (!vp->val && (s = yasm_vp_id(vp))) {
+        yasm_error_set(YASM_ERROR_TYPE, N_("unrecognized symbol type `%s'"),
+                       s);
+        return -1;
+    } else if (!vp->val && vp->type == YASM_PARAM_EXPR && !data->size) {
+        data->size = yasm_expr_copy(vp->param.e);
+        return 0;
+    } else
+        return yasm_dir_helper_valparam_warn(obj, vp, line, d);
+}
+
+static int
+elf_global_helper_vis(void *obj, yasm_valparam *vp, unsigned long line,
+                      void *d, uintptr_t vis)
+{
+    struct elf_build_global_data *data = (struct elf_build_global_data *)d;
+    data->vis = vis;
+    data->vis_overrides++;
+    return 0;
+}
+
+
 static elf_symtab_entry *
 build_global(yasm_objfmt_elf *objfmt_elf, yasm_symrec *sym)
 {
     yasm_valparamhead *objext_valparams =
         yasm_symrec_get_objext_valparams(sym);
-    elf_symbol_type type = 0;
-    yasm_expr *size = NULL;
-    elf_symbol_vis vis = STV_DEFAULT;
-    unsigned int vis_overrides = 0;
 
-    if (objext_valparams) {
-        yasm_valparam *vp = yasm_vps_first(objext_valparams);
-        for (; vp; vp = yasm_vps_next(vp))
-        {
-            if (vp->val) {
-                if (yasm__strcasecmp(vp->val, "function") == 0)
-                    type = STT_FUNC;
-                else if (yasm__strcasecmp(vp->val, "data") == 0 ||
-                         yasm__strcasecmp(vp->val, "object") == 0)
-                    type = STT_OBJECT;
-                else if (yasm__strcasecmp(vp->val, "internal") == 0) {
-                    vis = STV_INTERNAL;
-                    vis_overrides++;
-                }
-                else if (yasm__strcasecmp(vp->val, "hidden") == 0) {
-                    vis = STV_HIDDEN;
-                    vis_overrides++;
-                }
-                else if (yasm__strcasecmp(vp->val, "protected") == 0) {
-                    vis = STV_PROTECTED;
-                    vis_overrides++;
-                }
-                else
-                    yasm_error_set(YASM_ERROR_TYPE,
-                                   N_("unrecognized symbol type `%s'"),
-                                   vp->val);
-            }
-            else if (vp->param && !size) {
-                size = vp->param;
-                vp->param = NULL;       /* to avoid double-free of expr */
-            }
-        }
-        if (vis_overrides > 1) {
-            yasm_warn_set(YASM_WARN_GENERAL,
-                N_("More than one symbol visibility provided; using last"));
-        }
+    struct elf_build_global_data data;
+
+    static const yasm_dir_help help[] = {
+        { "function", 0, yasm_dir_helper_flag_set,
+          offsetof(struct elf_build_global_data, type), STT_FUNC },
+        { "data", 0, yasm_dir_helper_flag_set,
+          offsetof(struct elf_build_global_data, type), STT_OBJECT },
+        { "object", 0, yasm_dir_helper_flag_set,
+          offsetof(struct elf_build_global_data, type), STT_OBJECT },
+        { "internal", 0, elf_global_helper_vis, 0, STV_INTERNAL },
+        { "hidden", 0, elf_global_helper_vis, 0, STV_HIDDEN },
+        { "protected", 0, elf_global_helper_vis, 0, STV_PROTECTED },
+    };
+
+    data.size = NULL;
+    data.type = 0;
+    data.vis = STV_DEFAULT;
+    data.vis_overrides = 0;
+
+    if (objext_valparams)
+        yasm_dir_helper(sym, yasm_vps_first(objext_valparams),
+                        yasm_symrec_get_decl_line(sym), help, NELEMS(help),
+                        &data, elf_global_helper_valparam);
+
+    if (data.vis_overrides > 1) {
+        yasm_warn_set(YASM_WARN_GENERAL,
+            N_("More than one symbol visibility provided; using last"));
     }
 
     return elf_objfmt_symtab_append(objfmt_elf, sym, SHN_UNDEF, STB_GLOBAL,
-                                    type, vis, size, NULL);
+                                    data.type, data.vis, data.size, NULL);
 }
 
 static /*@null@*/ elf_symtab_entry *
-build_common(yasm_objfmt_elf *objfmt_elf, yasm_symrec *sym)
+build_common(yasm_objfmt_elf *objfmt_elf, yasm_symrec *sym, yasm_object *object)
 {
     yasm_expr **size = yasm_symrec_get_common_size(sym);
     yasm_valparamhead *objext_valparams =
@@ -192,16 +218,21 @@ build_common(yasm_objfmt_elf *objfmt_elf, yasm_symrec *sym)
     if (objext_valparams) {
         yasm_valparam *vp = yasm_vps_first(objext_valparams);
         for (; vp; vp = yasm_vps_next(vp)) {
-            if (!vp->val && vp->param) {
-                /*@dependent@*/ /*@null@*/ const yasm_intnum *align_expr;
+            if (!vp->val) {
+                /*@only@*/ /*@null@*/ yasm_expr *align_expr;
+                /*@dependent@*/ /*@null@*/ const yasm_intnum *align_intn;
 
-                align_expr = yasm_expr_get_intnum(&vp->param, 0);
-                if (!align_expr) {
+                if (!(align_expr = yasm_vp_expr(vp, object->symtab,
+                                                yasm_symrec_get_def_line(sym)))
+                    || !(align_intn = yasm_expr_get_intnum(&align_expr, 0))) {
                     yasm_error_set(YASM_ERROR_VALUE,
                         N_("alignment constraint is not an integer"));
+                    if (align_expr)
+                        yasm_expr_destroy(align_expr);
                     return NULL;
                 }
-                addralign = yasm_intnum_get_uint(align_expr);
+                addralign = yasm_intnum_get_uint(align_intn);
+                yasm_expr_destroy(align_expr);
 
                 /* Alignments must be a power of two. */
                 if (!is_exp2(addralign)) {
@@ -209,7 +240,7 @@ build_common(yasm_objfmt_elf *objfmt_elf, yasm_symrec *sym)
                         N_("alignment constraint is not a power of two"));
                     return NULL;
                 }
-            } else if (vp->val)
+            } else
                 yasm_warn_set(YASM_WARN_GENERAL,
                               N_("Unrecognized qualifier `%s'"), vp->val);
         }
@@ -240,7 +271,7 @@ elf_objfmt_build_symtab(yasm_symrec *sym, /*@null@*/ void *d)
     }
 
     if (vis & YASM_SYM_COMMON) {
-        entry = build_common(info->objfmt_elf, sym);
+        entry = build_common(info->objfmt_elf, sym, info->object);
         yasm_errwarn_propagate(info->errwarns,
                                yasm_symrec_get_decl_line(sym));
         /* If the COMMON variable was actually defined, fall through. */
@@ -764,6 +795,7 @@ elf_objfmt_output(yasm_object *object, FILE *f, int all_syms,
 
     /* add all (local) syms to symtab because relocation needs a symtab index
      * if all_syms, register them by name.  if not, use strtab entry 0 */
+    buildsym_info.object = object;
     buildsym_info.objfmt_elf = objfmt_elf;
     buildsym_info.errwarns = errwarns;
     buildsym_info.local_names = all_syms;
@@ -921,186 +953,193 @@ elf_objfmt_add_default_section(yasm_object *object)
     return retval;
 }
 
+struct elf_section_switch_data {
+    /*@only@*/ /*@null@*/ yasm_intnum *align_intn;
+    unsigned long flags;
+    unsigned long type;
+    int gasflags;
+};
+
+/* GAS-style flags */
+static int
+elf_helper_gasflags(void *obj, yasm_valparam *vp, unsigned long line, void *d,
+                    /*@unused@*/ uintptr_t arg)
+{
+    struct elf_section_switch_data *data = (struct elf_section_switch_data *)d;
+    const char *s = yasm_vp_string(vp);
+    size_t i;
+
+    if (!s) {
+        yasm_error_set(YASM_ERROR_VALUE,
+                       N_("non-string section attribute"));
+        return -1;
+    }
+
+    data->flags = 0;
+    for (i=0; i<strlen(s); i++) {
+        switch (s[i]) {
+            case 'a':
+                data->flags |= SHF_ALLOC;
+                break;
+            case 'w':
+                data->flags |= SHF_WRITE;
+                break;
+            case 'x':
+                data->flags |= SHF_EXECINSTR;
+                break;
+            case 'M':
+                data->flags |= SHF_MERGE;
+                break;
+            case 'S':
+                data->flags |= SHF_STRINGS;
+                break;
+            case 'G':
+                data->flags |= SHF_GROUP;
+                break;
+            case 'T':
+                data->flags |= SHF_TLS;
+                break;
+            default:
+                yasm_warn_set(YASM_WARN_GENERAL,
+                              N_("unrecognized section attribute: `%c'"),
+                              s[i]);
+        }
+    }
+
+    data->gasflags = 1;
+    return 0;
+}
+
 static /*@observer@*/ /*@null@*/ yasm_section *
 elf_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams,
                           /*@null@*/ yasm_valparamhead *objext_valparams,
                           unsigned long line)
 {
-    yasm_valparam *vp = yasm_vps_first(valparams);
+    yasm_valparam *vp;
     yasm_section *retval;
     int isnew;
-    unsigned long type = SHT_PROGBITS;
-    unsigned long flags = SHF_ALLOC;
     unsigned long align = 4;
     int flags_override = 0;
-    char *sectname;
+    const char *sectname;
     int resonly = 0;
-    static const struct {
-        const char *name;
-        unsigned long flags;
-    } flagquals[] = {
-        { "alloc",      SHF_ALLOC },
-        { "exec",       SHF_EXECINSTR },
-        { "write",      SHF_WRITE },
-        /*{ "progbits", SHT_PROGBITS },*/
-        /*{ "align",    0 } */
+
+    struct elf_section_switch_data data;
+
+    static const yasm_dir_help help[] = {
+        { "alloc", 0, yasm_dir_helper_flag_or,
+          offsetof(struct elf_section_switch_data, flags), SHF_ALLOC },
+        { "exec", 0, yasm_dir_helper_flag_or,
+          offsetof(struct elf_section_switch_data, flags), SHF_EXECINSTR },
+        { "write", 0, yasm_dir_helper_flag_or,
+          offsetof(struct elf_section_switch_data, flags), SHF_WRITE },
+        { "progbits", 0, yasm_dir_helper_flag_set,
+          offsetof(struct elf_section_switch_data, type), SHT_PROGBITS },
+        { "noalloc", 0, yasm_dir_helper_flag_and,
+          offsetof(struct elf_section_switch_data, flags), SHF_ALLOC },
+        { "noexec", 0, yasm_dir_helper_flag_and,
+          offsetof(struct elf_section_switch_data, flags), SHF_EXECINSTR },
+        { "nowrite",  0, yasm_dir_helper_flag_and,
+          offsetof(struct elf_section_switch_data, flags), SHF_WRITE },
+        { "noprogbits", 0, yasm_dir_helper_flag_set,
+          offsetof(struct elf_section_switch_data, type), SHT_NOBITS },
+        { "nobits", 0, yasm_dir_helper_flag_set,
+          offsetof(struct elf_section_switch_data, type), SHT_NOBITS },
+        { "gasflags", 1, elf_helper_gasflags, 0, 0 },
+        { "align", 1, yasm_dir_helper_intn,
+          offsetof(struct elf_section_switch_data, align_intn), 0 }
     };
+    /*@only@*/ /*@null@*/ yasm_expr *merge_expr = NULL;
     /*@dependent@*/ /*@null@*/ const yasm_intnum *merge_intn = NULL;
     elf_secthead *esd;
 
-    if (!vp || vp->param || !vp->val)
-        return NULL;
+    data.align_intn = NULL;
+    data.flags = SHF_ALLOC;
+    data.type = SHT_PROGBITS;
+    data.gasflags = 0;
 
-    sectname = vp->val;
+    vp = yasm_vps_first(valparams);
+    sectname = yasm_vp_string(vp);
+    if (!sectname)
+        return NULL;
+    vp = yasm_vps_next(vp);
 
     if (strcmp(sectname, ".bss") == 0) {
-        type = SHT_NOBITS;
-        flags = SHF_ALLOC + SHF_WRITE;
+        data.type = SHT_NOBITS;
+        data.flags = SHF_ALLOC + SHF_WRITE;
         resonly = 1;
     } else if (strcmp(sectname, ".data") == 0) {
-        type = SHT_PROGBITS;
-        flags = SHF_ALLOC + SHF_WRITE;
+        data.type = SHT_PROGBITS;
+        data.flags = SHF_ALLOC + SHF_WRITE;
     } else if (strcmp(sectname, ".rodata") == 0) {
-        type = SHT_PROGBITS;
-        flags = SHF_ALLOC;
+        data.type = SHT_PROGBITS;
+        data.flags = SHF_ALLOC;
     } else if (strcmp(sectname, ".text") == 0) {
         align = 16;
-        type = SHT_PROGBITS;
-        flags = SHF_ALLOC + SHF_EXECINSTR;
+        data.type = SHT_PROGBITS;
+        data.flags = SHF_ALLOC + SHF_EXECINSTR;
     } else if (strcmp(sectname, ".comment") == 0) {
         align = 0;
-        type = SHT_PROGBITS;
-        flags = 0;
+        data.type = SHT_PROGBITS;
+        data.flags = 0;
     } else {
         /* Default to code */
         align = 1;
     }
 
-    while ((vp = yasm_vps_next(vp))) {
-        size_t i;
-        int match;
-
-        if (!vp->val) {
-            yasm_warn_set(YASM_WARN_GENERAL,
-                          N_("Unrecognized numeric qualifier"));
-            continue;
-        }
-
-        match = 0;
-        for (i=0; i<NELEMS(flagquals) && !match; i++) {
-            if (yasm__strcasecmp(vp->val, flagquals[i].name) == 0) {
-                flags_override = 1;
-                match = 1;
-                flags |= flagquals[i].flags;
-            }
-            else if (yasm__strcasecmp(vp->val+2, flagquals[i].name) == 0
-                  && yasm__strncasecmp(vp->val, "no", 2) == 0) {
-                flags &= ~flagquals[i].flags;
-                flags_override = 1;
-                match = 1;
-            }
-        }
-
-        if (match)
-            ;
-        else if (yasm__strncasecmp(vp->val, "gas_", 4) == 0) {
-            /* GAS-style flags */
-            flags = 0;
-            for (i=4; i<strlen(vp->val); i++) {
-                switch (vp->val[i]) {
-                    case 'a':
-                        flags |= SHF_ALLOC;
-                        break;
-                    case 'w':
-                        flags |= SHF_WRITE;
-                        break;
-                    case 'x':
-                        flags |= SHF_EXECINSTR;
-                        break;
-                    case 'M':
-                        flags |= SHF_MERGE;
-                        break;
-                    case 'S':
-                        flags |= SHF_STRINGS;
-                        break;
-                    case 'G':
-                        flags |= SHF_GROUP;
-                        break;
-                    case 'T':
-                        flags |= SHF_TLS;
-                        break;
-                    default:
-                        yasm_warn_set(YASM_WARN_GENERAL,
-                                      N_("unrecognized section attribute: `%c'"),
-                                      vp->val[i]);
-                }
-            }
-        } else if (yasm__strcasecmp(vp->val, "progbits") == 0) {
-            type |= SHT_PROGBITS;
-        }
-        else if (yasm__strcasecmp(vp->val, "noprogbits") == 0 ||
-                 yasm__strcasecmp(vp->val, "nobits") == 0) {
-            type &= ~SHT_PROGBITS;
-            type |= SHT_NOBITS;
+    flags_override = yasm_dir_helper(object, vp, line, help, NELEMS(help),
+                                     &data, yasm_dir_helper_valparam_warn);
+    if (flags_override < 0)
+        return NULL;    /* error occurred */
+
+    if (data.align_intn) {
+        align = yasm_intnum_get_uint(data.align_intn);
+        yasm_intnum_destroy(data.align_intn);
+
+        /* Alignments must be a power of two. */
+        if (!is_exp2(align)) {
+            yasm_error_set(YASM_ERROR_VALUE,
+                           N_("argument to `%s' is not a power of two"),
+                           "align");
+            return NULL;
         }
-        else if (yasm__strcasecmp(vp->val, "align") == 0 && vp->param) {
-            /*@dependent@*/ /*@null@*/ const yasm_intnum *align_expr;
-
-            align_expr = yasm_expr_get_intnum(&vp->param, 0);
-            if (!align_expr) {
-                yasm_error_set(YASM_ERROR_VALUE,
-                               N_("argument to `%s' is not an integer"),
-                               vp->val);
-                return NULL;
-            }
-            align = yasm_intnum_get_uint(align_expr);
-
-            /* Alignments must be a power of two. */
-            if (!is_exp2(align)) {
-                yasm_error_set(YASM_ERROR_VALUE,
-                               N_("argument to `%s' is not a power of two"),
-                               vp->val);
-                return NULL;
-            }
-        } else
-            yasm_warn_set(YASM_WARN_GENERAL,
-                          N_("Unrecognized qualifier `%s'"), vp->val);
     }
-        /* Handle merge entity size */
-        if (flags & SHF_MERGE) {
-            if (objext_valparams && (vp = yasm_vps_first(objext_valparams))
-                && vp->param) {
-
-                merge_intn = yasm_expr_get_intnum(&vp->param, 0);
-                if (!merge_intn)
-                    yasm_warn_set(YASM_WARN_GENERAL,
-                                  N_("invalid merge entity size"));
-            } else {
+
+    /* Handle merge entity size */
+    if (data.flags & SHF_MERGE) {
+        if (objext_valparams && (vp = yasm_vps_first(objext_valparams))
+            && !vp->val) {
+            if (!(merge_expr = yasm_vp_expr(vp, object->symtab, line)) ||
+                !(merge_intn = yasm_expr_get_intnum(&merge_expr, 0)))
                 yasm_warn_set(YASM_WARN_GENERAL,
-                              N_("entity size for SHF_MERGE not specified"));
-                flags &= ~SHF_MERGE;
-            }
+                              N_("invalid merge entity size"));
+        } else {
+            yasm_warn_set(YASM_WARN_GENERAL,
+                          N_("entity size for SHF_MERGE not specified"));
+            data.flags &= ~SHF_MERGE;
         }
+    }
 
     retval = yasm_object_get_general(object, sectname, 0, align,
-                                     (flags & SHF_EXECINSTR) != 0, resonly,
-                                     &isnew, line);
+                                     (data.flags & SHF_EXECINSTR) != 0,
+                                     resonly, &isnew, line);
 
     if (isnew)
-        esd = elf_objfmt_init_new_section(object, retval, sectname, type,
-                                          flags, line);
+        esd = elf_objfmt_init_new_section(object, retval, sectname, data.type,
+                                          data.flags, line);
     else
         esd = yasm_section_get_data(retval, &elf_section_data);
 
     if (isnew || yasm_section_is_default(retval)) {
         yasm_section_set_default(retval, 0);
-        elf_secthead_set_typeflags(esd, type, flags);
+        elf_secthead_set_typeflags(esd, data.type, data.flags);
         if (merge_intn)
             elf_secthead_set_entsize(esd, yasm_intnum_get_uint(merge_intn));
         yasm_section_set_align(retval, align, line);
-    } else if (flags_override)
+    } else if (flags_override && !data.gasflags)
         yasm_warn_set(YASM_WARN_GENERAL,
                       N_("section flags ignored on section redeclaration"));
+    if (merge_expr)
+        yasm_expr_destroy(merge_expr);
     return retval;
 }
 
@@ -1108,12 +1147,13 @@ static void
 dir_type(yasm_object *object, yasm_valparamhead *valparams,
          yasm_valparamhead *objext_valparams, unsigned long line)
 {
-    yasm_valparam *vp = yasm_vps_first(valparams);
     yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)object->objfmt;
-    char *symname = vp->val;
+    yasm_valparam *vp = yasm_vps_first(valparams);
+    const char *symname = yasm_vp_id(vp);
     /* Get symbol elf data */
     yasm_symrec *sym = yasm_symtab_use(object->symtab, symname, line);
     elf_symtab_entry *entry = yasm_symrec_get_data(sym, &elf_symrec_data);
+    /*@null@*/ const char *type;
 
     /* Create entry if necessary */
     if (!entry) {
@@ -1122,16 +1162,16 @@ dir_type(yasm_object *object, yasm_valparamhead *valparams,
         yasm_symrec_add_data(sym, &elf_symrec_data, entry);
     }
 
-    /* Pull new type from val */
+    /* Pull new type from param */
     vp = yasm_vps_next(vp);
-    if (vp && vp->val) {
-        if (yasm__strcasecmp(vp->val, "function") == 0)
+    if (vp && !vp->val && (type = yasm_vp_id(vp))) {
+        if (yasm__strcasecmp(type, "function") == 0)
             elf_sym_set_type(entry, STT_FUNC);
-        else if (yasm__strcasecmp(vp->val, "object") == 0)
+        else if (yasm__strcasecmp(type, "object") == 0)
             elf_sym_set_type(entry, STT_OBJECT);
         else
             yasm_warn_set(YASM_WARN_GENERAL,
-                          N_("unrecognized symbol type `%s'"), vp->val);
+                          N_("unrecognized symbol type `%s'"), type);
     } else
         yasm_error_set(YASM_ERROR_SYNTAX, N_("no type specified"));
 }
@@ -1140,12 +1180,13 @@ static void
 dir_size(yasm_object *object, yasm_valparamhead *valparams,
          yasm_valparamhead *objext_valparams, unsigned long line)
 {
-    yasm_valparam *vp = yasm_vps_first(valparams);
     yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)object->objfmt;
-    char *symname = vp->val;
+    yasm_valparam *vp = yasm_vps_first(valparams);
+    const char *symname = yasm_vp_id(vp);
     /* Get symbol elf data */
     yasm_symrec *sym = yasm_symtab_use(object->symtab, symname, line);
     elf_symtab_entry *entry = yasm_symrec_get_data(sym, &elf_symrec_data);
+    /*@only@*/ /*@null@*/ yasm_expr *size;
 
     /* Create entry if necessary */
     if (!entry) {
@@ -1154,14 +1195,10 @@ dir_size(yasm_object *object, yasm_valparamhead *valparams,
         yasm_symrec_add_data(sym, &elf_symrec_data, entry);
     }
 
-    /* Pull new size from either param (expr) or val */
+    /* Pull new size from param */
     vp = yasm_vps_next(vp);
-    if (vp && vp->param) {
-        elf_sym_set_size(entry, vp->param);
-        vp->param = NULL;
-    } else if (vp && vp->val)
-        elf_sym_set_size(entry, yasm_expr_create_ident(yasm_expr_sym(
-            yasm_symtab_use(object->symtab, vp->val, line)), line));
+    if (vp && !vp->val && (size = yasm_vp_expr(vp, object->symtab, line)))
+        elf_sym_set_size(entry, size);
     else
         yasm_error_set(YASM_ERROR_SYNTAX, N_("no size specified"));
 }
@@ -1170,9 +1207,9 @@ static void
 dir_weak(yasm_object *object, yasm_valparamhead *valparams,
          yasm_valparamhead *objext_valparams, unsigned long line)
 {
-    yasm_valparam *vp = yasm_vps_first(valparams);
     yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)object->objfmt;
-    char *symname = vp->val;
+    yasm_valparam *vp = yasm_vps_first(valparams);
+    const char *symname = yasm_vp_id(vp);
     yasm_symrec *sym = yasm_symtab_declare(object->symtab, symname,
                                            YASM_SYM_GLOBAL, line);
     elf_objfmt_symtab_append(objfmt_elf, sym, SHN_UNDEF, STB_WEAK, 0,
@@ -1186,12 +1223,19 @@ dir_ident(yasm_object *object, yasm_valparamhead *valparams,
     yasm_valparamhead sect_vps;
     yasm_datavalhead dvs;
     yasm_section *comment;
-    yasm_valparam *vp = yasm_vps_first(valparams);
+    yasm_valparam *vp;
     yasm_valparam *vp2;
 
+    /* Accept, but do nothing with empty ident */
+    if (!valparams)
+        return;
+    vp = yasm_vps_first(valparams);
+    if (!vp)
+        return;
+
     /* Put ident data into .comment section */
     yasm_vps_initialize(&sect_vps);
-    vp2 = yasm_vp_create(yasm__xstrdup(".comment"), NULL);
+    vp2 = yasm_vp_create_string(NULL, yasm__xstrdup(".comment"));
     yasm_vps_append(&sect_vps, vp2);
     comment = elf_objfmt_section_switch(object, &sect_vps, NULL, line);
     yasm_vps_delete(&sect_vps);
@@ -1210,8 +1254,15 @@ dir_ident(yasm_object *object, yasm_valparamhead *valparams,
 
     yasm_dvs_initialize(&dvs);
     do {
-        yasm_dvs_append(&dvs, yasm_dv_create_string(vp->val, strlen(vp->val)));
-        vp->val = NULL;
+        const char *s = yasm_vp_string(vp);
+        if (!s) {
+            yasm_error_set(YASM_ERROR_VALUE,
+                           N_(".comment requires string parameters"));
+            yasm_dvs_delete(&dvs);
+            return;
+        }
+        yasm_dvs_append(&dvs,
+                        yasm_dv_create_string(yasm__xstrdup(s), strlen(s)));
     } while ((vp = yasm_vps_next(vp)));
 
     yasm_section_bcs_append(comment,
@@ -1230,11 +1281,11 @@ static const yasm_directive elf_objfmt_directives[] = {
     { ".type",          "gas",  dir_type,       YASM_DIR_ID_REQUIRED },
     { ".size",          "gas",  dir_size,       YASM_DIR_ID_REQUIRED },
     { ".weak",          "gas",  dir_weak,       YASM_DIR_ID_REQUIRED },
-    { ".ident",         "gas",  dir_ident,      YASM_DIR_ARG_REQUIRED },
+    { ".ident",         "gas",  dir_ident,      YASM_DIR_ANY },
     { "type",           "nasm", dir_type,       YASM_DIR_ID_REQUIRED },
     { "size",           "nasm", dir_size,       YASM_DIR_ID_REQUIRED },
     { "weak",           "nasm", dir_weak,       YASM_DIR_ID_REQUIRED },
-    { "ident",          "nasm", dir_ident,      YASM_DIR_ARG_REQUIRED },
+    { "ident",          "nasm", dir_ident,      YASM_DIR_ANY },
     { NULL, NULL, NULL, 0 }
 };
 
index 70f463ba526dbcc26d422fed7e5c766943b0ea80..109c3f912a80d005b30390ec577659aca011eddc 100644 (file)
@@ -1288,14 +1288,14 @@ macho_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams,
                             yasm_valparamhead *objext_valparams,
                             unsigned long line)
 {
-    yasm_valparam *vp = yasm_vps_first(valparams);
+    yasm_valparam *vp;
     yasm_section *retval;
     int isnew;
     const char *f_segname, *f_sectname;
     unsigned long flags;
     unsigned long align;
     int flags_override = 0;
-    char *sectname;
+    const char *sectname;
     int resonly = 0;
     macho_section_data *msd;
     size_t i;
@@ -1365,10 +1365,22 @@ macho_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams,
             S_ATTR_NO_DEAD_STRIP, 0}
     };
 
-    if (!vp || vp->param || !vp->val)
-        return NULL;
+    struct macho_section_switch_data {
+        /*@only@*/ /*@null@*/ yasm_intnum *align_intn;
+    } data;
+
+    static const yasm_dir_help help[] = {
+        { "align", 1, yasm_dir_helper_intn,
+          offsetof(struct macho_section_switch_data, align_intn), 0 }
+    };
 
-    sectname = vp->val;
+    data.align_intn = NULL;
+
+    vp = yasm_vps_first(valparams);
+    sectname = yasm_vp_string(vp);
+    if (!sectname)
+        return NULL;
+    vp = yasm_vps_next(vp);
 
     /* translate .text,.data,.bss to __text,__data,__bss... */
     for (i=0; i<NELEMS(section_name_translation); i++) {
@@ -1387,43 +1399,29 @@ macho_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams,
     flags = section_name_translation[i].flags;
     align = section_name_translation[i].align;
 
-    while ((vp = yasm_vps_next(vp))) {
-        if (!vp->val) {
-            yasm_warn_set(YASM_WARN_GENERAL,
-                          N_("Unrecognized numeric qualifier"));
-            continue;
+    flags_override = yasm_dir_helper(object, vp, line, help, NELEMS(help),
+                                     &data, yasm_dir_helper_valparam_warn);
+    if (flags_override < 0)
+        return NULL;    /* error occurred */
+
+    if (data.align_intn) {
+        align = yasm_intnum_get_uint(data.align_intn);
+        yasm_intnum_destroy(data.align_intn);
+
+        /* Alignments must be a power of two. */
+        if (!is_exp2(align)) {
+            yasm_error_set(YASM_ERROR_VALUE,
+                           N_("argument to `%s' is not a power of two"),
+                           vp->val);
+            return NULL;
         }
 
-        flags_override = 1;
-        if (yasm__strcasecmp(vp->val, "align") == 0 && vp->param) {
-            /*@dependent@ *//*@null@ */ const yasm_intnum *align_expr;
-
-            align_expr = yasm_expr_get_intnum(&vp->param, 0);
-            if (!align_expr) {
-                yasm_error_set(YASM_ERROR_VALUE,
-                               N_("argument to `%s' is not an integer"),
-                               vp->val);
-                return NULL;
-            }
-            align = yasm_intnum_get_uint(align_expr);
-
-            /* Alignments must be a power of two. */
-            if (!is_exp2(align)) {
-                yasm_error_set(YASM_ERROR_VALUE,
-                               N_("argument to `%s' is not a power of two"),
-                               vp->val);
-                return NULL;
-            }
-
-            /* Check to see if alignment is supported size */
-            if (align > 16384) {
-                yasm_error_set(YASM_ERROR_VALUE,
-                    N_("macho implementation does not support alignments > 16384"));
-                return NULL;
-            }
-        } else
-            yasm_warn_set(YASM_WARN_GENERAL,
-                          N_("Unrecognized qualifier `%s'"), vp->val);
+        /* Check to see if alignment is supported size */
+        if (align > 16384) {
+            yasm_error_set(YASM_ERROR_VALUE,
+                N_("macho implementation does not support alignments > 16384"));
+            return NULL;
+        }
     }
 
     retval = yasm_object_get_general(object, sectname, 0, align, 1, resonly,
index aa583a5bf23b37576da5ae9123065224b7e0ca67..124f256079f8967681b6f4baa4b6a052e0dd748b 100644 (file)
@@ -463,68 +463,57 @@ rdf_objfmt_output_section_file(yasm_section *sect, /*@null@*/ void *d)
     return 0;
 }
 
+#define FLAG_EXT    0x1000
+#define FLAG_GLOB   0x2000
+#define FLAG_SET    0x4000
+#define FLAG_CLR    0x8000
+#define FLAG_MASK   0x0fff
+
+static int
+rdf_helper_flag(void *obj, yasm_valparam *vp, unsigned long line, void *d,
+                uintptr_t flag)
+{
+    yasm_symrec *sym = (yasm_symrec *)obj;
+    yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
+    unsigned int *flags = (unsigned int *)d;
+
+    if (((vis & YASM_SYM_GLOBAL) && (flag & FLAG_GLOB)) ||
+        ((vis & YASM_SYM_EXTERN) && (flag & FLAG_EXT))) {
+        if (flag & FLAG_SET)
+            *flags |= flag & FLAG_MASK;
+        else if (flag & FLAG_CLR)
+            *flags &= ~(flag & FLAG_MASK);
+    }
+    return 0;
+}
+
 static unsigned int
 rdf_parse_flags(yasm_symrec *sym)
 {
-    yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
     /*@dependent@*/ /*@null@*/ yasm_valparamhead *objext_valparams =
         yasm_symrec_get_objext_valparams(sym);
-    yasm_valparam *vp;
     unsigned int flags = 0;
 
-    static const struct {
-        enum {
-            FLAG_EXT = 1,
-            FLAG_GLOB = 2
-        } type;
-        enum {
-            FLAG_SET = 1,
-            FLAG_CLR = 2
-        } action;
-        const char *name;
-        unsigned int flags;
-    } flagtbl[] = {
-        { FLAG_EXT|FLAG_GLOB, FLAG_SET, "data", SYM_DATA },
-        { FLAG_EXT|FLAG_GLOB, FLAG_SET, "object", SYM_DATA },
-        { FLAG_EXT|FLAG_GLOB, FLAG_SET, "proc", SYM_FUNCTION },
-        { FLAG_EXT|FLAG_GLOB, FLAG_SET, "function", SYM_FUNCTION },
-        { FLAG_EXT, FLAG_SET, "import", SYM_IMPORT },
-        { FLAG_GLOB, FLAG_SET, "export", SYM_GLOBAL },
-        { FLAG_EXT, FLAG_SET, "far", SYM_FAR },
-        { FLAG_EXT, FLAG_CLR, "near", SYM_FAR },
+    static const yasm_dir_help help[] = {
+        { "data", 0, rdf_helper_flag, 0,
+          FLAG_EXT|FLAG_GLOB|FLAG_SET|SYM_DATA },
+        { "object", 0, rdf_helper_flag, 0,
+          FLAG_EXT|FLAG_GLOB|FLAG_SET|SYM_DATA },
+        { "proc", 0, rdf_helper_flag, 0,
+          FLAG_EXT|FLAG_GLOB|FLAG_SET|SYM_FUNCTION },
+        { "function", 0, rdf_helper_flag, 0,
+          FLAG_EXT|FLAG_GLOB|FLAG_SET|SYM_FUNCTION },
+        { "import", 0, rdf_helper_flag, 0, FLAG_EXT|FLAG_SET|SYM_IMPORT },
+        { "export", 0, rdf_helper_flag, 0, FLAG_GLOB|FLAG_SET|SYM_GLOBAL },
+        { "far", 0, rdf_helper_flag, 0, FLAG_EXT|FLAG_SET|SYM_FAR },
+        { "near", 0, rdf_helper_flag, 0, FLAG_EXT|FLAG_CLR|SYM_FAR }
     };
 
     if (!objext_valparams)
         return 0;
 
-    vp = yasm_vps_first(objext_valparams);
-    for (; vp; vp = yasm_vps_next(vp)) {
-        size_t i;
-        int match;
-
-        if (!vp->val) {
-            yasm_warn_set(YASM_WARN_GENERAL,
-                          N_("Unrecognized numeric qualifier"));
-            continue;
-        }
-
-        match = 0;
-        for (i=0; i<NELEMS(flagtbl) && !match; i++) {
-            if ((((vis & YASM_SYM_GLOBAL) && (flagtbl[i].type & FLAG_GLOB)) ||
-                 ((vis & YASM_SYM_EXTERN) && (flagtbl[i].type & FLAG_EXT))) &&
-                yasm__strcasecmp(vp->val, flagtbl[i].name) == 0) {
-                if (flagtbl[i].action == FLAG_SET)
-                    flags |= flagtbl[i].flags;
-                else if (flagtbl[i].action == FLAG_CLR)
-                    flags &= ~flagtbl[i].flags;
-                match = 1;
-            }
-        }
-
-        if (!match)
-            yasm_warn_set(YASM_WARN_GENERAL, N_("Unrecognized qualifier `%s'"),
-                          vp->val);
-    }
+    yasm_dir_helper(sym, yasm_vps_first(objext_valparams), 0, help,
+                    NELEMS(help), &flags, yasm_dir_helper_valparam_warn);
 
     return flags;
 }
@@ -620,16 +609,25 @@ rdf_objfmt_output_sym(yasm_symrec *sym, /*@null@*/ void *d)
             if (objext_valparams) {
                 yasm_valparam *vp = yasm_vps_first(objext_valparams);
                 for (; vp; vp = yasm_vps_next(vp)) {
-                    if (!vp->val && vp->param) {
-                        /*@null@*/ const yasm_intnum *align_expr;
-
-                        align_expr = yasm_expr_get_intnum(&vp->param, 0);
-                        if (!align_expr) {
+                    if (!vp->val) {
+                        /*@only@*/ /*@null@*/ yasm_expr *align_expr;
+                        /*@dependent@*/ /*@null@*/
+                        const yasm_intnum *align_intn;
+
+                        if (!(align_expr = yasm_vp_expr(vp,
+                                info->object->symtab,
+                                yasm_symrec_get_decl_line(sym))) ||
+                            !(align_intn = yasm_expr_get_intnum(&align_expr,
+                                                                0))) {
                             yasm_error_set(YASM_ERROR_VALUE,
-                                N_("alignment constraint is not an integer"));
+                                N_("argument to `%s' is not an integer"),
+                                vp->val);
+                            if (align_expr)
+                                yasm_expr_destroy(align_expr);
                             continue;
                         }
-                        addralign = yasm_intnum_get_uint(align_expr);
+                        addralign = yasm_intnum_get_uint(align_intn);
+                        yasm_expr_destroy(align_expr);
 
                         /* Alignments must be a power of two. */
                         if (!is_exp2(addralign)) {
@@ -637,7 +635,7 @@ rdf_objfmt_output_sym(yasm_symrec *sym, /*@null@*/ void *d)
                                 N_("alignment constraint is not a power of two"));
                             continue;
                         }
-                    } else if (vp->val)
+                    } else
                         yasm_warn_set(YASM_WARN_GENERAL,
                             N_("Unrecognized qualifier `%s'"), vp->val);
                 }
@@ -854,6 +852,32 @@ rdf_objfmt_add_default_section(yasm_object *object)
     return retval;
 }
 
+static int
+rdf_helper_set_type(void *obj, yasm_valparam *vp, unsigned long line,
+                    void *d, uintptr_t newtype)
+{
+    unsigned int *type = (unsigned int *)d;
+    *type = newtype;
+    return 0;
+}
+
+struct rdf_section_switch_data {
+    /*@only@*/ /*@null@*/ yasm_intnum *reserved_intn;
+    unsigned int type;
+};
+
+static int
+rdf_helper_set_reserved(void *obj, yasm_valparam *vp, unsigned long line,
+                        void *d)
+{
+    struct rdf_section_switch_data *data = (struct rdf_section_switch_data *)d;
+
+    if (!vp->val && vp->type == YASM_PARAM_EXPR)
+        return yasm_dir_helper_intn(obj, vp, line, &data->reserved_intn, 0);
+    else
+        return yasm_dir_helper_valparam_warn(obj, vp, line, d);
+}
+
 static /*@observer@*/ /*@null@*/ yasm_section *
 rdf_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams,
                           /*@unused@*/ /*@null@*/
@@ -863,85 +887,70 @@ rdf_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams,
     yasm_valparam *vp = yasm_vps_first(valparams);
     yasm_section *retval;
     int isnew;
-    unsigned int type = 0xffff;
     unsigned int reserved = 0;
     int flags_override = 0;
-    char *sectname;
+    const char *sectname;
     rdf_section_data *rsd;
 
-    static const struct {
-        const char *name;
-        unsigned int type;
-    } typenames[] = {
-        { "bss", RDF_SECT_BSS },
-        { "code", RDF_SECT_CODE },
-        { "text", RDF_SECT_CODE },
-        { "data", RDF_SECT_DATA },
-        { "comment", RDF_SECT_COMMENT },
-        { "lcomment", RDF_SECT_LCOMMENT },
-        { "pcomment", RDF_SECT_PCOMMENT },
-        { "symdebug", RDF_SECT_SYMDEBUG },
-        { "linedebug", RDF_SECT_LINEDEBUG },
+    struct rdf_section_switch_data data;
+
+    static const yasm_dir_help help[] = {
+        { "bss", 0, rdf_helper_set_type,
+          offsetof(struct rdf_section_switch_data, type), RDF_SECT_BSS },
+        { "code", 0, rdf_helper_set_type,
+          offsetof(struct rdf_section_switch_data, type), RDF_SECT_CODE },
+        { "text", 0, rdf_helper_set_type,
+          offsetof(struct rdf_section_switch_data, type), RDF_SECT_CODE },
+        { "data", 0, rdf_helper_set_type,
+          offsetof(struct rdf_section_switch_data, type), RDF_SECT_DATA },
+        { "comment", 0, rdf_helper_set_type,
+          offsetof(struct rdf_section_switch_data, type), RDF_SECT_COMMENT },
+        { "lcomment", 0, rdf_helper_set_type,
+          offsetof(struct rdf_section_switch_data, type), RDF_SECT_LCOMMENT },
+        { "pcomment", 0, rdf_helper_set_type,
+          offsetof(struct rdf_section_switch_data, type), RDF_SECT_PCOMMENT },
+        { "symdebug", 0, rdf_helper_set_type,
+          offsetof(struct rdf_section_switch_data, type), RDF_SECT_SYMDEBUG },
+        { "linedebug", 0, rdf_helper_set_type,
+          offsetof(struct rdf_section_switch_data, type), RDF_SECT_LINEDEBUG },
+        { "reserved", 1, yasm_dir_helper_intn,
+          offsetof(struct rdf_section_switch_data, reserved_intn), 0 }
     };
 
-    if (!vp || vp->param || !vp->val)
-        return NULL;
+    data.reserved_intn = NULL;
+    data.type = 0xffff;
 
-    sectname = vp->val;
+    vp = yasm_vps_first(valparams);
+    sectname = yasm_vp_string(vp);
+    if (!sectname)
+        return NULL;
+    vp = yasm_vps_next(vp);
 
     if (strcmp(sectname, ".text") == 0)
-        type = RDF_SECT_CODE;
+        data.type = RDF_SECT_CODE;
     else if (strcmp(sectname, ".data") == 0)
-        type = RDF_SECT_DATA;
+        data.type = RDF_SECT_DATA;
     else if (strcmp(sectname, ".bss") == 0)
-        type = RDF_SECT_BSS;
-
-    /* Look for section type */
-    if ((vp = yasm_vps_next(vp))) {
-        size_t i;
-        int match;
-        if (vp->val) {
-            match = 0;
-            for (i=0; i<NELEMS(typenames) && !match; i++) {
-                if (yasm__strcasecmp(vp->val, typenames[i].name) == 0) {
-                    type = typenames[i].type;
-                    flags_override = 1;
-                    match = 1;
-                }
-            }
-            if (!match)
-                yasm_warn_set(YASM_WARN_GENERAL,
-                              N_("Unrecognized RDF segment type `%s'"),
-                              vp->val);
-        } else
-            yasm_warn_set(YASM_WARN_GENERAL,
-                          N_("Unrecognized numeric qualifier"));
-    }
+        data.type = RDF_SECT_BSS;
+
+    flags_override = yasm_dir_helper(object, vp, line, help, NELEMS(help),
+                                     &data, rdf_helper_set_reserved);
+    if (flags_override < 0)
+        return NULL;    /* error occurred */
 
-    if (type == 0xffff) {
+    if (data.type == 0xffff) {
         yasm_error_set(YASM_ERROR_VALUE,
                        N_("new segment declared without type code"));
-        type = RDF_SECT_DATA;
+        data.type = RDF_SECT_DATA;
     }
 
-    /* Look for reserved value */
-    if (vp && (vp = yasm_vps_next(vp))) {
-        if (!vp->val && vp->param) {
-            /*@dependent@*/ /*@null@*/ const yasm_intnum *reserved_expr;
-
-            reserved_expr = yasm_expr_get_intnum(&vp->param, 0);
-            if (!reserved_expr)
-                yasm_error_set(YASM_ERROR_VALUE,
-                    N_("reserved value must be numeric"));
-            else
-                reserved = yasm_intnum_get_uint(reserved_expr);
-        } else if (vp->val)
-            yasm_warn_set(YASM_WARN_GENERAL, N_("Unrecognized qualifier `%s'"),
-                          vp->val);
+    if (data.reserved_intn) {
+        reserved = yasm_intnum_get_uint(data.reserved_intn);
+        yasm_intnum_destroy(data.reserved_intn);
     }
 
     retval = yasm_object_get_general(object, sectname, 0, 0, 1,
-                                     type == RDF_SECT_BSS, &isnew, line);
+                                     data.type == RDF_SECT_BSS, &isnew, line);
 
     if (isnew)
         rsd = rdf_objfmt_init_new_section(object, retval, sectname, line);
@@ -950,7 +959,7 @@ rdf_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams,
 
     if (isnew || yasm_section_is_default(retval)) {
         yasm_section_set_default(retval, 0);
-        rsd->type = type;
+        rsd->type = data.type;
         rsd->reserved = reserved;
     } else if (flags_override)
         yasm_warn_set(YASM_WARN_GENERAL,
@@ -1021,8 +1030,7 @@ dir_library(yasm_object *object, yasm_valparamhead *valparams,
             yasm_valparamhead *objext_valparams, unsigned long line)
 {
     yasm_valparam *vp = yasm_vps_first(valparams);
-    rdf_objfmt_add_libmodule(object, vp->val, 1);
-    vp->val = NULL;     /* don't free it */
+    rdf_objfmt_add_libmodule(object, yasm__xstrdup(yasm_vp_string(vp)), 1);
 }
 
 static void
@@ -1030,8 +1038,7 @@ dir_module(yasm_object *object, yasm_valparamhead *valparams,
            yasm_valparamhead *objext_valparams, unsigned long line)
 {
     yasm_valparam *vp = yasm_vps_first(valparams);
-    rdf_objfmt_add_libmodule(object, vp->val, 0);
-    vp->val = NULL;     /* don't free it */
+    rdf_objfmt_add_libmodule(object, yasm__xstrdup(yasm_vp_string(vp)), 0);
 }
 
 /* Define valid debug formats to use with this object format */
@@ -1041,8 +1048,8 @@ static const char *rdf_objfmt_dbgfmt_keywords[] = {
 };
 
 static const yasm_directive rdf_objfmt_directives[] = {
-    { "library",        "nasm", dir_library,    YASM_DIR_ID_REQUIRED },
-    { "module",         "nasm", dir_module,     YASM_DIR_ID_REQUIRED },
+    { "library",        "nasm", dir_library,    YASM_DIR_ARG_REQUIRED },
+    { "module",         "nasm", dir_module,     YASM_DIR_ARG_REQUIRED },
     { NULL, NULL, NULL, 0 }
 };
 
index 1239c4dd7d4aa333147ae137612f89c425efd532..8bf5ea0fc81dd909b252ba23e1c7c4ec4376dad3 100644 (file)
@@ -1,5 +1,5 @@
 module thismodule
-module "$thismodule"
+module $thismodule
 global foo:export
 global bar:export proc
 global bar2:export function
index 4b430e80c6b53dbe27a0633a93a16e4b1a180bd5..7bd402dce34f063ccb47a6f95b938c621e8d949f 100644 (file)
@@ -12,5 +12,9 @@ EXTRA_DIST += modules/objfmts/xdf/tests/xdfother.asm
 EXTRA_DIST += modules/objfmts/xdf/tests/xdfother.hex
 EXTRA_DIST += modules/objfmts/xdf/tests/xdfprotect.asm
 EXTRA_DIST += modules/objfmts/xdf/tests/xdfprotect.hex
+EXTRA_DIST += modules/objfmts/xdf/tests/xdfsect.asm
+EXTRA_DIST += modules/objfmts/xdf/tests/xdfsect.hex
+EXTRA_DIST += modules/objfmts/xdf/tests/xdfsect-err.asm
+EXTRA_DIST += modules/objfmts/xdf/tests/xdfsect-err.errwarn
 EXTRA_DIST += modules/objfmts/xdf/tests/xdfvirtual.asm
 EXTRA_DIST += modules/objfmts/xdf/tests/xdfvirtual.hex
diff --git a/modules/objfmts/xdf/tests/xdfsect-err.asm b/modules/objfmts/xdf/tests/xdfsect-err.asm
new file mode 100644 (file)
index 0000000..cca409a
--- /dev/null
@@ -0,0 +1,18 @@
+[section]
+section 1 use16=5
+section 2 use32=5
+section 3 use64=5
+section 4 bss=5
+section 5 flat=5
+section 6 foo
+section 7 foo=5
+section 8 absolute=foo
+section 9 absolute="foo"
+section 10 absolute
+section 11 virtual=foo
+section 12 virtual="foo"
+section 13 virtual
+section 14 align=foo
+section 15 align="foo"
+section 16 align
+section 17 "bar"
diff --git a/modules/objfmts/xdf/tests/xdfsect-err.errwarn b/modules/objfmts/xdf/tests/xdfsect-err.errwarn
new file mode 100644 (file)
index 0000000..4a9d5b3
--- /dev/null
@@ -0,0 +1,20 @@
+-:1: directive `section' requires an argument
+-:2: warning: Unrecognized qualifier `use16'
+-:3: warning: Unrecognized qualifier `use32'
+-:4: warning: Unrecognized qualifier `use64'
+-:5: warning: Unrecognized qualifier `bss'
+-:6: warning: Unrecognized qualifier `flat'
+-:7: warning: Unrecognized qualifier `foo'
+-:8: warning: Unrecognized qualifier `foo'
+-:9: argument to `absolute' is not an integer
+-:9: undefined symbol `foo' (first use)
+-:9:  (Each undefined symbol is reported only once.)
+-:10: argument to `absolute' is not an integer
+-:11: warning: Unrecognized qualifier `absolute'
+-:12: argument to `virtual' is not an integer
+-:13: argument to `virtual' is not an integer
+-:14: warning: Unrecognized qualifier `virtual'
+-:15: argument to `align' is not an integer
+-:16: argument to `align' is not an integer
+-:17: warning: Unrecognized qualifier `align'
+-:18: warning: Unrecognized string qualifier
diff --git a/modules/objfmts/xdf/tests/xdfsect.asm b/modules/objfmts/xdf/tests/xdfsect.asm
new file mode 100644 (file)
index 0000000..8d20155
--- /dev/null
@@ -0,0 +1,13 @@
+section 1
+section 2 use16
+section 3 use32
+section 4 use64
+section 5 bss
+section 6 flat
+section 7 use16 flat
+section 8 use32 bss
+section 9 use64 absolute=0x5555 flat
+section 10 flat virtual=0x1111 absolute=0x2222
+section 11 use32 align=4
+section 12 use16 absolute=0x1111 virtual=0x2222 align=4 flat bss
+section 13 use16 use32 use64
diff --git a/modules/objfmts/xdf/tests/xdfsect.hex b/modules/objfmts/xdf/tests/xdfsect.hex
new file mode 100644 (file)
index 0000000..4f0c0c1
--- /dev/null
@@ -0,0 +1,836 @@
+22 
+43 
+65 
+87 
+0e 
+00 
+00 
+00 
+0e 
+00 
+00 
+00 
+34 
+03 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+01 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+02 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+10 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+03 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+20 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+04 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+40 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+05 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+04 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+06 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+02 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+07 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+12 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+08 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+24 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+09 
+00 
+00 
+00 
+55 
+55 
+00 
+00 
+00 
+00 
+00 
+00 
+55 
+55 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+43 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+0a 
+00 
+00 
+00 
+22 
+22 
+00 
+00 
+00 
+00 
+00 
+00 
+11 
+11 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+03 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+0b 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+04 
+00 
+20 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+0c 
+00 
+00 
+00 
+11 
+11 
+00 
+00 
+00 
+00 
+00 
+00 
+22 
+22 
+00 
+00 
+00 
+00 
+00 
+00 
+04 
+00 
+17 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+0d 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+40 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+20 
+03 
+00 
+00 
+00 
+00 
+00 
+00 
+01 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+26 
+03 
+00 
+00 
+00 
+00 
+00 
+00 
+02 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+28 
+03 
+00 
+00 
+00 
+00 
+00 
+00 
+03 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+2a 
+03 
+00 
+00 
+00 
+00 
+00 
+00 
+04 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+2c 
+03 
+00 
+00 
+00 
+00 
+00 
+00 
+05 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+2e 
+03 
+00 
+00 
+00 
+00 
+00 
+00 
+06 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+30 
+03 
+00 
+00 
+00 
+00 
+00 
+00 
+07 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+32 
+03 
+00 
+00 
+00 
+00 
+00 
+00 
+08 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+34 
+03 
+00 
+00 
+00 
+00 
+00 
+00 
+09 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+36 
+03 
+00 
+00 
+00 
+00 
+00 
+00 
+0a 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+38 
+03 
+00 
+00 
+00 
+00 
+00 
+00 
+0b 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+3b 
+03 
+00 
+00 
+00 
+00 
+00 
+00 
+0c 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+3e 
+03 
+00 
+00 
+00 
+00 
+00 
+00 
+0d 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+41 
+03 
+00 
+00 
+00 
+00 
+00 
+00 
+2e 
+74 
+65 
+78 
+74 
+00 
+31 
+00 
+32 
+00 
+33 
+00 
+34 
+00 
+35 
+00 
+36 
+00 
+37 
+00 
+38 
+00 
+39 
+00 
+31 
+30 
+00 
+31 
+31 
+00 
+31 
+32 
+00 
+31 
+33 
+00 
index 5c23c4ed0d78af71bc755724f43752a6bbed63e0..84e0e3145926ec55952707a4648b85ee71b049d7 100644 (file)
@@ -645,99 +645,107 @@ xdf_objfmt_add_default_section(yasm_object *object)
     return retval;
 }
 
+static int
+xdf_helper_use(void *obj, yasm_valparam *vp, unsigned long line, void *d,
+               uintptr_t bits)
+{
+    yasm_object *object = (yasm_object *)obj;
+    unsigned long *flags = (unsigned long *)d;
+    *flags &= ~(XDF_SECT_USE_16|XDF_SECT_USE_32|XDF_SECT_USE_64);
+    switch (bits) {
+        case 16: *flags |= XDF_SECT_USE_16; break;
+        case 32: *flags |= XDF_SECT_USE_32; break;
+        case 64: *flags |= XDF_SECT_USE_64; break;
+    };
+    yasm_arch_set_var(object->arch, "mode_bits", bits);
+    return 0;
+}
+
 static /*@observer@*/ /*@null@*/ yasm_section *
 xdf_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams,
                           /*@unused@*/ /*@null@*/
                           yasm_valparamhead *objext_valparams,
                           unsigned long line)
 {
-    yasm_valparam *vp = yasm_vps_first(valparams);
+    yasm_valparam *vp;
     yasm_section *retval;
     int isnew;
-    /*@dependent@*/ /*@null@*/ const yasm_intnum *absaddr = NULL;
-    /*@dependent@*/ /*@null@*/ const yasm_intnum *vaddr = NULL;
-    unsigned long align = 0;
-    unsigned long flags = 0;
     int flags_override = 0;
-    char *sectname;
+    const char *sectname;
     int resonly = 0;
     xdf_section_data *xsd;
+    unsigned long align = 0;
 
-    if (!vp || vp->param || !vp->val)
+    struct xdf_section_switch_data {
+        /*@only@*/ /*@null@*/ yasm_intnum *absaddr;
+        /*@only@*/ /*@null@*/ yasm_intnum *vaddr;
+        /*@only@*/ /*@null@*/ yasm_intnum *align_intn;
+        unsigned long flags;
+    } data;
+
+    static const yasm_dir_help help[] = {
+        { "use16", 0, xdf_helper_use,
+          offsetof(struct xdf_section_switch_data, flags), 16 },
+        { "use32", 0, xdf_helper_use,
+          offsetof(struct xdf_section_switch_data, flags), 32 },
+        { "use64", 0, xdf_helper_use,
+          offsetof(struct xdf_section_switch_data, flags), 64 },
+        { "bss", 0, yasm_dir_helper_flag_or,
+          offsetof(struct xdf_section_switch_data, flags), XDF_SECT_BSS },
+        { "flat", 0, yasm_dir_helper_flag_or,
+          offsetof(struct xdf_section_switch_data, flags), XDF_SECT_FLAT },
+        { "absolute", 1, yasm_dir_helper_intn,
+          offsetof(struct xdf_section_switch_data, absaddr), 0 },
+        { "virtual", 1, yasm_dir_helper_intn,
+          offsetof(struct xdf_section_switch_data, vaddr), 0 },
+        { "align", 1, yasm_dir_helper_intn,
+          offsetof(struct xdf_section_switch_data, align_intn), 0 }
+    };
+
+    data.absaddr = NULL;
+    data.vaddr = NULL;
+    data.align_intn = NULL;
+    data.flags = 0;
+
+    vp = yasm_vps_first(valparams);
+    sectname = yasm_vp_string(vp);
+    if (!sectname)
         return NULL;
-
-    sectname = vp->val;
-
-    while ((vp = yasm_vps_next(vp))) {
-        if (!vp->val) {
-            yasm_warn_set(YASM_WARN_GENERAL,
-                          N_("Unrecognized numeric qualifier"));
-            continue;
+    vp = yasm_vps_next(vp);
+
+    flags_override = yasm_dir_helper(object, vp, line, help, NELEMS(help),
+                                     &data, yasm_dir_helper_valparam_warn);
+    if (flags_override < 0)
+        return NULL;    /* error occurred */
+
+    if (data.absaddr)
+        data.flags |= XDF_SECT_ABSOLUTE;
+    if (data.align_intn) {
+        align = yasm_intnum_get_uint(data.align_intn);
+        yasm_intnum_destroy(data.align_intn);
+
+        /* Alignments must be a power of two. */
+        if (!is_exp2(align)) {
+            yasm_error_set(YASM_ERROR_VALUE,
+                           N_("argument to `%s' is not a power of two"),
+                           "align");
+            if (data.vaddr)
+                yasm_intnum_destroy(data.vaddr);
+            if (data.absaddr)
+                yasm_intnum_destroy(data.absaddr);
+            return NULL;
         }
 
-        flags_override = 1;
-        if (yasm__strcasecmp(vp->val, "use16") == 0) {
-            flags &= ~(XDF_SECT_USE_32|XDF_SECT_USE_64);
-            flags |= XDF_SECT_USE_16;
-            yasm_arch_set_var(object->arch, "mode_bits", 16);
-        } else if (yasm__strcasecmp(vp->val, "use32") == 0) {
-            flags &= ~(XDF_SECT_USE_16|XDF_SECT_USE_64);
-            flags |= XDF_SECT_USE_32;
-            yasm_arch_set_var(object->arch, "mode_bits", 32);
-        } else if (yasm__strcasecmp(vp->val, "use64") == 0) {
-            flags &= ~(XDF_SECT_USE_16|XDF_SECT_USE_32);
-            flags |= XDF_SECT_USE_64;
-            yasm_arch_set_var(object->arch, "mode_bits", 64);
-        } else if (yasm__strcasecmp(vp->val, "bss") == 0) {
-            flags |= XDF_SECT_BSS;
-        } else if (yasm__strcasecmp(vp->val, "flat") == 0) {
-            flags |= XDF_SECT_FLAT;
-        } else if (yasm__strcasecmp(vp->val, "absolute") == 0 && vp->param) {
-            flags |= XDF_SECT_ABSOLUTE;
-            absaddr = yasm_expr_get_intnum(&vp->param, 0);
-            if (!absaddr) {
-                yasm_error_set(YASM_ERROR_NOT_CONSTANT,
-                               N_("argument to `%s' is not an integer"),
-                               vp->val);
-                return NULL;
-            }
-        } else if (yasm__strcasecmp(vp->val, "virtual") == 0 && vp->param) {
-            vaddr = yasm_expr_get_intnum(&vp->param, 0);
-            if (!vaddr) {
-                yasm_error_set(YASM_ERROR_NOT_CONSTANT,
-                               N_("argument to `%s' is not an integer"),
-                               vp->val);
-                return NULL;
-            }
-        } else if (yasm__strcasecmp(vp->val, "align") == 0 && vp->param) {
-            /*@dependent@*/ /*@null@*/ const yasm_intnum *align_expr;
-
-            align_expr = yasm_expr_get_intnum(&vp->param, 0);
-            if (!align_expr) {
-                yasm_error_set(YASM_ERROR_VALUE,
-                               N_("argument to `%s' is not an integer"),
-                               vp->val);
-                return NULL;
-            }
-            align = yasm_intnum_get_uint(align_expr);
-
-            /* Alignments must be a power of two. */
-            if (!is_exp2(align)) {
-                yasm_error_set(YASM_ERROR_VALUE,
-                               N_("argument to `%s' is not a power of two"),
-                               vp->val);
-                return NULL;
-            }
-
-            /* Check to see if alignment is supported size */
-            if (align > 4096) {
-                yasm_error_set(YASM_ERROR_VALUE,
-                               N_("XDF does not support alignments > 4096"));
-                return NULL;
-            }
-        } else
-            yasm_warn_set(YASM_WARN_GENERAL, N_("Unrecognized qualifier `%s'"),
-                          vp->val);
+        /* Check to see if alignment is supported size */
+        if (align > 4096) {
+            yasm_error_set(YASM_ERROR_VALUE,
+                           N_("XDF does not support alignments > 4096"));
+            if (data.vaddr)
+                yasm_intnum_destroy(data.vaddr);
+            if (data.absaddr)
+                yasm_intnum_destroy(data.absaddr);
+            return NULL;
+        }
     }
 
     retval = yasm_object_get_general(object, sectname, 0, align, 1, resonly,
@@ -750,16 +758,16 @@ xdf_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams,
 
     if (isnew || yasm_section_is_default(retval)) {
         yasm_section_set_default(retval, 0);
-        xsd->flags = flags;
-        if (absaddr) {
+        xsd->flags = data.flags;
+        if (data.absaddr) {
             if (xsd->addr)
                 yasm_intnum_destroy(xsd->addr);
-            xsd->addr = yasm_intnum_copy(absaddr);
+            xsd->addr = data.absaddr;
         }
-        if (vaddr) {
+        if (data.vaddr) {
             if (xsd->vaddr)
                 yasm_intnum_destroy(xsd->vaddr);
-            xsd->vaddr = yasm_intnum_copy(vaddr);
+            xsd->vaddr = data.vaddr;
         }
         yasm_section_set_align(retval, align, line);
     } else if (flags_override)
index 45b36c3200b352a03465f16e5d543b55a964d2ed..702b47ddd59c3c5d98083443f71313f1a090383b 100644 (file)
@@ -439,7 +439,7 @@ parse_line(yasm_parser_gas *parser_gas)
             } else if (align) {
                 /* Give third parameter as objext valparam */
                 yasm_valparamhead *extvps = yasm_vps_create();
-                vp = yasm_vp_create(NULL, align);
+                vp = yasm_vp_create_expr(NULL, align);
                 yasm_vps_append(extvps, vp);
 
                 sym = yasm_symtab_declare(p_symtab, id, YASM_SYM_COMMON,
@@ -652,7 +652,7 @@ parse_line(yasm_parser_gas *parser_gas)
 
                 /* Pass change along to debug format */
                 yasm_vps_initialize(&vps);
-                vp = yasm_vp_create(filename, NULL);
+                vp = yasm_vp_create_string(NULL, filename);
                 yasm_vps_append(&vps, vp);
 
                 yasm_object_directive(p_object, ".file", "gas", &vps, NULL,
@@ -666,8 +666,8 @@ parse_line(yasm_parser_gas *parser_gas)
             yasm_vps_initialize(&vps);
 
             if (!expect(INTNUM)) return NULL;
-            vp = yasm_vp_create(NULL,
-                                p_expr_new_ident(yasm_expr_int(INTNUM_val)));
+            vp = yasm_vp_create_expr(NULL,
+                p_expr_new_ident(yasm_expr_int(INTNUM_val)));
             yasm_vps_append(&vps, vp);
             get_next_token(); /* INTNUM */
 
@@ -675,7 +675,7 @@ parse_line(yasm_parser_gas *parser_gas)
                 yasm_vps_delete(&vps);
                 return NULL;
             }
-            vp = yasm_vp_create(STRING_val.contents, NULL);
+            vp = yasm_vp_create_string(NULL, STRING_val.contents);
             yasm_vps_append(&vps, vp);
             get_next_token(); /* STRING */
 
@@ -771,18 +771,22 @@ parse_dirvals(yasm_parser_gas *parser_gas, yasm_valparamhead *vps)
         switch (curtok) {
             case ID:
                 get_peek_token(parser_gas);
-                if (parser_gas->peek_token == ',' ||
-                    is_eol_tok(parser_gas->peek_token)) {
-                    /* Just an ID */
-                    vp = yasm_vp_create(ID_val, NULL);
-                    get_next_token(); /* ID */
-                } else {
-                    e = parse_expr(parser_gas);
-                    vp = yasm_vp_create(NULL, e);
+                switch (parser_gas->peek_token) {
+                    case '+': case '-':
+                    case '|': case '^': case '&': case '!':
+                    case '*': case '/': case '%': case LEFT_OP: case RIGHT_OP:
+                        e = parse_expr(parser_gas);
+                        vp = yasm_vp_create_expr(NULL, e);
+                        break;
+                    default:
+                        /* Just an ID */
+                        vp = yasm_vp_create_id(NULL, ID_val, '\0');
+                        get_next_token(); /* ID */
+                        break;
                 }
                 break;
             case STRING:
-                vp = yasm_vp_create(STRING_val.contents, NULL);
+                vp = yasm_vp_create_string(NULL, STRING_val.contents);
                 get_next_token(); /* STRING */
                 break;
             case '@':
@@ -793,7 +797,7 @@ parse_dirvals(yasm_parser_gas *parser_gas, yasm_valparamhead *vps)
                 e = parse_expr(parser_gas);
                 if (!e)
                     return num;
-                vp = yasm_vp_create(NULL, e);
+                vp = yasm_vp_create_expr(NULL, e);
                 break;
         }
         yasm_vps_append(vps, vp);
@@ -1284,20 +1288,18 @@ gas_get_section(yasm_parser_gas *parser_gas, char *name,
     yasm_section *new_section;
 
     yasm_vps_initialize(&vps);
-    vp = yasm_vp_create(name, NULL);
+    vp = yasm_vp_create_id(NULL, name, '\0');
     yasm_vps_append(&vps, vp);
 
     if (!builtin) {
-        if (flags) {
-            gasflags = yasm_xmalloc(5+strlen(flags));
-            strcpy(gasflags, "gas_");
-            strcat(gasflags, flags);
-        } else
-            gasflags = yasm__xstrdup("gas_");
-        vp = yasm_vp_create(gasflags, NULL);
+        if (flags)
+            gasflags = yasm__xstrdup(flags);
+        else
+            gasflags = yasm__xstrdup("");
+        vp = yasm_vp_create_string(yasm__xstrdup("gasflags"), gasflags);
         yasm_vps_append(&vps, vp);
         if (type) {
-            vp = yasm_vp_create(type, NULL);
+            vp = yasm_vp_create_id(NULL, type, '\0');
             yasm_vps_append(&vps, vp);
         }
     }
index 0202eae0f22b8dce94c3b7cd195f9e748a95d33b..cbd84993fd861ca09654278b57b0e662fe682a56 100644 (file)
@@ -65,8 +65,6 @@ static void nasm_parser_directive
     (yasm_parser_nasm *parser_nasm, const char *name,
      /*@null@*/ yasm_valparamhead *valparams,
      /*@null@*/ yasm_valparamhead *objext_valparams);
-static int fix_directive_symrec(/*@null@*/ yasm_expr__item *ei,
-                                /*@null@*/ void *d);
 static void define_label(yasm_parser_nasm *parser_nasm, /*@only@*/ char *name,
                          int local);
 
@@ -394,63 +392,54 @@ parse_directive_valparams(yasm_parser_nasm *parser_nasm,
     for (;;) {
         yasm_valparam *vp;
         yasm_expr *e;
+        char *id = NULL;
+
+        /* Look for value first */
+        if (curtok == ID) {
+            get_peek_token(parser_nasm);
+            if (parser_nasm->peek_token == '=') {
+                id = ID_val;
+                get_next_token(); /* id */
+                get_next_token(); /* '=' */
+            }
+        }
 
+        /* Look for parameter */
         switch (curtok) {
             case STRING:
-                vp = yasm_vp_create(STRING_val.contents, NULL);
+                vp = yasm_vp_create_string(id, STRING_val.contents);
                 get_next_token();
                 break;
             case ID:
-            {
-                char *id = ID_val;
-                get_peek_token(parser_nasm);
-                if (parser_nasm->peek_token == '=') {
-                    get_next_token(); /* id */
-                    get_next_token(); /* = */
-                    e = parse_expr(parser_nasm, DIR_EXPR);
-                    if (!e) {
-                        yasm_vps_delete(vps);
-                        return 0;
-                    }
-                    yasm_expr__traverse_leaves_in(e, parser_nasm,
-                                                  fix_directive_symrec);
-                    vp = yasm_vp_create(id, e);
-                    break;
-                }
-                if (parser_nasm->peek_token == ','
-                    || parser_nasm->peek_token == ']'
-                    || parser_nasm->peek_token == ':') {
-                    /* Try to catch just IDs here first */
-                    get_next_token(); /* id */
-                    vp = yasm_vp_create(id, NULL);
-                    break;
+                /* We need a peek token, but avoid error if we have one
+                 * already; we need to work whether or not we hit the
+                 * "value=" if test above.
+                 *
+                 * We cheat and peek ahead to see if this is just an ID or
+                 * the ID is part of an expression.  We assume a + or - means
+                 * that it's part of an expression (e.g. "x+y" is parsed as
+                 * the expression "x+y" and not as "x", "+y").
+                 */
+                if (parser_nasm->peek_token == NONE)
+                    get_peek_token(parser_nasm);
+                switch (parser_nasm->peek_token) {
+                    case '|': case '^': case '&': case LEFT_OP: case RIGHT_OP:
+                    case '+': case '-':
+                    case '*': case '/': case '%': case SIGNDIV: case SIGNMOD:
+                        break;
+                    default:
+                        /* Just an id */
+                        vp = yasm_vp_create_id(id, ID_val, '$');
+                        get_next_token();
+                        goto next;
                 }
                 /*@fallthrough@*/
-            }
             default:
-            {
-                /* If direxpr is just an ID, put it in val and delete the expr.
-                 * Otherwise, we need to go through the expr and replace the
-                 * current (local) symrecs with the use of global ones.
-                 */
-                const /*@null@*/ yasm_symrec *vp_symrec;
                 e = parse_expr(parser_nasm, DIR_EXPR);
-                if (!e) {
-                    yasm_vps_delete(vps);
-                    return 0;
-                }
-                if ((vp_symrec = yasm_expr_get_symrec(&e, 0))) {
-                    vp = yasm_vp_create(
-                        yasm__xstrdup(yasm_symrec_get_name(vp_symrec)), NULL);
-                    yasm_expr_destroy(e);
-                } else {
-                    yasm_expr__traverse_leaves_in(e, parser_nasm,
-                                                  fix_directive_symrec);
-                    vp = yasm_vp_create(NULL, e);
-                }
-            }
+                vp = yasm_vp_create_expr(id, e);
+                break;
         }
-
+next:
         yasm_vps_append(vps, vp);
         if (curtok == ',')
             get_next_token();
@@ -985,9 +974,8 @@ parse_expr6(yasm_parser_nasm *parser_nasm, expr_type type)
             e = p_expr_new_ident(yasm_expr_reg(REG_val[0]));
             break;
         case ID:
-            e = p_expr_new_ident(yasm_expr_sym(
-                yasm_symtab_define_label(p_symtab, ID_val,
-                    yasm_section_bcs_first(cursect), 0, cur_line)));
+            sym = yasm_symtab_use(p_symtab, ID_val, cur_line);
+            e = p_expr_new_ident(yasm_expr_sym(sym));
             yasm_xfree(ID_val);
             break;
         default:
@@ -1100,21 +1088,6 @@ define_label(yasm_parser_nasm *parser_nasm, char *name, int local)
     yasm_xfree(name);
 }
 
-static int
-fix_directive_symrec(yasm_expr__item *ei, void *d)
-{
-    yasm_parser_nasm *parser_nasm = (yasm_parser_nasm *)d;
-    if (!ei || ei->type != YASM_EXPR_SYM)
-        return 0;
-
-    /* FIXME: Delete current symrec */
-    ei->data.sym =
-        yasm_symtab_use(p_symtab, yasm_symrec_get_name(ei->data.sym),
-                        cur_line);
-
-    return 0;
-}
-
 static void
 dir_align(yasm_object *object, yasm_valparamhead *valparams,
           yasm_valparamhead *objext_valparams, unsigned long line)
index 4931498ce2438945365fb6a7d95cf61de87476bd..56bd8dfcbb54c6ee52d43ef1948abe9c7592a40b 100644 (file)
@@ -605,9 +605,11 @@ directive2:
             RETURN(s->tok[0]);
         }
 
-        /* forced identifier */
+        /* forced identifier; within directive, don't strip '$', this is
+         * handled later.
+         */
         "$" [a-zA-Z0-9_$#@~.?]+ {
-            lvalp->str_val = yasm__xstrndup(TOK+1, TOKLEN-1);
+            lvalp->str_val = yasm__xstrndup(TOK, TOKLEN);
             RETURN(ID);
         }