Memory Code (MC) is a language that provides a concise way to manipulate memory. It compiles to TS, and ultimately to IL.
MC has of two instruction types. The first directs the agent to perform a read-modify-write operation. It consists of the modify function’s name, f, and the memory address where to apply it, x:
f x
It commands the agent to:
The following MC program demonstrate this instruction type. It performs the sum from the previous section.
sum.mc COPY_B_A 0 ADD_AB_FB 1 SWAP 1 ADD_AB_FB 2 SWAP 2 ADD_AB_FB 3 SWAP 2 SWAP 1 SWAP 0
The second instruction type directs the agent to execute a previously defined MC program, p, relative to a specified memory address, x:
p x
The MC compiler replaces the instruction with p's contents, such that the memory address arguments of p's instruction are incremented by x. The compiler recursively repeats that process until all what remains are instructions of the first type. To ensure the process finishes, the compiler does not permit circular dependencies.
The code below references the last example to illustrate this instruction type.
sum5.mc sum 5
The compiler expands the single instruction, offsetting the memory locations per the provided address:
sum5Expanded.mc COPY_B_A 5 ADD_AB_FB 6 SWAP 6 ADD_AB_FB 7 SWAP 7 ADD_AB_FB 8 SWAP 7 SWAP 6 SWAP 5
The expanded version reveals sum5 totals bytes 6, 7, 8, and 9, and it puts the result into byte 5. In other words, it executes sum relative to byte 5.
MC does not provide instructions for initializing memory. Rather, an MC program operates on existing memory, a rectangular pile originating from a TS program and potentially manipulated by other MC programs. That being the case, the compiler requires the existing pile’s dimensions. The pile’s height provides the original surface row index. Then, for each MC instruction, the compiler increments the surface row index by the height of the instruction’s function, and it uses the function’s byte width along with the pile’s width to figure out how many identity functions to build and where to build them.
The compiler knows the function byte widths because, at startup, it counts the number of in directives in each TS program. And it knows the function heights because it builds an instance of each function on a finite, private playfield, using zeros for input.
For the identity functions, the compiler outputs a sequence of TS instructions that direct the agent to build columns above the pile’s surface nodes, primarily from vertical I-tetrominoes, where the heights of the columns equal the height of the MC instruction’s function.
If the compiler encounters an MC instruction that references a memory address beyond the pile’s width, then it expands the pile up to that address before it translates the instruction to TS. As explained in the last section, to allocate and initialize bytes, the compiler appends 0-nodes in the form of horizontal I-tetrominoes, and it pads the nodes in the same way that it synthesizes the identity functions.
The agent can execute the TS program generated by the MC compiler on any rectangular pile matching the dimensions provided at compilation time.
© 2023 meatfighter.com |