Posterous theme by Cory Watilo

Filed under: programming

DSLs using Unix shells

Back when I was in graduate school writing lots of Lisp code (and I do miss writing Lisp code) I frequently made use of macros to create small domain specific languages (DSLs). Now that I am working on a team writing C/C++ and shell scripts, breaking out the macro-esque code is a little more difficult.

That said, it’s not impossible. I haven’t written enough C/C++ to do much with preprocessor pseudo-macros, but I have written a lot of shell scripts. And I’ve found you can get a good taste of Lisp-style macros in some circumstances.

One situation that I like to employ them is with configuration files. More specifically, these are configuration files that will be sourced by a running shell (using the source or . command). While writing shell-based infrastructures, I’ve often found that you end up putting lots of things in configuration files. You might end up with something like this:

FOO_args=aaa
BAR_args=bbb
BAR_elements=ccc

This can get out of hand quickly; parameter names on the order of 25 to 40 characters is not unheard of. I find this hard to read and error prone when editing it on a live system (especially embedded ones where you have a limited set of tools).

If find the following a little easier to work with:

foo
{
    define args=aaa
}

bar
{
    define args=bbb elements=ccc
}

Sure, it’s more lines, but it immediately tells you quite a bit about what the configuration settings are meant to do. In short, it says it better.

The question is, how can this be turned into something the shell can evaluate that will result in the definitions being accessible to the rest of the code?

Consider the following:

#!/bin/bash

SCOPE=

function configure
{
    unset SCOPE
    SCOPE=$(echo ${1} | tr '[[:lower:]]' '[[:upper:]]')
}

function define
{
    for def in ${@}; do eval "${SCOPE}_${def}"; done
}

With a slight modification to the idealized configuration code above, the objective of defining the same parameters with a different syntax is achieved.

#!/bin/bash

. ./function-defs.sh

configure foo
{
    define args=aaa
}

configure bar
{
    define args=bbb elements=ccc
}

echo "FOO_args is ${FOO_args}"
echo "BAR_args is ${BAR_args}"
echo "BAR_elements is ${BAR_elements}"

Of course, this example is for demonstration purposes and things can get more complicated; consider the case of configure only working in certain circumstances and thus, making define a no-op.

All in all, this technique has made some things a lot simpler for me in some cases.

My year in Lisp

Xach asked about your year in Lisp on reddit (*). Rather than get a reddit account just to answer the comment, I figured I'd answer here.

Early in the year I got a good chunk of a UNIVAC I emulator working; however, the annoying ambiguities in the representation of numbers caused that to stall. I should finish it and put it on GitHub (assuming there are no licensing problems), so that will be my first 2011 Lisp resolution.

Most of the rest of my time was spent dabbling with adaptive systems writing experiments that generally didn't go anywhere. I tried "growing" a system from some basic elements but couldn't get a good handle on what it is I wanted for some time. I finally decided on making functions the basic element of computation with the following properties:

  • each is a separate entity/object;
  • the initial form of communication is a single, bivalent stream of bits (likely UTF-8 characters);
  • they can change their configuration (for example, add more communication streams);
  • they can clone themselves.

I haven't decided on the atomic operations yet. I'm not even sure arithmetic will qualify.

Obviously this is not meant to be a terribly useful set of definitions at the outset. I'm really looking at ways to build functions/programs that can adjust to their environment without having to maintain them, that is, without having to port them to a different system.

I also couldn't make it to ILC 2010 due to my job, which is too bad since the conference was in North America and not all that difficult for me to get to.

It was a quiet year. Hopefully I'll have more to say in 2011.

(*) Yes, I used to have a reddit account but I got tired of the place a while ago and closed it.