This blog isn’t dead, it just smells that way. Actually, we have been having trouble with our ISP – something configuration has changed that causes the worker process in which context out web-application runs, to not have write permissions to the web folder where the entries and comments are stored. So that means that I cannot make blog entries and no one cane post comments. We need to have this sorted out or move to another ISP real quick. For now my solution is to generate the blog entry xml file on my local computer and upload it via ftp. That’s how you are seeing this entry.
Now to the real topic of this post - I have been toying around with Scheme for some time now – I would like to say a long time – but considering how long scheme has been around (as opposed to say C#), my time is not that long.
Over the weekend (literally) I have made for myself a compiler that compiles a language that has a lot of braces. I would really like to say that it is scheme – it is not – but it is very scheme-like. Why it is not scheme -
- It is a subset of the language
- It has some differences in semantics even in the subset that I managed to implement
Sometime last Thursday I watched a 90 minute video that shows how one can write a Scheme to C compiler. Sidharth originally pointed me to this. Well, I didn’t watch all 90 minutes – shortly after the 60th minute or so I jumped up all charged up, ready to write a scheme compiler.
What the video showed me is how to solve some hard problems in scheme compilation – basically how get rid of closures and continuations. The video shows you how to do a closure conversion and CPS conversion. Those very two issues about scheme compilation that I had nagging for sometime – watching the video took them away.
This is the subset of scheme that I implemented so far. It has support for lambda, define, if and lists. In terms of library which is in C# and is extensible and I have +, =, car, cdr, cons, display, remainder, newline etc.
So effectively I can compile code like this
(define print (lambda (s)
(display "Value is ")
(display s)
(newline)))
(define gcd (lambda (a b)
(if (= b 0)
a
(gcd b (remainder a b)))))
(print (gcd 50 70))
and compile it to generate a .Net exe that actually runs :)
This has been really good fun and a rather creative thinking exercise. I currently plan to take it forward and implement a few more things I am curious about. Its good fun to see what code like this does to your thinking about things.
Right now the code flow of the compiler is structured like this –
Scanner -> Parser -> [Abstract Syntax Tree] -> Code generator -> exe
The once I have a stable code generator, I am expecting that instead of focusing on being able to compile every construct in scheme, I can translate constructs down into the simpler constructs which the code generator already handles.
For example I don’t intend to compile a ‘cond’ statement – instead I would take the AST that has the ‘cond’ and transform it into an AST which can the ‘cond’ replaced with a nested ‘if’. Similar closure conversion and CPS conversion (continuation passing style conversion) would be other AST transforms.
So the code flow would be like this –
Scanner -> Parser -> [AST] -> AST Transforms -> [AST] -> Code generator -> exe
Once I have the present code a little stabilized and I have a framework for doing tree transforms, I should have a fairly complete implementation of a scheme like language.
Things I cant solve -
Why I say scheme-like language is because I doubt if I will ever actually implement a whole standards compliant system – simply for the sheer effort. That aside I presently don’t know enough to be able to compile some aspects of the language.
In scheme not many things have special status. As an example variable name is simply a binding to some value.
So I can say -
(define x (lambda (a) (+ a 10)))
which binds variable x to a lambda (a function) that takes a parameter and adds 10 to it and returns it.
Now I can call it and assign the result to another variable ‘a’ -
(define a (x 10))
Now in the same program I can define x to be something else, say just a number…
So typing of variables go for a toss. Similarly I cannot really hardcode any function calls in the generated code – I have to indirect them through a variable that holds a delegate, because at runtime I cannot really know which function that variable is bound to. But those are solvable problems.
The hard problem comes up when you deal with what scheme calls special forms. As an example ‘if’ is a special form.
(if (= a b) (display a) (display b))
Here either value of ‘a’ is displayed, or value of b is displayed.
Now it is not possible to implement ‘if’ using a function call. Because whenever you call a function, all the arguments to the function are fully evaluated. So if there was a function called ‘if’ the condition, then and else parts would be evaluated before the ‘if’ function is called. So in this case the user would see both ‘a’ and ‘b’ being displayed. So ‘if’ has to be treated differently by the compiler and I have to generate test and branch instructions for the ‘if’.
The problem comes in the fact that the user can perfectly well say something like this –
(define if 10)
So from now on ‘if’ is 10.. that’s crazy because that’s a runtime condition, whereas my compiler has already generated test/branch code for the if.
When writing a compiler and I see ‘if’ I emit intermediate code which tests a condition and braches to the right code block for execution. If at runtime the meaning of the ‘if’ itself changes then the branching and compile time generated code has no meaning.
You may argue that in the case of ‘if’, I can solve the problem by having variable that indicates the current value of ‘if’ and at compile time I can generate code for an additional check with this variable. However that’s a limited hack… and it doesn’t explain what I will do when at runtime the meaning of ‘define’ changes or the meaning of ‘lambda’ changes.
I cant solve this problem right now, I don’t know how to – so I have given define, lambda and if a special ‘keyword’ like status – similar to keywords in other languages where keywords cannot be redefined to mean something else at runtime.
I don’t know if this is a problem I will be solving also.
Things I hope I can implement
- closures
- continuations
- more special forms (list, quote)
- a better function dispatch mechanism (generate the delegates types)
- tail calls
- cond, let, letrec
Here is my early ‘over-the-weekend’ quality scheme compiler for download. Use with caution.
This also requires the elusive .Net 2.0. I am not releasing source just yet, but it will come.
However, if you are looking for an actual full fledged compiler scheme compiler for .Net GotDotNet lists the following -
|
Scheme |
Northwestern University Hotdog Scheme |
|
Scheme |
Tachy (Scheme-like) language |
|
Scheme |
Indiana University Scheme.NET |
You may have more luck with these.
You may not be able to leave comments on my blog right now.
Do send me mail for now roshan -dot- james -at- gmail -dot- com.