User:Ben Russell
I forgot my password, yet again. GAH! I'm usually pretty good with passwords.
Announcement
If you find some archaic license on any of these languages, disregard it. I don't care what you do with it anymore. I'd like to see it simply used as it should be. I am cleaning up all the licence crap now. --Ben Russell 05:31, 12 August 2008 (UTC)
Criminal convictions
- HighFive, the first, the worst.
- TheSquare, 2D multitasking language better suited for battle games.
- RETURN, just plain weird.
- MiniScript, something that's actually useful.
- An advanced SKI interpreter.
- A Brainfuck interpreter.
- A Befunge-98 interpreter.
SACHA
This is a programming language originally designed for RoboZZle as an alternative language. I have yet to genericise my interpreter.
A name or condition (cond) follows the same syntax as C; that is, [[a-z][A-Z]_]([[a-z][A-Z][0-9]_])*
.
All blocks are pre-parsed, but not pre-assigned. For @
blocks, the block is assigned to a function name. For ?
and ~
blocks, the block is executed, with the function and program counter (PC) set to AFTER the block.
There are two stacks, the value stack and the execution stack. The first stores names of functions. The second stores entries consisting of a pointer to a function and its respective PC.
Built-in functions cannot be overridden. When doing the ;
command, it checks the list of builtin functions first, and only if there isn't a function in that list does it attempt to execute a user function.
The only errors are syntax errors. There are no runtime errors. Mismatched blocks and unknown characters are the only two errors at this point.
Whitespace is your friend; use it wisely, although there's nothing stopping you doing this:
f1@f1-gf;gr;f1;@;
But you can't do this:
@f1-gf;gr;f1;@f1;
- note that this interprets the second @ as another function declaration.
Syntax is as follows:
@name ... @
- Defun - define a function.
name
- Push - push a function name onto the value stack.
?cond ... ?
- If - execute this block if the condition is true.
~cond ... ~
- Unless - execute this block if the condition is false.
;
- Execute - pop the top of the value stack, and run the function of this name if possible.
:
- Pop - pop the top of the value stack.
!
- Return - pop the top of the execution stack over the current function pointer and PC.
-
- Break - pop the top of the execution stack.
:
- Dup - duplicate the top of the value stack.
=
- Extend - duplicate the top of the execution stack.
For RoboZZle, the following functions are defined:
- gf
- Go (move) forward.
- gl, gr
- Go (turn) left / right
- pr, pg, pb
- Paint red / green / blue.
And the following conditions are defined:
- cr, cg, cb
- Colour red / green / blue: true if the tile you are on is of this colour.
Here's an example solution for a RoboZZle puzzle, "Parity checker". The grid is given. Note that the "g" straight after the grid tells you what goes underneath the robot. Also note that a capital letter denotes that there is a star on that cell. I have modified the grid so not to violate any copyrights, although the original idea is by snydej.
>ggggggggggggggg bbbbrrrbbbbbbrbr rbbbbbbrbbrbbrbb bbrrbbbbbbrrrbbb rbrbbbrbrrbbbbbb rrrbrbrrbbbbbrrb rrrbrbbbbbbbbbrr rbbbbbbrbbrbrbbb brbrbrbbbrbbbbrb rbbbbrbrrrbbbrrb GGGGGGGGGGGGGGGG .G..GGG..GGG.... g
And here's the program:
@l_loop = @ @l_until_cg ~cg --; ~ @ @f_swp1 @f_swpc f_swp2; @ @f_fire gf;gr;gr;gf; @ @ @f_swp2 @f_swpc f_swp1; @ @f_fire gr;gr; @ @ @f_main- gr; f_swp2; l_loop;= gf; ?cr f_swpc; ? l_until_cg;-- f_fire; l_loop;= gf; l_until_cg;-- gr; gf; f_main;@ f_main;
Note that I tend to use "break" a lot; it keeps the stack down nicely. Also note that this will NOT convert to normal RoboZZle commands easily due to really weird loop constructs.
A
Note: I am not actually working on this. This was written several years ago. I believe that I have lost the compiler.
I'm also currently working on a processor architecture, called "A", which I will release as public domain. It's what I will categorise as an "AISC" - Accumulator-based Instruction Set Computer. The objective is to have really really small code. Public domain; I've had problems in the past with people squawking at me.
There are 3 main registers: A,B,C. To load values in, a "D" register is used, which fetches the value after it. There are two others which can't be accessed normally: "PC", program counter, and "SP", stack pointer.
It's a little-endian machine. It has to be 8-bit little-endian, that's standard. Big-endian sucks. PDP-endian sucks even more. 16-bit little-endian is inappropriate for 8-bit opcodes. 4-bit LE is just plain weird. It's 8-bit little endian only. Stack is decrementing.
The basic opcode is in the format iiiidtxx
, where i is the instruction, d is the direction, t is the type, and x is the register. However, it doesn't follow this entirely, as you will find out soon. Exceptions will be shown as indented.
Registers
- 00 - A
- 01 - B
- 10 - C
- 11 - value after opcode
Instructions
000000xx - MOV A,x 000001xx - MOV A,[x] 000010xx - MOV x,A 000010xx - MOV [x],A 000100xx - XOR A,x 000101xx - XOR A,[x] 000110xx - XOR x,A 000110xx - XOR [x],A 001000xx - OR A,x 001001xx - OR A,[x] 001010xx - OR x,A 001010xx - OR [x],A 001100xx - AND A,x 001101xx - AND A,[x] 001110xx - AND x,A 001110xx - AND [x],A 010000xx - PUSH x 010001xx - SHL x 010010xx - POP x 010011xx - SHR x 010100xx - INC x 010101xx - INC [x] 010110xx - DEC x 010111xx - DEC [x] 0110xxyy - XCHG x,y 01100000 - DI 01100101 - EI 01101010 - [ unused opcode ] 0110xx11 - IN x,[next byte] 011011xx - OUT [next byte],x 01101111 - INT x 011100xx - MOV B,x 011101xx - MOV B,[x] 011110xx - MOV x,B 011111xx - MOV [x],B 100000xx - ADD A,x 100001xx - ADD A,[x] 100010xx - ADD x,A 100010xx - ADD [x],A 100100xx - ADC A,x 100101xx - ADC A,[x] 100110xx - ADC x,A 100110xx - ADC [x],A 101000xx - SUB A,x 101001xx - SUB A,[x] 101010xx - SUB x,A 101010xx - SUB [x],A 101100xx - SBC A,x 101101xx - SBC A,[x] 101110xx - SBC x,A 101110xx - SBC [x],A 110000xx - JMP x 11000100 - RET NZ 11000101 - RET Z 11000110 - RET NC 11000111 - RET C 11001100 - JMP [x] 110011xx - [ unused opcodes ] 110100xx - JNZ x 110101xx - JZ x 110110xx - JNC x 110111xx - JC x 111000xx - CMP A,x 111001xx - MOV SP,x 111010xx - CMP x,A 111011xx - MOV x,SP 111100xx - CALL x 11110100 - RET 11110101 - RETI 11110110 - SYSLD (read on for more info) 11110111 - HALT 111110xx - [ unused opcodes ]
Virtually anywhere there is "X", you can replace it with a data value, and put the data value at the end, e.g:
MOV A,0x12345678 03
When a CALL
is issued, it pushes onto the stack in the order PC, B, C
.
"A" is not preserved, and it can be used as a return code.
Now, WTF is SYSLD
? Well, it's used for extensions. You set C to the SYSLD type, and B and A as any parameters.
The first two (0x00
to 0x01
) are reserved for interrupts.
- 0x00: Load Interrupt Handler - B = 8-bit interrupt number, A = handler location. Returns nothing.
- 0x01: Read Interrupt Handler Location - B = 8-bit interrupt number. Returns handler location as A.
The rest you can define to your heart's content. I suggest putting some SIMD stuff in. Heck, you could even stick a GDT in there.
Compiler progress
Well, it can compile the MOV instruction completely.