A meta compilation framework for Ruby à la Meta-II by Val Schorre.
This uses a C version of Meta-II developed by Long Nguyen to bootstrap a Ruby version from a fully self-contained, 26 (non-empty) line specification file. The generated Ruby Meta-II compiler file is 231 lines of Ruby code. A more readable and commented version of the specification file is available here. It also has better error handling both when used from the command line and when compiling (but it is longer, 73 loc for the spec and 328 loc for the generated compiler).
There is also a more useful meta compiler, based on the readable one, which accepts regexps and comments in the syntax file. Here is an example syntax file for a compiler that uses both regexps and comments.
Clone the git repo and then run:
rake bootstrap
and it will bootstrap and print info about each step. This requires gcc, rake and a recent ruby.
If you only want the finished result you can just install as a gem:
gem install meta_compile
since it is available on rubygems.org.
In your local copy of the git repo, use the pre-generated binary to compile the specification file to a ruby file:
bin/meta_compile syntaxes/meta_to_ruby_minimal.meta > t.rb
This generates a t.rb which is itself a compiler for meta syntax specs. So lets use it to generate itself:
ruby t.rb syntaxes/meta_to_ruby_minimal.meta > t2.rb
And ensure they are really the same:
diff t.rb t2.rb
To be really sure we can try the generated t2.rb as a meta-compiler:
ruby t2.rb syntaxes/meta_to_ruby_minimal.meta > t3.rb
and this should convince us:
diff t2.rb t3.rb
- Rudimentary error handling/reports while compiling/parsing
Once the first meta compiler is up and running we can evolve the language. For example I made a change so Ruby regexps can be used instead of only string literals. Note that we need to use a stepping stone syntax file before we can create a new meta compiler that accepts the new syntax.
Let's use this to compile programs which can only contain assignments of numbers to variables:
.syntax assignments
assignments = as *as;
as = /\w+/ <'address ' $> ':=' ex1 <'store'> ';';
ex1 = /\d+/ <'literal ' $>;
.end
The new thing here compared to the original Meta-II syntax is the two Regexp's (in as and ex1). First we need to bootstrap the meta compiler that accepts regexps:
rake boot_regexp
Then we create a compiler for the assignments syntax:
ruby bin/metac_regexp syntaxes/assignments.meta > tas.rb
We now have a compiler for assignments and if we apply it to the file:
a := 137;
b := 4;
by running the command:
ruby tas.rb inputs/assignments.input1
it prints:
address a
literal 137
store
address d
literal 4
store
Not bad. :)
Since it is so easy to implement with the regexp-capable compiler later. See the example compiler for assignments above, for example.