09 Nov 2014

So I’ve got another personal project I’ve been working on. Here’s the README:

C-Ast is a GNU Guile library for generating C code. There are some examples in the example directory, but briefly, it lets you turn s-expresions like:

(for ((= i 0) (< i limit) (+= i 1))
    (call printf "i = %d\n" i))

Into C source code:

for (i = 0; i < limit; i += 1) {
    printf("i = %d\n", i);

…which can then be fed through a C compiler.

This is interesting because it allows use of scheme to easily manipulate C programs – many the same benefits of a proper lisp-style macro system can be used to write low-level code.

The intention is for this to be a building block for building other tools.

C-Ast is still in a very early stage of development – you can write hello world, but it’s missing a lot of important features and some documentation, and probably isn’t packaged the way a guile library should be – I’m still very new to the language.

I got your standard hello world program working this week. When building tools like this, the value of actually trying to use it can’t be understated; “Let’s try to write hello world” brought me to a lot of realizations like “You can’t call functions yet” or “you don’t have string literals” – really obvious stuff that I just hadn’t written yet. I then tried a more complicated program: cat. Here’s what I’ve got so far:

(ld "cat"
    (cc "cat"

        '(!include<> "stdio.h")

        '(def copy (func int (in (ptr FILE)) (out (ptr FILE)))
              (decl c int)

              (while 1
                  (= c (call fgetc in))
                  (if (== c EOF)
                    (return 0))
                  (call fputc c out))))

        '(def main (func int (argc int) (argv (ptr (ptr char))))
              (decl i int)

              (if (<= argc 1)
                  (call copy stdin stdout)
                  (return 0)))

              (for ((= i 1) (< i argc) (+= i 1))
                (+= argv 1)
                (if (== (call strcmp 

I had originally planned to do this with a buffer as a global variable, using read and write, but quickly realized that I didn’t have a way to declare arrays. “Okay, need to add that. For now I’ll just use stdio, which will do the buffering for me, and may be a better approach anyway.” Well… I also needed to be able to index arrays to iterate over the arguments to main. I added that to the TODO list, and said, “I can use pointer arithmetic and dereference argv as needed – not exactly idiomatic, but it should work.” Except no dereference operator. Poop.

Well, now I have a list of the next few features to add. Woo.

Here’s the code

What happened to Zlisp?

I kinda promised promised myself not to start any new projects until I’d finished the last one. That… didn’t work. I see a couple problems with this plan in hindsight:

  1. Ill defined goal – when is it “done?”
  2. As mentioned, it’s really good to shake out your design by using it quickly. I didn’t quite have an idea of what sort of programs I wanted to write in Zlisp, and I failed to get things working quickly enough to be able to do that. I’m not sure what I could have done about that in this case. Maybe I could have taken an approach that would have let me prototype more quickly.
  3. This was too strict – sticking exclusively to one thing until it’s done is just not something I do. Yeah, that’s kinda the point, but the longer I tried to do this the more restless I got. I also started working on other things, with no intention of doing more than playing around a bit for an afternoon. This seemed to satisfy my concious, but I’d spend more and more time not working on Zlisp as a result.

In any case, Zlisp is more or less abandoned at this point.