Simple Stack is a minimalist stack-based programming language. During execution, there is a single stack; all operations manipulate this stack. There is also a call stack, so the program can return from a procedure call. However, there are no local variables, or for that matter, any variables at all.
A program is a series of procedure definitions, separated by commas. A definition is a name, followed by zero or more commands (separated by whitespace). There are three possible commands:
,
, !
, and .
.
.
pops the top of the stack and discards it. It is an error if the stack is empty.
!
pops the top of the stack and executes it. If the word that was popped was the name of a procedure, calls that procedure; otherwise, prints the word. It is an error to use this command when the stack is empty.
There is no direct support for comments; however, you can achieve the same effect by defining a procedure that you never call (though be careful about commas, since those end the procedure).
When the interpreter starts, the stack is empty, and it'll execute the command main!
.
To make programming easier, there's also a slightly higher-level version of Simple Stack that can fairly easily be compiled to the lower-level version. This variant adds support for enums and switch statements to examine them, and reserves the characters [
and ]
. Programs that do not include brackets are the same in both versions of the language.
Programs are now a list of procedure and enum definitions. Enum definitions are just a list of values in brackets (no commas between the values, though the whole definition is separated from other definitions by commas). Enum types don't have names. Enum values should only be defined once, and should not have the same name as a procedure.
An additional command type is allowed: a list, in square brackets, of the form [name1 commands, name2 commands, name3 commands...]
. The set of names must be the same as an enum that's been declared. This command pops the current value (which must be one of the specified names, otherwise behavior is undefined) and executes the corresponding list of commands.
Each case in a switch statement becomes its own command, with a name containing brackets (thus not conflicting with any possible names in the higher-level language). The enum values are all procedures that push all commands for the cases selecting that value onto the stack. The switch statement executes the top of the stack, then pops enough off to get to the right command, and executes it. The commands for the cases then pop off the rest.
For instance,
[true false], foo [true yes!, false no!], not [true false, false true]
translates to something like
true true[0] true[1], false false[0] false[1], foo ! . !, true[0] yes!, false[0] no!, not ! !, true[1] . false, false[1] . true
where the names true[0]
, true[1]
, false[0]
, false[1]
, and the order in which they're pushed onto the stack, are implementation-dependent.