VSEP - The Very Simple Expression Parser (and solver) Library


About

VSEP is a C library for parsing and solving very simple expressions.It can parse and solve expressions like:

(a + b + c)

f(b , c , d , -1.0001e-5) & g(2 * b)

f()

Where a, b, c and d are variables that can be specified at runtime
f and g are function, also specified at runtime.
The & is logical AND
The + is numeric addition
and the * is numeric multiplication.

VSEP uses lazy evaluation. Any variables and functions are specified at runtime using callbacks in the form of C function pointers, and VSEP calls those callbacks so that the function is evaluated in the "simplest" way. Because it is possible to pass VSEP a "difficulty function" returning the "difficulty" of getting some variable or function for every "callback function", the word "simplest" is easy to define.

The word "simplest" here means that VSEP first tries to simplfiy the expression with all non-function and non-variable types. For example, it would simplify (1 + 1) to 2 or (1 | b) to 1. Then, it fetches the value of that function or variable with the lowest "difficulty" from its respective C callback function. It then tries to simplify the tree again. Then it gets the function or variable with the 2nd lowest "difficulty", tries to simplify, etc.. This means that for the expression (1 | b), the variable b is never evaluated.

VSEP is intentionally not a Turing Complete Programming Language, instead trying to do only one simple thing, and to do it well.


Example Scenario

VSEP can be used in situations where one wishes to alter the control flow of a program at runtime in ways dependent on various variables within a program.

For example, one might have a configuration file with a "permission" field, and have that field contain:

(isAdministrator(user) & !(fileExists('/blacklists/' + user)))

Note that in VSEP, the '+' operator for strings denotes string concatenation
Note also that numbers are converted to strings when adding numbers to strings.

The following example will show a way how this can be done using VSEP. Of course, you might ask yourself why we would wish to have so much code for such a (relatively) simple logical AND operation. The answer is that for doing the operation in one place, you will save no time or effort using VSEP. However, if you wish to do similar operations very often in your program, or want your permissions configurable in a configuration file at runtime, VSEP might be what you are looking for.

Let's assume that the string above is available to our C program as const char* permission_expression.

We also have the following C functions specified somewhere:
Note that this code simply represents an example vsep callback function.
vsep_data* my_callback(const char* name, int argc, vsep_data** argv, void* context)
{
     //Let's assume context is a pointer to an integer with the current userid
	vsep_data* result = NULL;
	if(!strcmp(name,"user") &&(argc == -1))
	{ 
		long int userid = (long int) *((int*) context);
		result = vsep_data_new_int(userid);
		return result;
	}else if(!strcmp(name,"isAdministrator") && (argc == 1))
	{ 
		//Let's assume that in this situation,
		// all administrators have userids of less than or equal to 100 
		vsep_data* argument1 = argv[0];

		//The following line checks whether the argument provided is an integer or not.
		if(argument1->type != VSEP_TYPE_INT) return vsep_data_new_int(0);

		if(*((long int*) argument1->data) <= 100) return vsep_data_new_int(1);
		else return vsep_data_new_int(0);
	}else if(!strcmp(name,"fileExists") && (argc == 1))
	{
		const char* filename = NULL;
		FILE* my_file = NULL;
		int file_exists = 0;

		//It only makes sense to check for filenames that are strings:
		//It is an error if they are not, hence we return the special NULL type.
		//See SPEC for details, but most operations that involve NULL also return NULL

		if(argv[0]->type != VSEP_TYPE_STRING) return vsep_data_new_null();

		filename = argv[0]->data;
		my_file = fopen(filename,"r");
		if(my_file)
		{
			file_exists = 1;
			fclose(my_file);
		}

		return vsep_data_new_int(result);
	}

	return NULL;
}
Our C program would then initially run:

vsep_tree* t = vsep_parse(permission_expression);
vsep_tree_add_callback(&my_callback,NULL,t);

Whenever we wanted to then check whether the user with userid in int userid; had the right permission, we would do:
	vsep_tree_set_callback_context(&my_callback,&userid,t);
	vsep_tree_solve(t);
	int result = vsep_tree_is_true(t);
	vsep_tree_reconstruct(t); //This line makes it possible to run this whole block of code over and over again.

Or, even simpler, we coud simply do the equivalent:
	int result = vsep_tree_execute_with_extra_callback_function(t,&my_callback,NULL,&userid);

Note that then we would not need run vsep_tree_add_callback initially for this method.

Either way, int result would hold whether the expression was true or not in the end.

Finally, we run to free any resources allocated.
	vsep_tree_free(t);


Installation Instructions

So you may (or may not) have looked at the Example above or other documentation, and decided that you want to install vsep. This is relatively easy. First, download the source code, and unpack it. Then either run ./INSTALL, or read the INSTALL file.
To install vsep, you will need probably need gcc. However, if you try compiling vsep with a compiler that is not gcc and find an error, please report a bug.
vsep has very few dependencies. To build it however, you will need a c compiler, automake and libtool.


Download

There are several ways to get vsep. You can use git to download the source code
Or, you can download the sourcecode from the most recent of these files. There are no binary packages available yet, hopefully one day.


vseptester

The vseptester command line utility is useful for playing around with VSEP. It is not compiled by default when installing vsep. To compile it, run make vseptester from within the source code directory. Then run ./vseptester to display the usage information for vseptester. A typical usage for vseptester would be vseptester "1 + 2 + a" Note that vseptester has a sample callback that returns 31415 for all one-letter variable and function names that are not '!' or '_'. It registers the difficulty of getting variable (or function) 'a' as 5, 'b' as 10 and any other as 2. Vseptester also has the callback from the Example above added to the callback tree. Hence use the isAdministrator and fileExists if you wish.

FAQ

No questions have been asked so far. Ask some, by emailing natschil_at_users.sourceforge.net

SPEC

So you'd like to know all the features of vsep. Well here is a kind of specification
Contribute

There are several ways to contribute to VSEP. The first is by using it. If you find any bugs, report them! The second way is to consciously hunt for bugs in the code. The third is to donate money. When you donate money, it sits around for 2 months. If anybody other than Nathanael Schilling finds a bug and what part of the C code that causes that bug is in VSEP during that time, they get that money. After that, it goes to Nathanael Schilling. A lot of time was spent coding vsep, so if you've used it and are happy with how it works, consider contributing. Or not. It's free software, so do whatever you like. Currently, the only way to contribute is by bitcoin. Hence if you want to get rid of bitcoins, contribute to 1KCD99Z1Kcn49gT3kFUpxKhYgQa4yLtLR1


Bugs

If you can prove that you've found a bug in VSEP, including the place in the source code causing the bug, you get all the bitcoins donated to vsep in the past two months. Note that this does not include the vseptester utility. Bugs include non-standard (c99) C code, undefined behaviour, etc. These bugs are limited to the vsep library, i.e. the vsep.c and vsep.h files. Please also report improvement suggestions, spelling mistakes anywhere, etc. Email any bug reports or improvement suggestions to natschil_at_users.sourceforge.net.


Liscencing

VSEP is liscenced under the MIT liscence, see the COPYING file in the source code for details. VSEP is liscenced that way because basically it allows you to do (almost) anything with the code. If you wish to do even more, email natschil_at_users.sourceforge.net. If you use vsep in any of your code, consider sending me a one-liner "I am using vsep in project foo", as I'd be interested in knowing where/if this code is being used.



© 2013 Nathanael Schilling