"PostFix REPL" is a simple REPL (read-eval-print-loop) for the "PostFix" language described in the book Design Concepts in Programming Languages. I haven't found any interpreters or compilers to play with described mini-language, so I decided to write my own.
PostFix is 'A Simple Stack Language' (see page 8 in the book).
PostFix language grammar (informally):
program ::= (start-token natural-number command-list)
start-token ::= postfix
natural-nuber ::= Any nonnegative integer (0, 1, 2, etc.)
command-list ::= command
| command command-list
command ::= numerical
| command-token
| executable-sequence
numerical ::= Any integer numeral. E.g., 17, 0, -3, etc
command-token ::= add
| sub
| mul
| div
| rem
| lt
| gt
| eq
| pop
| swap
| sel
| nget
| exec
executable-sequence := (command-list)
Every "PostFix" program starts with (postfix
keyword followed by non-negative number which represents number of
arguments to the program with an arbitrary list of commands. Sample programs in PostFix language:
(postfix 0 4 7 sub)
(postfix 2 add 2 div)
(postfix 4 4 nget 5 nget mul mul swap 4 nget mul add add)
(postfix 1 ((3 nget swap exec) (2 mul swap exec) swap) (5 sub) swap exec exec)
Commands:
N
. Push the numeral N onto the stack.add
(addition). Call the top stack valuev1
and next top-to-stack valuev2
. Pop these two values off the stack and push the result ofv2 + v1
onto the stack. If there are fewer than two values on the stack or the two top values aren't both numerals, signal an error.sub
Call the top stack valuev1
and next top-to-stack valuev2
. Pop these two values off the stack and push the result ofv2 - v1
onto the stack. If there are fewer than two values on the stack or the two top values aren't both numerals, signal an error.mul
(multiplication). Call the top stack valuev1
and next top-to-stack valuev2
. Pop these two values off the stack and push the result ofv2 * v1
onto the stack. If there are fewer than two values on the stack or the two top values aren't both numerals, signal an error.div
(integer division). Call the top stack valuev1
and next top-to-stack valuev2
. Pop these two values off the stack and push the result ofv2 / v1
onto the stack. If there are fewer than two values on the stack or the two top values aren't both numerals, signal an error. Signal an error ifv1
is zero.rem
(reminder of integer division). Call the top stack valuev1
and next top-to-stack valuev2
. Pop these two values off the stack and push the reminder of the result ofv2 / v1
onto the stack. If there are fewer than two values on the stack or the two top values aren't both numerals, signal an error. Signal an error ifv1
is zero.lt
. Call the top stack valuev1
and next top-to-stack valuev2
. Pop these two values off the stack. Ifv2 < v1
, then push1
(a true value) on the stack, otherwise push a0
(false). If there are fewer then two values on the stack or the top two values aren't both numerals, signal an error.gt
. Call the top stack valuev1
and next top-to-stack valuev2
. Pop these two values off the stack. Ifv2 > v1
, then push1
(a true value) on the stack, otherwise push a0
(false). If there are fewer then two values on the stack or the top two values aren't both numerals, signal an error.eq
. Call the top stack valuev1
and next top-to-stack valuev2
. Pop these two values off the stack. Ifv2 = v1
, then push1
(a true value) on the stack, otherwise push a0
(false). If there are fewer then two values on the stack or the top two values aren't both numerals, signal an error.pop
. Pop the top element off the stack and discard it. Signal an error if the stack is empty.swap
. Swap the top two elements of the stack. Signal an error if the sack has fewer than two values.sel
. Call the top three stack values (from top down)v1
,v2
, andv3
. Pop these three values off the stack. Ifv3
is the numeral0
, pushv1
onto the stack; ifv3
is a nonzero numeral, pushv2
onto the stack. Signal an error if the stack does not contain three values, or ifv3
is not a numeral.nget
. Call the top stack valuev_index
and the remaining stack values (from top down)v1
,v2
, ...,vn
. Popv_index
off the stack. Ifv_index
is a numerali
such that1 <= i <= n
andvi
is a numeral, pushvi
onto the stack. Signal an error if the stack does not contain at least one value, ifv_index
is not a numeral, ifi
is not in the range[1..n]
, or ifvi
is not a numeral.exec
. Pop the executable sequence from the top of the stack, and prepend its component commands onto the sequence of currently executing commands. Signal an error of the stack is empty or the top stack value isn't an executable sequence.(C1 ... Cn)
. Push the executable sequence(C1 ... Cn)
as a single value onto the stack. Executable sequences are used in conjunction withexec
.
In "PostFix" all parentheses are required and none are optional. Moving parentheses around changes the structure of the program and most likely changes its behavior.
Use: sbt run
command to run interactive interpreter. Type exit
or :q
to exit the interpreter.
Step 0: Fork it!
Step 1: Build it.
In order to build "PostFix REPL" from sources you'll need to have:
- Scala 2.12.2 SDK
- Sbt 0.13.15
Compile and run tests: sbt clean test
. Make sure that build works and all tests pass before you start adding new
features or fixing bugs.
Step 2: Submit an issue. Good issue answers two
questions: what
and why
.
Step 3: Work in a separate branch, prepend every commit by issue number like #10 your commit message
.
Step 4: Make a Pull Request from the branch in your fork repository to the master branch in this repository.
Done.