mirror of https://github.com/dirtbags/tanks.git
212 lines
4.6 KiB
Markdown
212 lines
4.6 KiB
Markdown
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:
|
|
|
|
* 58
|
|
* -58
|
|
* 0x3A (hex)
|
|
* 072 (octal)
|
|
|
|
|
|
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.
|
|
|
|
* `x ~` (bitwise invert)
|
|
* `x !` (logical not)
|
|
* `x abs` (absolute value)
|
|
|
|
|
|
Binary Operations
|
|
-----------------
|
|
|
|
The following procedures pop two values and push one. They work as in
|
|
an RPN calculator, meaning that `8 4 /` yields `2`.
|
|
|
|
* `y x +` (y + x)
|
|
* `y x -` (y - x)
|
|
* `y x *` (y * x)
|
|
* `y x /` (y / x)
|
|
* `y x %` (y modulo x)
|
|
* `y x &` (y and x)
|
|
* `y x |` (y or x)
|
|
* `y x ^` (x xor x)
|
|
* `y x <<` (y shifted left by x)
|
|
* `y x >>` (y shifted right by x)
|
|
|
|
|
|
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`.
|
|
|
|
* `y x >` (y greater than x)
|
|
* `y x >=` (y greater than or equal to x)
|
|
* `y x <` (y less than x)
|
|
* `y x <=` (y less than or equal to x)
|
|
* `y x =` (y equal to x)
|
|
* `y x <>` (y not equal to x)
|
|
|
|
|
|
Conditional Procedures
|
|
----------------------
|
|
|
|
* `x { i ... } if` (if x, evaluate i)
|
|
* `x { i ... } { e ... } ifelse` (if x, evaluate i, otherwise evaluate e)
|
|
|
|
|
|
Stack Manipulation
|
|
------------------
|
|
|
|
* `x pop` (discard x)
|
|
* `x dup` (duplicate x)
|
|
* `y x exch` (exchange x and y on the stack)
|
|
|
|
|
|
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.
|
|
|
|
* `y x mset` (store y in slot x)
|
|
* `x mget` (retrieve value in slot x)
|
|
|
|
|
|
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
|
|
|
|
|