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>