
; flat assembler core
; Copyright (c) 1999-2021, Tomasz Grysztar.
; All rights reserved.

calculate_expression:
	mov	[current_offset],edi
	mov	[value_undefined],0
	cmp	byte [esi],0
	je	get_string_value
	cmp	byte [esi],'.'
	je	convert_fp
      calculation_loop:
	mov	eax,[tagged_blocks]
	sub	eax,0Ch
	cmp	eax,edi
	jbe	out_of_memory
	lods	byte [esi]
	cmp	al,1
	je	get_byte_number
	cmp	al,2
	je	get_word_number
	cmp	al,4
	je	get_dword_number
	cmp	al,8
	je	get_qword_number
	cmp	al,0Fh
	je	value_out_of_range
	cmp	al,10h
	je	get_register
	cmp	al,11h
	je	get_label
	cmp	al,')'
	je	expression_calculated
	cmp	al,']'
	je	expression_calculated
	cmp	al,'!'
	je	invalid_expression
	sub	edi,14h
	mov	ebx,edi
	sub	ebx,14h
	cmp	al,0F0h
	je	calculate_rva
	cmp	al,0F1h
	je	calculate_plt
	cmp	al,0D0h
	je	calculate_not
	cmp	al,0E0h
	je	calculate_bsf
	cmp	al,0E1h
	je	calculate_bsr
	cmp	al,083h
	je	calculate_neg
	mov	dx,[ebx+8]
	or	dx,[edi+8]
	cmp	al,80h
	je	calculate_add
	cmp	al,81h
	je	calculate_sub
	mov	ah,[ebx+12]
	or	ah,[edi+12]
	jz	absolute_values_calculation
	call	recoverable_misuse
      absolute_values_calculation:
	cmp	al,90h
	je	calculate_mul
	cmp	al,91h
	je	calculate_div
	or	dx,dx
	jnz	invalid_expression
	cmp	al,0A0h
	je	calculate_mod
	cmp	al,0B0h
	je	calculate_and
	cmp	al,0B1h
	je	calculate_or
	cmp	al,0B2h
	je	calculate_xor
	cmp	al,0C0h
	je	calculate_shl
	cmp	al,0C1h
	je	calculate_shr
	jmp	invalid_expression
      expression_calculated:
	sub	edi,14h
	cmp	[value_undefined],0
	je	expression_value_ok
	xor	eax,eax
	mov	[edi],eax
	mov	[edi+4],eax
	mov	[edi+12],eax
      expression_value_ok:
	ret
      get_byte_number:
	xor	eax,eax
	lods	byte [esi]
	stos	dword [edi]
	xor	al,al
	stos	dword [edi]
      got_number:
	and	word [edi-8+8],0
	and	word [edi-8+12],0
	and	dword [edi-8+16],0
	add	edi,0Ch
	jmp	calculation_loop
      get_word_number:
	xor	eax,eax
	lods	word [esi]
	stos	dword [edi]
	xor	ax,ax
	stos	dword [edi]
	jmp	got_number
      get_dword_number:
	movs	dword [edi],[esi]
	xor	eax,eax
	stos	dword [edi]
	jmp	got_number
      get_qword_number:
	movs	dword [edi],[esi]
	movs	dword [edi],[esi]
	jmp	got_number
      get_register:
	mov	byte [edi+9],0
	and	word [edi+12],0
	lods	byte [esi]
	mov	[edi+8],al
	mov	byte [edi+10],1
	xor	eax,eax
	mov	[edi+16],eax
	stos	dword [edi]
	stos	dword [edi]
	add	edi,0Ch
	jmp	calculation_loop
      get_label:
	xor	eax,eax
	mov	[edi+8],eax
	mov	[edi+12],eax
	mov	[edi+20],eax
	lods	dword [esi]
	cmp	eax,0Fh
	jb	predefined_label
	je	reserved_word_used_as_symbol
	mov	ebx,eax
	mov	ax,[current_pass]
	mov	[ebx+18],ax
	mov	cl,[ebx+9]
	shr	cl,1
	and	cl,1
	neg	cl
	or	byte [ebx+8],8
	test	byte [ebx+8],1
	jz	label_undefined
	cmp	ax,[ebx+16]
	je	unadjusted_label
	test	byte [ebx+8],4
	jnz	label_out_of_scope
	test	byte [ebx+9],1
	jz	unadjusted_label
	mov	eax,[ebx]
	sub	eax,dword [adjustment]
	stos	dword [edi]
	mov	eax,[ebx+4]
	sbb	eax,dword [adjustment+4]
	stos	dword [edi]
	sbb	cl,[adjustment_sign]
	mov	[edi-8+13],cl
	mov	eax,dword [adjustment]
	or	al,[adjustment_sign]
	or	eax,dword [adjustment+4]
	jz	got_label
	or	[next_pass_needed],-1
	jmp	got_label
      unadjusted_label:
	mov	eax,[ebx]
	stos	dword [edi]
	mov	eax,[ebx+4]
	stos	dword [edi]
	mov	[edi-8+13],cl
      got_label:
	test	byte [ebx+9],4
	jnz	invalid_use_of_symbol
	call	store_label_reference
	mov	al,[ebx+11]
	mov	[edi-8+12],al
	mov	eax,[ebx+12]
	mov	[edi-8+8],eax
	cmp	al,ah
	jne	labeled_registers_ok
	shr	eax,16
	add	al,ah
	jo	labeled_registers_ok
	xor	ah,ah
	mov	[edi-8+10],ax
	mov	[edi-8+9],ah
      labeled_registers_ok:
	mov	eax,[ebx+20]
	mov	[edi-8+16],eax
	add	edi,0Ch
	mov	al,[ebx+10]
	or	al,al
	jz	calculation_loop
	test	[operand_flags],1
	jnz	calculation_loop
      check_size:
	xchg	[operand_size],al
	or	al,al
	jz	calculation_loop
	cmp	al,[operand_size]
	jne	operand_sizes_do_not_match
	jmp	calculation_loop
      actual_file_offset_label:
	mov	eax,[undefined_data_end]
	mov	ebp,[addressing_space]
	test	byte [ds:ebp+0Ah],1
	jnz	use_undefined_data_offset
	cmp	eax,[current_offset]
	jne	use_current_offset
       use_undefined_data_offset:
	mov	eax,[undefined_data_start]
	jmp	make_file_offset_label
      current_file_offset_label:
	mov	ebp,[addressing_space]
	test	byte [ds:ebp+0Ah],1
	jz	use_current_offset
	mov	eax,[undefined_data_end]
	jmp	make_file_offset_label
       use_current_offset:
	mov	eax,[current_offset]
       make_file_offset_label:
	cmp	[output_format],2
	jae	invalid_use_of_symbol
	sub	eax,[code_start]
	jmp	make_dword_label_value
      current_offset_label:
	mov	eax,[current_offset]
       make_current_offset_label:
	xor	edx,edx
	xor	ch,ch
	mov	ebp,[addressing_space]
	sub	eax,[ds:ebp]
	sbb	edx,[ds:ebp+4]
	sbb	ch,[ds:ebp+8]
	jp	current_offset_label_ok
	call	recoverable_overflow
       current_offset_label_ok:
	stos	dword [edi]
	mov	eax,edx
	stos	dword [edi]
	mov	eax,[ds:ebp+10h]
	stos	dword [edi]
	mov	cl,[ds:ebp+9]
	mov	[edi-12+12],cx
	mov	eax,[ds:ebp+14h]
	mov	[edi-12+16],eax
	add	edi,8
	jmp	calculation_loop
      org_origin_label:
	mov	eax,[addressing_space]
	mov	eax,[eax+18h]
	jmp	make_current_offset_label
      counter_label:
	mov	eax,[counter]
      make_dword_label_value:
	stos	dword [edi]
	xor	eax,eax
	stos	dword [edi]
	add	edi,0Ch
	jmp	calculation_loop
      timestamp_label:
	call	make_timestamp
      make_qword_label_value:
	stos	dword [edi]
	mov	eax,edx
	stos	dword [edi]
	add	edi,0Ch
	jmp	calculation_loop
      predefined_label:
	or	eax,eax
	jz	current_offset_label
	cmp	eax,1
	je	counter_label
	cmp	eax,2
	je	timestamp_label
	cmp	eax,3
	je	org_origin_label
	cmp	eax,4
	je	current_file_offset_label
	cmp	eax,5
	je	actual_file_offset_label
	mov	edx,invalid_value
	jmp	error_undefined
      label_out_of_scope:
	mov	edx,symbol_out_of_scope
	jmp	error_undefined
      label_undefined:
	mov	edx,undefined_symbol
      error_undefined:
	cmp	[current_pass],1
	ja	undefined_value
      force_next_pass:
	or	[next_pass_needed],-1
      undefined_value:
	or	[value_undefined],-1
	and	word [edi+12],0
	xor	eax,eax
	stos	dword [edi]
	stos	dword [edi]
	add	edi,0Ch
	cmp	[error_line],0
	jne	calculation_loop
	mov	eax,[current_line]
	mov	[error_line],eax
	mov	[error],edx
	mov	[error_info],ebx
	jmp	calculation_loop
      calculate_add:
	xor	ah,ah
	mov	ah,[ebx+12]
	mov	al,[edi+12]
	or	al,al
	jz	add_values
	or	ah,ah
	jz	add_relocatable
	add	ah,al
	jnz	invalid_add
	mov	ecx,[edi+16]
	cmp	ecx,[ebx+16]
	je	add_values
      invalid_add:
	call	recoverable_misuse
	jmp	add_values
      add_relocatable:
	mov	ah,al
	mov	ecx,[edi+16]
	mov	[ebx+16],ecx
      add_values:
	mov	[ebx+12],ah
	mov	eax,[edi]
	add	[ebx],eax
	mov	eax,[edi+4]
	adc	[ebx+4],eax
	mov	al,[edi+13]
	adc	[ebx+13],al
	jp	add_sign_ok
	call	recoverable_overflow
      add_sign_ok:
	or	dx,dx
	jz	calculation_loop
	push	esi
	mov	esi,ebx
	mov	cl,[edi+10]
	mov	al,[edi+8]
	call	add_register
	mov	cl,[edi+11]
	mov	al,[edi+9]
	call	add_register
	pop	esi
	jmp	calculation_loop
      add_register:
	or	al,al
	jz	add_register_done
      add_register_start:
	cmp	[esi+8],al
	jne	add_in_second_slot
	add	[esi+10],cl
	jo	value_out_of_range
	jnz	add_register_done
	mov	byte [esi+8],0
	ret
      add_in_second_slot:
	cmp	[esi+9],al
	jne	create_in_first_slot
	add	[esi+11],cl
	jo	value_out_of_range
	jnz	add_register_done
	mov	byte [esi+9],0
	ret
      create_in_first_slot:
	cmp	byte [esi+8],0
	jne	create_in_second_slot
	mov	[esi+8],al
	mov	[esi+10],cl
	ret
      create_in_second_slot:
	cmp	byte [esi+9],0
	jne	invalid_expression
	mov	[esi+9],al
	mov	[esi+11],cl
      add_register_done:
	ret
      out_of_range:
	jmp	calculation_loop
      calculate_sub:
	xor	ah,ah
	mov	ah,[ebx+12]
	mov	al,[edi+12]
	or	al,al
	jz	sub_values
	or	ah,ah
	jz	negate_relocatable
	cmp	al,ah
	jne	invalid_sub
	xor	ah,ah
	mov	ecx,[edi+16]
	cmp	ecx,[ebx+16]
	je	sub_values
      invalid_sub:
	call	recoverable_misuse
	jmp	sub_values
      negate_relocatable:
	neg	al
	mov	ah,al
	mov	ecx,[edi+16]
	mov	[ebx+16],ecx
      sub_values:
	mov	[ebx+12],ah
	mov	eax,[edi]
	sub	[ebx],eax
	mov	eax,[edi+4]
	sbb	[ebx+4],eax
	mov	al,[edi+13]
	sbb	[ebx+13],al
	jp	sub_sign_ok
	cmp	[error_line],0
	jne	sub_sign_ok
	call	recoverable_overflow
      sub_sign_ok:
	or	dx,dx
	jz	calculation_loop
	push	esi
	mov	esi,ebx
	mov	cl,[edi+10]
	mov	al,[edi+8]
	call	sub_register
	mov	cl,[edi+11]
	mov	al,[edi+9]
	call	sub_register
	pop	esi
	jmp	calculation_loop
      sub_register:
	or	al,al
	jz	add_register_done
	neg	cl
	jo	value_out_of_range
	jmp	add_register_start
      calculate_mul:
	or	dx,dx
	jz	mul_start
	cmp	word [ebx+8],0
	jne	mul_start
	xor	ecx,ecx
      swap_values:
	mov	eax,[ebx+ecx]
	xchg	eax,[edi+ecx]
	mov	[ebx+ecx],eax
	add	ecx,4
	cmp	ecx,16
	jb	swap_values
      mul_start:
	push	esi edx
	mov	esi,ebx
	xor	bl,bl
	cmp	byte [esi+13],0
	je	mul_first_sign_ok
	xor	bl,-1
	mov	eax,[esi]
	mov	edx,[esi+4]
	not	eax
	not	edx
	add	eax,1
	adc	edx,0
	mov	[esi],eax
	mov	[esi+4],edx
	or	eax,edx
	jz	mul_overflow
      mul_first_sign_ok:
	cmp	byte [edi+13],0
	je	mul_second_sign_ok
	xor	bl,-1
	cmp	byte [esi+8],0
	je	mul_first_register_sign_ok
	neg	byte [esi+10]
	jo	invalid_expression
      mul_first_register_sign_ok:
	cmp	byte [esi+9],0
	je	mul_second_register_sign_ok
	neg	byte [esi+11]
	jo	invalid_expression
      mul_second_register_sign_ok:
	mov	eax,[edi]
	mov	edx,[edi+4]
	not	eax
	not	edx
	add	eax,1
	adc	edx,0
	mov	[edi],eax
	mov	[edi+4],edx
	or	eax,edx
	jz	mul_overflow
      mul_second_sign_ok:
	cmp	dword [esi+4],0
	jz	mul_numbers
	cmp	dword [edi+4],0
	jz	mul_numbers
	jnz	mul_overflow
      mul_numbers:
	mov	eax,[esi+4]
	mul	dword [edi]
	or	edx,edx
	jnz	mul_overflow
	mov	ecx,eax
	mov	eax,[esi]
	mul	dword [edi+4]
	or	edx,edx
	jnz	mul_overflow
	add	ecx,eax
	jc	mul_overflow
	mov	eax,[esi]
	mul	dword [edi]
	add	edx,ecx
	jc	mul_overflow
	mov	[esi],eax
	mov	[esi+4],edx
	or	bl,bl
	jz	mul_ok
	not	eax
	not	edx
	add	eax,1
	adc	edx,0
	mov	[esi],eax
	mov	[esi+4],edx
	or	eax,edx
	jnz	mul_ok
	not	bl
      mul_ok:
	mov	[esi+13],bl
	pop	edx
	or	dx,dx
	jz	mul_calculated
	cmp	word [edi+8],0
	jne	invalid_value
	cmp	byte [esi+8],0
	je	mul_first_register_ok
	call	get_byte_scale
	imul	byte [esi+10]
	mov	dl,ah
	cbw
	cmp	ah,dl
	jne	value_out_of_range
	mov	[esi+10],al
	or	al,al
	jnz	mul_first_register_ok
	mov	[esi+8],al
      mul_first_register_ok:
	cmp	byte [esi+9],0
	je	mul_calculated
	call	get_byte_scale
	imul	byte [esi+11]
	mov	dl,ah
	cbw
	cmp	ah,dl
	jne	value_out_of_range
	mov	[esi+11],al
	or	al,al
	jnz	mul_calculated
	mov	[esi+9],al
      mul_calculated:
	pop	esi
	jmp	calculation_loop
      mul_overflow:
	pop	edx esi
	call	recoverable_overflow
	jmp	calculation_loop
      get_byte_scale:
	mov	al,[edi]
	cbw
	cwde
	cdq
	cmp	edx,[edi+4]
	jne	value_out_of_range
	cmp	eax,[edi]
	jne	value_out_of_range
	ret
      calculate_div:
	push	esi edx
	mov	esi,ebx
	call	div_64
	pop	edx
	or	dx,dx
	jz	div_calculated
	cmp	byte [esi+8],0
	je	div_first_register_ok
	call	get_byte_scale
	or	al,al
	jz	value_out_of_range
	mov	al,[esi+10]
	cbw
	idiv	byte [edi]
	or	ah,ah
	jnz	invalid_use_of_symbol
	mov	[esi+10],al
      div_first_register_ok:
	cmp	byte [esi+9],0
	je	div_calculated
	call	get_byte_scale
	or	al,al
	jz	value_out_of_range
	mov	al,[esi+11]
	cbw
	idiv	byte [edi]
	or	ah,ah
	jnz	invalid_use_of_symbol
	mov	[esi+11],al
      div_calculated:
	pop	esi
	jmp	calculation_loop
      calculate_mod:
	push	esi
	mov	esi,ebx
	call	div_64
	mov	[esi],eax
	mov	[esi+4],edx
	mov	[esi+13],bh
	pop	esi
	jmp	calculation_loop
      calculate_and:
	mov	eax,[edi]
	mov	edx,[edi+4]
	mov	cl,[edi+13]
	and	[ebx],eax
	and	[ebx+4],edx
	and	[ebx+13],cl
	jmp	calculation_loop
      calculate_or:
	mov	eax,[edi]
	mov	edx,[edi+4]
	mov	cl,[edi+13]
	or	[ebx],eax
	or	[ebx+4],edx
	or	[ebx+13],cl
	jmp	calculation_loop
      calculate_xor:
	mov	eax,[edi]
	mov	edx,[edi+4]
	mov	cl,[edi+13]
	xor	[ebx],eax
	xor	[ebx+4],edx
	xor	[ebx+13],cl
	jmp	calculation_loop
      shr_negative:
	mov	byte [edi+13],0
	not	dword [edi]
	not	dword [edi+4]
	add	dword [edi],1
	adc	dword [edi+4],0
	jc	shl_over
      calculate_shl:
	cmp	byte [edi+13],0
	jne	shl_negative
	mov	edx,[ebx+4]
	mov	eax,[ebx]
	cmp	dword [edi+4],0
	jne	shl_over
	movsx	ecx,byte [ebx+13]
	xchg	ecx,[edi]
	cmp	ecx,64
	je	shl_max
	ja	shl_over
	cmp	ecx,32
	jae	shl_high
	shld	[edi],edx,cl
	shld	edx,eax,cl
	shl	eax,cl
	mov	[ebx],eax
	mov	[ebx+4],edx
	jmp	shl_done
      shl_over:
	cmp	byte [ebx+13],0
	jne	shl_overflow
      shl_max:
	movsx	ecx,byte [ebx+13]
	cmp	eax,ecx
	jne	shl_overflow
	cmp	edx,ecx
	jne	shl_overflow
	xor	eax,eax
	mov	[ebx],eax
	mov	[ebx+4],eax
	jmp	calculation_loop
      shl_high:
	sub	cl,32
	shld	[edi],edx,cl
	shld	edx,eax,cl
	shl	eax,cl
	mov	[ebx+4],eax
	and	dword [ebx],0
	cmp	edx,[edi]
	jne	shl_overflow
      shl_done:
	movsx	eax,byte [ebx+13]
	cmp	eax,[edi]
	je	calculation_loop
      shl_overflow:
	call	recoverable_overflow
	jmp	calculation_loop
      shl_negative:
	mov	byte [edi+13],0
	not	dword [edi]
	not	dword [edi+4]
	add	dword [edi],1
	adc	dword [edi+4],0
	jnc	calculate_shr
	dec	dword [edi+4]
      calculate_shr:
	cmp	byte [edi+13],0
	jne	shr_negative
	mov	edx,[ebx+4]
	mov	eax,[ebx]
	cmp	dword [edi+4],0
	jne	shr_over
	mov	ecx,[edi]
	cmp	ecx,64
	jae	shr_over
	push	esi
	movsx	esi,byte [ebx+13]
	cmp	ecx,32
	jae	shr_high
	shrd	eax,edx,cl
	shrd	edx,esi,cl
	mov	[ebx],eax
	mov	[ebx+4],edx
	pop	esi
	jmp	calculation_loop
      shr_high:
	sub	cl,32
	shrd	edx,esi,cl
	mov	[ebx],edx
	mov	[ebx+4],esi
	pop	esi
	jmp	calculation_loop
      shr_over:
	movsx	eax,byte [ebx+13]
	mov	dword [ebx],eax
	mov	dword [ebx+4],eax
	jmp	calculation_loop
      calculate_not:
	cmp	word [edi+8],0
	jne	invalid_expression
	cmp	byte [edi+12],0
	je	not_ok
	call	recoverable_misuse
      not_ok:
	not	dword [edi]
	not	dword [edi+4]
	not	byte [edi+13]
	add	edi,14h
	jmp	calculation_loop
      calculate_bsf:
	cmp	word [edi+8],0
	jne	invalid_expression
	cmp	byte [edi+12],0
	je	bsf_ok
	call	recoverable_misuse
      bsf_ok:
	xor	ecx,ecx
	bsf	eax,[edi]
	jnz	finish_bs
	mov	ecx,32
	bsf	eax,[edi+4]
	jnz	finish_bs
	cmp	byte [edi+13],0
	jne	finish_bs
      bs_overflow:
	call	recoverable_overflow
	add	edi,14h
	jmp	calculation_loop
      calculate_bsr:
	cmp	word [edi+8],0
	jne	invalid_expression
	cmp	byte [edi+12],0
	je	bsr_ok
	call	recoverable_misuse
      bsr_ok:
	cmp	byte [edi+13],0
	jne	bs_overflow
	mov	ecx,32
	bsr	eax,[edi+4]
	jnz	finish_bs
	xor	ecx,ecx
	bsr	eax,[edi]
	jz	bs_overflow
      finish_bs:
	add	eax,ecx
	xor	edx,edx
	mov	[edi],eax
	mov	[edi+4],edx
	mov	[edi+13],dl
	add	edi,14h
	jmp	calculation_loop
      calculate_neg:
	cmp	byte [edi+8],0
	je	neg_first_register_ok
	neg	byte [edi+10]
	jo	invalid_expression
      neg_first_register_ok:
	cmp	byte [edi+9],0
	je	neg_second_register_ok
	neg	byte [edi+11]
	jo	invalid_expression
      neg_second_register_ok:
	neg	byte [edi+12]
	xor	eax,eax
	xor	edx,edx
	xor	cl,cl
	xchg	eax,[edi]
	xchg	edx,[edi+4]
	xchg	cl,[edi+13]
	sub	[edi],eax
	sbb	[edi+4],edx
	sbb	[edi+13],cl
	jp	neg_sign_ok
	call	recoverable_overflow
      neg_sign_ok:
	add	edi,14h
	jmp	calculation_loop
      calculate_rva:
	cmp	word [edi+8],0
	jne	invalid_expression
	mov	al,[output_format]
	cmp	al,5
	je	calculate_gotoff
	cmp	al,4
	je	calculate_coff_rva
	cmp	al,3
	jne	invalid_expression
	test	[format_flags],8
	jnz	pe64_rva
	mov	al,2
	bt	[resolver_flags],0
	jc	rva_type_ok
	xor	al,al
      rva_type_ok:
	cmp	byte [edi+12],al
	je	rva_ok
	call	recoverable_misuse
      rva_ok:
	mov	byte [edi+12],0
	mov	eax,[code_start]
	mov	eax,[eax+34h]
	xor	edx,edx
      finish_rva:
	sub	[edi],eax
	sbb	[edi+4],edx
	sbb	byte [edi+13],0
	jp	rva_finished
	call	recoverable_overflow
      rva_finished:
	add	edi,14h
	jmp	calculation_loop
      pe64_rva:
	mov	al,4
	bt	[resolver_flags],0
	jc	pe64_rva_type_ok
	xor	al,al
      pe64_rva_type_ok:
	cmp	byte [edi+12],al
	je	pe64_rva_ok
	call	recoverable_misuse
      pe64_rva_ok:
	mov	byte [edi+12],0
	mov	eax,[code_start]
	mov	edx,[eax+34h]
	mov	eax,[eax+30h]
	jmp	finish_rva
      calculate_gotoff:
	test	[format_flags],1
	jnz	calculate_elf_dyn_rva
	test	[format_flags],8
	jnz	invalid_expression
      calculate_coff_rva:
	mov	dl,5
	cmp	byte [edi+12],2
	je	change_value_type
      incorrect_change_of_value_type:
	call	recoverable_misuse
      change_value_type:
	mov	byte [edi+12],dl
	add	edi,14h
	jmp	calculation_loop
      calculate_elf_dyn_rva:
	xor	dl,dl
	test	byte [edi+12],1
	jnz	incorrect_change_of_value_type
	jmp	change_value_type
      calculate_plt:
	cmp	word [edi+8],0
	jne	invalid_expression
	cmp	[output_format],5
	jne	invalid_expression
	test	[format_flags],1
	jnz	invalid_expression
	mov	dl,6
	mov	dh,2
	test	[format_flags],8
	jz	check_value_for_plt
	mov	dh,4
      check_value_for_plt:
	mov	eax,[edi]
	or	eax,[edi+4]
	jnz	incorrect_change_of_value_type
	cmp	byte [edi+12],dh
	jne	incorrect_change_of_value_type
	mov	eax,[edi+16]
	cmp	byte [eax],80h
	jne	incorrect_change_of_value_type
	jmp	change_value_type
      div_64:
	xor	ebx,ebx
	cmp	dword [edi],0
	jne	divider_ok
	cmp	dword [edi+4],0
	jne	divider_ok
	cmp	[next_pass_needed],0
	je	value_out_of_range
	jmp	div_done
      divider_ok:
	cmp	byte [esi+13],0
	je	div_first_sign_ok
	mov	eax,[esi]
	mov	edx,[esi+4]
	not	eax
	not	edx
	add	eax,1
	adc	edx,0
	mov	[esi],eax
	mov	[esi+4],edx
	or	eax,edx
	jz	value_out_of_range
	xor	bx,-1
      div_first_sign_ok:
	cmp	byte [edi+13],0
	je	div_second_sign_ok
	mov	eax,[edi]
	mov	edx,[edi+4]
	not	eax
	not	edx
	add	eax,1
	adc	edx,0
	mov	[edi],eax
	mov	[edi+4],edx
	or	eax,edx
	jz	value_out_of_range
	xor	bl,-1
      div_second_sign_ok:
	cmp	dword [edi+4],0
	jne	div_high
	mov	ecx,[edi]
	mov	eax,[esi+4]
	xor	edx,edx
	div	ecx
	mov	[esi+4],eax
	mov	eax,[esi]
	div	ecx
	mov	[esi],eax
	mov	eax,edx
	xor	edx,edx
	jmp	div_done
      div_high:
	push	ebx
	mov	eax,[esi+4]
	xor	edx,edx
	div	dword [edi+4]
	mov	ebx,[esi]
	mov	[esi],eax
	and	dword [esi+4],0
	mov	ecx,edx
	mul	dword [edi]
      div_high_loop:
	cmp	ecx,edx
	ja	div_high_done
	jb	div_high_large_correction
	cmp	ebx,eax
	jae	div_high_done
      div_high_correction:
	dec	dword [esi]
	sub	eax,[edi]
	sbb	edx,[edi+4]
	jnc	div_high_loop
      div_high_done:
	sub	ebx,eax
	sbb	ecx,edx
	mov	edx,ecx
	mov	eax,ebx
	pop	ebx
	jmp	div_done
      div_high_large_correction:
	push	eax edx
	mov	eax,edx
	sub	eax,ecx
	xor	edx,edx
	div	dword [edi+4]
	shr	eax,1
	jz	div_high_small_correction
	sub	[esi],eax
	push	eax
	mul	dword [edi+4]
	sub	dword [esp+4],eax
	pop	eax
	mul	dword [edi]
	sub	dword [esp+4],eax
	sbb	dword [esp],edx
	pop	edx eax
	jmp	div_high_loop
      div_high_small_correction:
	pop	edx eax
	jmp	div_high_correction
      div_done:
	or	bh,bh
	jz	remainder_ok
	not	eax
	not	edx
	add	eax,1
	adc	edx,0
	mov	ecx,eax
	or	ecx,edx
	jnz	remainder_ok
	not	bh
      remainder_ok:
	or	bl,bl
	jz	div_ok
	not	dword [esi]
	not	dword [esi+4]
	add	dword [esi],1
	adc	dword [esi+4],0
	mov	ecx,[esi]
	or	ecx,[esi+4]
	jnz	div_ok
	not	bl
      div_ok:
	mov	[esi+13],bl
	ret
      store_label_reference:
	cmp	[symbols_file],0
	je	label_reference_ok
	cmp	[next_pass_needed],0
	jne	label_reference_ok
	mov	eax,[tagged_blocks]
	mov	dword [eax-4],2
	mov	dword [eax-8],4
	sub	eax,8+4
	cmp	eax,edi
	jbe	out_of_memory
	mov	[tagged_blocks],eax
	mov	[eax],ebx
      label_reference_ok:
	ret
      convert_fp:
	inc	esi
	and	word [edi+8],0
	and	word [edi+12],0
	mov	al,[value_size]
	cmp	al,2
	je	convert_fp_word
	cmp	al,4
	je	convert_fp_dword
	test	al,not 8
	jz	convert_fp_qword
	call	recoverable_misuse
      convert_fp_qword:
	xor	eax,eax
	xor	edx,edx
	cmp	word [esi+8],8000h
	je	fp_qword_store
	mov	bx,[esi+8]
	mov	eax,[esi]
	mov	edx,[esi+4]
	add	eax,eax
	adc	edx,edx
	mov	ecx,edx
	shr	edx,12
	shrd	eax,ecx,12
	jnc	fp_qword_ok
	add	eax,1
	adc	edx,0
	bt	edx,20
	jnc	fp_qword_ok
	and	edx,1 shl 20 - 1
	inc	bx
	shr	edx,1
	rcr	eax,1
      fp_qword_ok:
	add	bx,3FFh
	cmp	bx,7FFh
	jge	value_out_of_range
	cmp	bx,0
	jg	fp_qword_exp_ok
	or	edx,1 shl 20
	mov	cx,bx
	neg	cx
	inc	cx
	cmp	cx,52+1
	ja	value_out_of_range
	cmp	cx,32
	jb	fp_qword_small_shift
	sub	cx,32
	mov	eax,edx
	xor	edx,edx
	shr	eax,cl
	jmp	fp_qword_shift_done
      fp_qword_small_shift:
	mov	ebx,edx
	shr	edx,cl
	shrd	eax,ebx,cl
      fp_qword_shift_done:
	mov	bx,0
	jnc	fp_qword_exp_ok
	add	eax,1
	adc	edx,0
	test	edx,1 shl 20
	jz	fp_qword_exp_ok
	and	edx,1 shl 20 - 1
	inc	bx
      fp_qword_exp_ok:
	shl	ebx,20
	or	edx,ebx
	jnz	fp_qword_store
	or	eax,eax
	jz	value_out_of_range
      fp_qword_store:
	mov	bl,[esi+11]
	shl	ebx,31
	or	edx,ebx
	mov	[edi],eax
	mov	[edi+4],edx
	add	esi,13
	ret
      convert_fp_word:
	xor	eax,eax
	cmp	word [esi+8],8000h
	je	fp_word_store
	mov	bx,[esi+8]
	mov	ax,[esi+6]
	shl	ax,1
	shr	ax,6
	jnc	fp_word_ok
	inc	ax
	bt	ax,10
	jnc	fp_word_ok
	and	ax,1 shl 10 - 1
	inc	bx
	shr	ax,1
      fp_word_ok:
	add	bx,0Fh
	cmp	bx,01Fh
	jge	value_out_of_range
	cmp	bx,0
	jg	fp_word_exp_ok
	or	ax,1 shl 10
	mov	cx,bx
	neg	cx
	inc	cx
	cmp	cx,10+1
	ja	value_out_of_range
	xor	bx,bx
	shr	ax,cl
	jnc	fp_word_exp_ok
	inc	ax
	test	ax,1 shl 10
	jz	fp_word_exp_ok
	and	ax,1 shl 10 - 1
	inc	bx
      fp_word_exp_ok:
	shl	bx,10
	or	ax,bx
	jz	value_out_of_range
      fp_word_store:
	mov	bl,[esi+11]
	shl	bx,15
	or	ax,bx
	mov	[edi],eax
	xor	eax,eax
	mov	[edi+4],eax
	add	esi,13
	ret
      convert_fp_dword:
	xor	eax,eax
	cmp	word [esi+8],8000h
	je	fp_dword_store
	mov	bx,[esi+8]
	mov	eax,[esi+4]
	shl	eax,1
	shr	eax,9
	jnc	fp_dword_ok
	inc	eax
	bt	eax,23
	jnc	fp_dword_ok
	and	eax,1 shl 23 - 1
	inc	bx
	shr	eax,1
      fp_dword_ok:
	add	bx,7Fh
	cmp	bx,0FFh
	jge	value_out_of_range
	cmp	bx,0
	jg	fp_dword_exp_ok
	or	eax,1 shl 23
	mov	cx,bx
	neg	cx
	inc	cx
	cmp	cx,23+1
	ja	value_out_of_range
	xor	bx,bx
	shr	eax,cl
	jnc	fp_dword_exp_ok
	inc	eax
	test	eax,1 shl 23
	jz	fp_dword_exp_ok
	and	eax,1 shl 23 - 1
	inc	bx
      fp_dword_exp_ok:
	shl	ebx,23
	or	eax,ebx
	jz	value_out_of_range
      fp_dword_store:
	mov	bl,[esi+11]
	shl	ebx,31
	or	eax,ebx
	mov	[edi],eax
	xor	eax,eax
	mov	[edi+4],eax
	add	esi,13
	ret
      get_string_value:
	inc	esi
	lods	dword [esi]
	mov	ecx,eax
	cmp	ecx,8
	ja	value_out_of_range
	mov	edx,edi
	xor	eax,eax
	stos	dword [edi]
	stos	dword [edi]
	mov	edi,edx
	rep	movs byte [edi],[esi]
	mov	edi,edx
	inc	esi
	and	word [edi+8],0
	and	word [edi+12],0
	ret

get_byte_value:
	mov	[value_size],1
	or	[operand_flags],1
	call	calculate_value
	or	al,al
	jz	check_byte_value
	call	recoverable_misuse
      check_byte_value:
	mov	eax,[edi]
	mov	edx,[edi+4]
	cmp	byte [edi+13],0
	je	byte_positive
	cmp	edx,-1
	jne	range_exceeded
	cmp	eax,-100h
	jb	range_exceeded
	ret
      byte_positive:
	test	edx,edx
	jnz	range_exceeded
	cmp	eax,100h
	jae	range_exceeded
      return_byte_value:
	ret
      range_exceeded:
	xor	eax,eax
	xor	edx,edx
      recoverable_overflow:
	cmp	[error_line],0
	jne	ignore_overflow
	push	[current_line]
	pop	[error_line]
	mov	[error],value_out_of_range
	or	[value_undefined],-1
      ignore_overflow:
	ret
      recoverable_misuse:
	cmp	[error_line],0
	jne	ignore_misuse
	push	[current_line]
	pop	[error_line]
	mov	[error],invalid_use_of_symbol
      ignore_misuse:
	ret
get_word_value:
	mov	[value_size],2
	or	[operand_flags],1
	call	calculate_value
	cmp	al,2
	jb	check_word_value
	call	recoverable_misuse
      check_word_value:
	mov	eax,[edi]
	mov	edx,[edi+4]
	cmp	byte [edi+13],0
	je	word_positive
	cmp	edx,-1
	jne	range_exceeded
	cmp	eax,-10000h
	jb	range_exceeded
	ret
      word_positive:
	test	edx,edx
	jnz	range_exceeded
	cmp	eax,10000h
	jae	range_exceeded
	ret
get_dword_value:
	mov	[value_size],4
	or	[operand_flags],1
	call	calculate_value
	cmp	al,4
	jne	check_dword_value
	mov	[value_type],2
	mov	eax,[edi]
	cdq
	cmp	edx,[edi+4]
	jne	range_exceeded
	mov	ecx,edx
	shr	ecx,31
	cmp	cl,[value_sign]
	jne	range_exceeded
	ret
      check_dword_value:
	mov	eax,[edi]
	mov	edx,[edi+4]
	cmp	byte [edi+13],0
	je	dword_positive
	cmp	edx,-1
	jne	range_exceeded
	ret
      dword_positive:
	test	edx,edx
	jne	range_exceeded
	ret
get_pword_value:
	mov	[value_size],6
	or	[operand_flags],1
	call	calculate_value
	cmp	al,4
	jne	check_pword_value
	call	recoverable_misuse
      check_pword_value:
	mov	eax,[edi]
	mov	edx,[edi+4]
	cmp	byte [edi+13],0
	je	pword_positive
	cmp	edx,-10000h
	jb	range_exceeded
	ret
      pword_positive:
	cmp	edx,10000h
	jae	range_exceeded
	ret
get_qword_value:
	mov	[value_size],8
	or	[operand_flags],1
	call	calculate_value
      check_qword_value:
	mov	eax,[edi]
	mov	edx,[edi+4]
	ret
get_count_value:
	mov	[value_size],8
	or	[operand_flags],1
	call	calculate_expression
	cmp	word [edi+8],0
	jne	invalid_value
	mov	[value_sign],0
	mov	al,[edi+12]
	or	al,al
	jz	check_count_value
	call	recoverable_misuse
      check_count_value:
	cmp	byte [edi+13],0
	jne	invalid_count_value
	mov	eax,[edi]
	mov	edx,[edi+4]
	or	edx,edx
	jnz	invalid_count_value
	ret
      invalid_count_value:
	cmp	[error_line],0
	jne	zero_count
	mov	eax,[current_line]
	mov	[error_line],eax
	mov	[error],invalid_value
      zero_count:
	xor	eax,eax
	ret
get_value:
	mov	[operand_size],0
	lods	byte [esi]
	call	get_size_operator
	cmp	al,'('
	jne	invalid_value
	mov	al,[operand_size]
	cmp	al,1
	je	value_byte
	cmp	al,2
	je	value_word
	cmp	al,4
	je	value_dword
	cmp	al,6
	je	value_pword
	cmp	al,8
	je	value_qword
	or	al,al
	jnz	invalid_value
	mov	[value_size],al
	call	calculate_value
	mov	eax,[edi]
	mov	edx,[edi+4]
	ret
      calculate_value:
	call	calculate_expression
	cmp	word [edi+8],0
	jne	invalid_value
	mov	eax,[edi+16]
	mov	[symbol_identifier],eax
	mov	al,[edi+13]
	mov	[value_sign],al
	mov	al,[edi+12]
	mov	[value_type],al
	ret
      value_qword:
	call	get_qword_value
      truncated_value:
	mov	[value_sign],0
	ret
      value_pword:
	call	get_pword_value
	movzx	edx,dx
	jmp	truncated_value
      value_dword:
	call	get_dword_value
	xor	edx,edx
	jmp	truncated_value
      value_word:
	call	get_word_value
	xor	edx,edx
	movzx	eax,ax
	jmp	truncated_value
      value_byte:
	call	get_byte_value
	xor	edx,edx
	movzx	eax,al
	jmp	truncated_value
get_address_word_value:
	mov	[address_size],2
	mov	[value_size],2
	mov	[free_address_range],0
	jmp	calculate_address
get_address_dword_value:
	mov	[address_size],4
	mov	[value_size],4
	mov	[free_address_range],0
	jmp	calculate_address
get_address_qword_value:
	mov	[address_size],8
	mov	[value_size],8
	mov	[free_address_range],0
	jmp	calculate_address
get_address_value:
	mov	[address_size],0
	mov	[value_size],8
	or	[free_address_range],-1
      calculate_address:
	cmp	byte [esi],'.'
	je	invalid_address
	call	calculate_expression
	mov	eax,[edi+16]
	mov	[address_symbol],eax
	mov	al,[edi+13]
	mov	[address_sign],al
	mov	al,[edi+12]
	mov	[value_type],al
	cmp	al,0
	je	address_size_ok
	jg	get_address_symbol_size
	neg	al
      get_address_symbol_size:
	cmp	al,6
	je	special_address_type_32bit
	cmp	al,5
	je	special_address_type_32bit
	ja	invalid_address_type
	test	al,1
	jnz	invalid_address_type
	shl	al,5
	jmp	address_symbol_ok
      invalid_address_type:
	call	recoverable_misuse
      special_address_type_32bit:
	mov	al,40h
      address_symbol_ok:
	mov	ah,[address_size]
	or	[address_size],al
	shr	al,4
	or	ah,ah
	jz	address_size_ok
	cmp	al,ah
	je	address_size_ok
	cmp	ax,0408h
	je	address_sizes_mixed
	cmp	ax,0804h
	jne	address_sizes_do_not_agree
      address_sizes_mixed:
	cmp	[value_type],4
	jne	address_sizes_mixed_type_ok
	mov	[value_type],2
      address_sizes_mixed_type_ok:
	mov	eax,[edi]
	cdq
	cmp	edx,[edi+4]
	je	address_size_ok
	cmp	[error_line],0
	jne	address_size_ok
	call	recoverable_overflow
      address_size_ok:
	xor	ebx,ebx
	xor	ecx,ecx
	mov	cl,[value_type]
	shl	ecx,16
	mov	ch,[address_size]
	cmp	word [edi+8],0
	je	check_immediate_address
	mov	al,[edi+8]
	mov	dl,[edi+10]
	call	get_address_register
	mov	al,[edi+9]
	mov	dl,[edi+11]
	call	get_address_register
	mov	ax,bx
	shr	ah,4
	shr	al,4
	or	bh,bh
	jz	check_address_registers
	or	bl,bl
	jz	check_address_registers
	cmp	al,ah
	jne	check_vsib
      check_address_registers:
	or	al,ah
	cmp	al,0Ch
	jae	check_vsib
	cmp	al,6
	je	check_vsib
	cmp	al,7
	je	check_vsib
	mov	ah,[address_size]
	and	ah,0Fh
	jz	address_registers_sizes_ok
	cmp	al,ah
	jne	invalid_address
      address_registers_sizes_ok:
	cmp	al,4
	je	sib_allowed
	cmp	al,8
	je	sib_allowed
	cmp	al,9
	je	check_ip_relative_address
	cmp	cl,1
	ja	invalid_address
	cmp	[free_address_range],0
	jne	check_qword_value
	jmp	check_word_value
      address_sizes_do_not_match:
	cmp	al,0Fh
	jne	invalid_address
	mov	al,bh
	and	al,0Fh
	cmp	al,ah
	jne	invalid_address
      check_ip_relative_address:
	or	bl,bl
	jnz	invalid_address
	cmp	bh,98h
	je	check_rip_relative_address
	cmp	bh,94h
	jne	invalid_address
	cmp	[free_address_range],0
	je	check_dword_value
	mov	eax,[edi]
	mov	edx,[edi+4]
	ret
      check_rip_relative_address:
	mov	eax,[edi]
	cdq
	cmp	edx,[edi+4]
	jne	range_exceeded
	cmp	dl,[edi+13]
	jne	range_exceeded
	ret
      get_address_register:
	or	al,al
	jz	address_register_ok
	cmp	dl,1
	jne	scaled_register
	or	bh,bh
	jnz	scaled_register
	mov	bh,al
      address_register_ok:
	ret
      scaled_register:
	or	bl,bl
	jnz	invalid_address
	mov	bl,al
	mov	cl,dl
	jmp	address_register_ok
      sib_allowed:
	or	bh,bh
	jnz	check_index_with_base
	cmp	cl,3
	je	special_index_scale
	cmp	cl,5
	je	special_index_scale
	cmp	cl,9
	je	special_index_scale
	cmp	cl,2
	jne	check_index_scale
	cmp	bl,45h
	jne	special_index_scale
	cmp	[code_type],64
	je	special_index_scale
	cmp	[segment_register],4
	jne	special_index_scale
	cmp	[value_type],0
	jne	check_index_scale
	mov	al,[edi]
	cbw
	cwde
	cmp	eax,[edi]
	jne	check_index_scale
	cdq
	cmp	edx,[edi+4]
	jne	check_immediate_address
      special_index_scale:
	mov	bh,bl
	dec	cl
      check_immediate_address:
	cmp	[free_address_range],0
	jne	check_qword_value
	mov	al,[address_size]
	and	al,0Fh
	cmp	al,2
	je	check_word_value
	cmp	al,4
	je	check_dword_value
	cmp	al,8
	je	check_qword_value
	or	al,al
	jnz	invalid_value
	cmp	[code_type],64
	jne	check_dword_value
	jmp	check_qword_value
      check_index_with_base:
	cmp	cl,1
	jne	check_index_scale
	cmp	bl,44h
	je	swap_base_with_index
	cmp	bl,84h
	je	swap_base_with_index
	cmp	[code_type],64
	je	check_for_rbp_base
	cmp	bl,45h
	jne	check_for_ebp_base
	cmp	[segment_register],3
	je	swap_base_with_index
	jmp	check_immediate_address
      check_for_ebp_base:
	cmp	bh,45h
	jne	check_immediate_address
	cmp	[segment_register],4
	jne	check_immediate_address
      swap_base_with_index:
	xchg	bl,bh
	jmp	check_immediate_address
      check_for_rbp_base:
	cmp	bh,45h
	je	swap_base_with_index
	cmp	bh,85h
	je	swap_base_with_index
	jmp	check_immediate_address
      check_index_scale:
	test	cl,not 1111b
	jnz	invalid_address
	mov	al,cl
	dec	al
	and	al,cl
	jz	check_immediate_address
	jmp	invalid_address
      check_vsib:
	xor	ah,ah
      check_vsib_base:
	test	bh,bh
	jz	check_vsib_index
	mov	al,bh
	shr	al,4
	cmp	al,4
	je	check_vsib_base_size
	cmp	[code_type],64
	jne	swap_vsib_registers
	cmp	al,8
	jne	swap_vsib_registers
      check_vsib_base_size:
	mov	ah,[address_size]
	and	ah,0Fh
	jz	check_vsib_index
	cmp	al,ah
	jne	invalid_address
      check_vsib_index:
	mov	al,bl
	and	al,0E0h
	cmp	al,0C0h
	jae	check_index_scale
	cmp	al,60h
	je	check_index_scale
	jmp	invalid_address
      swap_vsib_registers:
	xor	ah,-1
	jz	invalid_address
	cmp	cl,1
	ja	invalid_address
	xchg	bl,bh
	mov	cl,1
	jmp	check_vsib_base

calculate_relative_offset:
	cmp	[value_undefined],0
	jne	relative_offset_ok
	test	bh,bh
	setne	ch
	cmp	bx,[ds:ebp+10h]
	je	origin_registers_ok
	xchg	bh,bl
	xchg	ch,cl
	cmp	bx,[ds:ebp+10h]
	jne	invalid_value
      origin_registers_ok:
	cmp	cx,[ds:ebp+10h+2]
	jne	invalid_value
	mov	bl,[address_sign]
	add	eax,[ds:ebp]
	adc	edx,[ds:ebp+4]
	adc	bl,[ds:ebp+8]
	sub	eax,edi
	sbb	edx,0
	sbb	bl,0
	mov	[value_sign],bl
	mov	bl,[value_type]
	mov	ecx,[address_symbol]
	mov	[symbol_identifier],ecx
	test	bl,1
	jnz	relative_offset_unallowed
	cmp	bl,6
	je	plt_relative_offset
	mov	bh,[ds:ebp+9]
	cmp	bl,bh
	je	set_relative_offset_type
	cmp	bx,0402h
	je	set_relative_offset_type
      relative_offset_unallowed:
	call	recoverable_misuse
      set_relative_offset_type:
	cmp	[value_type],0
	je	relative_offset_ok
	mov	[value_type],0
	cmp	ecx,[ds:ebp+14h]
	je	relative_offset_ok
	mov	[value_type],3
      relative_offset_ok:
	ret
      plt_relative_offset:
	mov	[value_type],7
	cmp	byte [ds:ebp+9],2
	je	relative_offset_ok
	cmp	byte [ds:ebp+9],4
	jne	recoverable_misuse
	ret

calculate_logical_expression:
	xor	al,al
  calculate_embedded_logical_expression:
	mov	[logical_value_wrapping],al
	call	get_logical_value
      logical_loop:
	cmp	byte [esi],'|'
	je	logical_or
	cmp	byte [esi],'&'
	je	logical_and
	ret
      logical_or:
	inc	esi
	or	al,al
	jnz	logical_value_already_determined
	push	eax
	call	get_logical_value
	pop	ebx
	or	al,bl
	jmp	logical_loop
      logical_and:
	inc	esi
	or	al,al
	jz	logical_value_already_determined
	push	eax
	call	get_logical_value
	pop	ebx
	and	al,bl
	jmp	logical_loop
      logical_value_already_determined:
	push	eax
	call	skip_logical_value
	jc	invalid_expression
	pop	eax
	jmp	logical_loop
  get_value_for_comparison:
	mov	[value_size],8
	or	[operand_flags],1
	lods	byte [esi]
	call	calculate_expression
	cmp	byte [edi+8],0
	jne	first_register_size_ok
	mov	byte [edi+10],0
      first_register_size_ok:
	cmp	byte [edi+9],0
	jne	second_register_size_ok
	mov	byte [edi+11],0
      second_register_size_ok:
	mov	eax,[edi+16]
	mov	[symbol_identifier],eax
	mov	al,[edi+13]
	mov	[value_sign],al
	mov	bl,[edi+12]
	mov	eax,[edi]
	mov	edx,[edi+4]
	mov	ecx,[edi+8]
	ret
  get_logical_value:
	xor	al,al
      check_for_negation:
	cmp	byte [esi],'~'
	jne	negation_ok
	inc	esi
	xor	al,-1
	jmp	check_for_negation
      negation_ok:
	push	eax
	mov	al,[esi]
	cmp	al,91h
	je	logical_expression
	cmp	al,0FFh
	je	invalid_expression
	cmp	al,88h
	je	check_for_defined
	cmp	al,8Ah
	je	check_for_earlier_defined
	cmp	al,89h
	je	check_for_used
	cmp	al,'0'
	je	given_false
	cmp	al,'1'
	je	given_true
	cmp	al,'('
	jne	invalid_value
	call	get_value_for_comparison
	mov	bh,[value_sign]
	push	eax edx
	push	[symbol_identifier]
	push	ebx ecx
	mov	al,[esi]
	or	al,al
	jz	logical_number
	cmp	al,0Fh
	je	logical_number
	cmp	al,92h
	je	logical_number
	cmp	al,'&'
	je	logical_number
	cmp	al,'|'
	je	logical_number
	inc	esi
	mov	[compare_type],al
	cmp	byte [esi],'('
	jne	invalid_value
	call	get_value_for_comparison
	cmp	bl,[esp+4]
	jne	values_not_relative
	or	bl,bl
	jz	check_values_registers
	mov	ebx,[symbol_identifier]
	cmp	ebx,[esp+8]
	jne	values_not_relative
      check_values_registers:
	cmp	ecx,[esp]
	je	values_relative
	ror	ecx,16
	xchg	ch,cl
	ror	ecx,16
	xchg	ch,cl
	cmp	ecx,[esp]
	je	values_relative
      values_not_relative:
	cmp	[compare_type],0F8h
	jne	invalid_comparison
	add	esp,12+8
	jmp	return_false
      invalid_comparison:
	call	recoverable_misuse
      values_relative:
	pop	ebx
	shl	ebx,16
	mov	bx,[esp]
	add	esp,8
	pop	ecx ebp
	cmp	[compare_type],'='
	je	check_equal
	cmp	[compare_type],0F1h
	je	check_not_equal
	cmp	[compare_type],0F8h
	je	return_true
	test	ebx,0FFFF0000h
	jz	check_less_or_greater
	call	recoverable_misuse
      check_less_or_greater:
	cmp	[compare_type],'>'
	je	check_greater
	cmp	[compare_type],'<'
	je	check_less
	cmp	[compare_type],0F2h
	je	check_not_less
	cmp	[compare_type],0F3h
	je	check_not_greater
	jmp	invalid_expression
      check_equal:
	cmp	bh,[value_sign]
	jne	return_false
	cmp	eax,ebp
	jne	return_false
	cmp	edx,ecx
	jne	return_false
	jmp	return_true
      check_greater:
	cmp	bh,[value_sign]
	jg	return_true
	jl	return_false
	cmp	edx,ecx
	jb	return_true
	ja	return_false
	cmp	eax,ebp
	jb	return_true
	jae	return_false
      check_less:
	cmp	bh,[value_sign]
	jg	return_false
	jl	return_true
	cmp	edx,ecx
	jb	return_false
	ja	return_true
	cmp	eax,ebp
	jbe	return_false
	ja	return_true
      check_not_less:
	cmp	bh,[value_sign]
	jg	return_true
	jl	return_false
	cmp	edx,ecx
	jb	return_true
	ja	return_false
	cmp	eax,ebp
	jbe	return_true
	ja	return_false
      check_not_greater:
	cmp	bh,[value_sign]
	jg	return_false
	jl	return_true
	cmp	edx,ecx
	jb	return_false
	ja	return_true
	cmp	eax,ebp
	jb	return_false
	jae	return_true
      check_not_equal:
	cmp	bh,[value_sign]
	jne	return_true
	cmp	eax,ebp
	jne	return_true
	cmp	edx,ecx
	jne	return_true
	jmp	return_false
      logical_number:
	pop	ecx ebx eax edx eax
	or	bl,bl
	jnz	invalid_logical_number
	or	cx,cx
	jz	logical_number_ok
      invalid_logical_number:
	call	recoverable_misuse
      logical_number_ok:
	test	bh,bh
	jnz	return_true
	or	eax,edx
	jnz	return_true
	jmp	return_false
      check_for_earlier_defined:
	or	bh,-1
	jmp	check_if_expression_defined
      check_for_defined:
	xor	bh,bh
      check_if_expression_defined:
	or	bl,-1
	lods	word [esi]
	cmp	ah,'('
	jne	invalid_expression
      check_expression:
	lods	byte [esi]
	or	al,al
	jz	defined_string
	cmp	al,'.'
	je	defined_fp_value
	cmp	al,')'
	je	expression_checked
	cmp	al,'!'
	je	invalid_expression
	cmp	al,0Fh
	je	check_expression
	cmp	al,10h
	je	defined_register
	cmp	al,11h
	je	check_if_symbol_defined
	cmp	al,80h
	jae	check_expression
	movzx	eax,al
	add	esi,eax
	jmp	check_expression
      defined_register:
	inc	esi
	jmp	check_expression
      defined_fp_value:
	add	esi,12+1
	jmp	expression_checked
      defined_string:
	lods	dword [esi]
	add	esi,eax
	inc	esi
	jmp	expression_checked
      check_if_symbol_defined:
	lods	dword [esi]
	cmp	eax,-1
	je	invalid_expression
	cmp	eax,0Fh
	jb	check_expression
	je	reserved_word_used_as_symbol
	test	bh,bh
	jnz	no_prediction
	test	byte [eax+8],4
	jnz	no_prediction
	test	byte [eax+8],1
	jz	symbol_predicted_undefined
	mov	cx,[current_pass]
	sub	cx,[eax+16]
	jz	check_expression
	cmp	cx,1
	ja	symbol_predicted_undefined
	or	byte [eax+8],40h+80h
	jmp	check_expression
      no_prediction:
	test	byte [eax+8],1
	jz	symbol_undefined
	mov	cx,[current_pass]
	sub	cx,[eax+16]
	jz	check_expression
	jmp	symbol_undefined
      symbol_predicted_undefined:
	or	byte [eax+8],40h
	and	byte [eax+8],not 80h
      symbol_undefined:
	xor	bl,bl
	jmp	check_expression
      expression_checked:
	mov	al,bl
	jmp	logical_value_ok
      check_for_used:
	lods	word [esi]
	cmp	ah,2
	jne	invalid_expression
	lods	dword [esi]
	cmp	eax,0Fh
	jb	invalid_use_of_symbol
	je	reserved_word_used_as_symbol
	inc	esi
	test	byte [eax+8],8
	jz	not_used
	mov	cx,[current_pass]
	sub	cx,[eax+18]
	jz	return_true
	cmp	cx,1
	ja	not_used
	or	byte [eax+8],10h+20h
	jmp	return_true
      not_used:
	or	byte [eax+8],10h
	and	byte [eax+8],not 20h
	jmp	return_false
      given_false:
	inc	esi
      return_false:
	xor	al,al
	jmp	logical_value_ok
      given_true:
	inc	esi
      return_true:
	or	al,-1
	jmp	logical_value_ok
      logical_expression:
	lods	byte [esi]
	mov	dl,[logical_value_wrapping]
	push	edx
	call	calculate_embedded_logical_expression
	pop	edx
	mov	[logical_value_wrapping],dl
	push	eax
	lods	byte [esi]
	cmp	al,92h
	jne	invalid_expression
	pop	eax
      logical_value_ok:
	pop	ebx
	xor	al,bl
	ret

skip_symbol:
	lods	byte [esi]
	or	al,al
	jz	nothing_to_skip
	cmp	al,0Fh
	je	nothing_to_skip
	cmp	al,1
	je	skip_instruction
	cmp	al,2
	je	skip_label
	cmp	al,3
	je	skip_label
	cmp	al,4
	je	skip_special_label
	cmp	al,20h
	jb	skip_assembler_symbol
	cmp	al,'('
	je	skip_expression
	cmp	al,'['
	je	skip_address
      skip_done:
	clc
	ret
      skip_label:
	add	esi,2
      skip_instruction:
	add	esi,2
      skip_assembler_symbol:
	inc	esi
	jmp	skip_done
      skip_special_label:
	add	esi,4
	jmp	skip_done
      skip_address:
	mov	al,[esi]
	and	al,11110000b
	cmp	al,60h
	jb	skip_expression
	cmp	al,70h
	ja	skip_expression
	inc	esi
	jmp	skip_address
      skip_expression:
	lods	byte [esi]
	or	al,al
	jz	skip_string
	cmp	al,'.'
	je	skip_fp_value
	cmp	al,')'
	je	skip_done
	cmp	al,']'
	je	skip_done
	cmp	al,'!'
	je	skip_expression
	cmp	al,0Fh
	je	skip_expression
	cmp	al,10h
	je	skip_register
	cmp	al,11h
	je	skip_label_value
	cmp	al,80h
	jae	skip_expression
	movzx	eax,al
	add	esi,eax
	jmp	skip_expression
      skip_label_value:
	add	esi,3
      skip_register:
	inc	esi
	jmp	skip_expression
      skip_fp_value:
	add	esi,12
	jmp	skip_done
      skip_string:
	lods	dword [esi]
	add	esi,eax
	inc	esi
	jmp	skip_done
      nothing_to_skip:
	dec	esi
	stc
	ret

expand_path:
	lods	byte [esi]
	cmp	al,'%'
	je	environment_variable
	stos	byte [edi]
	or	al,al
	jnz	expand_path
	cmp	edi,[memory_end]
	ja	out_of_memory
	ret
      environment_variable:
	mov	ebx,esi
      find_variable_end:
	lods	byte [esi]
	or	al,al
	jz	not_environment_variable
	cmp	al,'%'
	jne	find_variable_end
	mov	byte [esi-1],0
	push	esi
	mov	esi,ebx
	call	get_environment_variable
	pop	esi
	mov	byte [esi-1],'%'
	jmp	expand_path
      not_environment_variable:
	mov	al,'%'
	stos	byte [edi]
	mov	esi,ebx
	jmp	expand_path
get_include_directory:
	lods	byte [esi]
	cmp	al,';'
	je	include_directory_ok
	stos	byte [edi]
	or	al,al
	jnz	get_include_directory
	dec	esi
	dec	edi
      include_directory_ok:
	cmp	byte [edi-1],'/'
	je	path_separator_ok
	cmp	byte [edi-1],'\'
	je	path_separator_ok
	mov	al,'/'
	stos	byte [edi]
      path_separator_ok:
	ret
