Go to the first, previous, next, last section, table of contents.


assembler overview

The Muq assembler uses a procedural rather than text interface: To produce a Muq compiledFunction you:

Here's an example compiling a simple 'hello' function equivalent to : hello "Hello, world!\n" , ;

stack:
makeAssembler --> *asm*
stack:
"Hello, world!\n" *asm* assembleConstant
stack:
#', *asm* assembleCall
stack:
nil -1 makeFunction asm finishAssembly
stack: #<c-fn _>
--> #'hello
stack:
hello
Hello, world!
stack:

Code is deposited monotonically from start to end of function: there is no way to back up and insert more instructions between those already laid down.

Jumps are connected to labels by giving them matching ids: Calling assembleLabel with an ID of 13, and (later or earlier) calling assembleBra also with an ID of 13, results in assembly of an unconditional jump from the assembleBra location to the assembleLabel location. It is an error if there is not exactly one matching label for each branch. IDs should be small integers obtained from assembleLabelGet.

Most bytecodes are deposited by doing an assembleCall on the appropriate function: The assembler checks to see if the function is a primitive, and if so deposits the appropriate bytecodes rather than an actual call. This greatly simplifies compiler construction and maintainance, since the compilers need contain very little information about the bytecoded instruction set.

The exceptions are the bytecodes which need special parameters. These fall into two general classes:

  1. Those which need a label parameter specifying the scope of some construct (the jumps and error-trapping primitives).
  2. Those which need a parameter specifying an offset into the constant vector or stackframe (the local-variable get- and set- primitives, mostly).

Note that there are special assembler functions to push CATCHFRAMES and UNWINDFRAMES, but no special functions to pop them. This is because they can be popped merely by invoking assembleCall on popCatchframe and popUnwindframe. The corresponding pushes cannot be handled this way because they need to reference a code label.

Note that LOCKFRAMES (implementing withLockDo{...}) are both pushed and popped in this fashion, using pushLockframe and popLockframe.


Go to the first, previous, next, last section, table of contents.