-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathparse-input.s
324 lines (280 loc) · 7.17 KB
/
parse-input.s
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
.section .data
.include "linux.s"
.include "ascii.s"
.include "logic.s"
.include "numbers.s"
.equ NOT_ALL_DIGITS, -1
.section .bss
.section .text
# FUNCTION: str_len
#
# Count the number of characters in a null-terminated string.
#
# PARAMETERS
#
# %rdi - address of a string
#
# LOCAL VARIABLES
#
# %rax - count of chars
#
# RETURN
#
# Number of chars in the string
#
.globl str_len
.type str_len, @function
str_len:
xorq %rax, %rax # set char counter to zero
loop:
cmpb $NULL_TERMINATOR, (%rdi,%rax) # compare byte against null
# (%rdi,%rax) = address in %rdi
# + value in %rax, goes through
# addresses one byte at a time
je end # if null exit
incq %rax # move to next byte
jmp loop # back around loop
end:
ret
# FUNCTION: is_number
#
# Check if a string is made entirely of the characters 0-9.
# Allows for negative numbers starting with '-'.
#
# PARAMETERS
#
# %rdi - address of string
# %rsi - length of string
#
# LOCAL VARIABLES
#
# %rdx - current offset
# %cl - current byte being examined (first part of %rcx)
#
# RETURN
#
# TRUE (1) if all numerals, else FALSE (0)
#
.globl is_number
.type is_number, @function
is_number:
movq $TRUE, %rax # assume it is a number
xor %rdx, %rdx # set offset to zero
check_if_negative:
movb (%rdi,%rdx,1), %cl # get first byte
cmpb $NEGATIVE_SIGN, %cl # check if negation sign
je check_length
jmp loop_is_number
check_length:
cmpq $1, %rsi # if negative but only one char long
je not_number # then string is just a minus sign
incq %rdx # ...else move to second char
loop_is_number:
cmpq %rdx, %rsi
je exit_is_number
movb (%rdi,%rdx,1), %cl # get current byte
cmpb $ZERO_CHAR, %cl # check it is a numeral
jl not_number
cmpb $NINE_CHAR, %cl
jg not_number
incq %rdx
jmp loop_is_number
not_number:
movq $FALSE, %rax
exit_is_number:
ret
# FUNCTION: convert_to_int
#
# Convert a string into the integer represented by its digits.
# Checks for and provides appropriate negation if the string
# represents a negative number.
#
# PARAMETERS
#
# %rdi - input string
# %rsi - length of string
#
# LOCAL VARIABLES
#
# %r15 - save whether string starts with negative sign
#
# RETURN
#
# The integer represented by the string
#
.globl convert_to_int
.type convert_to_int, @function
convert_to_int:
call is_negative
movq %rax, %r15
cmpq $TRUE, %r15
je handle_negative
go_convert_to_int:
call digits_to_int
cmpq $TRUE, %r15
je make_int_negative
jmp exit_convert_to_int
make_int_negative:
neg %rax
jmp exit_convert_to_int
handle_negative:
inc %rdi # move the start of the string along by one byte
dec %rsi # decrement the length of the string
jmp go_convert_to_int
exit_convert_to_int:
ret
# FUNCTION: is_negative
#
# Check if string starts with negation symbol.
#
# PARAMETERS
#
# %rdi - string
#
# RETURN
#
# TRUE (1) if starts with negation, else FALSE (0)
#
.globl is_negative
.type is_negative, @function
is_negative:
movq $TRUE, %rax
cmpb $NEGATIVE_SIGN, (%rdi)
je exit_is_negative
movq $FALSE, %rax
exit_is_negative:
ret
# FUNCTION: digits_to_int
#
# Turn a string of digits into an integer.
#
# PROCEDURE
#
# -> Take in string
# -> Calculate greatest power of 10 from length of string
# -> Get each byte (char) in turn, using an offset of string start
# -> Convert that char to an int
# -> Multiply that int by 10 to the current power
# -> Decrement power
# -> Increment offset
# -> Return once final_int * 10**0 has been added to total
#
# PARAMETERS
#
# %rdi - address of string
# %rsi - length of string
#
# LOCAL VARIABLES
#
# %r12 - store address of string
# %r13 - current offset of string
# %r14 - total
# %r15 - current power
# %bl - current byte being examined (first part of %rbx)
# %rcx - quadword representation of current byte, after conversion to int
#
# RETURN
#
# Integer equivalent of the string of digits
#
.globl digits_to_int
.type digits_to_int, @function
digits_to_int:
pushq %r15 # save from calling function
movq %rdi, %r12 # save string address
xor %r13, %r13 # set offset to zero
xor %r14, %r14 # set total to zero
movq %rsi, %r15 # set first power from length of string
subq $1, %r15 # minus 1
loop_digits_to_int:
movb (%r12,%r13,1), %bl # get current byte
subb $INT_CONVERT, %bl # convert to int
movq $DECIMAL_BASE, %rdi # pass BASE
movq %r15, %rsi # pass POWER
call base_to_power # return BASE**POWER in %rax
movzbq %bl, %rcx # zero extend the multiplier
mul %rcx # implicitly mul %rcx, %rax
addq %rax, %r14 # add to running total
back_to_top:
dec %r15
inc %r13
cmpq $0, %r15
jl exit_loop_digits_to_int
jmp loop_digits_to_int
exit_loop_digits_to_int:
movq %r14, %rax
popq %r15 # restore register
ret
# FUNCTION: string_lengths_match
#
# Test if two strings are the same length.
#
# PARAMETERS
#
# %rdi - first string
# %rsi - second string
#
# LOCAL VARIABLES
#
# %r8 - length of first string
# %r9 - length of second string
#
# RETURN
#
# TRUE (1) if strings are the same length, else FALSE (0)
#
.globl string_lengths_match
.type string_lengths_match, @function
string_lengths_match:
call str_len
movq %rax, %r8
movq %rsi, %rdi
call str_len
movq %rax, %r9
cmpq %r8, %r9
je same_len
movq $FALSE, %rax
jmp exit_string_lengths_match
same_len:
movq $TRUE, %rax
exit_string_lengths_match:
ret
# FUNCTION: string_elements_match
#
# Test that two strings are made of same sequence of characters.
# Assumes strings are known to be of same length.
#
# PARAMETERS
#
# %rdi - first string
# %rsi - second string
# %rdx - length of strings
#
# LOCAL VARIABLES
#
# %r14 - current offset
# %cl - the current char to check - lower byte of %rcx
#
# RETURN
#
# TRUE (1) if strings are the same, else FALSE (0)
#
.globl string_elements_match
.type string_elements_match, @function
string_elements_match:
movq %rdx, %r14
match_loop:
cmpq $0, %r14
je same
dec %r14
movb (%rdi,%r14), %cl
cmpb %cl, (%rsi,%r14)
jne not_same
jmp match_loop
not_same:
movq $FALSE, %rax
jmp exit_string_elements_match
same:
movq $TRUE, %rax
exit_string_elements_match:
ret