vfl
vfl (viba's FALSE-like) is a FALSE-like programming language. It is very similar to FALSE in spirit (ie. a very terse, minimal stack-based language) but is different in a few ways. Key differences from FALSE include:
- Access to an unbounded array of variables (well, technically bounded by the 32-bit integer limit)
- Control flow works differently
- Add modulo (
%
) and less-than (<
) operators (but sacrifice the unary negation operator) - Input/output between different "ports", to facilitate arbitrary implementation defined I/O
- Uses only ASCII characters
- Proves viba is unable to make a programming language with a name not starting with 'v'
links
description
vfl uses a main stack (usually just called "the stack") for most computation, in addition to a call stack used for function calls. The size of each stack is implementation defined.
Programs have access to an array of variables. Each variable is addressed with a non-negative integer. The size of the variable array is implementation defined. All variables are initialized to zero.
All values in vfl (including on the main stack, the call stack, and in variables) are 32-bit signed integers (using two's compliment encoding). Of course, many programming languages don't provide such control over data types, so vfl implementations written in such languages might ignore this.
Boolean values are represented as 0 for false, and -1 (ie. ~0 or all bits set) for true. This is so that bitwise NOT is equivalent to boolean NOT. However, any nonzero value is considered to be true.
All whitespace (and in fact, all characters with no meaning in vfl) are generally ignored, but may be necessary to separate consecutive integer literals (eg. 123 456
).
Below is a list of symbols and their meanings in vfl. The "Synopsis" column uses the common notation from Forth, which indicates the values the command pops from the stack, followed by the values the command pushes to the stack.
Symbol | Synopsis | Description |
---|---|---|
`...` |
-- |
Any characters between backticks is a comment, and are thus ignored. |
123 |
-- 123 |
Push a (non-negative) integer literal onto the stack. |
'c |
-- 'c' |
Push the given character code onto the stack. |
a-z |
-- a-z |
Push the corresponding integer from 0 to 25 onto the stack. This is intended to emulate the single-letter variable names from FALSE, but may also be used as a shorter way to write some integers. |
$ |
x -- x x |
DUP: Duplicate the top stack value. |
\ |
x y -- y x |
SWAP: Swap the top two stack values. |
_ |
x -- |
DROP: Pop a value from the stack and discard it. |
@ |
x y z -- y z x |
ROT: Take the third stack value from the top and move it to the top. |
? |
x y z 2 -- x y z x |
PICK: Take the Nth value (starting from 0) from the top of the stack and duplicate it to the top. |
: |
value addr -- |
Store a value into the variable at the given address. |
; |
addr -- value |
Read the value of the variable at the given address. |
+ |
x y -- x+y |
Push x plus y . |
- |
x y -- x-y |
Push x minus y . |
* |
x y -- x*y |
Push x multiplied by y . |
/ |
x y -- x/y |
Push x divided by y (rounded down). |
% |
x y -- x%y |
Push x modulo y . |
& |
x y -- x&y |
Push x bitwise AND y . |
| |
x y -- x|y |
Push x bitwise OR y . |
~ |
x -- ~x |
Push bitwise NOT x . |
= |
x y -- x==y |
Push -1 if x equals y , 0 otherwise. |
> |
x y -- x>y |
Push -1 if x is greater than y , 0 otherwise. |
< |
x y -- x<y |
Push -1 if x is less than y , 0 otherwise. |
{...} |
-- lambda |
Define a lambda (or anonymous function or procedure or whatever you want to call it) and push it onto the stack. |
! |
lambda -- |
Execute a lambda. |
(...) |
condition -- |
Run a block of code only if the condition is true (nonzero). If-else can be expressed as: condition$(true)~(false) |
[...] |
-- |
Loop a block of code. |
^ |
-- |
Break from the current loop. While loops can be expressed as: [condition~(^)body] |
# |
-- |
Immediately skip to the next iteration of the current loop (ie. a "continue" statement). |
. |
value port -- |
Output a value to a port. |
, |
port -- value |
Input a value from a port. |
"..." |
port -- |
Output each character of a string sequentially to the given port. If a \ is encountered, it is skipped over and the character following it is output unconditionally. This allows for the escape sequences \" and \\ . |
ports
Values may be input and output through different numbered ports. Ports 0 and 1 are reserved and always have the following behaviour:
Port | Out/In | Description |
---|---|---|
0 | out | Write the given byte to stdout. |
in | Return a byte read from stdin, or -1 if EOF. | |
1 | out | Write the given value formatted as a decimal integer (without trailing newlines or whitespace) to stdout. |
in | Return a decimal integer read from stdin. |
The behavour of all other ports is implementation defined. Reading input from a port which goes unused by an implementation always returns 0.