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