GAXT
Designed by | Fancryer |
---|---|
Appeared in | 2022 |
Dimensions | one-dimensional |
Computational class | Total |
Reference implementation | Interpreter |
Influenced by | Forth, Brainfuck |
File extension(s) | .gaxt |
GAXT is an esoteric programming language created by Fancryer and uses two stacks: a stack for calculations (hereinafter - CalcStack) and a stack for variables (hereinafter - VarStack). Current GAXT version: v0.2-beta. There is an unfinished Java interpreter that will be publicly available after the stable release. All supported tokens, represented as a string: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+-*/_`<=>?$:;~%{|}\^()@[].,#!.
Values
GAXT only has 64-bit signed integers. Accordingly, all mathematical operations result in integers, including division.
Variables
GAXT has a 26-element array for storing variable values, one for each letter from a to z. Initially, all variables are initialized to zero. To work with a variable, you need to put its name in varStack, you can do this regardless of which stack is currently in use. Only variable names are passed to VarStack, their values are stored in an array and retrieved during operations.
Constants (DEPRECATED after GAXT 0.2-beta release)
There are 26 constants in GAXT, one for each Latin letter from A to Z. In GAXT v0.1-alpha all constants are predefined. Constants were provided to make it easier to print characters, but they can also be used as normal values. Below are the values of all constants in alphabetical order.
- A: 10
- B: 20
- C: 30
- D: 40
- E: 50
- F: 60
- G: 70
- H: 80
- I: 90
- J: 100
- K: 200
- L: 300
- M: 400
- N: 500
- O: 600
- P: 700
- Q: 800
- R: 900
- S: 1000
- T: 2000
- U: 3000
- V: 4000
- W: 5000
- X: 6000
- Y: 7000
- Z: 8000
Operators
All operators are written in postfix form.
Each mathematical or logical operator performs the following actions depending on the current stack:
CalcStack | VarStack |
---|---|
|
|
3. Creates a temporary variable ρ for the result of the operation.
4. Pushes ρ on the stack. |
Math
Character | Operator | ρ |
---|---|---|
+ | Add | α + β |
- | Subtract | α - β |
* | Multiply | α * β |
/ | Divide | α / β |
_ | Concat | str(α)..(str(β)) |
The concatenation operation is performed differently depending on the sign of α and β (the '-' and '+' before α or β show their sign):
Concat | +α | 0 | -α |
---|---|---|---|
+β | αβ | β | -αβ |
0 | α | 0 | -α |
-β | -αβ | -β | αβ |
Logical
The result of logical operations is always either 0 or 1.
Character | Operator | ρ |
---|---|---|
` | Nor | α ↓ β |
< | Less | α < β |
= | Equal | α = β |
> | Greater | α > β |
Print operations do not affect the state of the stack, but it is not possible to remove printed characters from the output.
CalcStack | VarStack |
---|---|
Peeks the value from the top of the stack and assigns it to the temporary variable β. |
Peeks the value of a variable from the top of the stack and assigns it to the temporary variable β. |
Character | Operator | Action |
---|---|---|
? | PrintInt | Prints β as int (including '-' sign if b is negative). |
$ | PrintChar | Prints β as a character if it is in ASCII and can be printed. |
Stack
Character | Operator | Action |
---|---|---|
: | Assign | Assigns the value of the top of the current stack to the top of another stack. This removes the top of the current stack. Also, the operation cannot be performed if the other or current stack is empty. |
; | Reverse | Reverses current stack. |
~ | Shave | Removes the top of the stack. The operation cannot be performed if the current stack is empty. |
% | Clear | Erases the stack completely. |
Flow
Character | Operator | Action |
---|---|---|
{ | If | Executes the code before the "then" statement if the top of the current stack is non-zero, otherwise execution jumps to the character after the "then" statement. |
| | Then | Separates the code that is executed when the condition before the "if" is true, from the code that is executed otherwise. |
} | Else | Closes if-then-else group. |
\ | Break | Breaks one level of nesting: exits the current loop or macro. |
^ | Continue | Jumps to the beginning of the current nesting level (loop or macro) regardless of the state of the stacks. |
Macro
A macro in GAXT is similar to a procedure in conventional programming languages: it stores code that is executed immediately after the macro is called, and does not require a program finish statement. At the moment (GAXT v0.1-alpha) nested macros are not allowed.
Character | Operator | Action |
---|---|---|
( | Read | Starts macro recording, any characters before the "write" statement are not executed. |
) | Write | Ends macro recording and stores it in the macro list. |
@ | Call | Calls the macro written at the index at the top of the current stack. It is not possible to call a macro if it has not been recorded before. In this case, the operator is ignored. |
Loop
Cycles in GAXT are only with a postcondition. Loops of any nesting are allowed up to level 263-1.
Character | Operator | Action |
---|---|---|
[ | Repeat | Increments the nesting level, executes all code up to the "Until" statement. |
] | Until | Exits the loop if the top of the current stack is zero or empty, otherwise jumps to the character after the "Repeat" of this loop. |
Label
Labels in GAXT are analogous to goto in C or jmp in assembly language. You can create or load any label at any time.
Character | Operator | Action |
---|---|---|
. | Save | Creates a new label and adds it to the list of labels. You can create up to 263-1 labels. |
, | Load | Jumps to the label at the index at the top of the current stack. The label cannot be loaded if it has not been previously recorded. In this case, the operator is ignored. |
Service
Character | Operator | Action |
---|---|---|
# | Switch | Changes the current stack: CalcStack -> VarStack or VarStack -> CalcStack. |
! | Finish | Terminates the entire program even when called in a loop or procedure, regardless of the current nesting level. |
String
Since version 0.2-beta, GAXT has added support for strings (interpolated too). A string is a sequence of numbers written upside down onto the stack. The length of the string is written next.
Character | Operator | Action |
---|---|---|
" | String edge | Toggles line-not-line mode (actually just represents a string boundary). On completion of a string, pushes it onto the stack (see above). |
& | Raw code | Can only be inserted into a string, allowing almost any code to be executed while the string is being pushed onto the stack (a potentially dangerous operation). |
' | Formatter | Escapes (replaces) the next character according to the table below. |
Format character | Name | Action |
---|---|---|
whitespace | Fmt_space | Whitespace (ASCII) character. |
\n | Fmt_new_line | Line feed character. |
\t | Fmt_tab | Tabulation character. |
! | Fmt_finish | Exclamation mark character. |
a-z (any variable) | Fmt_var | The value of the variable as a number (as when using '?'). |
Undefined and comments
Any character that is not a digit, variable/constant name, or operator must be ignored in all implementations of GAXT or derived programming languages. All characters written after the "Finish" statement are also ignored.
Examples
Hello world
A typical "Hello, world!" print. | This example uses delta encoding to reduce the length of the source code. | GAXT 0.2-beta realization |
---|---|---|
72_$~ J1+$~ 10_8_$~ 10_8_$~ 11_1_$~ 44_$~ 32_$~ 11_9_$~ 11_1_$~ 11_4_$~ 10_8_$~ J$~ 33_$~! |
G2+$ C+1-$ 7+$$ 3+$ G-3+$ A-2-$ JB+1-$ 8-$ 3+$ 6-$ 8-$ F-7-$~! |
"Hello,' world'!"~[$~]! |
78 characters | 49 characters | 23 characters (and code is also easier to read) |
First 10 Fibonacci numbers
This example should work in theory, but has not been tested in practice. Translated from C (do-while loop).
An: 0x: 1y: 0z: 0i: # [ x? # C2+$ 1x: 1y: # +z: # 1y: # x: # 1z: # y: # 11i:+ #i: # in< ]!
Conditional branching
This program will print "A" if 2<3, and "B" otherwise.
23< { I7+ | I8+ } $~~!
Macro test
Since GAXT ignores any characters that are not included in its set of tokens, and ASCII-Latin is included in it (set), the comments are in Russian.
(a0:b0:) обнулить а и б (#?~#) напечатать значение вершины другого стека (C2+$~) напечатать пробел ($~ 2@ F1+$~ 2@) напечатать символ и пробел и равно и пробел a3: а равно трём I7+ 3@ a1@ 2@ напечатать а равно и его значение и пробел b5: б равно пяти I8+ 3@ b1@ напечатать б равно и его значение 0@ очистить а и б A$ напечатать перевод строки I7+ 3@ a1@ 2@ напечатать а равно и его значение и пробел I8+ 3@ b1@ напечатать б равно и его значение ! финиш
99 bottles of beer
GAXT 0.1-alpha | GAXT 0.2-beta |
---|---|
( 9@ H3+-$ H1-+$ 9-$ G-$ F6++$ 3+$$ A3++$% ) ( C2+$ G9++$ 1-$ G8+-$ H4++$ A2+-$ 3-$ G1--$ H7++$ B2+-$ A1++$$% ) ( H4+$ A3++$ A+$ 6-$ F9+-$ G9++$ 1-$ 9-$ F9+-$ F8++$ A1++$ 8+$ 9-$ G8+-$ F5++$ A3++$ A-$ F8+-$ H+$ A5+-$ A8++$$ H3+-$ G3++$ A1++$ H4+-$ F5++$ A7++$ 3-$ 6+$ 7-$ A-$ E6+-$ A2+-$% ) ( I8+$ A3++$ 5+$$ 8-$ 7-$ F9+-$ G9++$ 9-$ G-$ F6++$ 3+$$ A3++$% ) (0@1@) (#ba+?ba-%#) (D4+$ A2+-$%) (D9+$ A7+-$%) (D6+$C6+-$%) ( C2+$ F6++$ A3++$ 5+$$ 8-$ 7-$ A4++$ ) ( 5@4@6@5@0@ 8@ 2@#b?#4@8@ #ba-# ) ( JA+$ 1+$ G9+-$ G7++$ 2+$ 3+$ A3+-$% ) 98_b: a1: b#[#A@#]# 7@3@1@6@7@3@8@ 2@A1+@4@! |
( "'b' bottles' of' beer' on' the' wall,' 'b' bottles' of' beer.'\n"~[$~] "Take' one' down' and' pass' it' around,' &#ba-#&'b' bottles' of' beer' on' the' wall'\n"~[$~] ) b99_: a1: #[%#0@#b]%! |
Grammar
Below is the formal GAXT grammar in EBNF (ANTLR version).
grammar GAXT; program: expression* FINISH EOF; expression: loop | store_macro | stack_push | stack_op | print | direct_stack_op | service | flow | call_macro | label; label: SAVE | LOAD; string: STRING_EDGE string_chars=string_char* STRING_EDGE; expr_in_string: loop | store_macro | VARIABLE | CONSTANT | DIGIT | stack_op | print | direct_stack_op | service | flow | call_macro | TOKEN; string_char: expr_in_string | formatter; formatter: Fmt_variable | Fmt_space | Fmt_tab | Fmt_new_line | Fmt_finish | fmt_expr; Fmt_variable: FORMAT VARIABLE; Fmt_space: FORMAT ' '; Fmt_tab: FORMAT '\t'; Fmt_new_line: (FORMAT '\n') | '\'\\n'; Fmt_finish: FORMAT '!'; fmt_expr: AMPERSAND expression* AMPERSAND; AMPERSAND: '&'; flow: full_branch | short_branch | BREAK | CONTINUE; full_branch: IF true_branch=expression* THEN false_branch=expression* ELSE; short_branch: IF true_branch=expression* ELSE; service: SWITCH; direct_stack_op: ASSIGN | CLEAR | REVERSE | SHAVE; print: PRINT_INT | PRINT_CHAR; stack_op: stack_math | stack_logical; stack_logical: NOR | LESS | EQUAL | GREATER; stack_math: ADD | SUB | MULT | DIV | CAT; stack_push: string | VARIABLE | CONSTANT | DIGIT; loop: REPEAT expression* UNTIL; macro: store_macro | call_macro; store_macro: READ expression* WRITE; call_macro: CALL; FINISH: '!'; SPACE: [\r\n\t\u0020] -> skip; VARIABLE: [a-z]; CONSTANT: [A-Z]; DIGIT: [0-9]; ADD: '+'; SUB: '-'; MULT: '*'; DIV: '/'; CAT: '_'; NOR: '`'; LESS: '<'; EQUAL: '='; GREATER: '>'; PRINT_INT: '?'; PRINT_CHAR: '$'; ASSIGN: ':'; REVERSE: ';'; SHAVE: '~'; CLEAR: '%'; IF: '{'; THEN: '|'; ELSE: '}'; BREAK: '\\'; CONTINUE: '^'; READ: '('; WRITE: ')'; CALL: '@'; REPEAT: '['; UNTIL: ']'; STRING_EDGE: '"'; FORMAT: '\; SAVE: '.'; LOAD: ','; SWITCH: '#'; PROGRAM_END: EOF; COMMENT: ~ ( 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm'//variables a-m | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z'//variables n-z | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M'//constants A-M | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z'//constants N-Z | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'//digits | '+' | '-' | '*' | '/' | '_'//math | '`' | '<' | '=' | '>'//logical | '?' | '$'//print | ':' | ';' | '~' | '%'//direct_stack | '{' | '|' | '}' | '\\' | '^'//flow | '(' | ')' | '@'//macro | '[' | ']'//loop | '.' | ','//label | '#' | '!'//service | '"' | '\'' | '&'//string ) -> skip;