diff --git a/hspeak_ast.py b/hspeak_ast.py
index 625975c..ae53234 100755
--- a/hspeak_ast.py
+++ b/hspeak_ast.py
@@ -1,5 +1,8 @@
 #!/usr/bin/env python3
 
+import sys
+import array
+
 reserved = {
 }
 
@@ -146,6 +149,73 @@ yacc.yacc()
 
 # --
 
+KIND_NUMBER = 1      #int32. ID is the value
+KIND_FLOW = 2        #Flow control (flow_list), including begin and end.
+KIND_GLOBAL = 3      #Global variable
+KIND_LOCAL = 4       #Local variable
+KIND_MATH = 5        #Math builtin function
+KIND_FUNCTION = 6    #Builtin command
+KIND_SCRIPT = 7      #Call to script
+KIND_NONLOCAL = 8    #Nonlocal variable
+
+from hspeak_defines import hspeak_function
+
+math_list = {
+    #(MATH_ID, NUM_ARGS)
+    "random": (0, 2),
+    "exponent": (1, 2),
+    "modulus": (2, 2),
+    "divide": (3, 2),
+    "multiply": (4, 2),
+    "subtract": (5, 2),
+    "add": (6, 2),
+    "xor": (7, 2),
+    "or": (8, 2),
+    "and": (9, 2),
+    "equal": (10, 2),
+    "notequal": (11, 2),
+    "lessthan": (12, 2),
+    "greaterthan": (13, 2),
+    "lessthanorequalto": (14, 2),
+    "greaterthanorequalto": (15, 2),
+    "setvariable": (16, 2),
+    "increment": (17, 2),
+    "decrement": (18, 2),
+    "not": (19, 1),
+    "logand": (20, 2),
+    "logor": (21, 2),
+    "logxor": (22, 2),
+    "abs": (23, 1),
+    "sign": (24, 1),
+    "sqrt": (25, 1),
+}
+
+binop_list = {
+    "/": (3, 2),
+    "*": (4, 2),
+    "-": (5, 2),
+    "+": (6, 2),
+}
+
+flow_list = {
+    "do": 0,
+    "begin": 1,
+    "end": 2,
+    "return": 3,
+    "if": 4,
+    "then": 5,
+    "else": 6,
+    "for": 7,
+    "while": 10,
+    "break": 11,
+    "continue": 12,
+    "exitscript": 13,
+    "exitreturning": 14,
+    "switch": 15,
+}
+
+
+
 class AST_node:
 
     def __init__(self, type_, children = None, leaf = None):
@@ -170,6 +240,83 @@ class AST_node:
 
         return s
 
+    def kind_and_id(self):
+        "Returns a pair"
+        print(self.type, self.children,self.leaf)
+        if self.type == 'number':
+            return KIND_NUMBER, int(self.leaf)
+        elif self.type == 'function':
+            if self.leaf in hspeak_function:
+                return KIND_FUNCTION, hspeak_function[self.leaf][0]
+            if self.leaf in math_list:
+                return KIND_MATH, math_list[self.leaf][0]
+            if self.leaf in flow_list:
+                return KIND_FLOW, flow_list[self.leaf]
+            # Lots of other stuff missing
+        elif self.type == 'binop':
+            if self.leaf in binop_list:
+                return KIND_MATH, binop_list[self.leaf][0]
+        elif self.type == 'return':
+            return KIND_FLOW, flow_list["return"]
+        else:
+            print('Unknown AST node type', self.type)
+            sys.exit(1)
+        print('Unknown name', self.leaf)
+        sys.exit(1)
+
+    def compile_recurse(self, cmddata, strdata):
+        kind, id = self.kind_and_id()
+        cmddata.extend([kind, id])
+
+
+        if kind in (KIND_FLOW, KIND_MATH, KIND_FUNCTION, KIND_SCRIPT):
+            cmddata.append(len(self.children))
+            # Then append the offsets to the children. We don't know them
+            # yet, add placeholders instead.
+            childptrs = len(cmddata)
+            for _ in self.children:
+                cmddata.append(0)
+
+            for idx, child in enumerate(self.children):
+                # Now we know where the child will go
+                # (because we don't bother to compress the output)
+                cmddata[childptrs + idx] = len(cmddata)
+                child.compile_recurse(cmddata, strdata)
+
+def toHSZ(ast):
+    "Return a compiled .hsz lump as a bytes array"
+
+    num_locals = 0
+    num_args = 0
+    num_nonlocals = 0
+    parent_script = 0
+    nesting_depth = 0
+
+    CODE_START_BYTE_OFFSET = 18
+    HSZ_FORMAT_VERSION = 3
+
+
+    cmddata = array.array('i')
+    strdata = array.array('B')
+
+    # Create a root do() node
+    root = AST_node("function", [ast], "do")
+
+    root.compile_recurse(cmddata, strdata)
+
+    def i32(value):
+        return (value >> 16), (value & 0xffff)
+
+    header = array.array('h')
+    header.extend([CODE_START_BYTE_OFFSET, num_locals, num_args, HSZ_FORMAT_VERSION])
+    if len(strdata):
+        header.extend(i32(CODE_START_BYTE_OFFSET + len(cmddata) * 4))
+    else:
+        header.extend(i32(0))  # No string table
+    header.extend([parent_script, nesting_depth, num_nonlocals])
+
+    return header.tobytes() + cmddata.tobytes() + strdata.tobytes()
+
 # --
 
 AST_root = None
@@ -220,4 +367,6 @@ if __name__ == "__main__":
 
         if AST_root:
             print(AST_root.toString())
+            with open("out.hsz", "wb") as hszfile:
+                hszfile.write(toHSZ(AST_root))
             set_AST_root(None)
