Opinions About Compiler Building

2026-08-12

My random opinions about compiler building in the 21st century based on 30+ years of software consulting. I think of language design and compiler-building as two different things. One should actually avoid building compilers in the 21st century - we have enough compilers already. There’s always room for new languages, though. (In fact, I favour languages that use something better than characters for syntax, but, I digress…)

(Caveat: some of the links below point to experimental code, I write more about this stuff in my substack articles, blog, YouTube (all listed below))

  • prototype the language and play with it first - use OhmJS to whip together a parser - OhmJS is based on PEG technology which makes it easy to write grammars
  • use Ohm-editor (part of the OhmJS package) - it’s essentially a REPL for grammar writing that shows parse trees (CSTs), it saves a lot of time up front
  • when satisfied, you can re-code the grammar using whatever other technology you deem is necessary (e.g. Pratt parsing, whatever) - writing the code twice (or more) is more efficient than starting out dealing with implementation issues right off the bat

  • the easiest part of building a compiler is writing a parser (and scanner if you use something other than PEG), but, it’s been formalized and therefore discussed more often than the hard parts

  • you can build an MVI (Minimum Viable Implementation) of a language by transpiling code written in the language to some already existing language (e.g. Python, Javascript, etc.) - I favour using a text-to-text transmogrifier (“transpiler”) like the T2T stuff in Parts Based Programming

  • Steve Philips invented a new language Voltair by transpiling Voltair code into Go code. I think that he used an LLM to build the transpiler.
  • Alan Kay is on record saying that new languages should use existing languages as “assembler”

  • type checking is best expressed as a relational program - use something like Prolog or one of its descendants

  • use triples only, don’t bother with the OO extensions to Prolog - a triple is - relation(subject,object)
  • you can code up your own exhaustive search inferencer based on Nils Holm’s Prolog in Scheme code or my automated port of it to Javascript, but why bother? Write it first in Prolog (or …), then when satisfied re-code it in something else

  • type checking is much harder and more involved than parsing, start by expressing the rules in relational form and getting the rules right before calcifying implementation details

  • when doing code emission, emit “dumb” code first, then clean it up with a peepholer as described in Fraser/Davidson or Cordy’s OCG (GCC uses RTL, IMO, Cordy’s OCG is even better) - go for simplicity first, make code emission easy, then tighten up later after measurements prove which parts need to be tightened up

  • Holt et al, invented Data Descriptors - a way to normalize all data into the same form, which then makes things like allocation easy to think about

  • I favour a UNIX-y pipeline approach - use multiple stages, each written in a language that is better suited to each particular problem, e.g. Ohm for parsing, Prolog for type checking, Cordy’s MISTs for portability, etc.
  • making a compiler blazing fast and efficient is a different problem from creating a language, Production Engineers should worry about efficiency, but these issues should not impose themselves on the initial design, MVI of a language
  • first, write an interpreter for the language, and only then tighten up efficiency by building a compiler for the language
  • a compiler / language is just a really big program that takes a long time to implement
  • Javascript or Lisp are pretty good IRs (Intermediate Representation), LLVM is overkill and complicated, Python is good but it’s indentation-based syntax is painful to generate (I “solve” this problem by generating code in a meta-python (Python with braces instead of indentation) then use a small (40 lines of JS) program to replace brace-bracketed code with properly indented code)
  • what we “know” about compiler-building is based on crufty old ideas from the 20th century, we have better tools and machines today and we should be able to do better - my PBP kernel] (“multi-tasking”, “coroutining”) (especially - 0d.rt,- stock.rt,- jit.rt) is written in a meta-language- .rtthat generates the kernel in multiple languages (Python, JS, CL - it can do more, but I ran out of interest)

Appendix - T2T

T2T is one of the tools in the PBP toolkit — once you install PBP, you have access to T2T.

Appendix RWR

RWR is part of T2T. This is the specification for RWR

Appendix - PBP

Appendix - Further About PBP

Towards Parts Based Programming

PBP cookbook playlist

Decision Tree Diagram Transmogrifier

State Machine Diagram Tool

FDD LLM - 5 Whys Tool - code repository

State Machine Tool - code repository

Decision Tree Tool - code repository

PBP all tools (PBP, T2T, das2json)

The Spherical Cows of Programming

The Wrong Spherical Cow - First Principles of Parts Based Programming

The Case For Composable Notations (1 / 5) - The Spherical Cow We Forgot We Were Riding

The Case For Composable Notations (2 / 5) - The Restrictions That Came With The Cow

The Case For Composable Notations (3 / 5) - State Isn’t The Enemy The Case For Composable Notations (4 / 5) - Ease of Expression Is the Whole Point

The Case For Composable Notations (5 / 5) - UNIX Already Showed Us the Way

The Case For Composable Notations (6 / 5) - WIP - Notations in Progress

See Also

Email: ptcomputingsimplicity@gmail.comSubstack: paultarvydas.s. bstack.comVideos: https://www. youtube.com/@programmingsimplicity2980Discord: https://discord.gg/65YZUh6J. qLeanpub: https:. /leanpub.com/u/paul-tarvydasTwitter: @paul_tarvydasBluesky: @paultarvydas.bsky.socialMastodon: @paultarvydas(earlier) Blog: guitarvydas.github.ioReferences: https://guitarvydas.github.io/2024/01/06/References.html

Paid subscriptions are a voluntary way to support this work.