Eval

# 6. Eval

The eval(3m) module will evaluate simple arithmentic expressions consisting of integers, symbols for which the provided `symlook_fn` returns an integer, and any of the operators `|&^+-*/()`. Operator precedence is roughly the same as the C language; '(' and ')' are higher than '*' and '/' which are higher than '+' and '-' which are higher than '^', '&', and '|'. Prefixing integer tokens with '-' to indicate negative values is currently not supported.

Example 3. A Symbol Lookup Table
The following example illustrates how to use the `eval` module with a symbol table to evaluate a simple arithmetic expression from the commandline.

      #include <stdlib.h>
      #include <stdio.h>
      #include <mba/eval.h>
      #include <mba/msgno.h>

      struct {
      	const tchar *name;
      	const unsigned long val;
      } symtab[] = {
          { _T("N"), 3 },
          { _T("MAXVALUES"), 0xFFFF },
          { _T("whatever"), 100 }
      };

      int
      symbol_lookup(const tchar *name, unsigned long *val, void *context)
      {
      	int i;

      	for (i = 0; symtab[i].name; i++) {
      		if (tcscmp(symtab[i].name, name) == 0) {
      			*val = symtab[i].val;
      			return 0;
      		}
      	}

      	return -1;
      }

      int
      main(int argc, char *argv[])
      {
      	unsigned long result;
      	struct eval *eval = eval_new(&symbol_lookup, NULL);

      	if (eval_expression(eval, argv[1], argv[1] + strlen(argv[1]), &result) == -1) {
      		MSG("");
      		return EXIT_FAILURE;
      	}

      	printf("%s = %ld\n", argv[1], result);

      	return EXIT_SUCCESS;
      }
      output:
      $ ./eval '(5 + 3) * N'
      (5 + 3) * N = 24

Large tables should be generated with a program that sorts the identifiers so the the `symlook_fn` can perform a binary search (see end of `wcwidth.c`).

### 6.1. The Eval Functions

The `eval_new` function
Synopsis

      #include <mba/eval.h>
      struct eval *eval_new(symlook_fn symlook, void *context);

Description
The `eval_new` function creates and returns a new context object for evaluating expressions. The `symlook` parameter is defined as follows:

      typedef int (*symlook_fn)(const tchar *name, unsigned long *val, void *context);

The `symlook_fn` function will be called to resolve any non-numeric symbols and should place the value identified by `name` into `val` and return 0. If the symbol is not found -1 should be returned.

The `eval_new` function can be used repeatedly to evaluate any number of expressions before being destroyed with the `eval_del` function. The `context` parameter is passed uninterpreted to the `symlook_fn` (e.g. a hashmap perhaps).

The `eval_del` function
Synopsis

      #include <mba/eval.h>
      void eval_del(void *eval);

Description
The `eval_del` function deletes the context object `eval` freeing any memory allocated with `eval_new` or during the evaluation of expressions.

The `eval_eval_expression` function
Synopsis

      #include <mba/eval.h>
      int eval_expression(struct eval *eval, const tchar *expr, const tchar *elim, unsigned long *result);

Description
The `eval_expression` function evaluates an infix expression like `'(5 + 3) * N'`, converts it into a stack of tokens in postfix orientation, and reduces it with a simple translation matrix to produce a single integer value. The `eval` parameter is a context object created with `eval_new`. The expression at `expr` is evaluated up to, but not including, the memory at `elim`, and writes the resulting value in the memory at `result`.
Returns
The `eval_expression` function returns 0 if the expression was successfully reduced or -1 if an error occured in which case `errno` will be set appropriately (e.g. `ENOENT` if the `symlook_fn` could not resolve a symbol).

Copyright 2003 Michael B. Allen <mba2000 ioplex.com>