~rabbits/fractran

27557f710d73d249bd85a33e3100b94ebdcfdef7 — neauoire 8 months ago e616603 main
Started a little client
7 files changed, 341 insertions(+), 211 deletions(-)

M .gitignore
M README.md
M build.sh
R .clang-format => etc/.clang-format
A etc/build.sh
R fractran.c => etc/fractran.c
A src/fractran.tal
M .gitignore => .gitignore +4 -7
@@ 1,7 1,4 @@
.DS*
*jpg~
*png~
*gif~
*.chr
*.bmp
fractran
\ No newline at end of file
bin/
.snarf
.theme
*.chr
\ No newline at end of file

M README.md => README.md +4 -126
@@ 1,135 1,13 @@
# Fractran

A simple [fractran](https://wiki.xxiivv.com/site/fractran.html) interpreter, written in ANSI C.
A 16-bit [fractran](https://wiki.xxiivv.com/site/fractran.html) playground, written in [Uxntal](https://wiki.xxiivv.com/site/uxntal.html). A valid input begins with the accumulator state, followed by a series of positive fractions. If the accumulator value is 1008(2⁴ × 3² × 7), r2 has the value 4, r3 has the value 2, r7 has the value 1, and all other registers are unassigned. 

## Build

```
cc fractran.c -std=c89 -Os -DNDEBUG -g0 -s -Wall -o fractran
```

## HowTo

A valid input begins with the accumulator state, followed by a series of positive fractions. If the accumulator value is 1008(2⁴ × 3² × 7), r2 has the value 4, r3 has the value 2, r7 has the value 1, and all other registers are unassigned. 

## Adder Program

Adding the values stored in the registers 2 and 3, and storing the result in the register 3.

```
3888 2/3
```

### Stepping
You must have the [Uxn](https://git.sr.ht/~rabbits/uxn/) assembler and emulator.

```
3888 2/3
r02=04 r03=05
3888 × 2/3 = 2592/1 
r02=05 r03=04
2592 × 2/3 = 1728/1 
r02=06 r03=03
1728 × 2/3 = 1152/1 
r02=07 r03=02
1152 × 2/3 = 768/1 
r02=08 r03=01
768 × 2/3 = 512/1 
r02=09
512 × 2/3 = 1024/3 
r02=09
uxnasm fractran.tal fractran.rom && uxnemu fractran.rom
```

## Multiplication Program

Multiplying the values stored in the registers 2 and 3, and storing the result in the register 5.

```
36 385/13 13/21 1/7 3/11 7/2 1/3
```

### Stepping

```
r02=02 r03=02
36 × 385/13 = 13860/13 
36 × 13/21 = 156/7 
36 × 1/7 = 36/7 
36 × 3/11 = 108/11 
36 × 7/2 = 126/1 
r02=01 r03=02 r07=01
126 × 385/13 = 48510/13 
126 × 13/21 = 78/1 
r02=01 r03=01 r13=01
78 × 385/13 = 2310/1 
r02=01 r03=01 r05=01 r07=01 r11=01
2310 × 385/13 = 889350/13 
2310 × 13/21 = 1430/1 
r02=01 r05=01 r11=01 r13=01
1430 × 385/13 = 42350/1 
r02=01 r05=02 r07=01 r11=02
42350 × 385/13 = 16304750/13 
42350 × 13/21 = 78650/3 
42350 × 1/7 = 6050/1 
r02=01 r05=02 r11=02
6050 × 385/13 = 2329250/13 
6050 × 13/21 = 78650/21 
6050 × 1/7 = 6050/7 
6050 × 3/11 = 1650/1 
r02=01 r03=01 r05=02 r11=01
1650 × 385/13 = 635250/13 
1650 × 13/21 = 7150/7 
1650 × 1/7 = 1650/7 
1650 × 3/11 = 450/1 
r02=01 r03=02 r05=02
450 × 385/13 = 173250/13 
450 × 13/21 = 1950/7 
450 × 1/7 = 450/7 
450 × 3/11 = 1350/11 
450 × 7/2 = 1575/1 
r03=02 r05=02 r07=01
1575 × 385/13 = 606375/13 
1575 × 13/21 = 975/1 
r03=01 r05=02 r13=01
975 × 385/13 = 28875/1 
r03=01 r05=03 r07=01 r11=01
28875 × 385/13 = 11116875/13 
28875 × 13/21 = 17875/1 
r05=03 r11=01 r13=01
17875 × 385/13 = 529375/1 
r05=04 r07=01 r11=02
529375 × 385/13 = 203809375/13 
529375 × 13/21 = 983125/3 
529375 × 1/7 = 75625/1 
r05=04 r11=02
75625 × 385/13 = 29115625/13 
75625 × 13/21 = 983125/21 
75625 × 1/7 = 75625/7 
75625 × 3/11 = 20625/1 
r03=01 r05=04 r11=01
20625 × 385/13 = 7940625/13 
20625 × 13/21 = 89375/7 
20625 × 1/7 = 20625/7 
20625 × 3/11 = 5625/1 
r03=02 r05=04
5625 × 385/13 = 2165625/13 
5625 × 13/21 = 24375/7 
5625 × 1/7 = 5625/7 
5625 × 3/11 = 16875/11 
5625 × 7/2 = 39375/2 
5625 × 1/3 = 1875/1 
r03=01 r05=04
1875 × 385/13 = 721875/13 
1875 × 13/21 = 8125/7 
1875 × 1/7 = 1875/7 
1875 × 3/11 = 5625/11 
1875 × 7/2 = 13125/2 
1875 × 1/3 = 625/1 
r05=04
625 × 385/13 = 240625/13 
625 × 13/21 = 8125/21 
625 × 1/7 = 625/7 
625 × 3/11 = 1875/11 
625 × 7/2 = 4375/2 
625 × 1/3 = 625/3 
r05=04
```
If do not wish to assemble it yourself, you can download [fractran.rom](https://rabbits.srht.site/fractran/fractran.rom).

M build.sh => build.sh +17 -78
@@ 1,85 1,24 @@
#!/bin/bash
#!/bin/sh -e

# format code
clang-format -i fractran.c
echo "Cleaning.."
rm -rf bin
mkdir bin

# remove old
rm ./fractran
echo "Assembling.."
uxnasm src/fractran.tal bin/fractran.rom 

# debug(slow)
# cc -std=c89 -DDEBUG -Wall -Wpedantic -Wshadow -Wextra -Werror=implicit-int -Werror=incompatible-pointer-types -Werror=int-conversion -Wvla -g -Og -fsanitize=address -fsanitize=undefined fractran.c -o fractran

# build(fast)
cc fractran.c -std=c89 -Os -DNDEBUG -g0 -s -Wall -o fractran

# Size
echo "Size: $(du -sk ./fractran)"

# Install
if [ -d "$HOME/bin" ] && [ -e ./fractran ]
echo "Installing.."
if [ -d "$HOME/roms" ] && [ -e ./bin/fractran.rom ]
then
	cp ./fractran $HOME/bin
    echo "Installed: $HOME/bin" 
	cp ./bin/fractran.rom $HOME/roms
    echo "Installed in $HOME/roms" 
fi

# run
echo "========== ADDER OPERATOR ========="
echo "144 3/2" | ./fractran
echo "Expected: 729"

echo "========= SUBTRACT OPERATOR ======="
echo "254803968 1/6" | ./fractran
echo "Expected: 32768"

echo "============ MIN PROGRAM =========="
echo "69984 5/6 1/3 1/2" | ./fractran
echo "Expected: 3125"

echo "============ MAX PROGRAM =========="
echo "69984 5/6 5/2 5/3" | ./fractran
echo "Expected: 78125"

echo "====== MULTIPLICATION PROGRAM ====="
echo "36 385/13 13/21 1/7 3/11 7/2 1/3" | ./fractran

echo "=========== BLANK PROGRAM ========="
echo "6" | ./fractran

echo "=========== INVALID QUERY ========="
echo "" | ./fractran

echo "============= AND GATE ==========="
echo "7 5/42 1/21 1/14 1/7" | ./fractran
echo "14 5/42 1/21 1/14 1/7" | ./fractran
echo "21 5/42 1/21 1/14 1/7" | ./fractran
echo "42 5/42 1/21 1/14 1/7" | ./fractran

echo "============= OR GATE ==========="
echo "7 5/42 5/21 5/14 1/7" | ./fractran
echo "14 5/42 5/21 5/14 1/7" | ./fractran
echo "21 5/42 5/21 5/14 1/7" | ./fractran
echo "42 5/42 5/21 5/14 1/7" | ./fractran

echo "============= XOR GATE ==========="
echo "7 1/42 5/21 5/14 1/7" | ./fractran
echo "14 1/42 5/21 5/14 1/7" | ./fractran
echo "21 1/42 5/21 5/14 1/7" | ./fractran
echo "42 1/42 5/21 5/14 1/7" | ./fractran

echo "============= NAND GATE ==========="
echo "7 1/42 5/21 5/14 5/7" | ./fractran
echo "14 1/42 5/21 5/14 5/7" | ./fractran
echo "21 1/42 5/21 5/14 5/7" | ./fractran
echo "42 1/42 5/21 5/14 5/7" | ./fractran

echo "============= NOR GATE ==========="
echo "7 1/42 1/21 1/14 5/7" | ./fractran
echo "14 1/42 1/21 1/14 5/7" | ./fractran
echo "21 1/42 1/21 1/14 5/7" | ./fractran
echo "42 1/42 1/21 1/14 5/7" | ./fractran
if [ "${1}" = '--push' ]; 
then
	echo "Pushing.."
	~/Applications/butler push bin/fractran.rom hundredrabbits/fractran:uxn
fi

echo "============= XNOR GATE ==========="
echo "7 5/42 1/21 1/14 5/7" | ./fractran
echo "14 5/42 1/21 1/14 5/7" | ./fractran
echo "21 5/42 1/21 1/14 5/7" | ./fractran
echo "42 5/42 1/21 1/14 5/7" | ./fractran
echo "Running.."
uxnemu bin/fractran.rom ako10x10.chr

R .clang-format => etc/.clang-format +0 -0
A etc/build.sh => etc/build.sh +85 -0
@@ 0,0 1,85 @@
#!/bin/bash

# format code
clang-format -i fractran.c

# remove old
rm ./fractran

# debug(slow)
# cc -std=c89 -DDEBUG -Wall -Wpedantic -Wshadow -Wextra -Werror=implicit-int -Werror=incompatible-pointer-types -Werror=int-conversion -Wvla -g -Og -fsanitize=address -fsanitize=undefined fractran.c -o fractran

# build(fast)
cc fractran.c -std=c89 -Os -DNDEBUG -g0 -s -Wall -o fractran

# Size
echo "Size: $(du -sk ./fractran)"

# Install
if [ -d "$HOME/bin" ] && [ -e ./fractran ]
then
	cp ./fractran $HOME/bin
    echo "Installed: $HOME/bin" 
fi

# run
echo "========== ADDER OPERATOR ========="
echo "144 3/2" | ./fractran
echo "Expected: 729"

echo "========= SUBTRACT OPERATOR ======="
echo "254803968 1/6" | ./fractran
echo "Expected: 32768"

echo "============ MIN PROGRAM =========="
echo "69984 5/6 1/3 1/2" | ./fractran
echo "Expected: 3125"

echo "============ MAX PROGRAM =========="
echo "69984 5/6 5/2 5/3" | ./fractran
echo "Expected: 78125"

echo "====== MULTIPLICATION PROGRAM ====="
echo "36 385/13 13/21 1/7 3/11 7/2 1/3" | ./fractran

echo "=========== BLANK PROGRAM ========="
echo "6" | ./fractran

echo "=========== INVALID QUERY ========="
echo "" | ./fractran

echo "============= AND GATE ==========="
echo "7 5/42 1/21 1/14 1/7" | ./fractran
echo "14 5/42 1/21 1/14 1/7" | ./fractran
echo "21 5/42 1/21 1/14 1/7" | ./fractran
echo "42 5/42 1/21 1/14 1/7" | ./fractran

echo "============= OR GATE ==========="
echo "7 5/42 5/21 5/14 1/7" | ./fractran
echo "14 5/42 5/21 5/14 1/7" | ./fractran
echo "21 5/42 5/21 5/14 1/7" | ./fractran
echo "42 5/42 5/21 5/14 1/7" | ./fractran

echo "============= XOR GATE ==========="
echo "7 1/42 5/21 5/14 1/7" | ./fractran
echo "14 1/42 5/21 5/14 1/7" | ./fractran
echo "21 1/42 5/21 5/14 1/7" | ./fractran
echo "42 1/42 5/21 5/14 1/7" | ./fractran

echo "============= NAND GATE ==========="
echo "7 1/42 5/21 5/14 5/7" | ./fractran
echo "14 1/42 5/21 5/14 5/7" | ./fractran
echo "21 1/42 5/21 5/14 5/7" | ./fractran
echo "42 1/42 5/21 5/14 5/7" | ./fractran

echo "============= NOR GATE ==========="
echo "7 1/42 1/21 1/14 5/7" | ./fractran
echo "14 1/42 1/21 1/14 5/7" | ./fractran
echo "21 1/42 1/21 1/14 5/7" | ./fractran
echo "42 1/42 1/21 1/14 5/7" | ./fractran

echo "============= XNOR GATE ==========="
echo "7 5/42 1/21 1/14 5/7" | ./fractran
echo "14 5/42 1/21 1/14 5/7" | ./fractran
echo "21 5/42 1/21 1/14 5/7" | ./fractran
echo "42 5/42 1/21 1/14 5/7" | ./fractran

R fractran.c => etc/fractran.c +2 -0
@@ 11,6 11,8 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE.
*/

/* cc fractran.c -std=c89 -Os -DNDEBUG -g0 -s -Wall -o fractran */

typedef struct Fraction {
	unsigned int num, den;
} Fraction;

A src/fractran.tal => src/fractran.tal +229 -0
@@ 0,0 1,229 @@
( fractran )

( 
	*/*	Jump
	*/0	Push Acc/Load from memory
	0/*	Pop Acc/Save in memory
	0/0	Pop, or Break )

|00 @System     &vector $2 &wst      $1 &rst    $1 &eaddr  $2 &ecode  $1 &pad     $1 &r       $2 &g      $2 &b     $2 &debug  $1 &halt $1
|10 @Console    &vector $2 &read     $1 &pad    $5 &write  $1 &error  $1
|20 @Screen     &vector $2 &width    $2 &height $2 &auto   $1 &pad    $1 &x       $2 &y       $2 &addr   $2 &pixel $1 &sprite $1
|80 @Controller &vector $2 &button   $1 &key    $1 &func   $1
|90 @Mouse      &vector $2 &x        $2 &y      $2 &state  $1 &pad    $3 &scrollx $2 &scrolly $2
|a0 @File       &vector $2 &success  $2 &stat   $2 &delete $1 &append $1 &name    $2 &length  $2 &read   $2 &write $2

|0000

	@acc $2
	@ptr $2
	@len $2
	@halt $1

|0100 ( -> )

	( vectors )
	;on-button .Controller/vector DEO2
	( theme )
	#0ffc .System/r DEO2
	#0f8c .System/g DEO2
	#0f8c .System/b DEO2

	#15 .Screen/auto DEO

	#0012 .acc STZ2
	#0000 .ptr STZ2
	#0000 .len STZ2

	( create program )
	#0003 #0001 ;append JSR2
	#0003 #0001 ;append JSR2
	#0003 #0001 ;append JSR2
	#0001 #0009 ;append JSR2
	#0000 #0000 ;append JSR2

	;redraw JSR2

BRK

@on-button ( -> )

	.Controller/button DEI #00 NEQ JMP BRK

	;run JSR2

BRK

( utils )

@print-fraction ( num* den* -- )

	SWP2 ;print JSR2 LIT '/ #18 DEO ;print JSR2 #0a18 DEO

JMP2r

@get ( id* -- num* den* )

	#20 SFT2
	;program ADD2 STH2k LDA2
	INC2r INC2r STH2r LDA2

JMP2r

@append ( num* den* -- )

	;program .len LDZ2 #20 SFT2 ADD2 STH2 SWP2
	STH2kr STA2
	INC2r INC2r STH2r STA2
	.len LDZ2k INC2 ROT STZ2

JMP2r

@run ( -- )

	.ptr LDZ2 ;get JSR2 ;print-fraction JSR2

	.ptr LDZ2 ;get JSR2 #0000 EQU2 STH #0000 EQU2 STHr #0101 EQU2 ,&break JCN

	.ptr LDZ2 ;get JSR2 SWP2 .acc LDZ2 MUL2 SWP2 

	OVR2 OVR2 ( MOD2 ) DIV2k MUL2 SUB2 ORA ,&end JCN

	DIV2 .acc STZ2
	;redraw JSR2
	( mod2 ) .ptr LDZ2 INC2 .len LDZ2 DIV2k MUL2 SUB2 .ptr STZ2
	

JMP2r
	&end POP2 POP2 #01 .halt STZ ;redraw JSR2 JMP2r
	&break #01 .halt STZ ;redraw JSR2 JMP2r

@run-break ( -- )

	#01 .halt STZ ;redraw JSR2

JMP2r

@redraw ( -- )
	
	#0010 .Screen/x DEO2
	#0020 .Screen/y DEO2

	.acc LDZ2 ;draw-accumulator JSR2

	#0010 .Screen/x DEO2
	#0040 .Screen/y DEO2

	;draw-program JSR2

JMP2r

@draw-program ( -- )

	.len LDZ2 #0000
	&loop
		DUP2 .ptr LDZ2 EQU2 STH
		DUP2 ;get JSR2 #01 STHr ADD ;draw-fraction JSR2
		INC2 GTH2k ,&loop JCN
	POP2 POP2

JMP2r

@draw-accumulator ( val* -- )

	#02 ;draw-short JSR2
	#03 ;arrow-icn ;draw-sprite JSR2

	.ptr LDZ2 #01 .halt LDZ ADD ;draw-short JSR2

JMP2r

@draw-fraction ( num* den* color -- )

	STH
	SWP2 STHkr ,draw-short JSR
	( line )
	.Screen/x DEI2k #0020 SUB2 ROT DEO2
	.Screen/y DEI2k #0008 ADD2 ROT DEO2
	#32 .Screen/auto DEO
	;line-icn .Screen/addr DEO2
	STHkr #05 MUL .Screen/sprite DEO
	#15 .Screen/auto DEO
	
	STHr ,draw-short JSR

	( comma )
	;comma-icn .Screen/addr DEO2
	#0f .Screen/sprite DEO

	.Screen/x DEI2k #0006 ADD2 ROT DEO2
	.Screen/y DEI2k #0010 SUB2 ROT DEO2

JMP2r

@draw-short ( short* color -- )

	STH SWP STHkr ,draw-byte JSR STHr

@draw-byte ( byte color -- )

	STH DUP #04 SFT STHkr ,draw-hex JSR #0f AND STHr

@draw-hex ( char color -- )

	SWP #00 SWP #40 SFT2 ;font-hex ADD2

@draw-sprite ( color addr* -- )

	.Screen/addr DEO2
	.Screen/sprite DEO

JMP2r

@print ( short* -- )

	&short ( short* -- ) SWP ,&byte JSR
	&byte ( byte -- ) DUP #04 SFT ,&char JSR
	&char ( char -- ) #0f AND DUP #09 GTH #27 MUL ADD #30 ADD #18 DEO

JMP2r

@print-dec ( value* -- )

	#2710 DIV2k DUP #30 ADD #18 DEO MUL2 SUB2
	#03e8 DIV2k DUP #30 ADD #18 DEO MUL2 SUB2
	#0064 DIV2k DUP #30 ADD #18 DEO MUL2 SUB2
	#000a DIV2k DUP #30 ADD #18 DEO MUL2 SUB2
	#30 ADD #18 DEO POP

JMP2r

@font-hex
    0000 003c 6666 6666 6666 663c 0000 0000
    0000 0018 3818 1818 1818 1818 0000 0000
    0000 003c 4606 060c 1830 607e 0000 0000
    0000 007e 0c18 3c06 0606 463c 0000 0000
    0000 0006 0e16 2646 7f06 0606 0000 0000
    0000 007e 6060 7c06 0606 463c 0000 0000
    0000 001c 3060 7c66 6666 663c 0000 0000
    0000 007e 0606 060c 1818 1818 0000 0000
    0000 003c 6666 663c 6666 663c 0000 0000
    0000 003c 6666 6666 3e06 0c38 0000 0000
    0000 0000 003c 463e 6666 663e 0000 0000
    0000 0060 607c 6666 6666 667c 0000 0000
    0000 0000 0038 6460 6060 6438 0000 0000
    0000 0006 063e 6666 6666 663e 0000 0000
    0000 0000 003c 6666 7e60 623c 0000 0000
    0000 001c 3078 3030 3030 3030 0000 0000

@arrow-icn
	0000 0000 0008 0c7e 0c08 0000 0000 0000

@comma-icn
	0303 0102 0000 0000 0000 0000 0000 0000

@line-icn
	0000 0000 0000 00ff

@program