This page contains code examples that demonstrate programming techniques for the Torque meta-assembler.
Integer encodings
Little-endian
This macro encodes an integer in two bytes as a 16-bit little-endian value.
%BYTE:n #nnnn_nnnn ; %BYTE-L:n BYTE:[n 0xFF <and>] ; %BYTE-H:n BYTE:[n 8 <shr>] ; %16LE:n BYTE-L:n BYTE-H:n ; 16LE:9000
Big-endian
This macro encodes an integer in four bytes as a 32-bit big-endian value. A more general approach is taken to breaking the value into bytes.
%BYTE:n #nnnn_nnnn ; %BYTE-I:n:i [n [8 i *] <shr> 0xFF <and>] ; %32BE:n BYTE-I:n:3 BYTE-I:n:2 BYTE-I:n:1 BYTE-I:n:0 ; 32BE:96000
LEB128
This macro encodes an integer using the variable-length LEB128 integer encoding. The macro recurses into itself in order to handle integers of arbitrary magnitude.
%LEB128:n ?[n <len> 7 <gth>] { BYTE:[n 0x7f <and> 0x80 <or>] LEB128:[n 7 >>] } ?[n <len> 7 <leq>] { BYTE:[n 0x7f <and>] } ; LEB128:51966
The encoding works by breaking an integer down into one or more 7-bit sections, then packing each section into a byte ala 7-bit ASCII, using the highest bit to indicate that there are still more bytes to come, and finally flipping the bytes to little-endian order. The process looks like the following, encoding the value 51966:
51966 ( Decimal ) 11001010 11111110 ( Binary ) 0000011 0010101 1111110 ( 7-bit groups ) 00000011 10010101 11111110 ( 8-bit groups ) 11111110 10010101 00000011 ( Little-endian ) 0xfe 0x95 0x03 ( Hexadecimal )
Text encodings
ASCII
This macro encodes a string using the 7-bit ASCII encoding. An error is raised if a non-ASCII character is included.
%ASCII:c #0ccc_cccc ; ASCII:"This is a string."
UTF-8
This macro encodes a string using the variable-width UTF-8 text encoding. Conditional blocks are used to select the correct byte packing for each character value.
%UTF8-B1:c #0ccccccc ; %UTF8-B2:c #10cccccc ; %UTF8-B3:c #110ccccc ; %UTF8-B4:c #1110cccc ; %UTF8-B5:c #11110ccc ; %UTF8:c ?[c 0x7f <=] { UTF8-B1:c } ?[c 0x80 >= c 0x07ff <= <and>] { UTF8-B3:[c 6 >>] UTF8-B2:[c 0x3f <and>] } ?[c 0x0800 >= c 0xffff <= <and>] { UTF8-B4:[c 12 >>] UTF8-B2:[c 6 >> 0x3f <and>] UTF8-B2:[c 0x3f <and>] } ?[c 0x010000 >= c 0x10ffff <= <and>] { UTF8-B5:[c 18 >>] UTF8-B2:[c 12 >> 0x3f <and>] UTF8-B2:[c 6 >> 0x3f <and>] UTF8-B2:[c 0x3f <and>] } ; UTF8:"tohutÅ"
Null-terminated
This macro adds a null byte to the end of an ASCII-encoded string.
%BYTE:n #nnnn_nnnn ; %ASCII:c #0ccc_cccc ; %STRING:"string" ASCII:string BYTE:0 ; STRING:"Null-terminated string"
Length-prefixed
This macro adds a one-byte length prefix to the start of an ASCII-encoded string.
%BYTE:n #nnnn_nnnn ; %ASCII:c #0ccc_cccc ; %STRING:"string" BYTE:[~end ~start -] &start ASCII:string &end ; STRING:"Length-prefixed string"
Structure
Padding
This macro expands to n
null bytes, using recursion.
%PAD:n ?[n 0 >] { #0000_0000 PAD:[n 1 -] } ; PAD:16
Alignment
This macro aligns the following value to an arbitrary address boundary.
%ALIGN:n &here |[~here [n 1 -] + n / n *] ; ALIGN:4
It works by pinning to the next address that is a multiple of the passed integer.
Flow control
if-else
This macro implements an if-else conditional statement for a target instruction set.
%IF-ELSE:cond:{true-block}:{false-block} JMP-IF:cond:~true false-block JMP:~end &true true-block &end ; IF-ELSE:[n 0 >]:{ DO-THING }:{ OTHER-THING }
if-else (static)
This macro implements an if-else conditional statement as a macro, with evaluation performed at assemble-time. Only one of the two blocks will be included in the assembled program.
%IF-ELSE:cond:{true-block}:{false-block} ?[cond 0 !=] true-block ?[cond 0 ==] false-block IF-ELSE:[n 0 >]:{ DO-THING }:{ OTHER-THING }
for-loop
This macro implements a for-loop for a target instruction set.
%FOR:n:{body} SET:counter:n &loop body DEC:counter JMP-IF:counter:~loop ; FOR:3:{ DO-THING }
for-loop (static)
This macro implements an unrolled for-loop as a macro, with looping performed at assemble-time. The body of the loop will be duplicated n
times.
%FOR:n:{body} ?[n 0 >] { body FOR:[n 1 -]:body } ; FOR:3:{ DO-THING }
Objects
2D point
This example shows how to create and modify an object representing a 2D point, using labels and named offsets for field access.
%BYTE:n #nnnn_nnnn ; %16BE:n BYTE:[n 8 <shr>] BYTE:[n 0xff <and>] ; %POINT:x:y 16BE:x 16BE:y ; %POINT.X 0 ; %POINT.Y 2 ; @point-1 POINT:50:-7 @point-2 POINT:20:-45 @point-3 POINT:0:0 SET:[point-3 POINT.X +]:15 SET:[point-3 POINT.Y +]:32