A symbolic, flow-based programming language written in Fortran - now delivered as a compiled toolchain for performance and portability.
Version: 1.1.7
Author: Capinol
Toolchain: forminc (compiler) + forminvm (virtual machine)
Looking for the classic interpreter docs? See
README_interpreter.md.
Formin is a flow-based, label-driven programming language that uses symbolic instruction syntax for complete control over execution flow.
Commands follow a consistent structure:
command#/token1|token2|token3/#
Each instruction starts with a command name, followed by arguments (called tokens) separated by |.
String literals are wrapped in single quotes ('), while variables are referenced directly.
Example:
create#/greeting|'Hello, World!'/#
spew#/greeting/#
Source files (.fmn) are compiled with forminc into compact bytecode (.fbc) that is executed by the portable forminvm runtime.
Formin now ships as a compiled toolchain consisting of:
forminc– the ahead-of-time compiler that emits.fbcbytecodeforminvm– the lightweight virtual machine that executes the compiled program
Download the pair from the Releases page and place them somewhere on your PATH.
- Download the latest release and extract
formincandforminvm. - Make them executable:
chmod +x forminc forminvm
- Move both to a system path:
sudo mv forminc forminvm /usr/local/bin/
- Compile and run a sample:
forminc Examples/helloWorld.fmn forminvm Examples/helloWorld.fmn.fbc
- Download the latest release of
forminc.exeandforminvm.exe. - Optional: add their folder to
PATH, or keep them next to your project. - Compile and run:
.\forminc.exe Examples\helloWorld.fmn .\forminvm.exe Examples\helloWorld.fmn.fbc
If Windows blocks the binaries, right-click → Properties → Unblock, or run PowerShell as Administrator.
forminc source.fmn– compiles a source file intosource.fmn.fbc.
forminvm ver– prints the VM version.forminvm program.fbc– runs a compiled program.forminvm program.fbc loud– runs the program and prints total execution time.
- Create a new file called
hello.fmn:create#/name|'World'/# spew#/'Hello,'|name|!/# - Compile it to bytecode:
forminc hello.fmn
- Run the compiled program:
Output:
forminvm hello.fmn.fbc
Hello, World!
Formin binaries are provided under the MIT License. Logo © Capinol 2025, licensed under CC BY-SA 4.0.
If you want to put comments, see this
prints things, supports multiple things at once, automatically adds space between them.
Example: spew#/'Hello'|'World!/#
prints things, supports multiple things at once. Unline spew, it doesn't add space between each token printed.
Example: spewmult#/'Hello'|'World!/#
sets the print color to the given color. Accepted colors: reset, black, red, green, yellow, blue, magenta, cyan, white, bright_red, bright_green, bright_yellow, bright_blue, bright_magenta, bright_cyan, bright_white Only works on modern terminals.
Example: color#/green/#
clears the terminal, same as 'clear' on UNIX and 'cls' on Win.
Example: clear#//#
either turns number into character or vice versa. Example
ends the program.
Example: bye
sets a marker at given line of program, can be returned to with go#//# Example: (infinite loop)
mark#/loop/#
spew#/'You are in the loop!'/#
go#/loop/#
goes to a marker. Example: in mark#//#
goes back to the last go#//# call Example: (prints 1,2,3)
spew#/'1'/#
go#/print2/#
go#/print3/#
bye
mark#/print2/#
spew#/'2'/#
goback#//#
mark#/print3/#
spew#/'3'/#
goback#//#
gets the users os (Either win or unix) and saves to a var Example
writes the input into the terminal/powershell of the computer running it.
Pair it with ins to pipe scripted stdin into interactive programs.
Example (unix): sys#/'ps aux'/#
gets the current cpu time since start of program and writes it in a variable. Example:
cputime#/startVar/#
... code in between ...
cputime#/endVar/#
sub#/execTime|endVar|startVar/#
spew#/Execution time:|execTime/#
makes a variable and sets it to a value.
Has 3 types: int, real, string
Example: create#/x|10|int/#
sets an existing variable to a different value/type Example: ``` set#/x|'a'|str/#
Asks the user a question, and stores it in a variable Example:
ask#/'What is your name?'|name/#
spew#/'Hello'|name/#
Captures the numeric keycode of the most recent key event (or the same key while it's still being held) and stores it in a variable. Returns 0 when no key has been pressed yet.
Example:
key#/lastKey/#
spew#/'Last keycode:'|lastKey/#
On Windows, held keys keep reporting while the key stays down. On Unix-like systems the command reports the latest key press only.
Buffers lines that will be piped into the next sys command. Each token becomes one stdin line, letting you interact with spawned programs (like another forminvm run) without manual typing.
Example:
ins#/'1'|'5'|'7'/#
sys#/'forminvm Examples/simpleCalc.fmn.fbc'/#
Goes to given line if condition is met, and to a different line if it isnt met.
Format: ifgo#/*x*|*comparer*|*y*|*go1*|*go2*/#
Format explanation:
x: first thing to compare
comparer: how to compare them
is
isnt
<
>
>=
<=
y: second thing to compare go1: marker to go to if condition is met - can be _ to ignore go2: marker to go to if condition isnt met - can be _ to ignore Example:
ask#/'Enter a number:'|number/#
ifgo#/x|is|6|isSix|isntSix/#
mark#/isSix/#
spew#/'Your number is six!'/#
bye
mark#/isntSix/#
spew#/'Your number isnt six! '/#
bye
Skips upcoming lines that use specific suffix markers when a comparison is true. Great for toggling optional blocks (like comments) without jumping around with markers.
Format: ifskip#/*x*|*comparer*|*y*|*suffixMask*|*count*/#
Format explanation:
x: first thing to compare
comparer: comparison operator (same list as ifgo)
y: second thing to compare
suffixMask: string containing every suffix character you want to skip (e.g. . or %!)
count: positive number of future lines (matching any of those suffix characters) to skip
When the x comparer y test passes, the VM starts ignoring commands whose suffix begins with any character listed in suffixMask until it has skipped count of them. Each skipped command is treated like a comment at runtime without needing to manually insert go / mark pairs.
Example
gets the type of a var and stores it in another var. Example
gets a random value from (0 to 1)*userMod and saves it in a var.
Syntax: formin randi#/*var to store output*|*userMod*/#
Example
Adds two numbers (can be variable), and stores the result in a given variable
Syntax: add#/*variable to store result*|*first num*|*second num*/#
Example: (add 1 to x)
add#/x|x|1/#
Substracts number 1 by number 2 (can be variable), and stores the result in a given variable
Syntax: sub #/*variable to store result*|*first num*|*second num*/#
Example: (sub x by 1)
sub#/x|x|1/#
Multiplies two numbers (can be variable), and stores the result in a given variable
Syntax: mult#/*variable to store result*|*first num*|*second num*/#
Example: (mult x by 2)
mult#/x|x|2/#
Divides number 1 by number 2 (can be variable), and stores the result in a given variable
Syntax: sub#/*variable to store result*|*first num*|*second num*/#
Example: (Divide x by 2)
div#/x|x|2/#
Watch out for divison by zero!
Gets the remainder of a number after division Example
Gets the power of first variable to power of second variable Example
Gets the square root of a number.
Example: sqrt#/x|16/# > x is 4
Gets the absolute value of a number. Example
Gets the floor/ceiling of a number. Example
Opens a file, creates new one if supplied file doesn't exist.
Syntax: open#/*how the file be reffered as*| *filepath*/#
Example: open#/fileHello|hello.txt/#
Reads a line in supplied file, then advances the line to next one (for later reading)
Syntax: read#/*how the file is reffered as| *variable to store line content in*/#
Example: (read first line in a file called hello.txt)
open#/file|hello.txt/#
read#/file|line/#
spew#/line/#
close#/file/#
Closes given file Example:
open#/file|hello.txt/#
read#/file|line/#
spew#/line/#
close#/file/#
ALWAYS CLOSE FILES AFTER OPENING - NOT DOING SO MAKES THE FILE PERSIST IN MEMORY EVEN AFTER CLOSING PROGRAM.
This section will contain all tokens of the str#//# command. str example
The string command can be used to manipulate strings. Syntax:
str#/*method*|*method variables*/#
Methods:
Syntax:
str#/cat|*var to store result*|*string 1*|*string 2*|*spacing*/#
by default, cat doesnt add space between the 2 strings; in order to do so, write sp in the spacing token. The spacing token can be left out. Example
Syntax:
str#/*any of the 3*|*var to store result*|*string*/#
Either reverses the string and stores it to the var, or converts it into uppercase/lowercase and stores in the var or gets the lenght and stores in the var. Example:
create#/anadrome|'drawer'/#
spew#/anadrome/#
str#/rev|anadrome|anadrome/#
spew#/anadrome/#
lists function the same as arrays.
syntax: list#/*method*|*params*/#
list methods:
create/new : makes a new list with set name.
Example: list#/create|names/#
push: pushes value to a list (puts it at the end of the list)
Example: list#/push|names|'Robert'/#
get: gets value of list item at an index
Example: list#/get|firstName|names|1/#
The example above gets the first item of the list 'names' and stores it in a variable 'firstName'.
set: sets value of an item at an index
Example: list#/set|names|1|'Josh'/#
Example above sets the first value in the list 'names' to 'Josh'.
len: gets the lenght of a list
Example: list#/len|listLenght|names/#
Example above gets the lenght of the list 'names' and stores it in a var 'listLenght'.
pop: removes last item of list and saves it
Example: list#/pop|lastName|names/#
Example above removes the last item of the list 'names' and stores it in a var 'lastName'.
clear: clears a list.
Example: list#/clear|names/#
Gets the sine, cosine, tangent of a number.
Syntax: sin#/*where to store result*|*dg/rad*|*number*/#
Example
Suffixes are special characters at the end of a command, to change the way it behaves.
They are 1 character long
Example: spew#/'Hello world!'/#*suffix*
Example above shows the location of suffixes
if you don't use a suffix, nothing about the command changes (wow).
the ? suffix makes it so that the command can only be executed once. Example:
create#/x|1/#
spew#/x/#
mark#/loop/#
add#/x|x|1/#?
spew#/x/#
go#/loop/#
because of the ? suffix at the end of the add command, x is increased by 1 only once.
!
the ! suffix makes it so that if a command fails, the program exits early. Example:
create#/x|1/#
... some code between ...
create#/x/#!
because of the ! suffix, instead of just printing a warning, the program exits.
If you use any suffix that's not declared here, the line acts as a comment.
It's the best way to make comments without the interpreter shouting at you, and those suffix characters can also be targeted by ifskip to toggle optional blocks on or off.