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
(begin
(= 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)
(begin
(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.
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:
- Ill defined goal – when is it “done?”
- 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.
- 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.