|
/* *\ |
|
** __________ brainfuck.s ** |
|
** / -. \ __/ ____ Maybe running only on ** |
|
** / `-'_/ /_ / __/ Mac OS X Mountain Lion ** |
|
** / /_) ) __/__ __\ \ http://twitter.com/pasberth ** |
|
** /____ / / /_//____/ ** |
|
\* /__/ */ |
|
|
|
.comm memory, 30000 |
|
.text |
|
.globl main |
|
invalidOptionMsg: .ascii "invalid flag: " |
|
main: |
|
popq %rax // %rax = argc |
|
cmp $1, %rax // if (argc == 1) |
|
jz exit // goto exit; |
|
cmp $2, %rax // else if (argc != 2) |
|
jnz parseOption // goto parseOption; |
|
jmp execProgram // else goto execProgram; |
|
parseOption: |
|
checkHyphen: |
|
movq 8(%rsp), %rax // %rax = argv[1] |
|
movb 0(%rax), %al // %al = *argv[1] |
|
cmp $'-, %al // if (*argv[1] != '-') |
|
jnz invalidOption // goto invalidOption; |
|
extractOption: |
|
movq 8(%rsp), %rax // %rax = argv[1] |
|
movb 1(%rax), %al // %al = argv[1][1] |
|
cmpb $'f, %al // from file |
|
jz fromFile |
|
cmpb $'e, %al // eval expr |
|
jz evalExpr |
|
jmp invalidOption |
|
invalidOption: |
|
/* for example, if the input is "./brainfuck -x a", * |
|
* does print "invalid flag: x" and exit program. */ |
|
movq $0x2000004, %rax |
|
movq $1, %rdi |
|
leaq invalidOptionMsg(%rip), %rsi |
|
movq $14, %rdx |
|
syscall |
|
movq 8(%rsp), %rbx // %rbx = argv[1] |
|
leaq 1(%rbx), %rax // %rax = argv[1] + 1 |
|
movq %rax, %rsi |
|
movq $0x2000004, %rax |
|
movq $1, %rdi |
|
movq $1, %rdx |
|
syscall |
|
jmp exit |
|
fromFile: |
|
jmp exit |
|
evalExpr: |
|
push %rax |
|
movq 24(%rsp), %rax |
|
call brainfuck |
|
pop %rax |
|
jmp exit |
|
execProgram: |
|
jmp exit |
|
exit: |
|
movq $0x2000001, %rax |
|
movq $0, %rdi |
|
syscall |
|
ret |
|
/* |
|
* %rax: brainfuck program. |
|
*/ |
|
brainfuck: |
|
pushq %rbp |
|
movq %rsp, %rbp |
|
pushq %rbx |
|
movq %rax, %rbx |
|
pushq %rax |
|
movq %rbx, %rax |
|
leaq memory(%rip), %rbx |
|
pushq %rbx |
|
pushq %rax |
|
/* |
|
* 16(%rsp) : |
|
* 8(%rsp) : pointer to a memory |
|
* 0(%rsp) : brainfuck program. |
|
*/ |
|
eval: |
|
movq (%rsp), %rax |
|
cmp $0, %rax |
|
jz done |
|
|
|
movb (%rax), %al |
|
cmpb $0, %al |
|
jz done |
|
|
|
cmpb $',, %al |
|
jz getCh |
|
cmpb $'., %al |
|
jz putCh |
|
cmpb $'+, %al |
|
jz incrVal |
|
cmpb $'-, %al |
|
jz declVal |
|
cmpb $'<, %al |
|
jz decrPtr |
|
cmpb $'>, %al |
|
jz incrPtr |
|
cmpb $'[, %al |
|
jz begWhile |
|
cmpb $'], %al |
|
jz endWhile |
|
jmp next |
|
done: |
|
popq %rax |
|
popq %rbx |
|
popq %rax |
|
popq %rbx |
|
leave |
|
ret |
|
next: |
|
incb (%rsp) |
|
jmp eval |
|
getCh: |
|
pushq %rbx |
|
pushq %rax // input buffer |
|
movq $0x2000003, %rax |
|
movq $0, %rdi |
|
movq %rsp, %rsi |
|
movq $1, %rdx |
|
syscall |
|
movq (%rsp), %rax |
|
movq 24(%rsp), %rbx |
|
movq %rax, (%rbx) |
|
popq %rax |
|
popq %rbx |
|
jmp next |
|
putCh: |
|
pushq %rbx |
|
pushq %rax |
|
movq 24(%rsp), %rbx |
|
movq $0x2000004, %rax |
|
movq $1, %rdi |
|
movq %rbx, %rsi |
|
movq $1, %rdx |
|
syscall |
|
popq %rax |
|
popq %rbx |
|
jmp next |
|
incrVal: |
|
movq 8(%rsp), %rbx |
|
incb (%rbx) |
|
jmp next |
|
declVal: |
|
movq 8(%rsp), %rbx |
|
decb (%rbx) |
|
jmp next |
|
incrPtr: |
|
incb 8(%rsp) |
|
jmp next |
|
decrPtr: |
|
decb 8(%rsp) |
|
jmp next |
|
begWhile: |
|
movq 8(%rsp), %rbx |
|
movb (%rbx), %al |
|
cmp $0, %al |
|
jz begWhileSkip |
|
jmp begWhileDo |
|
begWhileSkip: |
|
incb (%rsp) |
|
movq (%rsp), %rax |
|
movb (%rax), %al |
|
cmpb $0, %al |
|
jz done |
|
cmpb $'], %al |
|
jnz begWhileSkip |
|
jmp next |
|
begWhileDo: |
|
jmp next |
|
endWhile: |
|
movq 8(%rsp), %rbx |
|
movb (%rbx), %al |
|
cmp $0, %al |
|
jz endWhileBreak |
|
jmp endWhileContinue |
|
endWhileBreak: |
|
jmp next |
|
endWhileContinue: |
|
movq $0, %rbx |
|
endWhileContinue1: |
|
decb (%rsp) |
|
movq (%rsp), %rax |
|
movb (%rax), %al |
|
cmpb $0, %al |
|
jz done |
|
cmpb $'], %al |
|
jz endWhileContinueNestBeg |
|
cmpb $'[, %al |
|
jnz endWhileContinue1 |
|
cmpq $0, %rbx |
|
jnz endWhileContinueNestEnd |
|
jmp next |
|
endWhileContinueNestBeg: |
|
inc %rbx |
|
jmp endWhileContinue1 |
|
endWhileContinueNestEnd: |
|
dec %rbx |
|
jmp endWhileContinue1 |