The Forf Language

Welcome to Forf! PUNCH

Forf is a simple, postfix, stack-based programming language. It was designed to be used as an extension language for games. Forf programs run in fixed size memory and can be time-constrained.

Forf was heavily influenced by the PostScript programming language.

About Stacks

Central to the operation of Forf is the notion of a stack. A stack is a last-in-first-out (LIFO) list, like a stack of dishes. Items can be "pushed" onto the top of the stack, or "popped" off the top of the stack. Items may only be pushed or popped, meaning the top stack element is the only element that can be accessed. To get to the third item down in a stack, it is necessary to first pop two items off.

Data Types

There are three data types in Forf: Integers, Substacks, and Procedures.

Integers

Integers are stored as the "long" type and have whatever boundaries the host CPU and C compiler enforce. They may be entered in decimal (12), octal (014), or hex (0xC), and may be positive or negative.

The following are valid integers:

Procedures

Data is read one by one from your program and either pushed onto the data stack (integers and substacks) or evaluated (procedures). When a procedures is evaluated, it pops zero or more elements off the data stack, does something with them, and then pushes zero or more elements back onto the stack.

The "+" procedure, for instance, pops two values, adds them, and pushes the result. The following data stack:

[bottom] 58 88 5 [top]

When given to the "+" procedure, would yield:

[bottom] 58 93 [top]

Substacks

Substacks are groups of data on the data stack. They are used only by the "if" and "ifelse" procedures, and are denoted by "{" (start substack) and "}" (end substack). Substacks may be nested.

The following will result in 58 on the top of the stack:

5 8 < { 50 8 + } { 50 8 - } ifelse

Comments

Anything inside parenthesis is ignored by the forf interpreter.

Built-in Procedures

The following procedures are built in to Forf. Since the language was designed to be extended, your game provides additional procedures.

Unary Operations

These procedures pop one value and push one.

Binary Operations

The following procedures pop two values and push one. They work as in an RPN calculator, meaning that 8 4 / yields 2.

Comparison

These procedures pop two numbers and compare them, pushing 1 if the comparison is true, 0 if false. For instance, 5 3 > yields 1.

Conditional Procedures

Stack Manipulation

Memory

Your game may provide you with one or more memory slots. These are like variables in other languages, and may persist across invocations of your program.

Examples

Compute 58²:

58 58 *

Compute 58³:

58 58 58 * *

Another way to compute 58³:

58 dup dup * *

The ifelse example, which does a comparison and puts 58 on the stack:

5 8 < { 50 8 + } { 50 8 - } ifelse

Another way to do that:

50 5 8 < { 8 + } { 8 - } ifelse

Yet another way:

50 8 5 8 < { + } { - } ifelse

Is memory slot 3 greater than 100?

3 mget 100 >

Given x, if x² is greater than 100 yield x², otherwise 0:

dup dup * 100 > { dup * } { pop 0 } ifelse

Another way to do the same thing:

dup * dup 100 < { pop 0 } if

Given coordinates (x, y) on the stack, is the distance to (x, y) less than 88? This compares x²+y² against 88².

dup * exch dup * + 88 88 * <

Perform different actions given some number between 0 and 3:

dup 0 = { action0 } if
dup 1 = { action1 } if
dup 2 = { action2 } if
dup 3 = { action3 } if
pop