This is going to be a multi-part blogpost series where I go about trying to design my own “Terrible Language” (referred to as tl from now on). I will start with just using C++ macros and template metaprogramming to first establish the syntax of the language. Once I am happy with it, I am going to go ahead and implement a GCC frontend followed by an LLVM frontend of the language. It’s going to be super fun!

Given how much I like C++, tl is going to look somewhat like it but I will still try to abstract away the complicated parts of C++ from it. I am going to try to use as much of new C++17 features as possible to learn about them as we go.

And so tl was born

tl stands for “Terrible Language” and so it is going to be terribly designed as well (apologies!). For the first part, I am going to have a single header file std_tl.h which will contain all the macros, functions, and classes needed to write a tl program. The compiler tlc is going to be a simple bash wrapper script that uses g++ internally to compile programs. Since I am aiming to use the C++17 standard, a compatible g++ would be required. I am going to keep it extremely simple so the compiler will not be accepting any extra flags/arguments apart from the source code file.

In the end, I want to do something like

$ ./tlc foobar.tl

The “compiler”

TLDR; The tlc bash wrapper script looks like this

#!/bin/bash

mkdir .tltmp 2>/dev/null
tmp_file=".tltmp/tltmp_$1.cpp"
echo "#include <$(pwd)/std_tl.h>" > $tmp_file
cat >> "$tmp_file" < "$1"
g++ -std=c++17 "$tmp_file" -o "$1.exe"
rm -rf .tltmp

It creates a .tltmp/ directory where it creates a new .cpp file which contains the #include header to our std_tl.h file and then copy-pastes the tl source code. It then calls g++ to compile the program and then gets rid of the temporary directory. Plain and simple. I like it.

We will be using this wrapper script from now on as our compiler for all tl programs.

Starting with the syntax

For starters, I do not want to worry about function declarations. I just want a single function that has all of our code. Something like

tl {
    // do something here
}

This can be very easily done with defining a macro for the main() function in our std_tl.h file like this

#define tl int main(int __attribute__((unused)) argc, char __attribute__((unused)) **argv)

But this is just not enough. The very basic operation that we should be able to do is printing on the screen. So how about adding something like this to std_tl.h

#define print(str) \
    std::cout << str
#define println(str) \
    print(str) << std::endl

With the above in place, we can write our “Hello World” program in tl!

tl {
    println("Hello world!");
}

Let’s compile and run it

$ ./tlc hello_world.tl
$ ./hello_world.tl.exe
Hello world!

Awesome!

I am going to end this blogpost here. Next steps would be to think more about what I want as part of the syntax as well as trying to use more of C++17 features.

Oh and the source code is available at https://github.com/mnafees/tl

Stay tuned for Part 2!