Forte is an stack-based programming language implemented in C++. It is inspired by Forth, but it uses its own type system, syntax, module system, runtime model, and planned bytecode compilation + execution.
The project is currently under active development.
Forte programs are made of whitespace-separated tokens. Literal values are pushed onto a stack, and words operate on values from that stack.
Example:
1 2 + .#
This pushes 1 and 2, adds them, and prints the result as a number.
Forte currently supports:
- Stack-based execution
- Native C++ modules loaded with
dlopen - Runtime symbol scopes
- Variables backed by runtime data memory
- Prefix words such as
def,if,while,for,rep,var,cast, andimport - User-defined words
- Basic arithmetic, bitwise, comparison, stack, data, and I/O words
Forte natively supports the following primitive types which, for ease of manipulation, take up 8 bytes each on the stack.
| Marker | Name | Meaning |
|---|---|---|
# |
num | double number |
$ |
ptr | pointer |
% |
word | raw bitfield |
@ |
char | character |
Each type has its own marker, which is used in casts, documentation, and stack-effect comments.
var x
10 x <-
x -> .#
Variables evaluate to pointers. Use <- to store and -> to fetch.
'a' .@
"hello" print
Strings are represented as stack strings terminated by a null character.
def square
dup *
done
5 square .#
User functions are defined using the "def" prefix.
3 rep
"hi" print \n
done
1 if
"true" print
else
"false" print
done
while
condition
do
body
done
for
init
cond
condition
step
update
do
body
done
Forte supports line comments and parenthesized comments.
; this is a line comment
( this is an inline comment )
+ - * /
& | ^ ~ << >>
> < = != <= >=
&& || !
| Word | Effect |
|---|---|
drop |
remove the top value |
dup |
duplicate the top value |
<> |
swap the top two values |
over |
copy the second value to the top |
rot |
rotate the top three values |
nip |
remove the second value |
tuck |
copy the top value under the second value |
drop2 |
drop the top two values |
dup2 |
duplicate the top two values |
| Word | Effect |
|---|---|
<- |
store a value at a pointer |
-> |
fetch a value from a pointer |
| Word | Effect |
|---|---|
in |
read one character |
.# |
print a number |
.@ |
print a character |
.$ |
print a pointer |
.% |
print a word / bit value |
print |
print a stack string |
println |
print a stack string and newline |
\n |
print newline |
\t |
print tab |
cat |
concatenate stack strings |
flush |
flush standard output |
Forte is split into interpreter components and native modules.
State coordinates execution. It owns or references:
- a
Runtime - a
Scope - parent state information
- prefix parsing context
- local data-base cleanup information
State handles token evaluation, symbol resolution, user function calls, prefix handling, and interaction with the runtime stack/data.
Runtime owns execution data:
- stack
- data memory
- loaded module handles
It provides stack operations, data allocation, pointer validation, and module-handle cleanup.
Scope stores symbols and supports parent-scope lookup.
Symbols may refer to:
- native functions
- prefix functions
- data pointers
- user-defined token bodies
Scope also tracks block prefixes that consume tokens until done.
The loader handles:
- Forte source file loading (libraries)
- native module loading through
dlopen - calling module initialization functions with
dlsym
Helpers currently include tokenization and type conversion utilities.
The tokenizer supports:
- whitespace-separated tokens
- quoted strings
- quoted characters
- escape sequences
;line comments( ... )comments
Forte loads native modules from shared objects.
Current modules include:
modules/prefix.so
modules/core.so
modules/io.so
The core module registers arithmetic, bitwise, comparison, logic, stack, control, and data words.
Example native registration:
extern "C" void forte_init_module(forte::State* state) {
state->newEntry("+", add);
state->newEntry("-", sub);
}The prefix module registers prefix words such as:
for
while
rep
if
cast
var
def
import
Block prefixes are registered so nested done depth can be tracked correctly.
The I/O module registers input and output words such as:
in
.#
.@
.$
.%
print
println
\n
\t
cat
flush
Interactive mode:
./forteRun a file:
./forte program.frte