1/* eval.c    expression evaluator for the Netwide Assembler
2 *
3 * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
4 * Julian Hall. All rights reserved. The software is
5 * redistributable under the licence given in the file "Licence"
6 * distributed in the NASM archive.
7 *
8 * initial version 27/iii/95 by Simon Tatham
9 */
10#include <util.h>
11#include <libyasm-stdint.h>
12#include <libyasm/coretype.h>
13#include <libyasm/intnum.h>
14#include <libyasm/expr.h>
15#include <libyasm/symrec.h>
16#include <ctype.h>
17
18#include "nasm.h"
19#include "nasmlib.h"
20#include "nasm-eval.h"
21
22/* The assembler symbol table. */
23extern yasm_symtab *nasm_symtab;
24
25static scanner scan;    /* Address of scanner routine */
26static efunc error;     /* Address of error reporting routine */
27
28static struct tokenval *tokval;   /* The current token */
29static int i;                     /* The t_type of tokval */
30
31static void *scpriv;
32
33/*
34 * Recursive-descent parser. Called with a single boolean operand,
35 * which is TRUE if the evaluation is critical (i.e. unresolved
36 * symbols are an error condition). Must update the global `i' to
37 * reflect the token after the parsed string. May return NULL.
38 *
39 * evaluate() should report its own errors: on return it is assumed
40 * that if NULL has been returned, the error has already been
41 * reported.
42 */
43
44/*
45 * Grammar parsed is:
46 *
47 * expr  : bexpr [ WRT expr6 ]
48 * bexpr : rexp0 or expr0 depending on relative-mode setting
49 * rexp0 : rexp1 [ {||} rexp1...]
50 * rexp1 : rexp2 [ {^^} rexp2...]
51 * rexp2 : rexp3 [ {&&} rexp3...]
52 * rexp3 : expr0 [ {=,==,<>,!=,<,>,<=,>=} expr0 ]
53 * expr0 : expr1 [ {|} expr1...]
54 * expr1 : expr2 [ {^} expr2...]
55 * expr2 : expr3 [ {&} expr3...]
56 * expr3 : expr4 [ {<<,>>} expr4...]
57 * expr4 : expr5 [ {+,-} expr5...]
58 * expr5 : expr6 [ {*,/,%,//,%%} expr6...]
59 * expr6 : { ~,+,-,SEG } expr6
60 *       | (bexpr)
61 *       | symbol
62 *       | $
63 *       | number
64 */
65
66static yasm_expr *rexp0(void), *rexp1(void), *rexp2(void), *rexp3(void);
67
68static yasm_expr *expr0(void), *expr1(void), *expr2(void), *expr3(void);
69static yasm_expr *expr4(void), *expr5(void), *expr6(void);
70
71static yasm_expr *(*bexpr)(void);
72
73static yasm_expr *rexp0(void)
74{
75    yasm_expr *e, *f;
76
77    e = rexp1();
78    if (!e)
79        return NULL;
80
81    while (i == TOKEN_DBL_OR)
82    {
83        i = scan(scpriv, tokval);
84        f = rexp1();
85        if (!f) {
86            yasm_expr_destroy(e);
87            return NULL;
88        }
89
90        e = yasm_expr_create_tree(e, YASM_EXPR_LOR, f, 0);
91    }
92    return e;
93}
94
95static yasm_expr *rexp1(void)
96{
97    yasm_expr *e, *f;
98
99    e = rexp2();
100    if (!e)
101        return NULL;
102
103    while (i == TOKEN_DBL_XOR)
104    {
105        i = scan(scpriv, tokval);
106        f = rexp2();
107        if (!f) {
108            yasm_expr_destroy(e);
109            return NULL;
110        }
111
112        e = yasm_expr_create_tree(e, YASM_EXPR_LXOR, f, 0);
113    }
114    return e;
115}
116
117static yasm_expr *rexp2(void)
118{
119    yasm_expr *e, *f;
120
121    e = rexp3();
122    if (!e)
123        return NULL;
124    while (i == TOKEN_DBL_AND)
125    {
126        i = scan(scpriv, tokval);
127        f = rexp3();
128        if (!f) {
129            yasm_expr_destroy(e);
130            return NULL;
131        }
132
133        e = yasm_expr_create_tree(e, YASM_EXPR_LAND, f, 0);
134    }
135    return e;
136}
137
138static yasm_expr *rexp3(void)
139{
140    yasm_expr *e, *f;
141
142    e = expr0();
143    if (!e)
144        return NULL;
145
146    while (i == TOKEN_EQ || i == TOKEN_LT || i == TOKEN_GT ||
147           i == TOKEN_NE || i == TOKEN_LE || i == TOKEN_GE)
148    {
149        int j = i;
150        i = scan(scpriv, tokval);
151        f = expr0();
152        if (!f) {
153            yasm_expr_destroy(e);
154            return NULL;
155        }
156
157        switch (j)
158        {
159            case TOKEN_EQ:
160                e = yasm_expr_create_tree(e, YASM_EXPR_EQ, f, 0);
161                break;
162            case TOKEN_LT:
163                e = yasm_expr_create_tree(e, YASM_EXPR_LT, f, 0);
164                break;
165            case TOKEN_GT:
166                e = yasm_expr_create_tree(e, YASM_EXPR_GT, f, 0);
167                break;
168            case TOKEN_NE:
169                e = yasm_expr_create_tree(e, YASM_EXPR_NE, f, 0);
170                break;
171            case TOKEN_LE:
172                e = yasm_expr_create_tree(e, YASM_EXPR_LE, f, 0);
173                break;
174            case TOKEN_GE:
175                e = yasm_expr_create_tree(e, YASM_EXPR_GE, f, 0);
176                break;
177        }
178    }
179    return e;
180}
181
182static yasm_expr *expr0(void)
183{
184    yasm_expr *e, *f;
185
186    e = expr1();
187    if (!e)
188        return NULL;
189
190    while (i == '|')
191    {
192        i = scan(scpriv, tokval);
193        f = expr1();
194        if (!f) {
195            yasm_expr_destroy(e);
196            return NULL;
197        }
198
199        e = yasm_expr_create_tree(e, YASM_EXPR_OR, f, 0);
200    }
201    return e;
202}
203
204static yasm_expr *expr1(void)
205{
206    yasm_expr *e, *f;
207
208    e = expr2();
209    if (!e)
210        return NULL;
211
212    while (i == '^') {
213        i = scan(scpriv, tokval);
214        f = expr2();
215        if (!f) {
216            yasm_expr_destroy(e);
217            return NULL;
218        }
219
220        e = yasm_expr_create_tree(e, YASM_EXPR_XOR, f, 0);
221    }
222    return e;
223}
224
225static yasm_expr *expr2(void)
226{
227    yasm_expr *e, *f;
228
229    e = expr3();
230    if (!e)
231        return NULL;
232
233    while (i == '&') {
234        i = scan(scpriv, tokval);
235        f = expr3();
236        if (!f) {
237            yasm_expr_destroy(e);
238            return NULL;
239        }
240
241        e = yasm_expr_create_tree(e, YASM_EXPR_AND, f, 0);
242    }
243    return e;
244}
245
246static yasm_expr *expr3(void)
247{
248    yasm_expr *e, *f;
249
250    e = expr4();
251    if (!e)
252        return NULL;
253
254    while (i == TOKEN_SHL || i == TOKEN_SHR)
255    {
256        int j = i;
257        i = scan(scpriv, tokval);
258        f = expr4();
259        if (!f) {
260            yasm_expr_destroy(e);
261            return NULL;
262        }
263
264        switch (j) {
265            case TOKEN_SHL:
266                e = yasm_expr_create_tree(e, YASM_EXPR_SHL, f, 0);
267                break;
268            case TOKEN_SHR:
269                e = yasm_expr_create_tree(e, YASM_EXPR_SHR, f, 0);
270                break;
271        }
272    }
273    return e;
274}
275
276static yasm_expr *expr4(void)
277{
278    yasm_expr *e, *f;
279
280    e = expr5();
281    if (!e)
282        return NULL;
283    while (i == '+' || i == '-')
284    {
285        int j = i;
286        i = scan(scpriv, tokval);
287        f = expr5();
288        if (!f) {
289            yasm_expr_destroy(e);
290            return NULL;
291        }
292        switch (j) {
293          case '+':
294            e = yasm_expr_create_tree(e, YASM_EXPR_ADD, f, 0);
295            break;
296          case '-':
297            e = yasm_expr_create_tree(e, YASM_EXPR_SUB, f, 0);
298            break;
299        }
300    }
301    return e;
302}
303
304static yasm_expr *expr5(void)
305{
306    yasm_expr *e, *f;
307
308    e = expr6();
309    if (!e)
310        return NULL;
311    while (i == '*' || i == '/' || i == '%' ||
312           i == TOKEN_SDIV || i == TOKEN_SMOD)
313    {
314        int j = i;
315        i = scan(scpriv, tokval);
316        f = expr6();
317        if (!f) {
318            yasm_expr_destroy(e);
319            return NULL;
320        }
321        switch (j) {
322          case '*':
323            e = yasm_expr_create_tree(e, YASM_EXPR_MUL, f, 0);
324            break;
325          case '/':
326            e = yasm_expr_create_tree(e, YASM_EXPR_DIV, f, 0);
327            break;
328          case '%':
329            e = yasm_expr_create_tree(e, YASM_EXPR_MOD, f, 0);
330            break;
331          case TOKEN_SDIV:
332            e = yasm_expr_create_tree(e, YASM_EXPR_SIGNDIV, f, 0);
333            break;
334          case TOKEN_SMOD:
335            e = yasm_expr_create_tree(e, YASM_EXPR_SIGNMOD, f, 0);
336            break;
337        }
338    }
339    return e;
340}
341
342static yasm_expr *expr6(void)
343{
344    yasm_expr *e = NULL;
345
346    if (i == '-') {
347        i = scan(scpriv, tokval);
348        e = expr6();
349        if (!e)
350            return NULL;
351        return yasm_expr_create_branch(YASM_EXPR_NEG, e, 0);
352    } else if (i == '+') {
353        i = scan(scpriv, tokval);
354        return expr6();
355    } else if (i == '~') {
356        i = scan(scpriv, tokval);
357        e = expr6();
358        if (!e)
359            return NULL;
360        return yasm_expr_create_branch(YASM_EXPR_NOT, e, 0);
361    } else if (i == TOKEN_SEG) {
362        i = scan(scpriv, tokval);
363        e = expr6();
364        if (!e)
365            return NULL;
366        error(ERR_NONFATAL, "%s not supported", "SEG");
367        return e;
368    } else if (i == '(') {
369        i = scan(scpriv, tokval);
370        e = bexpr();
371        if (!e)
372            return NULL;
373        if (i != ')') {
374            error(ERR_NONFATAL, "expecting `)'");
375            return NULL;
376        }
377        i = scan(scpriv, tokval);
378        return e;
379    }
380    else if (i == TOKEN_NUM || i == TOKEN_ID ||
381             i == TOKEN_HERE || i == TOKEN_BASE)
382    {
383        switch (i) {
384          case TOKEN_NUM:
385            e = yasm_expr_create_ident(yasm_expr_int(tokval->t_integer), 0);
386            break;
387          case TOKEN_ID:
388            if (nasm_symtab) {
389                yasm_symrec *sym =
390                    yasm_symtab_get(nasm_symtab, tokval->t_charptr);
391                if (sym) {
392                    e = yasm_expr_create_ident(yasm_expr_sym(sym), 0);
393                } else {
394                    error(ERR_NONFATAL,
395                          "undefined symbol `%s' in preprocessor",
396                          tokval->t_charptr);
397                    e = yasm_expr_create_ident(yasm_expr_int(
398                        yasm_intnum_create_int(1)), 0);
399                }
400                break;
401            }
402            /*fallthrough*/
403          case TOKEN_HERE:
404          case TOKEN_BASE:
405            error(ERR_NONFATAL,
406                  "cannot reference symbol `%s' in preprocessor",
407                  (i == TOKEN_ID ? tokval->t_charptr :
408                   i == TOKEN_HERE ? "$" : "$$"));
409            e = yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_int(1)),
410                                       0);
411            break;
412        }
413        i = scan(scpriv, tokval);
414        return e;
415    } else {
416        error(ERR_NONFATAL, "expression syntax error");
417        return NULL;
418    }
419}
420
421yasm_expr *nasm_evaluate (scanner sc, void *scprivate, struct tokenval *tv,
422                          int critical, efunc report_error)
423{
424    if (critical & CRITICAL) {
425        critical &= ~CRITICAL;
426        bexpr = rexp0;
427    } else
428        bexpr = expr0;
429
430    scan = sc;
431    scpriv = scprivate;
432    tokval = tv;
433    error = report_error;
434
435    if (tokval->t_type == TOKEN_INVALID)
436        i = scan(scpriv, tokval);
437    else
438        i = tokval->t_type;
439
440    return bexpr ();
441}
442