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!

" # 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 integer

- Emit unsigned integer i8...i64 - Emit signed integer

- Emit signed integer f - Emit float

- Emit float d - Emit double

- Emit double hex - Toggle hex mode on/off (defaults to OFF)

- Toggle hex mode on/off (defaults to OFF) str <expr> - Write a string

- Write a string strl <expr> - Write a string AND newline

- Write a string AND newline endl - Write a newline

- Write a newline not <expr> Boolean NOT a char

Boolean NOT a char if <cond> <pred> endif Execute <pred> if <cond> == 1

Execute if get <expr> - Fetch the global variable named expr

- Fetch the global variable named set <expr1> <expr2> - Assign the global variable named expr1 to expr2

- Assign the global variable named to = - Compare two values, return 0 or 1

- Compare two values, return or times <count> <pred> endtimes - Execute <pred> <count> times. i is always set to the current iteration’s index.

- Execute times. is always set to the current iteration’s index. macro <name> <param-names...> begin <pred> endmacro - Declare a custom macro named <name> .

- Declare a custom macro named . return - End termination of the current macro. Exits the script if not in a macro.

- End termination of the current macro. Exits the script if not in a macro. size - Return the size of an item

- Return the size of an item len - Equivalent to C strlen

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.