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


Assembling Conditionals And Loops

One major class of programming language functionality which cannot easily be expressed simply as loading a constant or calling a function is control structure: loops, ifs and such. From the compiler writer's point of view, these are all built out of labels marking places in the code, and branch instructions jumping to these labels.

Let's assemble a simple "nil if 1 else 2 fi" function, which demonstrates all the essentials:

stack:
*asm* reset
stack:
*asm* assembleLabelGet --> *elseLabel*
stack:
*asm* assembleLabelGet --> *fiLabel*
stack:
nil *asm* assembleConstant
stack:
*elseLabel* *asm* assembleBeq
stack:
1 *asm* assembleConstant
stack:
*fiLabel* *asm* assembleBra
stack:
*elseLabel* *asm* assembleLabel
stack:
2 *asm* assembleConstant
stack:
*fiLabel* *asm* assembleLabel
stack:
nil -1 *fun* *asm* finishAssembly --> *cfn*
stack:
*cfn* call{ -> $ }
stack: 2

This time, a peek at the disassembly produces:

constants:
0: nil
code bytes:
00: 34 00 1f 04 33 01 2b 02 33 02 2e
code disassembly:
000:      34 00       GETk   0
002:      1f 04       BEQ    008:
004:      33 01       GETi   1
006:      2b 02       BRA    00a:
008:      33 02       GETi   2
00a:      2e          RETURN 

How does this work?

Labels may be deposited before or after the matching branch. Preceding labels result in loops; following labels result in conditionals. The Muq assembler cares nothing about how well-structured your jump architecture is (although future optimizing versions of it may have difficulty optimizing nasty unstructured code).

Just be sure that every label used was properly allocated, and that every branch assembled is to a properly deposited label.

As a minor note: The Muq server implements both one- and two-byte branch offsets. The assembler uses the usual jump minimization algorithm to always use one-byte branch offsets where possible. Supporting three-byte branch offsets would be trivial, but I don't think I want people clogging the virtual memory buffer with functions more than 64K long, so I haven't implemented this. Any function producing more than 64K of code probably needs to be rewritten :).


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