Bear in mind that this was twenty years ago, so it's not exactly fresh in my mind; but basically: it was intended to do one job, once, which was to compile the real compiler (written in a simplified version of the language) into bytecode. Once that worked, I would never need to touch it again.
Which meant that it was perfectly allowable for it to be hacky and non-future proof, which it was.
Here's part of the code which read local variables definitions (in C-like syntax):
function do_local( \
nt, st, n, t){
nt = readtype()
st = tokens
ensuretoken(readtoken(), token_word)
n = tokens
outofscope(n, 1)
ldb[n] = "var"
ldb[n, "type"] = st
ldb[n, "sp"] = sp - spmark
emit("# local " n " of type " st " at " (sp-spmark) "\n")
tokens is the value of the current token, ldb is the symbol table; you can see how I'm faking a structure using an associative array indexed by keyword.
There's nothing actually very wrong with this code, but there's no type safety, barely any checking for undefined variables, no checking for mistyped structure field names, no proper data types at all, in fact... awk wouldn't scale for making the compiler much more complicated than it currently is. But it did hit the ideal sweet spot for getting something working relatively quickly for a one-shot job. It's still really good at that.