The only known bug (or lack of feature) is EOF isn't handled. I
didn't feel like "bloating" the code with a few more bytes :-)
Enjoy!
; Title: BrainFuck Interpreter
; File: BF6502A2.Ver2.s
; CPU: 6502
; Platform: Apple ][ //e
; By: Michael Pohoreski
; Date: Dec, 2008
; Description: 135 Byte Interpreter of BrainFuck (Version 2)
; License: BSD "Sharing is Caring!"
;
; Reference: http://en.wikipedia.org/wiki/Brainfuck
; > ++pData;
; < --pData;
; + ++(*pData);
; - --(*pData);
; . putchar(*pData);
; , *pData=getchar();
; [ while (*pData) {
; ] }
;
; Note: Select, Copy, then Shift-INS to paste into AppleWin, or
manually enter...
CALL-151
300:20 E2 F3 A9 06 85 3C A9 08 85 3D
30B:A0 00 84 40 A9 20 85 41
313:20 1D 03 20 C2 FC A0 00 F0 F6 // interpret
31D:B1 3C D0 02 68 68 // fetch
323:A2 07 DD 77 03 F0 04 CA 10 F8 60 // find op
32E:A9 03 48 BD 7F 03 48 18 B1 40 60 // exec
339:4C 11 FE // bf_next
33C:A5 40 D0 02 C6 41 C6 40 60 // bf_prev
345:69 02 18 // bf_inc
348:E9 00 A0 00 91 40 60 // bf_dec
34F:20 0C FD 29 7F 10 F4 // bf_in
356:09 80 4C ED FD // bf_out
35B:D0 19 20 C2 FC B1 3C C9 5D D0 F7 // bf_if
366:F0 0E A5 3C D0 02 C6 3D C6 3C B1 3C C9 5B D0 F2 60 // bf_end
377:2C 2E 5B 3C 5D 3E 2D 2B
37F:4E 55 5A 3B 65 38 47 44
FA62G
0 "++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<
+++++++++++++++.>.+++.------.--------.>+.>."
REM Hello World!
CALL 768
REM http://esolangs.org/wiki/Talk:Brainfuck
0 "++++++++[->-[->-[->-[-]<]<]<]"
REM -n/a-
CALL 768
0 ">++++++++[<++++++++++>-]<[>+>+<<-]>-.>-----.>"
REM OK
CALL 768
0 "+++++++++++++[>+++++++++>++++++++>++++++++>+++++<<<<-]>-.>.---.>++++
+.<----.<.>>+++++.<++++++++.>++++++.<----.----.<.-.>>+.----------.<<+
+.>>>-.<<<++++.>.+++++++.>..>------------------.<<-----.>.>.<-.<<+."
REM thematri...@yahoo.co.nz
CALL 768
0 "++++++++[->-[->-[->-[-]<]<]<]>++++++++[<++++++++++>-]<[>+>+<<-]
>-.>-----.>"
; Source
;pCode EQU $3C ; can't use $00C0, used by AppleSoft!
;pData EQU $FE ; shouldn't use $00DA, used by AppleSoft: LINENUMONERR
BFPC EQU $3C ; BFPC/pCode same as A1L/H
DATA EQU $40 ; DATA/pData same as A3L/H
HGR EQU $F3E2
HGR EQU $F3D8
COUT EQU $FDED
RDKEY EQU $FD0C
NXTA1_8 EQU $FCC2 ; standard entry point is NXTA1 = $FCBA
STOR_6 EQU $FE11 ; standard entry point is STOR = $FE0B
.ORG $300
; JSR HGR2 ; 20 D8 F3 ; If want 16K of data space... uncomment
JSR HGR ; 20 E2 F3 ; Clear 8K of data space
LDA #$06 ; A9 06 ; $0806 first Applesoft token
STA BFPC ; 85 3C
LDA #$08 ; A9 08 ; $0806 first Applesoft token
STA BFPC+1 ; 85 3D
LDY #$00 ; A0 00 ; use HGR page 1 for data ...
STY DATA ; 84 40
; UNDO optimization: HGR sets current HiRes page pointer, E6 = $20
LDA #$20 ; A9 20
STA DATA+1 ; 85 41
INTERPRET
JSR FETCH ; 20 1D 03
JSR NXTA1+8 ; 20 C2 FC
LDY #$00 ; A0 00 ; because COUT trashes Y
BEQ INTERPRET ; F0 F6 ; branch always
FETCH
LDA (BFPC),Y ; B1 3C
BNE FIND_OP ; D0 02
EXIT
PLA ; 68
PLA ; 68
; optimization: intentional-fall through : RTS after not finding
opcode
FIND_OP
LDX #$07 ; A2 07 ; 8 Instructions
.1
CMP OPCHAR,X ; DD 77 03 ; table of opcodes (char)
BEQ EXEC ; F0 04
DEX ; CA
BPL .1 ; 10 F8
; Note: (alternative) optimization: intentional fall-through: bad-
opcode so skip next instruction
; and fall into into INC_PC, but this is no longer stands compliant
-- as it
; skips two opcodes instead of one on a invalid opcode
RTS ; 60
EXEC
LDA #$03 ; A9 03 ; high byte of this code address
PHA ; 48
LDA OPFUNCPTR,X ; BD 7F 03 ; function pointer table (address)
PHA ; 48
CLC ; 18 ; optimization: common code
LDA (DATA),Y ; B1 40 ; optimization: common code
RTS ; 60 ; relative jsr
BF_NEXT
; optimization: use monitor rom STOR: BF_NEXT -> STOR+6 = $FE11
; INC DATA ; E6 E5
; BNE .1 ; D0 02
; INC DATA+1 ; E6 E6
;.1
; RTS ; 60
;FE11
; INC A3L ; E6 40
; BNE RTS5 ; D0
; INC A3H ; E6 41
;RTS5 RTS ; 60
JMP STOR+6 ; 4C 11 FE
BF_PREV
LDA DATA ; A5 40
BNE .1 ; D0 02
DEC DATA+1 ; C6 41
.1
DEC DATA ; C6 40
RTS ; 60
BF_INC
ADC #$02 ; 69 02 ; optimization: n+2-1 = n+1
CLC ; 18 ; optimization: fall-through into BF_INCDEC
BF_DEC
SBC #$00 ; E9 00
BF_INCDEC
LDY #$00 ; A0 00
STA (DATA),Y ; 91 40
RTS ; 60
BF_IN
JSR RDKEY ; 20 0C FD ; trashes Y
AND #$7F ; 29 7F ; convert 8-bit Apple Text to 7-bit ASCII
BPL BF_INCDEC ; 10 F4 ; optmization: BPL BF_INCDEC (10 F4)
BF_OUT
ORA #$80 ; 09 80 ; output Hi-Bit Apple Text !
JMP COUT ; 4C ED FD ; trashes A, Y
BF_IF ; if( !*pData ) pc = ']'
BNE .3 ; D0 19 ; optimization: BEQ .1, therefore BNE RTS
; RTS
; optimization: JSR INC_PC -> JSR NXTA1+8 = $FCC2
;INC_PC -> NXTA1+8 = $FCC2
; INC BFPC ; E6 3C
; BNE .1 ; D0 02
; INC BFPC+1 ; E6 3D
;.1
; RTS ; 60
.1
JSR NXTA1+8 ; 20 C2 FC
LDA (BFPC), Y ; B1 3C
CMP ']' ; C9 5D
BNE .1 ; D0 F7
.2
; optimization: intentional-fall through: remove RTS -- we got here
if BEQ, so exit...
BF_END ; if( !*pData ) pc = '['
BEQ .3 ; F0 0E ; optimization: BNE .1, therefore BEQ RTS
.1
LDA BFPC ; A5 3C
BNE .2 ; D0 02
DEC BFPC+1 ; C6 3D
.2
DEC BFPC ; C6 3C
LDA (BFPC),Y ; B1 3C
CMP '[' ; C9 5B
BNE .1 ; D0 F2
.3
RTS ; 60
OPCHAR DA ",.[<]>-+" ; sorted: 2B 2C 2D 2E 3C 3E 5B 5D
OPFUNCPTR ; sorted by usage: least commonly called to most frequently
called
DFB BF_IN -1 ; , 2C
DFB BF_OUT -1 ; . 2E
DFB BF_IF -1 ; [ 5B
DFB BF_PREV-1 ; < 3C
DFB BF_END -1 ; ] 5D
DFB BF_NEXT-1 ; > 3E
DFB BF_DEC -1 ; - 2D
DFB BF_INC -1 ; + 2B
// AppleWin symbols...
SYM BRAINFUCK = 300
SYM LASTVARS = 303
SYM INTERPRET = 313
SYM FETCH = 31D
SYM EXIT = 320
SYM FIND_OP = 323
SYM EXEC = 32E
SYM BF_NEXT = 339 // > 3E
SYM BF_NEXT_1 = 33B
SYM BF_PREV = 33C // < 3C
SYM BF_PREV_1 = 342
SYM BF_INC = 345 // + 2B
SYM BF_DEC = 348 // - 2D
SYM BF_INCDEC = 34A
SYM BF_IN = 34F // , 2C
SYM BF_OUT = 356 // . 2E
SYM BF_IF = 35B // [ 5B
SYM BF_IF_1 = 35D
SYM BF_IF_2 = 35E
SYM BF_END = 366 // ] 5D
SYM BF_END_1 = 368
SYM BF_END_2 = 36E
SYM BF_END_3 = 376
SYM NXTA1_8 = FCC2
SYM STOR_6 = FE11
SYM OPCHAR = 377
SYM OPFUNCPTR = 37F
Notes:
Apple Specific Optimizations:
- use F800 rom code :-)
1) INC_PC -> NXTA1+8 = $FCC2
INC BFPC ; E6 3C
BNE .1 ; D0 02
INC BFPC+1 ; E6 3D
.1
RTS ; 60
FE11
INC A3L ; E6 40
BNE RTS5 ; D0
INC A3H ; E6 41
RTS5 RTS ; 60
2) BF_NEXT -> STOR+6 = $FE11
INC PDATA ; E6 40
BNE .1 ; D0 02
INC PDATA+1 ; E6 41
.1
RTS ; 60
FE11
INC A3L ; E6 40
BNE RTS5 ; D0
INC A3H ; E6 41
RTS5 RTS ; 60
http://en.wikipedia.org/wiki/Brainfuck#Hello_World.21
ugggh you're crazy...
source code for "hello world" is:
++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++
++++++++++++.>.+++.------.--------.>+.>.
yikes
On Thu, 18 Dec 2008, Michael wrote:
> Let me know if you find corrections, or optimizations :)
>
> The only known bug (or lack of feature) is EOF isn't handled. I
> didn't feel like "bloating" the code with a few more bytes :-)
>
> Enjoy!
Wow, and I thought I'd gotten it small with 192 bytes for a 65C02. o.O
-uso.
The 195 byte version is impressive! Good Job!
ARGH! The prev version didn't handle nested brackets. Here is the 187
byte version that does.
If I do another version, I could add matching bracket detection, and
EOF support. We'll see. A program is never done...
; Title: BrainFuck Interpreter
; File: BF6502A2.Ver3.s
: CPU: 6502
; Platform: Apple ][ //e
; By: Michael Pohoreski
; Date: Dec, 2008
; Description: 187 Byte Interpreter of BrainFuck (Version 3 - nested
if/then support)
; License: BSD "Sharing is Caring!"
;
; http://groups.google.com/group/comp.emulators.apple2/browse_thread/thread/3a6dc92aa0d9a040
;
; Definition:
; http://en.wikipedia.org/wiki/Brainfuck
;
; Reference Tests
; http://esoteric.sange.fi/brainfuck/bf-source/prog/tests.b
;
; Examples
; http://esoteric.sange.fi/brainfuck/bf-source/prog/
; http://esolangs.org/wiki/Brainfuck#Implementations
; http://www.muppetlabs.com/~breadbox/bf/standards.html
; http://software.xfx.net/utilities/vbbfck/index.php
;
; http://nesdev.parodius.com/6502.txt
;
; > ++pData;
; < --pData;
; + ++(*pData);
; - --(*pData);
; . putchar(*pData);
; , *pData=getchar();
; [ while (*pData) { // if( *pData == 0 ), pCode = find_same_depth
( ']' );
; ] } // if( *pData != 0 ), pCode = find_same_depth
( '[' );
;
; Note: Select then Shift-INS to paste into AppleWin, or manually
enter...
CALL-151
300: 20 D8 F3 20 E2 F3
306: A0 00 84 3C 84 40 84 EE
30E: A9 60 85 3D A9 20 85 41
316: B1 3C F0 1F 20 24 03 20 C2 FC A0 00 F0 F2
324: A2 07 D5 F0 F0 04 CA 10 F9 60
32E: A9 03 48 B5 F8 48 18 B1 40 60
338: 4C 11 FE
33B: A5 40 D0 02 C6 41 C6 40 60
344: 69 02 18
347: E9 00
349: A0 00 91 40 60
34E: 20 0C FD 29 7F 10 F4
355: 09 80 4C ED FD
35A: E6 EE B1 40 D0 E3 A5 EE 85 EF
364: 20 C2 FC B1 3C C9 5B D0 04 E6 EF D0 F3
371: C9 5D D0 EF A5 EE C5 EF F0 C8 C6 EF 18 90 E4
380: C6 EE B1 40 F0 BD A5 EE 85 EF
38A: A5 3C D0 02 C6 3D
390: C6 3C B1 3C C9 5D D0 04 C6 EF D0 EE
39C: C9 5B D0 EA A5 EE C5 EF F0 9D E6 EF 18 90 DF
F0: 2C 2E 5B 3C 5D 3E 2D 2B
F8: 4D 54 59 3A 7F 37 46 43
// AppleWin symbols...
SYM CUR_DEPTH = EE
SYM NUM_BRACKET = EF
SYM BRAINFUCK = 300
SYM FETCH = 316
SYM INTERPRET = 324
SYM FIND_OP = 326
SYM EXEC = 32E
SYM EXIT = 337
SYM BF_NEXT = 338 // > 3E
SYM BF_PREV = 33B // < 3C
SYM BF_PREV_1 = 341
SYM EXIT_2 = 343
SYM BF_INC = 344 // + 2B
SYM BF_DEC = 347 // - 2D
SYM STORE_DATA = 349
SYM BF_IN = 34E // , 2C
SYM BF_OUT = 355 // . 2E
SYM BF_IF = 35A // [ 5B
SYM BF_IF_2 = 364
SYM BF_IF_4 = 371
SYM BF_FI = 380 // ] 5D
SYM BF_FI_2 = 38A
SYM BF_FI_3 = 390
SYM BF_FI_4 = 39C
SYM NXTA1_8 = FCC2
SYM STOR_6 = FE11
SYM OPCODE = F0
SYM OPFUNCPTR = F8
;
=====================================================================
; Examples
0 "++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<
+++++++++++++++.>.+++.------.--------.>+.>."
REM Hello World!
CALL -151
6000<806.900M
FA62G
CALL 768
REM http://esolangs.org/wiki/Talk:Brainfuck
0 "++++++++[->-[->-[->-[-]<]<]<]"
CALL-151
6000<806.900M
FA62G
CALL 768
REM -n/a-
0 ">++++++++[<++++++++++>-]<[>+>+<<-]>-.>-----.>"
REM OK
CALL 768
0 "+++++++++++++[>+++++++++>++++++++>++++++++>+++++<<<<-]>-.>.---.>++++
+.<----.<.>>+++++.<++++++++.>++++++.<----.----.<.-.>>+.----------.<<+
+.>>>-.<<<++++.>.+++++++.>..>------------------.<<-----.>.>.<-.<<+."
REM thematri...@yahoo.co.nz
CALL 768
0 "++++++++[->-[->-[->-[-]<]<]<]>++++++++[<++++++++++>-]<[>+>+<<-]
>-.>-----.>"
CALL -151
6000<806.900M
FA62G
CALL 768
0 "++++[>++++++<-]>[>+++++>+++++++<<-]>>++++<[[>[[>>+<<-]<]>>>-]>-[>+>
+<<-]>]+++++[>+++++++<<++>-]>.<<."
REM Need 32K data!!!
REM Prints #
CALL -151
2000:0
2001<2000.BFFEM
FA62G
CALL 768
;
=====================================================================
; Source
OPCODE .EQ $F0
OPFUNCPTR .EQ $F8
CUR_DEPTH .EQ $EE; // current nested depth
NUM_BRACKET .EQ $EF; // depth to find[]
;STACK_L .EQ $0800
;STACK_H .EQ $0900
NXTA1_8 .EQ $FCC2 ; standard entry point is NXTA1 = $FCBA
STOR_8 .EQ $FE11 ; standard entry point is STOR = $FE0B
;pCode .EQ $3C ; can't use $00C0, used by AppleSoft!
;pData .EQ $FE ; shouldn't use $00DA, used by AppleSoft: LINENUMONERR
BFPC .EQ $3C ; BFPC/pCode same as A1L/H
DATA .EQ $40 ; DATA/pData same as A3L/H
HGR2 .EQ $F3E2
HGR .EQ $F3D8
COUT .EQ $FDED
RDKEY .EQ $FD0C
NXTA1 .EQ $FCBA
NXTA1_8 .EQ $FCC2
STOR .EQ $FE0B
STOR_6 .EQ $FE11
CLRTEXT .EQ $C050
SETTEXT .EQ $C051
.ORG $300
; The old start address of $0806 = first Applesoft token
; STA CLRTEXT ; 8D 50 C0 ; // C051 or C050
JSR HGR2 ; 20 D8 F3 ; Clear top 8K of data
JSR HGR ; 20 E2 F3 ; Clear bot 8K of data
LDY #$00 ; A0 00 ;
STY BFPC ; 84 3C ;
STY DATA ; 84 40 ;
STY CUR_DEPTH ; 84 EE ;
; ; Optional: $08/$10 for small code ($0800..$0FFF =
2K) / large data ($1000..$BFFF = 44K)
; ; DEFAULT: $60/$20 for big code ($6000..$BFFF =
24K) / medium data ($2000..$5FFF = 16K)
LDA #$60 ; A9 60 ; Start CODE buffer
STA BFPC+1 ; 85 3D ;
LDA #$20 ; A9 20 ; Start DATA buffer
STA DATA+1 ; 85 41 ;
FETCH
LDA (BFPC),Y ; B1 3C ;
BEQ EXIT ; F0 1F ;
JSR INTERPRET ; 20 24 03 ;
JSR NXTA1+8 ; 20 C2 FC ;
LDY #$00 ; A0 00 ; because COUT trashes Y
BEQ FETCH ; F0 F2 ; branch always
INTERPRET
LDX #$07 ; A2 07 ; 8 Instructions
FIND_OP
CMP OPCODE,X ; D5 F0 ; table of opcodes (char)
BEQ EXEC ; F0 03 ;
DEX ; CA ;
BPL FIND_OP ; 10 F9 ;
RTS ; 60 ;
EXEC
LDA #$03 ; A9 03 ; high byte of this code address
PHA ; 48 ;
LDA OPFUNCPTR,X ; B5 F8 ; function pointer table (address)
PHA ; 48 ;
CLC ; 18 ; optimization: common code
LDA (DATA),Y ; B1 40 ; optimization: common code
EXIT
RTS ; 60 ; 1) exit to caller, 2) relative jsr to our bf_*(),
or 3) exit our bf_*()
BF_NEXT
JMP STOR+6 ; 4C 11 FE ;
BF_PREV
LDA DATA ; A5 40 ;
BNE .1 ; D0 02 ;
DEC DATA+1 ; C6 41 ;
.1 DEC DATA ; C6 40 ;
EXIT_2
RTS ; 60 ;
BF_INC
ADC #$02 ; 69 02 ; optimization: n+2-1 = n+1
CLC ; 18 ; optimization: fall-through into BF_INCDEC
BF_DEC
SBC #$00 ; E9 00 ;
STORE_DATA
LDY #$00 ; A0 00 ;
STA (DATA),Y ; 91 40 ;
RTS ; 60 ;
BF_IN
JSR RDKEY ; 20 0C FD ; trashes Y
AND #$7F ; 29 7F ; convert 8-bit Apple Text to 7-bit ASCII
BPL STORE_DATA ; 10 F4 ;
; CMP #$0D ; C9 0D ;
; BNE STORE_DATA ; D0 F5 ;
; LDA #$0A ; A9 0A ;
; BPL STORE_DATA ; 10 F2 ; optmization: BPL BF_INCDEC (10 F4)
BF_OUT
ORA #$80 ; 09 80 ; output Hi-Bit Apple Text !
; CMP #$8A ; C9 8A ;
; BNE .1 ; D0 02 ;
; LDA #8D ; A9 8D ; map newline 0A to 8D
.1 JMP COUT ; 4C ED FD ; trashes A, Y
BF_IF ; ; if( *pData == 0 ) pc = ']'
INC CUR_DEPTH ; E6 EE ; *** depth++
LDA (DATA),Y ; B1 40 ; optimization: common code
BNE EXIT_2 ; D0 E3 ; optimization: BEQ .1, therefore BNE RTS
LDA CUR_DEPTH ; A5 EE ; match_depth = depth
STA NUM_BRACKET ; 85 EF ;
.2
JSR NXTA1+8 ; 20 C2 FC ; ***
LDA (BFPC), Y ; B1 3C ;
CMP '[' ; C9 5B ; ***
BNE .4 ; D0 04 ;
INC NUM_BRACKET ; E6 EF ; *** inc stack
BNE .2 ; D0 F3 ;
.4
CMP ']' ; C9 5D ; ***
BNE .2 ; D0 EF ;
LDA CUR_DEPTH ; A5 EE ;
CMP NUM_BRACKET ; C5 EF ;
BEQ EXIT_2 ; F0 C8 ;
DEC NUM_BRACKET ; C6 EF ; *** dec stack
CLC ; 18 ;
BCC .2 ; 90 E4 ;
BF_FI ; ; if( *pData != 0 ) pc = '['
DEC CUR_DEPTH ; C6 EE ; depth--
LDA (DATA),Y ; B1 40 ;
BEQ EXIT_2 ; F0 BD ; optimization: BNE .1, therefore BEQ RTS
LDA CUR_DEPTH ; A5 EE ; match_depth = depth
STA NUM_BRACKET ; 85 EF ;
.2
LDA BFPC ; A5 3C ;
BNE .3 ; D0 02 ;
DEC BFPC+1 ; C6 3D ;
.3
DEC BFPC ; C6 3C ;
LDA (BFPC),Y ; B1 3C ;
CMP ']' ; C9 5D ;
BNE .4 ; D0 04 ;
DEC NUM_BRACKET ; C6 EF ; dec stack
BNE .2 ; D0 EE ;
.4
CMP '[' ; C9 5B ;
BNE .2 ; D0 EA ;
LDA CUR_DEPTH ; A5 EE ;
CMP NUM_BRACKET ; C5 EF ;
BEQ EXIT_2 ; F0 9D ;
INC NUM_BRACKET ; E6 EF ; dec stack
CLC ; 18 ;
BCC .2 ; 90 DF ;
.ORG $F0
OPCODE DA ",.[<]>-+" ; sorted: 2B 2C 2D 2E 3C 3E 5B 5D
The use of the HGR memory space for data and its initialization are
great ideas ;-)
A 65c816 version could be a good starting point for people I know who
discover the IIgs...
antoine
We hope you do!
Et bonne année 2009 :D
Babar
Oh m'sieur Babar !
Bonne année,
antoine
Visit this:
http://esoteric.voxelperfect.net/wiki/Main_Page
And click on "Browsing the joke language list" for more mischief.
Those guys (and possibly gals) have way too much time at their
hands to create that stuff.
The other link ("Browsing the language list") isn't necessarily
better,
though. The language "0x29A" isn't named as obvious as "Brainfuck"
but does exactly the same. Its author calls the paradigm
"dysfunctional
programming"...
bye
Marcus