asm_dip/toolchain/fasmg.kl0e/source/expressions.inc

4253 lines
95 KiB
PHP
Raw Normal View History

2024-11-24 20:13:28 -08:00
struct ExpressionTerm
attributes dd ? ; EXPR_# in low byte, plus any EXPRF_#
metadata dd ?
value dd ?
ends
EXPR_NUMBER = 30h
EXPR_STRING = 22h
EXPR_FLOAT = 2Eh
EXPR_SYMBOL_VALUE = 10h
EXPR_OPERATOR = 20h
EXPR_SYMBOL = 40h
EXPR_POLYNOMIAL = 31h
EXPR_MISSING_ARGUMENT = 29h
EXPR_MISSING_PARENTHESIS = 28h
EXPRF_VALUE_IN_WORKSPACE = 100h
EXPRF_CALM_LITERAL = 200h
EXPRF_OPERATOR_UNARY = 1000h
convert_number:
; in:
; edx - 32-bit length followed by a string of that length
; out:
; cf set when number has no known prefix or suffix but is not a plain decimal number
; when cf = 0:
; edx - 32-bit length followed by binary data of that length, null when string did not represent a valid number
; when cf = 1:
; edx preserved
; preserves: esi
mov edi,[value_workspace.memory_start]
add edi,[value_position]
mov ecx,[edx]
add edx,4
cmp byte [edx],'$'
je pascal_hexadecimal_number
cmp ecx,2
jb check_number_suffix
cmp word [edx],'0x'
je c_hexadecimal_number
check_number_suffix:
movzx eax,byte [edx+ecx-1]
mov al,[characters+eax]
cmp al,'h'
je suffixed_hexadecimal_number
cmp al,'b'
je suffixed_binary_number
cmp al,'o'
je suffixed_octal_number
cmp al,'q'
je suffixed_octal_number
cmp al,'d'
jne decimal_number
or ah,1
dec ecx
jz invalid_number
decimal_number:
mov ebx,ecx
check_decimal_digits:
mov al,[edx+ebx-1]
cmp al,27h
je check_next_decimal_digit
cmp al,'_'
je check_next_decimal_digit
cmp al,'0'
jb unknown_number
cmp al,'9'
ja unknown_number
check_next_decimal_digit:
dec ebx
jnz check_decimal_digits
push ecx edx
add ecx,12
mov edx,value_workspace
call reserve_workspace
xor eax,eax
mov dword [edi+4],eax
add eax,4
mov dword [edi],eax
pop edx ebx
convert_decimal_number:
mov al,[edx]
cmp al,27h
je skip_decimal_digit
cmp al,'_'
je skip_decimal_digit
sub al,'0'
mov ecx,[edi]
xor ecx,ecx
add_decimal_digit:
add ecx,4
movzx eax,al
add [edi+ecx],eax
setc al
sets ah
cmp ecx,[edi]
jb add_decimal_digit
or ah,al
jz decimal_digit_added
xor ah,ah
add ecx,4
mov [edi+ecx],eax
mov [edi],ecx
decimal_digit_added:
dec ebx
jz decimal_number_converted
next_decimal_digit:
inc edx
push ebx edx
mov ebx,10
xor ecx,ecx
xor edx,edx
multiply_decimal_number:
add ecx,4
mov eax,[edi+ecx]
mov [edi+ecx],edx
mul ebx
add [edi+ecx],eax
cmp ecx,[edi]
jb multiply_decimal_number
test edx,edx
jz decimal_number_multiplied
add ecx,4
mov [edi+ecx],edx
mov [edi],ecx
decimal_number_multiplied:
pop edx ebx
xor eax,eax
jmp convert_decimal_number
skip_decimal_digit:
inc edx
dec ebx
jnz convert_decimal_number
decimal_number_converted:
lea edx,[edi+4]
mov ecx,[edi]
dec ecx
optimize_number:
movsx eax,byte [edx+ecx-1]
cmp ah,[edx+ecx]
jne number_optimized
loop optimize_number
cmp byte [edx],0
je number_finished
number_optimized:
inc ecx
number_finished:
sub edx,4
mov [edx],ecx
lea edi,[edx+4+ecx]
sub edi,[value_workspace.memory_start]
mov [value_position],edi
; clc
retn
c_hexadecimal_number:
sub ecx,3
jc invalid_number
add edx,2
jmp hexadecimal_number
pascal_hexadecimal_number:
inc edx
suffixed_hexadecimal_number:
sub ecx,2
jc invalid_number
hexadecimal_number:
push edx ecx
shr ecx,1
add ecx,6
mov edx,value_workspace
call reserve_workspace
pop ebx edx
push edi
xor eax,eax
stosd
mov [edi],al
xor cl,cl
hexadecimal_digit:
movzx eax,byte [edx+ebx]
cmp al,27h
je skip_hexadecimal_digit
cmp al,'_'
je skip_hexadecimal_digit
mov al,[characters+eax]
sub al,'0'
jc invalid_digit
cmp al,10
jb hexadecimal_digit_ok
sub al,'a'-'0'
jc invalid_digit
add al,10
cmp al,16
jae invalid_digit
hexadecimal_digit_ok:
shl al,cl
or [edi],al
sub ebx,1
jc number_converted
xor cl,4
jnz hexadecimal_digit
inc edi
mov [edi],cl
jmp hexadecimal_digit
skip_hexadecimal_digit:
sub ebx,1
jnc hexadecimal_digit
number_converted:
pop edx
inc edi
and byte [edi],0
add edx,4
mov ecx,edi
sub ecx,edx
jmp optimize_number
suffixed_binary_number:
sub ecx,2
jc invalid_number
push edx ecx
shr ecx,3
add ecx,6
mov edx,value_workspace
call reserve_workspace
pop ebx edx
push edi
xor eax,eax
stosd
mov [edi],al
xor cl,cl
binary_digit:
mov al,[edx+ebx]
cmp al,27h
je skip_binary_digit
cmp al,'_'
je skip_binary_digit
sub al,'0'
jc invalid_digit
cmp al,2
jae invalid_digit
shl al,cl
or [edi],al
sub ebx,1
jc number_converted
inc cl
and cl,111b
jnz binary_digit
inc edi
mov [edi],cl
jmp binary_digit
skip_binary_digit:
sub ebx,1
jnc binary_digit
jmp number_converted
suffixed_octal_number:
sub ecx,2
jc invalid_number
push edx ecx
shr ecx,1
add ecx,6
mov edx,value_workspace
call reserve_workspace
pop ebx edx
push edi
xor eax,eax
stosd
mov [edi],al
xor cl,cl
octal_digit:
mov al,[edx+ebx]
cmp al,27h
je skip_octal_digit
cmp al,'_'
je skip_octal_digit
sub al,'0'
jc invalid_digit
cmp al,8
jae invalid_digit
shl eax,cl
or [edi],al
add cl,3
cmp cl,8
jb skip_octal_digit
sub cl,8
inc edi
mov [edi],ah
xor eax,eax
skip_octal_digit:
sub ebx,1
jnc octal_digit
jmp number_converted
unknown_number:
test ah,ah
jnz invalid_number
sub edx,4
stc
retn
invalid_digit:
pop edi
invalid_number:
xor edx,edx
mov al,30h
clc
retn
convert_number_back:
; in:
; edx - 32-bit length followed by binary data of that length
; out:
; edx - 32-bit length followed by a string of that length
; note:
; the number is treated as unsigned
; returned string is in temporary storage and should be copied out of it immediately
mov edi,[value_workspace.memory_start]
add edi,[value_position]
mov ecx,[edx]
add ecx,2
shl ecx,2
mov esi,edx
mov edx,value_workspace
call reserve_workspace
lodsd
lea ebx,[edi+4+(eax+1)*4]
mov edx,edi
mov ecx,eax
rep movsb
xchg eax,ecx
stosd
jecxz highest_dword_offset_ok
dec ecx
and ecx,not 11b
highest_dword_offset_ok:
mov esi,edx
mov edi,ebx
push edi
obtain_digit:
xor edx,edx
divide_highest_dwords:
mov eax,[esi+ecx]
call div10
test eax,eax
jnz more_digits_to_come
sub ecx,4
jnc divide_highest_dwords
pop ecx
cmp ecx,edi
je store_final_digit
test dl,dl
jz finish_number
store_final_digit:
add dl,'0'
dec edi
mov [edi],dl
finish_number:
sub ecx,edi
sub edi,4
mov [edi],ecx
mov edx,edi
retn
more_digits_to_come:
mov ebx,ecx
divide_remaining_dwords:
mov [esi+ebx],eax
sub ebx,4
jc store_digit
mov eax,[esi+ebx]
call div10
jmp divide_remaining_dwords
store_digit:
add dl,'0'
dec edi
mov [edi],dl
jmp obtain_digit
div10:
; cmp edx,10
; jae internal_error
push ebx ecx
push eax
mov ebx,eax
mov ecx,edx
shld edx,eax,2
sub ebx,edx
sbb ecx,0
mov eax,ebx
mov ebx,1999999Ah
mul ebx
mov eax,ecx
imul eax,ebx
add eax,edx
pop edx
imul ecx,eax,10
sub edx,ecx
cmp edx,10
jb div10_done
sub edx,10
inc eax
div10_done:
pop ecx ebx
retn
fit_value:
; in:
; edx - 32-bit length followed by numeric data
; ecx = number of bytes that the value has to fit into
; edi - buffer for the specified amount of bytes, null when just checking whether value fits in range
; out:
; sf set when value is negative
; cf set if value does not fit into extended range for specified size
; when cf = 0:
; edi - value fit into specified amount of bytes
; preserves: edx, esi, edi
; note: when value is zero, it fits even into zero byte range
mov ebx,ecx
cmp [edx],ecx
jbe term_in_range
xor al,al
cmp [edx+4+ecx],al
je check_redundant_bytes
dec al
cmp [edx+4+ecx],al
jne term_out_of_range
jecxz term_out_of_range
check_redundant_bytes:
inc ecx
cmp ecx,[edx]
je term_in_range
cmp [edx+4+ecx],al
je check_redundant_bytes
term_out_of_range:
mov ecx,[edx]
mov al,[edx+4+ecx-1]
test al,al
stc
retn
term_in_range:
test edi,edi
jz value_fit
mov ecx,[edx]
cmp ecx,ebx
jbe copy_value
mov ecx,ebx
copy_value:
lea eax,[edx+4]
xchg eax,esi
rep movsb
mov esi,eax
mov ecx,[edx]
movsx eax,byte [edx+4+ecx-1]
mov al,ah
mov ecx,ebx
sub ecx,[edx]
jbe value_ready
rep stosb
value_ready:
sub edi,ebx
value_fit:
test al,al
clc
retn
start_decimal_converter:
; preserves: ebx
mov edx,value_workspace
mov edi,[value_position]
mov [converter_position],edi
add edi,[edx+Workspace.memory_start]
mov ecx,2*sizeof.FloatData
call reserve_workspace
lea ecx,[edi+2*sizeof.FloatData]
sub ecx,[edx+Workspace.memory_start]
mov [value_position],ecx
mov esi,edi
xor eax,eax
assert sizeof.FloatData and 11b = 0
mov ecx,sizeof.FloatData shr 2
rep stosd
mov edx,edi
mov ecx,sizeof.FloatData shr 2
rep stosd
mov [edx+FloatData.exponent],7
retn
convert_decimal_digit:
; in:
; al = value of subsequent digit
; ecx = number of zero digits to insert before
; out:
; edi - FloatData holding the value corresponding to digits converted so far
; note: start_decimal_converter should be called before converting the first digit
mov esi,[value_workspace.memory_start]
add esi,[converter_position]
mov edi,esi
shl eax,24
mov [esi+sizeof.FloatData+FloatData.mantissa],eax
jecxz multiply_by_ten
inc ecx
call multiply_float_by_power_of_ten
jmp add_subsequent_digit
multiply_by_ten:
mov ecx,10
call multiply_float_by_unsigned_int
add_subsequent_digit:
mov esi,edi
lea ebx,[esi+sizeof.FloatData]
call add_floats
retn
finish_decimal_conversion:
; out:
; edi - FloatData holding the converted value
; preserves: ebx, ecx, esi, edi
; note: this function should not be called before all the digits of a value have been processed by convert_decimal_digit
mov eax,[converter_position]
mov edi,[value_workspace.memory_start]
add edi,eax
add eax,2*sizeof.FloatData
cmp eax,[value_position]
jne decimal_conversion_finished
sub eax,sizeof.FloatData
mov [value_position],eax
decimal_conversion_finished:
retn
keep_value:
; in:
; edx - numeric or string data returned by source parsing or expression evaluating functions
; preserves: ebx, esi, edi
; note:
; this function should be used in conjunction with get_kept_value to retain access to data
; while calling other parsing or expression evaluating functions
xor al,al
cmp edx,[value_workspace.memory_end]
jae keep_value_pointer
mov ecx,edx
sub ecx,[value_workspace.memory_start]
jc keep_value_pointer
mov edx,ecx
inc al
keep_value_pointer:
mov [kept_value],edx
mov [kept_value_in_workspace],al
retn
get_kept_value:
; out:
; edx - numeric or string data previously passed to keep_value
; preserves: eax, ebx, ecx, esi, edi
mov edx,[kept_value]
cmp [kept_value_in_workspace],0
je kept_value_ok
add edx,[value_workspace.memory_start]
kept_value_ok:
retn
get_constant_value:
; in:
; esi = pointer into preprocessed line or the last embedded line
; out:
; esi = pointer advanced past the processed part of line
; al = type of value, zero when expression gave no result
; when al = 22h:
; edx - 32-bit length followed by string data
; when al = 30h:
; edx - 32-bit length followed by numeric data
; when al = 2Eh:
; edx - FloatData
call get_expression_value
jc return_empty_type
get_calculated_constant_value:
; in:
; edi - list of ExpressionTerm elements as returned by get_expression_value
; out:
; same as get_constant_value
; preserves: esi, edi
call forbid_variable_terms
call get_term_value
mov eax,[edi+ExpressionTerm.attributes]
assert EXPR_STRING = 22h
assert EXPR_NUMBER = 30h
assert EXPR_FLOAT = 2Eh
retn
return_empty_type:
xor al,al
retn
forbid_variable_terms:
mov eax,edi
detect_variable_terms:
add eax,sizeof.ExpressionTerm
cmp [eax+ExpressionTerm.attributes],0
je expression_terms_ok
cmp [eax+ExpressionTerm.metadata],0
je detect_variable_terms
mov edx,_misused_variable_term
call register_error
expression_terms_ok:
retn
get_numeric_constant_value:
; in:
; esi = pointer into preprocessed line or the last embedded line
; out:
; esi = pointer advanced past the processed part of line
; edx - 32-bit length followed by numeric data, null when expression gave no result
; edi - ExpressionTerm, null when expression gave no result
call get_expression_value
jc empty_numeric_constant
call forbid_variable_terms
call get_numeric_term_value
retn
empty_numeric_constant:
xor edx,edx
xor edi,edi
retn
get_expression_value:
; in:
; esi = pointer into preprocessed line or the last embedded line
; out:
; cf set if expression gave no result
; esi = pointer advanced past the processed part of line
; when cf = 0:
; edi - list of ExpressionTerm elements, the closing element has attributes set to zero
mov edi,[expression_workspace.memory_start]
and [leave_opening_parentheses],0
call parse_expression
push esi
mov esi,[expression_workspace.memory_start]
mov edi,[calculation_workspace.memory_start]
call calculate_parsed_expression
call pop_terms
pop esi
retn
convert_terms_to_numeric_value:
; in:
; edi - list of ExpressionTerm elements as returned by get_expression_value
; out:
; esi - value in VALTYPE_NUMERIC format
; ecx = length of value
; note: the returned value is placed in assembly workspace
mov edx,assembly_workspace
convert_terms_to_numeric_value_in_workspace:
; in:
; edx - Workspace
; edi - list of ExpressionTerm elements as returned by get_expression_value
; out:
; esi - value in VALTYPE_NUMERIC format (same as [edx+Workspace.memory_start])
; ecx = length of value
; preserves: edx
mov ebx,[edx+Workspace.memory_start]
copy_numeric_term_values:
mov esi,edx
call get_numeric_term_value
xchg esi,edx
xchg ebx,edi
mov ecx,[esi]
add ecx,8
call reserve_workspace
lodsd
stosd
mov ecx,eax
rep movsb
next_numeric_term:
add ebx,sizeof.ExpressionTerm
cmp [ebx+ExpressionTerm.attributes],0
je numeric_term_values_copied
mov eax,[ebx+ExpressionTerm.metadata]
test eax,eax
jz next_numeric_term
stosd
xchg ebx,edi
jmp copy_numeric_term_values
numeric_term_values_copied:
xor eax,eax
stosd
mov esi,[edx+Workspace.memory_start]
mov ecx,edi
sub ecx,esi
retn
update_predicted_shift:
; in:
; edx - ValueDefinition that is going to be updated
; esi - new value in VALTYPE_NUMERIC fomat
; preserves: ebx, ecx, edx, esi
test edx,edx
jz zero_shift
cmp [edx+ValueDefinition.type],VALTYPE_NUMERIC
jne zero_shift
mov eax,[current_pass]
dec eax
cmp eax,[edx+ValueDefinition.pass]
jne zero_shift
call get_low_dword
mov [predicted_shift],eax
mov edi,[edx+ValueDefinition.value]
xchg esi,edi
call get_low_dword
sub [predicted_shift],eax
test byte [predicted_shift+3],11000000b
mov esi,edi
jnp zero_shift
retn
zero_shift:
mov [predicted_shift],0
retn
get_low_dword:
mov eax,[esi]
cmp eax,1
jb low_dword_ready
je dword_from_single_byte
cmp eax,3
jb dword_from_two_bytes
je dword_from_three_bytes
mov eax,[esi+4]
low_dword_ready:
retn
dword_from_single_byte:
movsx eax,byte [esi+4]
retn
dword_from_two_bytes:
movsx eax,word [esi+4]
retn
dword_from_three_bytes:
mov eax,[esi+4-1]
sar eax,8
retn
get_area_value:
; in:
; edi - command sequence created by parse_expression
; out:
; cf set if expression does not yield a valid and accessible VALTYPE_AREA value
; when cf = 0:
; ebx - SymbolTree_Leaf
; edx - ValueDefinition
; preserves: esi
mov al,[edi]
cmp al,EXPR_SYMBOL
je check_for_plain_symbol
cmp al,EXPR_SYMBOL_VALUE
jne no_plain_area_symbol
cmp dword [edi+3*4],0
jne no_plain_area_symbol
mov edx,[edi+2*4]
test edx,edx
jz no_plain_area_symbol
check_area_symbol:
cmp [edx+ValueDefinition.type],VALTYPE_AREA
jne no_plain_area_symbol
mov ebx,[edi+4]
call mark_symbol_as_used
clc
retn
check_for_plain_symbol:
cmp dword [edi+2*4],0
jne no_plain_area_symbol
mov ebx,[edi+4]
call get_available_value
jnc check_area_symbol
no_plain_area_symbol:
push esi
mov esi,edi
mov edi,[calculation_workspace.memory_start]
call calculate_parsed_expression
jc invalid_area_expression
call pop_terms
jc invalid_area_expression
mov eax,edi
xor esi,esi
extract_variable_term:
add eax,sizeof.ExpressionTerm
cmp [eax+ExpressionTerm.attributes],0
je variable_term_extracted
cmp [eax+ExpressionTerm.metadata],0
je extract_variable_term
test esi,esi
jnz invalid_area_expression
mov esi,eax
jmp extract_variable_term
variable_term_extracted:
test esi,esi
jz invalid_area_expression
call get_term_value
xor ecx,ecx
mov edi,ecx
call fit_value
jc invalid_area_expression
mov edi,esi
call get_term_value
mov ecx,1
mov edi,value
call fit_value
jc invalid_area_expression
cmp byte [value],1
jne invalid_area_expression
mov ebx,[esi+ExpressionTerm.metadata]
mov edx,[ebx+SymbolTree_Leaf.definition]
test edx,edx
jz invalid_area_expression
cmp [edx+ValueDefinition.type],VALTYPE_AREA
jne invalid_area_expression
pop esi
clc
retn
invalid_area_expression:
pop esi
invalid_area_symbol:
stc
retn
get_constituent_value:
; same as get_processed_value
; note: after any expression evaluation functions have been used, only this function should be used to retrieve constituents of line
xor al,al
xchg al,[current_constituent]
test al,al
jz get_processed_value
get_constituent_components:
mov ebx,[constituent_symbol]
mov edx,[constituent_value]
mov ecx,[constituent_whitespace]
clc
retn
peek_at_constituent_value:
; same as get_constituent_value, but returned values are also kept in constituent variables
; note:
; the retrieved value is still going to be available to expression evaluation functions or to the next call of get_constituent_value
; to consume the value it is enough to set [current_constituent] to zero
cmp [current_constituent],0
jne get_current_constituent
call get_processed_value
jc constituent_value_ok
mov [current_constituent],al
mov [constituent_symbol],ebx
mov [constituent_value],edx
mov [constituent_whitespace],ecx
constituent_value_ok:
retn
get_current_constituent:
mov al,[current_constituent]
jmp get_constituent_components
parse_expression:
; in:
; esi = pointer into preprocessed line or the last embedded line
; edi = pointer to a place in expression workspace where the parsed command sequence should be stored
; [leave_opening_parentheses] = non-zero when parentheses opened in the beginning of expression that did not get closed should be returned to caller instead of being registered in parsed expression
; out:
; esi = pointer advanced past the processed part of line
; edi = pointer advanced past the created sequence in expression workspace
; ecx = number of parentheses opened in the beginning of expression that did not get closed (zero when [leave_opening_parentheses] was zero)
mov [expression_end],edi
sub edi,[expression_workspace.memory_start]
mov [expression_position],edi
mov eax,[operator_stack_base]
mov [operator_stack],eax
mov [operator_stack_position],eax
mov [operator_argument_expected],1
get_expression_element:
mov edi,[expression_end]
mov edx,expression_workspace
mov ecx,[operator_stack_position]
sub ecx,[operator_stack_base]
add ecx,16
call reserve_workspace
mov [expression_end],edi
call peek_at_constituent_value
mov edi,[expression_end]
jc expression_line_end
cmp al,'('
je open_subexpression
cmp al,')'
je close_subexpression
cmp al,30h
je store_expression_number
cmp al,22h
je store_expression_string
cmp al,2Eh
je store_expression_float
cmp al,1Ah
je expression_symbol
movzx eax,al
shl eax,2
add eax,[operator_table]
mov edx,[eax]
test edx,edx
jz terminate_expression
xor ebx,ebx
mov ecx,edx
jmp identify_operator
expression_symbol:
test edx,edx
jz store_expression_symbol
mov ecx,edx
identify_operator:
cmp [ecx+ValueDefinition.type],VALTYPE_NATIVE_COMMAND
jne inspect_expression_symbol
test [ecx+ValueDefinition.attribute],OPERATOR_UNARY
setnz al
xor al,[operator_argument_expected]
jz store_expression_operator
mov ecx,[ecx+ValueDefinition.previous]
test ecx,ecx
jnz identify_operator
inspect_expression_symbol:
cmp [edx+ValueDefinition.type],VALTYPE_NATIVE_COMPARATOR
je terminate_expression
store_expression_symbol:
cmp [operator_argument_expected],0
je terminate_expression
mov eax,EXPR_SYMBOL_VALUE
stosd
mov eax,ebx
stosd
mov eax,edx
stosd
expression_symbol_stored:
mov [expression_end],edi
and [operator_argument_expected],0
and [current_constituent],0
jmp get_expression_element
store_expression_number:
cmp [operator_argument_expected],0
je terminate_expression
mov eax,EXPR_NUMBER
value_pointer_in_expression:
cmp edx,[value_workspace.memory_end]
jae value_pointer_in_expression_ok
mov ebx,edx
sub ebx,[value_workspace.memory_start]
jc value_pointer_in_expression_ok
mov edx,ebx
or eax,EXPRF_VALUE_IN_WORKSPACE
value_pointer_in_expression_ok:
stosd
mov eax,edx
stosd
jmp expression_symbol_stored
store_expression_string:
cmp [operator_argument_expected],0
je terminate_expression
mov eax,EXPR_STRING
jmp value_pointer_in_expression
store_expression_float:
cmp [operator_argument_expected],0
je terminate_expression
mov eax,EXPR_FLOAT
jmp value_pointer_in_expression
store_expression_operator:
mov edx,[ecx+ValueDefinition.value]
mov cl,[ecx+ValueDefinition.attribute]
mov ch,cl
and cl,OPERATOR_PRECEDENCE_MASK
mov ebx,[operator_stack_position]
cmp [operator_argument_expected],0
jne push_operator
establish_operator_precedence:
cmp ebx,[operator_stack]
je push_operator
cmp cl,[ebx-8]
ja push_operator
jb store_pending_operator
test ch,OPERATOR_RIGHT_ASSOCIATIVE
jnz push_operator
store_pending_operator:
sub ebx,8
xor eax,eax
test byte [ebx+1],OPERATOR_UNARY
setnz al
shl eax,bsf EXPRF_OPERATOR_UNARY
mov al,EXPR_OPERATOR
stosd
mov eax,[ebx+4]
stosd
jmp establish_operator_precedence
push_operator:
call reserve_operator_stack
mov [ebx],ecx
mov [ebx+4],edx
add ebx,8
mov [operator_stack_position],ebx
mov [expression_end],edi
or [operator_argument_expected],1
and [current_constituent],0
jmp get_expression_element
open_subexpression:
cmp [operator_argument_expected],0
je terminate_expression
mov ebx,[operator_stack_position]
call reserve_operator_stack
mov eax,[operator_stack]
sub eax,[operator_stack_base]
mov [ebx],eax
add ebx,4
mov [operator_stack],ebx
mov [operator_stack_position],ebx
and [current_constituent],0
jmp get_expression_element
close_subexpression:
mov eax,[operator_stack]
cmp eax,[operator_stack_base]
je terminate_expression
cmp [operator_argument_expected],0
je subexpression_closed
mov eax,EXPR_MISSING_ARGUMENT
stosd
subexpression_closed:
call store_remaining_operators
mov [expression_end],edi
sub ebx,4
mov eax,[ebx]
add eax,[operator_stack_base]
mov [operator_stack],eax
mov [operator_stack_position],ebx
and [current_constituent],0
jmp get_expression_element
expression_line_end:
and [current_constituent],0
terminate_expression:
cmp [operator_argument_expected],0
je close_expression
mov eax,[operator_stack_position]
cmp eax,[operator_stack]
jne expression_terminated_prematurely
mov eax,edi
sub eax,[expression_workspace.memory_start]
cmp eax,[expression_position]
je close_expression
expression_terminated_prematurely:
mov eax,EXPR_MISSING_ARGUMENT
stosd
close_expression:
call store_remaining_operators
xor ecx,ecx
cmp ebx,[operator_stack_base]
jne forcibly_close_subexpressions
expression_parsed:
xor eax,eax
stosd
retn
forcibly_close_subexpressions:
sub ebx,4
mov eax,[ebx]
add eax,[operator_stack_base]
mov [operator_stack],eax
cmp [leave_opening_parentheses],0
je internal_parenthesis
cmp eax,ebx
je external_parenthesis
internal_parenthesis:
mov eax,EXPR_MISSING_PARENTHESIS
inc ecx
rep stosd
mov [operator_stack_position],ebx
call store_remaining_operators
cmp ebx,[operator_stack_base]
jne forcibly_close_subexpressions
jmp expression_parsed
external_parenthesis:
inc ecx
cmp ebx,[operator_stack_base]
jne forcibly_close_subexpressions
jmp expression_parsed
reserve_operator_stack:
mov eax,[operator_stack_end]
sub eax,8
cmp ebx,eax
jbe operator_stack_ready
push edx
mov eax,[operator_stack_base]
sub ebx,eax
sub [operator_stack],eax
mov ecx,[operator_stack_end]
sub ecx,eax
add ecx,8
call grow_stack
add ebx,eax
add [operator_stack],eax
mov [operator_stack_base],eax
add eax,ecx
mov [operator_stack_end],eax
pop edx
operator_stack_ready:
retn
store_remaining_operators:
mov ebx,[operator_stack_position]
store_operator:
cmp ebx,[operator_stack]
je remaining_operators_stored
sub ebx,8
xor eax,eax
test byte [ebx+1],OPERATOR_UNARY
setnz al
shl eax,bsf EXPRF_OPERATOR_UNARY
mov al,EXPR_OPERATOR
stosd
mov eax,[ebx+4]
stosd
jmp store_operator
remaining_operators_stored:
retn
calculate_parsed_expression:
; in:
; esi - command sequence created by parse_expression
; edi - top of the stack in the calculation workspace
; out:
; cf set if expression had structural errors
; esi = pointer moved past the processed sequence
; edi - top of the updated stack
; when cf = 0:
; eax = non-zero if result is considered not yet known for resolving purposes
mov [expression_end],esi
mov eax,edi
sub eax,[calculation_workspace.memory_start]
mov [calculation_position],eax
cmp dword [esi],0
je invalid_expression
calculation_loop:
mov esi,[expression_end]
lodsd
cmp al,EXPR_OPERATOR
je execute_operator
cmp al,EXPR_NUMBER
je push_literal
cmp al,EXPR_STRING
je push_literal
cmp al,EXPR_FLOAT
je push_literal
cmp al,EXPR_SYMBOL_VALUE
je push_symbol_value
cmp al,EXPR_SYMBOL
je push_symbol_current_value
cmp al,EXPR_POLYNOMIAL
je push_polynomial_literal
test eax,eax
jnz structural_error
; clc
retn
execute_operator:
lodsd
mov [expression_end],esi
jmp eax
push_literal:
mov ebx,eax
mov edx,calculation_workspace
mov ecx,2*sizeof.ExpressionTerm
call reserve_workspace
lodsd
test ebx,EXPRF_CALM_LITERAL
jnz calm_literal_value
test ebx,EXPRF_VALUE_IN_WORKSPACE
jnz valid_literal_value
test eax,eax
jnz valid_literal_value
jmp invalid_number_in_expression
calm_literal_value:
add eax,[calm_literals]
valid_literal_value:
mov [edi+ExpressionTerm.attributes],ebx
mov [edi+ExpressionTerm.value],eax
xor eax,eax
mov [edi+ExpressionTerm.metadata],eax
mov [edi+sizeof.ExpressionTerm+ExpressionTerm.attributes],eax
add edi,2*sizeof.ExpressionTerm
mov [expression_end],esi
jmp calculation_loop
push_polynomial_literal:
; occurring only in reduced CALM expressions
mov ebx,eax
lodsd
mov [expression_end],esi
test ebx,EXPRF_CALM_LITERAL
jz polynomial_value_ready
add eax,[calm_literals]
polynomial_value_ready:
xor esi,esi
mov ebx,eax
jmp push_polynomial
push_symbol_current_value:
; occurring only in CALM expressions, entire expression workspace should be free to use
lodsd
test eax,eax
jz invalid_identifier_in_expression
mov ebx,eax
mov [expression_end],esi
call use_available_value
jc undefined_symbol_in_expression
mov al,[edx+ValueDefinition.type]
cmp al,VALTYPE_SYMBOLIC
jne identify_value_to_push
push esi edi
call clear_line_embeddings
xor esi,esi
xor ecx,ecx
call embed_symbolic_value
mov edi,[expression_workspace.memory_start]
and [leave_opening_parentheses],0
call parse_expression
pop edi
call get_constituent_value
jnc invalid_subexpression
mov esi,[expression_workspace.memory_start]
push [calculation_position]
call calculate_parsed_expression
pop [calculation_position]
jc invalid_subexpression
pop [expression_end]
test eax,eax
jnz unknown_result
jmp calculation_loop
invalid_subexpression:
pop [expression_end]
mov edx,_invalid_expression
call register_error
jmp unknown_result
push_symbol_value:
lodsd
test eax,eax
jz invalid_identifier_in_expression
mov ebx,eax
lodsd
mov edx,eax
call mark_symbol_as_used
mov [expression_end],esi
test edx,edx
jz undefined_symbol_in_expression
mov al,[edx+ValueDefinition.type]
identify_value_to_push:
cmp al,VALTYPE_NUMERIC
je push_numeric_symbol
cmp al,VALTYPE_ELEMENT
je push_element
cmp al,VALTYPE_AREA
je push_area
cmp al,VALTYPE_STRING
je push_string
cmp al,VALTYPE_FLOAT
je push_float
cmp al,VALTYPE_PLAIN
je push_plain_symbol
cmp al,VALTYPE_NATIVE_FUNCTION
jne invalid_symbol_in_expression
jmp [edx+ValueDefinition.value]
push_numeric_symbol:
xor esi,esi
test [edx+ValueDefinition.flags],VAL_SHIFTABLE
jz predicted_shift_ok
mov eax,[edx+ValueDefinition.pass]
cmp eax,[current_pass]
je predicted_shift_ok
mov esi,[predicted_shift]
predicted_shift_ok:
mov ebx,[edx+ValueDefinition.value]
mov eax,ebx
add eax,[edx+ValueDefinition.value_length]
push_polynomial:
push eax edi
mov edx,calculation_workspace
mov ecx,2*sizeof.ExpressionTerm
call reserve_workspace
mov [edi+ExpressionTerm.attributes],EXPR_NUMBER
mov [edi+ExpressionTerm.value],ebx
test esi,esi
jz push_numeric_terms
or [next_pass_needed],1
mov ecx,temporary_value
mov dword [ecx],4
mov dword [ecx+4],esi
lea esi,[edi+sizeof.ExpressionTerm]
mov [esi+ExpressionTerm.attributes],EXPR_NUMBER
mov [esi+ExpressionTerm.value],ecx
push ebx
call add_term_values
pop ebx
push_numeric_terms:
add edi,sizeof.ExpressionTerm
mov edx,calculation_workspace
mov ecx,sizeof.ExpressionTerm
call reserve_workspace
mov eax,[ebx]
lea ebx,[ebx+4+eax]
mov eax,[ebx]
test eax,eax
jz numeric_terms_pushed
mov eax,[ebx]
mov [edi+ExpressionTerm.metadata],eax
add ebx,4
mov [edi+ExpressionTerm.attributes],EXPR_NUMBER
mov [edi+ExpressionTerm.value],ebx
jmp push_numeric_terms
numeric_terms_pushed:
pop edx ecx
sub ecx,8
cmp ebx,ecx
jbe symbol_metadata_ok
xor ebx,ebx
symbol_metadata_ok:
mov [edx+ExpressionTerm.metadata],ebx
xor eax,eax
mov [edi+ExpressionTerm.attributes],eax
add edi,sizeof.ExpressionTerm
jmp calculation_loop
push_plain_symbol:
mov ebx,[edx+ValueDefinition.value]
push_plain_value:
mov edx,calculation_workspace
mov ecx,2*sizeof.ExpressionTerm
call reserve_workspace
mov esi,edi
mov edx,value_workspace
mov edi,[edx+Workspace.memory_start]
add edi,[value_position]
mov ecx,4+4
call reserve_workspace
xor eax,eax
test ebx,ebx
jz number_length_ok
bsr eax,ebx
inc al
shr al,3
inc al
number_length_ok:
stosd
mov [edi],ebx
add eax,edi
sub eax,[value_workspace.memory_start]
xchg eax,[value_position]
mov edi,esi
mov [edi+ExpressionTerm.attributes],EXPR_NUMBER + EXPRF_VALUE_IN_WORKSPACE
mov [edi+ExpressionTerm.value],eax
xor eax,eax
mov [edi+ExpressionTerm.metadata],eax
mov [edi+sizeof.ExpressionTerm+ExpressionTerm.attributes],eax
add edi,2*sizeof.ExpressionTerm
jmp calculation_loop
push_string:
mov al,EXPR_STRING
push_value:
mov [term_type],al
mov ebx,[edx+ValueDefinition.value]
mov edx,calculation_workspace
mov ecx,2*sizeof.ExpressionTerm
call reserve_workspace
mov [edi+ExpressionTerm.value],ebx
xor eax,eax
mov [edi+ExpressionTerm.metadata],eax
mov [edi+sizeof.ExpressionTerm+ExpressionTerm.attributes],eax
mov al,[term_type]
mov [edi+ExpressionTerm.attributes],eax
add edi,2*sizeof.ExpressionTerm
jmp calculation_loop
push_float:
mov al,EXPR_FLOAT
jmp push_value
push_area:
mov esi,edx
jmp push_variable_term
push_element:
xor esi,esi
push_variable_term:
mov edx,calculation_workspace
mov ecx,3*sizeof.ExpressionTerm
call reserve_workspace
mov eax,EXPR_NUMBER
mov [edi+ExpressionTerm.attributes],eax
mov [edi+ExpressionTerm.metadata],esi
mov [edi+sizeof.ExpressionTerm+ExpressionTerm.attributes],eax
mov [edi+ExpressionTerm.value],zero_value
mov [edi+sizeof.ExpressionTerm+ExpressionTerm.value],singular_value
mov [edi+sizeof.ExpressionTerm+ExpressionTerm.metadata],ebx
and [edi+2*sizeof.ExpressionTerm+ExpressionTerm.attributes],0
add edi,3*sizeof.ExpressionTerm
jmp calculation_loop
base_address_value:
mov edx,[current_area]
area_address_value:
mov ebx,[edx+ValueDefinition.value]
add ebx,sizeof.AreaHeader
push_numeric_value:
mov edx,calculation_workspace
mov ecx,sizeof.ExpressionTerm
call reserve_workspace
mov [edi+ExpressionTerm.attributes],EXPR_NUMBER
mov [edi+ExpressionTerm.value],ebx
and [edi+ExpressionTerm.metadata],0
jmp push_variable_terms
truncated_address_value:
xor esi,esi
jmp push_current_address
current_address_value:
or esi,-1
push_current_address:
mov edx,calculation_workspace
mov ecx,2*sizeof.ExpressionTerm
call reserve_workspace
mov eax,[current_area]
mov ebx,[eax+ValueDefinition.value]
mov ecx,[eax+ValueDefinition.value_length]
sub ecx,[ebx+AreaHeader.base_address_length]
sub ecx,sizeof.AreaHeader
and esi,[ebx+AreaHeader.uninitialized_length]
add ecx,esi
add ebx,sizeof.AreaHeader
mov esi,temporary_value
mov dword [esi],4
mov [esi+4],ecx
mov [edi+ExpressionTerm.attributes],EXPR_NUMBER
mov [edi+ExpressionTerm.value],esi
and [edi+ExpressionTerm.metadata],0
lea esi,[edi+sizeof.ExpressionTerm]
mov [esi+ExpressionTerm.attributes],EXPR_NUMBER
mov [esi+ExpressionTerm.value],ebx
call add_term_values
mov ebx,[esi+ExpressionTerm.value]
push_variable_terms:
mov eax,[ebx]
lea ebx,[ebx+4+eax]
convert_variable_term:
add edi,sizeof.ExpressionTerm
mov edx,calculation_workspace
mov ecx,sizeof.ExpressionTerm
call reserve_workspace
mov eax,[ebx]
test eax,eax
jz variable_terms_converted
mov [edi+ExpressionTerm.metadata],eax
add ebx,4
mov [edi+ExpressionTerm.attributes],EXPR_NUMBER
mov [edi+ExpressionTerm.value],ebx
mov eax,[ebx]
lea ebx,[ebx+4+eax]
jmp convert_variable_term
variable_terms_converted:
mov [edi+ExpressionTerm.attributes],eax
add edi,sizeof.ExpressionTerm
jmp calculation_loop
truncated_position_value:
call prepare_to_push_computed_value
call get_output_length
jmp push_output_position
prepare_to_push_computed_value:
mov edx,calculation_workspace
mov ecx,2*sizeof.ExpressionTerm
call reserve_workspace
mov esi,edi
mov edx,value_workspace
mov edi,[edx+Workspace.memory_start]
add edi,[value_position]
mov ecx,4+8
call reserve_workspace
retn
current_position_value:
call prepare_to_push_computed_value
call get_output_position
push_output_position:
mov edi,[value_workspace.memory_start]
add edi,[value_position]
push_computed_value:
mov ecx,eax
or ecx,edx
jz computed_value_length_ok
bsr ecx,edx
jnz long_computed_value
bsr ecx,eax
inc cl
shr cl,3
inc cl
jmp computed_value_length_ok
long_computed_value:
inc cl
shr cl,3
add cl,1+4
computed_value_length_ok:
mov [edi],ecx
add edi,4
stosd
mov eax,edx
stosd
add ecx,edi
sub ecx,[value_workspace.memory_start]
xchg ecx,[value_position]
mov edi,esi
mov [edi+ExpressionTerm.attributes],EXPR_NUMBER + EXPRF_VALUE_IN_WORKSPACE
mov [edi+ExpressionTerm.value],ecx
xor eax,eax
mov [edi+ExpressionTerm.metadata],eax
mov [edi+sizeof.ExpressionTerm+ExpressionTerm.attributes],eax
add edi,2*sizeof.ExpressionTerm
jmp calculation_loop
current_time_value:
call prepare_to_push_computed_value
call get_timestamp
jmp push_computed_value
current_line_number_value:
call prepare_to_push_computed_value
call get_file_source_entry
mov eax,[ebx+SourceEntry.line_number]
xor edx,edx
jmp push_computed_value
current_file_name_value:
mov edx,calculation_workspace
mov ecx,2*sizeof.ExpressionTerm
call reserve_workspace
push edi
call get_file_source_entry
jmp push_file_name_value
main_file_name_value:
mov edx,calculation_workspace
mov ecx,2*sizeof.ExpressionTerm
call reserve_workspace
push edi
mov ebx,[source_context]
lea ebx,[ebx+sizeof.SourceContext]
push_file_name_value:
mov esi,[ebx+SourceEntry.name]
xor ecx,ecx
cmp [ebx+SourceEntry.type],SOURCE_FILE
jne file_name_length_ok
mov ecx,[ebx+SourceEntry.name_length]
test ecx,ecx
jnz file_name_length_ok
mov edi,esi
xor al,al
dec ecx
repne scasb
add ecx,2
neg ecx
file_name_length_ok:
mov ebx,ecx
add ecx,4
mov edx,value_workspace
mov edi,[edx+Workspace.memory_start]
add edi,[value_position]
call reserve_workspace
mov eax,ebx
stosd
mov ecx,ebx
rep movsb
mov eax,edi
sub eax,[value_workspace.memory_start]
xchg eax,[value_position]
pop edi
mov [edi+ExpressionTerm.attributes],EXPR_STRING + EXPRF_VALUE_IN_WORKSPACE
mov [edi+ExpressionTerm.value],eax
xor eax,eax
mov [edi+ExpressionTerm.metadata],eax
mov [edi+sizeof.ExpressionTerm+ExpressionTerm.attributes],eax
add edi,2*sizeof.ExpressionTerm
jmp calculation_loop
structural_error:
cmp eax,EXPR_MISSING_PARENTHESIS
je expression_missing_parenthesis
invalid_expression:
mov edx,_invalid_expression
call register_error
stc
retn
expression_missing_parenthesis:
mov edx,_missing_closing_parenthesis
call register_error
stc
retn
undefined_symbol_in_expression:
cmp [next_pass_needed],0
jne unknown_result
mov edx,_undefined_symbol
jmp error_causing_unknown_result
invalid_identifier_in_expression:
mov edx,_invalid_identifier
jmp error_causing_unknown_result
invalid_number_in_expression:
mov edx,_invalid_number
jmp error_causing_unknown_result
invalid_symbol_in_expression:
mov edx,_invalid_symbol_value
error_causing_unknown_result:
call register_error
unknown_result:
mov eax,edi
mov edi,[calculation_position]
add edi,[calculation_workspace.memory_start]
cmp edi,eax
jb unknown_result_terms_ready
mov edi,eax
mov edx,calculation_workspace
mov ecx,2*sizeof.ExpressionTerm
call reserve_workspace
xor eax,eax
mov [edi+ExpressionTerm.metadata],eax
mov [edi+sizeof.ExpressionTerm+ExpressionTerm.attributes],eax
unknown_result_terms_ready:
mov [edi+ExpressionTerm.attributes],EXPR_NUMBER
mov [edi+ExpressionTerm.value],zero_value
add edi,2*sizeof.ExpressionTerm
mov esi,[expression_end]
skip_expression:
lodsd
cmp al,EXPR_OPERATOR
je skip_dword
cmp al,EXPR_NUMBER
je skip_dword
cmp al,EXPR_STRING
je skip_dword
cmp al,EXPR_FLOAT
je skip_dword
cmp al,EXPR_SYMBOL
je skip_dword
cmp al,EXPR_SYMBOL_VALUE
je skip_two_dwords
cmp al,EXPR_POLYNOMIAL
je skip_dword
test eax,eax
jnz invalid_expression
inc eax
; clc
retn
skip_two_dwords:
add esi,4
skip_dword:
add esi,4
jmp skip_expression
pop_terms:
; in:
; edi = top of the stack
; out:
; edi = new top of the stack, at the same time a pointer to the first term of retrieved linear polynomial
; cf set when there were no more entries on the stack
; preserves: eax, ebx, ecx, edx, esi
cmp edi,[calculation_workspace.memory_start]
je nothing_to_pop
sub edi,sizeof.ExpressionTerm
find_first_term:
cmp edi,[calculation_workspace.memory_start]
je first_term_found
cmp [edi-sizeof.ExpressionTerm+ExpressionTerm.attributes],0
je first_term_found
sub edi,sizeof.ExpressionTerm
jmp find_first_term
first_term_found:
clc
retn
nothing_to_pop:
and [edi+ExpressionTerm.metadata],0
and [edi+sizeof.ExpressionTerm+ExpressionTerm.attributes],0
mov [edi+ExpressionTerm.attributes],EXPR_NUMBER
mov [edi+ExpressionTerm.value],zero_value
stc
retn
calculate_to_number:
call pop_terms
cmp byte [edi+ExpressionTerm.attributes],EXPR_FLOAT
je single_term_result
make_terms_numeric:
mov eax,[edi+ExpressionTerm.attributes]
test eax,eax
jz all_terms_numeric
call get_numeric_term_value
add edi,sizeof.ExpressionTerm
jmp make_terms_numeric
all_terms_numeric:
add edi,sizeof.ExpressionTerm
jmp calculation_loop
calculate_to_string:
call pop_terms
call get_string_term_value
jmp single_term_result
calculate_to_float:
call pop_terms
call get_float_term_value
jmp single_term_result
extract_integer_part:
call pop_terms
call truncate_term_value
jmp single_term_result
calculate_neg:
call pop_terms
cmp byte [edi+ExpressionTerm.attributes],EXPR_FLOAT
je negate_float_term
call negate_term_value
add edi,sizeof.ExpressionTerm
negate_element_terms:
cmp [edi+ExpressionTerm.attributes],0
je all_terms_negated
cmp [edi+ExpressionTerm.metadata],0
je negate_next_term
call negate_term_value
negate_next_term:
add edi,sizeof.ExpressionTerm
jmp negate_element_terms
all_terms_negated:
add edi,sizeof.ExpressionTerm
jmp calculation_loop
negate_float_term:
call prepare_altered_float_term
xor [ebx+FloatData.attributes],FLOAT_NEGATIVE
single_term_result:
add edi,sizeof.ExpressionTerm
mov eax,edi
call check_for_excess_terms
jnc single_term_result_ok
mov edx,_misused_variable_term
call register_error
single_term_result_ok:
and [edi+ExpressionTerm.attributes],0
add edi,sizeof.ExpressionTerm
jmp calculation_loop
check_for_excess_terms:
cmp [eax+ExpressionTerm.attributes],0
je no_excess_terms
cmp [eax+ExpressionTerm.metadata],0
jne excess_terms
add eax,sizeof.ExpressionTerm
jne check_for_excess_terms
no_excess_terms:
clc
retn
excess_terms:
stc
retn
prepare_altered_float_term:
mov ebx,edi
mov edx,value_workspace
mov edi,[edx+Workspace.memory_start]
add edi,[value_position]
mov ecx,sizeof.FloatData
call reserve_workspace
xchg edi,ebx
call get_term_value
xchg edi,ebx
mov esi,edx
assert sizeof.FloatData and 11b = 0
mov ecx,sizeof.FloatData shr 2
rep movsd
mov eax,edi
sub eax,[value_workspace.memory_start]
xchg eax,[value_position]
sub edi,sizeof.FloatData
xchg edi,ebx
mov [edi+ExpressionTerm.value],eax
or [edi+ExpressionTerm.attributes],EXPRF_VALUE_IN_WORKSPACE
retn
calculate_add:
call pop_terms
mov esi,edi
call pop_terms
cmp byte [esi+ExpressionTerm.attributes],EXPR_FLOAT
je add_float_terms
cmp byte [edi+ExpressionTerm.attributes],EXPR_FLOAT
je add_float_terms
cmp [edi+ExpressionTerm.metadata],0
jne add_constant_terms
mov eax,[esi+ExpressionTerm.metadata]
mov [edi+ExpressionTerm.metadata],eax
add_constant_terms:
call add_term_values
add esi,sizeof.ExpressionTerm
add_variable_terms:
cmp [esi+ExpressionTerm.attributes],0
je all_terms_added
mov eax,[esi+ExpressionTerm.metadata]
test eax,eax
jz add_next_term
push edi
find_element_to_add_to:
add edi,sizeof.ExpressionTerm
cmp [edi+ExpressionTerm.attributes],0
je attach_new_element
cmp eax,[edi+ExpressionTerm.metadata]
jne find_element_to_add_to
push esi
call add_term_values
jnz variable_term_added
and [edi+ExpressionTerm.metadata],0
variable_term_added:
pop esi edi
add_next_term:
add esi,sizeof.ExpressionTerm
jmp add_variable_terms
attach_new_element:
assert sizeof.ExpressionTerm and 11b = 0
mov ecx,sizeof.ExpressionTerm shr 2
rep movsd
and [edi+ExpressionTerm.attributes],0
pop edi
jmp add_variable_terms
all_terms_added:
add edi,sizeof.ExpressionTerm
cmp [edi+ExpressionTerm.attributes],0
jne all_terms_added
add edi,sizeof.ExpressionTerm
jmp calculation_loop
add_float_terms:
mov eax,add_floats
operation_on_float_terms:
push esi edi eax
mov ebx,edi
mov edx,value_workspace
mov edi,[edx+Workspace.memory_start]
add edi,[value_position]
mov ecx,sizeof.FloatData
call reserve_workspace
lea ecx,[edi+sizeof.FloatData]
sub ecx,[edx+Workspace.memory_start]
mov [value_position],ecx
xchg edi,ebx
call get_float_term_value
xchg edi,esi
call get_float_term_value
mov edi,esi
mov esi,edx
call get_term_value
mov edi,ebx
mov ebx,edx
pop eax
call eax
mov ebx,edi
sub ebx,[value_workspace.memory_start]
test [edi+FloatData.attributes],FLOAT_INFINITE or FLOAT_INDETERMINATE or FLOAT_UNDERFLOW
jz operation_on_float_terms_ok
mov edx,_indeterminate_result
call register_error
xor eax,eax
mov [edi+FloatData.attributes],eax
add edi,FloatData.mantissa
mov ecx,MANTISSA_SEGMENTS
rep stosd
operation_on_float_terms_ok:
pop edi esi
mov [edi+ExpressionTerm.value],ebx
mov [edi+ExpressionTerm.attributes],EXPR_FLOAT + EXPRF_VALUE_IN_WORKSPACE
and [edi+ExpressionTerm.metadata],0
finish_calculation_on_single_terms:
add edi,sizeof.ExpressionTerm
mov eax,edi
call check_for_excess_terms
jc single_terms_violation
lea eax,[esi+sizeof.ExpressionTerm]
call check_for_excess_terms
jnc single_terms_ok
single_terms_violation:
mov edx,_misused_variable_term
call register_error
single_terms_ok:
and [edi+ExpressionTerm.attributes],0
add edi,sizeof.ExpressionTerm
jmp calculation_loop
calculate_sub:
call pop_terms
mov esi,edi
call pop_terms
cmp byte [esi+ExpressionTerm.attributes],EXPR_FLOAT
je subtract_float_terms
cmp byte [edi+ExpressionTerm.attributes],EXPR_FLOAT
je subtract_float_terms
cmp [edi+ExpressionTerm.metadata],0
jne subtract_constant_terms
mov eax,[esi+ExpressionTerm.metadata]
mov [edi+ExpressionTerm.metadata],eax
subtract_constant_terms:
call subtract_term_values
add esi,sizeof.ExpressionTerm
subtract_variable_terms:
cmp [esi+ExpressionTerm.attributes],0
je all_terms_subtracted
mov eax,[esi+ExpressionTerm.metadata]
test eax,eax
jz subtract_next_term
push edi
find_element_to_subtract_from:
add edi,sizeof.ExpressionTerm
cmp [edi+ExpressionTerm.attributes],0
je attach_negated_element
cmp eax,[edi+ExpressionTerm.metadata]
jne find_element_to_subtract_from
push esi
call subtract_term_values
jnz variable_term_subtracted
and [edi+ExpressionTerm.metadata],0
variable_term_subtracted:
pop esi edi
subtract_next_term:
add esi,sizeof.ExpressionTerm
jmp subtract_variable_terms
attach_negated_element:
assert sizeof.ExpressionTerm and 11b = 0
mov ecx,sizeof.ExpressionTerm shr 2
rep movsd
sub edi,sizeof.ExpressionTerm
call negate_term_value
add edi,sizeof.ExpressionTerm
and [edi+ExpressionTerm.attributes],0
pop edi
jmp subtract_variable_terms
all_terms_subtracted:
add edi,sizeof.ExpressionTerm
cmp [edi+ExpressionTerm.attributes],0
jne all_terms_subtracted
add edi,sizeof.ExpressionTerm
jmp calculation_loop
subtract_float_terms:
mov eax,subtract_floats
jmp operation_on_float_terms
calculate_mul:
call pop_terms
mov esi,edi
call pop_terms
cmp byte [esi+ExpressionTerm.attributes],EXPR_FLOAT
je multiply_float_terms
cmp byte [edi+ExpressionTerm.attributes],EXPR_FLOAT
je multiply_float_terms
cmp [esi+sizeof.ExpressionTerm+ExpressionTerm.attributes],0
jne multiply_by_destination
multiply_terms:
call multiply_term_values
jnz multiply_next_term
and [edi+ExpressionTerm.metadata],0
multiply_next_term:
add edi,sizeof.ExpressionTerm
cmp [edi+ExpressionTerm.attributes],0
je terms_multiplied
jmp multiply_terms
terms_multiplied:
add edi,sizeof.ExpressionTerm
jmp calculation_loop
multiply_by_destination:
and [esi+ExpressionTerm.metadata],0
cmp [edi+sizeof.ExpressionTerm+ExpressionTerm.attributes],0
je duplicate_destination_constant_term
mov edx,_nonlinear_polynomial
call register_error
duplicate_destination_constant_term:
mov eax,[edi+ExpressionTerm.attributes]
mov edx,[edi+ExpressionTerm.value]
mov [edi+sizeof.ExpressionTerm+ExpressionTerm.attributes],eax
mov [edi+sizeof.ExpressionTerm+ExpressionTerm.value],edx
multiply_source_terms:
mov eax,[esi+ExpressionTerm.metadata]
mov [edi+ExpressionTerm.metadata],eax
call multiply_term_values
jnz multiply_next_source_term
and [edi+ExpressionTerm.metadata],0
multiply_next_source_term:
add esi,sizeof.ExpressionTerm
add edi,sizeof.ExpressionTerm
cmp [esi+ExpressionTerm.attributes],0
je source_terms_multiplied
cmp [esi+sizeof.ExpressionTerm+ExpressionTerm.attributes],0
je multiply_source_terms
jmp duplicate_destination_constant_term
source_terms_multiplied:
and [edi+ExpressionTerm.attributes],0
jmp terms_multiplied
multiply_float_terms:
mov eax,multiply_floats
jmp operation_on_float_terms
calculate_div:
call pop_terms
mov eax,edi
call check_for_excess_terms
jnc divisor_ok
mov edx,_misused_variable_term
call register_error
divisor_ok:
mov esi,edi
call pop_terms
cmp byte [esi+ExpressionTerm.attributes],EXPR_FLOAT
je divide_float_terms
cmp byte [edi+ExpressionTerm.attributes],EXPR_FLOAT
je divide_float_terms
and [edi+ExpressionTerm.metadata],0
mov eax,[esi+ExpressionTerm.attributes]
mov edx,[esi+ExpressionTerm.value]
mov [esi+sizeof.ExpressionTerm+ExpressionTerm.attributes],eax
mov [esi+sizeof.ExpressionTerm+ExpressionTerm.value],edx
call divide_term_values
divide_variable_term:
add edi,sizeof.ExpressionTerm
cmp [edi+ExpressionTerm.attributes],0
je division_done
cmp [edi+ExpressionTerm.metadata],0
je divide_variable_term
mov eax,[esi+sizeof.ExpressionTerm+ExpressionTerm.attributes]
mov edx,[esi+sizeof.ExpressionTerm+ExpressionTerm.value]
mov [esi+ExpressionTerm.attributes],eax
mov [esi+ExpressionTerm.value],edx
call divide_term_values
jz divide_variable_term
mov edx,_subdivided_variable_term
call register_error
jmp divide_variable_term
division_done:
add edi,sizeof.ExpressionTerm
jmp calculation_loop
divide_float_terms:
mov eax,divide_floats
jmp operation_on_float_terms
calculate_mod:
call pop_terms
mov esi,edi
call pop_terms
call divide_term_values
and [esi+ExpressionTerm.metadata],0
assert sizeof.ExpressionTerm and 11b = 0
mov ecx,sizeof.ExpressionTerm shr 2
rep movsd
mov eax,edi
call check_for_excess_terms
jc mod_variable_term
mov eax,esi
call check_for_excess_terms
jnc mod_terms_ok
mod_variable_term:
mov edx,_misused_variable_term
call register_error
mod_terms_ok:
and [edi+ExpressionTerm.attributes],0
add edi,sizeof.ExpressionTerm
jmp calculation_loop
calculate_not:
call pop_terms
call invert_term_value_bits
jmp single_term_result
calculate_xor:
call pop_terms
mov esi,edi
call pop_terms
call bitwise_add_term_values
finish_bitwise_calculation:
cmp [edi+ExpressionTerm.metadata],0
jne finish_calculation_on_single_terms
mov eax,[esi+ExpressionTerm.metadata]
mov [edi+ExpressionTerm.metadata],eax
jmp finish_calculation_on_single_terms
calculate_and:
call pop_terms
mov esi,edi
call pop_terms
call bitwise_multiply_term_values
jmp finish_bitwise_calculation
calculate_or:
call pop_terms
mov esi,edi
call pop_terms
call bitwise_inclusive_or_of_term_values
jmp finish_bitwise_calculation
calculate_shl:
call pop_terms
call get_numeric_term_value
mov ecx,5
call fit_value
js negative_shift_left
jc huge_shift_left
shift_left:
mov esi,edi
check_shift_left_argument:
add edi,sizeof.ExpressionTerm
cmp [edi+ExpressionTerm.attributes],0
je shift_left_argument_ok
cmp [edi+ExpressionTerm.metadata],0
je check_shift_left_argument
mov edx,_misused_variable_term
call register_error
shift_left_argument_ok:
mov edi,esi
call pop_terms
and [edi+ExpressionTerm.metadata],0
cmp byte [edi+ExpressionTerm.attributes],EXPR_FLOAT
je shift_floating_point_left
shift_term_left:
mov eax,[esi]
mov dl,[esi+4]
call shift_term_value_left
shift_variable_term_left:
add edi,sizeof.ExpressionTerm
cmp [edi+ExpressionTerm.attributes],0
je shift_done
cmp [edi+ExpressionTerm.metadata],0
je shift_variable_term_left
jmp shift_term_left
shift_done:
add edi,sizeof.ExpressionTerm
jmp calculation_loop
negative_shift_left:
jc huge_shift_right
not byte [edi+4]
neg dword [edi]
jc shift_right
inc byte [edi+4]
jnz shift_right
huge_shift_right:
or eax,-1
mov [edi],eax
mov [edi+4],al
jmp shift_right
shift_floating_point_left:
push esi
call prepare_altered_float_term
pop esi
xchg esi,ebx
call get_float_unnormalization
jc single_term_result
mov eax,[esi+FloatData.exponent]
cdq
add eax,[ebx]
movzx ebx,byte [ebx+4]
adc ebx,edx
mov [esi+FloatData.exponent],eax
cdq
cmp ebx,edx
jne floating_point_over_boundary
test ecx,ecx
jz single_term_result
push edi
mov edi,esi
and [mantissa_tail],0
call normalize_float
pop edi
jmp single_term_result
floating_point_over_boundary:
jecxz floating_point_out_of_range
test ebx,ebx
jnz floating_point_out_of_range
mov ecx,7FFFFFFFh
sub eax,ecx
mov [esi+FloatData.exponent],ecx
push eax edi
mov edi,esi
and [mantissa_tail],0
call normalize_float
pop edi ecx
mov eax,[esi+FloatData.exponent]
cdq
add eax,ecx
js floating_point_out_of_range
adc edx,0
jnz floating_point_out_of_range
mov [esi+FloatData.exponent],eax
jmp single_term_result
floating_point_out_of_range:
mov edx,_value_out_of_range
call register_error
jmp single_term_result
calculate_shr:
call pop_terms
call get_numeric_term_value
mov ecx,5
call fit_value
js negative_shift_right
jc huge_shift_right
shift_right:
mov esi,edi
check_shift_right_argument:
add edi,sizeof.ExpressionTerm
cmp [edi+ExpressionTerm.attributes],0
je shift_right_argument_ok
cmp [edi+ExpressionTerm.metadata],0
je check_shift_right_argument
mov edx,_misused_variable_term
call register_error
shift_right_argument_ok:
mov edi,esi
call pop_terms
and [edi+ExpressionTerm.metadata],0
cmp byte [edi+ExpressionTerm.attributes],EXPR_FLOAT
je shift_floating_point_right
shift_term_right:
mov eax,[esi]
mov dl,[esi+4]
call shift_term_value_right
shift_variable_term_right:
add edi,sizeof.ExpressionTerm
cmp [edi+ExpressionTerm.attributes],0
je shift_done
cmp [edi+ExpressionTerm.metadata],0
je shift_variable_term_right
call get_term_value
mov ecx,[esi]
mov bl,cl
mov al,[esi+4]
shrd ecx,eax,3
shr al,3
jnz not_exact_shift
cmp ecx,[edx]
jae not_exact_shift
xchg edi,edx
add edi,4
xor al,al
repe scasb
xchg edi,edx
jne not_exact_shift
mov cl,bl
and cl,8-1
jz shift_term_right
mov al,1
shl al,cl
dec al
test [edx],al
jz shift_term_right
not_exact_shift:
mov edx,_subdivided_variable_term
call register_error
jmp shift_variable_term_right
negative_shift_right:
jc huge_shift_left
not byte [edi+4]
neg dword [edi]
jc shift_left
inc byte [edi+4]
jnz shift_left
huge_shift_left:
or eax,-1
mov [edi],eax
mov [edi+4],al
jmp shift_left
shift_floating_point_right:
push esi
call prepare_altered_float_term
pop esi
xchg esi,ebx
call get_float_unnormalization
jc single_term_result
mov eax,[esi+FloatData.exponent]
cdq
sub eax,[ebx]
movzx ecx,byte [ebx+4]
sbb edx,ecx
mov ecx,edx
mov [esi+FloatData.exponent],eax
cdq
cmp ecx,edx
je single_term_result
cmp ecx,-1
jne floating_point_out_of_range
mov [esi+FloatData.exponent],-80000000h
mov ecx,eax
neg ecx
push edi
mov edi,esi
and [mantissa_tail],0
call unnormalize_float
pop edi
mov [esi+FloatData.exponent],-80000000h
call get_float_unnormalization
jc floating_point_out_of_range
jmp single_term_result
calculate_bsf:
call pop_terms
mov esi,edi
mov edi,[value_position]
add edi,[value_workspace.memory_start]
mov ecx,10
mov edx,value_workspace
call reserve_workspace
call find_first_set_bit_in_term_value
jz bit_scan_result_undefined
movzx edx,dl
bit_scan_result_ready:
mov ebx,edi
and dword [edi],0
add edi,4
stosd
mov ax,dx
stosw
mov ecx,6
optimize_result_value:
cmp [edi-1],dh
jne result_value_ready
movsx eax,byte [edi-2]
cmp ah,dh
jne result_value_ready
dec edi
loop optimize_result_value
result_value_ready:
mov [ebx],ecx
sub edi,[value_workspace.memory_start]
mov [value_position],edi
sub ebx,[value_workspace.memory_start]
mov edi,esi
mov [edi+ExpressionTerm.value],ebx
mov [edi+ExpressionTerm.attributes],EXPR_NUMBER + EXPRF_VALUE_IN_WORKSPACE
and [edi+ExpressionTerm.metadata],0
jmp single_term_result
calculate_bsr:
call pop_terms
mov esi,edi
mov edi,[value_position]
add edi,[value_workspace.memory_start]
mov ecx,10
mov edx,value_workspace
call reserve_workspace
cmp byte [esi+ExpressionTerm.attributes],EXPR_FLOAT
je extract_float_exponent
call find_last_set_bit_in_term_value
jc bit_scan_result_undefined
movzx edx,dl
jmp bit_scan_result_ready
bit_scan_result_undefined:
mov edi,esi
mov edx,_indeterminate_result
call register_error
mov [edi+ExpressionTerm.value],zero_value
mov [edi+ExpressionTerm.attributes],EXPR_NUMBER
and [edi+ExpressionTerm.metadata],0
jmp single_term_result
extract_float_exponent:
mov edi,esi
mov [destination_term],edi
call get_term_value
mov esi,edx
call get_float_unnormalization
jc exponent_indeterminate
mov eax,[esi+FloatData.exponent]
cdq
sub eax,ecx
sbb edx,0
exponent_extracted:
mov edi,[value_position]
add edi,[value_workspace.memory_start]
mov esi,[destination_term]
jmp bit_scan_result_ready
exponent_indeterminate:
mov edx,_indeterminate_result
call register_error
xor eax,eax
xor edx,edx
jmp exponent_extracted
calculate_bswap:
call pop_terms
call get_numeric_term_value
mov ecx,4
call fit_value
js bswap_argument_out_of_range
jc bswap_argument_out_of_range
mov esi,edi
mov eax,edi
call check_for_excess_terms
jnc bswap_argument_ok
mov edx,_misused_variable_term
call register_error
bswap_argument_ok:
call pop_terms
and [edi+ExpressionTerm.metadata],0
mov ebx,[esi]
call reverse_term_value_bytes
jmp single_term_result
bswap_argument_out_of_range:
mov edx,_value_out_of_range
call register_error
call pop_terms
jmp single_term_result
calculate_bappend:
call pop_terms
mov [source_term],edi
call pop_terms
mov [destination_term],edi
call get_string_term_value
mov ecx,[edx]
mov edi,[source_term]
call get_string_term_value
add ecx,[edx]
add ecx,4
mov edi,[value_position]
mov edx,value_workspace
add edi,[edx+Workspace.memory_start]
call reserve_workspace
push edi
mov edi,[destination_term]
call get_term_value
mov [edi+ExpressionTerm.attributes],EXPR_STRING + EXPRF_VALUE_IN_WORKSPACE
mov eax,[value_position]
mov [edi+ExpressionTerm.value],eax
pop edi
mov esi,edx
mov ecx,[esi]
movsd
rep movsb
push edi
mov edi,[source_term]
call get_term_value
pop edi
mov esi,edx
lodsd
mov ecx,eax
rep movsb
mov edx,[value_workspace.memory_start]
sub edi,edx
xchg [value_position],edi
add edi,edx
add [edi],eax
mov esi,[source_term]
mov edi,[destination_term]
jmp finish_calculation_on_single_terms
count_bytes:
call pop_terms
call get_string_term_value
mov esi,edi
add esi,sizeof.ExpressionTerm
mov eax,esi
call check_for_excess_terms
mov ebx,[edx]
jnc push_plain_value
mov edx,_misused_variable_term
call register_error
jmp push_plain_value
count_elements:
call pop_terms
mov edx,[edi+ExpressionTerm.metadata]
xor ebx,ebx
mov edx,edi
count_variable_terms:
add edx,sizeof.ExpressionTerm
cmp [edx+ExpressionTerm.attributes],0
je push_plain_value
cmp [edx+ExpressionTerm.metadata],0
je count_variable_terms
inc ebx
jmp count_variable_terms
extract_element_reverse:
xor eax,eax
extract_element:
call get_indexed_term
jc replace_with_zero
jecxz replace_with_constant_unit
mov ebx,[ebx+ExpressionTerm.metadata]
jmp push_element
get_indexed_term:
call pop_terms
mov esi,edi
call pop_terms
mov ebx,edi
test eax,eax
jnz process_term_indexing
xchg ebx,esi
process_term_indexing:
mov edx,esi
check_term_index:
add edx,sizeof.ExpressionTerm
cmp [edx+ExpressionTerm.attributes],0
je term_index_ok
cmp [edx+ExpressionTerm.metadata],0
je check_term_index
mov edx,_misused_variable_term
call register_error
term_index_ok:
push ebx
xchg edi,esi
call get_numeric_term_value
mov ecx,4
call fit_value
xchg esi,edi
pop ebx
js no_such_term
jc no_such_term
xor ecx,ecx
find_indexed_term:
cmp ecx,[esi]
je term_found
find_next_term:
add ebx,sizeof.ExpressionTerm
cmp [ebx+ExpressionTerm.attributes],0
je no_such_term
cmp [ebx+ExpressionTerm.metadata],0
je find_next_term
inc ecx
jmp find_indexed_term
term_found:
clc
retn
no_such_term:
stc
retn
replace_with_constant_unit:
mov edx,singular_value
jmp replace_with_simple_number
replace_with_zero:
mov edx,zero_value
replace_with_simple_number:
mov eax,EXPR_NUMBER
replace_with_simple_constant:
mov [edi+ExpressionTerm.attributes],eax
mov [edi+ExpressionTerm.value],edx
xor eax,eax
mov [edi+ExpressionTerm.metadata],eax
mov [edi+sizeof.ExpressionTerm+ExpressionTerm.attributes],eax
add edi,2*sizeof.ExpressionTerm
jmp calculation_loop
extract_scale_reverse:
xor eax,eax
extract_scale:
call get_indexed_term
jc replace_with_zero
mov eax,[ebx+ExpressionTerm.attributes]
mov edx,[ebx+ExpressionTerm.value]
mov [edi+ExpressionTerm.attributes],eax
mov [edi+ExpressionTerm.value],edx
and [edi+sizeof.ExpressionTerm+ExpressionTerm.attributes],0
add edi,2*sizeof.ExpressionTerm
jmp calculation_loop
extract_metadata_reverse:
xor eax,eax
extract_metadata:
call get_indexed_term
jc replace_with_zero
extract_term_metadata:
mov ebx,[ebx+ExpressionTerm.metadata]
test ebx,ebx
jz replace_with_zero
test ecx,ecx
jz extract_label_metadata
mov edx,[ebx+SymbolTree_Leaf.definition]
test edx,edx
jz replace_with_zero
cmp [edx+ValueDefinition.type],VALTYPE_AREA
je area_address_value
cmp [edx+ValueDefinition.type],VALTYPE_ELEMENT
jne replace_with_zero
mov ecx,[edx+ValueDefinition.value_length]
jecxz replace_with_zero
jmp push_numeric_symbol
extract_size:
call pop_terms
mov ebx,[edi+ExpressionTerm.metadata]
test ebx,ebx
jz replace_with_zero
extract_label_metadata:
cmp dword [ebx],0
jne extract_area_size
add ebx,4
jmp push_numeric_value
extract_area_size:
call prepare_to_push_computed_value
xor edx,edx
mov eax,[ebx+ValueDefinition.value_length]
mov edi,[ebx+ValueDefinition.value]
sub eax,sizeof.AreaHeader
sub eax,[edi+AreaHeader.base_address_length]
add eax,[edi+AreaHeader.uninitialized_length]
adc edx,0
jmp push_output_position
extract_first_term_metadata:
call pop_terms
lea ebx,[edi+sizeof.ExpressionTerm]
mov ecx,1
jmp extract_term_metadata
get_term_value:
; in: edi - ExpressionTerm
; out: edx - 32-bit length followed by data
; preserves: eax, ebx, ecx, esi, edi
mov edx,[edi+ExpressionTerm.value]
test [edi+ExpressionTerm.attributes],EXPRF_VALUE_IN_WORKSPACE
jz value_pointer_ready
add edx,[value_workspace.memory_start]
value_pointer_ready:
retn
get_numeric_term_value:
; in: edi - ExpressionTerm
; out: edx - 32-bit length followed by numeric data
; preserves: ebx, esi, edi
; note:
; term is converted to numeric and the value workspace may be modified in process
; other pointers to term values may become invalidated
mov eax,[edi+ExpressionTerm.attributes]
mov edx,[edi+ExpressionTerm.value]
test eax,EXPRF_VALUE_IN_WORKSPACE
jz convert_to_numeric
add edx,[value_workspace.memory_start]
convert_to_numeric:
cmp al,EXPR_FLOAT
je wrong_numeric_type
cmp al,EXPR_NUMBER
je value_pointer_ready
mov eax,[edx]
test byte [edx+4+eax-1],80h
jnz extend_to_unsigned_value
mov byte [edi+ExpressionTerm.attributes],EXPR_NUMBER
retn
wrong_numeric_type:
mov edx,_invalid_value
call register_error
mov edx,zero_value
mov [edi+ExpressionTerm.value],edx
mov [edi+ExpressionTerm.attributes],EXPR_NUMBER
retn
extend_to_unsigned_value:
push esi edi
mov esi,edi
mov edi,[value_position]
add edi,[value_workspace.memory_start]
mov ecx,[edx]
add ecx,5
mov edx,value_workspace
call reserve_workspace
jnc pointer_for_unsigned_value_ready
mov edi,[value_position]
add edi,[value_workspace.memory_start]
pointer_for_unsigned_value_ready:
mov eax,EXPR_NUMBER + EXPRF_VALUE_IN_WORKSPACE
xchg eax,[esi+ExpressionTerm.attributes]
mov edx,[value_position]
xchg edx,[esi+ExpressionTerm.value]
mov esi,edx
test eax,EXPRF_VALUE_IN_WORKSPACE
jz make_unsigned_value
add esi,[value_workspace.memory_start]
make_unsigned_value:
mov edx,edi
lodsd
stosd
mov ecx,eax
rep movsb
xor al,al
stosb
sub edi,[value_workspace.memory_start]
mov [value_position],edi
inc dword [edx]
pop edi esi
retn
get_string_term_value:
; in: edi - ExpressionTerm
; out: edx - 32-bit length followed by string data
; preserves: ebx, ecx, esi, edi
mov eax,[edi+ExpressionTerm.attributes]
cmp al,EXPR_STRING
je string_value_available
mov byte [edi+ExpressionTerm.attributes],EXPR_STRING
cmp al,EXPR_NUMBER
je string_value_available
mov edx,_invalid_value
call register_error
mov edx,zero_value
mov [edi+ExpressionTerm.value],edx
mov [edi+ExpressionTerm.attributes],EXPR_STRING
retn
string_value_available:
mov edx,[edi+ExpressionTerm.value]
test eax,EXPRF_VALUE_IN_WORKSPACE
jz string_value_pointer_ready
add edx,[value_workspace.memory_start]
string_value_pointer_ready:
retn
get_float_term_value:
; in: edi - ExpressionTerm
; out: edx - FloatData
; preserves: ebx, esi, edi
; note:
; term is converted to float and the value workspace may be modified in process
; other pointers to term values may become invalidated
mov eax,[edi+ExpressionTerm.attributes]
mov edx,[edi+ExpressionTerm.value]
test eax,EXPRF_VALUE_IN_WORKSPACE
jz convert_to_float
add edx,[value_workspace.memory_start]
convert_to_float:
cmp al,EXPR_FLOAT
je value_pointer_ready
cmp al,EXPR_STRING
je convert_positive_to_float
mov eax,[edx]
test byte [edx+4+eax-1],80h
jnz convert_negative_to_float
convert_positive_to_float:
push ebx esi
mov ebx,edi
mov edx,value_workspace
mov edi,[edx+Workspace.memory_start]
add edi,[value_position]
mov ecx,sizeof.FloatData
call reserve_workspace
xchg edi,ebx
call get_term_value
mov esi,edx
lea eax,[ebx+sizeof.FloatData]
sub eax,[value_workspace.memory_start]
xchg eax,[value_position]
mov [edi+ExpressionTerm.value],eax
mov [edi+ExpressionTerm.attributes],EXPR_FLOAT + EXPRF_VALUE_IN_WORKSPACE
push edi
mov edi,ebx
call number_to_float
mov edx,edi
pop edi esi ebx
retn
convert_negative_to_float:
push ebx
call negate_term_value
pop ebx
call convert_positive_to_float
or [edx+FloatData.attributes],FLOAT_NEGATIVE
retn
negate_term_value:
; in:
; edi - ExpressionTerm
; out:
; zf set if result is zero
; preserves: esi, edi
push esi
mov [destination_term],edi
call get_numeric_term_value
mov esi,edx
mov edi,[value_position]
add edi,[value_workspace.memory_start]
mov ecx,[esi]
add ecx,5
mov edx,value_workspace
call reserve_workspace
jnc pointers_ready_for_negation
mov edi,[destination_term]
call get_term_value
mov esi,edx
mov edi,[value_position]
add edi,[value_workspace.memory_start]
pointers_ready_for_negation:
mov edx,[esi]
and edx,not 11b
mov eax,1
xor ecx,ecx
add esi,4
add edi,4
negate_dwords:
cmp ecx,edx
je dwords_negated
mov ebx,[esi+ecx]
not ebx
add eax,ebx
mov [edi+ecx],eax
setc al
movzx eax,al
add ecx,4
jmp negate_dwords
dwords_negated:
mov edx,[esi-4]
negate_bytes:
cmp ecx,edx
je bytes_negated
mov bl,[esi+ecx]
not bl
add al,bl
mov [edi+ecx],al
setc al
inc ecx
jmp negate_bytes
bytes_negated:
movsx ebx,byte [esi+ecx-1]
not bh
add al,bh
mov [edi+ecx],al
pop esi
value_calculated:
jecxz check_for_zero
optimize_value:
movsx edx,byte [edi+ecx-1]
cmp dh,[edi+ecx]
jne value_optimized
loop optimize_value
check_for_zero:
cmp byte [edi],0
je finish_value
value_optimized:
inc ecx
finish_value:
sub edi,4
mov [edi],ecx
value_finished:
mov edx,edi
sub edx,[value_workspace.memory_start]
lea eax,[edx+4+ecx]
mov [value_position],eax
mov edi,[destination_term]
mov [edi+ExpressionTerm.value],edx
mov [edi+ExpressionTerm.attributes],EXPR_NUMBER + EXPRF_VALUE_IN_WORKSPACE
test ecx,ecx
retn
add_term_values:
; in:
; esi - source ExpressionTerm
; edi - destination ExpressionTerm
; out:
; zf set if result is zero
; preserves: esi, edi
call prepare_pointers_for_summation
mov edx,[ebx]
cmp edx,[esi]
jb shorter_addend_selected
mov edx,[esi]
xchg ebx,esi
shorter_addend_selected:
and edx,not 11b
add ebx,4
add esi,4
add edi,4
xor al,al
xor ecx,ecx
add_dwords:
cmp ecx,edx
je dwords_added
neg al
mov eax,[esi+ecx]
adc eax,[ebx+ecx]
mov [edi+ecx],eax
setc al
add ecx,4
jmp add_dwords
dwords_added:
mov edx,[ebx-4]
add_bytes:
cmp ecx,edx
je bytes_added
neg al
mov al,[esi+ecx]
adc al,[ebx+ecx]
mov [edi+ecx],al
setc al
inc ecx
jmp add_bytes
bytes_added:
movsx ebx,byte [ebx+ecx-1]
sar ebx,8
mov edx,[esi-4]
sub edx,ecx
and edx,not 11b
add edx,ecx
carry_dwords:
cmp ecx,edx
je dwords_carried
neg al
mov eax,[esi+ecx]
adc eax,ebx
mov [edi+ecx],eax
setc al
add ecx,4
jmp carry_dwords
dwords_carried:
mov edx,[esi-4]
carry_bytes:
cmp ecx,edx
je bytes_carried
neg al
mov al,[esi+ecx]
adc al,bl
mov [edi+ecx],al
setc al
inc ecx
jmp carry_bytes
bytes_carried:
movsx edx,byte [esi+ecx-1]
neg al
mov al,dh
adc al,bl
mov [edi+ecx],al
mov esi,[source_term]
jmp value_calculated
prepare_pointers_for_summation:
mov [source_term],esi
mov [destination_term],edi
call get_numeric_term_value
mov ebx,[edx]
mov edi,esi
call get_numeric_term_value
mov ecx,[edx]
cmp ecx,ebx
jae sum_length_estimated
mov ecx,ebx
sum_length_estimated:
add ecx,5
mov edi,[value_position]
add edi,[value_workspace.memory_start]
mov edx,value_workspace
call reserve_workspace
mov edi,[destination_term]
call get_term_value
mov ebx,edx
mov edi,esi
call get_term_value
mov esi,edx
mov edi,[value_position]
add edi,[value_workspace.memory_start]
retn
subtract_term_values:
; in:
; esi - source ExpressionTerm
; edi - destination ExpressionTerm
; out:
; zf set if result is zero
; preserves: esi, edi
call prepare_pointers_for_summation
mov edx,[esi]
cmp edx,[ebx]
jb shorter_length_selected
mov edx,[ebx]
shorter_length_selected:
push edx
and edx,not 11b
add ebx,4
add esi,4
add edi,4
xor al,al
xor ecx,ecx
subtract_dwords:
cmp ecx,edx
je dwords_subtracted
neg al
mov eax,[ebx+ecx]
sbb eax,[esi+ecx]
mov [edi+ecx],eax
setc al
add ecx,4
jmp subtract_dwords
dwords_subtracted:
pop edx
subtract_bytes:
cmp ecx,edx
je bytes_subtracted
neg al
mov al,[ebx+ecx]
sbb al,[esi+ecx]
mov [edi+ecx],al
setc al
inc ecx
jmp subtract_bytes
bytes_subtracted:
cmp ecx,[ebx-4]
je minuend_ended
xchg esi,ebx
movsx ebx,byte [ebx+ecx-1]
sar ebx,8
mov edx,[esi-4]
sub edx,ecx
and edx,not 11b
add edx,ecx
borrow_dwords:
cmp ecx,edx
je dwords_borrowed
neg al
mov eax,[esi+ecx]
sbb eax,ebx
mov [edi+ecx],eax
setc al
add ecx,4
jmp borrow_dwords
dwords_borrowed:
mov edx,[esi-4]
borrow_bytes:
cmp ecx,edx
je bytes_borrowed
neg al
mov al,[esi+ecx]
sbb al,bl
mov [edi+ecx],al
setc al
inc ecx
jmp borrow_bytes
bytes_borrowed:
movsx edx,byte [esi+ecx-1]
neg al
mov al,dh
sbb al,bl
mov [edi+ecx],al
mov esi,[source_term]
jmp value_calculated
minuend_ended:
movsx ebx,byte [ebx+ecx-1]
sar ebx,8
mov edx,[esi-4]
sub edx,ecx
and edx,not 11b
add edx,ecx
subtract_supernumerary_dwords:
cmp ecx,edx
je supernumerary_dwords_subtracted
neg al
mov eax,ebx
sbb eax,[esi+ecx]
mov [edi+ecx],eax
setc al
add ecx,4
jmp subtract_supernumerary_dwords
supernumerary_dwords_subtracted:
mov edx,[esi-4]
subtract_supernumerary_bytes:
cmp ecx,edx
je supernumerary_bytes_subtracted
neg al
mov al,bl
sbb al,[esi+ecx]
mov [edi+ecx],al
setc al
inc ecx
jmp subtract_supernumerary_bytes
supernumerary_bytes_subtracted:
movsx edx,byte [esi+ecx-1]
neg al
mov al,bl
sbb al,dh
mov [edi+ecx],al
mov esi,[source_term]
jmp value_calculated
multiply_term_values:
; in:
; esi - source ExpressionTerm
; edi - destination ExpressionTerm
; out:
; zf set if result is zero
; preserves: esi, edi
mov [source_term],esi
mov [destination_term],edi
call get_numeric_term_value
mov edi,multiplier
mov ecx,4
call fit_value
jnc multiply_by_dword
mov edi,esi
call get_numeric_term_value
mov esi,[destination_term]
mov edi,multiplier
mov ecx,4
call fit_value
jnc multiply_by_dword
mov edi,[source_term]
call get_term_value
mov ebx,[edx]
mov edi,[destination_term]
call get_term_value
mov eax,[edx]
mov ecx,ebx
add ecx,eax
cmp ebx,eax
jae split_length_selected
xchg ebx,eax
split_length_selected:
shr ebx,1
add ecx,18
mov edi,[value_position]
add edi,[value_workspace.memory_start]
mov edx,value_workspace
call reserve_workspace
mov eax,edi
mov edi,[source_term]
push edi
call get_term_value
mov edi,eax
mov esi,edx
call split_value
mov eax,edi
mov edi,[destination_term]
push edi
call get_term_value
mov edi,eax
mov esi,edx
call split_value
sub edi,[value_workspace.memory_start]
mov edx,edi
mov edi,[free_temporary_terms]
add [free_temporary_terms],6*sizeof.ExpressionTerm
mov eax,EXPR_NUMBER + EXPRF_VALUE_IN_WORKSPACE
xchg edx,[value_position]
push edx
mov esi,[value_workspace.memory_start]
mov ecx,4
create_temporary_terms:
mov [edi+ExpressionTerm.attributes],eax
mov [edi+ExpressionTerm.value],edx
add edx,[esi+edx]
add edx,4
add edi,sizeof.ExpressionTerm
loop create_temporary_terms
mov ecx,2
duplicate_temporary_terms:
mov [edi+ExpressionTerm.attributes],eax
mov edx,[edi-4*sizeof.ExpressionTerm+ExpressionTerm.value]
mov [edi+ExpressionTerm.value],edx
add edi,sizeof.ExpressionTerm
loop duplicate_temporary_terms
push ebx
sub edi,6*sizeof.ExpressionTerm
lea esi,[edi+2*sizeof.ExpressionTerm]
call multiply_term_values
add esi,sizeof.ExpressionTerm
add edi,sizeof.ExpressionTerm
call multiply_term_values
add edi,sizeof.ExpressionTerm
call add_term_values
add esi,2*sizeof.ExpressionTerm
add edi,2*sizeof.ExpressionTerm
call add_term_values
mov esi,edi
sub edi,2*sizeof.ExpressionTerm
call multiply_term_values
add edi,sizeof.ExpressionTerm
mov eax,[esi-3*sizeof.ExpressionTerm+ExpressionTerm.attributes]
mov edx,[esi-3*sizeof.ExpressionTerm+ExpressionTerm.value]
mov [esi+ExpressionTerm.attributes],eax
mov [esi+ExpressionTerm.value],edx
mov eax,[edi-3*sizeof.ExpressionTerm+ExpressionTerm.attributes]
mov edx,[edi-3*sizeof.ExpressionTerm+ExpressionTerm.value]
mov [edi+ExpressionTerm.attributes],eax
mov [edi+ExpressionTerm.value],edx
call add_term_values
sub edi,sizeof.ExpressionTerm
sub esi,sizeof.ExpressionTerm
call subtract_term_values
mov eax,[esp]
xor dl,dl
shld edx,eax,3
shl eax,3
call shift_term_value_left
mov esi,edi
sub edi,2*sizeof.ExpressionTerm
call add_term_values
mov esi,edi
add edi,sizeof.ExpressionTerm
pop eax
xor dl,dl
shld edx,eax,4
shl eax,4
call shift_term_value_left
pop [value_position]
mov eax,[edi+ExpressionTerm.attributes]
mov edx,[edi+ExpressionTerm.value]
pop edi
mov [edi+ExpressionTerm.attributes],eax
mov [edi+ExpressionTerm.value],edx
call add_term_values
mov [free_temporary_terms],esi
pop esi
test edi,edi
retn
split_value:
cmp ebx,[esi]
jae too_small_to_split
mov eax,ebx
inc eax
stosd
mov ecx,ebx
lodsd
rep movsb
mov ecx,eax
xor al,al
stosb
sub ecx,ebx
mov eax,ecx
stosd
rep movsb
retn
too_small_to_split:
lodsd
mov ecx,eax
stosd
rep movsb
xor eax,eax
stosd
retn
multiply_by_dword:
sets al
mov [multiplier_sign],al
movzx eax,al
or eax,[multiplier]
jz zero_product
mov ebx,esi
mov edi,esi
call get_numeric_term_value
mov esi,edx
mov ecx,[esi]
add ecx,16
mov edi,[value_position]
add edi,[value_workspace.memory_start]
mov edx,value_workspace
call reserve_workspace
jnc pointers_ready_for_multiplication_by_dword
mov edi,ebx
call get_term_value
mov esi,edx
mov edi,[value_position]
add edi,[value_workspace.memory_start]
pointers_ready_for_multiplication_by_dword:
mov eax,[esi]
and eax,not 11b
mov [edi],eax
add esi,4
add edi,4
xor ebx,ebx
xor ecx,ecx
multiply_dwords_by_dword:
cmp ecx,[edi-4]
je dwords_multiplied_by_dword
mov eax,[esi+ecx]
mul [multiplier]
add eax,ebx
adc edx,0
mov ebx,edx
mov [edi+ecx],eax
add ecx,4
jmp multiply_dwords_by_dword
dwords_multiplied_by_dword:
mov edx,[esi-4]
and edx,11b
jz only_sign_in_last_dword
cmp edx,2
jb single_byte_in_last_dword
je two_bytes_in_last_dword
movsx eax,byte [esi+ecx+2]
shl eax,16
mov ax,[esi+ecx]
jmp last_dword_ready
two_bytes_in_last_dword:
movsx eax,word [esi+ecx]
jmp last_dword_ready
single_byte_in_last_dword:
movsx eax,byte [esi+ecx]
jmp last_dword_ready
only_sign_in_last_dword:
movsx eax,byte [esi+ecx-1]
sar eax,8
last_dword_ready:
mov [edi-4],eax
mul [multiplier]
add eax,ebx
adc edx,0
mov [edi+ecx],eax
xor eax,eax
mov ebx,[esi-4]
test byte [esi+ebx-1],80h
jz product_extension
sub edx,[multiplier]
sbb eax,0
product_extension:
mov [edi+ecx+4],edx
add ecx,8
mov [edi+ecx],eax
cmp [multiplier_sign],0
je product_ready
mov edx,[esi-4]
and edx,not 11b
xor ecx,ecx
xor al,al
adjust_product:
cmp ecx,edx
je finish_product_adjustment
neg al
mov eax,[esi+ecx]
sbb [edi+ecx+4],eax
setc al
add ecx,4
jmp adjust_product
finish_product_adjustment:
neg al
mov eax,[edi-4]
cdq
sbb [edi+ecx+4],eax
sbb [edi+ecx+8],edx
add ecx,8
product_ready:
mov esi,[source_term]
jmp value_calculated
zero_product:
; zf already set
mov esi,[source_term]
mov edi,[destination_term]
mov [edi+ExpressionTerm.value],zero_value
mov [edi+ExpressionTerm.attributes],EXPR_NUMBER
retn
divide_term_values:
; in:
; esi - divisor ExpressionTerm, to be replaced with remainder
; edi - dividend ExpressionTerm, to be replaced with quotient
; out:
; zf set if remainder is zero
; preserves: esi, edi
mov [source_term],esi
mov [destination_term],edi
call get_numeric_term_value
mov eax,[edx]
test byte [edx+4+eax-1],80h
jnz negative_dividend
xchg edi,esi
call get_numeric_term_value
mov eax,[edx]
test byte [edx+4+eax-1],80h
jnz negative_divisor
mov edi,divisor
mov ecx,4
call fit_value
jnc divide_by_dword
xor eax,eax
mov ebx,[edx]
find_divisor_length:
mov al,[edx+4+ebx-1]
test al,al
jnz divisor_length_ok
dec ebx
jmp find_divisor_length
divisor_length_ok:
bsr ecx,eax
inc cl
mov [long_divisor_length],ebx
mov [high_bits_count],cl
mov ebx,[edx+4+ebx-5]
shrd ebx,eax,cl
inc ebx
mov [divisor],ebx
mov eax,[source_term]
mov [long_divisor_term],eax
mov eax,[destination_term]
mov [long_dividend_term],eax
mov edi,[free_temporary_terms]
add [free_temporary_terms],4*sizeof.ExpressionTerm
mov [division_temporary_terms],edi
xor eax,eax
mov [edi+ExpressionTerm.attributes],eax
compare_dividend_with_divisor:
mov esi,edx
mov edi,[long_dividend_term]
call get_term_value
xor eax,eax
mov ebx,[edx]
find_dividend_length:
mov al,[edx+4+ebx-1]
test al,al
jnz dividend_length_ok
dec ebx
jmp find_dividend_length
dividend_length_ok:
cmp ebx,[long_divisor_length]
ja long_division
jb dividend_to_remainder
bsr ecx,eax
inc cl
cmp cl,[high_bits_count]
ja long_division
jb dividend_to_remainder
compare_with_divisor_bytes:
mov al,[edx+4+ebx-1]
cmp al,[esi+4+ebx-1]
ja subtract_divisor
jb dividend_to_remainder
dec ebx
jnz compare_with_divisor_bytes
mov esi,[long_divisor_term]
mov edi,[long_dividend_term]
mov eax,EXPR_NUMBER
mov [esi+ExpressionTerm.attributes],eax
mov [esi+ExpressionTerm.value],zero_value
mov [edi+ExpressionTerm.attributes],eax
mov [edi+ExpressionTerm.value],singular_value
jmp accomodate_quotient
dividend_to_remainder:
mov esi,[division_temporary_terms]
mov [free_temporary_terms],esi
mov eax,[esi+ExpressionTerm.attributes]
mov edx,[esi+ExpressionTerm.value]
test eax,eax
jnz quotient_ready
mov eax,EXPR_NUMBER
mov edx,zero_value
quotient_ready:
mov esi,[long_divisor_term]
mov edi,[long_dividend_term]
xchg eax,[edi+ExpressionTerm.attributes]
xchg edx,[edi+ExpressionTerm.value]
mov [esi+ExpressionTerm.attributes],eax
mov [esi+ExpressionTerm.value],edx
jmp test_remainder
subtract_divisor:
mov esi,[long_divisor_term]
mov edi,[long_dividend_term]
call subtract_term_values
mov eax,EXPR_NUMBER
mov edx,singular_value
xchg eax,[edi+ExpressionTerm.attributes]
xchg edx,[edi+ExpressionTerm.value]
mov [esi+ExpressionTerm.attributes],eax
mov [esi+ExpressionTerm.value],edx
accomodate_quotient:
mov esi,[division_temporary_terms]
mov [free_temporary_terms],esi
cmp [esi+ExpressionTerm.attributes],0
je quotient_complete
call add_term_values
quotient_complete:
mov esi,[long_divisor_term]
test_remainder:
cmp dword [esi],0
retn
long_division:
mov edi,[division_temporary_terms]
add edi,sizeof.ExpressionTerm
mov esi,[long_dividend_term]
mov eax,[esi+ExpressionTerm.attributes]
mov edx,[esi+ExpressionTerm.value]
mov [edi+ExpressionTerm.attributes],eax
mov [edi+ExpressionTerm.value],edx
mov ecx,8
cmp [divisor],0
je shift_dividend_right
add cl,32
shift_dividend_right:
xor edx,edx
mov eax,[long_divisor_length]
shld edx,eax,3
shl eax,3
sub cl,[high_bits_count]
sub eax,ecx
sbb edx,0
call shift_term_value_right
cmp [divisor],0
je quotient_approximation_ready
mov esi,edi
mov [destination_term],esi
add edi,sizeof.ExpressionTerm
mov [source_term],edi
call divide_by_dword
quotient_approximation_ready:
mov esi,[division_temporary_terms]
cmp [esi+ExpressionTerm.attributes],0
jne accumulate_quotient
mov eax,[edi+ExpressionTerm.attributes]
mov edx,[edi+ExpressionTerm.value]
mov [esi+ExpressionTerm.attributes],eax
mov [esi+ExpressionTerm.value],edx
jmp calculate_remainder
accumulate_quotient:
xchg esi,edi
call add_term_values
mov edi,esi
calculate_remainder:
mov esi,[long_divisor_term]
call multiply_term_values
mov esi,edi
mov edi,[long_dividend_term]
call subtract_term_values
mov edi,[long_divisor_term]
call get_term_value
jmp compare_dividend_with_divisor
negative_divisor:
call negate_term_value
xchg edi,esi
call divide_term_values
pushf
call negate_term_value
popf
retn
negative_dividend:
call negate_term_value
xchg edi,esi
call get_numeric_term_value
mov eax,[edx]
test byte [edx+4+eax-1],80h
jnz negative_dividend_and_divisor
xchg edi,esi
call divide_term_values
call negate_term_value
jmp negative_remainder
negative_dividend_and_divisor:
call negate_term_value
xchg edi,esi
call divide_term_values
negative_remainder:
xchg edi,esi
call negate_term_value
xchg edi,esi
retn
divide_by_dword:
cmp [divisor],0
je division_by_zero
mov ebx,esi
mov edi,esi
call get_term_value
mov esi,edx
mov ecx,[esi]
add ecx,4+9
mov edi,[value_position]
add edi,[value_workspace.memory_start]
mov edx,value_workspace
call reserve_workspace
jnc pointers_ready_for_division_by_dword
mov edi,ebx
call get_term_value
mov esi,edx
mov edi,[value_position]
add edi,[value_workspace.memory_start]
pointers_ready_for_division_by_dword:
mov eax,[esi]
add esi,4
add edi,4
mov ecx,eax
and ecx,not 11b
xor edx,edx
and eax,11b
jz first_dword_for_division_ready
cmp eax,2
jb single_byte_in_first_dword
je two_bytes_in_first_dword
mov dl,[esi+ecx+2]
shl edx,16
two_bytes_in_first_dword:
mov dh,[esi+ecx+1]
single_byte_in_first_dword:
mov dl,[esi+ecx]
first_dword_for_division_ready:
mov eax,edx
xor edx,edx
div [divisor]
mov [edi+ecx],eax
divide_dwords:
sub ecx,4
jc dwords_divided
mov eax,[esi+ecx]
div [divisor]
mov [edi+ecx],eax
jmp divide_dwords
dwords_divided:
mov ecx,[esi-4]
and ecx,not 11b
add ecx,4
call optimize_positive_value
lea ebx,[edi-4]
mov [ebx],ecx
lea edi,[edi+ecx+4]
mov ecx,5
mov [edi],edx
mov [edi+4],ch
call optimize_positive_value
lea eax,[edi-4]
mov [eax],ecx
sub ebx,[value_workspace.memory_start]
mov edi,[destination_term]
mov [edi+ExpressionTerm.value],ebx
mov [edi+ExpressionTerm.attributes],EXPR_NUMBER + EXPRF_VALUE_IN_WORKSPACE
sub eax,[value_workspace.memory_start]
mov esi,[source_term]
mov [esi+ExpressionTerm.value],eax
mov [esi+ExpressionTerm.attributes],EXPR_NUMBER + EXPRF_VALUE_IN_WORKSPACE
add eax,4
add eax,ecx
mov [value_position],eax
test ecx,ecx
retn
optimize_positive_value:
mov al,[edi+ecx-1]
test al,al
js zero_extension_needed
jnz positive_value_optimized
dec ecx
jnz optimize_positive_value
positive_value_optimized:
retn
zero_extension_needed:
inc ecx
retn
division_by_zero:
mov edx,_indeterminate_result
call register_error
xor eax,eax
jmp zero_product
invert_term_value_bits:
; in:
; edi - ExpressionTerm
; out:
; zf set if result is zero
; preserves: esi, edi
mov [destination_term],edi
call get_numeric_term_value
mov esi,edx
mov edi,[value_position]
add edi,[value_workspace.memory_start]
mov ecx,[esi]
add ecx,4
mov edx,value_workspace
call reserve_workspace
jnc pointers_ready_for_bit_inversion
mov edi,[destination_term]
call get_term_value
mov esi,edx
mov edi,[value_position]
add edi,[value_workspace.memory_start]
pointers_ready_for_bit_inversion:
mov edx,[esi]
xor ecx,ecx
test edx,edx
jz invert_zero
and edx,not 11b
add esi,4
add edi,4
invert_bits_in_dwords:
cmp ecx,edx
je bits_in_dwords_inverted
mov eax,[esi+ecx]
not eax
mov [edi+ecx],eax
add ecx,4
jmp invert_bits_in_dwords
bits_in_dwords_inverted:
mov edx,[esi-4]
invert_bits_in_bytes:
cmp ecx,edx
je bits_in_bytes_inverted
mov al,[esi+ecx]
not al
mov [edi+ecx],al
inc ecx
jmp invert_bits_in_bytes
bits_in_bytes_inverted:
sub edi,4
mov [edi],ecx
jmp value_finished
invert_zero:
inc ecx
mov [edi],ecx
neg cl
mov [edi+4],cl
jmp value_finished
bitwise_add_term_values:
; in:
; esi - source ExpressionTerm
; edi - destination ExpressionTerm
; out:
; zf set if result is zero
; preserves: esi, edi
call set_up_bitwise_operation
jc zero_product
bitwise_add_dwords:
cmp ecx,edx
je dwords_added_bitwise
mov eax,[esi+ecx]
xor eax,[ebx+ecx]
mov [edi+ecx],eax
add ecx,4
jmp bitwise_add_dwords
dwords_added_bitwise:
mov edx,[ebx-4]
bitwise_add_bytes:
cmp ecx,edx
je bytes_added_bitwise
mov al,[esi+ecx]
xor al,[ebx+ecx]
mov [edi+ecx],al
inc ecx
jmp bitwise_add_bytes
bytes_added_bitwise:
movsx ebx,byte [ebx+ecx-1]
sar ebx,8
mov edx,[esi-4]
sub edx,ecx
and edx,not 11b
add edx,ecx
bitwise_add_supernumerary_dwords:
cmp ecx,edx
je supernumerary_dwords_added_bitwise
mov eax,[esi+ecx]
xor eax,ebx
mov [edi+ecx],eax
add ecx,4
jmp bitwise_add_supernumerary_dwords
supernumerary_dwords_added_bitwise:
mov edx,[esi-4]
bitwise_add_supernumerary_bytes:
cmp ecx,edx
je supernumerary_bytes_added_bitwise
mov al,[esi+ecx]
xor al,bl
mov [edi+ecx],al
inc ecx
jmp bitwise_add_supernumerary_bytes
supernumerary_bytes_added_bitwise:
dec ecx
mov esi,[source_term]
jmp value_calculated
set_up_bitwise_operation:
mov [source_term],esi
mov [destination_term],edi
call get_numeric_term_value
mov ebx,[edx]
mov edi,esi
call get_numeric_term_value
mov ecx,[edx]
mov eax,ecx
or eax,ebx
jz bitwise_zero_with_zero
cmp ecx,ebx
jae bitwise_result_length_estimated
mov ecx,ebx
bitwise_result_length_estimated:
add ecx,4
mov edi,[value_position]
add edi,[value_workspace.memory_start]
mov edx,value_workspace
call reserve_workspace
mov edi,[destination_term]
call get_term_value
mov ebx,edx
mov edi,esi
call get_term_value
mov esi,edx
mov edi,[value_position]
add edi,[value_workspace.memory_start]
mov edx,[ebx]
cmp edx,[esi]
jb shorter_value_selected
mov edx,[esi]
xchg ebx,esi
shorter_value_selected:
and edx,not 11b
add ebx,4
add esi,4
add edi,4
xor al,al
xor ecx,ecx
retn
bitwise_zero_with_zero:
stc
retn
bitwise_multiply_term_values:
; in:
; esi - source ExpressionTerm
; edi - destination ExpressionTerm
; out:
; zf set if result is zero
; preserves: esi, edi
call set_up_bitwise_operation
jc zero_product
bitwise_multiply_dwords:
cmp ecx,edx
je dwords_multiplied_bitwise
mov eax,[esi+ecx]
and eax,[ebx+ecx]
mov [edi+ecx],eax
add ecx,4
jmp bitwise_multiply_dwords
dwords_multiplied_bitwise:
mov edx,[ebx-4]
bitwise_multiply_bytes:
cmp ecx,edx
je bytes_multiplied_bitwise
mov al,[esi+ecx]
and al,[ebx+ecx]
mov [edi+ecx],al
inc ecx
jmp bitwise_multiply_bytes
bytes_multiplied_bitwise:
movsx ebx,byte [ebx+ecx-1]
sar ebx,8
mov edx,[esi-4]
sub edx,ecx
and edx,not 11b
add edx,ecx
bitwise_multiply_supernumerary_dwords:
cmp ecx,edx
je supernumerary_dwords_multiplied_bitwise
mov eax,[esi+ecx]
and eax,ebx
mov [edi+ecx],eax
add ecx,4
jmp bitwise_multiply_supernumerary_dwords
supernumerary_dwords_multiplied_bitwise:
mov edx,[esi-4]
bitwise_multiply_supernumerary_bytes:
cmp ecx,edx
je supernumerary_bytes_multiplied_bitwise
mov al,[esi+ecx]
and al,bl
mov [edi+ecx],al
inc ecx
jmp bitwise_multiply_supernumerary_bytes
supernumerary_bytes_multiplied_bitwise:
dec ecx
mov esi,[source_term]
jmp value_calculated
bitwise_inclusive_or_of_term_values:
; in:
; esi - source ExpressionTerm
; edi - destination ExpressionTerm
; out:
; zf set if result is zero
; preserves: esi, edi
call set_up_bitwise_operation
jc zero_product
inclusive_or_of_dwords:
cmp ecx,edx
je performed_inclusive_or_of_dwords
mov eax,[esi+ecx]
or eax,[ebx+ecx]
mov [edi+ecx],eax
add ecx,4
jmp inclusive_or_of_dwords
performed_inclusive_or_of_dwords:
mov edx,[ebx-4]
inclusive_or_of_bytes:
cmp ecx,edx
je performed_inclusive_or_of_bytes
mov al,[esi+ecx]
or al,[ebx+ecx]
mov [edi+ecx],al
inc ecx
jmp inclusive_or_of_bytes
performed_inclusive_or_of_bytes:
movsx ebx,byte [ebx+ecx-1]
sar ebx,8
mov edx,[esi-4]
sub edx,ecx
and edx,not 11b
add edx,ecx
inclusive_or_of_supernumerary_dwords:
cmp ecx,edx
je performed_inclusive_or_of_supernumerary_dwords
mov eax,[esi+ecx]
or eax,ebx
mov [edi+ecx],eax
add ecx,4
jmp inclusive_or_of_supernumerary_dwords
performed_inclusive_or_of_supernumerary_dwords:
mov edx,[esi-4]
inclusive_or_of_supernumerary_bytes:
cmp ecx,edx
je performed_inclusive_or_of_supernumerary_bytes
mov al,[esi+ecx]
or al,bl
mov [edi+ecx],al
inc ecx
jmp inclusive_or_of_supernumerary_bytes
performed_inclusive_or_of_supernumerary_bytes:
dec ecx
mov esi,[source_term]
jmp value_calculated
shift_term_value_left:
; in:
; edi - ExpressionTerm
; dl:eax = number of bits
; out:
; zf set if result is zero
; preserves: esi, edi
mov ebx,eax
and al,8-1
mov [bit_shift],al
shrd ebx,edx,3
shr dl,3
mov [shift_overflow],dl
mov [destination_term],edi
call get_numeric_term_value
mov eax,[edx]
check_for_shifted_zero:
test eax,eax
jz shift_left_ok
cmp byte [edx+4+eax-1],0
jne reserve_memory_for_shift_left
dec eax
jmp check_for_shifted_zero
reserve_memory_for_shift_left:
cmp [shift_overflow],0
jne out_of_memory
push esi
mov esi,edx
mov edi,[value_position]
add edi,[value_workspace.memory_start]
mov ecx,[esi]
add ecx,ebx
jc out_of_memory
add ecx,5
jc out_of_memory
mov edx,value_workspace
call reserve_workspace
jnc pointers_ready_for_shift_left
mov edi,[destination_term]
call get_term_value
mov esi,edx
mov edi,[value_position]
add edi,[value_workspace.memory_start]
pointers_ready_for_shift_left:
add edi,4
mov ecx,ebx
push ecx
xor al,al
rep stosb
mov cl,[bit_shift]
mov edx,[esi]
add esi,4
xor ebx,ebx
shift_bytes_left:
cmp ebx,edx
je bytes_shifted_left
mov ah,[esi+ebx]
shl eax,cl
mov [edi+ebx],ah
mov al,[esi+ebx]
inc ebx
jmp shift_bytes_left
bytes_shifted_left:
movsx eax,byte [esi+ebx-1]
shl eax,cl
mov [edi+ebx],ah
pop ecx
sub edi,ecx
add ecx,ebx
pop esi
jmp value_calculated
shift_left_ok:
retn
shift_term_value_right:
; in:
; edi - ExpressionTerm
; dl:eax = number of bits
; out:
; zf set if result is zero
; preserves: esi, edi
push esi
mov ebx,eax
and al,8-1
mov [bit_shift],al
shrd ebx,edx,3
shr dl,3
jz byte_shift_ok
or ebx,-1
byte_shift_ok:
mov [destination_term],edi
call get_numeric_term_value
mov esi,edx
mov edi,[value_position]
add edi,[value_workspace.memory_start]
mov ecx,[esi]
sub ecx,ebx
jnc size_of_shift_result_estimated
xor ecx,ecx
size_of_shift_result_estimated:
add ecx,5
mov edx,value_workspace
call reserve_workspace
jnc pointers_ready_for_shift_right
mov edi,[destination_term]
call get_term_value
mov esi,edx
mov edi,[value_position]
add edi,[value_workspace.memory_start]
pointers_ready_for_shift_right:
add edi,4
mov cl,[bit_shift]
mov edx,[esi]
sub edx,ebx
jbe value_dissipated
lea esi,[esi+4+ebx]
xor ebx,ebx
shift_bytes_right:
inc ebx
cmp ebx,edx
je bytes_shifted_right
mov ax,[esi+ebx-1]
shr ax,cl
mov [edi+ebx-1],al
jmp shift_bytes_right
bytes_shifted_right:
dec ebx
movsx eax,byte [esi+ebx]
shr eax,cl
mov [edi+ebx],al
mov ecx,ebx
pop esi
jmp value_calculated
value_dissipated:
mov edx,[esi]
movsx eax,byte [esi+4+edx-1]
mov [edi],ah
xor ecx,ecx
pop esi
jmp value_calculated
find_first_set_bit_in_term_value:
; in:
; esi - ExpressionTerm
; out:
; zf set when value is zero
; when zf = 0:
; dl:eax = index of first set bit
; preserves: esi, edi
xchg edi,esi
call get_numeric_term_value
xchg edi,esi
mov ebx,edx
mov edx,[ebx]
and edx,not 11b
xor ecx,ecx
add ebx,4
find_first_set_bit_in_dwords:
cmp ecx,edx
je no_set_bit_found_in_dwords
bsf eax,[ebx+ecx]
jnz first_set_bit_found
add ecx,4
jmp find_first_set_bit_in_dwords
no_set_bit_found_in_dwords:
mov edx,[ebx-4]
find_first_set_bit_in_bytes:
cmp ecx,edx
je no_set_bit_found
movzx eax,byte [ebx+ecx]
bsf eax,eax
jnz first_set_bit_found
inc ecx
jmp find_first_set_bit_in_bytes
no_set_bit_found:
retn
first_set_bit_found:
xor dl,dl
shld edx,ecx,3
shl ecx,3
add eax,ecx
adc dl,0
inc dh
retn
find_last_set_bit_in_term_value:
; in:
; esi - ExpressionTerm
; out:
; cf set when value is zero or negative
; when cf = 0:
; dl:eax = index of last set bit
; preserves: esi, edi
xchg edi,esi
call get_numeric_term_value
xchg edi,esi
mov ebx,edx
mov edx,[ebx]
add ebx,4
test byte [ebx+edx-1],80h
jnz last_set_bit_unreachable
mov ecx,edx
and edx,11b
find_last_set_bit_in_dwords:
cmp ecx,edx
je find_last_set_bit_in_bytes
sub ecx,4
bsr eax,[ebx+ecx]
jnz last_set_bit_found
jmp find_last_set_bit_in_dwords
find_last_set_bit_in_bytes:
jecxz last_set_bit_unreachable
dec ecx
movzx eax,byte [ebx+ecx]
bsr eax,eax
jnz last_set_bit_found
jmp find_last_set_bit_in_bytes
last_set_bit_unreachable:
stc
retn
last_set_bit_found:
xor dl,dl
shld edx,ecx,3
shl ecx,3
add eax,ecx
adc dl,0
; clc
retn
truncate_term_value:
; in:
; edi - ExpressionTerm
; preserves: edi
cmp byte [edi+ExpressionTerm.attributes],EXPR_FLOAT
jne get_numeric_term_value
mov [destination_term],edi
call get_term_value
mov ecx,[edx+FloatData.exponent]
cmp ecx,0
jl no_integer_part
mov esi,edx
mov edi,[value_position]
add edi,[value_workspace.memory_start]
shr ecx,5
lea ecx,[4+(ecx+1)*4]
mov edx,value_workspace
call reserve_workspace
jnc pointers_ready_for_truncation
mov edi,[destination_term]
call get_term_value
mov esi,edx
mov edi,[value_position]
add edi,[value_workspace.memory_start]
pointers_ready_for_truncation:
add edi,4
mov ecx,32*MANTISSA_SEGMENTS
sub ecx,[esi+FloatData.exponent]
jbe integer_precision_loss
dec ecx
mov edx,ecx
and ecx,11111b
shr edx,5
neg edx
add edx,MANTISSA_SEGMENTS
mov ebx,[esi+FloatData.mantissa+(edx-1)*4]
extract_integer_bits:
mov eax,ebx
dec edx
jz extract_highest_integer_bits
mov ebx,[esi+FloatData.mantissa+(edx-1)*4]
shrd eax,ebx,cl
stosd
jmp extract_integer_bits
extract_highest_integer_bits:
shr eax,cl
stosd
integer_part_ready:
and byte [edi],0
dec ecx
sar ecx,3
neg ecx
add ecx,edi
mov edi,[destination_term]
mov [edi+ExpressionTerm.attributes],EXPR_NUMBER + EXPRF_VALUE_IN_WORKSPACE
mov edx,[value_position]
mov [edi+ExpressionTerm.value],edx
sub ecx,[value_workspace.memory_start]
mov [value_position],ecx
sub ecx,edx
sub ecx,4
add edx,[value_workspace.memory_start]
mov [edx],ecx
test [esi+FloatData.attributes],FLOAT_NEGATIVE
jnz negate_term_value
retn
integer_precision_loss:
neg ecx
inc ecx
mov edx,ecx
shr ecx,5
xor eax,eax
rep stosd
mov ecx,edx
and ecx,11111b
mov edx,MANTISSA_SEGMENTS-1
mov eax,[esi+FloatData.mantissa+edx*4]
shl eax,cl
stosd
extract_significant_bits:
mov eax,[esi+FloatData.mantissa+(edx-1)*4]
mov ebx,[esi+FloatData.mantissa+edx*4]
shld eax,ebx,cl
stosd
dec edx
jnz extract_significant_bits
mov eax,[esi+FloatData.mantissa+edx*4]
neg ecx
and ecx,11111b
jnz extract_highest_integer_bits
xor eax,eax
jmp integer_part_ready
no_integer_part:
mov [edi+ExpressionTerm.value],zero_value
mov [edi+ExpressionTerm.attributes],EXPR_NUMBER
retn
reverse_term_value_bytes:
; in:
; edi - ExpressionTerm
; ebx = number of bytes
; preserves: esi, edi
push esi
mov [destination_term],edi
call get_numeric_term_value
mov edi,[value_position]
add edi,[value_workspace.memory_start]
mov ecx,ebx
add ecx,4
mov edx,value_workspace
call reserve_workspace
mov edi,[destination_term]
call get_term_value
mov [edi+ExpressionTerm.attributes],EXPR_STRING + EXPRF_VALUE_IN_WORKSPACE
mov esi,[value_position]
mov [edi+ExpressionTerm.value],esi
lea eax,[esi+4+ebx]
mov [value_position],eax
add esi,[value_workspace.memory_start]
mov [esi],ebx
xor ecx,ecx
test ebx,ebx
jz reversed_bytes_ready
store_reversed_bytes:
cmp ecx,[edx]
jae extend_reversed_bytes
mov al,[edx+4+ecx]
mov [esi+4+ebx-1],al
inc ecx
dec ebx
jnz store_reversed_bytes
reversed_bytes_ready:
cmp ecx,[edx]
jae reversed_bytes_ok
mov al,[edx+4+ecx]
cbw
mov al,ah
lea edi,[edx+4+ecx]
neg ecx
add ecx,[edx]
repe scasb
je reversed_bytes_ok
mov edx,_value_out_of_range
call register_error
jmp reversed_bytes_ok
extend_reversed_bytes:
mov al,[edx+4+ecx-1]
cbw
mov al,ah
lea edi,[esi+4]
mov ecx,ebx
rep stosb
reversed_bytes_ok:
mov edi,[destination_term]
pop esi
retn