/**
 * \file libyasm/arch.h
 * \brief YASM architecture interface.
 *
 * \rcs
 * $Id: arch.h 1876 2007-06-02 21:50:51Z peter $
 * \endrcs
 *
 * \license
 *  Copyright (C) 2002-2007  Peter Johnson
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *  - Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  - Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 * \endlicense
 */
#ifndef YASM_ARCH_H
#define YASM_ARCH_H

/** Errors that may be returned by yasm_arch_module::create(). */
typedef enum yasm_arch_create_error {
    YASM_ARCH_CREATE_OK = 0,		/**< No error. */
    YASM_ARCH_CREATE_BAD_MACHINE,	/**< Unrecognized machine name. */
    YASM_ARCH_CREATE_BAD_PARSER		/**< Unrecognized parser name. */
} yasm_arch_create_error;

/** Return values for yasm_arch_module::parse_check_insnprefix(). */
typedef enum yasm_arch_insnprefix {
    YASM_ARCH_NOTINSNPREFIX = 0,	/**< Unrecognized */
    YASM_ARCH_INSN,			/**< An instruction */
    YASM_ARCH_PREFIX			/**< An instruction prefix */
} yasm_arch_insnprefix;

/** Types of registers / target modifiers that may be returned by
 * yasm_arch_module::parse_check_regtmod().
 */
typedef enum yasm_arch_regtmod {
    YASM_ARCH_NOTREGTMOD = 0,		/**< Unrecognized */
    YASM_ARCH_REG,			/**< A "normal" register */
    YASM_ARCH_REGGROUP,			/**< A group of indexable registers */
    YASM_ARCH_SEGREG,			/**< A segment register */
    YASM_ARCH_TARGETMOD			/**< A target modifier (for jumps) */
} yasm_arch_regtmod;

/** An instruction operand (opaque type). */
typedef struct yasm_insn_operand yasm_insn_operand;
#ifdef YASM_LIB_INTERNAL
/*@reldef@*/ STAILQ_HEAD(yasm_insn_operands, yasm_insn_operand);
#endif

#ifndef YASM_DOXYGEN
/** Base #yasm_arch structure.  Must be present as the first element in any
 * #yasm_arch implementation.
 */
typedef struct yasm_arch_base {
    /** #yasm_arch_module implementation for this architecture. */
    const struct yasm_arch_module *module;
} yasm_arch_base;
#endif

/** YASM machine subtype.  A number of different machine types may be
 * associated with a single architecture.  These may be specific CPU's, but
 * the ABI used to interface with the architecture should be the primary
 * differentiator between machines.  Some object formats (ELF) use the machine
 * to determine parameters within the generated output.
 */
typedef struct yasm_arch_machine {
    /** One-line description of the machine. */
    const char *name;

    /** Keyword used to select machine. */
    const char *keyword;
} yasm_arch_machine;

/** YASM architecture module interface.
 * \note All "data" in parser-related functions (yasm_arch_parse_*) needs to
 *	 start the parse initialized to 0 to make it okay for a parser-related
 *	 function to use/check previously stored data to see if it's been
 *	 called before on the same piece of data.
 */
typedef struct yasm_arch_module {
    /** One-line description of the architecture.
     * Call yasm_arch_name() to get the name of a particular #yasm_arch.
     */
    const char *name;

    /** Keyword used to select architecture.
     * Call yasm_arch_keyword() to get the keyword of a particular #yasm_arch.
     */
    const char *keyword;

    /** NULL-terminated list of directives.  NULL if none. */
    /*@null@*/ const yasm_directive *directives;

    /** Create architecture.
     * Module-level implementation of yasm_arch_create().
     * Call yasm_arch_create() instead of calling this function.
     */
    /*@only@*/ yasm_arch * (*create) (const char *machine, const char *parser,
				      yasm_arch_create_error *error);

    /** Module-level implementation of yasm_arch_destroy().
     * Call yasm_arch_destroy() instead of calling this function.
     */
    void (*destroy) (/*@only@*/ yasm_arch *arch);

    /** Module-level implementation of yasm_arch_get_machine().
     * Call yasm_arch_get_machine() instead of calling this function.
     */
    const char * (*get_machine) (const yasm_arch *arch);

    /** Module-level implementation of yasm_arch_get_address_size().
     * Call yasm_arch_get_address_size() instead of calling this function.
     */
    unsigned int (*get_address_size) (const yasm_arch *arch);

    /** Module-level implementation of yasm_arch_set_var().
     * Call yasm_arch_set_var() instead of calling this function.
     */
    int (*set_var) (yasm_arch *arch, const char *var, unsigned long val);

    /** Module-level implementation of yasm_arch_parse_check_insnprefix().
     * Call yasm_arch_parse_check_insnprefix() instead of calling this function.
     */
    yasm_arch_insnprefix (*parse_check_insnprefix)
	(yasm_arch *arch, /*@out@*/ uintptr_t data[4], const char *id,
	 size_t id_len);

    /** Module-level implementation of yasm_arch_parse_check_regtmod().
     * Call yasm_arch_parse_check_regtmod() instead of calling this function.
     */
    yasm_arch_regtmod (*parse_check_regtmod)
	(yasm_arch *arch, /*@out@*/ uintptr_t *data, const char *id,
	 size_t id_len);

    /** Module-level implementation of yasm_arch_get_fill().
     * Call yasm_arch_get_fill() instead of calling this function.
     */
    const unsigned char ** (*get_fill) (const yasm_arch *arch);

    /** Module-level implementation of yasm_arch_finalize_insn().
     * Call yasm_arch_finalize_insn() instead of calling this function.
     */
    void (*finalize_insn)
	(yasm_arch *arch, yasm_bytecode *bc, yasm_bytecode *prev_bc,
	 const uintptr_t data[4], int num_operands,
	 /*@null@*/ yasm_insn_operands *operands, int num_prefixes,
	 uintptr_t **prefixes, int num_segregs, const uintptr_t *segregs);

    /** Module-level implementation of yasm_arch_floatnum_tobytes().
     * Call yasm_arch_floatnum_tobytes() instead of calling this function.
     */
    int (*floatnum_tobytes) (yasm_arch *arch, const yasm_floatnum *flt,
			     unsigned char *buf, size_t destsize,
			     size_t valsize, size_t shift, int warn);

    /** Module-level implementation of yasm_arch_intnum_tobytes().
     * Call yasm_arch_intnum_tobytes() instead of calling this function.
     */
    int (*intnum_tobytes) (yasm_arch *arch, const yasm_intnum *intn,
			   unsigned char *buf, size_t destsize, size_t valsize,
			   int shift, const yasm_bytecode *bc,
			   int warn);

    /** Module-level implementation of yasm_arch_get_reg_size().
     * Call yasm_arch_get_reg_size() instead of calling this function.
     */
    unsigned int (*get_reg_size) (yasm_arch *arch, uintptr_t reg);

    /** Module-level implementation of yasm_arch_reggroup_get_reg().
     * Call yasm_arch_reggroup_get_reg() instead of calling this function.
     */
    uintptr_t (*reggroup_get_reg) (yasm_arch *arch, uintptr_t reggroup,
				   unsigned long regindex);

    /** Module-level implementation of yasm_arch_reg_print().
     * Call yasm_arch_reg_print() instead of calling this function.
     */
    void (*reg_print) (yasm_arch *arch, uintptr_t reg, FILE *f);

    /** Module-level implementation of yasm_arch_segreg_print().
     * Call yasm_arch_segreg_print() instead of calling this function.
     */
    void (*segreg_print) (yasm_arch *arch, uintptr_t segreg, FILE *f);

    /** Module-level implementation of yasm_arch_ea_create().
     * Call yasm_arch_ea_create() instead of calling this function.
     */
    yasm_effaddr * (*ea_create) (yasm_arch *arch, /*@keep@*/ yasm_expr *e);

    /** NULL-terminated list of machines for this architecture.
     * Call yasm_arch_get_machine() to get the active machine of a particular
     * #yasm_arch.
     */
    const yasm_arch_machine *machines;

    /** Default machine keyword.
     * Call yasm_arch_get_machine() to get the active machine of a particular
     * #yasm_arch.
     */
    const char *default_machine_keyword;

    /** Canonical "word" size in bits.
     * Call yasm_arch_wordsize() to get the word size of a particular
     * #yasm_arch.
     */
    unsigned int wordsize;

    /** Worst case minimum instruction length in bytes.
     * Call yasm_arch_min_insn_len() to get the minimum instruction length of
     * a particular #yasm_arch.
     */
    unsigned int min_insn_len;
} yasm_arch_module;

#ifdef YASM_LIB_INTERNAL
/** An instruction operand.  \internal */
struct yasm_insn_operand {
    /** Link for building linked list of operands.  \internal */
    /*@reldef@*/ STAILQ_ENTRY(yasm_insn_operand) link;

    /** Operand type. */
    enum yasm_insn_operand_type {
	YASM_INSN__OPERAND_REG = 1,	/**< A register. */
	YASM_INSN__OPERAND_SEGREG,	/**< A segment register. */
	YASM_INSN__OPERAND_MEMORY,	/**< An effective address
					 *   (memory reference). */
	YASM_INSN__OPERAND_IMM		/**< An immediate or jump target. */
    } type;

    /** Operand data. */
    union {
	uintptr_t reg;	    /**< Arch data for reg/segreg. */
	yasm_effaddr *ea;   /**< Effective address for memory references. */
	yasm_expr *val;	    /**< Value of immediate or jump target. */
    } data;

    uintptr_t targetmod;	/**< Arch target modifier, 0 if none. */

    /** Specified size of the operand, in bits.  0 if not user-specified. */
    unsigned int size:8;

    /** Nonzero if dereference.  Used for "*foo" in GAS.
     * The reason for this is that by default in GAS, an unprefixed value
     * is a memory address, except for jumps/calls, in which case it needs a
     * "*" prefix to become a memory address (otherwise it's an immediate).
     * This isn't knowable in the parser stage, so the parser sets this flag
     * to indicate the "*" prefix has been used, and the arch needs to adjust
     * the operand type appropriately depending on the instruction type.
     */
    unsigned int deref:1;

    /** Nonzero if strict.  Used for "strict foo" in NASM.
     * This is used to inhibit optimization on otherwise "sized" values.
     * For example, the user may just want to be explicit with the size on
     * "push dword 4", but not actually want to force the immediate size to
     * 4 bytes (rather wanting the optimizer to optimize it down to 1 byte as
     * though "dword" was not specified).  To indicate the immediate should
     * actually be forced to 4 bytes, the user needs to write
     * "push strict dword 4", which sets this flag.
     */
    unsigned int strict:1;
};
#endif

/** Get the one-line description of an architecture.
 * \param arch	    architecture
 * \return One-line description of architecture.
 */
const char *yasm_arch_name(const yasm_arch *arch);

/** Get the keyword used to select an architecture.
 * \param arch	    architecture
 * \return Architecture keyword.
 */
const char *yasm_arch_keyword(const yasm_arch *arch);

/** Get the word size of an architecture.
 * \param arch	    architecture
 * \return Word size (in bits).
 */
unsigned int yasm_arch_wordsize(const yasm_arch *arch);

/** Get the minimum instruction length of an architecture.
 * \param arch	    architecture
 * \return Minimum instruction length (in bytes).
 */
unsigned int yasm_arch_min_insn_len(const yasm_arch *arch);

/** Create architecture.
 * \param module	architecture module
 * \param machine	keyword of machine in use (must be one listed in
 *			#yasm_arch_module.machines)
 * \param parser	keyword of parser in use
 * \param error		error return value
 * \return NULL on error (error returned in error parameter), otherwise new
 *	   architecture.
 */
/*@only@*/ yasm_arch *yasm_arch_create(const yasm_arch_module *module,
				       const char *machine, const char *parser,
				       /*@out@*/ yasm_arch_create_error *error);

/** Clean up, free any architecture-allocated memory.
 * \param arch	architecture
 */
void yasm_arch_destroy(/*@only@*/ yasm_arch *arch);

/** Get architecture's active machine name.
 * \param arch	architecture
 * \return Active machine name.
 */
const char *yasm_arch_get_machine(const yasm_arch *arch);

/** Get architecture's active address size, in bits.
 * \param arch	architecture
 * \return Active address size (in bits).
 */
unsigned int yasm_arch_get_address_size(const yasm_arch *arch);

/** Set any arch-specific variables.  For example, "mode_bits" in x86.
 * \param arch	architecture
 * \param var	variable name
 * \param val	value to set
 * \return Zero on success, non-zero on failure (variable does not exist).
 */
int yasm_arch_set_var(yasm_arch *arch, const char *var, unsigned long val);

/** Check an generic identifier to see if it matches architecture specific
 * names for instructions or instruction prefixes.  Unrecognized identifiers
 * should return #YASM_ARCH_NOTINSNPREFIX so they can be treated as normal
 * symbols.  Any additional data beyond just the type (almost always necessary)
 * should be returned into the space provided by the data parameter.
 * \param arch		architecture
 * \param data		extra identification information (yasm_arch-specific)
 *			[output]
 * \param id		identifier as in the input file
 * \param id_len	length of id string
 * \return Identifier type (#YASM_ARCH_NOTINSNPREFIX if unrecognized)
 */
yasm_arch_insnprefix yasm_arch_parse_check_insnprefix
    (yasm_arch *arch, /*@out@*/ uintptr_t data[4], const char *id,
     size_t id_len);

/** Check an generic identifier to see if it matches architecture specific
 * names for registers or target modifiers.  Unrecognized identifiers should
 * return #YASM_ARCH_NOTREGTMOD.  Any additional data beyond just the type
 * (almost always necessary) should be returned into the space provided by the
 * data parameter.
 * \param arch		architecture
 * \param data		extra identification information (yasm_arch-specific)
 *			[output]
 * \param id		identifier as in the input file
 * \param id_len	length of id string
 * \return Identifier type (#YASM_ARCH_NOTREGTMOD if unrecognized)
 */
yasm_arch_regtmod yasm_arch_parse_check_regtmod
    (yasm_arch *arch, /*@out@*/ uintptr_t *data, const char *id,
     size_t id_len);

/** Get NOP fill patterns for 1-15 bytes of fill.
 * \param arch		architecture
 * \return 16-entry array of arrays; [0] is unused, [1] - [15] point to arrays
 * of 1-15 bytes (respectively) in length.
 */
const unsigned char **yasm_arch_get_fill(const yasm_arch *arch);

/** Finalize an instruction from a semi-generic insn description.  Note an
 * existing bytecode is required.
 * \param arch		architecture
 * \param bc		bytecode to finalize
 * \param prev_bc	previous bytecode in section
 * \param data		instruction data (from parse_check_id()); all
 *				zero indicates an empty instruction
 * \param num_operands	number of operands
 * \param operands	list of operands (in parse order)
 * \param num_prefixes	number of prefixes
 * \param prefixes	array of 4-element prefix data
 * \param num_segregs	number of segment register prefixes
 * \param segregs	array of segment register data
 * \return If no match is found (the instruction is invalid), no action is
 *         performed and an error is recorded.
 */
void yasm_arch_finalize_insn
    (yasm_arch *arch, yasm_bytecode *bc, yasm_bytecode *prev_bc,
     const uintptr_t data[4], int num_operands,
     /*@null@*/ yasm_insn_operands *operands, int num_prefixes,
     const uintptr_t **prefixes, int num_segregs, const uintptr_t *segregs);

/** Output #yasm_floatnum to buffer.  Puts the value into the least
 * significant bits of the destination, or may be shifted into more
 * significant bits by the shift parameter.  The destination bits are
 * cleared before being set.
 * Architecture-specific because of endianness.
 * \param arch		architecture
 * \param flt		floating point value
 * \param buf		buffer to write into
 * \param destsize	destination size (in bytes)
 * \param valsize	size (in bits)
 * \param shift		left shift (in bits)
 * \param warn		enables standard overflow/underflow warnings
 * \return Nonzero on error.
 */
int yasm_arch_floatnum_tobytes(yasm_arch *arch, const yasm_floatnum *flt,
			       unsigned char *buf, size_t destsize,
			       size_t valsize, size_t shift, int warn);

/** Output #yasm_intnum to buffer.  Puts the value into the least
 * significant bits of the destination, or may be shifted into more
 * significant bits by the shift parameter.  The destination bits are
 * cleared before being set.
 * \param arch		architecture
 * \param intn		integer value
 * \param buf		buffer to write into
 * \param destsize	destination size (in bytes)
 * \param valsize	size (in bits)
 * \param shift		left shift (in bits); may be negative to specify right
 *			shift (standard warnings include truncation to boundary)
 * \param bc		bytecode being output ("parent" of value)
 * \param warn		enables standard warnings (value doesn't fit into
 *			valsize bits)
 * \return Nonzero on error.
 */
int yasm_arch_intnum_tobytes(yasm_arch *arch, const yasm_intnum *intn,
			     unsigned char *buf, size_t destsize,
			     size_t valsize, int shift,
			     const yasm_bytecode *bc, int warn);

/** Get the equivalent size of a register in bits.
 * \param arch	architecture
 * \param reg	register
 * \return 0 if there is no suitable equivalent size, otherwise the size.
 */
unsigned int yasm_arch_get_reg_size(yasm_arch *arch, uintptr_t reg);

/** Get a specific register of a register group, based on the register
 * group and the index within the group.
 * \param arch		architecture
 * \param reggroup	register group
 * \param regindex	register index
 * \return 0 if regindex is not valid for that register group, otherwise the
 *         specific register value.
 */
uintptr_t yasm_arch_reggroup_get_reg(yasm_arch *arch, uintptr_t reggroup,
				     unsigned long regindex);

/** Print a register.  For debugging purposes.
 * \param arch		architecture
 * \param reg		register
 * \param f		file
 */
void yasm_arch_reg_print(yasm_arch *arch, uintptr_t reg, FILE *f);

/** Print a segment register.  For debugging purposes.
 * \param arch		architecture
 * \param segreg	segment register
 * \param f		file
 */
void yasm_arch_segreg_print(yasm_arch *arch, uintptr_t segreg, FILE *f);

/** Create an effective address from an expression.
 * \param arch	architecture
 * \param e	expression (kept, do not delete)
 * \return Newly allocated effective address.
 */
yasm_effaddr *yasm_arch_ea_create(yasm_arch *arch, /*@keep@*/ yasm_expr *e);


#ifndef YASM_DOXYGEN

/* Inline macro implementations for arch functions */

#define yasm_arch_name(arch) \
    (((yasm_arch_base *)arch)->module->name)
#define yasm_arch_keyword(arch) \
    (((yasm_arch_base *)arch)->module->keyword)
#define yasm_arch_wordsize(arch) \
    (((yasm_arch_base *)arch)->module->wordsize)
#define yasm_arch_min_insn_len(arch) \
    (((yasm_arch_base *)arch)->module->min_insn_len)

#define yasm_arch_create(module, machine, parser, error) \
    module->create(machine, parser, error)

#define yasm_arch_destroy(arch) \
    ((yasm_arch_base *)arch)->module->destroy(arch)
#define yasm_arch_get_machine(arch) \
    ((yasm_arch_base *)arch)->module->get_machine(arch)
#define yasm_arch_get_address_size(arch) \
    ((yasm_arch_base *)arch)->module->get_address_size(arch)
#define yasm_arch_set_var(arch, var, val) \
    ((yasm_arch_base *)arch)->module->set_var(arch, var, val)
#define yasm_arch_parse_check_insnprefix(arch, data, id, id_len) \
    ((yasm_arch_base *)arch)->module->parse_check_insnprefix(arch, data, id, \
							     id_len)
#define yasm_arch_parse_check_regtmod(arch, data, id, id_len) \
    ((yasm_arch_base *)arch)->module->parse_check_regtmod(arch, data, id, \
							  id_len)
#define yasm_arch_get_fill(arch) \
    ((yasm_arch_base *)arch)->module->get_fill(arch)
#define yasm_arch_finalize_insn(arch, bc, prev_bc, data, num_operands, \
				operands, num_prefixes, prefixes, \
				num_segregs, segregs) \
    ((yasm_arch_base *)arch)->module->finalize_insn \
	(arch, bc, prev_bc, data, num_operands, operands, num_prefixes, \
	 prefixes, num_segregs, segregs)
#define yasm_arch_floatnum_tobytes(arch, flt, buf, destsize, valsize, shift, \
				   warn) \
    ((yasm_arch_base *)arch)->module->floatnum_tobytes \
	(arch, flt, buf, destsize, valsize, shift, warn)
#define yasm_arch_intnum_tobytes(arch, intn, buf, destsize, valsize, shift, \
				 bc, warn) \
    ((yasm_arch_base *)arch)->module->intnum_tobytes \
	(arch, intn, buf, destsize, valsize, shift, bc, warn)
#define yasm_arch_get_reg_size(arch, reg) \
    ((yasm_arch_base *)arch)->module->get_reg_size(arch, reg)
#define yasm_arch_reggroup_get_reg(arch, regg, regi) \
    ((yasm_arch_base *)arch)->module->reggroup_get_reg(arch, regg, regi)
#define yasm_arch_reg_print(arch, reg, f) \
    ((yasm_arch_base *)arch)->module->reg_print(arch, reg, f)
#define yasm_arch_segreg_print(arch, segreg, f) \
    ((yasm_arch_base *)arch)->module->segreg_print(arch, segreg, f)
#define yasm_arch_ea_create(arch, e) \
    ((yasm_arch_base *)arch)->module->ea_create(arch, e)

#endif

/** Create an instruction operand from a register.
 * \param reg	register
 * \return Newly allocated operand.
 */
yasm_insn_operand *yasm_operand_create_reg(uintptr_t reg);

/** Create an instruction operand from a segment register.
 * \param segreg	segment register
 * \return Newly allocated operand.
 */
yasm_insn_operand *yasm_operand_create_segreg(uintptr_t segreg);

/** Create an instruction operand from an effective address.
 * \param ea	effective address
 * \return Newly allocated operand.
 */
yasm_insn_operand *yasm_operand_create_mem(/*@only@*/ yasm_effaddr *ea);

/** Create an instruction operand from an immediate expression.
 * Looks for cases of a single register and creates a register variant of
 * #yasm_insn_operand.
 * \param val	immediate expression
 * \return Newly allocated operand.
 */
yasm_insn_operand *yasm_operand_create_imm(/*@only@*/ yasm_expr *val);

/** Print an instruction operand.  For debugging purposes.
 * \param arch		architecture
 * \param f		file
 * \param indent_level	indentation level
 * \param op		instruction operand
 */
void yasm_operand_print(const yasm_insn_operand *op, FILE *f, int indent_level,
			yasm_arch *arch);

/** Create a new list of instruction operands.
 * \return Newly allocated list.
 */
yasm_insn_operands *yasm_ops_create(void);

/** Destroy a list of instruction operands (created with yasm_ops_create()).
 * \param headp		list of instruction operands
 * \param content	if nonzero, deletes content of each operand
 */
void yasm_ops_destroy(yasm_insn_operands *headp, int content);

/** Get the first operand in a list of instruction operands.
 * \param headp		list of instruction operands
 * \return First operand in list (NULL if list is empty).
 */
yasm_insn_operand *yasm_ops_first(yasm_insn_operands *headp);

/** Get the next operand in a list of instruction operands.
 * \param cur		previous operand
 * \return Next operand in list (NULL if cur was the last operand).
 */
yasm_insn_operand *yasm_operand_next(yasm_insn_operand *cur);

#ifdef YASM_LIB_INTERNAL
#define yasm_ops_initialize(headp)	STAILQ_INIT(headp)
#define yasm_ops_first(headp)		STAILQ_FIRST(headp)
#define yasm_operand_next(cur)		STAILQ_NEXT(cur, link)

/** Delete (free allocated memory for) a list of instruction operands (created
 * with yasm_ops_initialize()).
 * \param headp		list of instruction operands
 * \param content	if nonzero, deletes content of each operand
 */
void yasm_ops_delete(yasm_insn_operands *headp, int content);
#endif

/** Add data value to the end of a list of instruction operands.
 * \note Does not make a copy of the operand; so don't pass this function
 *	 static or local variables, and discard the op pointer after calling
 *	 this function.
 * \param headp		list of instruction operands
 * \param op		operand (may be NULL)
 * \return If operand was actually appended (it wasn't NULL), the operand;
 *	   otherwise NULL.
 */
/*@null@*/ yasm_insn_operand *yasm_ops_append
    (yasm_insn_operands *headp,
     /*@returned@*/ /*@null@*/ yasm_insn_operand *op);

/** Print a list of instruction operands.  For debugging purposes.
 * \param arch		architecture
 * \param f		file
 * \param indent_level	indentation level
 * \param headp		list of instruction operands
 */
void yasm_ops_print(const yasm_insn_operands *headp, FILE *f, int indent_level,
		    yasm_arch *arch);

#endif
