123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441 |
- /* eval.c expression evaluator for the Netwide Assembler
- *
- * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
- * Julian Hall. All rights reserved. The software is
- * redistributable under the licence given in the file "Licence"
- * distributed in the NASM archive.
- *
- * initial version 27/iii/95 by Simon Tatham
- */
- #include <util.h>
- #include <libyasm-stdint.h>
- #include <libyasm/coretype.h>
- #include <libyasm/intnum.h>
- #include <libyasm/expr.h>
- #include <libyasm/symrec.h>
- #include <ctype.h>
- #include "nasm.h"
- #include "nasmlib.h"
- #include "nasm-eval.h"
- /* The assembler symbol table. */
- extern yasm_symtab *nasm_symtab;
- static scanner scan; /* Address of scanner routine */
- static efunc error; /* Address of error reporting routine */
- static struct tokenval *tokval; /* The current token */
- static int i; /* The t_type of tokval */
- static void *scpriv;
- /*
- * 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 `i' 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.
- */
- /*
- * Grammar parsed is:
- *
- * expr : bexpr [ WRT expr6 ]
- * bexpr : rexp0 or expr0 depending on relative-mode setting
- * 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 : { ~,+,-,SEG } expr6
- * | (bexpr)
- * | symbol
- * | $
- * | number
- */
- static yasm_expr *rexp0(void), *rexp1(void), *rexp2(void), *rexp3(void);
- static yasm_expr *expr0(void), *expr1(void), *expr2(void), *expr3(void);
- static yasm_expr *expr4(void), *expr5(void), *expr6(void);
- static yasm_expr *(*bexpr)(void);
- static yasm_expr *rexp0(void)
- {
- yasm_expr *e, *f;
- e = rexp1();
- if (!e)
- return NULL;
- while (i == TOKEN_DBL_OR)
- {
- i = scan(scpriv, tokval);
- f = rexp1();
- if (!f) {
- yasm_expr_destroy(e);
- return NULL;
- }
- e = yasm_expr_create_tree(e, YASM_EXPR_LOR, f, 0);
- }
- return e;
- }
- static yasm_expr *rexp1(void)
- {
- yasm_expr *e, *f;
- e = rexp2();
- if (!e)
- return NULL;
-
- while (i == TOKEN_DBL_XOR)
- {
- i = scan(scpriv, tokval);
- f = rexp2();
- if (!f) {
- yasm_expr_destroy(e);
- return NULL;
- }
- e = yasm_expr_create_tree(e, YASM_EXPR_LXOR, f, 0);
- }
- return e;
- }
- static yasm_expr *rexp2(void)
- {
- yasm_expr *e, *f;
- e = rexp3();
- if (!e)
- return NULL;
- while (i == TOKEN_DBL_AND)
- {
- i = scan(scpriv, tokval);
- f = rexp3();
- if (!f) {
- yasm_expr_destroy(e);
- return NULL;
- }
- e = yasm_expr_create_tree(e, YASM_EXPR_LAND, f, 0);
- }
- return e;
- }
- static yasm_expr *rexp3(void)
- {
- yasm_expr *e, *f;
- e = expr0();
- if (!e)
- return NULL;
- while (i == TOKEN_EQ || i == TOKEN_LT || i == TOKEN_GT ||
- i == TOKEN_NE || i == TOKEN_LE || i == TOKEN_GE)
- {
- int j = i;
- i = scan(scpriv, tokval);
- f = expr0();
- if (!f) {
- yasm_expr_destroy(e);
- return NULL;
- }
- switch (j)
- {
- case TOKEN_EQ:
- e = yasm_expr_create_tree(e, YASM_EXPR_EQ, f, 0);
- break;
- case TOKEN_LT:
- e = yasm_expr_create_tree(e, YASM_EXPR_LT, f, 0);
- break;
- case TOKEN_GT:
- e = yasm_expr_create_tree(e, YASM_EXPR_GT, f, 0);
- break;
- case TOKEN_NE:
- e = yasm_expr_create_tree(e, YASM_EXPR_NE, f, 0);
- break;
- case TOKEN_LE:
- e = yasm_expr_create_tree(e, YASM_EXPR_LE, f, 0);
- break;
- case TOKEN_GE:
- e = yasm_expr_create_tree(e, YASM_EXPR_GE, f, 0);
- break;
- }
- }
- return e;
- }
- static yasm_expr *expr0(void)
- {
- yasm_expr *e, *f;
- e = expr1();
- if (!e)
- return NULL;
- while (i == '|')
- {
- i = scan(scpriv, tokval);
- f = expr1();
- if (!f) {
- yasm_expr_destroy(e);
- return NULL;
- }
- e = yasm_expr_create_tree(e, YASM_EXPR_OR, f, 0);
- }
- return e;
- }
- static yasm_expr *expr1(void)
- {
- yasm_expr *e, *f;
- e = expr2();
- if (!e)
- return NULL;
- while (i == '^') {
- i = scan(scpriv, tokval);
- f = expr2();
- if (!f) {
- yasm_expr_destroy(e);
- return NULL;
- }
- e = yasm_expr_create_tree(e, YASM_EXPR_XOR, f, 0);
- }
- return e;
- }
- static yasm_expr *expr2(void)
- {
- yasm_expr *e, *f;
- e = expr3();
- if (!e)
- return NULL;
- while (i == '&') {
- i = scan(scpriv, tokval);
- f = expr3();
- if (!f) {
- yasm_expr_destroy(e);
- return NULL;
- }
- e = yasm_expr_create_tree(e, YASM_EXPR_AND, f, 0);
- }
- return e;
- }
- static yasm_expr *expr3(void)
- {
- yasm_expr *e, *f;
- e = expr4();
- if (!e)
- return NULL;
- while (i == TOKEN_SHL || i == TOKEN_SHR)
- {
- int j = i;
- i = scan(scpriv, tokval);
- f = expr4();
- if (!f) {
- yasm_expr_destroy(e);
- return NULL;
- }
- switch (j) {
- case TOKEN_SHL:
- e = yasm_expr_create_tree(e, YASM_EXPR_SHL, f, 0);
- break;
- case TOKEN_SHR:
- e = yasm_expr_create_tree(e, YASM_EXPR_SHR, f, 0);
- break;
- }
- }
- return e;
- }
- static yasm_expr *expr4(void)
- {
- yasm_expr *e, *f;
- e = expr5();
- if (!e)
- return NULL;
- while (i == '+' || i == '-')
- {
- int j = i;
- i = scan(scpriv, tokval);
- f = expr5();
- if (!f) {
- yasm_expr_destroy(e);
- return NULL;
- }
- switch (j) {
- case '+':
- e = yasm_expr_create_tree(e, YASM_EXPR_ADD, f, 0);
- break;
- case '-':
- e = yasm_expr_create_tree(e, YASM_EXPR_SUB, f, 0);
- break;
- }
- }
- return e;
- }
- static yasm_expr *expr5(void)
- {
- yasm_expr *e, *f;
- e = expr6();
- if (!e)
- return NULL;
- while (i == '*' || i == '/' || i == '%' ||
- i == TOKEN_SDIV || i == TOKEN_SMOD)
- {
- int j = i;
- i = scan(scpriv, tokval);
- f = expr6();
- if (!f) {
- yasm_expr_destroy(e);
- return NULL;
- }
- switch (j) {
- case '*':
- e = yasm_expr_create_tree(e, YASM_EXPR_MUL, f, 0);
- break;
- case '/':
- e = yasm_expr_create_tree(e, YASM_EXPR_DIV, f, 0);
- break;
- case '%':
- e = yasm_expr_create_tree(e, YASM_EXPR_MOD, f, 0);
- break;
- case TOKEN_SDIV:
- e = yasm_expr_create_tree(e, YASM_EXPR_SIGNDIV, f, 0);
- break;
- case TOKEN_SMOD:
- e = yasm_expr_create_tree(e, YASM_EXPR_SIGNMOD, f, 0);
- break;
- }
- }
- return e;
- }
- static yasm_expr *expr6(void)
- {
- yasm_expr *e = NULL;
- if (i == '-') {
- i = scan(scpriv, tokval);
- e = expr6();
- if (!e)
- return NULL;
- return yasm_expr_create_branch(YASM_EXPR_NEG, e, 0);
- } else if (i == '+') {
- i = scan(scpriv, tokval);
- return expr6();
- } else if (i == '~') {
- i = scan(scpriv, tokval);
- e = expr6();
- if (!e)
- return NULL;
- return yasm_expr_create_branch(YASM_EXPR_NOT, e, 0);
- } else if (i == TOKEN_SEG) {
- i = scan(scpriv, tokval);
- e = expr6();
- if (!e)
- return NULL;
- error(ERR_NONFATAL, "%s not supported", "SEG");
- return e;
- } else if (i == '(') {
- i = scan(scpriv, tokval);
- e = bexpr();
- if (!e)
- return NULL;
- if (i != ')') {
- error(ERR_NONFATAL, "expecting `)'");
- return NULL;
- }
- i = scan(scpriv, tokval);
- return e;
- }
- else if (i == TOKEN_NUM || i == TOKEN_ID ||
- i == TOKEN_HERE || i == TOKEN_BASE)
- {
- switch (i) {
- case TOKEN_NUM:
- e = yasm_expr_create_ident(yasm_expr_int(tokval->t_integer), 0);
- break;
- case TOKEN_ID:
- if (nasm_symtab) {
- yasm_symrec *sym =
- yasm_symtab_get(nasm_symtab, tokval->t_charptr);
- if (sym) {
- e = yasm_expr_create_ident(yasm_expr_sym(sym), 0);
- } else {
- error(ERR_NONFATAL,
- "undefined symbol `%s' in preprocessor",
- tokval->t_charptr);
- e = yasm_expr_create_ident(yasm_expr_int(
- yasm_intnum_create_int(1)), 0);
- }
- break;
- }
- /*fallthrough*/
- case TOKEN_HERE:
- case TOKEN_BASE:
- error(ERR_NONFATAL,
- "cannot reference symbol `%s' in preprocessor",
- (i == TOKEN_ID ? tokval->t_charptr :
- i == TOKEN_HERE ? "$" : "$$"));
- e = yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_int(1)),
- 0);
- break;
- }
- i = scan(scpriv, tokval);
- return e;
- } else {
- error(ERR_NONFATAL, "expression syntax error");
- return NULL;
- }
- }
- yasm_expr *nasm_evaluate (scanner sc, void *scprivate, struct tokenval *tv,
- int critical, efunc report_error)
- {
- if (critical & CRITICAL) {
- critical &= ~CRITICAL;
- bexpr = rexp0;
- } else
- bexpr = expr0;
- scan = sc;
- scpriv = scprivate;
- tokval = tv;
- error = report_error;
- if (tokval->t_type == TOKEN_INVALID)
- i = scan(scpriv, tokval);
- else
- i = tokval->t_type;
- return bexpr ();
- }
|