c0e157e3b2
One must build yasm (included in the yasm directory) before building GMP, if building on an x86_64 machine. Note: make test and make tune do not currently build.
442 lines
11 KiB
C
442 lines
11 KiB
C
/* 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 ();
|
|
}
|