/**
 * \file libyasm/value.h
 * \brief YASM value interface.
 *
 * \rcs
 * $Id: value.h 2101 2008-05-23 06:46:51Z peter $
 * \endrcs
 *
 * \license
 *  Copyright (C) 2006-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_VALUE_H
#define YASM_VALUE_H

#ifndef YASM_LIB_DECL
#define YASM_LIB_DECL
#endif

/** Initialize a #yasm_value with just an expression.  No processing is
 * performed, the expression is simply stuck into value.abs and the other
 * fields are initialized.  Use yasm_expr_extract_value() to perform "smart"
 * processing into a #yasm_value.  This function is intended for use during
 * parsing simply to ensure all fields of the value are initialized; after
 * the parse is complete, yasm_value_extract() should be called to finalize
 * the value.  The value defaults to unsigned.
 * \param value     value to be initialized
 * \param e         expression (kept)
 * \param size      value size (in bits)
 */
YASM_LIB_DECL
void yasm_value_initialize(/*@out@*/ yasm_value *value,
                           /*@null@*/ /*@kept@*/ yasm_expr *e,
                           unsigned int size);

/** Initialize a #yasm_value with just a symrec.  No processing is performed,
 * the symrec is simply stuck into value.rel and the other fields are
 * initialized.
 * \param value     value to be initialized
 * \param sym       symrec
 * \param size      value size (in bits)
 */
YASM_LIB_DECL
void yasm_value_init_sym(/*@out@*/ yasm_value *value,
                         /*@null@*/ yasm_symrec *sym, unsigned int size);

/** Initialize a #yasm_value as a copy of another yasm_value.  Any expressions
 * within orig are copied, so it's safe to delete the copy.
 * \param value     value (copy to create)
 * \param orig      original value
 */
YASM_LIB_DECL
void yasm_value_init_copy(yasm_value *value, const yasm_value *orig);

/** Frees any memory inside value; does not free value itself.
 * \param value     value
 */
YASM_LIB_DECL
void yasm_value_delete(yasm_value *value);

/** Set a value to be relative to the current assembly position rather than
 * relative to the section start.
 * \param value     value
 * \param bc        bytecode containing value
 * \param ip_rel    if nonzero, indicates IP-relative data relocation,
 *                  sometimes used to generate special relocations
 * \note If value is just an absolute value, will get an absolute symrec to
 *       reference to (via bc's symbol table).
 */
YASM_LIB_DECL
void yasm_value_set_curpos_rel(yasm_value *value, yasm_bytecode *bc,
                               unsigned int ip_rel);

/** Perform yasm_value_finalize_expr() on a value that already exists from
 * being initialized with yasm_value_initialize().
 * \param value         value
 * \param precbc        previous bytecode to bytecode containing value
 * \return Nonzero if value could not be split.
 */
YASM_LIB_DECL
int yasm_value_finalize(yasm_value *value, /*@null@*/ yasm_bytecode *precbc);

/** Break a #yasm_expr into a #yasm_value constituent parts.  Extracts
 * the relative portion of the value, SEG and WRT portions, and top-level
 * right shift, if any.  Places the remaining expr into the absolute
 * portion of the value.  Essentially a combination of yasm_value_initialize()
 * and yasm_value_finalize().  First expands references to symrecs in
 * absolute sections by expanding with the absolute section start plus the
 * symrec offset within the absolute section.
 * \param value         value to store split portions into
 * \param e             expression input
 * \param precbc        previous bytecode to bytecode containing expression
 * \param size          value size (in bits)
 * \return Nonzero if the expr could not be split into a value for some
 *         reason (e.g. the relative portion was not added, but multiplied,
 *         etc).
 * \warning Do not use e after this call.  Even if an error is returned, e
 *          is stored into value.
 * \note This should only be called after the parse is complete.  Calling
 *       before the parse is complete will usually result in an error return.
 */
YASM_LIB_DECL
int yasm_value_finalize_expr(/*@out@*/ yasm_value *value,
                             /*@null@*/ /*@kept@*/ yasm_expr *e,
                             /*@null@*/ yasm_bytecode *precbc,
                             unsigned int size);

/** Get value if absolute or PC-relative section-local relative.  Returns NULL
 * otherwise.
 * \param value         value
 * \param bc            current bytecode (for PC-relative calculation); if
 *                      NULL, NULL is returned for PC-relative values.
 * \param calc_bc_dist  if nonzero, calculates bytecode distances in absolute
 *                      portion of value
 * \note Adds in value.rel (correctly) if PC-relative and in the same section
 *       as bc (and there is no WRT or SEG).
 * \return Intnum if can be resolved to integer value, otherwise NULL.
 */
YASM_LIB_DECL
/*@null@*/ /*@only@*/ yasm_intnum *yasm_value_get_intnum
    (yasm_value *value, /*@null@*/ yasm_bytecode *bc, int calc_bc_dist);

/** Output value if constant or PC-relative section-local.  This should be
 * used from objfmt yasm_output_value_func() functions.
 * functions.
 * \param value         value
 * \param buf           buffer for byte representation
 * \param destsize      destination size (in bytes)
 * \param bc            current bytecode (usually passed into higher-level
 *                      calling function)
 * \param warn          enables standard warnings: zero for none;
 *                      nonzero for overflow/underflow floating point and
 *                      integer warnings
 * \param arch          architecture
 * \note Adds in value.rel (correctly) if PC-relative and in the same section
 *       as bc (and there is no WRT or SEG); if this is not the desired
 *       behavior, e.g. a reloc is needed in this case, don't use this
 *       function!
 * \return 0 if no value output due to value needing relocation;
 *         1 if value output; -1 if error.
 */
YASM_LIB_DECL
int yasm_value_output_basic
    (yasm_value *value, /*@out@*/ unsigned char *buf, size_t destsize,
     yasm_bytecode *bc, int warn, yasm_arch *arch);

/** Print a value.  For debugging purposes.
 * \param value         value
 * \param indent_level  indentation level
 * \param f             file
 */
YASM_LIB_DECL
void yasm_value_print(const yasm_value *value, FILE *f, int indent_level);

#endif
