Permalink
Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
287 lines (256 sloc) 5.05 KB
# $Id$
#
# An Optimizing Brainfuck compiler
# By Leo based on bfc.imc by Leon
# emit register-only code
# XXX does no register range checking
# it runs the bench.bf 15 times faster then bfc.imc
.loadlib 'io_ops'
.macro debug()
push code, "# depth "
$S0 = depth
push code, $S0
push code, " reg "
$S0 = reg
push code, $S0
push code, "\n"
.endm
.sub main :main
.param pmc argv
.local int pc
.local int maxpc
.local int label
.local string labelstr
.local pmc code
.local string filename
.local string file
.local string line
.local string program
.local string char
program = argv[0]
# check argc
$I0 = argv
if $I0 < 2 goto usage
# Get the filename
filename = argv[1]
if filename goto SOURCE
usage:
print "usage: ../../parrot "
print program
print " file.bf\n"
end
# Read the file into S1
SOURCE:
open $P1, filename, 'r'
defined $I0, $P1
if $I0, SOURCE_LOOP
print filename
print " not found\n"
branch usage
SOURCE_LOOP:
read line, $P1, 1024
file = file . line
if line goto SOURCE_LOOP
close $P1
maxpc = length file
# Initialise
code = new 'StringBuilder'
push code, "# Code generated by bfco.pir\n"
push code, ".loadlib 'io_ops'\n"
# push code, "trace 1\n"
push code, "new P0, 'ResizableIntegerArray' # memory\n"
# this array doesn't support negative indices properly
# start with some offset
push code, "getstdout P30\n"
push code, "#pop S0, P30\n # unbuffer\n"
push code, "getstdin P30\n"
pc = 0 # pc
label = 0 # label count
.local int depth, n_lt, n_gt, reg
reg = 0
# The main compiler loop
INTERP:
substr char, file, pc, 1
push code, "\nSTEP"
labelstr = pc
push code, labelstr
push code, ": # "
push code, char
push code, "\n"
if char != "+" goto NOTPLUS
.local int n_plus
null n_plus
$I0 = pc + 1
plus_loop:
inc n_plus
if $I0 == maxpc goto emit_plus
substr char, file, $I0, 1
if char != "+" goto emit_plus
inc $I0
goto plus_loop
emit_plus:
pc = $I0 - 1
push code, " add I"
set $S1, reg
push code, $S1
push code, ", "
$S0 = n_plus
push code, $S0
push code, "\n"
push code, " band I"
push code, $S1
push code, ", 0xff\n"
goto NEXT
NOTPLUS:
if char != "-" goto NOTMINUS
.local int n_minus
null n_minus
$I0 = pc + 1
minus_loop:
inc n_minus
if $I0 == maxpc goto emit_minus
substr char, file, $I0, 1
if char != "-" goto emit_minus
inc $I0
goto minus_loop
emit_minus:
pc = $I0 - 1
push code, " sub I"
set $S1, reg
push code, $S1
push code, ", "
$S0 = n_minus
push code, $S0
push code, "\n"
push code, " band I"
push code, $S1
push code, ", 0xff\n"
goto NEXT
NOTMINUS:
if char != ">" goto NOTGT
null n_gt
$I0 = pc + 1
gt_loop:
inc n_gt
if $I0 == maxpc goto emit_gt
substr char, file, $I0, 1
if char != ">" goto emit_gt
inc $I0
goto gt_loop
emit_gt:
reg += n_gt
.debug()
pc = $I0 - 1
goto NEXT
NOTGT:
if char != "<" goto NOTLT
null n_lt
$I0 = pc + 1
lt_loop:
inc n_lt
if $I0 == maxpc goto emit_lt
substr char, file, $I0, 1
if char != "<" goto emit_lt
inc $I0
goto lt_loop
emit_lt:
reg -= n_lt
.debug()
pc = $I0 - 1
goto NEXT
NOTLT:
if char != "[" goto NOTOPEN
label = pc
depth = 0
OPEN_LOOP:
inc label
substr $S2, file, label, 1
if $S2 != "[" goto OPEN_NOTOPEN
inc depth
goto OPEN_LOOP
OPEN_NOTOPEN:
if $S2 != "]" goto OPEN_LOOP
if depth == 0 goto OPEN_NEXT
dec depth
goto OPEN_LOOP
OPEN_NEXT:
inc label
labelstr = label
push code, " unless I"
set $S0, reg
push code, $S0
push code, ", STEP"
push code, labelstr
push code, "\n"
goto NEXT
NOTOPEN:
if char != "]" goto NOTCLOSE
label = pc
depth = 0 # "height"
CLOSE_LOOP:
dec label
substr $S2, file, label, 1
if $S2 != "]" goto CLOSE_NOTCLOSE
inc depth
goto CLOSE_LOOP
CLOSE_NOTCLOSE:
if $S2 != "[" goto CLOSE_LOOP
if depth == 0 goto CLOSE_NEXT
dec depth
goto CLOSE_LOOP
CLOSE_NEXT:
labelstr = label
push code, " branch STEP"
push code, labelstr
push code, "\n"
goto NEXT
NOTCLOSE:
if char != "." goto NOTDOT
push code, " chr S31, I"
$S0 = reg
push code, $S0
push code, "\n"
push code, " print S31\n"
goto NEXT
NOTDOT:
if char != "," goto NEXT
labelstr = pc
push code, " read S31, P30, 1\n"
push code, " if S31, no_eof"
push code, labelstr
push code, "\n"
push code, " null I31\n"
push code, " branch eof"
push code, labelstr
push code, "\n"
push code, "no_eof"
push code, labelstr
push code, ":\n"
push code, " ord I31, S31\n"
push code, "eof"
push code, labelstr
push code, ":\n"
$S0 = reg
push code, " set I"
push code, $S0
push code, ", I31\n"
goto NEXT
NEXT:
inc pc
if pc < maxpc goto INTERP
labelstr = pc
push code, "STEP"
push code, labelstr
push code, ":\n"
push code, "end\n"
# Now actually run it
$P1 = compreg "PASM"
$P0 = $P1( code )
$P0()
end
.end
# Local Variables:
# mode: pir
# fill-column: 100
# End:
# vim: expandtab shiftwidth=4 ft=pir: