An example of an expression parser with optional symbol handlers. The symbols, if desired, can be handled with either a balanced tree or a hash table.
The last project I worked on came with a terrible expression parser. It had no operator precedence and a syntax error sent it into an infinite loop. There was no time available to swap it out with something better.
With that project long since put to rest and with me having nothing better to do and to prove to myself it can't be that hard to do, I decided to write my own expression parser from scratch just for the fun of it. This code is just example code. It isn't used in a production system (yet) so it likely has some yet to be discovered and failing dusty corner conditions. Use at your own risk. Or better still, just use it as a starting point and make something better.
It consists of three separate independent subsystems I believe suitable for use in a common library:
lib_btree - a balanced binary tree using the AVL algorithm coded with what was in Wikipedia. Contained entirely in lib_btree.[ch].
They can be found in the libs folder. There are Makefiles but they have only been built with gcc. Good luck building with other compilers.
The API's to each of the three subsystems are described via comments in the corresponding .h files.
The symbols can have a value type of string, integer or double. If a string term appears in the expression terms (after normal evaluation) are converted to strings and prefixed or concatenated with it leaving the final result always being a string. String terms in an expression may only be joined with a +. I.e. "foo"+10/2 results in "foo5" or "foo"+"bar" becomes "foobar" or 10/2+"foo" becomes "5foo".
For an example on how to use lib_exprs without needing or wanting symbols, see exprs_test_nos.c. I.e. ./main '1+2*3/4'
For an example on how to use both lib_exprs and lib_hashtbl, see exprs_test_ht.c.
For an example on how to use both lib_exprs and lib_btree, see exprs_test_bt.c.
I.e. when using symbols: ./main 'sym1=10;sym2=20;sym3=sym1+sym2;sym3*3.14159'.
Although the standard libc btree and hash functions no doubt work just fine, I was disappointed they had no user provided mechanism for memory management nor anything that might help with statistics collection. So these provided subsystems have optional callbacks for that as well as internal message reporting.