t2b
A wicked-powerful text macro language for building binary files. Supports comments, looping, Unicode, variables, conditionals, macros and recursion.
TLDR; Check out example/
.
Pre-built binaries are available for Win64 and MacOS64.
Usage
$ t2b <filename> here
$ t2b # Read directly from stdin
t2b
always writes to stdout. To output to a file, simply use a greater-than sign (>
).
Language
Newlines are solely for the sake of readability; all whitespace is the same.
# This is a comment!
#
# Comments must be on their own line.
# Emit a byte. In DECIMAL.
u8 10
# Emit a byte in hex.
u8 0xa
# Octal
u16 0o777
# And, of course, binary.
u8 0b00001110
# Spit out a signed integer.
i64 25677
# Print a string (no line break)
str hello
# Print with a line break.
strl hello
# Wrap in quotes to capture whitespace.
strl "hello world!"
# Escapes are supported.
str "hello, world!\n"
# Unicode?
str "\u{1234}"
# Print a newline.
endl
# Do something 5 times.
# Indentation is purely for readability.
times 5
u8 23
u32 24
times 10
# We can nest loops
str "50 times!!!"
endtimes
endtimes
# Capture the output of another command.
# Oh, and store it into a variable.
set foo (u8 33)
# Access its value.
set bar (get foo)
# Emit its value 3 times.
times 3 get foo endtimes
# Create a simple macro.
macro emit_twice x
begin
times 2 (get x)
endmacro
# Call it!
emit_twice 24
Why?
The need for such a program arose when I was working on writing a simple VM. Manually hex-editing files for an ever changing bytecode spec is tedious, error-prone, and most of all - sucky.
Now there’s a lightweight way to do just that.
Supported Commands
u8...u64
- Emit unsigned integeri8...i64
- Emit signed integerf
- Emit floatd
- Emit doublehex
- Toggle hex mode on/off (defaults to OFF)str <expr>
- Write a stringstrl <expr>
- Write a string AND newlineendl
- Write a newlinenot <expr>
Boolean NOT a charif <cond> <pred> endif
Execute<pred>
if<cond> == 1
get <expr>
- Fetch the global variable namedexpr
set <expr1> <expr2>
- Assign the global variable namedexpr1
toexpr2
=
- Compare two values, return0
or1
times <count> <pred> endtimes
- Execute<pred>
<count>
times.i
is always set to the current iteration’s index.macro <name> <param-names...> begin <pred> endmacro
- Declare a custom macro named<name>
.return
- End termination of the current macro. Exits the script if not in a macro.size
- Return the size of an itemlen
- Equivalent to Cstrlen
What’s next?
It’s now feasible to write a machine code compiler in shell. Hooray. Not sure why you would ever do that to yourself, though.