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
|