trivial-configuration-parser is a trivial parser library for configuration files. Here, configuration files have a simple syntax: named modules contain groups of keys and modules; individual keys are assigned a value by key = value. Semicolons are optional and are treated as whitespace; any whitespace can separate groups of key = value. A hash mark (#) starts a comment to the end of line.

If you're wondering why one would use this instead of s-expressions, scroll down.

See the file demo.conf included in the source for a demonstration configuration file.

The trivial-configuration-parser package, also called tconf, exports five symbols:

  Parses the configuration file given by the supplied pathname and
  returns something which can be accessed with CONFIGURATION-VALUE

CONFIGURATION-VALUE parsed-file key module1 module2 ...
  Given a key and a list of modules in inner->outer order, returns
  the value that the key has. If no key with that name is found in
  this module path, or the module path does not exist, an error is
  signalled. If there is a duplicate key with this name in that
  module path, or a duplicate module name corresponding to that path,
  an error is also signalled.

CONFIGURATION-VALUES parsed-file key module1 module2 ...
  Given a key and a list of modules in inner->outer order, returns all
  values that the key takes in modules named by the given modules. If
  the key cannot be found in the given modules, returns the empty

WRITE-CONFIGURATION-FILE parsed-file options-to-open ...
  Given a parsed configuration file (see below for a description of
  the contents), and extra arguments which will be passed to CL:OPEN,
  writes the file to the pathname that's specified in the
  configuration file.

The symbol TCONF:MODULE-MARKER is not defined and used to mark modules in the parsed configuration file.

A parsed configuration file is represented as a cons of the pathname where the configuration file is loaded from or saved to on disk and a list of key / value or key / module pairs. A key / value pair is a cons of a keyword symbol and some value. Because the sharp-sign (#) reader macro is used for comments, only symbols, lists, numbers, and strings can directly be written to or read from a configuration file. All symbols will be dumped without any package prefix and read back in to the keyword package.

A key / module pair is a cons cell of a keyword symbol and another cons cell, whose car is the symbol TCONF:MODULE-MARKER and whose cdr is a list of key / value or key / module pairs.

The configuration file:

foo {
    bar = (1 2 3);
    baz {
        bat = "Hi!";

Is represented as:

(#P"/path/to/foo.conf" (:foo trivial-configuration-parser:module-marker (:bar 1 2 3) (:baz trivial-configuration-parser:module-marker (:bat . "Hi!"))))


I'm not sure that I understand the point of this. Why does it not use s-expressions? What benefit does it gain from using its own syntax? Isn't it less trivial to implement on account of having to do its own parsing? -- Dan Knapp

More than one person has asked me why I would use this instead of using s-expressions. Actually, trivial-configuration-parser files are s-expressions, of a sort. The parsing goes through the lisp reader, which is entirely obvious from the source code. The readtable is hacked a bit to read these files permissively. A simple loop turns them into the slightly nicer alist-style representation above; ordinarily they come in as something like (:foo := "bar"). How else could I parse these in 50 lines of Lisp?

The goal here was to create a configuration format that non-lispers would find familiar and to reduce the chances of the user screwing up the file in some non-obvious way, particularly when the user isn't using emacs to edit the configuration file. If this isn't of value to you, move along.

Personally, I think it's worthwhile a demonstration of how to use the Lisp reader to parse something which looks little like Lisp, if nothing else.