Instructions
Requirements and Specifications
Screenshots of output
Source Code
section .data
noArgsStr:
db "Usage:", 10
db " %s ", 10, 0
intFilename:
db "project4_int.out", 0
fltFilename:
db "project4_float.out", 0
fileFmt:
db "wt", 0
intFmt:
db "%d", 10, 0
fltFmt:
db "%.38f", 10, 0
openErrorStr:
db "Error opening input file", 10, 0
openIntErrorStr:
db "Error opening integer output file", 10, 0
openFltErrorStr:
db "Error opening float output file", 10, 0
readErrorStr:
db "Error reading input file", 10, 0
intErrorStr:
db "Invalid number found in file", 10, 0
fltErrorStr:
db "Invalid floating point found in file", 10, 0
numIntsStr:
db "Number of integers: %d", 10, 0
numFltsStr:
db "Number of floating point numbers: %d", 10, 0
maxFltStr:
db "Largest floating point number: %f", 10, 0
minFltStr:
db "Smallest floating point number: %f", 10, 0
sumIntsStr:
db "Sum of all integers: %f", 10, 0
str:
db "%s", 10, 0
fd:
dd 0
intFile:
dd 0
fltFile:
dd 0
numInts:
dd 0
numFlts:
dd 0
maxFlt:
dd -1.0e30
minFlt:
dd 1.0e30
sumInts:
dd 0
flt10:
dd 10.0
section .bss
buffer:
resb 100
number:
resd 1
section .text
extern printf
extern fprintf
extern fopen
extern fclose
global main
;===============================================================================
; Main function for the program
;===============================================================================
main:
push ebp ; save frame pointer
mov ebp, esp ; create new frame
finit ; initialize fpu
mov eax, [ebp + 8] ; load argc
mov edi, [ebp + 12] ; load argv pointer
cmp eax, 1 ; compare argc with 1
je noArgs ; if argc == 1, no arguments were given
mov eax, 5 ; open file using syscall number 5
mov ebx, [edi + 4] ; filename is second command line argument
mov ecx, 0 ; open as read only
int 80h ; call os to open file
cmp eax, 0 ; check return value of syscall
jl openError ; if <0, then there was an error
mov [fd], eax ; save file descriptor
mov eax, fileFmt ; load format for output file
push eax ; pass as argument
mov eax, intFilename ; load integer output filename
push eax ; pass as argument
call fopen ; open with C library
add esp, 8 ; remove arguments from stack
cmp eax, 0 ; check for errors
jle openIntError ; if <=0, there was an error
mov [intFile], eax ; save file pointer
mov eax, fileFmt ; load format for output file
push eax ; pass as argument
mov eax, fltFilename ; load floating point output filename
push eax ; pass as argument
call fopen ; open with C library
add esp, 8 ; remove arguments from stack
cmp eax, 0 ; check for errors
jle openFltError ; if <=0, there was an error
mov [fltFile], eax ; save file pointer
; load number of entries in input file
mov eax, 100 ; load max numbers to read
push eax ; pass as 3rd argument to function
mov eax, buffer ; load pointer to buffer
push eax ; pass as second argument to function
mov eax, [fd] ; load file descriptor
push eax ; pass as argument to function
call readLine ; read line from file
add esp, 12 ; remove arguments from stack
cmp eax, 0 ; check for errors in function
jl readError ; if <0, there was an error
; convert to integer
mov eax, number ; load pointer to number space
push eax ; pass as second argument
mov eax, buffer ; load pointer to buffer
push eax ; pass as argument to function
call stringToInt ; convert string to integer
add esp, 8 ; remove arguments from stack
cmp eax, 0 ; check for errors
jl intError ; if not valid, error
mov ecx, [number] ; load number of entries
loadLoop:
push ecx ; save loop counter
; load entry
mov eax, 100 ; load max numbers to read
push eax ; pass as 3rd argument to function
mov eax, buffer ; load pointer to buffer
push eax ; pass as second argument to function
mov eax, [fd] ; load file descriptor
push eax ; pass as argument to function
call readLine ; read line from file
add esp, 12 ; remove arguments from stack
cmp eax, 0 ; check for errors in function
jl readError ; if <0, there was an error
; convert to integer
mov eax, number ; load pointer to number space
push eax ; pass as second argument
mov eax, buffer ; load pointer to buffer
push eax ; pass as argument to function
call stringToInt ; convert string to integer
add esp, 8 ; remove arguments from stack
cmp eax, 0 ; check for errors
jge isInteger ; if valid, process as integer
flthere:
; convert to float
mov eax, number ; load pointer to number space
push eax ; pass as second argument
mov eax, buffer ; load pointer to buffer
push eax ; pass as argument to function
call stringToFlt ; convert string to float
add esp, 8 ; remove arguments from stack
cmp eax, 0 ; check for errors
jl fltError ; if not valid, error
inc DWORD[numFlts] ; increment number of floating point numbers
fld DWORD[number] ; load number
fcom DWORD[maxFlt] ; compare with max
fnstsw ax ; move status to ax
sahf ; load flags
jb updMin ; if fst DWORD[maxFlt] ; else, update max
updMin:
fcom DWORD[minFlt] ; compare with min
fnstsw ax ; move status to ax
sahf ; load flags
ja printFlt ; if >min, skip
fst DWORD[minFlt] ; else, update min
printFlt:
sub esp, 8 ; push qword
fstp QWORD[esp] ; pass as argument
mov eax, fltFmt ; load file output format
push eax ; pass as argument
mov eax, [fltFile] ; load file pointer
push eax ; pass as argument
call fprintf ; print to file with C library
add esp, 16 ; remove arguments from stack
jmp nextEntry
isInteger:
inc DWORD[numInts] ; increment number of integers
fild DWORD[number] ; load read number into fpu
fiadd DWORD[sumInts] ; add to sum of integers
fistp DWORD[sumInts] ; update sum
mov eax, [number] ; load number
push eax ; pass as argument
mov eax, intFmt ; load file output format
push eax ; pass as argument
mov eax, [intFile] ; load file pointer
push eax ; pass as argument
call fprintf ; print to file with C library
add esp, 12 ; remove arguments from stack
nextEntry:
pop ecx ; load loop counter
dec ecx
je endLoop
jmp loadLoop ; repeat for the number of entries
endLoop:
mov eax, [intFile] ; load file pointer
push eax ; pass as argument
call fclose ; close with C library
add esp, 4 ; remove arguments from stack
mov eax, [fltFile] ; load file pointer
push eax ; pass as argument
call fclose ; close with C library
add esp, 4 ; remove arguments from stack
mov eax, 6 ; syscall to close file
mov ebx, [fd] ; load file descriptor
int 80h ; call os to close the file
; print results
mov eax, [numInts] ; load number of integers
push eax ; pass as argument
mov eax, numIntsStr ; load message string format
push eax ; pass as argument
call printf ; print number of ints
add esp, 8 ; remove arguments from stack
mov eax, [numFlts] ; load number of floats
push eax ; pass as argument
mov eax, numFltsStr ; load message string format
push eax ; pass as argument
call printf ; print number of ints
add esp, 8 ; remove arguments from stack
sub esp, 8 ; allocate space for float
fldz ; load zero
cmp DWORD[numFlts], 0 ; check if there are floats
je noflt1 ; if no floats, skip
fld DWORD[maxFlt] ; load largest float
noflt1:
fstp QWORD[esp] ; push to stack argument
mov eax, maxFltStr ; load message string format
push eax ; pass as argument
call printf ; print number of ints
add esp, 12 ; remove arguments from stack
sub esp, 8 ; allocate space for float
fldz ; load zero
cmp DWORD[numFlts], 0 ; check if there are floats
je noflt2 ; if no floats, skip
fld DWORD[minFlt] ; load smallest float
noflt2:
fstp QWORD[esp] ; push to stack argument
mov eax, minFltStr ; load message string format
push eax ; pass as argument
call printf ; print number of ints
add esp, 12 ; remove arguments from stack
sub esp, 8 ; allocate space for float
fild DWORD[sumInts] ; load sum of integers
fstp QWORD[esp] ; push to stack argument
mov eax, sumIntsStr ; load message string format
push eax ; pass as argument
call printf ; print number of ints
add esp, 12 ; remove arguments from stack
jmp progEnd ; jump to program end
noArgs:
push DWORD[edi] ; pass first command line argument
mov eax, noArgsStr ; load address of error string
push eax ; pass as argument to printf
call printf ; print error message on screen
add esp, 8 ; remove arguments from stack
jmp progEnd ; jump to program end
openError:
mov eax, openErrorStr ; load address of error string
push eax ; pass as argument to printf
call printf ; print error message on screen
add esp, 4 ; remove arguments from stack
jmp progEnd ; jump to program end
openIntError:
mov eax, openIntErrorStr ; load address of error string
push eax ; pass as argument to printf
call printf ; print error message on screen
add esp, 4 ; remove arguments from stack
jmp progEnd ; jump to program end
openFltError:
mov eax, openFltErrorStr ; load address of error string
push eax ; pass as argument to printf
call printf ; print error message on screen
add esp, 4 ; remove arguments from stack
jmp progEnd ; jump to program end
readError:
mov eax, readErrorStr ; load address of error string
push eax ; pass as argument to printf
call printf ; print error message on screen
add esp, 4 ; remove arguments from stack
jmp progEnd ; jump to program end
intError:
mov eax, intErrorStr ; load address of error string
push eax ; pass as argument to printf
call printf ; print error message on screen
add esp, 4 ; remove arguments from stack
jmp progEnd ; jump to program end
fltError:
mov eax, fltErrorStr ; load address of error string
push eax ; pass as argument to printf
call printf ; print error message on screen
add esp, 4 ; remove arguments from stack
jmp progEnd ; jump to program end
progEnd:
xor eax, eax ; return 0
pop ebp ; restore frame pointer
ret ; return to os
;===============================================================================
; Reads a line from the file to a buffer
; Receives file descriptor, pointer to buffer and max number of chars to read
; returns eax <0 if there was no error, number of read chars if there was no
; error
;===============================================================================
readLine:
push ebp ; save frame pointer
mov ebp, esp ; create new frame
mov edi, [ebp + 12] ; buffer pointer is the second argument
mov esi, 0 ; initialize number of read chars to zero
rdLoop:
mov eax, 3 ; read file using syscall number 3
mov ebx, [ebp + 8] ; take filename descriptor from first argument
mov ecx, edi ; pass current buffer pointer
mov edx, 1 ; read only 1 character
int 80h ; call os to open file
cmp eax, 0 ; check return value
jl rdError ; if <0 return read error
je rdEnd ; if we reached end of file, end
cmp BYTE[edi],13 ; if we reached cr (windows file)
je rdLoop ; continue to read newline
cmp BYTE[edi],10 ; if we reached newline
je rdEnd ; end reading file
inc edi ; increment buffer position
inc esi ; increment number of read chars
cmp esi, [ebp + 16] ; compare with max number of chars
jl rdLoop ; read another character if we didn't reach max
rdEnd:
mov BYTE[edi], 0 ; save string end
mov eax, esi ; return number of read chars
rdError:
pop ebp ; restore frame pointer
ret ; return to calling function
;===============================================================================
; Converts an input string to an integer
; Receives a string pointer and a pointer to an int variable
; Returns eax < 0 if error
;===============================================================================
stringToInt:
push ebp ; save frame pointer
mov ebp, esp ; create new frame
push ebx ; save ebx
mov ecx, 1 ; positive sign by default
mov ebx, 0 ; start with converted number in zero
mov esi, [ebp + 8] ; load string pointer
mov edi, [ebp + 12] ; load pointer to number
mov al, [esi] ; load character
cmp al, 0 ; if end of string
je stoiErr ; is an error
cmp BYTE[esi], '-' ; check if the number is negative
jne stoiLoop ; if not, start loop
mov ecx, -1 ; else, set negative sign
inc esi ; advance to next char
mov al, [esi] ; load character
cmp al, 0 ; if end of string
je stoiErr ; is an error
stoiLoop:
mov al, [esi] ; load digit
cmp al, 0 ; if end of string
je stoiEnd ; end loop
cmp al, '0' ; see if digit is valid
jl stoiErr ; if not, error
cmp al, '9' ; see if digit is valid
jg stoiErr ; if not, error
sub al, '0' ; convert digit to integer
imul ebx, 10 ; multiply old number by 10
movzx eax, al ; convert to dword
add ebx, eax ; add digit to number
inc esi ; increment pointer
jmp stoiLoop ; convert another char
stoiErr:
mov eax, -1 ; return -1 to indicate error
jmp stoiRet ; go to return
stoiEnd:
imul ebx, ecx ; multiply by sign
mov [edi], ebx ; save in output
mov eax, 0 ; return no error
stoiRet:
pop ebx ; restore ebx
pop ebp ; restore frame pointer
ret ; return to calling function
;===============================================================================
; Converts an input string to a float
; Receives a string pointer and a pointer to a float variable
; Returns eax < 0 if error
;===============================================================================
stringToFlt:
push ebp ; save frame pointer
mov ebp, esp ; create new frame
push ebx ; save ebx
mov ecx, 0 ; positive sign by default
mov ebx, 0 ; start with converted number in zero
mov esi, [ebp + 8] ; load string pointer
mov al, [esi] ; load character
cmp al, 0 ; if end of string
je stofErr ; is an error
cmp BYTE[esi], '-' ; check if the number is negative
jne stofLoop ; if not, start loop
mov ecx, 1 ; else, set negative sign
inc esi ; advance to next char
stofLoop:
mov al, [esi] ; load digit
cmp al, 0 ; if end of string
je stofErr ; is an error
cmp al, '.' ; if dot
je stofFrac ; go to fraction
cmp al, '0' ; see if digit is valid
jl stofErr ; if not, error
cmp al, '9' ; see if digit is valid
jg stofErr ; if not, error
sub al, '0' ; convert digit to integer
movzx eax, al ; convert to dword
imul ebx, 10 ; multiply old number by 10
add ebx, eax ; add digit to number
inc esi ; increment pointer
jmp stofLoop ; convert another char
stofFrac:
inc esi ; skip dot
push ebx ; save whole part
fild DWORD[esp] ; load in fpu
add esp, 4 ; restore stack pointer
fld1 ; initialize divisor to 1
mov ebx, 0 ; start with converted number in zero
stofFracLoop:
mov al, [esi] ; load digit
cmp al, 'E' ; if dot
je stofExp ; go to exponent
cmp al, '0' ; see if digit is valid
jl stofErr ; if not, error
cmp al, '9' ; see if digit is valid
jg stofErr ; if not, error
sub al, '0' ; convert digit to integer
movzx eax, al ; convert to dword
imul ebx, 10 ; multiply old number by 10
add ebx, eax ; add digit to number
fmul DWORD[flt10] ; multiply divisor by 10
inc esi ; increment pointer
jmp stofFracLoop ; convert another char
stofExp:
inc esi ; skip E
push ebx ; save fraction part
fild DWORD[esp] ; load in fpu
add esp,4 ; restore stack pointer
fdivr ; divide fraction by power of 10
fadd ; add to whole part
mov ebx, 0 ; start with converted exp in zero
mov edx, 0 ; initialize sign to positive
cmp BYTE[esi], '-' ; check if the exponent is negative
jne chkPos ; if not, check positive
mov edx, 1 ; else, set negative sign
jmp stofExp1
chkPos:
cmp BYTE[esi], '+' ; check if the exponent is positive
jne stofErr ; if not, error
stofExp1:
inc esi ; advance to next char to skip sign
cmp BYTE[esi + 2], 0 ; check valid exponent
jne stofErr ; if not, error
mov al, [esi] ; load digit
cmp al, '0' ; see if digit is valid
jl stofErr ; if not, error
cmp al, '9' ; see if digit is valid
jg stofErr ; if not, error
sub al, '0' ; convert digit to integer
movzx ebx, al ; convert to dword
mov al, [esi+1] ; load digit
cmp al, '0' ; see if digit is valid
jl stofErr ; if not, error
cmp al, '9' ; see if digit is valid
jg stofErr ; if not, error
sub al, '0' ; convert digit to integer
movzx eax, al ; convert to dword
imul ebx, 10 ; multiply old number by 10
add ebx, eax ; add digit to number
fld1 ; load 1 to fpu
expMul:
cmp ebx, 0 ; if exponent is zero
je stofEnd ; go to next step
fmul DWORD[flt10] ; multiply by 10
dec ebx ; decrement exponent
jmp expMul ; repeat loop
stofErr:
mov eax, -1 ; return -1 to indicate error
jmp stofRet ; go to return
stofEnd:
cmp edx, 0 ; if exponent is negative
jne expDiv ; then use divisions
fmulp ; multiply number by exponent
jmp last
expDiv:
fdivp ; divide number by exponent
last:
cmp ecx, 0 ; if sign is positive
je saveNum ; skip
fchs ; else change sign
saveNum:
mov edi, [ebp + 12] ; load pointer to number
fstp DWORD[edi] ; save in output
mov eax, 0 ; return no error
stofRet:
pop ebx ; restore ebx
pop ebp ; restore frame pointer
ret ; return to calling function