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

Operator precedence is roughly the same as the C language.

   ( )  higher
   * /
   + -
  ^ & | lower
  
Prefixing integer tokens with minus '-' to indicate a negative value is currently not supported.

Example 3. A Simple Calculator
The following example illustrates how to use the eval module with a hashmap(3m) as a symbol table to make a simple commandline calculator.


  #include <stdlib.h>
  #include <string.h>
  #include <stdio.h>
  
  #include <mba/hashmap.h>
  #include <mba/eval.h>
  
  int
  symtab_lookup(const unsigned char *key, unsigned long *val, struct hashmap *symtab)
  {
      const unsigned char *str;
  
      if ((str = hashmap_get(symtab, key))) {
          *val = strtoul(str, NULL, 0);
          return 0;
      }
  
      return -1;
  }
  int
  main(void)
  {
      struct hashmap symtab; 
      unsigned char buf[1024], *bp = buf;
      unsigned long result; 
      struct eval *eval = eval_new((symlook_fn)symtab_lookup, &symtab);
  
      hashmap_init(&symtab, 0, hash_str, cmp_str, NULL, NULL);
  
      while ((*bp = fgetc(stdin)) > 0) {
          if (*bp == '\n') { 
              *bp = '\0'; 
              bp = strchr(buf, '=');
              *bp++ = '\0'; 
              eval_expression(eval, bp, bp + strlen(bp), &result);
              sprintf(bp, "%u", result);
              printf(" %s=%ld\n", buf, result);
              hashmap_put(&symtab, strdup(buf), strdup(bp));
              bp = buf;
          } else {
              bp++;
          }
      }
  
      return EXIT_SUCCESS;
  }
  output:
  $ ./calc 
  foo=0xffff
   foo=65535
  bar=10 * foo & 0x3333
   bar=13106
  

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 map 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>