Config Parser

The Config Interpreter

Download This is an interpreter for a tiny language suitable for defining the syntax of config files. It's more concise than XML, and a lot less hassle than manually parsing. It can also be used for light application scripting. Depending on how you use it, it can be Turing-complete, but it is easy to limit functionality so the user doesn't do anything wrong if his code is untrusted.

DESIGN

The interpreter is based around a stack, like Forth. The language consists primarily of a sequence of code words. Each code word is either data which gets pushed on the stack, or a function which gets executed and may push or pop things from the stack. Sequences of functions and data can themselves be pushed on the stack, allowing iteration and conditional constructs.

SECURITY

All of the functions are defined by your program, meaning the user can't do anything you don't let him. It is a "whitelist" policy instead of a "blacklist" policy. Every value on the stack has a type tag, preventing the user from performing invalid operations. In addition, you can impose limits on the user's memory usage and execution time, preventing him from monopolizing your system.

SYNTAX

  1. A function is any sequence of characters other than {}()[]# or ;. Functions must be separated by whitespace or by {}()[]# or ;.
  2. Numbers are provided as doubles, like 5, 4.6, or -94.
  3. Strings are delimited by matching curly braces: {this{i{s}}[a](((string;} The reason for this unconventional choice is that strings will often contain other strings (for example, if the string is a program to be executed later) so you can nest one string in the other without having to escape the {}. A single unmatched { or } can be placed into the string using \{ or \}. The escape sequences \n and \\ are also provided.
  4. An expression delimited by matching square brackets is a "closure." It gets pushed on the stack as one unit instead of being executed.
  5. Comments begin with a ; and go until the end of the line.
  6. Normally, since this is a stack-based language, you write the function AFTER its arguments. However, in a concession to readability, any expression enclosed by parentheses gets moved one spot to the left. For example, F (1 2 3) is syntactic sugar for 1 2 3 F.
  7. Writing #SOMEVAR pops the top value off the stack and stores it in SOMEVAR. Afterwards, writing SOMEVAR pushes onto the stack the last value stored into SOMEVAR.

HOW TO USE IT

(See include/interp.h and examples/ for more detail)

Include interp.h and link with interp.c. Define functions that you would like the user to have. For example, if you want the user to specify the screen width and height, you could define a function SCREEN that sets the resolution so that the user puts SCREEN(640 480) in his config file. Functions shall be void and take no direct arguments, instead popping from the stack. Call initialize_interpreter with a list of your functions, and then call new_session(parse_script(configscript)) for each script you wish to execute.

Exactly what the syntax looks like in a particular script file depends on what functions you give the user. Even loop constructs are not built in, but are simple to implement with a function (see the examples directory). Suppose that you want the user to specify a "dog" data structure. You might define a function to let him do this:

DOG(15 4 {tan} {dachsund})

where DOG is a function that defines a dog for the benefit of your program, in this case producing a 15 pound tan dachsund who is 4 years old. Suppose however that you want to let the user specify _some_ attributes of the dog, the number not known in advance, letting other attributes be default. One way to do it looks like this:

DOG AGE(4) BREED({dachsund}) END

Here DOG pushes a default dog onto the stack. AGE pops the dog and "4" from the stack, sets the dog's age to 4, and pushes the dog back onto the stack. BREED behaves similarly, and END removes the completed dog from the stack.
Here is an example of a config file made with this interpreter, which was used in this project. Looking at the config file, note:

LICENSING

I am releasing my source code for this interpreter under the GPLv3. If you use it, send me a message.

© Bart Parkis
Last modified:Tue May 19 19:07:52 2009