Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4721 Akyltist 1
;-----------------------------------------------------------------------------+
2
; Функция преобразования строки в вещественное число [ by ManHunter / PCL ]   |
3
;-----------------------------------------------------------------------------|
4
; Параметры:                                                                  |
5
;   lpStr - указатель на исходную строку в формате ASCIIZ                     |
6
;   lpResult - указатель на переменную-приемник значения                      |
7
; На выходе:                                                                  |
8
;   EAX = 1 - строка успешно преобразована                                    |
9
;   EAX = 0 - строка не может быть преобразована в число                      |
10
;-----------------------------------------------------------------------------+
11
proc    string2float lpStr:DWORD, lpResult:DWORD
12
    ; Локальные переменные
13
    locals
14
      dot    dd ?   ; Указатель на дробную часть
15
      exp    dd ?   ; Указатель на экспоненту
16
      digit  dd ?   ; Цифра
17
    endl
18
 
19
    pusha
20
 
21
    ; Проверка строки на валидность
22
    mov     [digit],1
23
 
24
    mov     [exp],0
25
    mov     [dot],0
26
    mov     esi,[lpStr]
27
    ; Минус или плюс может быть только в начале
28
    cmp     byte [esi],'-'
29
    je      @f
30
    cmp     byte [esi],'+'
31
    jne     .loc_chk_loop
32
@@:
33
    inc     esi
34
 
35
    ; После знака не может быть нуля
36
    cmp     byte [esi],0
37
    je      .loc_chk_error
38
.loc_chk_loop:
39
    ; В строке должны быть цифр, экспонента и не более одной точки
40
    lodsb
41
    or      al,al
42
    jz      .loc_chk_complete
43
    cmp     al,'e'
44
    je      .loc_chk_exp
45
    cmp     al,'E'
46
    je      .loc_chk_exp
47
    cmp     al,'.'
48
    je      .loc_chk_dot
49
    cmp     al,'0'
50
    jb      .loc_chk_error
51
    cmp     al,'9'
52
    ja      .loc_chk_error
53
    jmp     .loc_chk_loop
54
 
55
.loc_chk_dot:
56
    ; Точка в строке уже есть?
57
    cmp     [dot],0
58
    ; Строка имеет некорректный формат
59
    jne     .loc_chk_error
60
 
61
    ; Экспонента уже есть?
62
    cmp     [exp],0
63
    ; Строка имеет некорректный формат
64
    jne     .loc_chk_error
65
 
66
    ; Указатель на дробную часть
67
    mov     [dot],esi
68
 
69
    jmp     .loc_chk_loop
70
 
71
.loc_chk_exp:
72
    ; Экспонента уже есть?
73
    cmp     [exp],0
74
    ; Строка имеет некорректный формат
75
    jne     .loc_chk_error
76
 
77
    ; Указатель на начало экспоненты
78
    mov     [exp],esi
79
 
80
    ; Сразу после экспоненты не может быть нуля
81
    cmp     byte [esi],0
82
    je      .loc_chk_error
83
 
84
    ; После экспоненты может быть знак
85
    cmp     byte [esi],'-'
86
    je      @f
87
    cmp     byte [esi],'+'
88
    jne     .loc_chk_loop
89
@@:
90
    inc     esi
91
 
92
    ; Сразу после минуса не может быть нуля
93
    cmp     byte [esi],0
94
    je      .loc_chk_error
95
 
96
    ; Проверить следующий символ
97
    jmp     .loc_chk_loop
98
 
99
.loc_chk_error:
100
    ; Строка не является числом
101
    mov     [digit],0
102
    jmp     .loc_ret
103
 
104
.loc_chk_complete:
105
    ; Инициализация сопроцессора
106
    finit
107
 
108
    ; Начальное значение числа
109
    fldz
110
 
111
    ; Множитель и делитель
112
    mov     [digit],10
113
    fild    dword [digit]
114
 
115
    ; Запись значений до запятой
116
    mov     esi,[lpStr]
117
 
118
    ; В начале строки минус?
119
    cmp     byte [esi],'-'
120
    je      @f
121
    cmp     byte [esi],'+'
122
    jne     .loc_before_dot
123
@@:
124
    inc     esi
125
    ; Преобразование числа до запятой
126
.loc_before_dot:
127
    lodsb
128
    ; Конец строки?
129
    or      al,al
130
    jz      .loc_complete
131
 
132
    cmp     al,'.'
133
    je      .loc_complete_before_dot
134
    cmp     al,'e'
135
    je      .loc_exp
136
    cmp     al,'E'
137
    je      .loc_exp
138
 
139
    ; Очередная цифра
140
    sub     al,'0'
141
    movzx   eax,al
142
    mov     [digit],eax
143
 
144
    ; Записать
145
    fild    dword [digit]
146
    fxch    st2
147
    fmul    st0,st1
148
    fxch    st2
149
    fadd    st2,st0
150
 
151
    ffree   st0     ; Почистить стек
152
    fincstp
153
 
154
    jmp     .loc_before_dot
155
 
156
    ; Преобразование дробной части числа
157
.loc_complete_before_dot:
158
    ; Дробная часть есть?
159
    cmp     [dot],0
160
    je      .loc_complete_after_dot
161
 
162
    ; Экспонента есть?
163
    cmp     [exp],0
164
    je      @f
165
 
166
    ; Указатель на начало экспоненты
167
    mov     esi,[exp]
168
    jmp     .loc_start_after_dot
169
@@:
170
    ; Иначе перенести указатель на конец строки
171
    xor     ecx,ecx
172
    dec     ecx
173
    xor     eax,eax
174
    mov     edi,esi
175
    repne   scasb
176
 
177
    mov     esi,edi
178
 
179
.loc_start_after_dot:
180
    std
181
    dec     esi
182
    dec     esi
183
 
184
    ; Дробная часть
185
    fldz
186
    fxch    st1
187
.loc_after_dot:
188
    lodsb
189
    ; Конец дробной части?
190
    cmp     al,'.'
191
    je      .loc_complete_after_dot
192
 
193
    ; Очередная цифра
194
    sub     al,'0'
195
    movzx   eax,al
196
    mov     [digit],eax
197
 
198
    ; Записать
199
    fild    dword [digit]
200
    fadd    st2,st0
201
    fxch    st2
202
    fdiv    st0,st1
203
    fxch    st2
204
 
205
    ffree   st0     ; Почистить стек
206
    fincstp
207
 
208
    jmp     .loc_after_dot
209
 
210
.loc_complete_after_dot:
211
    ; Сбросить флаг направления
212
    cld
213
 
214
    ffree   st0     ; Почистить стек
215
    fincstp
216
 
217
    ; Сложить дробную и целую часть
218
    fadd    st1,st0
219
 
220
.loc_exp:
221
    ; Экспонента есть?
222
    cmp     [exp],0
223
    je      .loc_complete
224
 
225
    ; Получить значение экспоненты
226
    xor     ecx,ecx
227
 
228
    mov     esi,[exp]
229
    ; В начале строки минус?
230
    cmp     byte [esi],'-'
231
    je      @f
232
    cmp     byte [esi],'+'
233
    jne     .loc_start_exp
234
@@:
235
    inc     esi
236
.loc_start_exp:
237
    lodsb
238
    or      al,al
239
    jz      .loc_end_exp
240
 
241
    sub     al,'0'
242
    movzx   eax,al
243
    imul    ecx,10
244
    add     ecx,eax
245
 
246
    jmp     .loc_start_exp
247
.loc_end_exp:
248
 
249
    or      ecx,ecx
250
    jz      .loc_complete
251
 
252
    ffree   st0     ; Почистить стек
253
    fincstp
254
 
255
    mov     [digit],10
256
    fild    dword [digit]
257
 
258
    ; Делить или умножать?
259
    mov     esi,[exp]
260
    cmp     byte [esi],'-'
261
    je      .loc_exp_divide
262
 
263
.loc_exp_multiple:
264
    fmul    st1,st0
265
    loop    .loc_exp_multiple
266
    jmp     .loc_complete
267
 
268
.loc_exp_divide:
269
    fdiv    st1,st0
270
    loop    .loc_exp_divide
271
 
272
.loc_complete:
273
    ffree   st0     ; Почистить стек
274
    fincstp
275
 
276
    ; В начале строки минус?
277
    mov     esi,[lpStr]
278
    cmp     byte [esi],'-'
279
    jne     @f
280
 
281
    ; Изменить знак числа
282
    fchs
283
@@:
284
    ; Записать значение в ячейку памяти
285
    mov     eax,[lpResult]
286
    ; Если требуется повышенная точность, то приемник
287
    ; должен иметь размер QWORD, а следующую команду
288
    ; надо заменить на fstp qword [eax]
289
    fstp    tword [eax]
290
 
291
    ; Успешное преобразование
292
    mov     [digit],1
293
.loc_ret:
294
    popa
295
 
296
    ; Результат преобразования
297
    mov     eax,[digit]
298
 
299
    ret
300
endp