3384 lines
		
	
	
		
			79 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			3384 lines
		
	
	
		
			79 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| 
 | |
| ; general note:
 | |
| ;  with the ability to run in various environments in mind, the entire assembler core
 | |
| ;  does not use ebp register and never directly touches esp; the stack is managed
 | |
| ;  with push and pop instructions, occasionally [esp] may be used to access the top value,
 | |
| ;  but no other assumptions about the stack layout are made
 | |
| 
 | |
| struct Workspace
 | |
| 	memory_start dd ?
 | |
| 	memory_end dd ?
 | |
| ends
 | |
| 
 | |
| struct SourceContext
 | |
| 	number_of_entries dd ?
 | |
|       ; entries SourceEntry[]
 | |
| ends
 | |
| 
 | |
| struct SourceEntry
 | |
| 	type db ?			; SOURCE_#
 | |
| 	flags db ?			; SRCF_#
 | |
| 	saved_result db ?
 | |
| 	reserved db ?
 | |
| 	name dd ?
 | |
| 	name_length dd ?
 | |
| 	text dd ?
 | |
| 	offset dd ?
 | |
| 	line_number dd ?
 | |
| 	number_of_attached_lines dd ?
 | |
| 	line_offset dd ?
 | |
| 	local_namespace dd ?
 | |
| ends
 | |
| 
 | |
| struct RecognitionContext
 | |
| 	base_namespace dd ?		; SymbolTree_Root
 | |
| 	base_label dd ? 		; SymbolTree_Foliage
 | |
| ends
 | |
| 
 | |
| struct LineEmbedding
 | |
| 	previous_pointer dd ?
 | |
| 	previous_end dd ?
 | |
| 	recognition_context dd ?
 | |
| 	definition dd ?
 | |
| 	whitespace dd ?
 | |
| ends
 | |
| 
 | |
| struct LineExcerpt
 | |
| 	data_start dd ?
 | |
| 	data_end dd ?
 | |
| 	recognition_context dd ?
 | |
| 	leftover_context dd ?
 | |
| ends
 | |
| 
 | |
| SOURCE_FILE = 0
 | |
| SOURCE_MEMORY = 1
 | |
| SOURCE_MACRO = 2
 | |
| SOURCE_CALM = 3
 | |
| 
 | |
| SRCF_PREPROCESSED = 1
 | |
| SRCF_ALM_STATEMENT = 2
 | |
| 
 | |
| PMODE_RETAIN_COMMENTS = 1
 | |
| PMODE_ISOLATE_LINES = 2
 | |
| 
 | |
| AMODE_SKIP = 1
 | |
| AMODE_DEFINITION = 2
 | |
| AMODE_POSTPONED = 4
 | |
| AMODE_CALM_DEFINITION = 8
 | |
| 
 | |
| TRACE_ERROR_STACK = 1
 | |
| TRACE_DISPLAY = 2
 | |
| 
 | |
| assembly_init:
 | |
| ; in:
 | |
| ;  al = any combination of TRACE_# flags
 | |
| 
 | |
| 	mov	[trace_mode],al
 | |
| 
 | |
| 	xor	eax,eax
 | |
| 	mov	edi,variables
 | |
| 	mov	ecx,(variables_end - variables) shr 2
 | |
| 	rep	stosd
 | |
|     if (variables_end - variables) and 11b
 | |
| 	mov	cl,(variables_end - variables) and 11b
 | |
| 	rep	stosb
 | |
|     end if
 | |
| 	mov	edi,characters
 | |
|       prepare_characters:
 | |
| 	stosb
 | |
| 	inc	al
 | |
| 	jnz	prepare_characters
 | |
| 	mov	esi,characters+'a'
 | |
| 	mov	edi,characters+'A'
 | |
| 	mov	ecx,'z'+1-'a'
 | |
| 	rep	movsb
 | |
| 	mov	edi,characters
 | |
| 	mov	esi,control_characters
 | |
| 	mov	cl,control_characters.count
 | |
|       mark_control_characters:
 | |
| 	lodsb
 | |
| 	mov	byte [edi+eax],20h
 | |
| 	loop	mark_control_characters
 | |
| 	mov	esi,syntactical_characters
 | |
| 	mov	cl,syntactical_characters.count
 | |
|       mark_syntactical_characters:
 | |
| 	lodsb
 | |
| 	mov	byte [edi+eax],0
 | |
| 	loop	mark_syntactical_characters
 | |
| 
 | |
| 	mov	esi,include_variable
 | |
| 	xor	ecx,ecx
 | |
| 	call	get_environment_variable
 | |
| 	mov	ecx,eax
 | |
| 	call	malloc_fixed
 | |
| 	mov	[include_paths],eax
 | |
| 	mov	edi,eax
 | |
| 	call	get_environment_variable
 | |
| 
 | |
| 	mov	cl,10
 | |
| 	call	create_string_map
 | |
| 	mov	[file_source_cache],ebx
 | |
| 
 | |
| 	mov	cl,12
 | |
| 	call	create_string_map
 | |
| 	mov	[memory_source_cache],ebx
 | |
| 
 | |
| 	mov	cl,10
 | |
| 	call	create_string_map
 | |
| 	mov	[file_data_cache],ebx
 | |
| 
 | |
| 	mov	cl,7
 | |
| 	call	create_string_map
 | |
| 	mov	[auxiliary_output_areas],ebx
 | |
| 
 | |
| 	mov	ecx,sizeof.SymbolTree_Root + sizeof.SymbolTree_Node
 | |
| 	call	create_tree_element
 | |
| 	mov	[root_namespace],eax
 | |
| 
 | |
| 	call	create_parameter_namespace
 | |
| 	mov	[root_parameter_namespace],eax
 | |
| 
 | |
| 	mov	ecx,4*sizeof.SymbolTree_Leaf
 | |
| 	call	create_tree_element
 | |
| 	mov	[eax+SymbolTree_Leaf.class],SYMCLASS_INSTRUCTION
 | |
| 	mov	[eax+SymbolTree_Leaf.flags],SYM_VARIABLE
 | |
| 	mov	[interceptor_symbol],eax
 | |
| 	add	eax,sizeof.SymbolTree_Leaf
 | |
| 	mov	[eax+SymbolTree_Leaf.class],SYMCLASS_STRUCTURE
 | |
| 	mov	[eax+SymbolTree_Leaf.flags],SYM_VARIABLE
 | |
| 	mov	[label_interceptor_symbol],eax
 | |
| 	add	eax,sizeof.SymbolTree_Leaf
 | |
| 	mov	[eax+SymbolTree_Leaf.class],SYMCLASS_INSTRUCTION
 | |
| 	mov	[eax+SymbolTree_Leaf.flags],SYM_VARIABLE
 | |
| 	mov	[other_interceptor_symbol],eax
 | |
| 	add	eax,sizeof.SymbolTree_Leaf
 | |
| 	mov	[void_symbol],eax
 | |
| 
 | |
| 	mov	ecx,400
 | |
| 	call	malloc_growable
 | |
| 	mov	[tree_stack_base],eax
 | |
| 	add	eax,ecx
 | |
| 	mov	[tree_stack_end],eax
 | |
| 
 | |
| 	mov	ecx,4000
 | |
| 	call	malloc_growable
 | |
| 	mov	[source_context],eax
 | |
| 	mov	[source_context_maximum_length],ecx
 | |
| 
 | |
| 	mov	ecx,1000
 | |
| 	call	malloc_growable
 | |
| 	mov	[line_embeddings],eax
 | |
| 	mov	[line_embeddings_maximum_length],ecx
 | |
| 
 | |
| 	mov	ecx,1000
 | |
| 	call	malloc_growable
 | |
| 	mov	[display_buffer],eax
 | |
| 	mov	[display_buffer_length],ecx
 | |
| 
 | |
| 	mov	ecx,1000
 | |
| 	call	malloc_growable
 | |
| 	mov	[macro_buffer],eax
 | |
| 	mov	[macro_buffer_length],ecx
 | |
| 
 | |
| 	mov	ecx,32*6*sizeof.ExpressionTerm
 | |
| 	call	malloc_fixed
 | |
| 	mov	[temporary_terms],eax
 | |
| 	mov	[free_temporary_terms],eax
 | |
| 
 | |
| 	mov	ecx,4*sizeof.FloatData
 | |
| 	call	malloc_fixed
 | |
| 	mov	[temporary_floats],eax
 | |
| 
 | |
| 	mov	ecx,400
 | |
| 	call	malloc_growable
 | |
| 	mov	[output_areas_list],eax
 | |
| 	mov	edi,eax
 | |
| 	add	eax,ecx
 | |
| 	mov	[output_areas_list_end],eax
 | |
| 	xor	eax,eax
 | |
| 	shr	ecx,2
 | |
| 	rep	stosd
 | |
| 	mov	[number_of_line_embeddings],eax
 | |
| 	mov	[virtual_area],eax
 | |
| 
 | |
| 	mov	ecx,1000
 | |
| 	call	malloc_growable
 | |
| 	mov	[directives_stack_base],eax
 | |
| 	add	eax,ecx
 | |
| 	mov	[directives_stack_end],eax
 | |
| 
 | |
| 	mov	ecx,1000
 | |
| 	call	malloc_growable
 | |
| 	mov	[counters_stack_base],eax
 | |
| 	add	eax,ecx
 | |
| 	mov	[counters_stack_end],eax
 | |
| 
 | |
| 	mov	ecx,400
 | |
| 	call	malloc_growable
 | |
| 	mov	[operator_stack_base],eax
 | |
| 	add	eax,ecx
 | |
| 	mov	[operator_stack_end],eax
 | |
| 
 | |
| 	mov	ecx,400
 | |
| 	call	malloc_growable
 | |
| 	mov	[condition_stack_base],eax
 | |
| 	add	eax,ecx
 | |
| 	mov	[condition_stack_end],eax
 | |
| 
 | |
| 	mov	ecx,400
 | |
| 	call	malloc_growable
 | |
| 	mov	[assembly_stack_base],eax
 | |
| 	add	eax,ecx
 | |
| 	mov	[assembly_stack_end],eax
 | |
| 
 | |
| 	mov	edx,preprocessing_workspace
 | |
| 	call	initialize_workspace
 | |
| 
 | |
| 	mov	edx,assembly_workspace
 | |
| 	call	initialize_workspace
 | |
| 
 | |
| 	mov	edx,identifier_workspace
 | |
| 	call	initialize_workspace
 | |
| 
 | |
| 	mov	edx,auxiliary_workspace
 | |
| 	call	initialize_workspace
 | |
| 
 | |
| 	mov	edx,value_workspace
 | |
| 	call	initialize_workspace
 | |
| 
 | |
| 	mov	edx,expression_workspace
 | |
| 	call	initialize_workspace
 | |
| 
 | |
| 	mov	edx,calculation_workspace
 | |
| 	call	initialize_workspace
 | |
| 
 | |
| 	mov	edx,calm_code_buffer
 | |
| 	call	initialize_workspace
 | |
| 
 | |
| 	mov	edx,calm_literals_buffer
 | |
| 	call	initialize_workspace
 | |
| 
 | |
| 	mov	edx,calm_auxiliary_buffer
 | |
| 	call	initialize_workspace
 | |
| 
 | |
| 	mov	ecx,256*4
 | |
| 	call	malloc_fixed
 | |
| 	mov	[operator_table],eax
 | |
| 	mov	edi,eax
 | |
| 	mov	ecx,256
 | |
| 	xor	eax,eax
 | |
| 	rep	stosd
 | |
| 	mov	esi,separating_operators
 | |
|     register_operators:
 | |
| 	lodsb
 | |
| 	test	al,al
 | |
| 	jz	operators_registered
 | |
| 	movzx	ebx,al
 | |
| 	shl	ebx,2
 | |
| 	add	ebx,[operator_table]
 | |
| 	mov	ecx,sizeof.ValueDefinition
 | |
| 	call	create_tree_element
 | |
| 	mov	edx,eax
 | |
| 	xchg	[ebx],eax
 | |
| 	mov	[edx+ValueDefinition.previous],eax
 | |
| 	inc	[edx+ValueDefinition.reference_count]
 | |
| 	lodsb
 | |
| 	mov	[edx+ValueDefinition.type],al
 | |
| 	lodsb
 | |
| 	mov	[edx+ValueDefinition.flags],al
 | |
| 	lodsb
 | |
| 	mov	[edx+ValueDefinition.attribute],al
 | |
| 	lodsd
 | |
| 	mov	[edx+ValueDefinition.value],eax
 | |
| 	jmp	register_operators
 | |
|     operators_registered:
 | |
| 
 | |
| 	xor	eax,eax
 | |
| 	mov	[name_volatile],al
 | |
| 	mov	[name_token],eax
 | |
| 	mov	[name_kind],NAME_CASEINSENSITIVE
 | |
| 	or	[symbol_required],1
 | |
| 	or	[symbol_expected],1
 | |
| 	mov	eax,[root_namespace]
 | |
| 	mov	[current_context.base_namespace],eax
 | |
| 	mov	esi,symbols
 | |
|     register_internal_symbols:
 | |
| 	lodsb
 | |
| 	test	al,al
 | |
| 	jnz	prepare_internal_symbol
 | |
| 	lodsb
 | |
| 	test	al,al
 | |
| 	jz	internal_symbols_registered
 | |
| 	and	[current_context.base_namespace],0
 | |
|     prepare_internal_symbol:
 | |
| 	movzx	ecx,al
 | |
| 
 | |
| 	xor	ebx,ebx
 | |
| 	mov	edx,FNV_OFFSET
 | |
|     hash_internal_symbol:
 | |
| 	movzx	eax,byte [esi+ebx]
 | |
| 	xor	dl,[characters+eax]
 | |
| 	imul	edx,FNV_PRIME
 | |
| 	inc	ebx
 | |
| 	cmp	ebx,ecx
 | |
| 	jb	hash_internal_symbol
 | |
| 
 | |
| 	mov	ebx,[current_context.base_namespace]
 | |
| 	test	ebx,ebx
 | |
| 	jz	register_internal_namespace
 | |
| 	mov	al,[esi+ecx]
 | |
| 	mov	[symbol_class],al
 | |
| 	push	esi
 | |
| 	call	scan_namespace
 | |
| 	pop	esi
 | |
| 	add	esi,ecx
 | |
| 	mov	ecx,sizeof.ValueDefinition
 | |
| 	call	create_tree_element
 | |
| 	mov	edx,eax
 | |
| 	xchg	[ebx+SymbolTree_Leaf.definition],eax
 | |
| 	mov	[edx+ValueDefinition.previous],eax
 | |
| 	inc	[edx+ValueDefinition.reference_count]
 | |
| 	lodsb
 | |
| 	lodsb
 | |
| 	mov	[edx+ValueDefinition.type],al
 | |
| 	lodsb
 | |
| 	mov	[edx+ValueDefinition.flags],al
 | |
| 	lodsb
 | |
| 	mov	[edx+ValueDefinition.attribute],al
 | |
| 	lodsd
 | |
| 	mov	[edx+ValueDefinition.value],eax
 | |
| 	jmp	register_internal_symbols
 | |
|     register_internal_namespace:
 | |
| 	mov	[symbol_class],SYMCLASS_EXPRESSION
 | |
| 	mov	ebx,[root_namespace]
 | |
| 	push	esi
 | |
| 	call	scan_namespace
 | |
| 	pop	esi
 | |
| 	add	esi,ecx
 | |
| 	mov	ecx,sizeof.ValueDefinition
 | |
| 	call	create_tree_element
 | |
| 	mov	[ebx+SymbolTree_Leaf.definition],eax
 | |
| 	inc	[eax+ValueDefinition.reference_count]
 | |
| 	mov	[eax+ValueDefinition.type],VALTYPE_RESERVED
 | |
| 	mov	[eax+ValueDefinition.flags],VAL_INTERNAL
 | |
| 	call	get_symbol_namespace
 | |
| 	mov	[current_context.base_namespace],ebx
 | |
| 	jmp	register_internal_symbols
 | |
|     internal_symbols_registered:
 | |
| 
 | |
| 	retn
 | |
| 
 | |
| assembly_shutdown:
 | |
| 
 | |
| 	call	discard_errors
 | |
| 
 | |
| 	mov	ebx,[auxiliary_output_areas]
 | |
| 	test	ebx,ebx
 | |
| 	jz	auxiliary_output_areas_released
 | |
| 	call	destroy_string_map
 | |
|     auxiliary_output_areas_released:
 | |
| 
 | |
| 	mov	ebx,[value_definition_chain]
 | |
|     release_values_from_chain:
 | |
| 	test	ebx,ebx
 | |
| 	jz	values_released
 | |
| 	cmp	[ebx+ValueDefinition.block_length],0
 | |
| 	je	release_next_value
 | |
| 	mov	eax,[ebx+ValueDefinition.value]
 | |
| 	call	mfree
 | |
|     release_next_value:
 | |
| 	mov	ebx,[ebx+ValueDefinition.interlink]
 | |
| 	jmp	release_values_from_chain
 | |
|     values_released:
 | |
| 
 | |
| 	mov	eax,[include_paths]
 | |
| 	call	mfree
 | |
| 
 | |
| 	mov	ebx,[file_source_cache]
 | |
| 	test	ebx,ebx
 | |
| 	jz	file_source_cache_released
 | |
| 	mov	edi,mfree
 | |
| 	call	iterate_through_map
 | |
| 	mov	ebx,[file_source_cache]
 | |
| 	call	destroy_string_map
 | |
|     file_source_cache_released:
 | |
| 
 | |
| 	mov	ebx,[file_data_cache]
 | |
| 	test	ebx,ebx
 | |
| 	jz	file_data_cache_released
 | |
| 	mov	edi,release_file_data
 | |
| 	call	iterate_through_map
 | |
| 	mov	ebx,[file_data_cache]
 | |
| 	call	destroy_string_map
 | |
|     file_data_cache_released:
 | |
| 
 | |
| 	mov	ebx,[memory_source_cache]
 | |
| 	test	ebx,ebx
 | |
| 	jz	memory_source_cache_released
 | |
| 	mov	edi,mfree
 | |
| 	call	iterate_through_map
 | |
| 	mov	ebx,[memory_source_cache]
 | |
| 	call	destroy_string_map
 | |
|     memory_source_cache_released:
 | |
| 
 | |
| 	mov	eax,[tree_stack_base]
 | |
| 	call	mfree
 | |
| 	mov	eax,[source_context]
 | |
| 	call	mfree
 | |
| 	mov	eax,[line_embeddings]
 | |
| 	call	mfree
 | |
| 	mov	eax,[output_areas_list]
 | |
| 	call	mfree
 | |
| 	mov	eax,[directives_stack_base]
 | |
| 	call	mfree
 | |
| 	mov	eax,[counters_stack_base]
 | |
| 	call	mfree
 | |
| 	mov	eax,[operator_stack_base]
 | |
| 	call	mfree
 | |
| 	mov	eax,[condition_stack_base]
 | |
| 	call	mfree
 | |
| 	mov	eax,[assembly_stack_base]
 | |
| 	call	mfree
 | |
| 
 | |
| 	mov	eax,[preprocessing_workspace.memory_start]
 | |
| 	call	mfree
 | |
| 	mov	eax,[assembly_workspace.memory_start]
 | |
| 	call	mfree
 | |
| 	mov	eax,[identifier_workspace.memory_start]
 | |
| 	call	mfree
 | |
| 	mov	eax,[value_workspace.memory_start]
 | |
| 	call	mfree
 | |
| 	mov	eax,[expression_workspace.memory_start]
 | |
| 	call	mfree
 | |
| 	mov	eax,[calculation_workspace.memory_start]
 | |
| 	call	mfree
 | |
| 	mov	eax,[auxiliary_workspace.memory_start]
 | |
| 	call	mfree
 | |
| 	mov	eax,[calm_code_buffer.memory_start]
 | |
| 	call	mfree
 | |
| 	mov	eax,[calm_literals_buffer.memory_start]
 | |
| 	call	mfree
 | |
| 	mov	eax,[calm_auxiliary_buffer.memory_start]
 | |
| 	call	mfree
 | |
| 
 | |
| 	mov	eax,[display_buffer]
 | |
| 	call	mfree
 | |
| 	mov	eax,[macro_buffer]
 | |
| 	call	mfree
 | |
| 	mov	eax,[temporary_terms]
 | |
| 	call	mfree
 | |
| 	mov	eax,[temporary_floats]
 | |
| 	call	mfree
 | |
| 	mov	eax,[operator_table]
 | |
| 	call	mfree
 | |
| 
 | |
| 	mov	eax,[tree_blocks]
 | |
| 	call	release_chained_blocks
 | |
| 
 | |
| 	mov	eax,[storage_blocks]
 | |
| 	call	release_chained_blocks
 | |
| 
 | |
| 	retn
 | |
| 
 | |
|     release_chained_blocks:
 | |
| 	test	eax,eax
 | |
| 	jz	blocks_released
 | |
| 	mov	ebx,[eax]
 | |
| 	call	mfree
 | |
| 	mov	eax,ebx
 | |
| 	jmp	release_chained_blocks
 | |
|       blocks_released:
 | |
| 	retn
 | |
| 
 | |
|     release_file_data:
 | |
| 	test	eax,eax
 | |
| 	jz	file_data_released
 | |
| 	mov	ebx,[eax+FileData.cache]
 | |
| 	call	mfree
 | |
|       release_file_cache:
 | |
| 	mov	eax,ebx
 | |
| 	test	eax,eax
 | |
| 	jz	file_data_released
 | |
| 	mov	ebx,[ebx+FileCache.next]
 | |
| 	call	mfree
 | |
| 	jmp	release_file_cache
 | |
|       file_data_released:
 | |
| 	retn
 | |
| 
 | |
|     release_auxiliary_output:
 | |
| 	test	eax,eax
 | |
| 	jz	auxiliary_output_released
 | |
| 	dec	[eax+ValueDefinition.reference_count]
 | |
| 	xor	eax,eax
 | |
| 	mov	[edx+MapEntry.value],eax
 | |
|       auxiliary_output_released:
 | |
| 	retn
 | |
| 
 | |
| assembly_pass:
 | |
| ; in:
 | |
| ;  esi - ASCIIZ string containing source text
 | |
| ;  edx - path to source file
 | |
| ; out:
 | |
| ;  cf clear if another pass is needed
 | |
| ; note:
 | |
| ;  if both string and file sources are present, they are assembled as combined text
 | |
| 	mov	[source_file],edx
 | |
| 	inc	[current_pass]
 | |
| 	call	discard_errors
 | |
| 	mov	eax,[directives_stack_base]
 | |
| 	mov	[directives_stack],eax
 | |
| 	mov	eax,[root_namespace]
 | |
| 	mov	[current_context.base_namespace],eax
 | |
| 	mov	edx,[counters_stack_base]
 | |
| 	mov	[current_counter],edx
 | |
| 	xor	eax,eax
 | |
| 	mov	[edx],al
 | |
| 	mov	[preprocessing_mode],al
 | |
| 	mov	[next_pass_needed],al
 | |
| 	mov	[assembly_mode],al
 | |
| 	mov	[use_raw_values],al
 | |
| 	mov	[shift_tracking],al
 | |
| 	mov	[current_area],eax
 | |
| 	mov	[current_output_area_entry],eax
 | |
| 	mov	[initial_output_area_entry],eax
 | |
| 	mov	[predicted_shift],eax
 | |
| 	mov	[display_data_length],eax
 | |
| 	mov	[macro_end_position],eax
 | |
| 	mov	[proxy_number],eax
 | |
| 	mov	[output_extension],eax
 | |
| 	mov	[output_extension_length],eax
 | |
| 	mov	ebx,[source_context]
 | |
| 	mov	[ebx+SourceContext.number_of_entries],eax
 | |
| 	add	ebx,sizeof.SourceContext
 | |
| 	mov	edi,ebx
 | |
| 	mov	ecx,sizeof.SourceEntry shr 2
 | |
| 	assert	sizeof.SourceEntry and 11b = 0
 | |
| 	rep	stosd
 | |
| 	mov	[line_start],eax
 | |
| 	mov	[line_end],eax
 | |
| 	test	esi,esi
 | |
| 	jz	read_main_source_file
 | |
| 	cmp	byte [esi],0
 | |
| 	je	read_main_source_file
 | |
| 	push	ebx
 | |
| 	call	use_source
 | |
| 	pop	ebx
 | |
| 	mov	[ebx+SourceEntry.type],SOURCE_MEMORY
 | |
| 	jmp	fill_main_source_entry
 | |
|       read_main_source_file:
 | |
| 	mov	esi,[source_file]
 | |
| 	test	esi,esi
 | |
| 	jz	no_source_to_assemble
 | |
| 	cmp	byte [esi],0
 | |
| 	je	no_source_to_assemble
 | |
| 	push	ebx
 | |
| 	call	read_source
 | |
| 	pop	ebx
 | |
| 	test	eax,eax
 | |
| 	jz	main_source_file_not_found
 | |
| 	mov	[ebx+SourceEntry.type],SOURCE_FILE
 | |
|       fill_main_source_entry:
 | |
| 	mov	[ebx+SourceEntry.name],esi
 | |
| 	mov	[ebx+SourceEntry.text],eax
 | |
| 	mov	eax,[root_parameter_namespace]
 | |
| 	and	[eax+SymbolTree_Root.parameters],0
 | |
| 	mov	[local_parameter_namespace],eax
 | |
| 	mov	[ebx+SourceEntry.local_namespace],eax
 | |
| 	mov	ebx,[source_context]
 | |
| 	inc	[ebx+SourceContext.number_of_entries]
 | |
| 	mov	esi,zero_value
 | |
| 	mov	ecx,4+4
 | |
| 	call	create_output_area
 | |
| 	mov	[current_area],edx
 | |
| 	inc	[edx+ValueDefinition.reference_count]
 | |
| 	mov	ebx,[auxiliary_output_areas]
 | |
| 	mov	edi,release_auxiliary_output
 | |
| 	call	iterate_through_map
 | |
| assembly_line:
 | |
| 	xor	eax,eax
 | |
| 	mov	[value_position],eax
 | |
| 	mov	[current_constituent],al
 | |
| 	call	clear_line_embeddings
 | |
|     get_line:
 | |
| 	xor	eax,eax
 | |
| 	mov	[symbol_class],SYMCLASS_PARAMETER
 | |
| 	mov	[symbol_expected],al
 | |
| 	mov	[symbol_required],al
 | |
| 	mov	[name_volatile],al
 | |
| 	mov	[preprocessed_context],eax
 | |
| 	mov	[alm_statement],al
 | |
| 	mov	ebx,[source_context]
 | |
| 	mov	ecx,[ebx+SourceContext.number_of_entries]
 | |
| 	dec	ecx
 | |
| 	imul	ecx,sizeof.SourceEntry
 | |
| 	lea	ebx,[ebx+sizeof.SourceContext+ecx]
 | |
| 	xchg	eax,[ebx+SourceEntry.number_of_attached_lines]
 | |
| 	inc	eax
 | |
| 	add	[ebx+SourceEntry.line_number],eax
 | |
| 	cmp	[ebx+SourceEntry.type],SOURCE_CALM
 | |
| 	je	calm_virtual_machine
 | |
| 	mov	eax,[ebx+SourceEntry.local_namespace]
 | |
| 	mov	[parameter_namespace],eax
 | |
| 	xor	edx,edx
 | |
| 	test	[eax+SymbolTree_Root.flags],NAMESPACE_UNATTACHED
 | |
| 	jnz	no_local_namespace
 | |
| 	mov	edx,eax
 | |
| 	mov	ecx,[eax+SymbolTree_Root.current_label]
 | |
| 	test	ecx,ecx
 | |
| 	jnz	local_namespace_ok
 | |
|     no_local_namespace:
 | |
| 	mov	eax,[current_context.base_namespace]
 | |
| 	mov	ecx,[eax+SymbolTree_Root.current_label]
 | |
|     local_namespace_ok:
 | |
| 	mov	[local_namespace],edx
 | |
| 	mov	[current_context.base_label],ecx
 | |
| 	cmp	[ebx+SourceEntry.type],SOURCE_MACRO
 | |
| 	je	get_line_from_macro
 | |
| 	and	[name_token],0
 | |
| 	mov	esi,[ebx+SourceEntry.text]
 | |
| 	mov	eax,[ebx+SourceEntry.offset]
 | |
| 	add	esi,eax
 | |
| 	mov	[ebx+SourceEntry.line_offset],eax
 | |
| 	cmp	byte [esi],0
 | |
| 	je	source_ended
 | |
| 	mov	edi,[preprocessing_workspace.memory_start]
 | |
|     preprocess_line_from_file:
 | |
| 	mov	ecx,14
 | |
| 	mov	edx,preprocessing_workspace
 | |
| 	call	reserve_workspace
 | |
| 	lodsb
 | |
| 	cmp	al,1Ah
 | |
| 	je	convert_name_symbol
 | |
| 	cmp	al,22h
 | |
| 	je	convert_quoted_string
 | |
| 	cmp	al,27h
 | |
| 	je	convert_quoted_string
 | |
| 	test	al,al
 | |
| 	jz	file_ended
 | |
| 	cmp	al,0Ah
 | |
| 	je	line_ended
 | |
| 	cmp	al,';'
 | |
| 	jne	preprocess_syntactical_character
 | |
| 	xor	edx,edx
 | |
| 	test	[preprocessing_mode],PMODE_RETAIN_COMMENTS
 | |
| 	jz	skip_comment
 | |
|     preprocess_syntactical_character:
 | |
| 	stosb
 | |
| 	cmp	al,'`'
 | |
| 	je	convert_parameter
 | |
| 	cmp	al,'\'
 | |
| 	jne	preprocess_line_from_file
 | |
| 	test	[preprocessing_mode],PMODE_ISOLATE_LINES
 | |
| 	jnz	preprocess_line_from_file
 | |
| 	mov	edx,esi
 | |
|     detect_line_concatenation:
 | |
| 	mov	al,[edx]
 | |
| 	inc	edx
 | |
| 	cmp	al,0Ah
 | |
| 	je	concatenate_line
 | |
| 	cmp	al,';'
 | |
| 	je	concatenation_comment
 | |
| 	cmp	al,20h
 | |
| 	jne	preprocess_line_from_file
 | |
| 	jmp	detect_line_concatenation
 | |
|     concatenate_line:
 | |
| 	mov	byte [edi-1],20h
 | |
| 	inc	esi
 | |
| 	inc	[ebx+SourceEntry.number_of_attached_lines]
 | |
| 	jmp	preprocess_line_from_file
 | |
|     concatenation_comment:
 | |
| 	test	[preprocessing_mode],PMODE_RETAIN_COMMENTS
 | |
| 	jnz	preprocess_line_from_file
 | |
| 	mov	byte [edi-1],20h
 | |
| 	mov	esi,edx
 | |
| 	inc	[ebx+SourceEntry.number_of_attached_lines]
 | |
|     skip_comment:
 | |
| 	lodsb
 | |
| 	test	al,al
 | |
| 	jz	file_ended
 | |
| 	cmp	al,0Ah
 | |
| 	je	comment_ended
 | |
| 	cmp	al,22h
 | |
| 	je	skip_quoted_string
 | |
| 	cmp	al,27h
 | |
| 	je	skip_quoted_string
 | |
| 	cmp	al,1Ah
 | |
| 	jne	skip_comment
 | |
| 	lodsd
 | |
| 	lea	esi,[esi+eax+12]
 | |
| 	jmp	skip_comment
 | |
|     comment_ended:
 | |
| 	test	edx,edx
 | |
| 	jnz	preprocess_line_from_file
 | |
| 	jmp	line_ended
 | |
|     skip_quoted_string:
 | |
| 	lodsd
 | |
| 	add	esi,eax
 | |
| 	jmp	skip_comment
 | |
|     convert_quoted_string:
 | |
| 	stosb
 | |
| 	mov	eax,esi
 | |
| 	stosd
 | |
| 	lodsd
 | |
| 	add	esi,eax
 | |
| 	jmp	preprocess_line_from_file
 | |
|     convert_name_symbol:
 | |
| 	mov	ecx,[esi]
 | |
| 	lea	eax,[esi+4+ecx+12]
 | |
| 	push	eax ebx
 | |
| 	mov	eax,[eax-4]
 | |
| 	test	eax,eax
 | |
| 	jz	name_symbol_not_cached
 | |
| 	mov	esi,eax
 | |
|       name_symbol_not_cached:
 | |
| 	call	preprocess_symbol
 | |
|     name_symbol_converted:
 | |
| 	pop	ebx esi
 | |
| 	jmp	preprocess_line_from_file
 | |
|     convert_parameter:
 | |
| 	cmp	byte [esi],1Ah
 | |
| 	jne	preprocess_line_from_file
 | |
| 	lodsb
 | |
| 	mov	ecx,[esi]
 | |
| 	lea	eax,[esi+4+ecx+12]
 | |
| 	push	eax ebx
 | |
| 	mov	eax,[eax-4]
 | |
| 	test	eax,eax
 | |
| 	jz	parameter_to_convert_not_cached
 | |
| 	mov	esi,eax
 | |
|       parameter_to_convert_not_cached:
 | |
| 	call	preprocess_symbol
 | |
| 	jc	name_symbol_converted
 | |
| 	call	convert_parameter_to_string
 | |
| 	jmp	name_symbol_converted
 | |
|     file_ended:
 | |
| 	dec	esi
 | |
|     line_ended:
 | |
| 	sub	esi,[ebx+SourceEntry.text]
 | |
| 	mov	[ebx+SourceEntry.offset],esi
 | |
| 	jmp	line_preprocessed
 | |
|     source_ended:
 | |
| 	mov	ebx,[source_context]
 | |
| 	dec	[ebx+SourceContext.number_of_entries]
 | |
| 	jnz	get_line
 | |
| 	cmp	[ebx+sizeof.SourceContext+SourceEntry.type],SOURCE_MEMORY
 | |
| 	jne	no_more_lines
 | |
| 	mov	esi,[source_file]
 | |
| 	test	esi,esi
 | |
| 	jz	no_more_lines
 | |
| 	cmp	byte [esi],0
 | |
| 	je	no_more_lines
 | |
| 	lea	edi,[ebx+sizeof.SourceContext]
 | |
| 	mov	ecx,sizeof.SourceEntry shr 2
 | |
| 	assert	sizeof.SourceEntry and 11b = 0
 | |
| 	xor	eax,eax
 | |
| 	rep	stosd
 | |
| 	call	read_source
 | |
| 	test	eax,eax
 | |
| 	jz	main_source_file_not_found
 | |
| 	mov	ebx,[source_context]
 | |
| 	inc	[ebx+SourceContext.number_of_entries]
 | |
| 	add	ebx,sizeof.SourceContext
 | |
| 	mov	[ebx+SourceEntry.type],SOURCE_FILE
 | |
| 	mov	[ebx+SourceEntry.name],esi
 | |
| 	mov	[ebx+SourceEntry.text],eax
 | |
| 	mov	eax,[parameter_namespace]
 | |
| 	mov	[ebx+SourceEntry.local_namespace],eax
 | |
| 	jmp	get_line
 | |
|     no_more_lines:
 | |
| 	jmp	pass_done
 | |
|     get_line_from_macro:
 | |
| 	mov	edx,[ebx+SourceEntry.text]
 | |
| 	mov	esi,[edx+ValueDefinition.value]
 | |
| 	mov	ecx,[edx+ValueDefinition.value_length]
 | |
| 	mov	eax,[ebx+SourceEntry.offset]
 | |
| 	test	[ebx+SourceEntry.flags],SRCF_PREPROCESSED
 | |
| 	jnz	use_preprocessed_line
 | |
| 	add	ecx,esi
 | |
| 	mov	[source_end],ecx
 | |
| 	add	esi,eax
 | |
| 	cmp	esi,[source_end]
 | |
| 	je	macro_ended
 | |
| 	mov	[ebx+SourceEntry.line_offset],eax
 | |
| 	mov	edi,[preprocessing_workspace.memory_start]
 | |
|     preprocess_line_from_macro:
 | |
| 	cmp	esi,[source_end]
 | |
| 	je	macro_line_ended
 | |
| 	mov	ecx,14
 | |
| 	mov	edx,preprocessing_workspace
 | |
| 	call	reserve_workspace
 | |
| 	lodsb
 | |
| 	cmp	al,1Ah
 | |
| 	je	reproduce_name_symbol
 | |
| 	test	al,al
 | |
| 	jz	macro_line_ended
 | |
| 	stosb
 | |
| 	cmp	al,22h
 | |
| 	je	reproduce_quoted_string
 | |
| 	cmp	al,27h
 | |
| 	je	reproduce_quoted_string
 | |
| 	cmp	al,30h
 | |
| 	je	reproduce_internal_token
 | |
| 	cmp	al,40h
 | |
| 	je	reproduce_context_token
 | |
| 	cmp	al,'`'
 | |
| 	je	conversion_operator_in_macro
 | |
| 	jmp	preprocess_line_from_macro
 | |
|     reproduce_quoted_string:
 | |
| 	movsd
 | |
| 	jmp	preprocess_line_from_macro
 | |
|     reproduce_internal_token:
 | |
| 	mov	ecx,[esi]
 | |
| 	add	ecx,4
 | |
| 	mov	edx,preprocessing_workspace
 | |
| 	call	reserve_workspace
 | |
| 	lodsd
 | |
| 	stosd
 | |
| 	mov	ecx,eax
 | |
| 	rep	movsb
 | |
| 	jmp	preprocess_line_from_macro
 | |
|     reproduce_context_token:
 | |
| 	mov	[preprocessed_context],esi
 | |
| 	assert	sizeof.RecognitionContext and 11b = 0
 | |
| 	mov	ecx,sizeof.RecognitionContext shr 2
 | |
| 	rep	movsd
 | |
| 	cmp	esi,[source_end]
 | |
| 	je	macro_line_ended
 | |
| 	cmp	byte [esi],40h
 | |
| 	jne	preprocess_line_from_macro
 | |
| 	inc	esi
 | |
| 	sub	edi,sizeof.RecognitionContext
 | |
| 	jmp	reproduce_context_token
 | |
|     reproduce_name_symbol:
 | |
| 	mov	[name_token],esi
 | |
| 	lodsd
 | |
| 	push	esi ebx
 | |
| 	mov	esi,eax
 | |
| 	call	preprocess_symbol
 | |
|     name_symbol_reproduced:
 | |
| 	pop	ebx esi
 | |
| 	jmp	preprocess_line_from_macro
 | |
|     conversion_operator_in_macro:
 | |
| 	cmp	esi,[source_end]
 | |
| 	je	macro_ended
 | |
| 	cmp	byte [esi],1Ah
 | |
| 	jne	preprocess_line_from_macro
 | |
| 	inc	esi
 | |
| 	mov	[name_token],esi
 | |
| 	lodsd
 | |
| 	push	esi ebx
 | |
| 	mov	esi,eax
 | |
| 	call	preprocess_symbol
 | |
| 	jc	name_symbol_reproduced
 | |
| 	call	convert_parameter_to_string
 | |
| 	jmp	name_symbol_reproduced
 | |
|     convert_parameter_to_string:
 | |
| 	call	convert_symbolic_value_to_string
 | |
| 	mov	ebx,[memory_source_cache]
 | |
| 	xor	eax,eax
 | |
| 	call	put_into_map
 | |
| 	mov	edi,[symbol_value_start]
 | |
| 	dec	edi
 | |
| 	mov	al,22h
 | |
| 	stosb
 | |
| 	mov	eax,esi
 | |
| 	stosd
 | |
| 	retn
 | |
|     macro_ended:
 | |
| 	mov	edx,[ebx+SourceEntry.text]
 | |
| 	and	[edx+ValueDefinition.flags],not VAL_IN_USE
 | |
| 	dec	[edx+ValueDefinition.reference_count]
 | |
| 	mov	ebx,[source_context]
 | |
| 	dec	[ebx+SourceContext.number_of_entries]
 | |
| 	jnz	get_line
 | |
| 	jmp	pass_done
 | |
|     use_preprocessed_line:
 | |
| 	test	eax,eax
 | |
| 	jnz	macro_ended
 | |
| 	dec	eax
 | |
| 	mov	[ebx+SourceEntry.offset],eax
 | |
| 	add	ecx,esi
 | |
| 	mov	[line_start],esi
 | |
| 	mov	[line_end],ecx
 | |
| 	jmp	got_line
 | |
|     macro_line_ended:
 | |
| 	mov	edx,[ebx+SourceEntry.text]
 | |
| 	sub	esi,[edx+ValueDefinition.value]
 | |
| 	mov	[ebx+SourceEntry.offset],esi
 | |
|     line_preprocessed:
 | |
| 	mov	[line_end],edi
 | |
| 	mov	esi,[preprocessing_workspace.memory_start]
 | |
| 	mov	[line_start],esi
 | |
|     got_line:
 | |
| 	and	[line_context],0
 | |
| assemble_instruction:
 | |
| 	mov	ebx,[interceptor_symbol]
 | |
| 	call	get_available_value
 | |
| 	jc	no_interceptor
 | |
| 	test	[edx+ValueDefinition.flags],VAL_UNCONDITIONAL
 | |
| 	jz	weak_interceptor
 | |
| 	jmp	execute_instruction
 | |
|       no_interceptor:
 | |
| 	xor	edx,edx
 | |
|       weak_interceptor:
 | |
| 	mov	[interceptor],edx
 | |
| 	xor	eax,eax
 | |
| 	mov	[label_interceptor],eax
 | |
| 	test	[assembly_mode],AMODE_CALM_DEFINITION
 | |
| 	jnz	assemble_alm_instruction
 | |
| 	mov	[symbol_definition],al
 | |
| 	mov	[instruction_branch],eax
 | |
| 	mov	dl,SYMCLASS_INSTRUCTION
 | |
| 	call	identify_symbol
 | |
| 	jc	empty_line
 | |
| 	mov	[label_branch],edx
 | |
| 	mov	al,[symbol_independent]
 | |
| 	mov	[label_independent],al
 | |
| 	test	ebx,ebx
 | |
| 	jz	unrecognized_instruction
 | |
| 	cmp	[ebx+SymbolTree_Leaf.class],SYMCLASS_INSTRUCTION
 | |
| 	jne	labeled_instruction
 | |
| 	cmp	[symbol_independent],-1
 | |
| 	je	unrecognized_instruction
 | |
| 	call	get_available_value
 | |
| 	jc	unrecognized_instruction
 | |
| 	test	[edx+ValueDefinition.flags],VAL_UNCONDITIONAL
 | |
| 	jnz	execute_instruction
 | |
| 	cmp	[interceptor],0
 | |
| 	jne	unrecognized_instruction
 | |
| 	test	[assembly_mode],AMODE_SKIP or AMODE_DEFINITION
 | |
| 	jnz	unrecognized_instruction
 | |
|     execute_instruction:
 | |
| 	mov	al,[edx+ValueDefinition.type]
 | |
| 	cmp	al,VALTYPE_CALM
 | |
| 	je	launch_calm
 | |
| 	cmp	al,VALTYPE_NATIVE_COMMAND
 | |
| 	je	execute_native_instruction
 | |
| 	cmp	al,VALTYPE_SYMBOLIC
 | |
| 	je	use_macro
 | |
| 	cmp	al,VALTYPE_RESERVED
 | |
| 	jne	unrecognized_instruction
 | |
| 	mov	edx,_symbolic_self_reference
 | |
| 	call	register_error
 | |
|     unrecognized_instruction:
 | |
| 	test	[assembly_mode],AMODE_SKIP
 | |
| 	jnz	assembly_line
 | |
| 	test	[assembly_mode],AMODE_DEFINITION
 | |
| 	jnz	add_line_to_macro
 | |
| 	cmp	[interceptor],0
 | |
| 	jne	execute_interceptor
 | |
| 	cmp	[label_interceptor],0
 | |
| 	jne	execute_label_interceptor
 | |
| 	mov	ebx,[other_interceptor_symbol]
 | |
| 	call	get_available_value
 | |
| 	jnc	execute_other_interceptor
 | |
| 	mov	edx,_illegal_instruction
 | |
| 	call	register_error
 | |
| 	mov	ebx,[label_branch]
 | |
| 	test	ebx,ebx
 | |
| 	jz	assembly_line
 | |
| 	mov	[symbol_class],SYMCLASS_INSTRUCTION
 | |
| 	or	[symbol_required],1
 | |
| 	or	[symbol_expected],1
 | |
| 	call	scan_symbol_branch
 | |
| 	xor	edx,edx
 | |
| 	call	mark_symbol_as_used
 | |
| 	mov	ebx,[instruction_branch]
 | |
| 	test	ebx,ebx
 | |
| 	jz	assembly_line
 | |
| 	mov	[symbol_class],SYMCLASS_STRUCTURE
 | |
| 	or	[symbol_required],1
 | |
| 	or	[symbol_expected],1
 | |
| 	call	scan_symbol_branch
 | |
| 	xor	edx,edx
 | |
| 	call	mark_symbol_as_used
 | |
| 	jmp	assembly_line
 | |
|     labeled_instruction:
 | |
| 	mov	[label_leaf],ebx
 | |
| 	mov	[label_instruction_start],esi
 | |
| 	mov	ebx,[label_interceptor_symbol]
 | |
| 	call	get_available_value
 | |
| 	jc	no_label_interceptor
 | |
| 	test	[edx+ValueDefinition.flags],VAL_UNCONDITIONAL
 | |
| 	jnz	execute_labeled_instruction
 | |
| 	mov	[label_interceptor],edx
 | |
| 	mov	eax,[embedded_context]
 | |
| 	mov	[label_instruction_context],eax
 | |
| 	jmp	identify_structure_instruction
 | |
|     no_label_interceptor:
 | |
| 	call	move_to_next_symbol
 | |
| 	jc	unrecognized_instruction	; orphan label
 | |
| 	cmp	al,':'
 | |
| 	je	define_label
 | |
| 	cmp	al,'='
 | |
| 	je	define_numeric_symbol
 | |
|     identify_structure_instruction:
 | |
| 	mov	dl,SYMCLASS_STRUCTURE
 | |
| 	call	identify_symbol
 | |
| 	mov	[instruction_branch],edx
 | |
| 	test	ebx,ebx
 | |
| 	jz	unrecognized_instruction
 | |
| 	cmp	[ebx+SymbolTree_Leaf.class],SYMCLASS_STRUCTURE
 | |
| 	jne	unrecognized_instruction
 | |
| 	call	get_available_value
 | |
| 	jc	unrecognized_instruction
 | |
| 	test	[edx+ValueDefinition.flags],VAL_UNCONDITIONAL
 | |
| 	jnz	execute_labeled_instruction
 | |
| 	test	[assembly_mode],AMODE_SKIP or AMODE_DEFINITION
 | |
| 	jnz	unrecognized_instruction
 | |
| 	cmp	[interceptor],0
 | |
| 	jne	execute_interceptor
 | |
| 	cmp	[label_interceptor],0
 | |
| 	jne	execute_label_interceptor
 | |
|     execute_labeled_instruction:
 | |
| 	mov	al,[edx+ValueDefinition.type]
 | |
| 	cmp	al,VALTYPE_CALM
 | |
| 	je	launch_calm
 | |
| 	cmp	al,VALTYPE_SYMBOLIC
 | |
| 	je	use_struc
 | |
| 	cmp	al,VALTYPE_NATIVE_COMMAND
 | |
| 	jne	unrecognized_instruction
 | |
|     execute_native_instruction:
 | |
| 	mov	eax,[current_pass]
 | |
| 	mov	[ebx+SymbolTree_Leaf.last_use_pass],eax
 | |
| 	jmp	[edx+ValueDefinition.value]
 | |
|     empty_line:
 | |
| 	mov	al,[assembly_mode]
 | |
| 	and	al,AMODE_SKIP or AMODE_DEFINITION
 | |
| 	cmp	al,AMODE_DEFINITION
 | |
| 	je	add_line_to_macro
 | |
| 	jmp	assembly_line
 | |
|     execute_interceptor:
 | |
| 	mov	ebx,[interceptor_symbol]
 | |
| 	mov	edx,[interceptor]
 | |
| 	xor	eax,eax
 | |
| 	mov	[embedded_context],eax
 | |
| 	mov	esi,[line_start]
 | |
| 	jmp	execute_instruction
 | |
|     execute_label_interceptor:
 | |
| 	mov	ebx,[label_interceptor_symbol]
 | |
| 	mov	edx,[label_interceptor]
 | |
| 	mov	eax,[label_instruction_context]
 | |
| 	mov	[embedded_context],eax
 | |
| 	mov	esi,[label_instruction_start]
 | |
| 	cmp	[edx+ValueDefinition.type],VALTYPE_CALM
 | |
| 	je	launch_calm
 | |
| 	jmp	use_struc
 | |
|     execute_other_interceptor:
 | |
| 	mov	ebx,[other_interceptor_symbol]
 | |
| 	xor	eax,eax
 | |
| 	mov	[embedded_context],eax
 | |
| 	mov	esi,[line_start]
 | |
| 	jmp	execute_instruction
 | |
| instruction_assembled:
 | |
| 	cmp	[current_constituent],0
 | |
| 	jne	extra_characters_on_line
 | |
| 	call	warp_to_next_symbol
 | |
| 	jc	assembly_line
 | |
|     extra_characters_on_line:
 | |
| 	mov	edx,_extra_characters_on_line
 | |
| 	call	register_error
 | |
| 	jmp	assembly_line
 | |
|     pass_done:
 | |
| 	mov	dl,DBLOCK_CONTROL
 | |
| 	call	find_directive_block
 | |
| 	jc	assemble_postponed_block
 | |
| 	mov	esi,edi
 | |
| 	sub	esi,[edi+DirectiveBlock.length_of_data]
 | |
| 	mov	edx,_missing_end_directive
 | |
| 	call	register_delayed_error
 | |
| 	call	close_control_directive_block
 | |
| 	jmp	pass_done
 | |
|     assemble_postponed_block:
 | |
| 	mov	dl,DBLOCK_POSTPONED
 | |
| 	call	find_directive_block
 | |
| 	jc	no_postponed_blocks
 | |
| 	mov	ebx,edi
 | |
| 	mov	esi,edi
 | |
| 	sub	esi,[edi+DirectiveBlock.length_of_data]
 | |
| 	mov	edi,[source_context]
 | |
| 	call	clone_source_context
 | |
| 	mov	edi,ebx
 | |
| 	call	close_directive_block
 | |
| 	or	[assembly_mode],AMODE_POSTPONED
 | |
| 	jmp	assembly_line
 | |
|     no_postponed_blocks:
 | |
| 	mov	ebx,[root_namespace]
 | |
| 	call	detect_mispredictions
 | |
|     assemble_suspended_block:
 | |
| 	mov	dl,DBLOCK_SUSPENDED
 | |
| 	call	find_directive_block
 | |
| 	jc	no_suspended_blocks
 | |
| 	cmp	[next_pass_needed],0
 | |
| 	jne	ignore_suspended_block
 | |
| 	mov	ebx,edi
 | |
| 	mov	esi,edi
 | |
| 	sub	esi,[edi+DirectiveBlock.length_of_data]
 | |
| 	mov	edi,[source_context]
 | |
| 	call	clone_source_context
 | |
| 	mov	edi,ebx
 | |
| 	call	close_directive_block
 | |
| 	or	[assembly_mode],AMODE_POSTPONED
 | |
| 	jmp	assembly_line
 | |
|     ignore_suspended_block:
 | |
| 	call	close_directive_block
 | |
| 	jmp	assemble_suspended_block
 | |
|     no_suspended_blocks:
 | |
| 	mov	esi,[directives_stack]
 | |
|     signal_unclosed_blocks:
 | |
| 	cmp	esi,[directives_stack_base]
 | |
| 	je	unclosed_blocks_signalled
 | |
| 	sub	esi,sizeof.DirectiveBlock
 | |
| 	mov	eax,[esi+DirectiveBlock.length_of_data]
 | |
| 	sub	esi,eax
 | |
| 	mov	edx,_missing_end_directive
 | |
| 	call	register_delayed_error
 | |
| 	jmp	signal_unclosed_blocks
 | |
|     unclosed_blocks_signalled:
 | |
| 	xor	eax,eax
 | |
| 	xchg	eax,[current_area]
 | |
| 	dec	[eax+ValueDefinition.reference_count]
 | |
| 	mov	al,[next_pass_needed]
 | |
| 	sub	al,1
 | |
| 	retn
 | |
|     main_source_file_not_found:
 | |
| 	mov	ebx,esi
 | |
| 	mov	edx,_source_file_not_found
 | |
| 	call	register_error
 | |
|     no_source_to_assemble:
 | |
| 	mov	esi,zero_value
 | |
| 	mov	ecx,4+4
 | |
| 	call	create_output_area
 | |
| 	mov	[current_area],edx
 | |
| 	inc	[edx+ValueDefinition.reference_count]
 | |
| 	stc
 | |
| 	retn
 | |
| 
 | |
| initialize_workspace:
 | |
| ; in:
 | |
| ;  edx - Workspace
 | |
| ; preserves: ebx, edx, esi, edi
 | |
| 	push	edx
 | |
| 	mov	ecx,1000h
 | |
| 	call	malloc_growable
 | |
| 	pop	edx
 | |
| 	mov	[edx+Workspace.memory_start],eax
 | |
| 	add	eax,ecx
 | |
| 	mov	[edx+Workspace.memory_end],eax
 | |
| 	retn
 | |
| 
 | |
| reserve_workspace:
 | |
| ; in:
 | |
| ;  edx - Workspace
 | |
| ;  edi - top of used workspace area
 | |
| ;  ecx = size of required reserve
 | |
| ; out:
 | |
| ;  cf set if workspace had to be expanded
 | |
| ;  edi - top of used workspace area (possibly relocated when cf is set)
 | |
| ; preserves: ebx, edx, esi
 | |
| 	mov	eax,[edx+Workspace.memory_end]
 | |
| 	sub	eax,ecx
 | |
| 	jc	not_enough_workspace
 | |
| 	cmp	edi,eax
 | |
| 	ja	not_enough_workspace
 | |
| 	clc
 | |
| 	retn
 | |
|     not_enough_workspace:
 | |
| 	add	ecx,edi
 | |
| 	jc	allocation_overflow
 | |
| 	sub	ecx,[edx+Workspace.memory_start]
 | |
| 	push	ecx
 | |
| 	bsr	eax,ecx
 | |
| 	xchg	ecx,eax
 | |
| 	dec	cl
 | |
| 	shr	eax,cl
 | |
| 	inc	eax
 | |
| 	shl	eax,cl
 | |
| 	mov	ecx,eax
 | |
| 	pop	eax
 | |
| 	cmp	ecx,eax
 | |
| 	jbe	allocation_overflow
 | |
| 	cmp	edi,[edx+Workspace.memory_start]
 | |
| 	je	reestablish_workspace
 | |
|     expand_workspace:
 | |
| 	mov	eax,[edx+Workspace.memory_start]
 | |
| 	sub	edi,eax
 | |
| 	push	edx
 | |
| 	call	realloc
 | |
| 	pop	edx
 | |
|     update_workspace:
 | |
| 	mov	[edx+Workspace.memory_start],eax
 | |
| 	add	edi,eax
 | |
| 	add	eax,ecx
 | |
| 	mov	[edx+Workspace.memory_end],eax
 | |
| 	stc
 | |
| 	retn
 | |
|     reestablish_workspace:
 | |
| 	push	edx ecx
 | |
| 	xor	eax,eax
 | |
| 	xchg	eax,[edx+Workspace.memory_start]
 | |
| 	call	mfree
 | |
| 	pop	ecx
 | |
| 	call	malloc_growable
 | |
| 	pop	edx
 | |
| 	xor	edi,edi
 | |
| 	jmp	update_workspace
 | |
|     allocation_overflow:
 | |
| 	jmp	out_of_memory
 | |
| 
 | |
| grow_stack:
 | |
| ; in:
 | |
| ;  eax = base address of memory block containing stack data
 | |
| ;  ecx = required minimum size of memory block
 | |
| ; out:
 | |
| ;  eax = new base address of memory block containing stack data
 | |
| ;  ecx = new size of memory block
 | |
| ; preserves: ebx, esi, edi
 | |
| 	push	ecx
 | |
| 	bsr	edx,ecx
 | |
| 	xchg	ecx,edx
 | |
| 	sub	cl,2
 | |
| 	shr	edx,cl
 | |
| 	inc	edx
 | |
| 	shl	edx,cl
 | |
| 	mov	ecx,edx
 | |
| 	pop	edx
 | |
| 	cmp	ecx,edx
 | |
| 	jbe	allocation_overflow
 | |
| 	call	realloc
 | |
| 	retn
 | |
| 
 | |
| create_source_entry:
 | |
| ; out:
 | |
| ;  cf set when the maximum number of entries in context has been exceeded
 | |
| ;  when cf = 0:
 | |
| ;   ebx - new SourceEntry in the main SourceContext
 | |
| ; preserves: edx, esi
 | |
| 	mov	ebx,[source_context]
 | |
| 	mov	eax,[ebx+SourceContext.number_of_entries]
 | |
| 	cmp	eax,[maximum_depth_of_stack]
 | |
| 	jae	source_context_full
 | |
| 	inc	[ebx+SourceContext.number_of_entries]
 | |
| 	imul	eax,sizeof.SourceEntry
 | |
| 	add	eax,sizeof.SourceContext
 | |
| 	mov	edi,eax
 | |
| 	add	eax,sizeof.SourceEntry
 | |
| 	cmp	eax,[source_context_maximum_length]
 | |
| 	jbe	source_context_length_ok
 | |
| 	mov	ecx,eax
 | |
| 	mov	eax,ebx
 | |
| 	mov	ebx,edx
 | |
| 	call	realloc
 | |
| 	mov	[source_context],eax
 | |
| 	mov	[source_context_maximum_length],ecx
 | |
| 	mov	edx,ebx
 | |
| 	mov	ebx,eax
 | |
|     source_context_length_ok:
 | |
| 	add	ebx,edi
 | |
| 	mov	edi,ebx
 | |
| 	mov	ecx,sizeof.SourceEntry shr 2
 | |
| 	assert	sizeof.SourceEntry and 11b = 0
 | |
| 	xor	eax,eax
 | |
| 	rep	stosd
 | |
| 	cmp	[alm_statement],0
 | |
| 	je	source_entry_created
 | |
| 	mov	[edi-sizeof.SourceEntry+SourceEntry.flags],SRCF_ALM_STATEMENT
 | |
|     source_entry_created:
 | |
| 	clc
 | |
| 	retn
 | |
|     source_context_full:
 | |
| 	stc
 | |
| 	retn
 | |
| 
 | |
| create_parameter_namespace:
 | |
| ; out:
 | |
| ;  eax - SymbolTree_Root
 | |
| ; preserves: ebx, edx, esi, edi
 | |
| 	mov	ecx,sizeof.SymbolTree_Root + sizeof.SymbolTree_LocalNode
 | |
| 	call	create_tree_element
 | |
| 	or	[eax+SymbolTree_Root.attributes],SYMTREE_LOCAL
 | |
| 	or	[eax+SymbolTree_Root.flags],NAMESPACE_UNATTACHED
 | |
| 	retn
 | |
| 
 | |
| clone_source_context:
 | |
| ; in:
 | |
| ;  esi - SourceContext
 | |
| ;  edi - buffer
 | |
| ; out:
 | |
| ;  edi = pointer advanced past the stored data
 | |
| ; preserves: ebx
 | |
| 	cmp	edi,[source_context]
 | |
| 	sete	[source_context_affected]
 | |
| 	mov	eax,[esi+SourceContext.number_of_entries]
 | |
| 	assert	sizeof.SourceContext and 11b = 0
 | |
| 	mov	ecx,sizeof.SourceContext shr 2
 | |
| 	rep	movsd
 | |
| 	test	eax,eax
 | |
| 	jnz	clone_source_entry
 | |
| 	retn
 | |
|     clone_source_entry:
 | |
| 	assert	SOURCE_FILE < SOURCE_MACRO & SOURCE_MEMORY < SOURCE_MACRO & SOURCE_CALM > SOURCE_MACRO
 | |
| 	cmp	[esi+SourceEntry.type],SOURCE_MACRO
 | |
| 	jb	copy_source_entry
 | |
| 	mov	edx,[esi+SourceEntry.text]
 | |
| 	inc	[edx+ValueDefinition.reference_count]
 | |
| 	cmp	[source_context_affected],0
 | |
| 	je	copy_source_entry
 | |
| 	or	[edx+ValueDefinition.flags],VAL_IN_USE
 | |
|       copy_source_entry:
 | |
| 	assert	sizeof.SourceEntry and 11b = 0
 | |
| 	mov	ecx,sizeof.SourceEntry shr 2
 | |
| 	rep	movsd
 | |
| 	dec	eax
 | |
| 	jnz	clone_source_entry
 | |
| 	retn
 | |
| 
 | |
| release_source_context:
 | |
| ; in:
 | |
| ;  eax - SourceContext
 | |
| ; preserves: eax, ebx, esi, edi
 | |
| 	cmp	eax,[source_context]
 | |
| 	sete	[source_context_affected]
 | |
| 	push	eax
 | |
| 	mov	ecx,[eax+SourceContext.number_of_entries]
 | |
| 	add	eax,sizeof.SourceContext
 | |
| 	test	ecx,ecx
 | |
| 	jnz	release_source_entry
 | |
| 	pop	eax
 | |
| 	retn
 | |
|     release_source_entry:
 | |
| 	assert	SOURCE_FILE < SOURCE_MACRO & SOURCE_MEMORY < SOURCE_MACRO & SOURCE_CALM > SOURCE_MACRO
 | |
| 	cmp	[eax+SourceEntry.type],SOURCE_MACRO
 | |
| 	jb	source_entry_released
 | |
| 	mov	edx,[eax+SourceEntry.text]
 | |
| 	dec	[edx+ValueDefinition.reference_count]
 | |
| 	cmp	[source_context_affected],0
 | |
| 	je	source_entry_released
 | |
| 	and	[edx+ValueDefinition.flags],not VAL_IN_USE
 | |
|       source_entry_released:
 | |
| 	add	eax,sizeof.SourceEntry
 | |
| 	loop	release_source_entry
 | |
| 	pop	eax
 | |
| 	retn
 | |
| 
 | |
| get_file_source_entry:
 | |
| ; out:
 | |
| ;  ebx - SourceEntry in the main SourceContext
 | |
| ; preserves: edx, esi, edi
 | |
| 	mov	ebx,[source_context]
 | |
| 	mov	ecx,[ebx+SourceContext.number_of_entries]
 | |
| 	mov	eax,ecx
 | |
| 	imul	eax,sizeof.SourceEntry
 | |
| 	lea	ebx,[ebx+sizeof.SourceContext+eax]
 | |
|       find_file_source_entry:
 | |
| 	sub	ebx,sizeof.SourceEntry
 | |
| 	cmp	[ebx+SourceEntry.type],SOURCE_FILE
 | |
| 	loopne	find_file_source_entry
 | |
| 	retn
 | |
| 
 | |
| preprocess_symbol:
 | |
| ; in:
 | |
| ;  esi - contents of the name token (32-bit length and name followed by two hashes)
 | |
| ;  edi - pointer into preprocessing_workspace where the preprocessed text should be stored
 | |
| ; out:
 | |
| ;  edi - just after the preprocessed text
 | |
| ;  cf set when symbol was used as-is (was not recognized as a parameter)
 | |
| ;  when cf = 0:
 | |
| ;   [symbol_value_start] - start of the preprocessed text
 | |
| ;   [symbol_value_end] - end of the preprocessed text (the same as edi)
 | |
| 	mov	eax,edi
 | |
| 	sub	eax,[preprocessing_workspace.memory_start]
 | |
| 	mov	[symbol_value_start],eax
 | |
| 	mov	[symbol_data],esi
 | |
| 	lodsd
 | |
| 	mov	ecx,eax
 | |
| 	mov	eax,[esi+ecx+4]
 | |
| 	mov	[case_insensitive_hash],eax
 | |
| 	mov	edx,[esi+ecx]
 | |
| 	mov	[name_kind],NAME_CASESENSITIVE
 | |
| 	mov	ebx,[parameter_namespace]
 | |
| 	call	scan_namespace
 | |
| 	jnc	parameter_found
 | |
| 	mov	[name_kind],NAME_CASEINSENSITIVE
 | |
| 	mov	ebx,[parameter_namespace]
 | |
| 	test	[ebx+SymbolTree_Root.attributes],SYMTREE_WITH_CASEINSENSITIVE_PARAMETERS
 | |
| 	jz	no_local_parameter_recognized
 | |
| 	mov	edx,[case_insensitive_hash]
 | |
| 	call	scan_namespace
 | |
| 	jnc	parameter_found
 | |
|     no_local_parameter_recognized:
 | |
| 	cmp	byte [esi],'%'
 | |
| 	jne	no_parameter_recognized
 | |
| 	cmp	ecx,2
 | |
| 	ja	no_parameter_recognized
 | |
| 	jb	current_counter_value
 | |
| 	cmp	byte [esi+1],'%'
 | |
| 	je	current_limit_value
 | |
|     no_parameter_recognized:
 | |
| 	mov	edi,[preprocessing_workspace.memory_start]
 | |
| 	add	edi,[symbol_value_start]
 | |
| 	mov	al,1Ah
 | |
| 	stosb
 | |
| 	mov	eax,[symbol_data]
 | |
| 	stosd
 | |
| 	stc
 | |
| 	retn
 | |
|     parameter_found:
 | |
| 	mov	edi,[preprocessing_workspace.memory_start]
 | |
| 	add	edi,[symbol_value_start]
 | |
| 	mov	edx,[ebx+SymbolTree_Leaf.definition]
 | |
| 	mov	al,[edx+ValueDefinition.type]
 | |
| 	cmp	al,VALTYPE_SYMBOLIC
 | |
| 	je	simple_parameter_value
 | |
| 	cmp	al,VALTYPE_SYMBOLIC_SEQUENCE
 | |
| 	je	iterator_value
 | |
| 	cmp	al,VALTYPE_NUMERIC_SEQUENCE
 | |
| 	je	named_counter_value
 | |
| 	cmp	al,VALTYPE_NATIVE_COMMAND
 | |
| 	jne	no_parameter_recognized
 | |
| 	jmp	[edx+ValueDefinition.value]
 | |
|     current_counter_value:
 | |
| 	mov	ebx,[parameter_namespace]
 | |
| 	test	[ebx+SymbolTree_Root.parameters],SPECPARM_COUNTER
 | |
| 	jz	no_parameter_recognized
 | |
| 	mov	esi,[current_counter]
 | |
| 	mov	dl,DBLOCK_CONTROL
 | |
| 	call	find_directive_block
 | |
|       find_breakable_block:
 | |
| 	jc	no_parameter_recognized
 | |
| 	test	[edi+DirectiveBlock.flags],CTRLF_BREAKABLE
 | |
| 	jz	look_deeper_for_breakable_block
 | |
| 	mov	eax,[parameter_namespace]
 | |
| 	cmp	eax,[edi+DirectiveBlock.parameter_namespace]
 | |
| 	je	found_breakable_block
 | |
|       look_deeper_for_breakable_block:
 | |
| 	mov	esi,[edi+DirectiveBlock.prior_counter_position]
 | |
| 	add	esi,[counters_stack_base]
 | |
| 	call	find_next_directive_block
 | |
| 	jmp	find_breakable_block
 | |
|       found_breakable_block:
 | |
| 	cmp	byte [esi],0
 | |
| 	je	no_parameter_recognized
 | |
| 	mov	edi,[preprocessing_workspace.memory_start]
 | |
| 	add	edi,[symbol_value_start]
 | |
| 	movzx	ecx,byte [esi]
 | |
| 	add	ecx,6
 | |
| 	mov	edx,preprocessing_workspace
 | |
| 	call	reserve_workspace
 | |
| 	mov	al,30h
 | |
| 	stosb
 | |
| 	mov	edx,edi
 | |
| 	xor	eax,eax
 | |
| 	lodsb
 | |
| 	stosd
 | |
| 	mov	ecx,eax
 | |
| 	rep	movsb
 | |
| 	test	byte [edi-1],80h
 | |
| 	jz	parameter_replaced
 | |
| 	xor	al,al
 | |
| 	stosb
 | |
| 	inc	dword [edx]
 | |
| 	jmp	parameter_replaced
 | |
|     current_limit_value:
 | |
| 	mov	ebx,[parameter_namespace]
 | |
| 	test	[ebx+SymbolTree_Root.parameters],SPECPARM_LIMIT
 | |
| 	jz	no_parameter_recognized
 | |
| 	mov	dl,DBLOCK_CONTROL
 | |
| 	call	find_directive_block
 | |
|       find_block_with_limit:
 | |
| 	jc	no_parameter_recognized
 | |
| 	test	[edi+DirectiveBlock.flags],CTRLF_BREAKABLE
 | |
| 	jz	look_deeper_for_block_with_limit
 | |
| 	test	[edi+DirectiveBlock.flags],CTRLF_HAS_REPEAT_DATA
 | |
| 	jz	look_deeper_for_block_with_limit
 | |
| 	mov	eax,[parameter_namespace]
 | |
| 	cmp	eax,[edi+DirectiveBlock.parameter_namespace]
 | |
| 	je	found_block_with_limit
 | |
|       look_deeper_for_block_with_limit:
 | |
| 	call	find_next_directive_block
 | |
| 	jmp	find_block_with_limit
 | |
|       found_block_with_limit:
 | |
| 	mov	ebx,edi
 | |
| 	sub	ebx,sizeof.RepeatData
 | |
| 	mov	edi,[preprocessing_workspace.memory_start]
 | |
| 	add	edi,[symbol_value_start]
 | |
| 	mov	ecx,[ebx+RepeatData.limit_length]
 | |
| 	add	ecx,6
 | |
| 	mov	edx,preprocessing_workspace
 | |
| 	call	reserve_workspace
 | |
| 	mov	al,30h
 | |
| 	stosb
 | |
| 	mov	edx,edi
 | |
| 	mov	eax,[ebx+RepeatData.limit_length]
 | |
| 	stosd
 | |
| 	sub	ebx,eax
 | |
| 	mov	esi,ebx
 | |
| 	mov	ecx,eax
 | |
| 	rep	movsb
 | |
| 	test	byte [edi-1],80h
 | |
| 	jz	parameter_replaced
 | |
| 	xor	al,al
 | |
| 	stosb
 | |
| 	inc	dword [edx]
 | |
| 	jmp	parameter_replaced
 | |
|     named_counter_value:
 | |
| 	mov	edx,[edx+ValueDefinition.value]
 | |
| 	mov	ebx,[edx]
 | |
| 	add	ebx,[counters_stack_base]
 | |
| 	cmp	byte [ebx],0
 | |
| 	je	no_parameter_recognized
 | |
| 	add	edx,4
 | |
| 	movzx	ecx,byte [ebx]
 | |
| 	cmp	ecx,[edx]
 | |
| 	jae	estimate_counter_length
 | |
| 	mov	ecx,[edx]
 | |
|       estimate_counter_length:
 | |
| 	add	ecx,6
 | |
| 	mov	esi,edx
 | |
| 	mov	edx,preprocessing_workspace
 | |
| 	call	reserve_workspace
 | |
| 	mov	al,30h
 | |
| 	stosb
 | |
| 	xor	eax,eax
 | |
| 	stosd
 | |
| 	push	edi
 | |
| 	movzx	ecx,byte [ebx]
 | |
| 	inc	ebx
 | |
| 	lodsd
 | |
| 	sub	eax,ecx
 | |
| 	jnc	counter_base_selected
 | |
| 	add	ecx,eax
 | |
| 	neg	eax
 | |
| 	xchg	ebx,esi
 | |
|       counter_base_selected:
 | |
| 	mov	edx,eax
 | |
| 	jecxz	counter_added_to_base
 | |
| 	xor	ah,ah
 | |
|       add_counter_to_base:
 | |
| 	lodsb
 | |
| 	add	al,ah
 | |
| 	setc	ah
 | |
| 	add	al,[ebx]
 | |
| 	adc	ah,0
 | |
| 	inc	ebx
 | |
| 	add	al,-1
 | |
| 	adc	ah,0
 | |
| 	stosb
 | |
| 	loop	add_counter_to_base
 | |
|       counter_added_to_base:
 | |
| 	mov	ecx,edx
 | |
| 	jecxz	counter_carried
 | |
|       carry_counter:
 | |
| 	lodsb
 | |
| 	add	al,ah
 | |
| 	setc	ah
 | |
| 	add	al,-1
 | |
| 	adc	ah,0
 | |
| 	stosb
 | |
| 	loop	carry_counter
 | |
|       counter_carried:
 | |
| 	pop	edx
 | |
| 	mov	al,ah
 | |
| 	dec	al
 | |
| 	jnz	extend_counter_value
 | |
| 	cmp	edx,edi
 | |
| 	je	counter_value_finished
 | |
| 	test	byte [edi-1],80h
 | |
| 	jz	counter_value_finished
 | |
|       extend_counter_value:
 | |
| 	stosb
 | |
|       counter_value_finished:
 | |
| 	mov	ecx,edi
 | |
| 	sub	ecx,edx
 | |
| 	mov	[edx-4],ecx
 | |
| 	jmp	parameter_replaced
 | |
|     iterator_value:
 | |
| 	mov	edx,[edx+ValueDefinition.value]
 | |
| 	mov	ebx,[edx]
 | |
| 	add	ebx,[counters_stack_base]
 | |
| 	movzx	ecx,byte [ebx]
 | |
| 	test	ecx,ecx
 | |
| 	jz	no_parameter_recognized
 | |
| 	push	edi
 | |
| 	mov	edi,value_index
 | |
| 	xor	eax,eax
 | |
| 	mov	[edi],eax
 | |
| 	mov	esi,ebx
 | |
| 	inc	esi
 | |
| 	rep	movsb
 | |
| 	mov	eax,[value_index]
 | |
| 	pop	edi
 | |
| 	shl	eax,2
 | |
| 	mov	esi,[edx+eax]
 | |
| 	mov	ecx,[edx+eax+4]
 | |
| 	sub	ecx,esi
 | |
| 	add	esi,edx
 | |
| 	jmp	copy_parameter_value
 | |
|     simple_parameter_value:
 | |
| 	mov	esi,[edx+ValueDefinition.value]
 | |
| 	mov	ecx,[edx+ValueDefinition.value_length]
 | |
|     copy_parameter_value:
 | |
| 	push	ecx
 | |
| 	mov	edx,preprocessing_workspace
 | |
| 	call	reserve_workspace
 | |
| 	pop	ecx
 | |
| 	cmp	[preprocessed_context],0
 | |
| 	jne	copy_with_preprocessed_context
 | |
| 	rep	movsb
 | |
| 	jmp	parameter_replaced
 | |
|       copy_token_pointer:
 | |
| 	movsd
 | |
| 	sub	ecx,4
 | |
|       copy_with_preprocessed_context:
 | |
| 	test	ecx,ecx
 | |
| 	jz	parameter_replaced
 | |
| 	lodsb
 | |
| 	stosb
 | |
| 	dec	ecx
 | |
| 	cmp	al,1Ah
 | |
| 	je	copy_token_pointer
 | |
| 	cmp	al,22h
 | |
| 	je	copy_token_pointer
 | |
| 	cmp	al,27h
 | |
| 	je	copy_token_pointer
 | |
| 	cmp	al,30h
 | |
| 	je	copy_token_data
 | |
| 	cmp	al,40h
 | |
| 	jne	copy_with_preprocessed_context
 | |
| 	mov	eax,ecx
 | |
| 	cmp	dword [esi],0
 | |
| 	jne	copy_parameter_context
 | |
| 	mov	edx,esi
 | |
| 	mov	esi,[preprocessed_context]
 | |
| 	assert	sizeof.RecognitionContext and 11b = 0
 | |
| 	mov	ecx,sizeof.RecognitionContext shr 2
 | |
| 	rep	movsd
 | |
| 	lea	esi,[edx+sizeof.RecognitionContext]
 | |
| 	mov	ecx,eax
 | |
| 	sub	ecx,sizeof.RecognitionContext
 | |
| 	jmp	copy_with_preprocessed_context
 | |
|       copy_parameter_context:
 | |
| 	assert	sizeof.RecognitionContext and 11b = 0
 | |
| 	mov	ecx,sizeof.RecognitionContext shr 2
 | |
| 	rep	movsd
 | |
| 	mov	ecx,eax
 | |
| 	sub	ecx,sizeof.RecognitionContext
 | |
| 	jmp	copy_with_preprocessed_context
 | |
|       copy_token_data:
 | |
| 	lodsd
 | |
| 	stosd
 | |
| 	sub	ecx,4
 | |
| 	sub	ecx,eax
 | |
| 	xchg	ecx,eax
 | |
| 	rep	movsb
 | |
| 	xchg	ecx,eax
 | |
| 	jmp	copy_with_preprocessed_context
 | |
|     local_symbol_name:
 | |
| 	mov	ecx,1+sizeof.RecognitionContext+1+4+1+sizeof.RecognitionContext
 | |
| 	mov	edx,preprocessing_workspace
 | |
| 	call	reserve_workspace
 | |
| 	mov	al,40h
 | |
| 	stosb
 | |
| 	mov	eax,[local_namespace]
 | |
| 	mov	[edi+RecognitionContext.base_namespace],eax
 | |
| 	xor	eax,eax
 | |
| 	mov	[edi+RecognitionContext.base_label],eax
 | |
| 	add	edi,sizeof.RecognitionContext
 | |
| 	mov	al,1Ah
 | |
| 	stosb
 | |
| 	mov	eax,[symbol_data]
 | |
| 	stosd
 | |
| 	mov	al,40h
 | |
| 	stosb
 | |
| 	mov	esi,[preprocessed_context]
 | |
| 	assert	sizeof.RecognitionContext and 11b = 0
 | |
| 	mov	ecx,sizeof.RecognitionContext shr 2
 | |
| 	test	esi,esi
 | |
| 	jz	reset_context
 | |
| 	rep	movsd
 | |
| 	stc
 | |
| 	retn
 | |
|     reset_context:
 | |
| 	xor	eax,eax
 | |
| 	rep	stosd
 | |
| 	stc
 | |
| 	retn
 | |
|     parameter_replaced:
 | |
| 	mov	[symbol_value_end],edi
 | |
| 	mov	eax,[preprocessing_workspace.memory_start]
 | |
| 	add	[symbol_value_start],eax
 | |
| 	clc
 | |
| 	retn
 | |
| 
 | |
| convert_symbolic_value_to_string:
 | |
| ; in:
 | |
| ;  [symbol_value_start] - start of the preprocessed text to convert
 | |
| ;  [symbol_value_end] - end of the preprocessed text to convert
 | |
| ; out:
 | |
| ;  esi - 32-bit length followed by string data
 | |
| ;  ecx = total length of string data (including the length prefix)
 | |
| 	mov	esi,[symbol_value_start]
 | |
| 	mov	edx,assembly_workspace
 | |
| 	mov	edi,[edx+Workspace.memory_start]
 | |
| 	add	edi,4
 | |
|       convert_token_to_text:
 | |
| 	mov	ecx,[symbol_value_end]
 | |
| 	sub	ecx,esi
 | |
| 	jbe	finish_conversion
 | |
| 	mov	edx,assembly_workspace
 | |
| 	call	reserve_workspace
 | |
| 	lodsb
 | |
| 	cmp	al,1Ah
 | |
| 	je	convert_name_token_to_text
 | |
| 	cmp	al,22h
 | |
| 	je	convert_string_token_to_text
 | |
| 	cmp	al,27h
 | |
| 	je	convert_string_token_to_text
 | |
| 	cmp	al,30h
 | |
| 	je	convert_internal_number_to_text
 | |
| 	cmp	al,40h
 | |
| 	je	ignore_context_token
 | |
| 	stosb
 | |
| 	jmp	convert_token_to_text
 | |
|       ignore_context_token:
 | |
| 	add	esi,sizeof.RecognitionContext
 | |
| 	jmp	convert_token_to_text
 | |
|       convert_name_token_to_text:
 | |
| 	lodsd
 | |
| 	mov	ebx,esi
 | |
| 	mov	esi,eax
 | |
| 	mov	ecx,[esi]
 | |
| 	mov	edx,assembly_workspace
 | |
| 	call	reserve_workspace
 | |
| 	lodsd
 | |
| 	mov	ecx,eax
 | |
| 	rep	movsb
 | |
| 	mov	esi,ebx
 | |
| 	jmp	convert_token_to_text
 | |
|       convert_string_token_to_text:
 | |
| 	lodsd
 | |
| 	mov	ebx,esi
 | |
| 	mov	esi,eax
 | |
| 	call	enclose_string
 | |
| 	mov	esi,ebx
 | |
| 	cmp	byte [esi-4-1],27h
 | |
| 	jne	convert_token_to_text
 | |
| 	dec	edi
 | |
| 	jmp	convert_token_to_text
 | |
|       enclose_string:
 | |
| 	mov	ecx,[esi]
 | |
| 	inc	ecx
 | |
| 	shl	ecx,1
 | |
| 	mov	edx,assembly_workspace
 | |
| 	call	reserve_workspace
 | |
| 	lodsd
 | |
| 	mov	ecx,eax
 | |
| 	mov	al,27h
 | |
| 	stosb
 | |
|       copy_string_characters:
 | |
| 	jecxz	string_characters_copied
 | |
| 	lodsb
 | |
| 	stosb
 | |
| 	dec	ecx
 | |
| 	cmp	al,27h
 | |
| 	jne	copy_string_characters
 | |
| 	stosb
 | |
| 	jmp	copy_string_characters
 | |
|       string_characters_copied:
 | |
| 	mov	al,27h
 | |
| 	stosb
 | |
| 	retn
 | |
|       convert_internal_number_to_text:
 | |
| 	mov	edx,esi
 | |
| 	lodsd
 | |
| 	add	esi,eax
 | |
| 	push	esi edi
 | |
| 	call	convert_number_back
 | |
| 	pop	edi
 | |
| 	mov	esi,edx
 | |
| 	mov	ecx,[esi]
 | |
| 	mov	edx,assembly_workspace
 | |
| 	call	reserve_workspace
 | |
| 	lodsd
 | |
| 	mov	ecx,eax
 | |
| 	rep	movsb
 | |
| 	pop	esi
 | |
| 	jmp	convert_token_to_text
 | |
|       finish_conversion:
 | |
| 	mov	esi,[assembly_workspace.memory_start]
 | |
| 	mov	ecx,edi
 | |
| 	sub	ecx,esi
 | |
| 	lea	eax,[ecx-4]
 | |
| 	mov	[esi],eax
 | |
| 	retn
 | |
| 
 | |
| compare_symbolic_values:
 | |
| ; in:
 | |
| ;  esi - first symbolic value
 | |
| ;  edi - second symbolic value
 | |
| ;  ecx = length to compare
 | |
| ; out:
 | |
| ;  ecx = zero when values equal, or a number of bytes following the point of difference
 | |
| ;  esi - the point of difference in first value
 | |
| ;  edi - the point of difference in second value
 | |
| 	mov	al,[esi]
 | |
| 	cmp	al,[edi]
 | |
| 	jne	symbolic_values_compared
 | |
| 	inc	esi
 | |
| 	inc	edi
 | |
| 	cmp	al,1Ah
 | |
| 	je	compare_tokens_with_data
 | |
| 	cmp	al,22h
 | |
| 	je	compare_tokens_with_data
 | |
| 	cmp	al,27h
 | |
| 	je	compare_tokens_with_data
 | |
| 	cmp	al,30h
 | |
| 	je	compare_internal_tokens
 | |
| 	cmp	al,40h
 | |
| 	je	compare_context_tokens
 | |
| 	loop	compare_symbolic_values
 | |
|     symbolic_values_compared:
 | |
| 	retn
 | |
|     compare_tokens_with_data:
 | |
| 	dec	ecx
 | |
| 	mov	eax,[esi]
 | |
| 	mov	edx,[edi]
 | |
| 	cmp	eax,edx
 | |
| 	jne	compare_token_data
 | |
| 	add	esi,4
 | |
| 	add	edi,4
 | |
| 	sub	ecx,4
 | |
| 	jnz	compare_symbolic_values
 | |
| 	retn
 | |
|     compare_token_data:
 | |
| 	mov	ebx,[eax]
 | |
| 	cmp	ebx,[edx]
 | |
| 	jne	symbolic_values_compared
 | |
| 	add	eax,ebx
 | |
| 	add	edx,ebx
 | |
| 	xchg	esi,eax
 | |
| 	xchg	edi,edx
 | |
| 	xchg	ecx,ebx
 | |
| 	dec	ecx
 | |
| 	shr	ecx,2
 | |
| 	inc	ecx
 | |
| 	cmp	byte [eax-1],1Ah
 | |
| 	jne	compare_token_dwords
 | |
| 	inc	ecx
 | |
| 	add	esi,4
 | |
| 	add	edi,4
 | |
|     compare_token_dwords:
 | |
| 	std
 | |
| 	repe	cmpsd
 | |
| 	cld
 | |
| 	jne	token_data_content_differs
 | |
| 	lea	esi,[eax+4]
 | |
| 	lea	edi,[edx+4]
 | |
| 	mov	ecx,ebx
 | |
| 	sub	ecx,4
 | |
| 	jnz	compare_symbolic_values
 | |
| 	retn
 | |
|     token_data_content_differs:
 | |
| 	mov	esi,eax
 | |
| 	mov	edi,edx
 | |
| 	mov	ecx,ebx
 | |
| 	retn
 | |
|     compare_internal_tokens:
 | |
| 	mov	eax,[esi]
 | |
| 	cmp	eax,[edi]
 | |
| 	jne	symbolic_values_compared
 | |
| 	add	esi,4
 | |
| 	add	edi,4
 | |
| 	sub	ecx,1+4
 | |
| 	sub	ecx,eax
 | |
| 	xchg	ecx,eax
 | |
| 	repe	cmpsb
 | |
| 	je	internal_tokens_equal
 | |
| 	inc	ecx
 | |
| 	dec	esi
 | |
| 	dec	edi
 | |
| 	add	ecx,eax
 | |
| 	retn
 | |
|     internal_tokens_equal:
 | |
| 	add	ecx,eax
 | |
| 	jnz	compare_symbolic_values
 | |
| 	retn
 | |
|     compare_context_tokens:
 | |
| 	dec	ecx
 | |
| 	assert	sizeof.RecognitionContext and 11b = 0
 | |
| 	mov	edx,sizeof.RecognitionContext shr 2
 | |
|     compare_contexts:
 | |
| 	mov	eax,[esi]
 | |
| 	cmp	eax,[edi]
 | |
| 	jne	symbolic_values_compared
 | |
| 	add	esi,4
 | |
| 	add	edi,4
 | |
| 	sub	ecx,4
 | |
| 	jz	symbolic_values_compared
 | |
| 	dec	edx
 | |
| 	jnz	compare_contexts
 | |
| 	jmp	compare_symbolic_values
 | |
| 
 | |
| move_to_next_symbol:
 | |
| ; in:
 | |
| ;  esi = pointer into preprocessed line or current embedded value
 | |
| ;  zeroed ecx is recommended for whitespace detection
 | |
| ; out:
 | |
| ;  esi = pointer advanced past the whitespace and context tokens
 | |
| ;  cf set when reached end of line or embedded value
 | |
| ;  ecx increased when there was whitespace on the way, preserved otherwise
 | |
| ;  when cf = 0:
 | |
| ;   esi - next symbol
 | |
| ;   al = initial byte of the next symbol
 | |
| ; preserves: ebx, edx, edi
 | |
| ; note:
 | |
| ;  [embedded_context] is updated to point to a RecognitionContext that should be in force at the new position (null means current namespace context);
 | |
| 	cmp	esi,[line_end]
 | |
| 	jb	next_token_available
 | |
| 	stc
 | |
| 	retn
 | |
|     next_token_available:
 | |
| 	mov	al,[esi]
 | |
| 	cmp	al,40h
 | |
| 	je	set_embedded_context
 | |
| 	cmp	al,20h
 | |
| 	je	pass_whitespace
 | |
| 	clc
 | |
| 	retn
 | |
|     pass_whitespace:
 | |
| 	inc	esi
 | |
| 	inc	ecx
 | |
| 	jmp	move_to_next_symbol
 | |
|     set_embedded_context:
 | |
| 	inc	esi
 | |
| 	cmp	[esi+RecognitionContext.base_namespace],0
 | |
| 	je	restore_embedded_context
 | |
| 	mov	[embedded_context],esi
 | |
| 	add	esi,sizeof.RecognitionContext
 | |
| 	jmp	move_to_next_symbol
 | |
|     restore_embedded_context:
 | |
| 	add	esi,sizeof.RecognitionContext
 | |
| 	mov	eax,[number_of_line_embeddings]
 | |
| 	test	eax,eax
 | |
| 	jz	clear_embedded_context
 | |
| 	dec	eax
 | |
| 	imul	eax,sizeof.LineEmbedding
 | |
| 	add	eax,[line_embeddings]
 | |
| 	mov	eax,[eax+LineEmbedding.recognition_context]
 | |
| 	mov	[embedded_context],eax
 | |
| 	jmp	move_to_next_symbol
 | |
|     clear_embedded_context:
 | |
| 	and	[embedded_context],0
 | |
| 	jmp	move_to_next_symbol
 | |
| 
 | |
| warp_to_next_symbol:
 | |
| ; in:
 | |
| ;  esi = pointer into preprocessed line or current embedded value
 | |
| ;  zeroed ecx is recommended for whitespace detection
 | |
| ; out:
 | |
| ;  esi - next symbol
 | |
| ;  cf set when end of line reached
 | |
| ;  ecx increased when there was whitespace on the way, preserved otherwise
 | |
| ;  when cf = 0:
 | |
| ;   al = initial byte of the next symbol
 | |
| ; preserves: ebx, edx, edi
 | |
| ; note:
 | |
| ;  [embedded_context] is updated to point to a RecognitionContext that should be in force at the new position (null means current namespace context);
 | |
| 	call	move_to_next_symbol
 | |
| 	jc	warp_through_embedding_boundary
 | |
| 	retn
 | |
|     warp_through_embedding_boundary:
 | |
| 	mov	eax,[number_of_line_embeddings]
 | |
| 	sub	eax,1
 | |
| 	jc	reached_end_of_line
 | |
| 	mov	[number_of_line_embeddings],eax
 | |
| 	imul	eax,sizeof.LineEmbedding
 | |
| 	add	eax,[line_embeddings]
 | |
| 	mov	esi,eax
 | |
| 	push	edx
 | |
| 	add	ecx,[esi+LineEmbedding.whitespace]
 | |
| 	mov	edx,[esi+LineEmbedding.recognition_context]
 | |
| 	mov	[embedded_context],edx
 | |
| 	mov	edx,[esi+LineEmbedding.definition]
 | |
| 	dec	[edx+ValueDefinition.reference_count]
 | |
| 	and	[edx+ValueDefinition.flags],not VAL_IN_USE
 | |
| 	mov	edx,[esi+LineEmbedding.previous_end]
 | |
| 	mov	[line_end],edx
 | |
| 	mov	esi,[esi+LineEmbedding.previous_pointer]
 | |
| 	pop	edx
 | |
| 	jmp	warp_to_next_symbol
 | |
|     reached_end_of_line:
 | |
|        ; stc
 | |
| 	retn
 | |
| 
 | |
| cut_piece_of_line:
 | |
| ; in:
 | |
| ;  esi = pointer into preprocessed line or current embedded value
 | |
| ;  edi - LineExcerpt to be filled with information about cut piece of line
 | |
| ;  dl = initial byte of symbol that should end the cut value, zero to cut up to the end of line (or current embedded value)
 | |
| ;  dh = initial byte of symbol that would open the nested piece, zero for no nesting
 | |
| ;  [breakpoint_token] = initial byte of symbol that should unconditionally end the cut value if it is met
 | |
| ; out:
 | |
| ;  esi = pointer advanced past the cut piece
 | |
| ;  al = initial byte of symbol at pointer, zero when no more symbols there
 | |
| ; preserves: ebx, edx, edi
 | |
| ; note: when [breakpoint_token] has the same value as either dl or dh, it has no effect
 | |
| 	mov	[number_of_enclosings],1
 | |
| 	call	move_to_next_symbol
 | |
| 	mov	[edi+LineExcerpt.data_start],esi
 | |
| 	mov	[edi+LineExcerpt.data_end],esi
 | |
| 	jc	last_piece_in_line
 | |
| 	mov	ecx,[embedded_context]
 | |
| 	mov	[edi+LineExcerpt.recognition_context],ecx
 | |
|     cut_piece:
 | |
| 	cmp	al,dh
 | |
| 	je	nested_piece
 | |
| 	cmp	al,dl
 | |
| 	je	close_nested_piece
 | |
| 	cmp	al,[breakpoint_token]
 | |
| 	jne	cut_token
 | |
| 	retn
 | |
|     nested_piece:
 | |
| 	inc	[number_of_enclosings]
 | |
| 	jmp	cut_token
 | |
|     close_nested_piece:
 | |
| 	dec	[number_of_enclosings]
 | |
| 	jz	end_of_piece
 | |
|     cut_token:
 | |
| 	cmp	al,1Ah
 | |
| 	je	cut_token_with_data
 | |
| 	cmp	al,22h
 | |
| 	je	cut_token_with_data
 | |
| 	cmp	al,27h
 | |
| 	je	cut_token_with_data
 | |
| 	cmp	al,30h
 | |
| 	je	cut_internal_token
 | |
| 	inc	esi
 | |
|     cut_next_token:
 | |
| 	mov	[edi+LineExcerpt.data_end],esi
 | |
| 	call	move_to_next_symbol
 | |
| 	jnc	cut_piece
 | |
|     last_piece_in_line:
 | |
| 	xor	al,al
 | |
|     end_of_piece:
 | |
| 	mov	ecx,[embedded_context]
 | |
| 	mov	[edi+LineExcerpt.leftover_context],ecx
 | |
| 	retn
 | |
|     cut_token_with_data:
 | |
| 	add	esi,1+4
 | |
| 	jmp	cut_next_token
 | |
|     cut_internal_token:
 | |
| 	inc	esi
 | |
| 	lodsd
 | |
| 	add	esi,eax
 | |
| 	jmp	cut_next_token
 | |
| 
 | |
| extract_piece_of_line:
 | |
| ; in:
 | |
| ;  esi = pointer into preprocessed line (not an embedded value)
 | |
| ;  edi - buffer for token sequence, must be large enough to hold all the remaining tokens in line and an additional context token
 | |
| ;  dl = initial byte of symbol that should end the cut value, zero to cut up to the end of line
 | |
| ;  dh = initial byte of symbol that would open the nested piece, zero for no nesting
 | |
| ;  [breakpoint_token] = initial byte of symbol that should unconditionally end the cut value if it is met
 | |
| ;  [contextless_processing] = zero to have current context added to the extracted value
 | |
| ; out:
 | |
| ;  esi = pointer advanced past the processed piece
 | |
| ;  edi - end of the extracted sequence of tokens in provided buffer
 | |
| ;  al = initial byte of symbol at pointer, zero when no more symbols there
 | |
| ;  [context_boundary] = equal to edi if the extracted sequence ends with a context token
 | |
| ; preserves: ebx, edx
 | |
| ; note:
 | |
| ;  when [breakpoint_token] has the same value as either dl or dh, it has no effect
 | |
| 	and	[context_boundary],0
 | |
| 	call	move_to_next_symbol
 | |
| 	jc	no_piece_to_extract
 | |
| 	mov	[number_of_enclosings],1
 | |
| 	mov	[whitespace_boundary],edi
 | |
| 	mov	al,40h
 | |
| 	stosb
 | |
| 	mov	eax,[embedded_context]
 | |
| 	test	eax,eax
 | |
| 	jz	extract_current_context
 | |
| 	xchg	esi,eax
 | |
| 	assert	sizeof.RecognitionContext and 11b = 0
 | |
| 	mov	ecx,sizeof.RecognitionContext shr 2
 | |
| 	rep	movsd
 | |
| 	mov	esi,eax
 | |
| 	mov	[context_boundary],edi
 | |
| 	jmp	extract_piece
 | |
|     extract_contextless:
 | |
| 	dec	edi
 | |
| 	jmp	extract_piece
 | |
|     extract_current_context:
 | |
| 	cmp	[contextless_processing],0
 | |
| 	jne	extract_contextless
 | |
| 	call	store_current_context
 | |
|     extract_piece:
 | |
| 	lodsb
 | |
| 	cmp	al,dh
 | |
| 	je	nested_piece_to_extract
 | |
| 	cmp	al,dl
 | |
| 	je	close_extracted_nested_piece
 | |
| 	cmp	al,[breakpoint_token]
 | |
| 	je	extraction_breakpoint
 | |
|     extract_token:
 | |
| 	cmp	al,40h
 | |
| 	je	extract_context_token
 | |
| 	cmp	al,20h
 | |
| 	je	extract_whitespace
 | |
| 	and	[whitespace_boundary],0
 | |
| 	stosb
 | |
| 	cmp	al,1Ah
 | |
| 	je	extract_token_with_data
 | |
| 	cmp	al,22h
 | |
| 	je	extract_token_with_data
 | |
| 	cmp	al,27h
 | |
| 	je	extract_token_with_data
 | |
| 	cmp	al,30h
 | |
| 	je	extract_internal_token
 | |
|     extract_next_token:
 | |
| 	cmp	esi,[line_end]
 | |
| 	jne	extract_piece
 | |
| 	xor	al,al
 | |
| 	cmp	[whitespace_boundary],0
 | |
| 	jne	drop_final_whitespace
 | |
| 	retn
 | |
|     nested_piece_to_extract:
 | |
| 	inc	[number_of_enclosings]
 | |
| 	jmp	extract_token
 | |
|     close_extracted_nested_piece:
 | |
| 	dec	[number_of_enclosings]
 | |
| 	jnz	extract_token
 | |
|     extraction_breakpoint:
 | |
| 	dec	esi
 | |
| 	cmp	[whitespace_boundary],0
 | |
| 	jne	drop_final_whitespace
 | |
| 	retn
 | |
|     drop_final_whitespace:
 | |
| 	mov	edi,[whitespace_boundary]
 | |
| 	retn
 | |
|     no_piece_to_extract:
 | |
| 	xor	al,al
 | |
| 	retn
 | |
|     extract_whitespace:
 | |
| 	cmp	[whitespace_boundary],0
 | |
| 	jne	whitespace_boundary_ok
 | |
| 	mov	[whitespace_boundary],edi
 | |
|     whitespace_boundary_ok:
 | |
| 	stosb
 | |
| 	jmp	extract_next_token
 | |
|     extract_token_with_data:
 | |
| 	movsd
 | |
| 	jmp	extract_next_token
 | |
|     extract_internal_token:
 | |
| 	lodsd
 | |
| 	stosd
 | |
| 	mov	ecx,eax
 | |
| 	rep	movsb
 | |
| 	jmp	extract_next_token
 | |
|     extract_context_token:
 | |
| 	cmp	[whitespace_boundary],0
 | |
| 	jne	context_whitespace_boundary_ok
 | |
| 	mov	[whitespace_boundary],edi
 | |
|     context_whitespace_boundary_ok:
 | |
| 	mov	[embedded_context],esi
 | |
| 	cmp	dword [esi],0
 | |
| 	jne	embedded_context_for_extraction_ok
 | |
| 	and	[embedded_context],0
 | |
|     embedded_context_for_extraction_ok:
 | |
| 	call	make_recognition_context_token
 | |
| 	jmp	extract_next_token
 | |
| 
 | |
| make_recognition_context_token:
 | |
| ; in:
 | |
| ;  al = 40h
 | |
| ;  esi - RecognitionContext (contents of the context token)
 | |
| ;  edi - buffer for the context token
 | |
| ;  [context_boundary] = equal to edi if it is at the end of another context token
 | |
| ;  [contextless_processing] = zero to convert context reset into a context switch capturing the current context
 | |
| ; out:
 | |
| ;  esi - past the processed RecognitionContext
 | |
| ;  edi - past the extracted context token
 | |
| ;  [context_boundary] - past the extracted context token
 | |
| ; preserves: ebx, edx
 | |
| 	cmp	edi,[context_boundary]
 | |
| 	je	reuse_recognition_context
 | |
| 	stosb
 | |
| 	jmp	store_recognition_context
 | |
|     reuse_recognition_context:
 | |
| 	sub	edi,sizeof.RecognitionContext
 | |
|     store_recognition_context:
 | |
|     ; in:
 | |
|     ;  esi - RecognitionContext to read (may have base namespace zeroed to indicate context reset)
 | |
|     ;  edi - RecognitionContext to fill
 | |
|     ; out:
 | |
|     ;  esi - past the processed RecognitionContext
 | |
|     ;  edi - past the filled RecognitionContext
 | |
|     ;  [context_boundary] - past the filled RecognitionContext
 | |
|     ;  [contextless_processing] = zero to convert context reset into a context switch capturing the current context
 | |
|     ; preserves: ebx, edx
 | |
| 	cmp	[contextless_processing],0
 | |
| 	jne	copy_recognition_context
 | |
| 	cmp	[esi+RecognitionContext.base_namespace],0
 | |
| 	je	capture_context_reset
 | |
|       copy_recognition_context:
 | |
| 	assert	sizeof.RecognitionContext and 11b = 0
 | |
| 	mov	ecx,sizeof.RecognitionContext shr 2
 | |
| 	rep	movsd
 | |
| 	mov	[context_boundary],edi
 | |
| 	retn
 | |
|       capture_context_reset:
 | |
| 	add	esi,sizeof.RecognitionContext
 | |
|     store_current_context:
 | |
|     ; in:
 | |
|     ;  edi - RecognitionContext to fill
 | |
|     ; out:
 | |
|     ;  edi - past the filled RecognitionContext
 | |
|     ;  [context_boundary] - past the filled RecognitionContext
 | |
|     ; preserves: ebx, edx, esi
 | |
| 	mov	eax,[current_context.base_namespace]
 | |
| 	mov	ecx,[current_context.base_label]
 | |
| 	mov	[edi+RecognitionContext.base_namespace],eax
 | |
| 	mov	[edi+RecognitionContext.base_label],ecx
 | |
| 	add	edi,sizeof.RecognitionContext
 | |
| 	mov	[context_boundary],edi
 | |
| 	retn
 | |
| 
 | |
| embed_symbolic_value:
 | |
| ; in:
 | |
| ;  ebx - SymbolTree_Leaf
 | |
| ;  edx - ValueDefinition
 | |
| ;  esi = pointer into preprocessed line or current embedded value
 | |
| ;  ecx = number of whitespace tokens to imply after emdedding
 | |
| ; out:
 | |
| ;  esi = pointer into embedded value
 | |
| ; preserves: ebx, edx
 | |
| 	mov	eax,[number_of_line_embeddings]
 | |
| 	inc	eax
 | |
| 	mov	[number_of_line_embeddings],eax
 | |
| 	imul	eax,sizeof.LineEmbedding
 | |
| 	cmp	eax,[line_embeddings_maximum_length]
 | |
| 	jbe	line_embedding_allocated
 | |
| 	push	eax ecx edx
 | |
| 	mov	ecx,sizeof.LineEmbedding
 | |
| 	add	ecx,[line_embeddings_maximum_length]
 | |
| 	mov	eax,[line_embeddings]
 | |
| 	call	grow_stack
 | |
| 	mov	[line_embeddings_maximum_length],ecx
 | |
| 	mov	[line_embeddings],eax
 | |
| 	pop	edx ecx eax
 | |
|     line_embedding_allocated:
 | |
| 	sub	eax,sizeof.LineEmbedding
 | |
| 	add	eax,[line_embeddings]
 | |
| 	mov	[eax+LineEmbedding.whitespace],ecx
 | |
| 	mov	edi,[line_end]
 | |
| 	mov	[eax+LineEmbedding.previous_pointer],esi
 | |
| 	mov	[eax+LineEmbedding.previous_end],edi
 | |
| 	mov	ecx,[embedded_context]
 | |
| 	mov	[eax+LineEmbedding.recognition_context],ecx
 | |
| 	and	[embedded_context],0
 | |
| 	mov	esi,[edx+ValueDefinition.value]
 | |
| 	mov	ecx,[edx+ValueDefinition.value_length]
 | |
| 	add	ecx,esi
 | |
| 	mov	[line_end],ecx
 | |
| 	mov	[eax+LineEmbedding.definition],edx
 | |
| 	inc	[edx+ValueDefinition.reference_count]
 | |
| 	or	[edx+ValueDefinition.flags],VAL_IN_USE
 | |
| 	retn
 | |
| 
 | |
| clear_line_embeddings:
 | |
| ; preserves: ebx, ecx, edx, esi, edi
 | |
| ; note:
 | |
| ;  when esi is said to point into preprocessed line or current embedded value, it must be between [line_start] and [line_end];
 | |
| ;  these two pointers change upon entering a symbolic value of evaluated identifier (with embed_symbolic_value)
 | |
| ;  and are restored when warp_to_next_symbol goes past the end of that embedded value;
 | |
| ;  this function needs to be called before setting up a new line for the assembly
 | |
| ;  and it discards the stack of stored [line_start] and [line_end] boundaries
 | |
| 	xor	eax,eax
 | |
| 	mov	[line_start],eax
 | |
| 	mov	[line_end],eax
 | |
| 	mov	[embedded_context],eax
 | |
| 	cmp	eax,[number_of_line_embeddings]
 | |
| 	je	embedded_values_ok
 | |
| 	push	ecx
 | |
|     discard_line_embedding:
 | |
| 	mov	ecx,eax
 | |
| 	imul	ecx,sizeof.LineEmbedding
 | |
| 	add	ecx,[line_embeddings]
 | |
| 	mov	ecx,[ecx+LineEmbedding.definition]
 | |
| 	dec	[ecx+ValueDefinition.reference_count]
 | |
| 	and	[ecx+ValueDefinition.flags],not VAL_IN_USE
 | |
| 	inc	eax
 | |
| 	cmp	eax,[number_of_line_embeddings]
 | |
| 	jne	discard_line_embedding
 | |
| 	and	[number_of_line_embeddings],0
 | |
| 	pop	ecx
 | |
|     embedded_values_ok:
 | |
| 	retn
 | |
| 
 | |
| identify_symbol_in_namespace:
 | |
| ; in:
 | |
| ;  ebx - SymbolTree_Root
 | |
| ;  esi = pointer into preprocessed line or current embedded value
 | |
| ;  dl = SYMCLASS_#
 | |
| ;  [symbol_definition] = non-zero when symbol needs to be identified for the purpose of definition
 | |
| ; out:
 | |
| ;  cf set when there were no more symbols in preprocessed line or current embedded value
 | |
| ;  esi = pointer advanced past the processed identifier and following whitespace or to the first token of a different symbol
 | |
| ;  ecx = number of whitespace tokens encountered immediately before the new position
 | |
| ;  when cf = 0:
 | |
| ;   ebx - SymbolTree_Leaf, null when no symbol was identified
 | |
| ;   edx - SymbolTree_Foliage, may be null if either ebx or edi is null
 | |
| ;   edi - SymbolTree_Root, null when there was no identifier at all or when identified symbol is not in a namespace
 | |
| ;   [symbol_start] - first token of identified symbol
 | |
| ;   [symbol_independent] = zero when identifier is relative to current label, all bits set for special identifiers
 | |
| ; note:
 | |
| ;  when ebx is null but edi is not, the identifier was malformed
 | |
| ;  when edi is null but ebx is not, a special symbol was identified; this is possible only for SYMCLASS_INSTRUCTION and SYMCLASS_STRUCTURE
 | |
| 	mov	[expected_class],dl
 | |
| 	xor	ecx,ecx
 | |
| 	call	move_to_next_symbol
 | |
| 	jnc	namespaces_ok
 | |
| 	retn
 | |
| identify_symbol:
 | |
| ; in:
 | |
| ;  esi = pointer into preprocessed line or current embedded value
 | |
| ;  dl = SYMCLASS_#
 | |
| ;  [symbol_definition] = non-zero when symbol needs to be identified for the purpose of definition
 | |
| ; out:
 | |
| ;  cf set when there were no more symbols in preprocessed line or current embedded value
 | |
| ;  esi = pointer advanced past the processed identifier and following whitespace or to the first token of a different symbol
 | |
| ;  ecx = number of whitespace tokens encountered immediately before the new position
 | |
| ;  [recognition_context] = applied recognition context
 | |
| ;  when cf = 0:
 | |
| ;   ebx - SymbolTree_Leaf, null when no symbol was identified
 | |
| ;   edx - SymbolTree_Foliage, may be null if either ebx or edi is null
 | |
| ;   edi - SymbolTree_Root, null when there was no identifier at all or when identified symbol is not in a namespace
 | |
| ;   [symbol_start] - first token of identified symbol (within current embedded value or preprocessed line)
 | |
| ;   [symbol_independent] = zero when identifier is relative to current label, all bits set for special identifiers
 | |
| ; note:
 | |
| ;  when ebx is null but edi is not, the identifier was malformed
 | |
| ;  when edi is null but ebx is not, a special symbol was identified; this is possible only for SYMCLASS_INSTRUCTION and SYMCLASS_STRUCTURE
 | |
| 	mov	[expected_class],dl
 | |
| 	xor	ecx,ecx
 | |
| 	call	move_to_next_symbol
 | |
| 	jc	identification_finished
 | |
| 	xor	ebx,ebx
 | |
| 	mov	edx,[embedded_context]
 | |
| 	test	edx,edx
 | |
| 	jnz	use_namespace
 | |
| 	mov	edx,current_context
 | |
|     use_namespace:
 | |
| 	mov	eax,[edx+RecognitionContext.base_namespace]
 | |
| 	mov	[recognition_context.base_namespace],eax
 | |
| 	mov	eax,[edx+RecognitionContext.base_label]
 | |
| 	mov	[recognition_context.base_label],eax
 | |
|     namespaces_ok:
 | |
| 	mov	[symbol_start],esi
 | |
| 	and	[symbol_independent],0
 | |
| 	cmp	[symbol_definition],0
 | |
| 	setnz	al
 | |
| 	shl	al,bsf RECOGNIZE_DEFINITION
 | |
| 	mov	[recognizer_setting],al
 | |
| 	xor	edx,edx
 | |
| 	xor	edi,edi
 | |
| 	mov	al,[esi]
 | |
| 	cmp	al,1Ah
 | |
| 	je	starting_with_name
 | |
| 	cmp	al,'.'
 | |
| 	je	starting_dot
 | |
| 	cmp	al,'#'
 | |
| 	je	starting_with_concatenation
 | |
| 	cmp	al,'?'
 | |
| 	je	starting_question_mark
 | |
|     return_no_identifier:
 | |
| 	xor	ebx,ebx
 | |
|     return_no_namespace:
 | |
| 	xor	edx,edx
 | |
| 	xor	edi,edi
 | |
| 	clc
 | |
| 	retn
 | |
|     starting_with_name:
 | |
| 	call	detect_numeric_symbol
 | |
| 	jc	return_no_identifier
 | |
|     valid_starting_name:
 | |
| 	or	[symbol_independent],1
 | |
|     valid_name:
 | |
| 	inc	esi
 | |
| 	mov	[name_token],esi
 | |
| 	lodsd
 | |
| 	mov	edi,eax
 | |
| 	and	[name_volatile],0
 | |
| 	xor	ecx,ecx
 | |
|     identify_name:
 | |
| 	mov	dh,[recognizer_setting]
 | |
| 	call	move_to_next_symbol
 | |
| 	jc	run_recognizer
 | |
| 	cmp	al,'#'
 | |
| 	jne	name_complete
 | |
| 	call	check_concatenation
 | |
| 	jnc	name_concatenation
 | |
| 	xor	al,al
 | |
|     name_complete:
 | |
| 	test	ecx,ecx
 | |
| 	jnz	run_recognizer
 | |
| 	cmp	al,'?'
 | |
| 	jne	run_recognizer
 | |
| 	or	dh,RECOGNIZE_CASE_INSENSITIVE
 | |
| 	inc	esi
 | |
| 	call	move_to_next_symbol
 | |
| 	jc	run_recognizer
 | |
| 	cmp	al,'#'
 | |
| 	jne	name_modifiers_complete
 | |
| 	call	check_concatenation
 | |
| 	jc	run_recognizer
 | |
|     name_modifiers_complete:
 | |
| 	test	ecx,ecx
 | |
| 	jnz	run_recognizer
 | |
| 	cmp	al,1Ah
 | |
| 	je	malformed_identifier
 | |
|     run_recognizer:
 | |
| 	push	esi ecx
 | |
| 	cmp	esi,[line_end]
 | |
| 	je	recognize_final_symbol
 | |
| 	test	ecx,ecx
 | |
| 	jnz	recognize_final_symbol
 | |
| 	cmp	byte [esi],'.'
 | |
| 	jne	recognize_final_symbol
 | |
| 	mov	esi,edi
 | |
| 	lodsd
 | |
| 	mov	ecx,eax
 | |
| 	mov	dl,SYMCLASS_EXPRESSION
 | |
| 	and	dh,not RECOGNIZE_DEFINITION
 | |
| 	call	recognize_symbol
 | |
| 	pop	ecx esi
 | |
|     dot_operator:
 | |
| 	inc	esi
 | |
| 	xor	ecx,ecx
 | |
| 	call	move_to_next_symbol
 | |
| 	jc	ending_with_dot
 | |
| 	cmp	al,'#'
 | |
| 	je	name_concatenation_after_dot
 | |
| 	test	ecx,ecx
 | |
| 	jnz	ending_with_dot
 | |
| 	cmp	al,'.'
 | |
| 	je	multiple_dot_operator
 | |
|     identify_name_after_dot:
 | |
| 	cmp	al,30h
 | |
| 	je	number_after_dot
 | |
| 	cmp	al,1Ah
 | |
| 	jne	ending_with_dot
 | |
| 	call	get_symbol_namespace
 | |
| 	xor	edi,edi
 | |
| 	jmp	valid_name
 | |
|     name_concatenation_after_dot:
 | |
| 	call	check_concatenation
 | |
| 	jc	ending_with_dot
 | |
| 	cmp	al,'.'
 | |
| 	je	multiple_dot_operator
 | |
|     number_after_dot:
 | |
| 	call	get_symbol_namespace
 | |
| 	mov	al,[esi]
 | |
| 	xor	edi,edi
 | |
| 	jmp	name_concatenation
 | |
|     recognize_final_symbol:
 | |
| 	mov	dl,[expected_class]
 | |
| 	mov	esi,edi
 | |
| 	lodsd
 | |
| 	mov	ecx,eax
 | |
| 	call	recognize_symbol
 | |
| 	pop	ecx esi
 | |
|     symbol_identified:
 | |
| 	clc
 | |
|     identification_finished:
 | |
| 	retn
 | |
|     ending_with_dot:
 | |
| 	mov	al,[expected_class]
 | |
| 	cmp	al,SYMCLASS_EXPRESSION
 | |
| 	jne	find_expected_class
 | |
| 	clc
 | |
| 	retn
 | |
|     starting_question_mark:
 | |
| 	inc	esi
 | |
| 	xor	ecx,ecx
 | |
| 	call	move_to_next_symbol
 | |
| 	jc	alone_question_mark
 | |
| 	cmp	al,'#'
 | |
| 	jne	symbol_after_question_mark
 | |
| 	call	check_concatenation
 | |
| 	jc	alone_question_mark
 | |
|     symbol_after_question_mark:
 | |
| 	test	ecx,ecx
 | |
| 	jnz	alone_question_mark
 | |
| 	cmp	al,'?'
 | |
| 	je	repeated_question_mark
 | |
| 	cmp	[symbol_definition],0
 | |
| 	jne	no_forced_definition
 | |
| 	mov	[expected_class],SYMCLASS_EXPRESSION
 | |
| 	or	[recognizer_setting],RECOGNIZE_DEFINITION
 | |
|     no_forced_definition:
 | |
| 	cmp	al,'.'
 | |
| 	je	starting_dot
 | |
| 	cmp	al,1Ah
 | |
| 	je	valid_starting_name
 | |
| 	cmp	al,30h
 | |
| 	je	concatenation_with_internal_number
 | |
|     alone_question_mark:
 | |
| 	mov	dl,[expected_class]
 | |
| 	cmp	dl,SYMCLASS_INSTRUCTION
 | |
| 	je	return_interceptor_symbol
 | |
| 	cmp	dl,SYMCLASS_STRUCTURE
 | |
| 	je	return_label_interceptor_symbol
 | |
| 	mov	eax,[symbol_start]
 | |
| 	cmp	byte [eax],'?'
 | |
| 	jne	malformed_identifier
 | |
| 	mov	esi,eax
 | |
| 	jmp	return_no_identifier
 | |
|     return_label_interceptor_symbol:
 | |
| 	mov	ebx,[label_interceptor_symbol]
 | |
| 	jmp	return_special_symbol
 | |
|     return_interceptor_symbol:
 | |
| 	mov	ebx,[interceptor_symbol]
 | |
|     return_special_symbol:
 | |
| 	or	[symbol_independent],-1
 | |
| 	jmp	return_no_namespace
 | |
|     repeated_question_mark:
 | |
| 	inc	esi
 | |
| 	xor	ecx,ecx
 | |
| 	call	move_to_next_symbol
 | |
| 	jc	return_other_interceptor_symbol
 | |
| 	cmp	al,'#'
 | |
| 	jne	return_other_interceptor_symbol
 | |
| 	call	check_concatenation
 | |
| 	jnc	symbol_after_question_mark
 | |
|     return_other_interceptor_symbol:
 | |
| 	cmp	[expected_class],SYMCLASS_INSTRUCTION
 | |
| 	jne	malformed_identifier
 | |
| 	mov	ebx,[other_interceptor_symbol]
 | |
| 	jmp	return_special_symbol
 | |
|     multiple_dot_operator:
 | |
| 	mov	ebx,edi
 | |
| 	xor	edi,edi
 | |
| 	jmp	starting_dot
 | |
|     additional_dot:
 | |
| 	inc	edi
 | |
|     starting_dot:
 | |
| 	inc	esi
 | |
| 	xor	ecx,ecx
 | |
| 	call	move_to_next_symbol
 | |
| 	jc	alone_dot
 | |
| 	cmp	al,'#'
 | |
| 	jne	symbol_after_starting_dot
 | |
| 	call	check_concatenation
 | |
| 	jc	alone_dot
 | |
|     symbol_after_starting_dot:
 | |
| 	test	ecx,ecx
 | |
| 	jnz	alone_dot
 | |
| 	cmp	al,'.'
 | |
| 	je	additional_dot
 | |
| 	cmp	al,30h
 | |
| 	je	name_after_starting_dot
 | |
| 	cmp	al,1Ah
 | |
| 	jne	alone_dot
 | |
|     name_after_starting_dot:
 | |
| 	test	ebx,ebx
 | |
| 	jnz	name_after_multiple_dot_operator
 | |
| 	call	get_base_label
 | |
| 	mov	edi,ebx
 | |
| 	mov	al,[esi]
 | |
| 	jmp	identify_name_after_dot
 | |
|     name_after_multiple_dot_operator:
 | |
| 	test	edx,edx
 | |
| 	jz	parent_namespace_ready
 | |
| 	call	get_symbol_namespace
 | |
|     parent_namespace_ready:
 | |
| 	call	synthesize_dot_label
 | |
| 	mov	edi,ebx
 | |
| 	mov	al,[esi]
 | |
| 	jmp	identify_name_after_dot
 | |
|     alone_dot:
 | |
| 	test	ebx,ebx
 | |
| 	jz	identify_current_label
 | |
| 	test	edx,edx
 | |
| 	jz	malformed_identifier
 | |
| 	push	ecx
 | |
| 	call	get_symbol_namespace
 | |
| 	pop	ecx
 | |
| 	call	synthesize_dot_label
 | |
| 	jmp	get_label_symbol
 | |
|     malformed_identifier:
 | |
| 	xor	ebx,ebx
 | |
| 	xor	edx,edx
 | |
| 	mov	edi,[recognition_context.base_namespace]
 | |
| 	jmp	symbol_identified
 | |
|     identify_current_label:
 | |
| 	call	get_base_label
 | |
| 	mov	eax,[local_namespace]
 | |
| 	test	eax,eax
 | |
| 	jz	get_label_symbol
 | |
| 	cmp	edx,[eax+SymbolTree_Root.current_label]
 | |
| 	jne	get_label_symbol
 | |
| 	test	[eax+SymbolTree_Root.flags],NAMESPACE_LABEL_FORWARDING
 | |
| 	setnz	[symbol_independent]
 | |
|     get_label_symbol:
 | |
| 	mov	edi,ebx
 | |
| 	mov	al,[expected_class]
 | |
|     find_expected_class:
 | |
| 	mov	[symbol_class],al
 | |
| 	mov	al,[symbol_definition]
 | |
| 	mov	[symbol_required],al
 | |
| 	mov	[symbol_expected],al
 | |
| 	mov	ebx,edx
 | |
| 	call	scan_symbol_branch
 | |
| 	jnc	current_label_identified
 | |
| 	mov	[symbol_class],SYMCLASS_EXPRESSION
 | |
| 	or	[symbol_required],1
 | |
| 	or	[symbol_expected],1
 | |
| 	mov	ebx,edx
 | |
| 	call	scan_symbol_branch
 | |
|       current_label_identified:
 | |
| 	clc
 | |
| 	retn
 | |
|     get_base_label:
 | |
| 	mov	edx,[recognition_context.base_label]
 | |
| 	test	edi,edi
 | |
| 	jnz	synthesize_dot_label
 | |
| 	test	edx,edx
 | |
| 	jnz	current_label_ready
 | |
|     synthesize_dot_label:
 | |
| 	push	ecx esi
 | |
| 	mov	esi,[identifier_workspace.memory_start]
 | |
| 	mov	eax,edi
 | |
| 	mov	[esi],eax
 | |
| 	mov	edx,FNV_OFFSET
 | |
| 	xor	ecx,ecx
 | |
|       hash_dot_label:
 | |
| 	test	eax,eax
 | |
| 	jz	dot_label_synthesised
 | |
| 	xor	dl,al
 | |
| 	imul	edx,FNV_PRIME
 | |
| 	inc	ecx
 | |
| 	shr	eax,8
 | |
| 	jmp	hash_dot_label
 | |
|       dot_label_synthesised:
 | |
| 	or	[name_volatile],1
 | |
| 	and	[name_token],0
 | |
| 	mov	[name_kind],NAME_NUMERIC
 | |
| 	mov	[symbol_class],SYMCLASS_EXPRESSION
 | |
| 	or	[symbol_required],1
 | |
| 	or	[symbol_expected],1
 | |
| 	test	ebx,ebx
 | |
| 	jnz	identify_dot_label
 | |
| 	mov	ebx,[recognition_context.base_namespace]
 | |
|       identify_dot_label:
 | |
| 	call	scan_namespace
 | |
| 	pop	esi ecx
 | |
|       current_label_ready:
 | |
| 	mov	ebx,[edx+SymbolTree_Foliage.root]
 | |
| 	retn
 | |
|     starting_with_concatenation:
 | |
| 	xor	ecx,ecx
 | |
| 	call	check_concatenation
 | |
| 	jc	empty_concatenation
 | |
|     name_concatenation:
 | |
| 	cmp	al,30h
 | |
| 	je	concatenation_with_internal_number
 | |
| 	cmp	al,1Ah
 | |
| 	jne	empty_concatenation
 | |
| 	test	edi,edi
 | |
| 	jz	starting_with_name
 | |
| 	inc	esi
 | |
| 	lodsd
 | |
| 	push	ebx esi
 | |
| 	mov	ebx,eax
 | |
|     attach_to_name:
 | |
| 	mov	esi,edi
 | |
| 	mov	edi,[identifier_workspace.memory_start]
 | |
| 	cmp	esi,edi
 | |
| 	jne	initial_concatenation
 | |
| 	lodsd
 | |
| 	add	esi,eax
 | |
| 	mov	edi,esi
 | |
| 	jmp	get_precalculated_hashes
 | |
|     initial_concatenation:
 | |
| 	test	esi,esi
 | |
| 	jz	initial_conversion
 | |
| 	mov	ecx,[esi]
 | |
| 	add	ecx,4+8
 | |
| 	mov	edx,identifier_workspace
 | |
| 	call	reserve_workspace
 | |
| 	lodsd
 | |
| 	stosd
 | |
| 	mov	ecx,eax
 | |
| 	rep	movsb
 | |
|     get_precalculated_hashes:
 | |
| 	xchg	ebx,esi
 | |
| 	mov	ecx,[esi]
 | |
| 	mov	eax,[identifier_workspace.memory_start]
 | |
| 	add	[eax],ecx
 | |
| 	add	ecx,8
 | |
| 	mov	edx,identifier_workspace
 | |
| 	call	reserve_workspace
 | |
| 	mov	ecx,[ebx]
 | |
| 	mov	edx,[ebx+4]
 | |
| 	lodsd
 | |
| 	lea	ebx,[esi+eax]
 | |
| 	xor	eax,eax
 | |
|     concatenation_hash:
 | |
| 	lodsb
 | |
| 	xor	cl,al
 | |
| 	xor	dl,[characters+eax]
 | |
| 	imul	ecx,FNV_PRIME
 | |
| 	imul	edx,FNV_PRIME
 | |
| 	stosb
 | |
| 	cmp	esi,ebx
 | |
| 	jne	concatenation_hash
 | |
| 	mov	eax,ecx
 | |
| 	stosd
 | |
| 	mov	eax,edx
 | |
| 	stosd
 | |
| 	pop	esi ebx
 | |
| 	mov	edi,[identifier_workspace.memory_start]
 | |
| 	or	[name_volatile],1
 | |
| 	and	[name_token],0
 | |
| 	xor	ecx,ecx
 | |
| 	jmp	identify_name
 | |
|     initial_conversion:
 | |
| 	xor	eax,eax
 | |
| 	stosd
 | |
| 	mov	esi,edi
 | |
| 	mov	eax,FNV_OFFSET
 | |
| 	mov	[esi],eax
 | |
| 	mov	[esi+4],eax
 | |
| 	jmp	get_precalculated_hashes
 | |
|     concatenation_with_internal_number:
 | |
| 	inc	esi
 | |
| 	mov	edx,esi
 | |
| 	lodsd
 | |
| 	add	esi,eax
 | |
| 	push	ebx esi
 | |
| 	push	edi
 | |
| 	call	convert_number_back
 | |
| 	pop	edi
 | |
| 	mov	ebx,edx
 | |
| 	jmp	attach_to_name
 | |
|     empty_concatenation:
 | |
| 	test	edi,edi
 | |
| 	jnz	identify_name_with_empty_concatenation
 | |
| 	call	move_to_next_symbol
 | |
| 	jc	malformed_identifier
 | |
| 	cmp	al,'.'
 | |
| 	je	starting_dot
 | |
| 	cmp	al,'?'
 | |
| 	je	starting_question_mark
 | |
| 	jmp	malformed_identifier
 | |
|     identify_name_with_empty_concatenation:
 | |
| 	mov	dh,[recognizer_setting]
 | |
| 	call	move_to_next_symbol
 | |
| 	jc	run_recognizer
 | |
| 	jmp	name_complete
 | |
| 
 | |
| detect_numeric_symbol:
 | |
| ; in:
 | |
| ;  esi - name token in preprocessed line or in current embedded value
 | |
| ; out:
 | |
| ;  cf set when symbol starting with this token should be considered numeric
 | |
| ; preserves: ebx, ecx, edx, esi, edi
 | |
| 	mov	eax,[esi+1]
 | |
| 	mov	al,[eax+4]
 | |
| 	cmp	al,'$'
 | |
| 	je	detect_pascal_hexadecimal
 | |
| 	sub	al,'0'
 | |
| 	cmp	al,10
 | |
| 	jb	numeric_symbol_detected
 | |
|       not_a_numeric_symbol:
 | |
| 	clc
 | |
| 	retn
 | |
|       detect_pascal_hexadecimal:
 | |
| 	mov	eax,[esi+1]
 | |
| 	cmp	dword [eax],2
 | |
| 	jb	not_a_numeric_symbol
 | |
| 	movzx	eax,byte [eax+4+1]
 | |
| 	mov	al,[characters+eax]
 | |
| 	sub	al,'0'
 | |
| 	cmp	al,10
 | |
| 	jb	numeric_symbol_detected
 | |
| 	sub	al,'a'-'0'
 | |
| 	jc	not_a_numeric_symbol
 | |
| 	cmp	al,16-10
 | |
| 	jae	not_a_numeric_symbol
 | |
|       numeric_symbol_detected:
 | |
| 	stc
 | |
| 	retn
 | |
| 
 | |
| check_concatenation:
 | |
| ; in:
 | |
| ;  esi - concatenation character in preprocessed line or in current embedded value
 | |
| ;  ecx = number of whitespace tokens encountered immediately before current position
 | |
| ; out:
 | |
| ;  cf set when there is no concatenation applicable to previous symbol
 | |
| ;  esi = pointer advanced past the processed operator and the whitespace that follows it
 | |
| ;  ecx = number of whitespace tokens encountered immediately before the new position
 | |
| ;  when cf = 0:
 | |
| ;   esi - symbol that follows concatenation operator
 | |
| ;   al = initial byte of symbol following concatenation operator
 | |
| ; preserves: ebx, edx, edi
 | |
| 	test	ecx,ecx
 | |
| 	jnz	no_concatenation
 | |
| 	inc	esi
 | |
| 	call	move_to_next_symbol
 | |
| 	jc	no_concatenation
 | |
| 	cmp	al,'#'
 | |
| 	je	check_concatenation
 | |
| 	test	ecx,ecx
 | |
| 	jnz	no_concatenation
 | |
|       ; clc
 | |
| 	retn
 | |
|     no_concatenation:
 | |
| 	stc
 | |
| 	retn
 | |
| 
 | |
| get_literal:
 | |
| ; in:
 | |
| ;  esi - token in preprocessed line or in current embedded value
 | |
| ; out:
 | |
| ;  al = type of value
 | |
| ;  esi = pointer advanced past the processed literal and the whitespace that follows it
 | |
| ;  ecx = number of whitespace tokens encountered immediately before the new position
 | |
| ;  when al = 22h:
 | |
| ;   edx - 32-bit length followed by string data
 | |
| ;  when al = 30h:
 | |
| ;   edx - 32-bit length followed by numeric data, null when invalid number
 | |
| ;  when al = 2Eh:
 | |
| ;   edx - FloatData, null when invalid number
 | |
| ;  when al is any other value, it is a simple special character, and edx is zero
 | |
| 	xor	ecx,ecx
 | |
| 	mov	al,[esi]
 | |
| 	cmp	al,1Ah
 | |
| 	je	get_literal_number
 | |
| 	cmp	al,22h
 | |
| 	je	get_literal_string
 | |
| 	cmp	al,27h
 | |
| 	je	missing_end_quote
 | |
| 	cmp	al,30h
 | |
| 	je	get_internal_number
 | |
| 	inc	esi
 | |
| 	mov	dl,al
 | |
| 	call	move_to_next_symbol
 | |
| 	mov	al,dl
 | |
| 	xor	edx,edx
 | |
| 	retn
 | |
|     get_literal_number:
 | |
| 	mov	edx,[esi+1]
 | |
| 	add	esi,5
 | |
|     check_for_more_parts_of_number:
 | |
| 	call	move_to_next_symbol
 | |
| 	jc	number_ready_for_conversion
 | |
| 	test	ecx,ecx
 | |
| 	jnz	check_for_number_concatenation
 | |
| 	cmp	al,'.'
 | |
| 	je	get_literal_float
 | |
|     check_for_number_concatenation:
 | |
| 	cmp	al,'#'
 | |
| 	jne	number_ready_for_conversion
 | |
| 	call	check_concatenation
 | |
| 	jc	number_ready_for_conversion
 | |
|     number_concatenation:
 | |
| 	cmp	al,30h
 | |
| 	je	attach_internal_number_to_number
 | |
| 	cmp	al,'.'
 | |
| 	je	get_literal_float
 | |
| 	cmp	al,1Ah
 | |
| 	jne	number_ready_for_conversion
 | |
|     attach_name_to_number:
 | |
| 	mov	ebx,[esi+1]
 | |
| 	add	esi,5
 | |
| 	push	esi
 | |
|     attach_to_number:
 | |
| 	mov	esi,edx
 | |
| 	mov	edi,[identifier_workspace.memory_start]
 | |
| 	cmp	esi,edi
 | |
| 	jne	initial_concatenation_of_number
 | |
| 	lodsd
 | |
| 	add	esi,eax
 | |
| 	mov	edi,esi
 | |
| 	jmp	attach_segment_of_number
 | |
|     initial_concatenation_of_number:
 | |
| 	mov	ecx,[esi]
 | |
| 	add	ecx,4
 | |
| 	mov	edx,identifier_workspace
 | |
| 	call	reserve_workspace
 | |
| 	lodsd
 | |
| 	stosd
 | |
| 	mov	ecx,eax
 | |
| 	rep	movsb
 | |
|     attach_segment_of_number:
 | |
| 	mov	esi,ebx
 | |
| 	mov	ecx,[esi]
 | |
| 	mov	eax,[identifier_workspace.memory_start]
 | |
| 	add	[eax],ecx
 | |
| 	mov	edx,identifier_workspace
 | |
| 	call	reserve_workspace
 | |
| 	lodsd
 | |
| 	mov	ecx,eax
 | |
| 	rep	movsb
 | |
| 	pop	esi
 | |
| 	mov	edx,[identifier_workspace.memory_start]
 | |
| 	jmp	check_for_more_parts_of_number
 | |
|     attach_internal_number_to_number:
 | |
| 	mov	ebx,edx
 | |
| 	inc	esi
 | |
| 	mov	edx,esi
 | |
| 	lodsd
 | |
| 	add	esi,eax
 | |
| 	push	esi
 | |
| 	push	ebx
 | |
| 	call	convert_number_back
 | |
| 	mov	ebx,edx
 | |
| 	pop	edx
 | |
| 	jmp	attach_to_number
 | |
|     number_ready_for_conversion:
 | |
| 	push	ecx
 | |
| 	call	convert_number
 | |
| 	pop	ecx
 | |
| 	jc	get_literal_float
 | |
| 	mov	al,30h
 | |
| 	retn
 | |
|     missing_end_quote:
 | |
| 	mov	edx,_missing_end_quote
 | |
| 	call	register_error
 | |
|     get_literal_string:
 | |
| 	mov	edx,[esi+1]
 | |
| 	add	esi,5
 | |
| 	call	move_to_next_symbol
 | |
| 	mov	al,22h
 | |
| 	retn
 | |
|     get_internal_number:
 | |
| 	lea	edx,[esi+1]
 | |
| 	mov	eax,[edx]
 | |
| 	lea	esi,[esi+1+4+eax]
 | |
| 	call	move_to_next_symbol
 | |
| 	jc	internal_number_ready
 | |
| 	test	ecx,ecx
 | |
| 	jnz	check_for_internal_number_concatenation
 | |
| 	cmp	al,'.'
 | |
| 	je	convert_internal_number_back
 | |
|     check_for_internal_number_concatenation:
 | |
| 	cmp	al,'#'
 | |
| 	jne	internal_number_ready
 | |
| 	call	check_concatenation
 | |
| 	jc	internal_number_ready
 | |
| 	cmp	al,1Ah
 | |
| 	je	convert_internal_number_back
 | |
| 	cmp	al,30h
 | |
| 	jne	internal_number_ready
 | |
|     convert_internal_number_back:
 | |
| 	push	esi
 | |
| 	call	convert_number_back
 | |
| 	mov	esi,edx
 | |
| 	mov	ecx,[esi]
 | |
| 	add	ecx,4
 | |
| 	mov	edi,[identifier_workspace.memory_start]
 | |
| 	mov	edx,identifier_workspace
 | |
| 	call	reserve_workspace
 | |
| 	lodsd
 | |
| 	stosd
 | |
| 	mov	ecx,eax
 | |
| 	rep	movsb
 | |
| 	pop	esi
 | |
| 	mov	edx,[identifier_workspace.memory_start]
 | |
| 	mov	al,[esi]
 | |
| 	jmp	number_concatenation
 | |
|     internal_number_ready:
 | |
| 	mov	al,30h
 | |
| 	retn
 | |
|     get_literal_float:
 | |
| 	xor	eax,eax
 | |
| 	mov	[zero_digits],eax
 | |
| 	mov	[decimal_places],eax
 | |
| 	mov	[literal_exponent],eax
 | |
| 	mov	[literal_exponent_sign],al
 | |
| 	mov	[literal_fractional_part],al
 | |
| 	mov	[waiting_for_digit],al
 | |
| 	mov	[float_literal_status],al
 | |
| 	push	esi ecx
 | |
| 	mov	ebx,edx
 | |
| 	call	start_decimal_converter
 | |
| 	lea	esi,[ebx+4]
 | |
| 	mov	ecx,[ebx]
 | |
|     get_float_digit:
 | |
| 	lodsb
 | |
| 	cmp	al,27h
 | |
| 	je	skip_float_digit
 | |
| 	cmp	al,'_'
 | |
| 	je	skip_float_digit
 | |
| 	cmp	al,'9'
 | |
| 	ja	float_nondigit
 | |
| 	sub	al,'0'
 | |
| 	jz	float_digit_zero
 | |
| 	jc	float_nondigit
 | |
| 	test	[float_literal_status],1
 | |
| 	jnz	reject_float_digit
 | |
| 	inc	[decimal_places]
 | |
| 	push	esi ecx
 | |
| 	xor	ecx,ecx
 | |
| 	xchg	ecx,[zero_digits]
 | |
| 	call	convert_decimal_digit
 | |
| 	pop	ecx esi
 | |
| 	and	[waiting_for_digit],0
 | |
|       skip_float_digit:
 | |
| 	loop	get_float_digit
 | |
| 	jmp	float_digits_ok
 | |
|       float_digit_zero:
 | |
| 	test	[float_literal_status],1
 | |
| 	jnz	reject_float_digit
 | |
| 	inc	[decimal_places]
 | |
| 	inc	[zero_digits]
 | |
| 	and	[waiting_for_digit],0
 | |
| 	loop	get_float_digit
 | |
|       float_digits_ok:
 | |
| 	pop	ecx esi
 | |
| 	call	move_to_next_symbol
 | |
| 	jc	no_more_tokens_in_float
 | |
| 	cmp	al,'.'
 | |
| 	je	decimal_point
 | |
| 	cmp	al,'#'
 | |
| 	jne	no_more_tokens_in_float
 | |
| 	call	check_concatenation
 | |
| 	jc	no_more_tokens_in_float
 | |
| 	jmp	next_token_in_float
 | |
|     decimal_point:
 | |
| 	test	ecx,ecx
 | |
| 	jnz	no_more_tokens_in_float
 | |
| 	mov	al,[literal_fractional_part]
 | |
| 	or	al,[literal_exponent_sign]
 | |
| 	jz	decimal_point_allowed
 | |
| 	or	[float_literal_status],-1
 | |
|     decimal_point_allowed:
 | |
| 	or	[literal_fractional_part],1
 | |
| 	or	[waiting_for_digit],1
 | |
| 	and	[decimal_places],0
 | |
|     get_following_digits:
 | |
| 	inc	esi
 | |
| 	xor	ecx,ecx
 | |
| 	call	move_to_adjacent_symbol
 | |
| 	jc	invalid_float_value
 | |
|     next_token_in_float:
 | |
| 	cmp	al,1Ah
 | |
| 	je	next_digits_section
 | |
| 	cmp	al,30h
 | |
| 	je	internal_number_as_digits
 | |
|     no_more_tokens_in_float:
 | |
| 	cmp	[waiting_for_digit],0
 | |
| 	jne	invalid_float_value
 | |
| 	cmp	[float_literal_status],-1
 | |
| 	je	invalid_float_value
 | |
| 	call	finish_decimal_conversion
 | |
| 	push	esi ecx
 | |
| 	mov	esi,edi
 | |
| 	xor	ecx,ecx
 | |
| 	cmp	[literal_fractional_part],0
 | |
| 	je	float_decimal_places_ok
 | |
| 	mov	ecx,[decimal_places]
 | |
|       float_decimal_places_ok:
 | |
| 	sub	ecx,[zero_digits]
 | |
| 	neg	ecx
 | |
| 	add	ecx,[literal_exponent]
 | |
| 	jo	float_conversion_failed
 | |
| 	call	multiply_float_by_power_of_ten
 | |
| 	test	[edi+FloatData.attributes],FLOAT_INFINITE or FLOAT_INDETERMINATE or FLOAT_UNDERFLOW
 | |
| 	jnz	float_conversion_failed
 | |
| 	mov	edx,edi
 | |
| 	pop	ecx esi
 | |
| 	mov	al,2Eh
 | |
| 	retn
 | |
|     float_conversion_failed:
 | |
| 	pop	ecx esi
 | |
|     invalid_float_value:
 | |
| 	xor	edx,edx
 | |
| 	mov	al,2Eh
 | |
| 	retn
 | |
|     next_digits_section:
 | |
| 	inc	esi
 | |
| 	lodsd
 | |
| 	xor	ecx,ecx
 | |
| 	push	esi ecx
 | |
| 	mov	esi,eax
 | |
| 	lodsd
 | |
| 	mov	ecx,eax
 | |
| 	cmp	[literal_exponent_sign],0
 | |
| 	jne	get_exponent_digit
 | |
| 	jmp	get_float_digit
 | |
|     internal_number_as_digits:
 | |
| 	inc	esi
 | |
| 	mov	edx,esi
 | |
| 	lodsd
 | |
| 	add	esi,eax
 | |
| 	xor	ecx,ecx
 | |
| 	push	esi ecx
 | |
| 	call	convert_number_back
 | |
| 	mov	esi,edx
 | |
| 	lodsd
 | |
| 	mov	ecx,eax
 | |
| 	cmp	[literal_exponent_sign],0
 | |
| 	jne	get_exponent_digit
 | |
| 	jmp	get_float_digit
 | |
|     get_literal_exponent:
 | |
| 	mov	al,1
 | |
| 	xchg	al,[literal_exponent_sign]
 | |
| 	test	al,al
 | |
| 	jnz	reject_exponent_digit
 | |
| 	or	[waiting_for_digit],1
 | |
| 	loop	get_exponent_digit
 | |
| 	pop	ecx esi
 | |
| 	call	move_to_adjacent_symbol
 | |
| 	jc	invalid_float_value
 | |
| 	cmp	al,1Ah
 | |
| 	je	next_digits_section
 | |
| 	cmp	al,30h
 | |
| 	je	internal_number_as_digits
 | |
| 	cmp	al,'+'
 | |
| 	je	get_following_digits
 | |
| 	cmp	al,'-'
 | |
| 	jne	invalid_float_value
 | |
| 	neg	[literal_exponent_sign]
 | |
| 	jmp	get_following_digits
 | |
|     get_exponent_digit:
 | |
| 	xor	eax,eax
 | |
| 	lodsb
 | |
| 	cmp	al,27h
 | |
| 	je	skip_exponent_digit
 | |
| 	cmp	al,'_'
 | |
| 	je	skip_exponent_digit
 | |
| 	sub	al,'0'
 | |
| 	jc	reject_exponent_digit
 | |
| 	cmp	al,10
 | |
| 	jae	reject_exponent_digit
 | |
| 	test	[float_literal_status],1
 | |
| 	jnz	reject_exponent_digit
 | |
| 	mov	edx,[literal_exponent]
 | |
| 	imul	edx,10
 | |
| 	jo	reject_exponent_digit
 | |
| 	cmp	[literal_exponent_sign],0
 | |
| 	jnl	exponent_digit_ok
 | |
| 	neg	eax
 | |
|       exponent_digit_ok:
 | |
| 	add	edx,eax
 | |
| 	jo	reject_exponent_digit
 | |
| 	mov	[literal_exponent],edx
 | |
| 	and	[waiting_for_digit],0
 | |
|       skip_exponent_digit:
 | |
| 	loop	get_exponent_digit
 | |
| 	jmp	float_digits_ok
 | |
|       reject_exponent_digit:
 | |
| 	or	[float_literal_status],-1
 | |
| 	jmp	skip_exponent_digit
 | |
|     float_nondigit:
 | |
| 	cmp	[waiting_for_digit],0
 | |
| 	jne	reject_float_digit
 | |
| 	movzx	eax,byte [esi-1]
 | |
| 	mov	al,[characters+eax]
 | |
| 	cmp	al,'e'
 | |
| 	je	get_literal_exponent
 | |
| 	cmp	al,'f'
 | |
| 	jne	reject_float_digit
 | |
| 	or	[float_literal_status],1
 | |
| 	jmp	skip_float_digit
 | |
|       reject_float_digit:
 | |
| 	or	[float_literal_status],-1
 | |
| 	jmp	skip_float_digit
 | |
|     move_to_adjacent_symbol:
 | |
| 	call	move_to_next_symbol
 | |
| 	jc	adjacent_symbol_ok
 | |
| 	cmp	al,'#'
 | |
| 	je	check_concatenation
 | |
| 	neg	ecx
 | |
|       adjacent_symbol_ok:
 | |
| 	retn
 | |
| 
 | |
| skip_literal:
 | |
| ; in:
 | |
| ;  esi - token in preprocessed line or in current embedded value
 | |
| ; out:
 | |
| ;  esi = pointer advanced past the processed literal and the whitespace that follows it
 | |
| ;  ecx = number of whitespace tokens encountered immediately before the new position
 | |
| 	xor	ecx,ecx
 | |
| 	mov	al,[esi]
 | |
| 	cmp	al,1Ah
 | |
| 	je	skip_literal_number
 | |
| 	cmp	al,22h
 | |
| 	je	skip_literal_string
 | |
| 	cmp	al,27h
 | |
| 	je	skip_literal_string
 | |
| 	cmp	al,30h
 | |
| 	je	skip_internal_number
 | |
| 	inc	esi
 | |
| 	call	move_to_next_symbol
 | |
| 	retn
 | |
|     skip_literal_string:
 | |
| 	add	esi,5
 | |
| 	call	move_to_next_symbol
 | |
| 	retn
 | |
|     skip_literal_number:
 | |
| 	xor	dh,dh
 | |
| 	inc	esi
 | |
| 	lodsd
 | |
| 	mov	dl,[eax+4]
 | |
| 	cmp	dl,'0'
 | |
| 	jb	skip_number_segments
 | |
| 	cmp	dl,'9'
 | |
| 	ja	skip_number_segments
 | |
| 	or	dh,1
 | |
|     check_for_possible_exponent:
 | |
| 	mov	ecx,[eax]
 | |
| 	mov	dl,[eax+4+ecx-1]
 | |
| 	cmp	dl,'e'
 | |
| 	je	possible_exponent
 | |
| 	cmp	dl,'E'
 | |
| 	jne	skip_number_segments
 | |
|     possible_exponent:
 | |
| 	or	dh,2
 | |
| 	jmp	skip_number_segments
 | |
|     skip_internal_number:
 | |
| 	inc	esi
 | |
| 	lodsd
 | |
| 	add	esi,eax
 | |
| 	mov	dh,1
 | |
|     skip_number_segments:
 | |
| 	xor	ecx,ecx
 | |
| 	call	move_to_next_symbol
 | |
| 	jc	literal_symbol_skipped
 | |
| 	cmp	al,'#'
 | |
| 	je	check_literal_concatenation
 | |
| 	test	ecx,ecx
 | |
| 	jnz	literal_symbol_skipped
 | |
| 	cmp	al,'.'
 | |
| 	jne	check_for_exponent
 | |
|     skip_decimal_point:
 | |
| 	inc	esi
 | |
| 	xor	ecx,ecx
 | |
| 	call	move_to_next_symbol
 | |
| 	jc	literal_symbol_skipped
 | |
| 	cmp	al,'#'
 | |
| 	je	check_literal_concatenation
 | |
| 	test	ecx,ecx
 | |
| 	jnz	literal_symbol_skipped
 | |
|     skip_attached_segment:
 | |
| 	cmp	al,'.'
 | |
| 	je	skip_decimal_point
 | |
| 	cmp	al,30h
 | |
| 	je	skip_attached_internal_number
 | |
| 	cmp	al,1Ah
 | |
| 	jne	check_for_exponent
 | |
|     skip_attached_number:
 | |
| 	inc	esi
 | |
| 	lodsd
 | |
| 	test	dh,1
 | |
| 	jnz	check_for_possible_exponent
 | |
| 	jmp	skip_number_segments
 | |
|     skip_attached_internal_number:
 | |
| 	inc	esi
 | |
| 	lodsd
 | |
| 	add	esi,eax
 | |
| 	and	dh,not 2
 | |
| 	jmp	skip_number_segments
 | |
|     check_for_exponent:
 | |
| 	cmp	dh,1+2
 | |
| 	jne	literal_symbol_skipped
 | |
| 	cmp	al,'+'
 | |
| 	je	skip_exponent
 | |
| 	cmp	al,'-'
 | |
| 	jne	literal_symbol_skipped
 | |
|     skip_exponent:
 | |
| 	xor	dh,dh
 | |
| 	jmp	skip_decimal_point
 | |
|     check_literal_concatenation:
 | |
| 	call	check_concatenation
 | |
| 	jnc	skip_attached_segment
 | |
|     literal_symbol_skipped:
 | |
| 	retn
 | |
| 
 | |
| get_processed_value:
 | |
| ; in:
 | |
| ;  esi = pointer into preprocessed line or current embedded value
 | |
| ; out:
 | |
| ;  cf set when there were no more symbols on the line
 | |
| ;  when cf = 0:
 | |
| ;   al = type of value
 | |
| ;   esi = pointer advanced past the processed element and the whitespace that follows it within the boundaries of current embedded value or preprocessed line
 | |
| ;   ecx = number of whitespace tokens encountered immediately before the new position
 | |
| ;   when al = 1Ah:
 | |
| ;    ebx - SymbolTree_Leaf, null when malformed identifier
 | |
| ;    edx - ValueDefinition, null when symbol with no valid value
 | |
| ;    additional variables set as by identify_symbol
 | |
| ;   when al = 22h:
 | |
| ;    edx - 32-bit length followed by string data
 | |
| ;   when al = 30h:
 | |
| ;    edx - 32-bit length followed by numeric data, null when invalid number
 | |
| ;   when al = 2Eh:
 | |
| ;    edx - FloatData, null when invalid number
 | |
| ;   when al is any other value, it is a simple special character, and edx is zero
 | |
| ; note:
 | |
| ;  to detect whitespace between two consecutive symbols, warp_to_next_symbol should be called after this function,
 | |
| ;  since it may further increase ecx when there is additional whitespace outside of current embedded value
 | |
| ;  when [use_raw_values] flag is set, this function is identical to get_raw_value
 | |
| 	call	get_raw_value
 | |
| 	jc	no_more_values
 | |
| 	cmp	al,1Ah
 | |
| 	jne	value_ok
 | |
| 	test	edx,edx
 | |
| 	jz	value_ok
 | |
| 	cmp	[edx+ValueDefinition.type],VALTYPE_SYMBOLIC
 | |
| 	je	symbolic_value
 | |
|     value_ok:
 | |
| 	clc
 | |
| 	retn
 | |
|     symbolic_value:
 | |
| 	cmp	[use_raw_values],0
 | |
| 	jne	value_ok
 | |
| 	mov	eax,[current_pass]
 | |
| 	mov	[ebx+SymbolTree_Leaf.last_use_pass],eax
 | |
| 	test	[ebx+SymbolTree_Leaf.flags],SYM_VARIABLE
 | |
| 	jnz	no_infinite_regress
 | |
| 	test	[edx+ValueDefinition.flags],VAL_IN_USE
 | |
| 	jz	no_infinite_regress
 | |
| 	push	edx
 | |
| 	mov	edx,_symbolic_self_reference
 | |
| 	call	register_error
 | |
| 	pop	edx
 | |
| 	retn
 | |
|     no_infinite_regress:
 | |
| 	call	embed_symbolic_value
 | |
| 	jmp	get_processed_value
 | |
| 
 | |
| get_raw_value:
 | |
| ; same as get_processed_value, but it does not expand symbolic value and returns it just like any other
 | |
| 	call	warp_to_next_symbol
 | |
| 	jc	no_more_values
 | |
| 	and	[symbol_definition],0
 | |
| 	mov	dl,SYMCLASS_EXPRESSION
 | |
| 	call	identify_symbol
 | |
| 	jc	get_raw_value
 | |
| 	test	edi,edi
 | |
| 	jz	literal_value
 | |
| 	mov	edi,edx
 | |
| 	test	ebx,ebx
 | |
| 	jz	invalid_symbol_value
 | |
| 	call	get_available_value
 | |
| 	jc	invalid_symbol_value
 | |
| 	mov	al,1Ah
 | |
| 	clc
 | |
| 	retn
 | |
|     invalid_symbol_value:
 | |
| 	xor	edx,edx
 | |
| 	mov	al,1Ah
 | |
| 	clc
 | |
| 	retn
 | |
|     literal_value:
 | |
| 	call	get_literal
 | |
| 	clc
 | |
| 	retn
 | |
|     no_more_values:
 | |
|        ; stc
 | |
| 	retn
 |