Livecoding time again today, and I’m writing a compiler. This is a prototype for an alternate take on code generation for my Cowgol programming language. This is an Ada-inspired programming language for very small systems, such as 8-bit machines, intended to be self-hosted on such systems (although realistically you’ll cross compile). Cowgol works, but is achingly slow, and in this video I’m experimenting with a drastically simplified code generation model to see whether I can eliminate 95% of the complexity and produce something which works nearly as well but is much smaller and faster.

It’s a utterly simple one-pass compiler, using flex and yacc for the lexer and parser, and a stack-based intermediate language with a few basic heuristics to generate runnable 8080 code. Everything has been sacrificed for the sake of simplicity. Did it work? Spoiler: embarrassingly yes.

The code’s all BSD 2-clause open source.

The compiler source

Find the compiler source here (although I've been tinkering with it).

I am initially aiming at CP/M, just because, but I also have the 6502 in mind (plus another architecture of Unprecedented Evil).

It was done in one sitting, with two breaks for tea and dinner respectively. The clock on my status bar is accurate.

List of interesting timestamps follows:

  • 00:06:33 First trivial program runs (just a ret statement)
  • 00:37:30 Symbol table, variable declarations skeleton (but no code generated)
  • 00:44:05 Symbol lookups and simple types
  • 00:50:02 Variable declarations code generation works
  • 00:59:51 Constant value propagation and lazy coercion to a concrete type
  • 01:05:55 Addition operator works with constants
  • 01:08:32 Variables can be looked up, addition operator generates code
  • 01:17:10 Proper memory storage for variables
  • 01:19:10 Running code
  • 01:31:10 Subtraction works
  • 01:47:01 Simple subroutine definitions work (you can’t call them)
  • 01:51:45 Calling simple subroutines works (with no parameters)
  • 01:59:37 Infinite loops work
  • 02:03:17 Variable assignment works
  • 02:03:39 TEA BREAK
  • 02:29:32 8-bit types work
  • 02:32:40 Tangential lecture on subroutines in a non-recursive language
  • 02:37:10 Start diversion on TOS optimisation
  • 03:11:47 Old Cowgol vs New Cowgol
  • 03:30:40 Pointer types and pointer arithmetic works
  • 03:41:46 Dereferencing pointers on read works
  • 03:50:35 Give up on TOS optimisation — too complex and I was getting it wrong anyway
  • 04:05:30 Tangential lector on comparing Old Cowgol and New Cowgol
  • 04:32:03 Hacked up conditionals and while…end while loop work (maybe)
  • 04:41:05 Dereferencing pointers on write works
  • 04:43:08 Comparison of Old Cowgol and New Cowgol generated code
  • 04:59:02 DINNER BREAK
  • 04:59:03 Plan next stages and problem summary
  • 05:02:30 Start work on virtual stack implementation
  • 05:37:50 Virtual stack works, is highly successful
  • 05:50:30 Lots of microoptimisations done, do another comparison
  • 05:57:00 Start implementing subroutine parameters
  • 06:47:50 Start debugging the Horrible Yacc Problem™
  • 07:03:26 Stop debugging the Horrible Yacc Problem™ and just brute force it
  • 07:07:51 Calling subroutines with parameters works
  • 07:32:29 String constants work
  • 07:33:53 Type inference works
  • 07:42:35 Extern subroutine declarations work
  • 07:50:24 if…then…end if works
  • 07:57:02 break works
  • 08:11:40 ‘Hello, world!’ works
  • 08:16:20 Bedtime