Crafting IDE-Ready Compilers
Tags: rust, compilers, series, languagedesign
Published: 2019-09-27 18:27:47

This is the introductory post of a series, so normally you would find a motivational section here. Why should you learn how to build a compiler? I'm not going to bother with that; Crafting Interpreters [did it better than I could, anyway](http://craftinginterpreters.com/introduction.html#why-learn-this-stuff). The short of it is, well, writing compilers is fun, and covers a lot of techniques for solving problems.

We're going to start by implementing an interpreter for the [Tiny-C] language. Tiny-C is a significantly stripped down C-style language where there is only one data type, no variable declarations, no functions, the only control flow options are `if` and `while`, and the only expressions are `+`, `-`, and `<`. Because of this, the grammar is simple enough I can include it here inline:

```
Program = Statement;
Statement =
  | If:{ "if" cond:ParenExpr then:Statement else:{ "else" then:Statement } }
  | While:{ "while" cond:ParenExpr then:Statement }
  | Block:{ "{" then:Statement* "}" }
  | Expr:{ then:Statement? ";" }
  ;
ParenExpr = "(" Expr ")";
Expr =
  | Assign:{ id:Id "=" val:Expr }
  | Test:{ lhs:Expr "<" rhs:Expr }
  | Sum:{ lhs:Expr "+" rhs:Term }
  | Diff:{ lhs:Expr "-" rhs:Term }
  ;
Term =
  | Id:{ 'a'..='z'+ }
  | Int:{ '0'..='9'+ }
  | Expr:ParenExpr
  ;
```

(Note that this is slightly modified from the original Tiny-C to better fit how we are going to build the compiler.) The simplicity of the language allows us to focus on the structure of the compiler rather than the intricacies of the language. If you don't fully understand the above grammar, don't worry: we'll be covering it in more detail in the future.

Additionally, we'll be writing the compiler in a fully IDE-ready style. This means our compiler will also serve as the intelligence engine powering a [language server protocol](https://microsoft.github.io/language-server-protocol/) server. Though our language is simple, we want to write the compiler as if it were a full-fat compiler for a full-fat language. By doing so, we can transfer what we learn here to real languages' intelligence engines.

Because we're trying to build a real compiler, we'll be taking full advantage of the available tooling for building compilers in Rust. Rust's ownership semantics make the compartmentalization and complex data flows through a compiler easier to see. For libraries, we'll be using at least [rowan](https://lib.rs/crates/rowan), [salsa](https://lib.rs/crates/salsa), and [lsp-server](https://lib.rs/crates/lsp-server).

With any luck, once we've implemented the interpreter for Tiny-C, we'll continue on to write a backend with [Cranelift](https://cranelift.readthedocs.io), and maybe even continue on to designing and writing a full language 👀

I plan to have a post in the series out at least every other Friday. Next time: we set up the repository structure and lex the language into its component tokens. We'll also be getting our first venture into code generation along the way.

[Discuss this below!](#comments) | [on Reddit!](https://www.reddit.com/r/rust/comments/da4gn6/im_writing_a_series_on_writing_compilers_in_rust/) | [on Twitter!](https://twitter.com/CAD97_/status/1176696422965698561) | [on Discord!](https://discord.gg/FuPE9JE) | [Watch me live!](https://dev.to/live/cad97)

## Related Reading

- [Crafting Interpreters](http://craftinginterpreters.com/)
- Matklad's [Modern Parser Generator](https://matklad.github.io/2018/06/06/modern-parser-generator.html)
- Matklad's [The Essence of Lexer](https://github.com/rust-lang/rust/pull/59706)
- KartikTalwar's [Tiny-C Compiler][Tiny-C]
- [rust-analyzer's architecture overview](https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/dev/architecture.md)
- the [Salsa book](https://salsa-rs.github.io/salsa/html/) (WIP) and [hello world](https://github.com/salsa-rs/salsa/blob/master/examples/hello_world)

  [Tiny-C]: <https://gist.github.com/KartikTalwar/3095780>