patternMinor
Brainf*ck interpreter written in x86 assembly
Viewed 0 times
interpreterwrittenx86assemblybrainf
Problem
I have written a program in x86 assembly (Intel syntax/MASM) that interprets brainfuck code that is fed to it via an interactive console and prints the final stack to stdout. Note that it does not include an implementation for the
It looks like this:
This is my first major foray into assembly, so I'm mainly looking for general tips, such as:
`.386
.model flat,stdcall
.stack 4096
include \masm32\include\masm32.inc
includelib \masm32\lib\masm32.lib
ExitProcess proto,dwExitCode:dword
.data
bfsrc BYTE 200 dup(0) ; buffer to store source code
bfcells BYTE 100 dup(0) ; 100-byte data array size for n
, command, but everything else has been implemented. The idea is that it presents the user with a prompt where they can enter their code; when the user hits Enter, it evaluates it and then dumps the resultant cell state to the console. While the cell state is maintained between prompt entries, the pointer position is not.It looks like this:
$++++++++[>++++[>++>+++>+++>++>+>->>+[>.>---.+++++++..+++.>>.>+.>++.
Hello World!
0 0 72 100 87 33 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--------------------------------------------------
%%CODEBLOCK_0%%gt;>[.>]
HdW!
0 0 72 100 87 33 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--------------------------------------------------
$++++++++[>+++++++++.
A
0 65 72 100 87 33 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--------------------------------------------------This is my first major foray into assembly, so I'm mainly looking for general tips, such as:
- Which registers I should be using in particular cases
- When I should be using RAM and when I should be using registers
- Ways that the code could be simplified
`.386
.model flat,stdcall
.stack 4096
include \masm32\include\masm32.inc
includelib \masm32\lib\masm32.lib
ExitProcess proto,dwExitCode:dword
.data
bfsrc BYTE 200 dup(0) ; buffer to store source code
bfcells BYTE 100 dup(0) ; 100-byte data array size for n
Solution
mov eax,0 ; eax is BF data pointer
mov ebx,0 ; ebx is BF source pointer
mov ecx,0 ; ecx is loop depthIf you used the
EDI register for the BF data pointer and the ESI register for the BF source pointer, not only would this be a more natural choice, you could also dismiss the push eaxand pop eax around invoke StdOut, addr charBuf.By further using
EBX for the loop depth you can also eliminate the need for push ecxand pop ecx around the same invoke StdOut, addr charBuf.Do note that clearing a register is better done trough an
xor instruction:xor edi, edi ; EDI is BF data pointer
xor esi, esi ; ESI is BF source pointer
xor ebx, ebx ; EBX is loop depthcmp BYTE PTR bfsrc[ebx], 0
je done
jmp processInstruction
done:Here's a clear opportunity to optimize the code. Instead of conditionally jumping to done you can use the opposite conditional jump and fall through. This saves an instruction:
cmp BYTE PTR bfsrc[ebx], 0
jne processInstruction
done:mov eax, 0
printNext:
cmp eax, 100
jge reset
push eax
...
pop eax
inc eax
jmp printNextYou've used a WHILE-loop here. A REPEAT-loop would have been more optimal. Also a better way to zero a register is by
xor-ing it with itself. Furthermore by using the EDI register you eliminate the need for the push eax and pop eax:xor edi, edi
printNext:
...
inc edi
cmp edi, 100
jl printNext
reset:mov dl, BYTE PTR bfcells[eax]
mov BYTE PTR charBuf[0], dl
; follow the character with null to terminate the string
mov BYTE PTR charBuf[1],0Use the
movzx here and shave off an instruction:movzx edx, BYTE PTR bfcells[eax]
mov WORD PTR charBuf[0], dx ; follow the character with null to terminate the stringCode Snippets
mov eax,0 ; eax is BF data pointer
mov ebx,0 ; ebx is BF source pointer
mov ecx,0 ; ecx is loop depthxor edi, edi ; EDI is BF data pointer
xor esi, esi ; ESI is BF source pointer
xor ebx, ebx ; EBX is loop depthcmp BYTE PTR bfsrc[ebx], 0
je done
jmp processInstruction
done:cmp BYTE PTR bfsrc[ebx], 0
jne processInstruction
done:mov eax, 0
printNext:
cmp eax, 100
jge reset
push eax
...
pop eax
inc eax
jmp printNextContext
StackExchange Code Review Q#129518, answer score: 4
Revisions (0)
No revisions yet.