Deterministic finite-state automaton in x86 Assembly (GCC)

44 Views Asked by At

I'm working on a DFA program in Assembly. This is basically a system that reads a binary string and interprets them in the following states, shown in the below image. enter image description here

It essentially just shows the even amount of 0's and even amount of 1's in a string. I tried to represent this system with the following program in assembly:

.section .data
input_prompt:
asciz "Enter a string of 0s and 1s: "

invalid_message:
.asciz "ERROR: invalid input\n"
EEPrompt:
    .asciz "Input accepted\n"
NotEEPrompt:
    .asciz "Input rejected\n"
newline:
.byte 10

.section .bss
input:
.byte 0
.byte 0  # to store the current character

.section .text
.globl main

main:

# PRINTS INPUT PROMPT
movl $4, %eax            # Writing syscall
movl $1, %ebx            # stdout, prepare for output
lea input_prompt, %ecx   # point to our input prompt
movl $29, %edx           # load our message length
int $0x80                # invoke syscall

movl $0, %ebx            # Initialize our state
lea input, %esi          # points to input buffer

read_loop:
# Read each character with call getchar@PLT
call getchar@PLT
# CHECKS FOR NEW LINE
cmpb $0x0A, %al          #If new line is detected, we are finished.
je input_complete        # End loop

# We need to determine if the character we are processing is a '1' or a '0'
cmpb $0x30, %al          # Compares input with ASCII '0'
jl invalid_input         # If it is less than 0, input is not valid
je zero_entered         # If character IS 0, proceed to jump table
cmpb $0x31, %al          # Compare input with ASCII '1'
jg invalid_input       # If input is greater than 1, input is not valid
je one_entered         # If character IS 1, proceed to jump table

# Store our new and valid input
movb %al, (%esi)         # Store character
inc %esi                # Increment buffer

zero_entered:
# '0' was input
cmpl $0, %eax        # We are in EE. Now, go to OE.
je ee_to_oe
cmpl $1, %eax        # We are in OE. Now, go to EE.
je oe_to_ee
cmpl $2, %eax        # We are in OO. Go to EO
je oo_to_eo
cmpl $3, %eax        # We are in EO. Go to OO.
je eo_to_oo

jmp read_loop

one_entered:
# '1' was input
cmpl $0, %eax        # We are in EE. Now, go to EO
je ee_to_eo
cmpl $1, %eax        # We are in OE. Now, go to OO.
je oe_to_oo
cmpl $2, %eax        # We are in OO. Now, go to OE.
je oo_to_oe
cmpl $3, %eax        # We are in EO. Now, go to EE.
je eo_to_ee

jmp read_loop

ee_to_oe:
movl $1, %eax        # EE to OE
jmp read_loop

oe_to_ee:
movl $0, %eax        # OE to EE
jmp read_loop

oo_to_eo:
movl $3, %eax        # OO to EO
jmp read_loop

eo_to_oo:
movl $2, %eax        # EO to OO
jmp read_loop

ee_to_eo:
movl $3, %eax        # EE to EO
jmp read_loop

oe_to_oo:
movl $2, %eax        # OE to OO
jmp read_loop

oo_to_oe:
movl $1, %eax        # OO to OE
jmp read_loop

eo_to_ee:
movl $0, %eax        # EO to EE
jmp read_loop

invalid_input:
# Invalid Input Detected. Terminate program.

movl $4, %eax            # syscall to write
movl $1, %ebx            # stdout
lea invalid_message, %ecx# point to our invalidity message
movl $29, %edx           # length of our message
int $0x80                # invoke syscall

# Exit with status code 1
movl $1, %eax            # syscall to exit
xor %ebx, %ebx           # status code: 1
int $0x80                # invoke syscall

accepted_input:
# Print a message for ACCEPTED input
movl $4, %eax            # syscall to write
movl $1, %ebx            # stdout
lea EEPrompt, %ecx       # point to our acceptance message
movl $16, %edx           # length of our message
int $0x80                # invoke syscall

# Exit with status code 1
movl $1, %eax            # syscall to exit
xor %ebx, %ebx           # status code: 1
int $0x80                # invoke syscall

rejected_input:
# Print a message for REJECTED input
movl $4, %eax            # syscall to write
movl $1, %ebx            # stdout
lea NotEEPrompt, %ecx    # point to the error message
movl $16, %edx           # message length
int $0x80                # invoke syscall

# Exit with status code 1
movl $1, %eax            # syscall: exit
xor %ebx, %ebx           # status code: 1
int $0x80                # invoke syscall

input_complete:
# Add a newline character to the end of the input
movb $0x0A, (%esi)

# Now, compare the %eax value to see if we are in EE. If 0 is in %eax, we are in EE.

cmpl $0, %eax        # Check to see if we are in EE.
je accepted_input    # IF SO, print our accepted message and exit
jg rejected_input    # IF NOT, print our rejected message and exit

# Exit the program
movl $1, %eax            # syscall: exit
xor %ebx, %ebx           # status code: 0
int $0x80                # invoke syscall

However, in my program the output always goes to the "rejected_input" state and I'm not sure why. I'm new to assembly, so I'm unsure if there was a program error, a misconception of how DFA works, or both.

enter image description here

0

There are 0 best solutions below