This is part 9/9 of Creating your own programming language with ANTLR.
Welcome to the final part of the tutorial. If you want to try to finish (some of) the implementation of the TL-node classes on your own, make sure you're up to date with the latest source files developed so far: download them here. You'll want to test your implementation using the test script below.
In order to test all functionality of TL, replace the contents of the test.tl file with the following source:
/* A script for testing Tiny Language syntax. */ // boolean expressions assert(true || false); assert(!false); assert(true && true); assert(!true || !false); assert(true && (true || false)); // relational expressions assert(1 < 2); assert(666 >= 666); assert(-5 > -6); assert(0 >= -1); assert('a' < 's'); assert('sw' <= 'sw'); // add assert(1 + 999 == 1000); assert( + 1 == [1,1]); assert(2 - -2 == 4); assert(-1 + 1 == 0); assert(1 - 50 == -49); assert([1,2,3,4,5] - 4 == [1,2,3,5]); // multiply assert(3 * 50 == 150); assert(4 / 2 == 2); assert(1 / 4 == 0.25); assert(999999 % 3 == 0); assert(-5 * -5 == 25); assert([1,2,3] * 2 == [1,2,3,1,2,3]); assert('ab'*3 == "ababab"); // power assert(2^10 == 1024); assert(3^3 == 27); // for- and while statements a = 0; for i=1 to 10 do a = a + i; end assert(a == (1+2+3+4+5+6+7+8+9+10)); b = -10; c = 0; while b < 0 do c = c + b; b = b + 1; end assert(c == -(1+2+3+4+5+6+7+8+9+10)); // if a = 123; if a > 200 do assert(false); end if a < 100 do assert(false); else if a > 124 do assert(false); else if a < 124 do assert(true); else do assert(false); end if false do assert(false); else do assert(true); end // functions def twice(n) temp = n + n; return temp; end def squared(n) return n*n; end def squaredAndTwice(n) return twice(squared(n)); end def list() return [7,8,9]; end assert(squared(666) == 666^2); assert(twice(squared(5)) == 50); assert(squaredAndTwice(10) == 200); assert(squared(squared(squared(2))) == 2^2^2^2); assert(list() == [7,8,9]); assert(size(list()) == 3); assert(list() == 8); // naive bubble sort def sort(list) while !sorted(list) do end end def sorted(list) n = size(list); for i=0 to n-2 do if list[i] > list[i+1] do temp = list[i+1]; list[i+1] = list[i]; list[i] = temp; return false; end end return true; end numbers = [3,5,1,4,2]; sort(numbers); assert(numbers == [1,2,3,4,5]); // resursive calls def fib(n) if n < 2 do return n; else do return fib(n-2) + fib(n-1); end end sequence = ; for i = 0 to 10 do sequence = sequence + fib(i); end assert(sequence == [0,1,1,2,3,5,8,13,21,34,55]); // lists and lookups, `in` operator n = [[1,0,0],[0,1,0],[0,0,1]]; p = [-1, 'abc', true]; assert('abc' in p); assert([0,1,0] in n); assert(n == 0); assert(n == n); assert(p); assert(p == 'c');
The script above is just a number of
assertcalls that fail whenever the expression provided as parameter evaluates to false. So, after running the script above, you'll know that everything went okay if you didn't see anything printed to the console.
If you don't want to implement all node classes yourself, download the complete implementation of TL here. Execute the Ant task
runto execute the test.tl file.
And when C# is more to your liking, Bruce (see the comments below) translated/implemented TL in C#:
Bruce wrote: Hi Bart, this is great. I converted the whole thing to C#; if you are interested I can send you the project (VS2010, C# 4.0) so that others can download it from your blog.
The "test.tl" file is in the bin/Debug folder under the console app project, so that the executable can find it without a path.
One other note: I had to add a couple of custom list classes so that the interpreter would understand the value-semantics of list equality comparisons. Apparently Java considers List equality on an item-by-item basis, whereas .NET uses reference equality on the list object itself. The two classes are TLNodeList and TLValueList. They override ToString() and Equals() to match Java equality comparisons.
Download Bruce's VS project here
First of all, realize that all source files posted here are for educational purposes only. In no way are they production worthy: there are no unit tests, I haven't re-factored anything and there are very little comments in the source.
That said, where to go from here?
Imagine the code was properly unit tested, there's proper exception handling etc. Then the next step would be to provide better/friendlier (error) messages to the user (programmer) if some illegal syntax is used. To find out more about that, please see: ANTLR 3.0 Error Reporting and Recovery on the official ANTLR Wiki.
After that, the language could be extended by some sort of structs/classes. To find out how to do that, get a hold of Language Implementation Patterns of the same author of the (almost) mandatory book The Definitive ANTLR Reference, Terence Parr, creator of ANTLR.
That's it for now. If you have questions about the source of this tutorial, or found an error, please post a message here below any of my blogs. If you are writing your own language using ANTLR and are stuck on that, please use the ANTLR mailing list, or post a question on StackOverflow where I frequently answer ANTLR related questions.
PS. For clarity, download the complete sources here.
For an implementation of TL using ANTLR 4, see this Github project: https://github.com/bkiers/tiny-language-antlr4