/* ----------------------------------------------------------------------- * * * Copyright 1996-2018 The NASM Authors - All Rights Reserved * See the file AUTHORS included with the NASM distribution for * the specific copyright holders. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * ----------------------------------------------------------------------- */ /* * eval.c expression evaluator for the Netwide Assembler */ #include "compiler.h" #include "nctype.h" #include "nasm.h" #include "nasmlib.h" #include "ilog2.h" #include "error.h" #include "eval.h" #include "labels.h" #include "floats.h" #include "assemble.h" #define TEMPEXPRS_DELTA … #define TEMPEXPR_DELTA … static scanner scanfunc; /* Address of scanner routine */ static void *scpriv; /* Scanner private pointer */ static expr **tempexprs = …; static int ntempexprs; static int tempexprs_size = …; static expr *tempexpr; static int ntempexpr; static int tempexpr_size; static struct tokenval *tokval; /* The current token */ static int tt; /* The t_type of tokval */ static bool critical; static int *opflags; static struct eval_hints *hint; static int64_t deadman; /* * Unimportant cleanup is done to avoid confusing people who are trying * to debug real memory leaks */ void eval_cleanup(void) { … } /* * Construct a temporary expression. */ static void begintemp(void) { … } static void addtotemp(int32_t type, int64_t value) { … } static expr *finishtemp(void) { … } /* * Add two vector datatypes. We have some bizarre behaviour on far- * absolute segment types: we preserve them during addition _only_ * if one of the segments is a truly pure scalar. */ static expr *add_vectors(expr * p, expr * q) { … } /* * Multiply a vector by a scalar. Strip far-absolute segment part * if present. * * Explicit treatment of UNKNOWN is not required in this routine, * since it will silently do the Right Thing anyway. * * If `affect_hints' is set, we also change the hint type to * NOTBASE if a MAKEBASE hint points at a register being * multiplied. This allows [eax*1+ebx] to hint EBX rather than EAX * as the base register. */ static expr *scalar_mult(expr * vect, int64_t scalar, int affect_hints) { … } static expr *scalarvect(int64_t scalar) { … } static expr *unknown_expr(void) { … } /* * The SEG operator: calculate the segment part of a relocatable * value. Return NULL, as usual, if an error occurs. Report the * error too. */ static expr *segment_part(expr * e) { … } /* * Recursive-descent parser. Called with a single boolean operand, * which is true if the evaluation is critical (i.e. unresolved * symbols are an error condition). Must update the global `tt' to * reflect the token after the parsed string. May return NULL. * * evaluate() should report its own errors: on return it is assumed * that if NULL has been returned, the error has already been * reported. * */ /* * Wrapper function around the scanner */ static int scan(void) { … } /* * Grammar parsed is: * * expr : bexpr [ WRT expr6 ] * bexpr : cexpr * cexpr : rexp0 [ {?} bexpr {:} cexpr ] * rexp0 : rexp1 [ {||} rexp1...] * rexp1 : rexp2 [ {^^} rexp2...] * rexp2 : rexp3 [ {&&} rexp3...] * rexp3 : expr0 [ {=,==,<>,!=,<,>,<=,>=,<=>} expr0... ] * expr0 : expr1 [ {|} expr1...] * expr1 : expr2 [ {^} expr2...] * expr2 : expr3 [ {&} expr3...] * expr3 : expr4 [ {<<,>>,<<<,>>>} expr4...] * expr4 : expr5 [ {+,-} expr5...] * expr5 : expr6 [ {*,/,%,//,%%} expr6...] * expr6 : { ~,+,-,IFUNC,SEG } expr6 * | (bexpr) * | symbol * | $ * | number */ static expr *cexpr(void); static expr *rexp0(void), *rexp1(void), *rexp2(void), *rexp3(void); static expr *expr0(void), *expr1(void), *expr2(void), *expr3(void); static expr *expr4(void), *expr5(void), *expr6(void); /* This inline is a placeholder for the root of the basic expression */ static inline expr *bexpr(void) { … } static expr *cexpr(void) { … } static expr *rexp0(void) { … } static expr *rexp1(void) { … } static expr *rexp2(void) { … } static expr *rexp3(void) { … } static expr *expr0(void) { … } static expr *expr1(void) { … } static expr *expr2(void) { … } static expr *expr3(void) { … } static expr *expr4(void) { … } static expr *expr5(void) { … } static expr *eval_floatize(enum floatize type) { … } static expr *eval_strfunc(enum strfunc type, const char *name) { … } static int64_t eval_ifunc(int64_t val, enum ifunc func) { … } static expr *expr6(void) { … } expr *evaluate(scanner sc, void *scprivate, struct tokenval *tv, int *fwref, bool crit, struct eval_hints *hints) { … }