Day 1: Building WyrdLang
Welcome to the first post in what I hope will be an interesting journey—building a programming language from scratch. The programming language will be named as WyrdLang, and over the coming weeks, I’ll be documenting the entire process of implementing a tree-walk interpreter.
Why “WyrdLang”? In Old English, wyrd means fate or destiny. And yes, it also sounds like “weird” which is perfectly fitting for a language with unconventional keywords that sounds like words from a fairytale.
I won’t be building this language without any reference or a good resource. I’m going to follow the excellent book Crafting Interpreters by Robert Nystrom.
Crafting Interpreters
This book is a masterpiece, it walks you through building not one, but two complete interpreters for a language called Lox. The first interpreter, jlox, is a tree-walk interpreter written in Java. It focuses on concepts and correctness, building a clean, understandable implementation. The second interpreter, clox, is written in C and includes a bytecode compiler and virtual machine for serious performance.
I’ll be focusing on the first interpreter the tree-walk approach, but with a twist.
The WyrdLang Difference
While I’m following the structure and wisdom of Crafting Interpreters, I’m making some significant changes:
1. C++ Instead of Java
The original jlox is written in Java, but I’m porting it to C++. Because I’m more comfortable with C++. While Java is an excellent teaching language, I want to work in a language where I can focus on language implementation concepts rather than fighting with unfamiliar syntax. This means I’ll be dealing with manual memory management (or smart pointers), templates instead of generics, and all the quirks that make C++ both powerful and occasionally a maddening disaster.
2. Different Keywords
Here’s one of the unique aspects of WyrdLang. Instead of standard programming keywords, I’m using a different set of keywords inspired by fairy tales. This is mostly for fun and to make the implementation feel more personal, but the core goal remains building a functional, well-designed interpreter.
| Original Keyword | WyrdLang Keyword | Meaning |
|---|---|---|
var | enchant | Declare a variable |
fun | spell | Define a function |
class | clan | Define a class |
if | when | Conditional execution |
else | otherwise | Alternative branch |
while | aslongas | While loop |
for | cycle | For loop |
return | manifest | Return a value |
print | cast | Print output |
true | aye | Boolean true |
false | nay | Boolean false |
nil | emptiness | Null/nil value |
and | together | Logical AND |
or | either | Logical OR |
this | thine | Current object reference |
super | elder | Superclass reference |
Here’s what code looks like in WyrdLang:
enchant greeting = "Hello, World!"
cast greeting
spell summonDragon(name) {
when (name == "Smaug") {
manifest "The dragon awakens!"
} otherwise {
manifest "A dragon arrives: " + name
}
}
enchant result = summonDragon("Smaug")
cast result
What is a Programming Language ?
Before we embark on building our own language, let’s step back and understand what a programming language actually is and how it works.
At its heart, a programming language is a bridge between human thought and machine execution. When we write code, we’re expressing our intentions about what we want the computer to do, in a form that’s somewhere between natural human language and the raw binary that CPUs understand. Computers only understand sequences of 1s and 0s. That’s it. Everything else—variables, functions, loops, classes is a beautiful illusion we’ve constructed to make programming manageable for human minds.
From Text to Execution
Imagine implementing a programming language as climbing a mountain. we start at the bottom with raw source code in our hands, just a string of characters that a pogrammer typed. As we climb up the mountain, we transform this text through various stages, each one revealing more about what the program means:

At the peak, we have a complete understanding of what the programmer wants. Then we descend the other side, transforming that high-level understanding into progressively lower-level representations until we reach something the computer can actually execute.
The Two Paths: Compilers vs. Interpreters
There are two main approaches to implementing a programming language:
Compilers:
- Translate our source code into another language—usually machine code—producing an executable file. Think of C, C++, or Rust. We compile once, then run the resulting program many times. It’s like translating a book from English to French: we do the work once, and then French speakers can read it directly.
Interpreters:
- Read our source code and execute it directly, without producing a separate executable file. Think of Python, Ruby, or JavaScript. The interpreter translates and executes our code on the fly, line by line (or statement by statement). It’s like having a real-time translator at a conference: they translate as the speaker talks.
In reality, many modern languages blur the line between these categories. Python compiles to bytecode before interpreting it. Java compiles to bytecode, then a JIT (Just-In-Time) compiler translates hot paths to machine code at runtime. It’s complicated, and gloriously so.
Building WyrdLang
I’m setting out to build WyrdLang as a tree-walk interpreter the simpler of the two main approaches to creating an interpreter. Here’s what that means:
What is a Tree-Walk Interpreter?
A tree-walk interpreter works by:
- Scanning the source code into tokens (lexical analysis)
- Parsing those tokens into an Abstract Syntax Tree (AST)
- Walking that tree structure, evaluating each node to execute the program
It’s called “tree-walk” because the interpreter literally traverses the tree structure, executing operations as it visits each node. It’s intuitive, relatively simple to implement, and most importantly for learning, we can understand every single piece of it.
The downside of the tree-walk approach is that they are slower than more sophisticated approaches like bytecode virtual machines or JIT (Just-In-Time) compilation. But for a learning project and a language inspired by fairy tales, speed isn’t my primary concern.
The Journey Ahead
Over the coming weeks, I’ll be documenting my journey building WyrdLang. Each blog post will cover a specific aspect of language implementation:
- Scanning: How we break source code into meaningful tokens
- Parsing: How we structure those tokens into a syntax tree
- Evaluating: How we execute the tree to run programs
- Variables and Scope: How we track enchantments and their domains
- Control Flow: How we implement
whenandaslongas - Functions: How spells are cast and results manifested
- Classes: How clans organize related spells
- Inheritance: How clans learn from their elders
Along the way, I’ll encounter bugs, design decisions, and implementation challenges. I’ll share the failures alongside the successes, the confusing moments alongside the revelations.
Why Build a Programming Language?
Fair question. Here’s my answer:
1. To Understand How Things Really Work
Building a programming language is the ultimate “peek behind the curtain,” moving you from driving the car to building the engine from scratch. By mastering low-level mechanics like scoping and memory overhead, you stop guessing at performance and start writing better code in every other language.
2. Incredible Learning Experience
Implementing a language tests every programming skill I have:
- Data structures: You’ll build hash tables, trees, dynamic arrays
- Algorithms: Parsing algorithms, tree traversals, scope resolution
- Architecture: How to structure a complex, multi-phase system, usage of design patterns
- Debugging: Finding subtle bugs in complex recursive code
By the end of this journey, I guarantee that I’ll be a better programmer.
3. Little Languages Are Everywhere
I will be able to create domain-specific languages: configuration formats, scripting systems for your application, query languages, markup formats. Understanding how languages work makes you better at designing these “little languages” that power so much of modern software.
What’s Next?
In the next post, I’ll dive into the first concrete step: scanning. We’ll learn how to take raw source code just a string of characters and break it into meaningful tokens. We’ll build the lexer that can recognize WyrdLang’s fairy tale keywords and transform text like enchant x = 42 into a stream of tokens the parser can understand.
We’ll talk about:
- What tokens are and why we need them
- How to recognize different types of lexemes
- Handling whitespace, comments, and errors
- The theory behind lexical analysis and regular languages
But that’s for next time. For now, I’m setting up my development environment, sketching out the initial architecture, and preparing for the first lines of code.
A Note on Open Source
I’ll be sharing all the WyrdLang source code on GitHub as I build it.
Tags: /wyrdlang/ /interpreter/ /crafting-interpreters/ /cpp/ /c++/ /programming-language/