User:Ben Russell

From Esolang
Jump to navigation Jump to search

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.