Justif & Recursion

Justif & Recursion, or, short, JUSTIF, is a small programming language with the following features:

Here is a Hello, World-type program in JUSTIF:

~1?.0=_,.$="Hello, World",=2:~2?.1!.0?>.1!.0,._+1,=2:0:0

And here is an example that will print the first 10 fibonacci numbers.

~1?.2=$,.0=1,.3=$,=2:~_?+._=10?!.0,.1=.$,._+.3,.0=.$,.$=.1,.2+$,
=_:0:_

Finally, here is atoi in good JUSTIF style:

~1?.2="1182",
.0=_,.1=$,=3,
!.$:~2?.3=.$!
.0,*.$=47?+.3
=58:0:~3?=2?.
$-48,.1*10,.$
+.3,.0+1,=3:0
:I AM JUSTIF_

Download

You can download the complete python-powered sourcecode to JUSTIF here (3602 bytes). It includes the sample programs mentioned below. You can also find a somewhat less readable version of that parser on my Obfuscated Python page.

The JUSTIF tutorial

The following sections describe how to use JUSTIF for programming.

Numbers, Whitespaces and Comments

Numbers are just plain decimal numbers. A future version of JUSTIF might feature ENHADINUMs support, but right now it doesn't. Whitespaces are SPACE, TAB, NEWLINE plus all uppercase and lowercase letters. This means there are no explicit comment specifiers needed. For example, you can modify the HELLO-WORLD example from above like this:

IF CALLED BY INDEX ONE ~1 ? 
DO 
    ASSIGN ZERO TO MEMORY CELL ZERO .0=_,
    ASSIGN STRING TO MEMORY CELL ONE .$="Hello, World",
    CALL SELF RECURSIVELY WITH INDEX TWO =2:
IF CALLED BY INDEX TWO ~2 ? 
    IF CELL ONE INDEXED BY CELL ZERO IS NOT NULL .1!.0 ? 
    DO  
        PRINT CHARACTER IN CELL ONE INDEXED BY CELL ZERO >.1!.0,
        INCREMENT CELL ZERO BY ONE ._+1,
        CALL SELF RECURSIVELY WITH INDEX TWO =2:0
ELSE DO NOTHING :0

which just might make the program more understandable. Furthermore, for perl programmers deciding to switch to JUSTIF, there are two helper tokens

_ - use the last number
$ - use the number used before the last number

For example, the expression

!.0,.1=.0,.1+.3

can be written as

!.0,.1=.$,._+.3

where the $ is replaced by 0 because it is the number used before the last number, and _ is replaced by 1 because it is the last number used. (Note that $ and _ do not chance the last number used).

Accessing Memory

JUSTIF has no variables, just a large memory array. Memory cells can contain either numbers or strings, nothing else. Memory cells are directly addressed with an index:

.0 - cell 0
.1 - cell 1
...
.n - cell n

You can access memory indirect by using the syntax

..0 - cell indexed by cell 0
..1 - cell indexed by cell 1
...
..n - cell indexed by cell n

If the cell contains a string, you can access the characters of the string (as integer values) with the syntax

.0!0 - character 0 of string at cell 0
.0!1 - character 1 of string at cell 0
...
.0!n - character n of string at cell 0
.1!0 - character 0 of string at cell 1
...
.n!0 - character 0 of string at cell n

You can access the characters in a string cell indirectly by using the syntax

.0!.1 - character indexed by cell 1 of string at cell 0
.0!.2 - character indexed by cell 2 of string at cell 0
...
.0!.n - character indexed by cell n of string at cell 0

You can do the following operations on cells

CELL '=' VALUE - assign value to cell
CELL '+' VALUE - increment cell by value
CELL '-' VALUE - subtract value from cell
CELL '*' VALUE - multiply cell by value
CELL '/' VALUE - divide cell by value

Values can be either integers, or strings, or other memory cells. Here are some example expressions:

.0=42 - assign the number 42 to the cell 0
.0="Test" - assign the string "Test" to the cell 0. 
.1=..0 - assign the cell indexed by the cell 0 to the cell 1

Doing I/O

There are two output commands

>cell - output cell as character
!cell - output cell as digit

Here are some examples

!42 - print 42
!.0 - print the cell 0 as integer
>.0 - print the cell 0 as character
!..0 - print the cell indexed by the cell 0 as integer
>.0!.1 - print the cell 0 indexed by the cell 1 as character

There is an input command, "<", that is currently not supported.

Comparison

You can compare a memory cell to another memory cell or to an integer constant by using the syntax

+cell=value - check if the cell is less than the value
-cell=value - check if the cell is equal to the value
*cell=value - check if the cell is larger than the value
/cell=value - check if the cell is not equal to the value

Here are some examples

+.1=10 - check if the cell 1 is less than 10
+.1=.2 - check if the cell 1 is less than the cell 2
+.1==2 - check if the cell 1 is less than the result of calling
         self recursively with index 2
-.1=10 - check if the cell 1 is equal to 10
*.1=10 - check if the cell 1 is greater than 10
/.1=10 - check if the cell 1 is not equal to 10

You can check if the current index is a specified value by using the syntax

~1 - check if the index is 1
~2 - check if the index is 0
...
~n - check if the index is n
~.0 - check if the index is the cell 0
~.1 - check if the index is the cell 1
...
~.n - check if the index is the cell n

The IF command

The IF-command is the only traditional logic construct in JUSTIF. It works exactly like the ?: operator in C. Example:

.0?.1=1:.1=2 - if .0 is true, assign 1 to .0, otherwise assign 2 to .0

You can use the comparison operators described above. Instructions can be grouped by using commas. Example:

.0?.1=1,.2=1:0 - if .0 is true, assign 1 to .1, assign 1 to .2,
    otherwise do nothing.

Calling self recursively

Each JUSTIF program is called initially with an index 1. It can call itself recursively with a new index. The syntax is

=1 - call self with index 1
=2 - call self with index 2
...
=n - call self with index n

Syntax

The complete syntax for JUSTIF reads:

CODE = INSTRUCTIONS.
IF = MEMORY|ISINDEX|COMPARE '?' INSTRUCTIONS ':' INSTRUCTIONS.
COMPARE = ('+'|'-'|'*'|'/') MEMORY '=' (DECINT|MEMORY).
ISINDEX = '~' (DECINT|MEMORY).
INSTRUCTIONS = INSTRUCTION { ',' INSTRUCTION }.
INSTRUCTION = RECURSION|MEMSET|INPUT|OUTPUT|IF.
OUTPUT = ('>'|'!') MEMORY.
INPUT = '<' MEMORY.
RECURSION = '=' DECINT.
MEMSET = MEMORY ('='|'+'|'*'|'/'|'-') DECINT|STRING|MEMORY.
STRING = '"' ascii '"'.
MEMORY = '.' (DECINT|MEMORY) ['!' (DECINT|MEMORY)]
DECINT = '_' | '$' | DECDIGIT {DECDIGIT}.
DECDIGIT = '0' .. '9'.