Added Brainf*ck implementation in ia32 assembly language.
This commit is contained in:
617
bf.s
Normal file
617
bf.s
Normal file
@@ -0,0 +1,617 @@
|
|||||||
|
.section .data
|
||||||
|
ptr:
|
||||||
|
.long 0
|
||||||
|
loop_ptr:
|
||||||
|
.long 0
|
||||||
|
ret_code:
|
||||||
|
.long 0
|
||||||
|
error_str:
|
||||||
|
.asciz "%s: fatal error: no input files\n"
|
||||||
|
bad_file:
|
||||||
|
.asciz "File %s could not be opened\n"
|
||||||
|
mode:
|
||||||
|
.asciz "r"
|
||||||
|
bad_loop:
|
||||||
|
.asciz "%s: fatal error: more than 1024 nested loops\n"
|
||||||
|
skip:
|
||||||
|
.long 0 /* Boolean flag to indicate that a badly formatted bf file must be skipped */
|
||||||
|
debug_str:
|
||||||
|
.asciz "Tape[%05d]: % 4d\n"
|
||||||
|
|
||||||
|
.section .rodata
|
||||||
|
.align 4
|
||||||
|
/* Jump table for the exec_bf_inst function */
|
||||||
|
.L10:
|
||||||
|
.long .L0 /* # = 35 */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long .L1 /* + = 43 */
|
||||||
|
.long .L2 /* , = 44 */
|
||||||
|
.long .L3 /* - = 45 */
|
||||||
|
.long .L4 /* . = 46 */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long .L5 /* < = 60 */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long .L6 /* > = 62 */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long .L7 /* [ = 91 */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
.long .L8 /* ] = 93 */
|
||||||
|
.long epilogue2 /* Default */
|
||||||
|
|
||||||
|
.section .bss
|
||||||
|
.comm bf_file, 4 /* Address of the current bf file's FILE structure */
|
||||||
|
.comm bf_file_name, 4 /* Address of the current bf file name */
|
||||||
|
.comm tape, 30000 /* 30000 unsigned byte cells for the tape */
|
||||||
|
.comm jmp_stack, 4100 /* 1024 long words to store bf loop adresses + 1 safeguard byte */
|
||||||
|
|
||||||
|
.section .text
|
||||||
|
.globl _start
|
||||||
|
_start:
|
||||||
|
movl (%esp), %ecx /* Get argc */
|
||||||
|
decl %ecx /* Substract 1 from argc */
|
||||||
|
movl 4(%esp), %ebx /* Get program name */
|
||||||
|
movl 8(%esp), %edx /* Get argv[1] */
|
||||||
|
|
||||||
|
/* if (argc - 1) == 0 then error */
|
||||||
|
cmpl $0, %ecx
|
||||||
|
jne eif1
|
||||||
|
/* Print error message, set return code and exit */
|
||||||
|
pushl %ebx
|
||||||
|
pushl $error_str
|
||||||
|
call printf
|
||||||
|
addl $8, %esp
|
||||||
|
movl $1, ret_code
|
||||||
|
jmp end
|
||||||
|
|
||||||
|
eif1:
|
||||||
|
/* Loop through all arguments */
|
||||||
|
movl $0, %edi
|
||||||
|
loop_start:
|
||||||
|
/* Process current input file */
|
||||||
|
pushl %eax
|
||||||
|
pushl %ecx
|
||||||
|
pushl %edx
|
||||||
|
pushl %edx
|
||||||
|
call interpret
|
||||||
|
addl $4, %esp
|
||||||
|
popl %edx
|
||||||
|
popl %ecx
|
||||||
|
popl %eax
|
||||||
|
|
||||||
|
/* Get current argument length */
|
||||||
|
pushl %ecx
|
||||||
|
pushl %edx
|
||||||
|
pushl %edx
|
||||||
|
call strlen
|
||||||
|
add $4, %esp
|
||||||
|
popl %edx
|
||||||
|
popl %ecx
|
||||||
|
|
||||||
|
/* Skip the characters from current arg + null char at the end */
|
||||||
|
addl $1, %eax
|
||||||
|
addl %eax, %edx
|
||||||
|
|
||||||
|
/* Increase arg counter and test loop end condition */
|
||||||
|
incl %edi
|
||||||
|
cmpl %ecx, %edi
|
||||||
|
jne loop_start
|
||||||
|
|
||||||
|
end:
|
||||||
|
movl $1, %eax
|
||||||
|
movl ret_code, %ebx
|
||||||
|
int $0x80
|
||||||
|
|
||||||
|
/* This function processes a Brainfuck file one instruction at a time.
|
||||||
|
Parameters: The name of the file as a C string. */
|
||||||
|
interpret:
|
||||||
|
pushl %ebp
|
||||||
|
movl %esp, %ebp
|
||||||
|
pushl %ebx
|
||||||
|
pushl %edi
|
||||||
|
pushl %esi
|
||||||
|
|
||||||
|
movl 8(%ebp), %ebx /* Get the file name*/
|
||||||
|
|
||||||
|
/* Open input file */
|
||||||
|
pushl %ebx /* Save the file name */
|
||||||
|
pushl $mode
|
||||||
|
pushl %ebx /* ebx holds the file name*/
|
||||||
|
call fopen /* eax will hold the file pointer from now on */
|
||||||
|
addl $8, %esp
|
||||||
|
popl %ebx /* Restore the file name */
|
||||||
|
movl %eax, bf_file /* Store the file ptr in memory */
|
||||||
|
movl %ebx, bf_file_name /* Store the file ptr in memory */
|
||||||
|
|
||||||
|
/* Check if file is open */
|
||||||
|
cmpl $0, %eax
|
||||||
|
jne echo
|
||||||
|
/* If file is NULL then print an error msg and exit */
|
||||||
|
pushl %ebx /* Save the file name */
|
||||||
|
pushl %ebx
|
||||||
|
pushl $bad_file
|
||||||
|
call printf
|
||||||
|
addl $8, %esp
|
||||||
|
popl %ebx /* Restore the file name */
|
||||||
|
jmp epilogue1
|
||||||
|
|
||||||
|
/* Process the file */
|
||||||
|
echo:
|
||||||
|
/* Check if this file must be skipped */
|
||||||
|
/* Only happens if max loops is reached */
|
||||||
|
movl skip, %esi
|
||||||
|
cmpl $0, %esi
|
||||||
|
movl $0, skip
|
||||||
|
jne close
|
||||||
|
|
||||||
|
/* Read 1 byte from the file */
|
||||||
|
pushl %ebx /* Save the file name */
|
||||||
|
pushl %eax /* Save the file pointer */
|
||||||
|
pushl %eax
|
||||||
|
call fgetc
|
||||||
|
addl $4, %esp
|
||||||
|
movl %eax, %ecx /* ecx will hold the char read */
|
||||||
|
popl %eax /* Restore the file pointer */
|
||||||
|
popl %ebx /* Restore the file name */
|
||||||
|
|
||||||
|
/* Test for EOF */
|
||||||
|
pushl %ebx /* Save the file name */
|
||||||
|
pushl %eax /* Save the file pointer */
|
||||||
|
pushl %ecx /* Save the char */
|
||||||
|
pushl %eax
|
||||||
|
call feof
|
||||||
|
addl $4, %esp
|
||||||
|
movl %eax, %edx
|
||||||
|
popl %ecx /* Restore the char */
|
||||||
|
popl %eax /* Restore the file pointer */
|
||||||
|
popl %ebx /* Restore the file name */
|
||||||
|
cmpl $0, %edx
|
||||||
|
jne close
|
||||||
|
|
||||||
|
/* Execute the corresponding instruction */
|
||||||
|
pushl %ebx /* Save the file name */
|
||||||
|
pushl %eax /* Save the file pointer */
|
||||||
|
pushl %ecx
|
||||||
|
call exec_bf_inst
|
||||||
|
addl $4, %esp
|
||||||
|
popl %eax /* Restore the file pointer */
|
||||||
|
popl %ebx /* Restore the file name */
|
||||||
|
jmp echo
|
||||||
|
|
||||||
|
/* Close input file */
|
||||||
|
close:
|
||||||
|
pushl %eax
|
||||||
|
call fclose
|
||||||
|
addl $4, %esp
|
||||||
|
|
||||||
|
epilogue1:
|
||||||
|
popl %esi
|
||||||
|
popl %edi
|
||||||
|
popl %ebx
|
||||||
|
leave
|
||||||
|
ret
|
||||||
|
|
||||||
|
/* Function that executes a BF instruction by calling the appropiate subroutine
|
||||||
|
with a switch construct.
|
||||||
|
Parameters: The instruction as a char.*/
|
||||||
|
exec_bf_inst:
|
||||||
|
pushl %ebp
|
||||||
|
movl %esp, %ebp
|
||||||
|
pushl %ebx
|
||||||
|
pushl %edi
|
||||||
|
pushl %esi
|
||||||
|
|
||||||
|
movl 8(%ebp), %ebx /* Get the instruction */
|
||||||
|
|
||||||
|
/* Determine wich case the instruction falls into */
|
||||||
|
subl $35, %ebx
|
||||||
|
cmpl $58, %ebx
|
||||||
|
ja epilogue2
|
||||||
|
jmp *.L10(,%ebx, 4)
|
||||||
|
|
||||||
|
.L0: /* # = 35 */
|
||||||
|
call debug_tape
|
||||||
|
jmp epilogue2
|
||||||
|
.L1: /* + = 43 */
|
||||||
|
call add_cell
|
||||||
|
jmp epilogue2
|
||||||
|
.L2: /* , = 44 */
|
||||||
|
call input_cell
|
||||||
|
jmp epilogue2
|
||||||
|
.L3: /* - = 45 */
|
||||||
|
call sub_cell
|
||||||
|
jmp epilogue2
|
||||||
|
.L4: /* . = 46 */
|
||||||
|
call output_cell
|
||||||
|
jmp epilogue2
|
||||||
|
.L5: /* < = 60 */
|
||||||
|
call move_left
|
||||||
|
jmp epilogue2
|
||||||
|
.L6: /* > = 62 */
|
||||||
|
call move_right
|
||||||
|
jmp epilogue2
|
||||||
|
.L7: /* [ = 91 */
|
||||||
|
call bf_loop_start
|
||||||
|
jmp epilogue2
|
||||||
|
.L8: /* ] = 93 */
|
||||||
|
call bf_loop_end
|
||||||
|
|
||||||
|
/* The function's epilogue doubles as defaut */
|
||||||
|
epilogue2:
|
||||||
|
popl %esi
|
||||||
|
popl %edi
|
||||||
|
popl %ebx
|
||||||
|
leave
|
||||||
|
ret
|
||||||
|
|
||||||
|
/* Instruction: > */
|
||||||
|
move_right:
|
||||||
|
pushl %ebp
|
||||||
|
movl %esp, %ebp
|
||||||
|
pushl %ebx
|
||||||
|
pushl %edi
|
||||||
|
pushl %esi
|
||||||
|
|
||||||
|
/* Increase the tape pointer by 1 looping around on cell 29999 */
|
||||||
|
movl ptr, %eax
|
||||||
|
incl %eax
|
||||||
|
cmpl $30000, %eax
|
||||||
|
jl end_mr
|
||||||
|
movl $0, %eax
|
||||||
|
end_mr:
|
||||||
|
movl %eax, ptr /* Update the tape pointer */
|
||||||
|
|
||||||
|
popl %esi
|
||||||
|
popl %edi
|
||||||
|
popl %ebx
|
||||||
|
leave
|
||||||
|
ret
|
||||||
|
|
||||||
|
/* Instruction: < */
|
||||||
|
move_left:
|
||||||
|
pushl %ebp
|
||||||
|
movl %esp, %ebp
|
||||||
|
pushl %ebx
|
||||||
|
pushl %edi
|
||||||
|
pushl %esi
|
||||||
|
|
||||||
|
/* Decrease the tape pointer by 1 looping around on cell 0 */
|
||||||
|
movl ptr, %eax
|
||||||
|
decl %eax
|
||||||
|
cmpl $0, %eax
|
||||||
|
jge end_ml
|
||||||
|
movl $29999, %eax
|
||||||
|
end_ml:
|
||||||
|
movl %eax, ptr /* Update the tape pointer */
|
||||||
|
|
||||||
|
popl %esi
|
||||||
|
popl %edi
|
||||||
|
popl %ebx
|
||||||
|
leave
|
||||||
|
ret
|
||||||
|
|
||||||
|
/* Instruction: + */
|
||||||
|
add_cell:
|
||||||
|
pushl %ebp
|
||||||
|
movl %esp, %ebp
|
||||||
|
pushl %ebx
|
||||||
|
pushl %edi
|
||||||
|
pushl %esi
|
||||||
|
|
||||||
|
/* Just add 1 on the tape */
|
||||||
|
movl ptr, %eax
|
||||||
|
incb tape(, %eax, 1)
|
||||||
|
|
||||||
|
popl %esi
|
||||||
|
popl %edi
|
||||||
|
popl %ebx
|
||||||
|
leave
|
||||||
|
ret
|
||||||
|
|
||||||
|
/* Instruction: - */
|
||||||
|
sub_cell:
|
||||||
|
pushl %ebp
|
||||||
|
movl %esp, %ebp
|
||||||
|
pushl %ebx
|
||||||
|
pushl %edi
|
||||||
|
pushl %esi
|
||||||
|
|
||||||
|
/* Just substract 1 on the tape */
|
||||||
|
movl ptr, %eax
|
||||||
|
decb tape(, %eax, 1)
|
||||||
|
|
||||||
|
popl %esi
|
||||||
|
popl %edi
|
||||||
|
popl %ebx
|
||||||
|
leave
|
||||||
|
ret
|
||||||
|
|
||||||
|
/* Instruction: . */
|
||||||
|
output_cell:
|
||||||
|
pushl %ebp
|
||||||
|
movl %esp, %ebp
|
||||||
|
pushl %ebx
|
||||||
|
pushl %edi
|
||||||
|
pushl %esi
|
||||||
|
|
||||||
|
/* Print wathever is on the tape as ascii */
|
||||||
|
movl ptr, %eax
|
||||||
|
xorl %ebx, %ebx
|
||||||
|
movb tape(, %eax, 1), %bl
|
||||||
|
pushl %ebx
|
||||||
|
call putchar
|
||||||
|
addl $4, %esp
|
||||||
|
|
||||||
|
/* Since we are printing just one char we must flush stoud to make sure it actually prints
|
||||||
|
instead of just being buffered by the OS */
|
||||||
|
pushl stdout
|
||||||
|
call fflush
|
||||||
|
addl $4, %esp
|
||||||
|
|
||||||
|
popl %esi
|
||||||
|
popl %edi
|
||||||
|
popl %ebx
|
||||||
|
leave
|
||||||
|
ret
|
||||||
|
|
||||||
|
/* Instruction: , */
|
||||||
|
input_cell:
|
||||||
|
pushl %ebp
|
||||||
|
movl %esp, %ebp
|
||||||
|
pushl %ebx
|
||||||
|
pushl %edi
|
||||||
|
pushl %esi
|
||||||
|
|
||||||
|
/* Read one char on stdin */
|
||||||
|
xorl %eax, %eax
|
||||||
|
call getchar
|
||||||
|
movl ptr, %ebx
|
||||||
|
movb %al, tape(, %ebx, 1)
|
||||||
|
|
||||||
|
input_end:
|
||||||
|
popl %esi
|
||||||
|
popl %edi
|
||||||
|
popl %ebx
|
||||||
|
leave
|
||||||
|
ret
|
||||||
|
|
||||||
|
/* Instruction: # */
|
||||||
|
debug_tape:
|
||||||
|
pushl %ebp
|
||||||
|
movl %esp, %ebp
|
||||||
|
pushl %ebx
|
||||||
|
pushl %edi
|
||||||
|
pushl %esi
|
||||||
|
|
||||||
|
/* First move the tape pointer 5 positions to the left*/
|
||||||
|
movl $0, %edi
|
||||||
|
.W1:
|
||||||
|
call move_left
|
||||||
|
incl %edi
|
||||||
|
cmpl $5, %edi
|
||||||
|
jl .W1
|
||||||
|
|
||||||
|
/* Then loop through the next 11 tape positions and print them */
|
||||||
|
movl $0, %edi
|
||||||
|
print_loop:
|
||||||
|
movl ptr, %eax
|
||||||
|
xorl %ebx, %ebx
|
||||||
|
movb tape(, %eax, 1), %bl
|
||||||
|
pushl %ebx
|
||||||
|
pushl %eax
|
||||||
|
pushl $debug_str
|
||||||
|
call printf
|
||||||
|
addl $12, %esp
|
||||||
|
call move_right
|
||||||
|
incl %edi
|
||||||
|
cmpl $11, %edi
|
||||||
|
jl print_loop
|
||||||
|
|
||||||
|
/* Flush stdout for the same reasons as in . */
|
||||||
|
pushl stdout
|
||||||
|
call fflush
|
||||||
|
addl $4, %esp
|
||||||
|
|
||||||
|
/* Finally restore the tape pointer to it's original position */
|
||||||
|
movl $0, %edi
|
||||||
|
.W2:
|
||||||
|
call move_left
|
||||||
|
incl %edi
|
||||||
|
cmpl $6, %edi
|
||||||
|
jl .W2
|
||||||
|
|
||||||
|
popl %esi
|
||||||
|
popl %edi
|
||||||
|
popl %ebx
|
||||||
|
leave
|
||||||
|
ret
|
||||||
|
|
||||||
|
/* Instruction: [ */
|
||||||
|
bf_loop_start:
|
||||||
|
pushl %ebp
|
||||||
|
movl %esp, %ebp
|
||||||
|
pushl %ebx
|
||||||
|
pushl %edi
|
||||||
|
pushl %esi
|
||||||
|
|
||||||
|
movl loop_ptr, %ebx
|
||||||
|
cmpl $1024, %ebx
|
||||||
|
jl check_loop
|
||||||
|
pushl bf_file_name
|
||||||
|
pushl $bad_loop
|
||||||
|
call printf
|
||||||
|
addl $8, %esp
|
||||||
|
movl $1, skip
|
||||||
|
jmp epilogue_ls
|
||||||
|
|
||||||
|
check_loop:
|
||||||
|
call cell_is_zero
|
||||||
|
cmpl $0, %eax
|
||||||
|
je push_loop
|
||||||
|
call find_matching_le
|
||||||
|
jmp epilogue_ls
|
||||||
|
|
||||||
|
push_loop:
|
||||||
|
pushl %ebx
|
||||||
|
pushl bf_file
|
||||||
|
call ftell
|
||||||
|
addl $4, %esp
|
||||||
|
popl %ebx
|
||||||
|
|
||||||
|
movl %eax, jmp_stack(, %ebx, 4)
|
||||||
|
incl %ebx
|
||||||
|
movl %ebx, loop_ptr
|
||||||
|
|
||||||
|
epilogue_ls:
|
||||||
|
popl %esi
|
||||||
|
popl %edi
|
||||||
|
popl %ebx
|
||||||
|
leave
|
||||||
|
ret
|
||||||
|
|
||||||
|
/* Instruction: ] */
|
||||||
|
bf_loop_end:
|
||||||
|
pushl %ebp
|
||||||
|
movl %esp, %ebp
|
||||||
|
pushl %ebx
|
||||||
|
pushl %edi
|
||||||
|
pushl %esi
|
||||||
|
|
||||||
|
/* Check if the current cell is 0 and loop if it isn't */
|
||||||
|
call cell_is_zero
|
||||||
|
cmpl $0, %eax
|
||||||
|
je loop
|
||||||
|
|
||||||
|
/* If the current cell is 0 then pop the last loop address */
|
||||||
|
movl loop_ptr, %ebx
|
||||||
|
decl %ebx
|
||||||
|
movl $0, jmp_stack(, %ebx, 4)
|
||||||
|
movl %ebx, loop_ptr
|
||||||
|
jmp epilogue_le
|
||||||
|
|
||||||
|
loop:
|
||||||
|
movl bf_file, %eax
|
||||||
|
movl loop_ptr, %ebx
|
||||||
|
decl %ebx
|
||||||
|
movl jmp_stack(, %ebx, 4), %ecx
|
||||||
|
pushl $0 /* SEEK_SET */
|
||||||
|
pushl %ecx
|
||||||
|
pushl %eax
|
||||||
|
call fseek
|
||||||
|
addl $12, %esp
|
||||||
|
|
||||||
|
epilogue_le:
|
||||||
|
popl %esi
|
||||||
|
popl %edi
|
||||||
|
popl %ebx
|
||||||
|
leave
|
||||||
|
ret
|
||||||
|
|
||||||
|
/* This function returns 1 if the current tape cell is 0, returns 0 otherwise */
|
||||||
|
cell_is_zero:
|
||||||
|
pushl %ebp
|
||||||
|
movl %esp, %ebp
|
||||||
|
pushl %ebx
|
||||||
|
pushl %edi
|
||||||
|
pushl %esi
|
||||||
|
|
||||||
|
/* Check if the current cell is 0 */
|
||||||
|
xorl %ebx, %ebx
|
||||||
|
movl ptr, %eax
|
||||||
|
movb tape(, %eax, 1), %bl
|
||||||
|
cmpb $0, %bl
|
||||||
|
jne .FALSE1
|
||||||
|
.TRUE1:
|
||||||
|
movl $1, %eax
|
||||||
|
jmp epilogue_cz
|
||||||
|
.FALSE1:
|
||||||
|
movl $0, %eax
|
||||||
|
|
||||||
|
epilogue_cz:
|
||||||
|
popl %esi
|
||||||
|
popl %edi
|
||||||
|
popl %ebx
|
||||||
|
leave
|
||||||
|
ret
|
||||||
|
|
||||||
|
/* Function that searches through the BF file in search of the matching ] for a given [.
|
||||||
|
NOTE: Doesn't handle mismatched loops */
|
||||||
|
find_matching_le:
|
||||||
|
pushl %ebp
|
||||||
|
movl %esp, %ebp
|
||||||
|
pushl %ebx
|
||||||
|
pushl %edi
|
||||||
|
pushl %esi
|
||||||
|
|
||||||
|
movl $1, %ebx
|
||||||
|
find_loop:
|
||||||
|
pushl %ebx
|
||||||
|
pushl bf_file
|
||||||
|
call fgetc
|
||||||
|
addl $4, %esp
|
||||||
|
popl %ebx
|
||||||
|
|
||||||
|
/* TODO: Check for EOF and skip file if a premature EOF is found */
|
||||||
|
|
||||||
|
cmpl $93, %eax
|
||||||
|
jne new_loop
|
||||||
|
decl %ebx
|
||||||
|
cmpl $0, %ebx
|
||||||
|
jne find_loop
|
||||||
|
jmp epilogue_fm
|
||||||
|
new_loop:
|
||||||
|
cmpl $91, %eax
|
||||||
|
jne find_loop
|
||||||
|
addl $1, %ebx
|
||||||
|
jmp find_loop
|
||||||
|
|
||||||
|
epilogue_fm:
|
||||||
|
popl %esi
|
||||||
|
popl %edi
|
||||||
|
popl %ebx
|
||||||
|
leave
|
||||||
|
ret
|
||||||
Reference in New Issue
Block a user