4853 lines
113 KiB
PHP
4853 lines
113 KiB
PHP
|
|
struct DirectiveBlock
|
|
type db ? ; DBLOCK_#
|
|
subtype db ? ; CTRL_# for DBLOCK_CONTROL
|
|
flags db ? ; CTRLF_# for DBLOCK_CONTROL
|
|
reserved db ?
|
|
reserved2 dw ?
|
|
prior_assembly_mode db ?
|
|
prior_special_parameters db ?
|
|
prior_counter_position dd ?
|
|
parameter_namespace dd ?
|
|
parameter dd ? ; pointer to first BlockParameter
|
|
length_of_data dd ?
|
|
ends
|
|
|
|
struct BlockParameter
|
|
symbol dd ? ; pointer to SymbolTree_Leaf
|
|
definition dd ? ; pointer to ValueDefinition
|
|
next dd ? ; pointer to another BlockParameter
|
|
ends
|
|
|
|
struct NamespaceData
|
|
prior_namespace dd ?
|
|
prior_label dd ?
|
|
ends
|
|
|
|
struct VirtualBlockData
|
|
outer_area dd ?
|
|
shift_tracking db ?
|
|
ends
|
|
|
|
struct ConditionalRepeatData
|
|
condition_length dd ?
|
|
ends
|
|
|
|
struct RepeatData
|
|
limit_length dd ?
|
|
index_position dd ?
|
|
ends
|
|
|
|
struct MacroData
|
|
nesting_counter dd ?
|
|
ends
|
|
|
|
struct SymbolSubstitution
|
|
symbol_start dd ?
|
|
symbol_end dd ?
|
|
value_start dd ?
|
|
value_end dd ?
|
|
leftover_context dd ?
|
|
ends
|
|
|
|
struct MatchedParameter
|
|
pattern dd ?
|
|
assembly_position dd ?
|
|
ends
|
|
|
|
DBLOCK_CLOSED = 0
|
|
DBLOCK_NAMESPACE = 1
|
|
DBLOCK_CONTROL = 2
|
|
DBLOCK_MACRO = 3
|
|
DBLOCK_VIRTUAL = 4
|
|
DBLOCK_CALMINSTRUCTION = 5
|
|
DBLOCK_POSTPONED = 8
|
|
DBLOCK_SUSPENDED = 9
|
|
|
|
CTRL_IF = 0
|
|
CTRL_WHILE = 2
|
|
CTRL_REPEAT = 3
|
|
CTRL_IRP = 4
|
|
CTRL_IRPV = 5
|
|
CTRL_MATCH = 6
|
|
CTRL_RMATCH = 7
|
|
CTRL_POSTPONE = 9
|
|
|
|
CTRLF_INACTIVE = 1
|
|
CTRLF_BREAKABLE = 2
|
|
CTRLF_HAS_REPEAT_DATA = 4
|
|
CTRLF_HAS_WRITABLE_INDEX = 8
|
|
CTRLF_ALLOWS_ELSE = 16
|
|
CTRLF_SUSPENDED = 32
|
|
|
|
add_directive_block:
|
|
; in:
|
|
; dl = DBLOCK_#
|
|
; ecx = length of additional data
|
|
; out: edi - new DirectiveBlock
|
|
; note: area for additional data is placed below the DirectiveBlock structure
|
|
; preserves: ebx, edx, esi
|
|
dec ecx
|
|
and ecx,(-1) shl 2
|
|
add ecx,1 shl 2
|
|
push esi ecx
|
|
mov esi,[source_context]
|
|
mov eax,[esi+SourceContext.number_of_entries]
|
|
imul eax,sizeof.SourceEntry
|
|
add eax,sizeof.SourceContext
|
|
add ecx,eax
|
|
add ecx,sizeof.DirectiveBlock
|
|
mov edi,[directives_stack]
|
|
lea eax,[edi+ecx]
|
|
cmp eax,[directives_stack_end]
|
|
jbe directives_stack_ready
|
|
add ecx,[directives_stack_end]
|
|
jc out_of_memory
|
|
mov eax,[directives_stack_base]
|
|
sub ecx,eax
|
|
push edx
|
|
call grow_stack
|
|
pop edx
|
|
add ecx,eax
|
|
mov [directives_stack_end],ecx
|
|
mov edi,eax
|
|
xchg eax,[directives_stack_base]
|
|
sub edi,eax
|
|
add edi,[directives_stack]
|
|
mov [directives_stack],edi
|
|
directives_stack_ready:
|
|
push edx
|
|
call clone_source_context
|
|
pop edx ecx
|
|
add edi,ecx
|
|
mov eax,edi
|
|
sub eax,[directives_stack]
|
|
mov [edi+DirectiveBlock.length_of_data],eax
|
|
mov [edi+DirectiveBlock.type],dl
|
|
mov al,[assembly_mode]
|
|
mov [edi+DirectiveBlock.prior_assembly_mode],al
|
|
mov ecx,[parameter_namespace]
|
|
mov [edi+DirectiveBlock.parameter_namespace],ecx
|
|
mov al,[ecx+SymbolTree_Root.parameters]
|
|
mov [edi+DirectiveBlock.prior_special_parameters],al
|
|
xor eax,eax
|
|
mov [edi+DirectiveBlock.subtype],al
|
|
mov [edi+DirectiveBlock.flags],al
|
|
mov [edi+DirectiveBlock.parameter],eax
|
|
mov eax,[current_counter]
|
|
sub eax,[counters_stack_base]
|
|
mov [edi+DirectiveBlock.prior_counter_position],eax
|
|
lea eax,[edi+sizeof.DirectiveBlock]
|
|
mov [directives_stack],eax
|
|
pop esi
|
|
retn
|
|
|
|
find_directive_block:
|
|
; in:
|
|
; dl = DBLOCK_#
|
|
; out:
|
|
; cf set when no such block found
|
|
; when cf = 0
|
|
; edi - DirectiveBlock of the latest block of this type
|
|
; preserves: ebx, edx, esi
|
|
mov edi,[directives_stack]
|
|
scan_directive_blocks:
|
|
cmp edi,[directives_stack_base]
|
|
je directive_block_not_found
|
|
sub edi,sizeof.DirectiveBlock
|
|
cmp dl,[edi+DirectiveBlock.type]
|
|
je directive_block_found
|
|
find_next_directive_block:
|
|
; in:
|
|
; dl = DBLOCK_#
|
|
; edi - DirectiveBlock
|
|
; out:
|
|
; cf set when no such block found
|
|
; when cf = 0
|
|
; edi - DirectiveBlock of the next latest block of this type
|
|
; preserves: ebx, edx, esi
|
|
mov ecx,[edi+DirectiveBlock.length_of_data]
|
|
sub edi,ecx
|
|
jmp scan_directive_blocks
|
|
directive_block_found:
|
|
clc
|
|
retn
|
|
directive_block_not_found:
|
|
stc
|
|
retn
|
|
|
|
close_control_directive_block:
|
|
; in: edi - DirectiveBlock
|
|
; preserves: esi
|
|
mov al,[edi+DirectiveBlock.prior_assembly_mode]
|
|
mov [assembly_mode],al
|
|
mov eax,[edi+DirectiveBlock.prior_counter_position]
|
|
add eax,[counters_stack_base]
|
|
mov [current_counter],eax
|
|
mov ecx,[edi+DirectiveBlock.parameter_namespace]
|
|
mov al,[edi+DirectiveBlock.prior_special_parameters]
|
|
mov [ecx+SymbolTree_Root.parameters],al
|
|
close_directive_block:
|
|
; in: edi - DirectiveBlock
|
|
; preserves: esi
|
|
mov [edi+DirectiveBlock.type],DBLOCK_CLOSED
|
|
mov eax,edi
|
|
mov ecx,[eax+DirectiveBlock.length_of_data]
|
|
sub eax,ecx
|
|
call release_source_context
|
|
call remove_block_parameters
|
|
lea eax,[edi+sizeof.DirectiveBlock]
|
|
cmp eax,[directives_stack]
|
|
je remove_directive_block
|
|
retn
|
|
remove_directive_block:
|
|
sub eax,sizeof.DirectiveBlock
|
|
mov ecx,[eax+DirectiveBlock.length_of_data]
|
|
sub eax,ecx
|
|
cmp eax,[directives_stack_base]
|
|
je directives_stack_cleared
|
|
cmp [eax-sizeof.DirectiveBlock+DirectiveBlock.type],DBLOCK_CLOSED
|
|
je remove_directive_block
|
|
directives_stack_cleared:
|
|
mov [directives_stack],eax
|
|
retn
|
|
|
|
add_block_parameter:
|
|
; in:
|
|
; ebx - SymbolTree_Leaf
|
|
; edi - DirectiveBlock
|
|
; esi - value
|
|
; ecx = length of value
|
|
; [value_type] = VALTYPE_#
|
|
; preserves: ebx, edi
|
|
push ecx
|
|
or [ebx+SymbolTree_Leaf.flags],SYM_VARIABLE
|
|
call create_value_definition
|
|
pop ecx
|
|
mov eax,[current_pass]
|
|
mov [edx+ValueDefinition.pass],eax
|
|
mov [edx+ValueDefinition.value_length],ecx
|
|
add ecx,sizeof.BlockParameter
|
|
push edi
|
|
mov edi,[edx+ValueDefinition.value]
|
|
cmp ecx,[edx+ValueDefinition.block_length]
|
|
jbe write_parameter_value
|
|
push edx
|
|
push ecx
|
|
cmp [edx+ValueDefinition.block_length],0
|
|
je allocate_memory_for_parameter
|
|
xor eax,eax
|
|
xchg eax,[edx+ValueDefinition.value]
|
|
call mfree
|
|
allocate_memory_for_parameter:
|
|
pop ecx
|
|
call malloc
|
|
pop edx
|
|
mov [edx+ValueDefinition.value],eax
|
|
mov [edx+ValueDefinition.block_length],ecx
|
|
mov edi,eax
|
|
write_parameter_value:
|
|
mov al,[value_type]
|
|
mov [edx+ValueDefinition.type],al
|
|
mov ecx,[edx+ValueDefinition.value_length]
|
|
rep movsb
|
|
mov ecx,edi
|
|
pop edi
|
|
mov [ecx+BlockParameter.symbol],ebx
|
|
mov [ecx+BlockParameter.definition],edx
|
|
inc [edx+ValueDefinition.reference_count]
|
|
mov eax,ecx
|
|
xchg eax,[edi+DirectiveBlock.parameter]
|
|
mov [ecx+BlockParameter.next],eax
|
|
retn
|
|
|
|
remove_block_parameters:
|
|
; in: edi - DirectiveBlock
|
|
; preserves: esi, edi
|
|
mov eax,[edi+DirectiveBlock.parameter]
|
|
test eax,eax
|
|
jz no_block_parameters
|
|
push esi edi
|
|
mov esi,eax
|
|
remove_block_parameter:
|
|
mov ebx,[esi+BlockParameter.symbol]
|
|
mov edx,[esi+BlockParameter.definition]
|
|
dec [edx+ValueDefinition.reference_count]
|
|
xor edi,edi
|
|
call remove_value_definition
|
|
mov esi,[esi+BlockParameter.next]
|
|
test esi,esi
|
|
jnz remove_block_parameter
|
|
pop edi esi
|
|
no_block_parameters:
|
|
retn
|
|
|
|
identify_parameter_symbol:
|
|
; in:
|
|
; esi = pointer into preprocessed line or current embedded value
|
|
; out:
|
|
; same as from identify_symbol_in_namespace
|
|
or [symbol_definition],1
|
|
mov ebx,[parameter_namespace]
|
|
mov dl,SYMCLASS_PARAMETER
|
|
call identify_symbol_in_namespace
|
|
jc parameter_symbol_identified
|
|
cmp edi,[parameter_namespace]
|
|
je parameter_symbol_identified
|
|
xor ebx,ebx
|
|
parameter_symbol_identified:
|
|
retn
|
|
|
|
cut_argument_value:
|
|
; in:
|
|
; esi = pointer into preprocessed line or current embedded value
|
|
; edi - LineExcerpt to be filled with information about cut piece of line
|
|
; [breakpoint_token] = initial byte of symbol that - if encountered - should immediately end the value
|
|
; out:
|
|
; esi = pointer advanced past the cut piece
|
|
; al = initial byte of symbol at pointer, zero when no more symbols there
|
|
; preserves: ebx, edi
|
|
call move_to_next_symbol
|
|
jc cut_plain_value
|
|
cmp byte [esi],'<'
|
|
je cut_enclosed_value
|
|
cut_plain_value:
|
|
mov dl,','
|
|
xor dh,dh
|
|
call cut_piece_of_line
|
|
retn
|
|
cut_enclosed_value:
|
|
inc esi
|
|
mov dl,'>'
|
|
mov dh,'<'
|
|
call cut_piece_of_line
|
|
cmp al,'>'
|
|
jne missing_enclosing
|
|
inc esi
|
|
call move_to_next_symbol
|
|
jnc parameter_value_cut
|
|
xor al,al
|
|
parameter_value_cut:
|
|
retn
|
|
missing_enclosing:
|
|
mov edx,_missing_closing_chevron
|
|
call register_error
|
|
retn
|
|
|
|
extract_argument_value:
|
|
; 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
|
|
; [breakpoint_token] = initial byte of symbol that - if encountered - should immediately end the value
|
|
; [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
|
|
; preserves: ebx
|
|
; note:
|
|
; when AMODE_DEFINITION is active, current context is not added to the extracted value
|
|
call move_to_next_symbol
|
|
jc extract_plain_value
|
|
cmp byte [esi],'<'
|
|
je extract_enclosed_value
|
|
extract_plain_value:
|
|
mov dl,','
|
|
xor dh,dh
|
|
call extract_piece_of_line
|
|
retn
|
|
extract_enclosed_value:
|
|
inc esi
|
|
mov dl,'>'
|
|
mov dh,'<'
|
|
call extract_piece_of_line
|
|
cmp al,'>'
|
|
jne missing_enclosing
|
|
inc esi
|
|
call move_to_next_symbol
|
|
jnc parameter_value_extracted
|
|
xor al,al
|
|
parameter_value_extracted:
|
|
retn
|
|
|
|
get_macro_definition_symbol:
|
|
; in:
|
|
; esi = pointer into preprocessed line or current embedded value
|
|
; al = initial byte of symbol at esi
|
|
; dl = SYMCLASS_#
|
|
; out:
|
|
; ebx - SymbolTree_Leaf
|
|
; esi = pointer advanced past the processed declaration
|
|
; [macro_leaf] - SymbolTree_Leaf
|
|
; [macro_flags] = VAL_#
|
|
mov [macro_flags],VAL_NONRECURSIVE
|
|
cmp al,'!'
|
|
je unconditional_interceptor
|
|
or [symbol_definition],1
|
|
call identify_symbol
|
|
jc invalid_macro_symbol
|
|
test ebx,ebx
|
|
jz invalid_macro_symbol
|
|
macro_symbol_identified:
|
|
call move_to_next_symbol
|
|
jc macro_symbol_ok
|
|
cmp al,':'
|
|
je recursive_macro
|
|
test ecx,ecx
|
|
jnz macro_symbol_ok
|
|
cmp al,'!'
|
|
je unconditional_macro
|
|
jmp macro_symbol_ok
|
|
unconditional_interceptor:
|
|
mov ebx,[interceptor_symbol]
|
|
cmp dl,SYMCLASS_STRUCTURE
|
|
jne unconditional_macro
|
|
mov ebx,[label_interceptor_symbol]
|
|
unconditional_macro:
|
|
or [macro_flags],VAL_UNCONDITIONAL
|
|
inc esi
|
|
call move_to_next_symbol
|
|
jc macro_symbol_ok
|
|
cmp al,':'
|
|
jne macro_symbol_ok
|
|
recursive_macro:
|
|
inc esi
|
|
call move_to_next_symbol
|
|
and [macro_flags],not VAL_NONRECURSIVE
|
|
or [ebx+SymbolTree_Leaf.flags],SYM_CONSTANT
|
|
jmp macro_symbol_ok
|
|
macro_symbol_ok:
|
|
mov [macro_leaf],ebx
|
|
mov edx,[ebx+SymbolTree_Leaf.definition]
|
|
test edx,edx
|
|
jz create_placeholder_value
|
|
test [edx+ValueDefinition.flags],VAL_INTERNAL
|
|
jnz macro_already_defined
|
|
mov eax,[current_pass]
|
|
sub eax,[edx+ValueDefinition.pass]
|
|
jz macro_already_defined
|
|
cmp eax,1
|
|
je macro_symbol_ready
|
|
create_placeholder_value:
|
|
; for VAL_UNCONDITIONAL macros this helps to detect when a macro tries to call itself,
|
|
; for regular ones this section interferes with operation of SYM_PREDICTED to sometimes prevent excess passes,
|
|
; when SYM_PREDICTED is needed to behave reliably for an instruction, its symbol
|
|
; should be marked with SYMX_INSTRUCTION_PREDICTED to skip this section
|
|
test [ebx+SymbolTree_Leaf.extra_flags],SYMX_INSTRUCTION_PREDICTED
|
|
jnz macro_symbol_ready
|
|
call create_value_definition
|
|
test edx,edx
|
|
jz macro_symbol_ready
|
|
mov eax,[current_pass]
|
|
dec eax
|
|
mov [edx+ValueDefinition.pass],eax
|
|
mov [edx+ValueDefinition.type],VALTYPE_RESERVED
|
|
mov al,[macro_flags]
|
|
mov [edx+ValueDefinition.flags],al
|
|
test al,VAL_UNCONDITIONAL
|
|
jnz macro_symbol_ready
|
|
or [edx+ValueDefinition.flags],VAL_IN_USE
|
|
test [ebx+SymbolTree_Leaf.flags],SYM_PREDICTED
|
|
jz macro_symbol_ready
|
|
mov edi,ebx
|
|
mov ecx,[current_pass]
|
|
check_macro_usage:
|
|
cmp ecx,[edi+SymbolTree_Leaf.last_use_pass]
|
|
je macro_possibly_used_earlier
|
|
mov edx,[edi+SymbolTree_Leaf.fallback_neighbour]
|
|
test edx,edx
|
|
jz look_up_parent_namespace_macro
|
|
cmp ecx,[edx+SymbolTree_Leaf.last_use_pass]
|
|
je macro_possibly_used_earlier
|
|
look_up_parent_namespace_macro:
|
|
mov edi,[edi+SymbolTree_Leaf.fallback_parent]
|
|
test edi,edi
|
|
jnz check_macro_usage
|
|
and [ebx+SymbolTree_Leaf.flags],not SYM_PREDICTED
|
|
jmp macro_symbol_ready
|
|
macro_possibly_used_earlier:
|
|
test al,VAL_NONRECURSIVE
|
|
jnz macro_symbol_ready
|
|
or [next_pass_needed],-1
|
|
macro_symbol_ready:
|
|
clc
|
|
retn
|
|
macro_already_defined:
|
|
test [ebx+SymbolTree_Leaf.flags],SYM_CONSTANT
|
|
jz macro_symbol_ready
|
|
mov edx,_conflicting_definition
|
|
call register_error
|
|
invalid_macro_symbol:
|
|
stc
|
|
retn
|
|
|
|
; instruction handler
|
|
; in:
|
|
; esi = pointer into preprocessed line
|
|
; ecx = number of whitespace tokens between previous symbol and current position
|
|
; edx - ValueDefinition of instruction
|
|
; ebx - SymbolTree_Leaf of instruction
|
|
; edi - SymbolTree_Root of instruction
|
|
; when [SymbolTree_Leaf.class] = SYMCLASS_STRUCTURE:
|
|
; [label_leaf] - SymbolTree_Leaf of structure label
|
|
; [label_branch] - SymbolTree_Foliage of structure label
|
|
; [label_independent] = zero when identifier of structure label is relative to current label
|
|
; out:
|
|
; when done, handler should jump to instruction_assembled with esi containing a pointer moved past the processed part of line,
|
|
; or jump directly to assembly_line when the rest of line should be ignored
|
|
; note:
|
|
; when esi is equal to [line_end], pointer is at the end of line and there is no data available at this address
|
|
|
|
set_namespace:
|
|
mov dl,DBLOCK_NAMESPACE
|
|
mov ecx,sizeof.NamespaceData
|
|
call add_directive_block
|
|
mov edx,[current_context.base_namespace]
|
|
mov [edi-sizeof.NamespaceData+NamespaceData.prior_namespace],edx
|
|
mov eax,[edx+SymbolTree_Root.current_label]
|
|
mov [edi-sizeof.NamespaceData+NamespaceData.prior_label],eax
|
|
and [symbol_definition],0
|
|
mov dl,SYMCLASS_EXPRESSION
|
|
call identify_symbol
|
|
jc missing_argument
|
|
test ebx,ebx
|
|
jz invalid_identifier
|
|
call get_symbol_namespace
|
|
mov [current_context.base_namespace],ebx
|
|
and [ebx+SymbolTree_Root.current_label],0
|
|
jmp instruction_assembled
|
|
end_namespace:
|
|
mov dl,DBLOCK_NAMESPACE
|
|
call find_directive_block
|
|
jc unexpected_instruction
|
|
mov edx,[edi-sizeof.NamespaceData+NamespaceData.prior_namespace]
|
|
mov eax,[edi-sizeof.NamespaceData+NamespaceData.prior_label]
|
|
mov [current_context.base_namespace],edx
|
|
mov [edx+SymbolTree_Root.current_label],eax
|
|
call close_directive_block
|
|
jmp instruction_assembled
|
|
|
|
set_base_address:
|
|
mov edx,[current_area]
|
|
mov ebx,[edx+ValueDefinition.value]
|
|
test [ebx+AreaHeader.flags],AREA_VIRTUAL
|
|
jnz unexpected_instruction
|
|
call get_expression_value
|
|
jc invalid_argument
|
|
push esi
|
|
call convert_terms_to_numeric_value
|
|
begin_new_output_area:
|
|
call create_output_area
|
|
inc [edx+ValueDefinition.reference_count]
|
|
xchg edx,[current_area]
|
|
dec [edx+ValueDefinition.reference_count]
|
|
; jz internal_error
|
|
pop esi
|
|
jmp instruction_assembled
|
|
begin_new_section:
|
|
mov edx,[current_area]
|
|
mov ebx,[edx+ValueDefinition.value]
|
|
test [ebx+AreaHeader.flags],AREA_VIRTUAL
|
|
jnz unexpected_instruction
|
|
call get_expression_value
|
|
jc invalid_argument
|
|
push esi
|
|
call convert_terms_to_numeric_value
|
|
call trim_output
|
|
call create_output_area
|
|
mov eax,edx
|
|
inc [eax+ValueDefinition.reference_count]
|
|
xchg eax,[current_area]
|
|
dec [eax+ValueDefinition.reference_count]
|
|
; jz internal_error
|
|
pop esi
|
|
jmp instruction_assembled
|
|
restart_output:
|
|
mov edx,[current_area]
|
|
mov ebx,[edx+ValueDefinition.value]
|
|
test [ebx+AreaHeader.flags],AREA_VIRTUAL
|
|
jnz unexpected_instruction
|
|
call peek_at_constituent_value
|
|
jc restart_output_at_current_address
|
|
call get_expression_value
|
|
jc invalid_argument
|
|
push esi
|
|
call convert_terms_to_numeric_value
|
|
jmp make_new_initial_output_area
|
|
restart_output_at_current_address:
|
|
push esi
|
|
call get_current_address_value
|
|
make_new_initial_output_area:
|
|
and [initial_output_area_entry],0
|
|
jmp begin_new_output_area
|
|
|
|
define_label:
|
|
inc esi
|
|
xor ecx,ecx
|
|
call move_to_next_symbol
|
|
jc define_simple_label
|
|
test ecx,ecx
|
|
jnz define_simple_label
|
|
cmp al,'='
|
|
je define_numeric_constant
|
|
cmp al,':'
|
|
je define_area_label
|
|
define_simple_label:
|
|
test [assembly_mode],AMODE_SKIP
|
|
jnz assemble_after_label
|
|
test [assembly_mode],AMODE_DEFINITION
|
|
jnz add_label_to_macro
|
|
cmp [interceptor],0
|
|
jne execute_interceptor
|
|
mov [argument_start],esi
|
|
call get_current_address_value
|
|
mov edi,ecx
|
|
mov ebx,[label_leaf]
|
|
call create_constant_value_definition
|
|
test edx,edx
|
|
jz assembly_line
|
|
mov ecx,edi
|
|
call assign_shiftable_value
|
|
label_defined:
|
|
call update_current_label
|
|
mov esi,[argument_start]
|
|
assemble_after_label:
|
|
mov [line_start],esi
|
|
mov eax,[embedded_context]
|
|
mov [line_context],eax
|
|
jmp assemble_instruction
|
|
define_area_label:
|
|
inc esi
|
|
test [assembly_mode],AMODE_SKIP
|
|
jnz assemble_after_label
|
|
test [assembly_mode],AMODE_DEFINITION
|
|
jnz add_label_to_macro
|
|
cmp [interceptor],0
|
|
jne execute_interceptor
|
|
mov [argument_start],esi
|
|
mov ebx,[label_leaf]
|
|
mov edx,[current_area]
|
|
call update_value_link
|
|
jmp label_defined
|
|
assign_shiftable_value:
|
|
mov [value_type],VALTYPE_NUMERIC
|
|
mov eax,[current_area]
|
|
mov eax,[eax+ValueDefinition.value]
|
|
test [eax+AreaHeader.flags],AREA_SHIFT_TRACKING_DISABLED
|
|
jnz assign_value
|
|
or [shift_tracking],-1
|
|
call update_predicted_shift
|
|
call assign_value
|
|
or [edx+ValueDefinition.flags],VAL_SHIFTABLE
|
|
retn
|
|
update_current_label:
|
|
mov edx,[label_branch]
|
|
cmp [label_independent],0
|
|
je current_label_ok
|
|
mov edi,[edx+SymbolTree_Foliage.root]
|
|
test [edi+SymbolTree_Root.flags],NAMESPACE_LOCAL
|
|
jnz current_label_ok
|
|
mov edi,[current_context.base_namespace]
|
|
mov [edi+SymbolTree_Root.current_label],edx
|
|
current_label_ok:
|
|
retn
|
|
|
|
define_numeric_symbol:
|
|
test [assembly_mode],AMODE_SKIP
|
|
jnz assembly_line
|
|
test [assembly_mode],AMODE_DEFINITION
|
|
jnz add_line_to_macro
|
|
cmp [interceptor],0
|
|
jne execute_interceptor
|
|
inc esi
|
|
xor ecx,ecx
|
|
call move_to_next_symbol
|
|
jc define_numeric_variable
|
|
test ecx,ecx
|
|
jnz define_numeric_variable
|
|
cmp al,':'
|
|
jne define_numeric_variable
|
|
inc esi
|
|
call get_expression_value
|
|
jc missing_argument
|
|
mov ebx,[label_leaf]
|
|
call create_value_definition
|
|
jmp define_numeric_value
|
|
define_numeric_constant:
|
|
test [assembly_mode],AMODE_SKIP
|
|
jnz assembly_line
|
|
test [assembly_mode],AMODE_DEFINITION
|
|
jnz add_line_to_macro
|
|
cmp [interceptor],0
|
|
jne execute_interceptor
|
|
inc esi
|
|
call get_expression_value
|
|
jc missing_argument
|
|
mov ebx,[label_leaf]
|
|
call create_constant_value_definition
|
|
jmp define_numeric_value
|
|
define_numeric_variable:
|
|
call get_expression_value
|
|
jc missing_argument
|
|
mov ebx,[label_leaf]
|
|
call update_value_definition
|
|
define_numeric_value:
|
|
test edx,edx
|
|
jz assembly_line
|
|
push esi
|
|
push ebx edx
|
|
mov eax,[edi+ExpressionTerm.attributes]
|
|
cmp al,EXPR_STRING
|
|
je define_string_variable
|
|
cmp al,EXPR_FLOAT
|
|
je define_float_variable
|
|
mov [value_type],VALTYPE_NUMERIC
|
|
call convert_terms_to_numeric_value
|
|
assign_numeric_value:
|
|
pop edx ebx
|
|
call assign_value
|
|
pop esi
|
|
jmp instruction_assembled
|
|
define_string_variable:
|
|
mov [value_type],VALTYPE_STRING
|
|
call get_term_value
|
|
mov esi,edx
|
|
mov ecx,[esi]
|
|
add ecx,4
|
|
jmp assign_numeric_value
|
|
define_float_variable:
|
|
mov [value_type],VALTYPE_FLOAT
|
|
call get_term_value
|
|
mov esi,edx
|
|
mov ecx,sizeof.FloatData
|
|
jmp assign_numeric_value
|
|
|
|
define_element:
|
|
or [symbol_definition],1
|
|
mov dl,SYMCLASS_EXPRESSION
|
|
call identify_symbol
|
|
jc missing_argument
|
|
test ebx,ebx
|
|
jz invalid_identifier
|
|
mov [label_leaf],ebx
|
|
call move_to_next_symbol
|
|
jc element_with_no_metadata
|
|
cmp al,':'
|
|
jne get_element_metadata
|
|
inc esi
|
|
get_element_metadata:
|
|
call get_expression_value
|
|
jc invalid_argument
|
|
mov ebx,[label_leaf]
|
|
call create_constant_value_definition
|
|
test edx,edx
|
|
jz assembly_line
|
|
mov [value_type],VALTYPE_ELEMENT
|
|
push esi
|
|
push ebx edx
|
|
call convert_terms_to_numeric_value
|
|
pop edx ebx
|
|
call assign_value
|
|
pop esi
|
|
jmp instruction_assembled
|
|
element_with_no_metadata:
|
|
mov ebx,[label_leaf]
|
|
call create_constant_value_definition
|
|
test edx,edx
|
|
jz assembly_line
|
|
mov [value_type],VALTYPE_ELEMENT
|
|
push esi
|
|
xor esi,esi
|
|
xor ecx,ecx
|
|
call assign_value
|
|
pop esi
|
|
jmp instruction_assembled
|
|
|
|
redefine_raw_symbolic_variable:
|
|
mov [update_function],update_value_definition
|
|
jmp raw_symbolic_variable
|
|
define_raw_symbolic_variable:
|
|
mov [update_function],create_value_definition
|
|
raw_symbolic_variable:
|
|
or [symbol_definition],1
|
|
mov dl,SYMCLASS_EXPRESSION
|
|
call identify_symbol
|
|
jc missing_argument
|
|
test ebx,ebx
|
|
jz invalid_identifier
|
|
mov [label_leaf],ebx
|
|
or [raw_value],1
|
|
jmp symbolic_variable
|
|
redefine_symbolic_variable:
|
|
mov [update_function],update_value_definition
|
|
and [raw_value],0
|
|
jmp symbolic_variable
|
|
define_symbolic_variable:
|
|
mov [update_function],create_value_definition
|
|
and [raw_value],0
|
|
symbolic_variable:
|
|
mov edi,[assembly_workspace.memory_start]
|
|
and [previous_symbol_end],0
|
|
and [contextless_processing],0
|
|
expand_symbols:
|
|
cmp [raw_value],0
|
|
jne copy_raw_symbols
|
|
and [symbol_definition],0
|
|
mov dl,SYMCLASS_EXPRESSION
|
|
push edi
|
|
call identify_symbol
|
|
jc symbols_expanded
|
|
test edi,edi
|
|
jnz symbol_ready
|
|
call skip_literal
|
|
xor ebx,ebx
|
|
symbol_ready:
|
|
pop edi
|
|
test ebx,ebx
|
|
jz copy_symbol
|
|
mov [further_whitespace],ecx
|
|
call get_available_value
|
|
jc copy_symbol
|
|
cmp [edx+ValueDefinition.type],VALTYPE_SYMBOLIC
|
|
jne copy_symbol
|
|
and [previous_symbol_end],0
|
|
mov eax,[current_pass]
|
|
mov [ebx+SymbolTree_Leaf.last_use_pass],eax
|
|
cmp ebx,[label_leaf]
|
|
jne replace_symbolic_variable
|
|
mov ecx,[edx+ValueDefinition.pass]
|
|
cmp ecx,[current_pass]
|
|
je replace_symbolic_variable
|
|
mov edx,_symbolic_self_reference
|
|
call register_error
|
|
jmp expand_symbols
|
|
replace_symbolic_variable:
|
|
mov ecx,[edx+ValueDefinition.value_length]
|
|
test ecx,ecx
|
|
jz expand_symbols
|
|
push esi
|
|
mov esi,[edx+ValueDefinition.value]
|
|
push ecx
|
|
add ecx,1+sizeof.RecognitionContext
|
|
add ecx,[further_whitespace]
|
|
mov edx,assembly_workspace
|
|
call reserve_workspace
|
|
mov al,40h
|
|
cmp al,[esi]
|
|
je copy_symbolic_value
|
|
stosb
|
|
mov eax,esi
|
|
mov esi,current_context
|
|
assert sizeof.RecognitionContext and 11b = 0
|
|
mov ecx,sizeof.RecognitionContext shr 2
|
|
rep movsd
|
|
mov esi,eax
|
|
copy_symbolic_value:
|
|
pop ecx
|
|
rep movsb
|
|
pop esi
|
|
mov al,20h
|
|
mov ecx,[further_whitespace]
|
|
rep stosb
|
|
jmp expand_symbols
|
|
copy_raw_symbols:
|
|
mov eax,esi
|
|
mov esi,[line_end]
|
|
cmp esi,eax
|
|
je symbolic_value_ready
|
|
mov [symbol_start],eax
|
|
copy_symbol:
|
|
mov ebx,esi
|
|
xchg [previous_symbol_end],esi
|
|
test esi,esi
|
|
jz copy_symbol_with_recognition_context
|
|
mov ecx,ebx
|
|
sub ecx,esi
|
|
mov edx,assembly_workspace
|
|
call reserve_workspace
|
|
and [context_boundary],0
|
|
jmp copy_symbol_tokens
|
|
copy_symbol_with_recognition_context:
|
|
mov ecx,ebx
|
|
sub ecx,[symbol_start]
|
|
add ecx,1+sizeof.RecognitionContext
|
|
mov edx,assembly_workspace
|
|
call reserve_workspace
|
|
mov al,40h
|
|
stosb
|
|
cmp [raw_value],0
|
|
je use_recognition_context
|
|
mov esi,[embedded_context]
|
|
test esi,esi
|
|
jz use_current_context
|
|
call store_recognition_context
|
|
jmp symbol_context_stored
|
|
use_current_context:
|
|
call store_current_context
|
|
jmp symbol_context_stored
|
|
use_recognition_context:
|
|
mov esi,recognition_context
|
|
assert sizeof.RecognitionContext and 11b = 0
|
|
mov ecx,sizeof.RecognitionContext shr 2
|
|
rep movsd
|
|
mov [context_boundary],edi
|
|
symbol_context_stored:
|
|
mov esi,[symbol_start]
|
|
copy_symbol_tokens:
|
|
cmp esi,ebx
|
|
jae expand_symbols
|
|
call store_token
|
|
jmp copy_symbol_tokens
|
|
symbols_expanded:
|
|
pop edi
|
|
symbolic_value_ready:
|
|
mov ebx,[label_leaf]
|
|
call [update_function]
|
|
test edx,edx
|
|
jz assembly_line
|
|
mov [value_type],VALTYPE_SYMBOLIC
|
|
mov esi,[assembly_workspace.memory_start]
|
|
mov ecx,edi
|
|
sub ecx,esi
|
|
call assign_value
|
|
jmp assembly_line
|
|
store_token:
|
|
lodsb
|
|
cmp al,40h
|
|
je make_recognition_context_token
|
|
stosb
|
|
cmp al,1Ah
|
|
je store_token_with_data
|
|
cmp al,22h
|
|
je store_token_with_data
|
|
cmp al,27h
|
|
je store_token_with_data
|
|
cmp al,30h
|
|
je store_internal_token
|
|
retn
|
|
store_token_with_data:
|
|
movsd
|
|
retn
|
|
store_internal_token:
|
|
lodsd
|
|
stosd
|
|
mov ecx,eax
|
|
rep movsb
|
|
retn
|
|
|
|
restore_variables:
|
|
mov al,[edx+ValueDefinition.attribute]
|
|
mov [chosen_class],al
|
|
restore_symbol_value:
|
|
mov dl,[chosen_class]
|
|
or [symbol_definition],1
|
|
call identify_symbol
|
|
jc missing_argument
|
|
test ebx,ebx
|
|
jz invalid_identifier
|
|
remove_variable_value:
|
|
xor edx,edx
|
|
xor edi,edi
|
|
call remove_value_definition
|
|
call move_to_next_symbol
|
|
jc assembly_line
|
|
cmp al,','
|
|
jne invalid_argument
|
|
inc esi
|
|
jmp restore_symbol_value
|
|
move_variable_values:
|
|
mov dl,[edx+ValueDefinition.attribute]
|
|
mov [chosen_class],dl
|
|
or [symbol_definition],1
|
|
call identify_symbol
|
|
jc missing_argument
|
|
test ebx,ebx
|
|
jz invalid_identifier
|
|
mov [label_leaf],ebx
|
|
call move_to_next_symbol
|
|
jc missing_argument
|
|
cmp al,','
|
|
jne invalid_argument
|
|
inc esi
|
|
mov dl,[chosen_class]
|
|
call identify_symbol
|
|
jc missing_argument
|
|
test ebx,ebx
|
|
jz invalid_identifier
|
|
xor edx,edx
|
|
mov edi,[label_leaf]
|
|
call remove_value_definition
|
|
jmp instruction_assembled
|
|
|
|
label_directive:
|
|
or [symbol_definition],1
|
|
mov dl,SYMCLASS_EXPRESSION
|
|
call identify_symbol
|
|
jc missing_argument
|
|
test ebx,ebx
|
|
jz invalid_identifier
|
|
mov [label_leaf],ebx
|
|
mov [label_branch],edx
|
|
mov al,[symbol_independent]
|
|
mov [label_independent],al
|
|
and [metadata_length],0
|
|
call peek_at_constituent_value
|
|
jc label_at_current_address
|
|
cmp al,1Ah
|
|
jne label_with_size
|
|
test edx,edx
|
|
jz label_with_size
|
|
cmp [edx+ValueDefinition.type],VALTYPE_NATIVE_PREPOSITION
|
|
jne label_with_size
|
|
cmp [edx+ValueDefinition.value],PREPOSITION_AT
|
|
je label_at_specified_address
|
|
label_with_size:
|
|
cmp al,':'
|
|
jne get_label_size
|
|
and [current_constituent],0
|
|
get_label_size:
|
|
call get_expression_value
|
|
jc invalid_argument
|
|
push esi
|
|
mov edx,auxiliary_workspace
|
|
call convert_terms_to_numeric_value_in_workspace
|
|
mov [metadata_length],ecx
|
|
pop esi
|
|
call peek_at_constituent_value
|
|
jc label_at_current_address
|
|
cmp al,1Ah
|
|
jne label_at_current_address
|
|
test edx,edx
|
|
jz invalid_argument
|
|
cmp [edx+ValueDefinition.type],VALTYPE_NATIVE_PREPOSITION
|
|
jne label_at_current_address
|
|
cmp [edx+ValueDefinition.value],PREPOSITION_AT
|
|
jne invalid_argument
|
|
label_at_specified_address:
|
|
and [current_constituent],0
|
|
call get_expression_value
|
|
jc invalid_argument
|
|
push esi
|
|
call convert_terms_to_numeric_value
|
|
mov edi,ecx
|
|
mov ebx,[label_leaf]
|
|
call create_constant_value_definition
|
|
test edx,edx
|
|
jz label_ready
|
|
call prepare_label_value
|
|
mov [value_type],VALTYPE_NUMERIC
|
|
call assign_value
|
|
jmp label_ready
|
|
label_at_current_address:
|
|
push esi
|
|
call get_current_address_value
|
|
mov edi,ecx
|
|
mov ebx,[label_leaf]
|
|
call create_constant_value_definition
|
|
test edx,edx
|
|
jz label_ready
|
|
call prepare_label_value
|
|
call assign_shiftable_value
|
|
label_ready:
|
|
pop esi
|
|
call update_current_label
|
|
jmp instruction_assembled
|
|
prepare_label_value:
|
|
mov ecx,edi
|
|
cmp [metadata_length],0
|
|
je label_metadata_ok
|
|
add edi,esi
|
|
push edx ecx
|
|
mov ecx,[metadata_length]
|
|
mov edx,assembly_workspace
|
|
call reserve_workspace
|
|
mov esi,[auxiliary_workspace.memory_start]
|
|
mov ecx,[metadata_length]
|
|
pop eax
|
|
add eax,ecx
|
|
rep movsb
|
|
pop edx
|
|
mov ecx,eax
|
|
mov esi,edi
|
|
sub esi,ecx
|
|
label_metadata_ok:
|
|
retn
|
|
|
|
virtual_block:
|
|
mov dl,DBLOCK_VIRTUAL
|
|
mov ecx,sizeof.VirtualBlockData
|
|
call add_directive_block
|
|
mov edx,[current_area]
|
|
mov [edi-sizeof.VirtualBlockData+VirtualBlockData.outer_area],edx
|
|
mov al,[shift_tracking]
|
|
mov [edi-sizeof.VirtualBlockData+VirtualBlockData.shift_tracking],al
|
|
call peek_at_constituent_value
|
|
jc virtual_at_current_address
|
|
cmp al,1Ah
|
|
jne invalid_argument
|
|
test edx,edx
|
|
jz invalid_argument
|
|
cmp [edx+ValueDefinition.type],VALTYPE_NATIVE_PREPOSITION
|
|
jne continue_virtual_block
|
|
mov eax,[edx+ValueDefinition.value]
|
|
cmp eax,PREPOSITION_AS
|
|
je virtual_at_current_address
|
|
cmp eax,PREPOSITION_AT
|
|
jne invalid_argument
|
|
and [current_constituent],0
|
|
call get_expression_value
|
|
jc invalid_argument
|
|
push esi
|
|
call convert_terms_to_numeric_value
|
|
jmp create_virtual_block
|
|
virtual_at_current_address:
|
|
push esi
|
|
call get_current_address_value
|
|
create_virtual_block:
|
|
lea ebx,[virtual_area]
|
|
call create_area
|
|
or [ebx+AreaHeader.flags],AREA_VIRTUAL
|
|
cmp [shift_tracking],0
|
|
je virtual_block_ready
|
|
or [ebx+AreaHeader.flags],AREA_SHIFT_TRACKING_DISABLED
|
|
virtual_block_ready:
|
|
inc [edx+ValueDefinition.reference_count]
|
|
or [edx+ValueDefinition.flags],VAL_IN_USE
|
|
mov [current_area],edx
|
|
pop esi
|
|
call get_constituent_value
|
|
jc instruction_assembled
|
|
cmp al,1Ah
|
|
jne invalid_argument
|
|
test edx,edx
|
|
jz invalid_argument
|
|
cmp [edx+ValueDefinition.type],VALTYPE_NATIVE_PREPOSITION
|
|
jne invalid_argument
|
|
cmp [edx+ValueDefinition.value],PREPOSITION_AS
|
|
jne invalid_argument
|
|
call get_constant_value
|
|
cmp al,22h
|
|
jne invalid_argument
|
|
mov ebx,[auxiliary_output_areas]
|
|
mov edi,esi
|
|
mov ecx,[edx]
|
|
lea esi,[edx+4]
|
|
test ecx,ecx
|
|
jnz register_auxiliary_file
|
|
dec esi
|
|
register_auxiliary_file:
|
|
mov eax,[current_area]
|
|
inc [eax+ValueDefinition.reference_count]
|
|
push ecx
|
|
call put_into_map
|
|
pop ecx
|
|
jmp validate_extension
|
|
continue_virtual_block:
|
|
and [leave_opening_parentheses],0
|
|
mov edi,[expression_workspace.memory_start]
|
|
call parse_expression
|
|
mov edi,[expression_workspace.memory_start]
|
|
call get_area_value
|
|
jc invalid_area
|
|
mov ecx,[current_pass]
|
|
cmp [edx+ValueDefinition.pass],ecx
|
|
jne invalid_area
|
|
mov eax,[edx+ValueDefinition.value]
|
|
test [eax+AreaHeader.flags],AREA_VIRTUAL
|
|
jz invalid_area
|
|
test [edx+ValueDefinition.flags],VAL_IN_USE
|
|
jnz invalid_area
|
|
inc [edx+ValueDefinition.reference_count]
|
|
or [edx+ValueDefinition.flags],VAL_IN_USE
|
|
mov [current_area],edx
|
|
jmp instruction_assembled
|
|
invalid_area:
|
|
mov edx,_invalid_area
|
|
call register_error
|
|
jmp assembly_line
|
|
|
|
end_virtual_block:
|
|
mov dl,DBLOCK_VIRTUAL
|
|
call find_directive_block
|
|
jc unexpected_instruction
|
|
mov al,[edi-sizeof.VirtualBlockData+VirtualBlockData.shift_tracking]
|
|
mov [shift_tracking],al
|
|
mov edx,[edi-sizeof.VirtualBlockData+VirtualBlockData.outer_area]
|
|
xchg edx,[current_area]
|
|
and [edx+ValueDefinition.flags],not VAL_IN_USE
|
|
dec [edx+ValueDefinition.reference_count]
|
|
jnz close_virtual_block
|
|
mov eax,edx
|
|
xchg eax,[retired_definition]
|
|
mov [edx+ValueDefinition.previous],eax
|
|
close_virtual_block:
|
|
call close_directive_block
|
|
jmp instruction_assembled
|
|
|
|
include_source:
|
|
call move_to_next_symbol
|
|
jc missing_argument
|
|
cmp al,'!'
|
|
jne conditional_include
|
|
inc esi
|
|
jmp get_file_name
|
|
conditional_include:
|
|
test [assembly_mode],AMODE_SKIP
|
|
jnz assembly_line
|
|
test [assembly_mode],AMODE_DEFINITION
|
|
jnz add_line_to_macro
|
|
get_file_name:
|
|
call get_constant_value
|
|
cmp al,22h
|
|
jne invalid_argument
|
|
push esi
|
|
mov [file_name],edx
|
|
call prepare_file_path
|
|
mov esi,[assembly_workspace.memory_start]
|
|
call read_source
|
|
test eax,eax
|
|
jnz include_read
|
|
mov esi,[local_path]
|
|
call read_source
|
|
test eax,eax
|
|
jnz include_read
|
|
mov ebx,esi
|
|
mov esi,[include_paths]
|
|
try_include_paths:
|
|
lodsb
|
|
test al,al
|
|
jz include_not_found
|
|
cmp al,';'
|
|
je try_include_paths
|
|
lea ebx,[esi-1]
|
|
measure_path:
|
|
lodsb
|
|
test al,al
|
|
jz path_measured
|
|
cmp al,';'
|
|
jne measure_path
|
|
path_measured:
|
|
dec esi
|
|
xchg esi,ebx
|
|
mov ecx,ebx
|
|
sub ecx,esi
|
|
mov edx,[file_name]
|
|
add ecx,[edx]
|
|
add ecx,2
|
|
mov edx,assembly_workspace
|
|
mov edi,[edx+Workspace.memory_start]
|
|
call reserve_workspace
|
|
mov ecx,ebx
|
|
sub ecx,esi
|
|
rep movsb
|
|
mov al,[esi-1]
|
|
cmp al,'/'
|
|
je path_separator_ok
|
|
cmp al,'\'
|
|
je path_separator_ok
|
|
mov al,'/'
|
|
stosb
|
|
path_separator_ok:
|
|
mov esi,[file_name]
|
|
lodsd
|
|
mov ecx,eax
|
|
rep movsb
|
|
xor al,al
|
|
stosb
|
|
mov esi,[assembly_workspace.memory_start]
|
|
push ebx
|
|
call read_source
|
|
mov ebx,esi
|
|
pop esi
|
|
test eax,eax
|
|
jz try_include_paths
|
|
mov esi,ebx
|
|
include_read:
|
|
mov edx,eax
|
|
call create_source_entry
|
|
jc include_stack_limit_exceeded
|
|
mov [ebx+SourceEntry.type],SOURCE_FILE
|
|
mov [ebx+SourceEntry.name],esi
|
|
mov [ebx+SourceEntry.text],edx
|
|
mov edx,[local_parameter_namespace]
|
|
mov eax,[edx+SymbolTree_Root.chain]
|
|
test eax,eax
|
|
jnz new_parameter_namespace_ok
|
|
call create_parameter_namespace
|
|
mov [edx+SymbolTree_Root.chain],eax
|
|
new_parameter_namespace_ok:
|
|
and [eax+SymbolTree_Root.parameters],0
|
|
mov [ebx+SourceEntry.local_namespace],eax
|
|
pop esi
|
|
call get_constituent_value
|
|
jc instruction_assembled
|
|
cmp al,','
|
|
jne extra_characters_on_line
|
|
cmp [number_of_line_embeddings],0
|
|
jne invalid_argument
|
|
jmp assemble_after_label
|
|
include_stack_limit_exceeded:
|
|
pop esi
|
|
mov edx,_stack_limit_exceeded
|
|
call register_error
|
|
jmp instruction_assembled
|
|
include_not_found:
|
|
pop esi
|
|
mov edx,_source_file_not_found
|
|
call register_error
|
|
jmp instruction_assembled
|
|
prepare_file_path:
|
|
mov [local_path],edx
|
|
call get_file_source_entry
|
|
mov esi,[ebx+SourceEntry.name]
|
|
mov ecx,esi
|
|
cut_parent_path:
|
|
lodsb
|
|
test al,al
|
|
jz parent_path_cut
|
|
cmp al,'/'
|
|
je found_path_segment
|
|
cmp al,'\'
|
|
jne cut_parent_path
|
|
found_path_segment:
|
|
mov ecx,esi
|
|
jmp cut_parent_path
|
|
parent_path_cut:
|
|
mov esi,[ebx+SourceEntry.name]
|
|
sub ecx,esi
|
|
mov ebx,ecx
|
|
add ecx,[edx]
|
|
inc ecx
|
|
mov edx,assembly_workspace
|
|
mov edi,[edx+Workspace.memory_start]
|
|
call reserve_workspace
|
|
mov ecx,ebx
|
|
rep movsb
|
|
mov edx,edi
|
|
xchg edx,[local_path]
|
|
lea esi,[edx+4]
|
|
mov ecx,[edx]
|
|
mov ebx,edi
|
|
rep movsb
|
|
xor al,al
|
|
stosb
|
|
retn
|
|
|
|
evaluate_string:
|
|
mov edi,[assembly_workspace.memory_start]
|
|
mov [string_end],edi
|
|
collect_source_string:
|
|
call get_constant_value
|
|
cmp al,30h
|
|
je collect_source_byte
|
|
cmp al,22h
|
|
jne invalid_argument
|
|
mov ebx,edx
|
|
mov edi,[string_end]
|
|
mov ecx,[ebx]
|
|
inc ecx
|
|
mov edx,assembly_workspace
|
|
call reserve_workspace
|
|
xchg esi,ebx
|
|
lodsd
|
|
mov ecx,eax
|
|
rep movsb
|
|
mov esi,ebx
|
|
source_fragment_collected:
|
|
mov [string_end],edi
|
|
call get_constituent_value
|
|
jc source_string_ready
|
|
cmp al,','
|
|
jne invalid_argument
|
|
jmp collect_source_string
|
|
collect_source_byte:
|
|
mov ebx,edx
|
|
mov edi,[string_end]
|
|
mov ecx,2
|
|
mov edx,assembly_workspace
|
|
call reserve_workspace
|
|
mov edx,ebx
|
|
mov ecx,1
|
|
call fit_value
|
|
jc value_out_of_range
|
|
inc edi
|
|
jmp source_fragment_collected
|
|
source_string_ready:
|
|
mov edi,[string_end]
|
|
xor al,al
|
|
stosb
|
|
push esi
|
|
mov esi,[assembly_workspace.memory_start]
|
|
call use_source
|
|
mov edx,eax
|
|
call create_source_entry
|
|
jc include_stack_limit_exceeded
|
|
mov [ebx+SourceEntry.type],SOURCE_MEMORY
|
|
mov [ebx+SourceEntry.name],esi
|
|
mov [ebx+SourceEntry.text],edx
|
|
mov eax,[parameter_namespace]
|
|
mov [ebx+SourceEntry.local_namespace],eax
|
|
pop esi
|
|
jmp instruction_assembled
|
|
|
|
assert_condition:
|
|
call get_condition_value
|
|
test al,al
|
|
jnz instruction_assembled
|
|
mov edx,_assertion_failed
|
|
call register_error
|
|
jmp instruction_assembled
|
|
|
|
conditional_block:
|
|
test [assembly_mode],AMODE_DEFINITION
|
|
jnz ignored_directive
|
|
mov dl,DBLOCK_CONTROL
|
|
xor ecx,ecx
|
|
call add_directive_block
|
|
mov [edi+DirectiveBlock.subtype],CTRL_IF
|
|
or [edi+DirectiveBlock.flags],CTRLF_ALLOWS_ELSE
|
|
test [assembly_mode],AMODE_SKIP
|
|
jnz skip_conditional_block
|
|
evaluate_conditional_block:
|
|
call get_condition_value
|
|
test al,al
|
|
jnz instruction_assembled
|
|
or [assembly_mode],AMODE_SKIP
|
|
jmp instruction_assembled
|
|
ignored_directive:
|
|
test [assembly_mode],AMODE_SKIP
|
|
jz add_line_to_macro
|
|
jmp assembly_line
|
|
|
|
else_conditional_block:
|
|
test [assembly_mode],AMODE_DEFINITION
|
|
jnz ignored_directive
|
|
mov dl,DBLOCK_CONTROL
|
|
call find_directive_block
|
|
jc unexpected_instruction
|
|
mov al,[edi+DirectiveBlock.flags]
|
|
test al,CTRLF_ALLOWS_ELSE
|
|
jz unexpected_instruction
|
|
mov ah,[assembly_mode]
|
|
push eax
|
|
call close_control_directive_block
|
|
mov dl,DBLOCK_CONTROL
|
|
xor ecx,ecx
|
|
call add_directive_block
|
|
mov [edi+DirectiveBlock.subtype],CTRL_IF
|
|
or [edi+DirectiveBlock.flags],CTRLF_ALLOWS_ELSE
|
|
pop eax
|
|
test al,CTRLF_INACTIVE
|
|
jnz skip_conditional_block
|
|
test ah,AMODE_SKIP
|
|
jnz evaluate_conditional_block
|
|
skip_conditional_block:
|
|
or [assembly_mode],AMODE_SKIP
|
|
or [edi+DirectiveBlock.flags],CTRLF_INACTIVE
|
|
jmp assembly_line
|
|
|
|
end_conditional_block:
|
|
test [assembly_mode],AMODE_DEFINITION
|
|
jnz ignored_directive
|
|
mov dl,DBLOCK_CONTROL
|
|
call find_directive_block
|
|
jc unexpected_instruction
|
|
cmp [edi+DirectiveBlock.subtype],CTRL_IF
|
|
jne unexpected_instruction
|
|
end_control_block:
|
|
call close_control_directive_block
|
|
jmp instruction_assembled
|
|
|
|
conditionally_repeated_block:
|
|
test [assembly_mode],AMODE_DEFINITION
|
|
jnz ignored_directive
|
|
test [assembly_mode],AMODE_SKIP
|
|
jnz inactive_conditionally_repeated_block
|
|
mov ecx,[line_end]
|
|
sub ecx,esi
|
|
add ecx,sizeof.ConditionalRepeatData
|
|
cmp [embedded_context],0
|
|
je condition_length_ok
|
|
add ecx,1+sizeof.RecognitionContext
|
|
condition_length_ok:
|
|
mov dl,DBLOCK_CONTROL
|
|
call add_directive_block
|
|
push esi
|
|
mov ecx,[line_end]
|
|
sub ecx,esi
|
|
sub edi,sizeof.ConditionalRepeatData
|
|
mov edx,ecx
|
|
sub edi,ecx
|
|
rep movsb
|
|
mov esi,[embedded_context]
|
|
test esi,esi
|
|
jz condition_stored
|
|
add edx,1+sizeof.RecognitionContext
|
|
mov ebx,edi
|
|
sub edi,edx
|
|
mov al,40h
|
|
stosb
|
|
assert sizeof.RecognitionContext and 11b = 0
|
|
mov ecx,sizeof.RecognitionContext shr 2
|
|
rep movsd
|
|
mov edi,ebx
|
|
condition_stored:
|
|
mov [edi+ConditionalRepeatData.condition_length],edx
|
|
add edi,sizeof.ConditionalRepeatData
|
|
pop esi
|
|
mov [edi+DirectiveBlock.subtype],CTRL_WHILE
|
|
or [edi+DirectiveBlock.flags],CTRLF_BREAKABLE
|
|
call get_condition_value
|
|
test al,al
|
|
jz skip_repeated_block
|
|
start_repeated_block:
|
|
mov ecx,2
|
|
call allocate_counter
|
|
mov edi,ebx
|
|
mov al,1
|
|
stosb
|
|
stosb
|
|
mov [current_counter],ebx
|
|
mov ecx,[parameter_namespace]
|
|
mov [ecx+SymbolTree_Root.parameters],SPECPARM_COUNTER
|
|
test esi,esi
|
|
jz assembly_line
|
|
jmp instruction_assembled
|
|
inactive_conditionally_repeated_block:
|
|
xor esi,esi
|
|
mov dh,CTRL_WHILE
|
|
inactive_breakable_block:
|
|
mov dl,DBLOCK_CONTROL
|
|
xor ecx,ecx
|
|
call add_directive_block
|
|
mov [edi+DirectiveBlock.subtype],dh
|
|
or [edi+DirectiveBlock.flags],CTRLF_BREAKABLE
|
|
skip_repeated_block:
|
|
or [assembly_mode],AMODE_SKIP
|
|
mov ecx,1
|
|
call allocate_counter
|
|
mov byte [ebx],0
|
|
mov [current_counter],ebx
|
|
mov ecx,[parameter_namespace]
|
|
mov [ecx+SymbolTree_Root.parameters],0
|
|
test esi,esi
|
|
jz assembly_line
|
|
jmp instruction_assembled
|
|
allocate_counter:
|
|
mov ebx,[current_counter]
|
|
movzx eax,byte [ebx]
|
|
lea ebx,[ebx+1+eax]
|
|
add ecx,ebx
|
|
cmp ecx,[counters_stack_end]
|
|
jbe counter_allocated
|
|
mov eax,[counters_stack_base]
|
|
sub ecx,eax
|
|
sub ebx,eax
|
|
call grow_stack
|
|
add ecx,eax
|
|
mov [counters_stack_end],ecx
|
|
mov [counters_stack_base],eax
|
|
add ebx,eax
|
|
counter_allocated:
|
|
retn
|
|
|
|
end_conditionally_repeated_block:
|
|
test [assembly_mode],AMODE_DEFINITION
|
|
jnz ignored_directive
|
|
mov dl,DBLOCK_CONTROL
|
|
call find_directive_block
|
|
jc unexpected_instruction
|
|
cmp [edi+DirectiveBlock.subtype],CTRL_WHILE
|
|
jne unexpected_instruction
|
|
test [assembly_mode],AMODE_SKIP
|
|
jnz end_control_block
|
|
push esi edi
|
|
push [line_end]
|
|
push [source_context]
|
|
lea esi,[edi-sizeof.ConditionalRepeatData]
|
|
mov [line_end],esi
|
|
sub esi,[esi+ConditionalRepeatData.condition_length]
|
|
sub edi,[edi+DirectiveBlock.length_of_data]
|
|
mov [source_context],edi
|
|
and [embedded_context],0
|
|
call get_condition_value
|
|
pop [source_context]
|
|
pop [line_end]
|
|
pop edi esi
|
|
test al,al
|
|
jz end_control_block
|
|
repeat_condition_upheld:
|
|
mov ebx,[current_counter]
|
|
movzx ecx,byte [ebx]
|
|
inc ebx
|
|
increase_counter:
|
|
inc byte [ebx]
|
|
jnz counter_increased
|
|
inc ebx
|
|
loop increase_counter
|
|
cmp ebx,[counters_stack_end]
|
|
jb counter_length_grown
|
|
lea ecx,[ebx+1]
|
|
mov eax,[counters_stack_base]
|
|
sub ecx,eax
|
|
sub ebx,eax
|
|
sub [current_counter],eax
|
|
call grow_stack
|
|
add ecx,eax
|
|
mov [counters_stack_end],ecx
|
|
mov [counters_stack_base],eax
|
|
add [current_counter],eax
|
|
add ebx,eax
|
|
counter_length_grown:
|
|
mov byte [ebx],1
|
|
mov ebx,[current_counter]
|
|
inc byte [ebx]
|
|
counter_increased:
|
|
push esi
|
|
test [edi+DirectiveBlock.flags],CTRLF_HAS_REPEAT_DATA
|
|
jz index_updated
|
|
mov esi,[current_counter]
|
|
mov eax,[counters_stack_base]
|
|
add eax,[edi-sizeof.RepeatData+RepeatData.index_position]
|
|
cmp eax,esi
|
|
je index_updated
|
|
xchg eax,edi
|
|
movzx ecx,byte [esi]
|
|
inc ecx
|
|
rep movsb
|
|
mov edi,eax
|
|
index_updated:
|
|
mov eax,[source_context]
|
|
mov esi,eax
|
|
call release_source_context
|
|
sub edi,[edi+DirectiveBlock.length_of_data]
|
|
xchg esi,edi
|
|
call clone_source_context
|
|
pop esi
|
|
jmp instruction_assembled
|
|
|
|
repeated_block:
|
|
test [assembly_mode],AMODE_DEFINITION
|
|
jnz ignored_directive
|
|
test [assembly_mode],AMODE_SKIP
|
|
jnz inactive_repeated_block
|
|
call get_numeric_constant_value
|
|
test edx,edx
|
|
jz invalid_count
|
|
mov ecx,[edx]
|
|
add edx,4
|
|
test ecx,ecx
|
|
jz inactive_repeated_block
|
|
mov al,[edx+ecx-1]
|
|
test al,al
|
|
js count_out_of_range
|
|
jnz count_ok
|
|
optimize_counter:
|
|
test ecx,ecx
|
|
jz inactive_repeated_block
|
|
dec ecx
|
|
mov al,[edx+ecx-1]
|
|
test al,al
|
|
jz optimize_counter
|
|
count_ok:
|
|
push esi ecx
|
|
mov esi,edx
|
|
mov dl,DBLOCK_CONTROL
|
|
add ecx,sizeof.RepeatData
|
|
call add_directive_block
|
|
mov [edi+DirectiveBlock.subtype],CTRL_REPEAT
|
|
or [edi+DirectiveBlock.flags],CTRLF_BREAKABLE + CTRLF_HAS_REPEAT_DATA
|
|
mov [directive_block],edi
|
|
pop ecx
|
|
sub edi,sizeof.RepeatData
|
|
mov [edi+RepeatData.limit_length],ecx
|
|
sub edi,ecx
|
|
rep movsb
|
|
pop esi
|
|
mov ecx,2
|
|
call allocate_counter
|
|
mov eax,ebx
|
|
sub eax,[counters_stack_base]
|
|
mov [edi+RepeatData.index_position],eax
|
|
mov edi,ebx
|
|
mov al,1
|
|
stosb
|
|
stosb
|
|
mov [current_counter],ebx
|
|
mov ecx,[parameter_namespace]
|
|
mov [ecx+SymbolTree_Root.parameters],SPECPARM_COUNTER + SPECPARM_LIMIT
|
|
define_named_counters:
|
|
xor al,al
|
|
xchg al,[current_constituent]
|
|
test al,al
|
|
jz get_counter_name
|
|
cmp al,','
|
|
je get_counter_name
|
|
cmp al,1Ah
|
|
jne invalid_argument
|
|
mov esi,[symbol_start]
|
|
get_counter_name:
|
|
call identify_parameter_symbol
|
|
jc instruction_assembled
|
|
test ebx,ebx
|
|
jz invalid_argument
|
|
mov [label_leaf],ebx
|
|
call peek_at_constituent_value
|
|
jc counter_with_default_base
|
|
cmp al,':'
|
|
jne counter_with_default_base
|
|
and [current_constituent],0
|
|
call get_numeric_constant_value
|
|
test edx,edx
|
|
jz invalid_counter_base
|
|
mov ecx,[edx]
|
|
test byte [edx+4+ecx-1],80h
|
|
jns counter_base_ok
|
|
mov edx,_value_out_of_range
|
|
call register_error
|
|
jmp counter_with_default_base
|
|
invalid_counter_base:
|
|
mov edx,_invalid_value
|
|
call register_error
|
|
counter_with_default_base:
|
|
mov edx,singular_value
|
|
counter_base_ok:
|
|
push esi
|
|
mov esi,edx
|
|
mov edx,assembly_workspace
|
|
mov edi,[edx+Workspace.memory_start]
|
|
mov ecx,[esi]
|
|
add ecx,8
|
|
call reserve_workspace
|
|
mov eax,[current_counter]
|
|
sub eax,[counters_stack_base]
|
|
stosd
|
|
lodsd
|
|
mov ecx,eax
|
|
stosd
|
|
rep movsb
|
|
mov esi,[assembly_workspace.memory_start]
|
|
mov ecx,edi
|
|
sub ecx,esi
|
|
mov [value_type],VALTYPE_NUMERIC_SEQUENCE
|
|
mov ebx,[label_leaf]
|
|
mov edi,[directive_block]
|
|
call add_block_parameter
|
|
pop esi
|
|
jmp define_named_counters
|
|
invalid_count:
|
|
mov edx,_invalid_value
|
|
call register_error
|
|
jmp inactive_repeated_block
|
|
count_out_of_range:
|
|
mov edx,_value_out_of_range
|
|
call register_error
|
|
inactive_repeated_block:
|
|
xor esi,esi
|
|
mov dh,CTRL_REPEAT
|
|
jmp inactive_breakable_block
|
|
|
|
end_repeated_block:
|
|
mov dh,CTRL_REPEAT
|
|
close_repeat:
|
|
test [assembly_mode],AMODE_DEFINITION
|
|
jnz ignored_directive
|
|
mov dl,DBLOCK_CONTROL
|
|
call find_directive_block
|
|
jc unexpected_instruction
|
|
cmp dh,[edi+DirectiveBlock.subtype]
|
|
jne unexpected_instruction
|
|
test [assembly_mode],AMODE_SKIP
|
|
jnz end_control_block
|
|
mov edx,[current_counter]
|
|
movzx ecx,byte [edx]
|
|
inc edx
|
|
lea ebx,[edi-sizeof.RepeatData]
|
|
cmp ecx,[ebx+RepeatData.limit_length]
|
|
jne repeat_condition_upheld
|
|
sub ebx,ecx
|
|
compare_counter_with_limit:
|
|
mov al,[ebx]
|
|
cmp al,[edx]
|
|
jne repeat_condition_upheld
|
|
inc ebx
|
|
inc edx
|
|
loop compare_counter_with_limit
|
|
jmp end_control_block
|
|
|
|
iterator_block:
|
|
test [assembly_mode],AMODE_DEFINITION
|
|
jnz ignored_directive
|
|
test [assembly_mode],AMODE_SKIP
|
|
jnz inactive_iterator_block
|
|
xor eax,eax
|
|
mov [breakpoint_token],al
|
|
mov [number_of_parameters],eax
|
|
mov edi,[expression_workspace.memory_start]
|
|
call move_to_next_symbol
|
|
jc invalid_iterator
|
|
cmp al,'<'
|
|
jne iterator_parameter_declaration
|
|
inc esi
|
|
mov [breakpoint_token],'>'
|
|
iterator_parameter_declaration:
|
|
push edi
|
|
call identify_parameter_symbol
|
|
pop edi
|
|
jc invalid_iterator
|
|
test ebx,ebx
|
|
jz invalid_iterator
|
|
mov eax,[number_of_parameters]
|
|
shl eax,2
|
|
add eax,[assembly_stack_base]
|
|
lea ecx,[eax+4]
|
|
cmp ecx,[assembly_stack_end]
|
|
jbe store_parameter_leaf
|
|
mov eax,[assembly_stack_base]
|
|
sub ecx,eax
|
|
call grow_stack
|
|
mov [assembly_stack_base],eax
|
|
add ecx,eax
|
|
mov [assembly_stack_end],ecx
|
|
mov ecx,[number_of_parameters]
|
|
shl ecx,2
|
|
add eax,ecx
|
|
store_parameter_leaf:
|
|
mov [eax],ebx
|
|
mov edx,expression_workspace
|
|
mov ecx,sizeof.LineExcerpt
|
|
call reserve_workspace
|
|
mov [edi+LineExcerpt.data_start],esi
|
|
mov [edi+LineExcerpt.data_end],esi
|
|
inc [number_of_parameters]
|
|
call move_to_next_symbol
|
|
jc invalid_iterator
|
|
cmp al,':'
|
|
je parameter_with_default_value
|
|
cmp al,'='
|
|
je parameter_with_default_value
|
|
cmp al,'*'
|
|
jne parameter_declaration_done
|
|
and [edi+LineExcerpt.data_start],0
|
|
inc esi
|
|
call move_to_next_symbol
|
|
jc invalid_iterator
|
|
jmp parameter_declaration_done
|
|
parameter_with_default_value:
|
|
inc esi
|
|
call cut_argument_value
|
|
parameter_declaration_done:
|
|
add edi,sizeof.LineExcerpt
|
|
mov ah,[breakpoint_token]
|
|
test ah,ah
|
|
jz iterator_parameters_declared
|
|
inc esi
|
|
cmp al,','
|
|
je iterator_parameter_declaration
|
|
cmp al,ah
|
|
jne invalid_iterator
|
|
call move_to_next_symbol
|
|
jc invalid_iterator
|
|
iterator_parameters_declared:
|
|
cmp al,','
|
|
jne invalid_iterator
|
|
mov ebx,[number_of_parameters]
|
|
mov [number_of_values],ebx
|
|
and [number_of_iterations],0
|
|
collect_iterator_values:
|
|
inc esi
|
|
call move_to_next_symbol
|
|
jc initialize_iterator
|
|
mov edx,expression_workspace
|
|
mov ecx,sizeof.LineExcerpt
|
|
call reserve_workspace
|
|
call cut_argument_value
|
|
add edi,sizeof.LineExcerpt
|
|
inc [number_of_values]
|
|
cmp ebx,[number_of_parameters]
|
|
jne iterator_value_collected
|
|
inc [number_of_iterations]
|
|
xor ebx,ebx
|
|
iterator_value_collected:
|
|
inc ebx
|
|
cmp al,','
|
|
je collect_iterator_values
|
|
initialize_iterator:
|
|
cmp [number_of_iterations],0
|
|
je inactive_iterator_block
|
|
mov dl,DBLOCK_CONTROL
|
|
mov ecx,5+sizeof.RepeatData
|
|
call add_directive_block
|
|
mov [edi+DirectiveBlock.subtype],CTRL_IRP
|
|
or [edi+DirectiveBlock.flags],CTRLF_BREAKABLE + CTRLF_HAS_REPEAT_DATA + CTRLF_HAS_WRITABLE_INDEX
|
|
mov [directive_block],edi
|
|
bsr ecx,[number_of_iterations]
|
|
shr ecx,3
|
|
inc ecx
|
|
push esi
|
|
sub edi,sizeof.RepeatData
|
|
mov [edi+RepeatData.limit_length],ecx
|
|
sub edi,ecx
|
|
mov esi,number_of_iterations
|
|
rep movsb
|
|
mov ecx,[edi+RepeatData.limit_length]
|
|
add ecx,3
|
|
call allocate_counter
|
|
mov eax,ebx
|
|
sub eax,[counters_stack_base]
|
|
mov [edi+RepeatData.index_position],eax
|
|
mov ecx,[edi+RepeatData.limit_length]
|
|
mov edi,ebx
|
|
mov al,1
|
|
stosb
|
|
stosb
|
|
lea edi,[edi+ecx-1]
|
|
mov [current_counter],edi
|
|
stosb
|
|
stosb
|
|
mov ecx,[parameter_namespace]
|
|
mov [ecx+SymbolTree_Root.parameters],SPECPARM_COUNTER + SPECPARM_LIMIT
|
|
xor eax,eax
|
|
create_iterator_sequences:
|
|
mov [parameter_index],eax
|
|
mov edx,assembly_workspace
|
|
mov edi,[edx+Workspace.memory_start]
|
|
mov ecx,[number_of_iterations]
|
|
add ecx,2
|
|
shl ecx,2
|
|
call reserve_workspace
|
|
mov eax,[directive_block]
|
|
mov eax,[eax-sizeof.RepeatData+RepeatData.index_position]
|
|
stosd
|
|
mov eax,[number_of_iterations]
|
|
add eax,2
|
|
shl eax,2
|
|
stosd
|
|
mov [sequence_header_length],eax
|
|
mov edx,edi
|
|
mov edi,[assembly_workspace.memory_start]
|
|
sub edx,edi
|
|
mov [sequence_header_cursor],edx
|
|
add edi,eax
|
|
mov eax,[number_of_parameters]
|
|
add eax,[parameter_index]
|
|
cmp eax,[number_of_values]
|
|
jae copy_default_value
|
|
copy_individual_value:
|
|
mov [value_index],eax
|
|
mov ebx,eax
|
|
assert sizeof.LineExcerpt = 1 shl 4
|
|
shl ebx,4
|
|
add ebx,[expression_workspace.memory_start]
|
|
mov esi,[ebx+LineExcerpt.data_start]
|
|
mov ecx,[ebx+LineExcerpt.data_end]
|
|
sub ecx,esi
|
|
jnz individual_value_ready
|
|
copy_default_value:
|
|
mov ebx,[parameter_index]
|
|
assert sizeof.LineExcerpt = 1 shl 4
|
|
shl ebx,4
|
|
add ebx,[expression_workspace.memory_start]
|
|
mov esi,[ebx+LineExcerpt.data_start]
|
|
test esi,esi
|
|
jz missing_required_individual_value
|
|
mov ecx,[ebx+LineExcerpt.data_end]
|
|
sub ecx,esi
|
|
individual_value_ready:
|
|
mov edx,assembly_workspace
|
|
add ecx,2*(1+sizeof.RecognitionContext)
|
|
call reserve_workspace
|
|
mov ecx,[ebx+LineExcerpt.data_end]
|
|
sub ecx,esi
|
|
jz next_iterator_value
|
|
cmp [ebx+LineExcerpt.recognition_context],0
|
|
je copy_iterator_value
|
|
mov al,40h
|
|
stosb
|
|
mov eax,esi
|
|
mov edx,ecx
|
|
mov esi,[ebx+LineExcerpt.recognition_context]
|
|
assert sizeof.RecognitionContext and 11b = 0
|
|
mov ecx,sizeof.RecognitionContext shr 2
|
|
rep movsd
|
|
mov ecx,edx
|
|
mov esi,eax
|
|
copy_iterator_value:
|
|
rep movsb
|
|
mov eax,[ebx+LineExcerpt.recognition_context]
|
|
or eax,[ebx+LineExcerpt.leftover_context]
|
|
jz next_iterator_value
|
|
mov al,40h
|
|
stosb
|
|
xor eax,eax
|
|
assert sizeof.RecognitionContext and 11b = 0
|
|
mov ecx,sizeof.RecognitionContext shr 2
|
|
rep stosd
|
|
next_iterator_value:
|
|
mov edx,[assembly_workspace.memory_start]
|
|
mov ecx,edi
|
|
sub ecx,edx
|
|
add edx,[sequence_header_cursor]
|
|
mov [edx],ecx
|
|
add [sequence_header_cursor],4
|
|
mov eax,[value_index]
|
|
add eax,[number_of_parameters]
|
|
cmp eax,[number_of_values]
|
|
jb copy_individual_value
|
|
mov eax,[sequence_header_length]
|
|
sub eax,[sequence_header_cursor]
|
|
jne copy_default_value
|
|
mov ecx,edi
|
|
mov esi,[assembly_workspace.memory_start]
|
|
sub ecx,esi
|
|
mov eax,[parameter_index]
|
|
shl eax,2
|
|
add eax,[assembly_stack_base]
|
|
mov ebx,[eax]
|
|
mov edi,[directive_block]
|
|
mov [value_type],VALTYPE_SYMBOLIC_SEQUENCE
|
|
call add_block_parameter
|
|
mov eax,[parameter_index]
|
|
inc eax
|
|
cmp eax,[number_of_parameters]
|
|
jb create_iterator_sequences
|
|
pop esi
|
|
jmp instruction_assembled
|
|
missing_required_individual_value:
|
|
mov edx,_missing_argument
|
|
call register_error
|
|
jmp next_iterator_value
|
|
invalid_iterator:
|
|
mov edx,_invalid_argument
|
|
call register_error
|
|
inactive_iterator_block:
|
|
xor esi,esi
|
|
mov dh,CTRL_IRP
|
|
jmp inactive_breakable_block
|
|
|
|
end_iterator_block:
|
|
mov dh,CTRL_IRP
|
|
jmp close_repeat
|
|
|
|
variable_iterator_block:
|
|
test [assembly_mode],AMODE_DEFINITION
|
|
jnz ignored_directive
|
|
test [assembly_mode],AMODE_SKIP
|
|
jnz skipped_variable_iterator_block
|
|
call move_to_next_symbol
|
|
jc invalid_iterator
|
|
call identify_parameter_symbol
|
|
jc invalid_variable_iterator
|
|
test ebx,ebx
|
|
jz invalid_variable_iterator
|
|
mov [label_leaf],ebx
|
|
call move_to_next_symbol
|
|
jc invalid_variable_iterator
|
|
cmp al,','
|
|
jne invalid_variable_iterator
|
|
inc esi
|
|
and [symbol_definition],0
|
|
mov dl,SYMCLASS_EXPRESSION
|
|
call identify_symbol
|
|
jc invalid_variable_identifier
|
|
test ebx,ebx
|
|
jz invalid_variable_identifier
|
|
mov eax,[current_pass]
|
|
mov [ebx+SymbolTree_Leaf.last_use_pass],eax
|
|
mov edi,[assembly_stack_base]
|
|
xor ecx,ecx
|
|
mov [number_of_values],ecx
|
|
mov edx,[ebx+SymbolTree_Leaf.definition]
|
|
collect_variable_values:
|
|
test edx,edx
|
|
jz variable_values_collected
|
|
mov eax,[edx+ValueDefinition.pass]
|
|
cmp eax,[current_pass]
|
|
jne variable_values_collected
|
|
cmp [edx+ValueDefinition.type],VALTYPE_RESERVED
|
|
je skip_variable_value
|
|
add edi,4
|
|
cmp edi,[assembly_stack_end]
|
|
jbe store_variable_value
|
|
push ecx edx
|
|
mov eax,[assembly_stack_base]
|
|
sub edi,eax
|
|
mov ecx,edi
|
|
call grow_stack
|
|
add edi,eax
|
|
mov [assembly_stack_base],eax
|
|
add eax,ecx
|
|
mov [assembly_stack_end],eax
|
|
pop edx ecx
|
|
store_variable_value:
|
|
mov [edi-4],edx
|
|
inc [number_of_values]
|
|
add ecx,[edx+ValueDefinition.value_length]
|
|
add ecx,1+sizeof.RecognitionContext
|
|
skip_variable_value:
|
|
mov edx,[edx+ValueDefinition.previous]
|
|
jmp collect_variable_values
|
|
variable_values_collected:
|
|
mov eax,[number_of_values]
|
|
test eax,eax
|
|
jz inactive_variable_iterator_block
|
|
add eax,2
|
|
shl eax,2
|
|
add ecx,eax
|
|
mov edx,assembly_workspace
|
|
mov edi,[edx+Workspace.memory_start]
|
|
call reserve_workspace
|
|
mov dl,DBLOCK_CONTROL
|
|
mov ecx,5+sizeof.RepeatData
|
|
call add_directive_block
|
|
mov [edi+DirectiveBlock.subtype],CTRL_IRPV
|
|
or [edi+DirectiveBlock.flags],CTRLF_BREAKABLE + CTRLF_HAS_REPEAT_DATA + CTRLF_HAS_WRITABLE_INDEX
|
|
mov [directive_block],edi
|
|
bsr ecx,[number_of_values]
|
|
shr ecx,3
|
|
inc ecx
|
|
push esi
|
|
sub edi,sizeof.RepeatData
|
|
mov [edi+RepeatData.limit_length],ecx
|
|
sub edi,ecx
|
|
mov esi,number_of_values
|
|
rep movsb
|
|
mov ecx,[edi+RepeatData.limit_length]
|
|
add ecx,3
|
|
call allocate_counter
|
|
mov eax,ebx
|
|
sub eax,[counters_stack_base]
|
|
mov [edi+RepeatData.index_position],eax
|
|
mov ecx,[edi+RepeatData.limit_length]
|
|
mov edi,ebx
|
|
mov al,1
|
|
stosb
|
|
stosb
|
|
lea edi,[edi+ecx-1]
|
|
mov [current_counter],edi
|
|
stosb
|
|
stosb
|
|
mov ecx,[parameter_namespace]
|
|
mov [ecx+SymbolTree_Root.parameters],SPECPARM_COUNTER + SPECPARM_LIMIT
|
|
mov edi,[assembly_workspace.memory_start]
|
|
mov ecx,[number_of_values]
|
|
mov edx,ecx
|
|
add ecx,2
|
|
shl ecx,2
|
|
mov ebx,edi
|
|
add edi,ecx
|
|
mov eax,[directive_block]
|
|
mov eax,[eax-sizeof.RepeatData+RepeatData.index_position]
|
|
mov [ebx],eax
|
|
add ebx,4
|
|
mov [ebx],ecx
|
|
create_value_sequence:
|
|
mov eax,edx
|
|
dec eax
|
|
shl eax,2
|
|
add eax,[assembly_stack_base]
|
|
mov eax,[eax]
|
|
push edx
|
|
mov cl,[eax+ValueDefinition.type]
|
|
cmp cl,VALTYPE_SYMBOLIC
|
|
je symbolic_value_in_sequence
|
|
cmp cl,VALTYPE_NUMERIC
|
|
jne proxy_value_in_sequence
|
|
mov esi,[eax+ValueDefinition.value]
|
|
mov ecx,[esi]
|
|
add esi,4
|
|
test byte [esi+ecx-1],80h
|
|
jnz proxy_value_in_sequence
|
|
cmp dword [esi+ecx],0
|
|
jne proxy_value_in_sequence
|
|
push ecx
|
|
add ecx,1+4
|
|
call allocate_value_in_sequence
|
|
pop ecx
|
|
mov al,30h
|
|
stosb
|
|
mov eax,ecx
|
|
stosd
|
|
rep movsb
|
|
jmp next_value_in_sequence
|
|
allocate_value_in_sequence:
|
|
mov eax,[ebx]
|
|
add eax,ecx
|
|
add ebx,4
|
|
mov [ebx],eax
|
|
mov edx,assembly_workspace
|
|
sub ebx,[edx+Workspace.memory_start]
|
|
call reserve_workspace
|
|
add ebx,[assembly_workspace.memory_start]
|
|
retn
|
|
proxy_value_in_sequence:
|
|
mov esi,eax
|
|
mov ecx,(1+sizeof.RecognitionContext)*2+1
|
|
call allocate_value_in_sequence
|
|
push ebx edi
|
|
push esi
|
|
xor eax,eax
|
|
mov ecx,[proxy_number]
|
|
inc [proxy_number]
|
|
mov dl,SYMCLASS_EXPRESSION
|
|
mov ebx,[current_context.base_namespace]
|
|
call get_abstract_symbol
|
|
xchg edx,[esp]
|
|
call update_value_link
|
|
pop edx
|
|
pop edi ebx
|
|
mov al,40h
|
|
stosb
|
|
mov eax,[current_context.base_namespace]
|
|
mov [edi+RecognitionContext.base_namespace],eax
|
|
mov [edi+RecognitionContext.base_label],edx
|
|
add edi,sizeof.RecognitionContext
|
|
mov al,'.'
|
|
stosb
|
|
jmp close_symbolic_value_in_sequence
|
|
symbolic_value_in_sequence:
|
|
mov esi,[eax+ValueDefinition.value]
|
|
mov ecx,[eax+ValueDefinition.value_length]
|
|
push ecx
|
|
add ecx,1+sizeof.RecognitionContext
|
|
call allocate_value_in_sequence
|
|
pop ecx
|
|
rep movsb
|
|
close_symbolic_value_in_sequence:
|
|
mov al,40h
|
|
stosb
|
|
xor eax,eax
|
|
assert sizeof.RecognitionContext and 11b = 0
|
|
mov ecx,sizeof.RecognitionContext shr 2
|
|
rep stosd
|
|
next_value_in_sequence:
|
|
pop edx
|
|
dec edx
|
|
jnz create_value_sequence
|
|
mov esi,[assembly_workspace.memory_start]
|
|
mov ecx,edi
|
|
sub ecx,esi
|
|
mov ebx,[label_leaf]
|
|
mov edi,[directive_block]
|
|
mov [value_type],VALTYPE_SYMBOLIC_SEQUENCE
|
|
call add_block_parameter
|
|
pop esi
|
|
jmp instruction_assembled
|
|
invalid_variable_identifier:
|
|
mov edx,_invalid_identifier
|
|
call register_error
|
|
jmp inactive_variable_iterator_block
|
|
invalid_variable_iterator:
|
|
mov edx,_invalid_argument
|
|
call register_error
|
|
skipped_variable_iterator_block:
|
|
xor esi,esi
|
|
inactive_variable_iterator_block:
|
|
mov dh,CTRL_IRPV
|
|
jmp inactive_breakable_block
|
|
|
|
end_variable_iterator_block:
|
|
mov dh,CTRL_IRPV
|
|
jmp close_repeat
|
|
|
|
set_iterator_index:
|
|
mov dl,DBLOCK_CONTROL
|
|
call find_directive_block
|
|
jc unexpected_instruction
|
|
find_indexable_block:
|
|
test [edi+DirectiveBlock.flags],CTRLF_HAS_WRITABLE_INDEX
|
|
jnz indexable_block_found
|
|
call find_next_directive_block
|
|
jc unexpected_instruction
|
|
jmp find_indexable_block
|
|
indexable_block_found:
|
|
; test [edi+DirectiveBlock.flags],CTRLF_HAS_REPEAT_DATA
|
|
; jnz internal_error
|
|
mov [directive_block],edi
|
|
call get_numeric_constant_value
|
|
test edx,edx
|
|
jz invalid_argument
|
|
mov ecx,[edx]
|
|
add edx,4
|
|
mov al,[edx+ecx-1]
|
|
test al,al
|
|
js value_out_of_range
|
|
jnz index_optimized
|
|
optimize_index:
|
|
test ecx,ecx
|
|
jz value_out_of_range
|
|
dec ecx
|
|
mov al,[edx+ecx-1]
|
|
test al,al
|
|
jz optimize_index
|
|
index_optimized:
|
|
mov edi,[directive_block]
|
|
sub edi,sizeof.RepeatData
|
|
mov ebx,[edi+RepeatData.limit_length]
|
|
cmp ecx,ebx
|
|
ja value_out_of_range
|
|
jb index_ok
|
|
sub edi,ebx
|
|
compare_index_with_limit:
|
|
mov al,[edx+ebx-1]
|
|
cmp al,[edi+ebx-1]
|
|
ja value_out_of_range
|
|
jb index_ok
|
|
dec ebx
|
|
jnz compare_index_with_limit
|
|
index_ok:
|
|
xchg esi,edx
|
|
mov edi,[directive_block]
|
|
mov edi,[edi-sizeof.RepeatData+RepeatData.index_position]
|
|
add edi,[counters_stack_base]
|
|
mov al,cl
|
|
stosb
|
|
rep movsb
|
|
mov esi,edx
|
|
jmp instruction_assembled
|
|
|
|
break_directive:
|
|
mov dl,DBLOCK_CONTROL
|
|
call find_directive_block
|
|
jc unexpected_instruction
|
|
find_block_to_break:
|
|
test [edi+DirectiveBlock.flags],CTRLF_BREAKABLE
|
|
jnz block_to_break_found
|
|
call find_next_directive_block
|
|
jc unexpected_instruction
|
|
jmp find_block_to_break
|
|
block_to_break_found:
|
|
or [assembly_mode],AMODE_SKIP
|
|
mov dl,DBLOCK_CONTROL
|
|
call find_directive_block
|
|
break_blocks:
|
|
or [edi+DirectiveBlock.flags],CTRLF_INACTIVE
|
|
test [edi+DirectiveBlock.flags],CTRLF_BREAKABLE
|
|
jnz disable_counter
|
|
or [edi+DirectiveBlock.prior_assembly_mode],AMODE_SKIP
|
|
call find_next_directive_block
|
|
jc unexpected_instruction
|
|
jmp break_blocks
|
|
disable_counter:
|
|
mov edi,[current_counter]
|
|
xor al,al
|
|
stosb
|
|
jmp instruction_assembled
|
|
|
|
else_directive:
|
|
mov edx,[ebx+SymbolTree_Leaf.branch]
|
|
call get_symbol_namespace
|
|
and [symbol_definition],0
|
|
mov dl,SYMCLASS_INSTRUCTION
|
|
call identify_symbol_in_namespace
|
|
jc plain_else
|
|
test ebx,ebx
|
|
jz invalid_else
|
|
mov al,[ebx+SymbolTree_Leaf.class]
|
|
cmp al,SYMCLASS_INSTRUCTION
|
|
jne invalid_else
|
|
call get_available_value
|
|
jc invalid_else
|
|
jmp prefixed_directive
|
|
invalid_else:
|
|
mov esi,[symbol_start]
|
|
plain_else:
|
|
test [assembly_mode],AMODE_DEFINITION
|
|
jnz ignored_directive
|
|
mov dl,DBLOCK_CONTROL
|
|
call find_directive_block
|
|
jc unexpected_instruction
|
|
test [edi+DirectiveBlock.flags],CTRLF_ALLOWS_ELSE
|
|
jz unexpected_instruction
|
|
and [edi+DirectiveBlock.flags],not CTRLF_ALLOWS_ELSE
|
|
call remove_block_parameters
|
|
test [edi+DirectiveBlock.flags],CTRLF_INACTIVE
|
|
jnz assembly_line
|
|
xor [assembly_mode],AMODE_SKIP
|
|
jmp instruction_assembled
|
|
|
|
end_directive:
|
|
mov edx,[ebx+SymbolTree_Leaf.branch]
|
|
call get_symbol_namespace
|
|
and [symbol_definition],0
|
|
mov dl,SYMCLASS_INSTRUCTION
|
|
call identify_symbol_in_namespace
|
|
jc missing_prefixed_directive
|
|
test ebx,ebx
|
|
jz invalid_prefixed_directive
|
|
mov al,[ebx+SymbolTree_Leaf.class]
|
|
cmp al,SYMCLASS_INSTRUCTION
|
|
jne invalid_prefixed_directive
|
|
call get_available_value
|
|
jc invalid_prefixed_directive
|
|
prefixed_directive:
|
|
test [edx+ValueDefinition.flags],VAL_UNCONDITIONAL
|
|
jnz execute_prefixed_directive
|
|
test [assembly_mode],AMODE_SKIP
|
|
jnz assembly_line
|
|
test [assembly_mode],AMODE_DEFINITION
|
|
jnz add_line_to_macro
|
|
execute_prefixed_directive:
|
|
mov al,[edx+ValueDefinition.type]
|
|
cmp al,VALTYPE_CALM
|
|
je launch_calm
|
|
cmp al,VALTYPE_SYMBOLIC
|
|
je use_macro
|
|
cmp al,VALTYPE_NATIVE_COMMAND
|
|
jne invalid_argument
|
|
jmp [edx+ValueDefinition.value]
|
|
missing_prefixed_directive:
|
|
test [assembly_mode],AMODE_SKIP
|
|
jnz assembly_line
|
|
test [assembly_mode],AMODE_DEFINITION
|
|
jnz add_line_to_macro
|
|
cmp [interceptor],0
|
|
jne execute_interceptor
|
|
jmp missing_argument
|
|
invalid_prefixed_directive:
|
|
test [assembly_mode],AMODE_SKIP
|
|
jnz assembly_line
|
|
test [assembly_mode],AMODE_DEFINITION
|
|
jnz add_line_to_macro
|
|
cmp [interceptor],0
|
|
jne execute_interceptor
|
|
jmp invalid_argument
|
|
|
|
raw_match_block:
|
|
mov bl,CTRL_RMATCH
|
|
jmp begin_match_block
|
|
match_block:
|
|
mov bl,CTRL_MATCH
|
|
begin_match_block:
|
|
test [assembly_mode],AMODE_DEFINITION
|
|
jnz ignored_directive
|
|
cmp bl,CTRL_RMATCH
|
|
sete [unprocessed_matching]
|
|
mov dl,DBLOCK_CONTROL
|
|
xor ecx,ecx
|
|
call add_directive_block
|
|
mov [directive_block],edi
|
|
mov [edi+DirectiveBlock.subtype],bl
|
|
or [edi+DirectiveBlock.flags],CTRLF_ALLOWS_ELSE
|
|
test [assembly_mode],AMODE_SKIP
|
|
jnz skip_conditional_block
|
|
evaluate_match:
|
|
mov [pattern_start],esi
|
|
and [number_of_parameters],0
|
|
get_match_pattern:
|
|
call move_to_next_symbol
|
|
jc invalid_match
|
|
qualify_pattern_element:
|
|
cmp al,','
|
|
je match_pattern_ok
|
|
cmp al,1Ah
|
|
je count_pattern_parameter
|
|
cmp al,30h
|
|
je invalid_match
|
|
cmp al,'='
|
|
jne skip_pattern_symbol
|
|
call skip_token
|
|
xor ecx,ecx
|
|
call move_to_next_symbol
|
|
jc invalid_match
|
|
test ecx,ecx
|
|
jz skip_pattern_symbol
|
|
jmp qualify_pattern_element
|
|
count_pattern_parameter:
|
|
call detect_numeric_symbol
|
|
jc invalid_match
|
|
inc [number_of_parameters]
|
|
add esi,1+4
|
|
jmp get_match_pattern
|
|
skip_pattern_symbol:
|
|
call skip_token
|
|
jmp get_match_pattern
|
|
match_pattern_ok:
|
|
mov [pattern_end],esi
|
|
inc esi
|
|
mov [argument_start],esi
|
|
mov eax,[embedded_context]
|
|
mov [matched_context],eax
|
|
mov edi,[expression_workspace.memory_start]
|
|
mov ecx,[number_of_parameters]
|
|
assert sizeof.MatchedParameter = 1 shl 3
|
|
shl ecx,3
|
|
mov ebx,ecx
|
|
mov edx,expression_workspace
|
|
call reserve_workspace
|
|
add edi,ebx
|
|
mov [substitutions_end],edi
|
|
cmp [unprocessed_matching],0
|
|
jne substitutions_ready
|
|
detect_substitutions:
|
|
mov eax,[embedded_context]
|
|
mov [stored_context],eax
|
|
and [symbol_definition],0
|
|
mov dl,SYMCLASS_EXPRESSION
|
|
call identify_symbol
|
|
jc substitutions_ready
|
|
test edi,edi
|
|
jnz check_for_substitution
|
|
call skip_literal
|
|
xor ebx,ebx
|
|
check_for_substitution:
|
|
test ebx,ebx
|
|
jz detect_substitutions
|
|
call get_available_value
|
|
jc detect_substitutions
|
|
cmp [edx+ValueDefinition.type],VALTYPE_SYMBOLIC
|
|
jne detect_substitutions
|
|
mov eax,[current_pass]
|
|
mov [ebx+SymbolTree_Leaf.last_use_pass],eax
|
|
mov ebx,edx
|
|
mov edi,[substitutions_end]
|
|
mov edx,expression_workspace
|
|
mov ecx,sizeof.SymbolSubstitution
|
|
call reserve_workspace
|
|
mov eax,[ebx+ValueDefinition.value]
|
|
mov [edi+SymbolSubstitution.value_start],eax
|
|
add eax,[ebx+ValueDefinition.value_length]
|
|
mov [edi+SymbolSubstitution.value_end],eax
|
|
mov ebx,esi
|
|
mov esi,[symbol_start]
|
|
mov [edi+SymbolSubstitution.symbol_start],esi
|
|
scan_replaced_symbol:
|
|
mov al,[esi]
|
|
cmp al,20h
|
|
je whitespace_in_replaced_symbol
|
|
cmp al,40h
|
|
jne actual_replaced_symbol
|
|
inc esi
|
|
mov [stored_context],esi
|
|
add esi,sizeof.RecognitionContext
|
|
jmp next_token_in_replaced_symbol
|
|
whitespace_in_replaced_symbol:
|
|
inc esi
|
|
jmp next_token_in_replaced_symbol
|
|
actual_replaced_symbol:
|
|
call skip_token
|
|
mov ecx,esi
|
|
mov edx,[stored_context]
|
|
next_token_in_replaced_symbol:
|
|
cmp esi,ebx
|
|
jb scan_replaced_symbol
|
|
mov [edi+SymbolSubstitution.symbol_end],ecx
|
|
mov [edi+SymbolSubstitution.leftover_context],edx
|
|
add edi,sizeof.SymbolSubstitution
|
|
mov [substitutions_end],edi
|
|
jmp detect_substitutions
|
|
substitutions_ready:
|
|
mov ebx,[number_of_parameters]
|
|
assert sizeof.MatchedParameter = 1 shl 3
|
|
shl ebx,3
|
|
add ebx,[expression_workspace.memory_start]
|
|
mov esi,[argument_start]
|
|
mov edi,[pattern_start]
|
|
xor eax,eax
|
|
mov [parameter_index],eax
|
|
mov [stored_position],eax
|
|
mov [substitution_active],al
|
|
match_with_pattern:
|
|
call get_pattern_token
|
|
cmp ah,1Ah
|
|
jne exact_match
|
|
wildcard_match:
|
|
call get_matched_token
|
|
jc no_match
|
|
cmp al,20h
|
|
jne wildcard_matched
|
|
inc esi
|
|
jmp wildcard_match
|
|
wildcard_matched:
|
|
xor eax,eax
|
|
mov edx,[expression_workspace.memory_start]
|
|
mov ecx,[parameter_index]
|
|
jecxz prepare_matched_parameter
|
|
dec ecx
|
|
assert sizeof.MatchedParameter = 1 shl 3
|
|
shl ecx,3
|
|
add edx,ecx
|
|
push edi
|
|
mov edi,[assembly_workspace.memory_start]
|
|
add edi,[edx+MatchedParameter.assembly_position]
|
|
push edx
|
|
call close_matched_value
|
|
pop edx
|
|
mov eax,edi
|
|
sub eax,[assembly_workspace.memory_start]
|
|
mov [edx+MatchedParameter.assembly_position],eax
|
|
pop edi
|
|
add edx,sizeof.MatchedParameter
|
|
prepare_matched_parameter:
|
|
mov [edx+MatchedParameter.pattern],edi
|
|
inc [parameter_index]
|
|
mov edi,[assembly_workspace.memory_start]
|
|
add edi,eax
|
|
xor eax,eax
|
|
mov [embedded_context],eax
|
|
mov [stored_position],eax
|
|
mov [whitespace_matching],al
|
|
push edx
|
|
call copy_matched_token
|
|
pop edx
|
|
sub edi,[assembly_workspace.memory_start]
|
|
mov [edx+MatchedParameter.assembly_position],edi
|
|
mov edi,[edx+MatchedParameter.pattern]
|
|
add edi,1+4
|
|
call get_pattern_token
|
|
cmp ah,1Ah
|
|
je wildcard_match
|
|
cmp ah,'?'
|
|
jne exact_match
|
|
inc edi
|
|
jmp match_with_pattern
|
|
exact_match:
|
|
cmp [stored_position],0
|
|
jne match_position_stored
|
|
mov [stored_position],esi
|
|
mov [stored_substitution],ebx
|
|
mov dl,[substitution_active]
|
|
mov [stored_substitution_activity],dl
|
|
mov ecx,[matched_context]
|
|
mov [stored_context],ecx
|
|
mov [stored_pattern],edi
|
|
or [whitespace_matching],1
|
|
match_position_stored:
|
|
cmp ah,','
|
|
je end_of_pattern
|
|
cmp ah,20h
|
|
je allow_whitespace
|
|
cmp ah,'='
|
|
jne match_tokens
|
|
inc edi
|
|
call get_pattern_token
|
|
match_tokens:
|
|
call get_matched_token
|
|
jc no_match
|
|
cmp al,20h
|
|
je match_whitespace
|
|
and [whitespace_matching],0
|
|
cmpsb
|
|
jne token_mismatch
|
|
cmp ah,1Ah
|
|
je match_name_tokens
|
|
cmp ah,22h
|
|
je match_string_tokens
|
|
cmp ah,27h
|
|
je match_string_tokens
|
|
cmp ah,30h
|
|
jne match_with_pattern
|
|
mov ecx,esi
|
|
mov edx,edi
|
|
lodsd
|
|
add esi,eax
|
|
mov eax,[edi]
|
|
lea edi,[edi+4+eax]
|
|
call get_pattern_token
|
|
cmp ah,'?'
|
|
jne compare_token_contents
|
|
inc edi
|
|
jmp compare_token_contents
|
|
match_string_tokens:
|
|
lodsd
|
|
mov ecx,eax
|
|
mov edx,[edi]
|
|
add edi,4
|
|
compare_token_contents:
|
|
cmp ecx,edx
|
|
je match_with_pattern
|
|
push esi edi
|
|
mov esi,ecx
|
|
mov edi,edx
|
|
mov ecx,[esi]
|
|
add ecx,4
|
|
repe cmpsb
|
|
pop edi esi
|
|
jne retract_match
|
|
jmp match_with_pattern
|
|
match_name_tokens:
|
|
lodsd
|
|
mov ecx,eax
|
|
mov edx,[edi]
|
|
add edi,4
|
|
call get_pattern_token
|
|
cmp ah,'?'
|
|
je case_insensitive_match
|
|
cmp ecx,edx
|
|
je match_with_pattern
|
|
push esi edi
|
|
mov esi,ecx
|
|
mov edi,edx
|
|
lodsd
|
|
scasd
|
|
jne name_mismatch
|
|
mov ecx,eax
|
|
mov eax,[esi+ecx]
|
|
cmp eax,[edi+ecx]
|
|
jne name_mismatch
|
|
repe cmpsb
|
|
jne name_mismatch
|
|
pop edi esi
|
|
jmp match_with_pattern
|
|
name_mismatch:
|
|
pop edi esi
|
|
jmp retract_match
|
|
case_insensitive_match:
|
|
inc edi
|
|
cmp ecx,edx
|
|
je match_with_pattern
|
|
push esi edi
|
|
mov esi,ecx
|
|
mov edi,edx
|
|
lodsd
|
|
scasd
|
|
jne name_mismatch
|
|
mov ecx,eax
|
|
mov eax,[esi+ecx+4]
|
|
cmp eax,[edi+ecx+4]
|
|
jne name_mismatch
|
|
xor eax,eax
|
|
compare_case_insensitively:
|
|
lodsb
|
|
mov dl,[characters+eax]
|
|
mov al,[edi]
|
|
inc edi
|
|
cmp dl,[characters+eax]
|
|
jne name_mismatch
|
|
loop compare_case_insensitively
|
|
pop edi esi
|
|
jmp match_with_pattern
|
|
match_converted_number:
|
|
call convert_number_to_match
|
|
jmp compare_token_contents
|
|
match_with_converted_number:
|
|
xchg esi,edi
|
|
call convert_number_to_match
|
|
xchg esi,edi
|
|
jmp compare_token_contents
|
|
convert_number_to_match:
|
|
mov edx,esi
|
|
lodsd
|
|
add esi,eax
|
|
push ebx esi edi
|
|
call convert_number_back
|
|
pop edi esi ebx
|
|
mov ecx,[edi]
|
|
add edi,4
|
|
retn
|
|
token_mismatch:
|
|
cmp ax,1A30h
|
|
je match_converted_number
|
|
cmp ax,301Ah
|
|
je match_with_converted_number
|
|
retract_match:
|
|
xor esi,esi
|
|
xchg esi,[stored_position]
|
|
test esi,esi
|
|
jz no_match
|
|
mov ebx,[stored_substitution]
|
|
mov dl,[stored_substitution_activity]
|
|
mov [substitution_active],dl
|
|
mov ecx,[stored_context]
|
|
mov [matched_context],ecx
|
|
mov edi,[stored_pattern]
|
|
and [whitespace_matching],0
|
|
mov edx,[parameter_index]
|
|
sub edx,1
|
|
jc no_match
|
|
assert sizeof.MatchedParameter = 1 shl 3
|
|
shl edx,3
|
|
add edx,[expression_workspace.memory_start]
|
|
push edi
|
|
mov edi,[assembly_workspace.memory_start]
|
|
add edi,[edx+MatchedParameter.assembly_position]
|
|
push edx
|
|
copy_whitespace:
|
|
call get_matched_token
|
|
jc no_match
|
|
cmp al,20h
|
|
jne copy_additional_symbol
|
|
call copy_matched_token
|
|
jmp copy_whitespace
|
|
copy_additional_symbol:
|
|
call copy_matched_token
|
|
pop edx
|
|
sub edi,[assembly_workspace.memory_start]
|
|
mov [edx+MatchedParameter.assembly_position],edi
|
|
pop edi
|
|
jmp match_with_pattern
|
|
match_whitespace:
|
|
cmp al,ah
|
|
je required_whitespace
|
|
cmp [whitespace_matching],0
|
|
je retract_match
|
|
inc esi
|
|
jmp match_tokens
|
|
required_whitespace:
|
|
inc esi
|
|
allow_whitespace:
|
|
inc edi
|
|
or [whitespace_matching],1
|
|
jmp match_with_pattern
|
|
end_of_pattern:
|
|
call get_matched_token
|
|
jc pattern_matched
|
|
cmp al,20h
|
|
jne retract_match
|
|
call skip_token
|
|
jmp end_of_pattern
|
|
pattern_matched:
|
|
mov ebx,[parameter_index]
|
|
sub ebx,1
|
|
jc matching_done
|
|
assert sizeof.MatchedParameter = 1 shl 3
|
|
shl ebx,3
|
|
add ebx,[expression_workspace.memory_start]
|
|
mov edi,[assembly_workspace.memory_start]
|
|
add edi,[ebx+MatchedParameter.assembly_position]
|
|
call close_matched_value
|
|
sub edi,[assembly_workspace.memory_start]
|
|
mov [ebx+MatchedParameter.assembly_position],edi
|
|
matching_done:
|
|
cmp [number_of_parameters],0
|
|
je assembly_line
|
|
mov [symbol_class],SYMCLASS_PARAMETER
|
|
and [name_volatile],0
|
|
and [name_token],0
|
|
or [symbol_required],1
|
|
or [symbol_expected],1
|
|
mov [value_type],VALTYPE_SYMBOLIC
|
|
xor eax,eax
|
|
mov [value_index],eax
|
|
define_matched_parameters:
|
|
mov [parameter_index],eax
|
|
assert sizeof.MatchedParameter = 1 shl 3
|
|
shl eax,3
|
|
add eax,[expression_workspace.memory_start]
|
|
mov edi,[eax+MatchedParameter.pattern]
|
|
mov esi,[edi+1]
|
|
lodsd
|
|
mov ecx,eax
|
|
add edi,1+4
|
|
call get_pattern_token
|
|
mov edx,[esi+ecx]
|
|
mov al,NAME_CASESENSITIVE
|
|
cmp ah,'?'
|
|
jne matched_name_kind_ok
|
|
mov edx,[esi+ecx+4]
|
|
mov al,NAME_CASEINSENSITIVE
|
|
matched_name_kind_ok:
|
|
mov [name_kind],al
|
|
mov ebx,[parameter_namespace]
|
|
call scan_namespace
|
|
mov eax,[parameter_index]
|
|
assert sizeof.MatchedParameter = 1 shl 3
|
|
shl eax,3
|
|
add eax,[expression_workspace.memory_start]
|
|
mov ecx,[eax+MatchedParameter.assembly_position]
|
|
mov esi,ecx
|
|
xchg esi,[value_index]
|
|
sub ecx,esi
|
|
add esi,[assembly_workspace.memory_start]
|
|
mov edi,[directive_block]
|
|
call add_block_parameter
|
|
mov eax,[parameter_index]
|
|
inc eax
|
|
cmp eax,[number_of_parameters]
|
|
jb define_matched_parameters
|
|
jmp assembly_line
|
|
no_match:
|
|
or [assembly_mode],AMODE_SKIP
|
|
jmp assembly_line
|
|
invalid_match:
|
|
mov edx,_invalid_argument
|
|
call register_error
|
|
or [assembly_mode],AMODE_SKIP
|
|
jmp assembly_line
|
|
get_pattern_token:
|
|
mov ah,[edi]
|
|
cmp ah,40h
|
|
je skip_pattern_context
|
|
retn
|
|
skip_pattern_context:
|
|
add edi,1+sizeof.RecognitionContext
|
|
jmp get_pattern_token
|
|
get_matched_token:
|
|
cmp ebx,[substitutions_end]
|
|
je token_in_line
|
|
cmp [substitution_active],0
|
|
jne token_in_substitution
|
|
cmp esi,[ebx+SymbolSubstitution.symbol_start]
|
|
je substitution_encountered
|
|
token_in_line:
|
|
cmp esi,[line_end]
|
|
je no_more_matched_tokens
|
|
check_for_matched_token:
|
|
mov al,[esi]
|
|
cmp al,40h
|
|
je matched_context_change
|
|
clc
|
|
retn
|
|
no_more_matched_tokens:
|
|
stc
|
|
retn
|
|
matched_context_change:
|
|
inc esi
|
|
cmp [unprocessed_matching],0
|
|
jne matched_context_change_done
|
|
mov [matched_context],esi
|
|
matched_context_change_done:
|
|
add esi,sizeof.RecognitionContext
|
|
jmp get_matched_token
|
|
substitution_encountered:
|
|
mov esi,[ebx+SymbolSubstitution.value_start]
|
|
and [matched_context],0
|
|
or [substitution_active],1
|
|
token_in_substitution:
|
|
cmp esi,[ebx+SymbolSubstitution.value_end]
|
|
jb check_for_matched_token
|
|
mov esi,[ebx+SymbolSubstitution.symbol_end]
|
|
mov ecx,[ebx+SymbolSubstitution.leftover_context]
|
|
mov [matched_context],ecx
|
|
add ebx,sizeof.SymbolSubstitution
|
|
and [substitution_active],0
|
|
jmp get_matched_token
|
|
skip_token:
|
|
inc esi
|
|
cmp al,1Ah
|
|
je skip_token_with_data
|
|
cmp al,22h
|
|
je skip_token_with_data
|
|
cmp al,27h
|
|
je skip_token_with_data
|
|
cmp al,30h
|
|
je skip_internal_token
|
|
cmp al,40h
|
|
je skip_context_token
|
|
retn
|
|
skip_token_with_data:
|
|
add esi,4
|
|
retn
|
|
skip_internal_token:
|
|
lodsd
|
|
add esi,eax
|
|
retn
|
|
skip_context_token:
|
|
add esi,sizeof.RecognitionContext
|
|
retn
|
|
copy_matched_token:
|
|
mov edx,[matched_context]
|
|
cmp edx,[embedded_context]
|
|
je matched_context_ok
|
|
test edx,edx
|
|
jz copy_matched_context
|
|
mov eax,[edx]
|
|
test eax,eax
|
|
jnz copy_matched_context
|
|
mov [matched_context],eax
|
|
cmp eax,[embedded_context]
|
|
je matched_context_ok
|
|
mov edx,eax
|
|
copy_matched_context:
|
|
mov [embedded_context],edx
|
|
mov ecx,1+sizeof.RecognitionContext
|
|
mov edx,assembly_workspace
|
|
call reserve_workspace
|
|
mov al,40h
|
|
stosb
|
|
assert sizeof.RecognitionContext and 11b = 0
|
|
mov ecx,sizeof.RecognitionContext shr 2
|
|
mov edx,[matched_context]
|
|
test edx,edx
|
|
jz clear_matched_context
|
|
xchg esi,edx
|
|
rep movsd
|
|
mov esi,edx
|
|
jmp matched_context_ok
|
|
clear_matched_context:
|
|
xor eax,eax
|
|
rep stosd
|
|
matched_context_ok:
|
|
mov ecx,1+4
|
|
mov edx,assembly_workspace
|
|
call reserve_workspace
|
|
lodsb
|
|
stosb
|
|
cmp al,1Ah
|
|
je copy_token_with_data
|
|
cmp al,22h
|
|
je copy_token_with_data
|
|
cmp al,27h
|
|
je copy_token_with_data
|
|
cmp al,30h
|
|
je copy_internal_token
|
|
retn
|
|
copy_token_with_data:
|
|
movsd
|
|
retn
|
|
copy_internal_token:
|
|
mov ecx,[esi]
|
|
add ecx,4
|
|
mov edx,assembly_workspace
|
|
call reserve_workspace
|
|
lodsd
|
|
stosd
|
|
mov ecx,eax
|
|
rep movsb
|
|
retn
|
|
close_matched_value:
|
|
mov eax,[embedded_context]
|
|
test eax,eax
|
|
jz matched_value_closed
|
|
mov ecx,1+sizeof.RecognitionContext
|
|
mov edx,assembly_workspace
|
|
call reserve_workspace
|
|
mov al,40h
|
|
stosb
|
|
xor eax,eax
|
|
assert sizeof.RecognitionContext and 11b = 0
|
|
mov ecx,sizeof.RecognitionContext shr 2
|
|
rep stosd
|
|
matched_value_closed:
|
|
retn
|
|
|
|
else_raw_match_block:
|
|
mov bl,CTRL_RMATCH
|
|
jmp begin_else_match_block
|
|
else_match_block:
|
|
mov bl,CTRL_MATCH
|
|
begin_else_match_block:
|
|
test [assembly_mode],AMODE_DEFINITION
|
|
jnz ignored_directive
|
|
mov dl,DBLOCK_CONTROL
|
|
call find_directive_block
|
|
jc unexpected_instruction
|
|
mov al,[edi+DirectiveBlock.flags]
|
|
test al,CTRLF_ALLOWS_ELSE
|
|
jz unexpected_instruction
|
|
mov ah,[assembly_mode]
|
|
push eax ebx
|
|
call close_control_directive_block
|
|
mov dl,DBLOCK_CONTROL
|
|
xor ecx,ecx
|
|
call add_directive_block
|
|
mov [directive_block],edi
|
|
pop ebx eax
|
|
cmp bl,CTRL_RMATCH
|
|
sete [unprocessed_matching]
|
|
mov [edi+DirectiveBlock.subtype],bl
|
|
or [edi+DirectiveBlock.flags],CTRLF_ALLOWS_ELSE
|
|
test al,CTRLF_INACTIVE
|
|
jnz skip_conditional_block
|
|
test ah,AMODE_SKIP
|
|
jnz evaluate_match
|
|
jmp skip_conditional_block
|
|
|
|
end_raw_match_block:
|
|
mov bl,CTRL_RMATCH
|
|
jmp close_match_block
|
|
end_match_block:
|
|
mov bl,CTRL_MATCH
|
|
close_match_block:
|
|
test [assembly_mode],AMODE_DEFINITION
|
|
jnz ignored_directive
|
|
mov dl,DBLOCK_CONTROL
|
|
call find_directive_block
|
|
jc unexpected_instruction
|
|
cmp [edi+DirectiveBlock.subtype],bl
|
|
jne unexpected_instruction
|
|
call close_control_directive_block
|
|
jmp instruction_assembled
|
|
|
|
postponed_block:
|
|
test [assembly_mode],AMODE_DEFINITION
|
|
jnz ignored_directive
|
|
mov dl,DBLOCK_CONTROL
|
|
xor ecx,ecx
|
|
call add_directive_block
|
|
mov [edi+DirectiveBlock.subtype],CTRL_POSTPONE
|
|
mov [directive_block],edi
|
|
or [assembly_mode],AMODE_SKIP
|
|
call get_constituent_value
|
|
jc instruction_assembled
|
|
cmp al,'?'
|
|
jne invalid_argument
|
|
mov edi,[directive_block]
|
|
or [edi+DirectiveBlock.flags],CTRLF_SUSPENDED
|
|
jmp instruction_assembled
|
|
|
|
end_postponed_block:
|
|
test [assembly_mode],AMODE_DEFINITION
|
|
jnz ignored_directive
|
|
mov dl,DBLOCK_CONTROL
|
|
call find_directive_block
|
|
jc end_postponed_execution
|
|
cmp [edi+DirectiveBlock.subtype],CTRL_POSTPONE
|
|
jne unexpected_instruction
|
|
mov al,[edi+DirectiveBlock.prior_assembly_mode]
|
|
mov [assembly_mode],al
|
|
test al,AMODE_SKIP
|
|
jz keep_postponed_block
|
|
call close_directive_block
|
|
jmp instruction_assembled
|
|
keep_postponed_block:
|
|
test [edi+DirectiveBlock.flags],CTRLF_SUSPENDED
|
|
jnz keep_suspended_block
|
|
mov [edi+DirectiveBlock.type],DBLOCK_POSTPONED
|
|
jmp instruction_assembled
|
|
keep_suspended_block:
|
|
mov [edi+DirectiveBlock.type],DBLOCK_SUSPENDED
|
|
jmp instruction_assembled
|
|
end_postponed_execution:
|
|
test [assembly_mode],AMODE_POSTPONED
|
|
jz unexpected_instruction
|
|
mov eax,[source_context]
|
|
mov esi,eax
|
|
call release_source_context
|
|
and [esi+SourceContext.number_of_entries],0
|
|
jmp pass_done
|
|
|
|
define_struc:
|
|
mov bl,SYMCLASS_STRUCTURE
|
|
jmp begin_macro_definition
|
|
define_macro:
|
|
mov bl,SYMCLASS_INSTRUCTION
|
|
begin_macro_definition:
|
|
test [assembly_mode],AMODE_DEFINITION
|
|
jnz nested_macro_definition
|
|
mov dl,DBLOCK_MACRO
|
|
mov ecx,sizeof.MacroData
|
|
call add_directive_block
|
|
mov [edi+DirectiveBlock.subtype],bl
|
|
mov [edi-sizeof.MacroData+MacroData.nesting_counter],1
|
|
xor eax,eax
|
|
mov [macro_end_position],eax
|
|
mov [macro_definition_active],al
|
|
or [assembly_mode],AMODE_DEFINITION
|
|
test [assembly_mode],AMODE_SKIP
|
|
jnz assembly_line
|
|
xor ecx,ecx
|
|
call move_to_next_symbol
|
|
jc invalid_macro_definition
|
|
cmp al,'('
|
|
je macro_with_label_parameter
|
|
read_macro_name:
|
|
mov dl,bl
|
|
call get_macro_definition_symbol
|
|
jc invalid_identifier
|
|
mov [argument_start],esi
|
|
mov eax,[embedded_context]
|
|
mov [macro_parameters_context],eax
|
|
xor ecx,ecx
|
|
call move_to_next_symbol
|
|
jc macro_parameters_correct
|
|
check_macro_parameters:
|
|
cmp al,'&'
|
|
jne macro_parameter_prefix_ok
|
|
inc esi
|
|
call move_to_next_symbol
|
|
jc invalid_macro_definition
|
|
macro_parameter_prefix_ok:
|
|
cmp al,'#'
|
|
jne check_parameter_name
|
|
call check_concatenation
|
|
jnc check_macro_parameters
|
|
invalid_macro_definition:
|
|
mov edx,_invalid_argument
|
|
call register_error
|
|
jmp assembly_line
|
|
check_parameter_name:
|
|
cmp al,'?'
|
|
je parameter_starting_question_mark
|
|
cmp al,1Ah
|
|
jne invalid_macro_definition
|
|
call detect_numeric_symbol
|
|
jc invalid_macro_definition
|
|
parameter_name_token:
|
|
inc esi
|
|
lodsd
|
|
parameter_name_present:
|
|
xor ecx,ecx
|
|
call move_to_next_symbol
|
|
jc macro_parameters_correct
|
|
cmp al,'?'
|
|
je check_parameter_name_modifier
|
|
cmp al,'#'
|
|
jne check_parameter_modifiers
|
|
call check_concatenation
|
|
jnc check_parameter_name_concatenation
|
|
call move_to_next_symbol
|
|
jc macro_parameters_correct
|
|
jmp check_parameter_modifiers
|
|
parameter_starting_question_mark:
|
|
inc esi
|
|
parameter_name_freeform:
|
|
call move_to_next_symbol
|
|
jc macro_parameters_correct
|
|
cmp al,1Ah
|
|
je parameter_name_token
|
|
cmp al,'#'
|
|
je parameter_name_freeform_concatenation
|
|
cmp al,30h
|
|
jne invalid_macro_definition
|
|
parameter_number_token:
|
|
inc esi
|
|
lodsd
|
|
add esi,eax
|
|
jmp parameter_name_present
|
|
parameter_name_freeform_concatenation:
|
|
call check_concatenation
|
|
jc invalid_macro_definition
|
|
jmp parameter_name_freeform
|
|
check_parameter_name_concatenation:
|
|
cmp al,1Ah
|
|
je parameter_name_token
|
|
cmp al,30h
|
|
je parameter_number_token
|
|
cmp al,'?'
|
|
jne check_parameter_modifiers
|
|
check_parameter_name_modifier:
|
|
inc esi
|
|
call move_to_next_symbol
|
|
jc macro_parameters_correct
|
|
check_parameter_modifiers:
|
|
cmp al,':'
|
|
je check_default_value
|
|
cmp al,'='
|
|
je check_default_value
|
|
cmp al,'*'
|
|
jne check_next_parameter
|
|
inc esi
|
|
call move_to_next_symbol
|
|
jnc check_next_parameter
|
|
jmp macro_parameters_correct
|
|
check_default_value:
|
|
mov edi,[expression_workspace.memory_start]
|
|
inc esi
|
|
call move_to_next_symbol
|
|
jc check_plain_default_value
|
|
cmp al,'<'
|
|
je check_enclosed_default_value
|
|
check_plain_default_value:
|
|
mov dl,','
|
|
xor dh,dh
|
|
mov [breakpoint_token],'&'
|
|
call cut_piece_of_line
|
|
jmp check_next_parameter
|
|
check_enclosed_default_value:
|
|
inc esi
|
|
mov dl,'>'
|
|
mov dh,'<'
|
|
mov [breakpoint_token],0
|
|
call cut_piece_of_line
|
|
cmp al,'>'
|
|
jne invalid_macro_definition
|
|
inc esi
|
|
call move_to_next_symbol
|
|
jc macro_parameters_correct
|
|
check_next_parameter:
|
|
test al,al
|
|
jz macro_parameters_correct
|
|
inc esi
|
|
cmp al,','
|
|
jne check_final_parameter_modifiers
|
|
call move_to_next_symbol
|
|
jc invalid_macro_definition
|
|
jmp check_macro_parameters
|
|
check_final_parameter_modifiers:
|
|
cmp al,'&'
|
|
jne invalid_macro_definition
|
|
call move_to_next_symbol
|
|
jnc invalid_macro_definition
|
|
macro_parameters_correct:
|
|
or [macro_definition_active],1
|
|
cmp [macro_parameters_context],0
|
|
je store_macro_header
|
|
xor esi,esi
|
|
mov ecx,1+sizeof.RecognitionContext
|
|
call append_to_macro
|
|
mov al,40h
|
|
stosb
|
|
mov esi,[macro_parameters_context]
|
|
assert sizeof.RecognitionContext and 11b = 0
|
|
mov ecx,sizeof.RecognitionContext shr 2
|
|
rep movsd
|
|
store_macro_header:
|
|
mov esi,[argument_start]
|
|
mov ecx,[line_end]
|
|
sub ecx,esi
|
|
call append_to_macro
|
|
call add_line_break_to_macro
|
|
jmp instruction_assembled
|
|
nested_macro_definition:
|
|
mov dl,DBLOCK_MACRO
|
|
call find_directive_block
|
|
; jc internal_error
|
|
cmp bl,[edi+DirectiveBlock.subtype]
|
|
jne add_nested_macro_block
|
|
inc [edi-sizeof.MacroData+MacroData.nesting_counter]
|
|
jmp add_line_to_macro
|
|
add_nested_macro_block:
|
|
mov ecx,sizeof.MacroData
|
|
call add_directive_block
|
|
mov [edi+DirectiveBlock.subtype],bl
|
|
mov [edi-sizeof.MacroData+MacroData.nesting_counter],1
|
|
jmp add_line_to_macro
|
|
macro_with_label_parameter:
|
|
cmp bl,SYMCLASS_STRUCTURE
|
|
jne invalid_macro_definition
|
|
mov [argument_start],esi
|
|
inc esi
|
|
xor ecx,ecx
|
|
call move_to_next_symbol
|
|
jc invalid_macro_definition
|
|
cmp al,'&'
|
|
jne check_label_parameter_initial_concatenation
|
|
inc esi
|
|
call move_to_next_symbol
|
|
jc invalid_macro_definition
|
|
check_label_parameter_initial_concatenation:
|
|
cmp al,'#'
|
|
jne check_label_parameter_name
|
|
call check_concatenation
|
|
jnc check_label_parameter_initial_concatenation
|
|
jmp invalid_macro_definition
|
|
check_label_parameter_name:
|
|
cmp al,1Ah
|
|
jne invalid_macro_definition
|
|
call detect_numeric_symbol
|
|
jc invalid_macro_definition
|
|
label_parameter_name_present:
|
|
inc esi
|
|
lodsd
|
|
xor ecx,ecx
|
|
call move_to_next_symbol
|
|
jc invalid_macro_definition
|
|
cmp al,'?'
|
|
je check_label_parameter_name_modifier
|
|
cmp al,'#'
|
|
jne label_parameter_name_end
|
|
call check_concatenation
|
|
jnc check_label_parameter_name_concatenation
|
|
call move_to_next_symbol
|
|
jc invalid_macro_definition
|
|
jmp label_parameter_name_end
|
|
check_label_parameter_name_concatenation:
|
|
cmp al,1Ah
|
|
je label_parameter_name_present
|
|
cmp al,'?'
|
|
jne label_parameter_name_end
|
|
check_label_parameter_name_modifier:
|
|
inc esi
|
|
call move_to_next_symbol
|
|
jc invalid_macro_definition
|
|
label_parameter_name_end:
|
|
inc esi
|
|
cmp al,')'
|
|
jne invalid_macro_definition
|
|
push esi
|
|
or [macro_definition_active],1
|
|
mov ecx,esi
|
|
mov esi,[argument_start]
|
|
sub ecx,esi
|
|
call append_to_macro
|
|
and [macro_definition_active],0
|
|
pop esi
|
|
xor ecx,ecx
|
|
call move_to_next_symbol
|
|
jc invalid_macro_definition
|
|
jmp read_macro_name
|
|
|
|
end_struc:
|
|
mov bl,SYMCLASS_STRUCTURE
|
|
jmp close_macro_block
|
|
end_macro:
|
|
mov bl,SYMCLASS_INSTRUCTION
|
|
close_macro_block:
|
|
mov dl,DBLOCK_MACRO
|
|
call find_directive_block
|
|
jc unexpected_instruction
|
|
cmp bl,[edi+DirectiveBlock.subtype]
|
|
je close_macro_definition
|
|
; handle improper nesting, for partial backward-compatibility:
|
|
cmp bl,SYMCLASS_INSTRUCTION
|
|
jne add_line_to_macro
|
|
call close_directive_block
|
|
mov dl,DBLOCK_MACRO
|
|
call find_directive_block
|
|
jc unexpected_instruction
|
|
; cmp [edi+DirectiveBlock.subtype],SYMCLASS_INSTRUCTION
|
|
; jne internal_error
|
|
close_macro_definition:
|
|
dec [edi-sizeof.MacroData+MacroData.nesting_counter]
|
|
jnz add_line_to_macro
|
|
mov al,[assembly_mode]
|
|
and al,not (AMODE_SKIP or AMODE_DEFINITION)
|
|
or al,[edi+DirectiveBlock.prior_assembly_mode]
|
|
mov [assembly_mode],al
|
|
call close_directive_block
|
|
mov al,[assembly_mode]
|
|
test al,AMODE_DEFINITION
|
|
jne add_line_to_macro
|
|
test al,AMODE_SKIP
|
|
jnz assembly_line
|
|
push esi
|
|
cmp [macro_definition_active],0
|
|
je macro_definition_done
|
|
mov ebx,[macro_leaf]
|
|
call create_value_definition
|
|
test edx,edx
|
|
jz macro_definition_done
|
|
mov [value],eax
|
|
mov [value_length],ecx
|
|
mov esi,[macro_buffer]
|
|
mov ecx,[macro_end_position]
|
|
mov [value_type],VALTYPE_SYMBOLIC
|
|
call assign_value
|
|
mov al,[macro_flags]
|
|
or [edx+ValueDefinition.flags],al
|
|
macro_definition_done:
|
|
pop esi
|
|
jmp instruction_assembled
|
|
|
|
escape_directive:
|
|
mov dl,DBLOCK_MACRO
|
|
call find_directive_block
|
|
jc unexpected_instruction
|
|
cmp [edi-sizeof.MacroData+MacroData.nesting_counter],1
|
|
ja add_line_to_macro
|
|
test [edi+DirectiveBlock.prior_assembly_mode],AMODE_DEFINITION
|
|
jnz add_line_to_macro
|
|
cmp [embedded_context],0
|
|
je escape_context_ok
|
|
push esi
|
|
xor esi,esi
|
|
mov ecx,1+sizeof.RecognitionContext
|
|
call append_to_macro
|
|
mov al,40h
|
|
stosb
|
|
mov esi,[embedded_context]
|
|
assert sizeof.RecognitionContext and 11b = 0
|
|
mov ecx,sizeof.RecognitionContext shr 2
|
|
rep movsd
|
|
pop esi
|
|
escape_context_ok:
|
|
mov ecx,[line_end]
|
|
sub ecx,esi
|
|
call append_to_macro
|
|
call add_line_break_to_macro
|
|
jmp assembly_line
|
|
add_line_to_macro:
|
|
mov esi,[line_start]
|
|
mov ecx,[line_end]
|
|
sub ecx,esi
|
|
call append_to_macro
|
|
call add_line_break_to_macro
|
|
jmp assembly_line
|
|
append_to_macro:
|
|
cmp [macro_definition_active],0
|
|
je macro_appended
|
|
mov edi,[macro_buffer]
|
|
mov eax,[macro_end_position]
|
|
add edi,eax
|
|
add eax,ecx
|
|
mov [macro_end_position],eax
|
|
cmp eax,[macro_buffer_length]
|
|
jbe macro_block_ready
|
|
push ecx
|
|
mov ecx,eax
|
|
mov eax,[macro_buffer]
|
|
sub edi,eax
|
|
call realloc
|
|
add edi,eax
|
|
mov [macro_buffer],eax
|
|
mov [macro_buffer_length],ecx
|
|
pop ecx
|
|
macro_block_ready:
|
|
test esi,esi
|
|
jz macro_appended
|
|
rep movsb
|
|
macro_appended:
|
|
retn
|
|
add_label_to_macro:
|
|
mov ecx,esi
|
|
xchg esi,[line_start]
|
|
sub ecx,esi
|
|
call append_to_macro
|
|
mov esi,[line_start]
|
|
cmp esi,[line_end]
|
|
jne assemble_instruction
|
|
call add_line_break_to_macro
|
|
jmp assemble_instruction
|
|
add_line_break_to_macro:
|
|
mov eax,[macro_buffer]
|
|
mov ecx,[macro_end_position]
|
|
cmp ecx,[macro_buffer_length]
|
|
jb macro_line_break
|
|
add ecx,100h
|
|
call realloc
|
|
mov [macro_buffer],eax
|
|
mov [macro_buffer_length],ecx
|
|
mov ecx,[macro_end_position]
|
|
macro_line_break:
|
|
lea edi,[eax+ecx]
|
|
xor al,al
|
|
stosb
|
|
inc [macro_end_position]
|
|
retn
|
|
|
|
use_macro:
|
|
and [label_branch],0
|
|
use_struc:
|
|
mov eax,[current_pass]
|
|
mov [ebx+SymbolTree_Leaf.last_use_pass],eax
|
|
mov [instruction_value],edx
|
|
mov eax,[ebx+SymbolTree_Leaf.branch]
|
|
mov [instruction_branch],eax
|
|
xor ecx,ecx
|
|
call embed_symbolic_value
|
|
measure_macro_header:
|
|
lodsb
|
|
test al,al
|
|
jz macro_header_measured
|
|
cmp al,1Ah
|
|
je measure_token_with_data
|
|
cmp al,22h
|
|
je measure_token_with_data
|
|
cmp al,27h
|
|
je measure_token_with_data
|
|
cmp al,30h
|
|
je measure_internal_token
|
|
cmp al,40h
|
|
jne measure_macro_header
|
|
add esi,sizeof.RecognitionContext
|
|
jmp measure_macro_header
|
|
measure_token_with_data:
|
|
add esi,4
|
|
jmp measure_macro_header
|
|
measure_internal_token:
|
|
lodsd
|
|
add esi,eax
|
|
jmp measure_macro_header
|
|
macro_header_measured:
|
|
mov [instruction_body],esi
|
|
dec esi
|
|
mov [line_end],esi
|
|
mov eax,ebx
|
|
mov ecx,[parameter_namespace]
|
|
call get_local_anchor
|
|
call get_local_namespace
|
|
mov [new_local_namespace],ebx
|
|
mov eax,[parameter_namespace]
|
|
mov [ebx+SymbolTree_Root.chain],eax
|
|
mov edx,[instruction_value]
|
|
local_namespace_ready:
|
|
mov esi,[edx+ValueDefinition.value]
|
|
or [symbol_definition],1
|
|
mov ebx,[new_local_namespace]
|
|
mov eax,[label_branch]
|
|
mov [ebx+SymbolTree_Root.current_label],eax
|
|
cmp [label_independent],0
|
|
je struc_label_ok
|
|
or [ebx+SymbolTree_Root.flags],NAMESPACE_LABEL_FORWARDING
|
|
struc_label_ok:
|
|
cmp byte [esi],'('
|
|
jne prepare_macro_parameters
|
|
inc esi
|
|
call move_to_next_symbol
|
|
jc invalid_argument
|
|
test [assembly_mode],AMODE_DEFINITION
|
|
setnz dl
|
|
cmp al,'&'
|
|
sete al
|
|
jne struc_label_prefix_ok
|
|
inc esi
|
|
struc_label_prefix_ok:
|
|
or al,dl
|
|
mov [contextless_processing],al
|
|
mov ebx,[new_local_namespace]
|
|
mov dl,SYMCLASS_PARAMETER
|
|
call identify_symbol_in_namespace
|
|
jc invalid_argument
|
|
test ebx,ebx
|
|
jz invalid_argument
|
|
cmp edi,[new_local_namespace]
|
|
jne invalid_argument
|
|
push esi
|
|
push [line_end]
|
|
push [embedded_context]
|
|
mov eax,[line_context]
|
|
mov [embedded_context],eax
|
|
mov esi,[line_start]
|
|
mov ecx,[label_instruction_start]
|
|
mov [line_end],ecx
|
|
sub ecx,esi
|
|
add ecx,(1+sizeof.RecognitionContext)*2
|
|
mov edx,assembly_workspace
|
|
mov edi,[edx+Workspace.memory_start]
|
|
call reserve_workspace
|
|
xor edx,edx
|
|
mov [breakpoint_token],dl
|
|
call extract_piece_of_line
|
|
call finish_extracted_parameter
|
|
pop [embedded_context]
|
|
pop [line_end]
|
|
or [ebx+SymbolTree_Leaf.flags],SYM_VARIABLE
|
|
call update_value_definition
|
|
mov [value_type],VALTYPE_SYMBOLIC
|
|
mov esi,[assembly_workspace.memory_start]
|
|
mov ecx,edi
|
|
sub ecx,esi
|
|
call assign_value
|
|
pop esi
|
|
call move_to_next_symbol
|
|
jc invalid_argument
|
|
cmp al,')'
|
|
jne invalid_argument
|
|
inc esi
|
|
prepare_macro_parameters:
|
|
mov edi,[expression_workspace.memory_start]
|
|
add edi,sizeof.LineExcerpt
|
|
xor eax,eax
|
|
mov [macro_greedy],al
|
|
mov [number_of_parameters],eax
|
|
macro_parameter_declaration:
|
|
call move_to_next_symbol
|
|
jc macro_parameters_declared
|
|
cmp al,'&'
|
|
sete al
|
|
mov [contextless_processing],al
|
|
jne identify_macro_parameter_name
|
|
inc esi
|
|
identify_macro_parameter_name:
|
|
mov ebx,[new_local_namespace]
|
|
mov dl,SYMCLASS_PARAMETER
|
|
push edi
|
|
call identify_symbol_in_namespace
|
|
mov eax,edi
|
|
pop edi
|
|
jc macro_parameters_declared
|
|
test ebx,ebx
|
|
jz invalid_argument
|
|
cmp eax,[new_local_namespace]
|
|
jne invalid_argument
|
|
mov eax,[number_of_parameters]
|
|
shl eax,3
|
|
add eax,[assembly_stack_base]
|
|
lea ecx,[eax+8]
|
|
cmp ecx,[assembly_stack_end]
|
|
jbe store_macro_parameter_leaf
|
|
mov eax,[assembly_stack_base]
|
|
sub ecx,eax
|
|
call grow_stack
|
|
mov [assembly_stack_base],eax
|
|
add ecx,eax
|
|
mov [assembly_stack_end],ecx
|
|
mov ecx,[number_of_parameters]
|
|
shl ecx,3
|
|
add eax,ecx
|
|
store_macro_parameter_leaf:
|
|
mov [eax],ebx
|
|
mov cl,[contextless_processing]
|
|
mov [eax+4],cl
|
|
mov edx,expression_workspace
|
|
mov ecx,sizeof.LineExcerpt
|
|
call reserve_workspace
|
|
mov [edi+LineExcerpt.data_start],esi
|
|
mov [edi+LineExcerpt.data_end],esi
|
|
inc [number_of_parameters]
|
|
call move_to_next_symbol
|
|
jc macro_parameters_declared
|
|
cmp al,':'
|
|
je macro_parameter_with_default_value
|
|
cmp al,'='
|
|
je macro_parameter_with_default_value
|
|
cmp al,'*'
|
|
jne next_parameter_declaration
|
|
and [edi+LineExcerpt.data_start],0
|
|
inc esi
|
|
call move_to_next_symbol
|
|
jnc next_parameter_declaration
|
|
xor al,al
|
|
jmp next_parameter_declaration
|
|
macro_parameter_with_default_value:
|
|
inc esi
|
|
call move_to_next_symbol
|
|
jc get_plain_default_value
|
|
cmp al,'<'
|
|
je get_enclosed_default_value
|
|
get_plain_default_value:
|
|
mov dl,','
|
|
xor dh,dh
|
|
mov [breakpoint_token],'&'
|
|
call cut_piece_of_line
|
|
jmp next_parameter_declaration
|
|
get_enclosed_default_value:
|
|
inc esi
|
|
mov dl,'>'
|
|
mov dh,'<'
|
|
mov [breakpoint_token],0
|
|
call cut_piece_of_line
|
|
cmp al,'>'
|
|
jne invalid_argument
|
|
inc esi
|
|
call move_to_next_symbol
|
|
jc macro_parameters_declared
|
|
next_parameter_declaration:
|
|
test al,al
|
|
jz macro_parameters_declared
|
|
inc esi
|
|
add edi,sizeof.LineExcerpt
|
|
cmp al,','
|
|
je macro_parameter_declaration
|
|
cmp al,'&'
|
|
jne invalid_argument
|
|
or [macro_greedy],1
|
|
call move_to_next_symbol
|
|
jnc invalid_argument
|
|
macro_parameters_declared:
|
|
call warp_to_next_symbol
|
|
; cmp [number_of_line_embeddings],0
|
|
; jne internal_error
|
|
mov edx,assembly_workspace
|
|
mov edi,[edx+Workspace.memory_start]
|
|
mov ecx,[line_end]
|
|
sub ecx,esi
|
|
add ecx,(1+sizeof.RecognitionContext)*2
|
|
call reserve_workspace
|
|
xor eax,eax
|
|
mov [breakpoint_token],al
|
|
mov [parameter_index],eax
|
|
macro_parameter_definition:
|
|
mov eax,[number_of_parameters]
|
|
sub eax,[parameter_index]
|
|
jz macro_parameters_ready
|
|
jmp get_macro_parameter
|
|
macro_parameter_after_comma:
|
|
mov eax,[number_of_parameters]
|
|
sub eax,[parameter_index]
|
|
jz macro_parameters_ready
|
|
inc esi
|
|
get_macro_parameter:
|
|
mov edi,[assembly_workspace.memory_start]
|
|
mov ecx,[parameter_index]
|
|
shl ecx,3
|
|
add ecx,[assembly_stack_base]
|
|
mov ebx,[ecx]
|
|
test [assembly_mode],AMODE_DEFINITION
|
|
setnz dl
|
|
or dl,[ecx+4]
|
|
mov [contextless_processing],dl
|
|
cmp [macro_greedy],0
|
|
je standard_parameter_value
|
|
cmp eax,1
|
|
ja standard_parameter_value
|
|
xor edx,edx
|
|
call extract_piece_of_line
|
|
jmp parameter_value_ready
|
|
standard_parameter_value:
|
|
call extract_argument_value
|
|
parameter_value_ready:
|
|
or [ebx+SymbolTree_Leaf.flags],SYM_VARIABLE
|
|
call update_value_definition
|
|
mov [value_type],VALTYPE_SYMBOLIC
|
|
cmp edi,[assembly_workspace.memory_start]
|
|
je empty_parameter_value
|
|
call finish_extracted_parameter
|
|
push esi
|
|
mov esi,[assembly_workspace.memory_start]
|
|
mov ecx,edi
|
|
sub ecx,esi
|
|
assign_parameter_value:
|
|
call assign_value
|
|
pop esi
|
|
parameter_value_assigned:
|
|
inc [parameter_index]
|
|
call move_to_next_symbol
|
|
jc macro_parameter_definition
|
|
cmp al,','
|
|
je macro_parameter_after_comma
|
|
macro_parameters_ready:
|
|
mov edx,[instruction_value]
|
|
mov ecx,[instruction_body]
|
|
sub ecx,[edx+ValueDefinition.value]
|
|
push ecx
|
|
call create_source_entry
|
|
pop eax
|
|
jc stack_limit_exceeded
|
|
mov [ebx+SourceEntry.type],SOURCE_MACRO
|
|
mov [ebx+SourceEntry.text],edx
|
|
mov [ebx+SourceEntry.offset],eax
|
|
or [edx+ValueDefinition.flags],VAL_IN_USE
|
|
inc [edx+ValueDefinition.reference_count]
|
|
mov eax,[new_local_namespace]
|
|
mov [local_namespace],eax
|
|
and [eax+SymbolTree_Root.parameters],0
|
|
mov [ebx+SourceEntry.local_namespace],eax
|
|
mov ecx,[instruction_branch]
|
|
test ecx,ecx
|
|
jz instruction_assembled
|
|
mov [ebx+SourceEntry.name],ecx
|
|
or [ebx+SourceEntry.name_length],-1
|
|
jmp instruction_assembled
|
|
stack_limit_exceeded:
|
|
mov edx,_stack_limit_exceeded
|
|
call register_error
|
|
test [assembly_mode],AMODE_SKIP
|
|
jnz assembly_line
|
|
test [assembly_mode],AMODE_DEFINITION
|
|
jz assembly_line
|
|
jmp add_line_to_macro
|
|
empty_parameter_value:
|
|
mov edi,[parameter_index]
|
|
inc edi
|
|
assert sizeof.LineExcerpt = 1 shl 4
|
|
shl edi,4
|
|
add edi,[expression_workspace.memory_start]
|
|
mov eax,[edi+LineExcerpt.data_start]
|
|
test eax,eax
|
|
jz missing_argument
|
|
mov ecx,[edi+LineExcerpt.data_end]
|
|
sub ecx,eax
|
|
push esi
|
|
mov esi,eax
|
|
test ecx,ecx
|
|
jz assign_parameter_value
|
|
push ebx edx
|
|
mov ebx,edi
|
|
mov edi,[assembly_workspace.memory_start]
|
|
add ecx,2*(1+sizeof.RecognitionContext)
|
|
mov edx,assembly_workspace
|
|
call reserve_workspace
|
|
mov al,40h
|
|
cmp [ebx+LineExcerpt.recognition_context],0
|
|
je parameter_with_current_context
|
|
stosb
|
|
mov eax,esi
|
|
mov esi,[ebx+LineExcerpt.recognition_context]
|
|
assert sizeof.RecognitionContext and 11b = 0
|
|
mov ecx,sizeof.RecognitionContext shr 2
|
|
rep movsd
|
|
mov [context_boundary],edi
|
|
mov esi,eax
|
|
jmp copy_parameter_contents
|
|
parameter_with_current_context:
|
|
cmp [contextless_processing],0
|
|
jne copy_parameter_contents
|
|
stosb
|
|
call store_current_context
|
|
copy_parameter_contents:
|
|
call store_token
|
|
cmp esi,[ebx+LineExcerpt.data_end]
|
|
jne copy_parameter_contents
|
|
call store_context_reset_token
|
|
pop edx ebx
|
|
mov esi,[assembly_workspace.memory_start]
|
|
mov ecx,edi
|
|
sub ecx,esi
|
|
jmp assign_parameter_value
|
|
finish_extracted_parameter:
|
|
test [assembly_mode],AMODE_DEFINITION
|
|
jz store_context_reset_token
|
|
cmp [embedded_context],0
|
|
jne store_context_reset_token
|
|
retn
|
|
store_context_reset_token:
|
|
cmp edi,[context_boundary]
|
|
je context_reset_in_reused_token
|
|
mov al,40h
|
|
stosb
|
|
store_context_reset:
|
|
xor eax,eax
|
|
assert sizeof.RecognitionContext and 11b = 0
|
|
mov ecx,sizeof.RecognitionContext shr 2
|
|
rep stosd
|
|
retn
|
|
context_reset_in_reused_token:
|
|
sub edi,sizeof.RecognitionContext
|
|
jmp store_context_reset
|
|
|
|
local_directive:
|
|
test [assembly_mode],AMODE_SKIP
|
|
jnz assembly_line
|
|
test [assembly_mode],AMODE_DEFINITION
|
|
jnz add_line_to_macro
|
|
mov ebx,[local_namespace]
|
|
test ebx,ebx
|
|
jz unexpected_instruction
|
|
or [symbol_definition],1
|
|
mov dl,SYMCLASS_PARAMETER
|
|
call identify_symbol_in_namespace
|
|
jc missing_argument
|
|
test ebx,ebx
|
|
jz invalid_argument
|
|
cmp edi,[local_namespace]
|
|
jne invalid_argument
|
|
or [ebx+SymbolTree_Leaf.flags],SYM_VARIABLE
|
|
call update_value_definition
|
|
mov eax,[current_pass]
|
|
mov [edx+ValueDefinition.pass],eax
|
|
mov [edx+ValueDefinition.type],VALTYPE_NATIVE_COMMAND
|
|
mov eax,local_symbol_name
|
|
xchg eax,[edx+ValueDefinition.value]
|
|
cmp [edx+ValueDefinition.block_length],0
|
|
je next_local_declaration
|
|
and [edx+ValueDefinition.block_length],0
|
|
call mfree
|
|
next_local_declaration:
|
|
call move_to_next_symbol
|
|
jc assembly_line
|
|
cmp al,','
|
|
jne invalid_argument
|
|
inc esi
|
|
jmp local_directive
|
|
outscope_directive:
|
|
test [assembly_mode],AMODE_SKIP
|
|
jnz assemble_prefixed_instruction
|
|
mov ebx,[source_context]
|
|
mov eax,[ebx+SourceContext.number_of_entries]
|
|
dec eax
|
|
imul eax,sizeof.SourceEntry
|
|
lea ebx,[ebx+sizeof.SourceContext+eax]
|
|
test [assembly_mode],AMODE_DEFINITION
|
|
jnz define_outscope
|
|
mov ecx,[ebx+SourceEntry.local_namespace]
|
|
test [ecx+SymbolTree_Root.flags],NAMESPACE_UNATTACHED
|
|
jnz unexpected_instruction
|
|
mov eax,[ecx+SymbolTree_Root.chain]
|
|
test eax,eax
|
|
jz unexpected_instruction
|
|
outscope_namespace_ok:
|
|
mov [parameter_namespace],eax
|
|
test [eax+SymbolTree_Root.flags],NAMESPACE_UNATTACHED
|
|
jz outscope_local_namespace_ok
|
|
xor eax,eax
|
|
outscope_local_namespace_ok:
|
|
mov [local_namespace],eax
|
|
assemble_prefixed_instruction:
|
|
mov [line_start],esi
|
|
mov eax,[embedded_context]
|
|
mov [line_context],eax
|
|
jmp assemble_instruction
|
|
define_outscope:
|
|
cmp [ebx+SourceEntry.type],SOURCE_MACRO
|
|
je assemble_prefixed_instruction
|
|
jmp ignored_directive
|
|
|
|
define_data:
|
|
and [label_leaf],0
|
|
define_labeled_data:
|
|
movzx eax,[edx+ValueDefinition.attribute]
|
|
mov [data_unit_length],eax
|
|
test eax,eax
|
|
jnz data_unit_length_ok
|
|
call get_numeric_constant_value
|
|
test edx,edx
|
|
jz invalid_argument
|
|
mov ecx,4
|
|
mov edi,data_unit_length
|
|
call fit_value
|
|
jc value_out_of_range
|
|
js value_out_of_range
|
|
cmp [data_unit_length],0
|
|
je value_out_of_range
|
|
call get_constituent_value
|
|
jc missing_argument
|
|
cmp al,':'
|
|
je data_unit_length_ok
|
|
cmp al,','
|
|
jne invalid_argument
|
|
data_unit_length_ok:
|
|
cmp [label_leaf],0
|
|
je data_definition
|
|
call define_data_label
|
|
data_definition:
|
|
call peek_at_constituent_value
|
|
jc missing_argument
|
|
cmp al,'?'
|
|
je single_uninitialized_unit
|
|
call get_constant_value
|
|
cmp al,30h
|
|
je numeric_data
|
|
cmp al,2Eh
|
|
je float_data
|
|
cmp al,22h
|
|
jne invalid_argument
|
|
call output_string
|
|
data_outputted:
|
|
call get_constituent_value
|
|
jc instruction_assembled
|
|
cmp al,','
|
|
jne invalid_argument
|
|
jmp data_definition
|
|
float_data:
|
|
push esi
|
|
push edx
|
|
mov ecx,[data_unit_length]
|
|
call initialize_output
|
|
pop esi
|
|
mov ecx,[data_unit_length]
|
|
call fit_float
|
|
pop esi
|
|
jmp data_outputted
|
|
numeric_data:
|
|
call keep_value
|
|
call peek_at_constituent_value
|
|
jc single_data_unit
|
|
cmp al,1Ah
|
|
jne single_data_unit
|
|
test edx,edx
|
|
jz single_data_unit
|
|
cmp [edx+ValueDefinition.type],VALTYPE_NATIVE_PREPOSITION
|
|
jne single_data_unit
|
|
cmp [edx+ValueDefinition.value],PREPOSITION_DUP
|
|
je duplication_operator
|
|
single_data_unit:
|
|
mov ecx,[data_unit_length]
|
|
call initialize_output
|
|
call get_kept_value
|
|
mov ecx,[data_unit_length]
|
|
call fit_value
|
|
jc value_out_of_range
|
|
jmp data_outputted
|
|
single_uninitialized_unit:
|
|
and [current_constituent],0
|
|
mov ecx,[data_unit_length]
|
|
call uninitialized_output
|
|
jmp data_outputted
|
|
duplication_operator:
|
|
call get_kept_value
|
|
mov edi,number_of_iterations
|
|
mov ecx,4
|
|
call fit_value
|
|
jc value_out_of_range
|
|
js value_out_of_range
|
|
xor eax,eax
|
|
mov [current_constituent],al
|
|
mov [initial_parentheses],eax
|
|
call peek_at_constituent_value
|
|
jc invalid_argument
|
|
cmp al,'?'
|
|
je reserve_through_duplication
|
|
mov edi,[expression_workspace.memory_start]
|
|
mov [expression_sequence_end],edi
|
|
or [leave_opening_parentheses],1
|
|
parse_duplicated_expression:
|
|
call parse_expression
|
|
add [initial_parentheses],ecx
|
|
jecxz duplicated_value_parsed
|
|
mov eax,[expression_workspace.memory_start]
|
|
mov eax,[eax]
|
|
test eax,eax
|
|
jnz duplicated_value_parsed
|
|
call get_constituent_value
|
|
jc invalid_argument
|
|
cmp al,'?'
|
|
jne invalid_argument
|
|
mov edi,[expression_workspace.memory_start]
|
|
or eax,-1
|
|
stosd
|
|
duplicated_value_parsed:
|
|
mov [expression_sequence_end],edi
|
|
and [leave_opening_parentheses],0
|
|
cmp [initial_parentheses],1
|
|
jb duplicated_data_parsed
|
|
ja invalid_argument
|
|
call get_constituent_value
|
|
jc missing_closing_parenthesis
|
|
cmp al,')'
|
|
je duplicated_data_parsed
|
|
cmp al,','
|
|
jne invalid_argument
|
|
mov edi,[expression_sequence_end]
|
|
call peek_at_constituent_value
|
|
jc invalid_argument
|
|
mov edi,[expression_sequence_end]
|
|
cmp al,'?'
|
|
jne parse_duplicated_expression
|
|
and [current_constituent],0
|
|
mov ecx,4
|
|
mov edx,expression_workspace
|
|
call reserve_workspace
|
|
or eax,-1
|
|
stosd
|
|
jmp duplicated_value_parsed
|
|
duplicated_data_parsed:
|
|
cmp [number_of_iterations],0
|
|
je data_outputted
|
|
duplicated_data:
|
|
mov eax,[expression_workspace.memory_start]
|
|
mov [expression_sequence_cursor],eax
|
|
generate_duplicate:
|
|
mov eax,[expression_sequence_cursor]
|
|
cmp eax,[expression_sequence_end]
|
|
je duplicate_outputted
|
|
cmp dword [eax],-1
|
|
je duplicated_uninitialized_unit
|
|
push esi
|
|
mov esi,eax
|
|
mov edi,[calculation_workspace.memory_start]
|
|
call calculate_parsed_expression
|
|
mov [expression_sequence_cursor],esi
|
|
pop esi
|
|
jc duplicate_outputted
|
|
call pop_terms
|
|
jc invalid_argument
|
|
call get_calculated_constant_value
|
|
cmp al,30h
|
|
je duplicated_data_unit
|
|
cmp al,2Eh
|
|
je duplicated_data_unit
|
|
cmp al,22h
|
|
jne invalid_argument
|
|
call output_string
|
|
jmp generate_duplicate
|
|
duplicated_data_unit:
|
|
push eax edx
|
|
mov ecx,[data_unit_length]
|
|
call initialize_output
|
|
pop edx eax
|
|
mov ecx,[data_unit_length]
|
|
cmp al,2Eh
|
|
je duplicated_float
|
|
call fit_value
|
|
jc value_out_of_range
|
|
jmp generate_duplicate
|
|
duplicated_float:
|
|
push esi
|
|
mov esi,edx
|
|
call fit_float
|
|
pop esi
|
|
jmp generate_duplicate
|
|
duplicated_uninitialized_unit:
|
|
add eax,4
|
|
mov [expression_sequence_cursor],eax
|
|
mov ecx,[data_unit_length]
|
|
call uninitialized_output
|
|
jmp generate_duplicate
|
|
duplicate_outputted:
|
|
dec [number_of_iterations]
|
|
jnz duplicated_data
|
|
jmp data_outputted
|
|
reserve_through_duplication:
|
|
and [current_constituent],0
|
|
mov eax,[number_of_iterations]
|
|
mul [data_unit_length]
|
|
test edx,edx
|
|
jnz duplication_overflow
|
|
mov ecx,eax
|
|
call uninitialized_output
|
|
jmp data_outputted
|
|
duplication_overflow:
|
|
mov edx,_area_overflow
|
|
call register_error
|
|
jmp data_outputted
|
|
output_string:
|
|
push esi
|
|
mov esi,edx
|
|
mov ecx,[esi]
|
|
call initialize_output
|
|
lodsd
|
|
mov ecx,eax
|
|
rep movsb
|
|
pop esi
|
|
mov ecx,[data_unit_length]
|
|
xor edx,edx
|
|
div ecx
|
|
test edx,edx
|
|
jz string_outputted
|
|
sub ecx,edx
|
|
push ecx
|
|
call initialize_output
|
|
pop ecx
|
|
xor al,al
|
|
rep stosb
|
|
string_outputted:
|
|
retn
|
|
define_data_label:
|
|
push esi
|
|
call get_current_address_value
|
|
lea edi,[esi+ecx]
|
|
mov ecx,4+4+4
|
|
mov edx,assembly_workspace
|
|
call reserve_workspace
|
|
mov edx,[data_unit_length]
|
|
bsr eax,edx
|
|
inc al
|
|
shr al,3
|
|
inc al
|
|
stosd
|
|
mov [edi],edx
|
|
add edi,eax
|
|
xor eax,eax
|
|
stosd
|
|
mov ebx,[label_leaf]
|
|
call create_constant_value_definition
|
|
test edx,edx
|
|
jz data_label_defined
|
|
mov ecx,edi
|
|
sub ecx,esi
|
|
call assign_shiftable_value
|
|
data_label_defined:
|
|
call update_current_label
|
|
pop esi
|
|
retn
|
|
|
|
reserve_labeled_data:
|
|
movzx eax,[edx+ValueDefinition.attribute]
|
|
mov [data_unit_length],eax
|
|
call define_data_label
|
|
jmp data_reservation
|
|
reserve_data:
|
|
movzx eax,[edx+ValueDefinition.attribute]
|
|
mov [data_unit_length],eax
|
|
data_reservation:
|
|
call get_numeric_constant_value
|
|
test edx,edx
|
|
jz invalid_argument
|
|
mov ecx,4
|
|
mov edi,[assembly_workspace.memory_start]
|
|
call fit_value
|
|
jc reservation_out_of_range
|
|
js reservation_out_of_range
|
|
mov eax,[edi]
|
|
mul [data_unit_length]
|
|
test edx,edx
|
|
jnz reservation_overflow
|
|
mov ecx,eax
|
|
call uninitialized_output
|
|
jmp instruction_assembled
|
|
reservation_out_of_range:
|
|
mov edx,_value_out_of_range
|
|
call register_error
|
|
jmp instruction_assembled
|
|
reservation_overflow:
|
|
mov edx,_area_overflow
|
|
call register_error
|
|
jmp instruction_assembled
|
|
|
|
include_labeled_data:
|
|
mov [data_unit_length],1
|
|
call define_data_label
|
|
include_data:
|
|
xor eax,eax
|
|
mov [data_offset],eax
|
|
mov [data_offset+4],eax
|
|
call get_constant_value
|
|
cmp al,22h
|
|
jne invalid_argument
|
|
push esi
|
|
call prepare_file_path
|
|
pop esi
|
|
call get_constituent_value
|
|
jc include_all_available_data
|
|
cmp al,':'
|
|
jne get_data_length
|
|
call get_numeric_constant_value
|
|
test edx,edx
|
|
jz invalid_argument
|
|
mov edi,file_offset
|
|
mov ecx,8
|
|
call fit_value
|
|
jc value_out_of_range
|
|
js value_out_of_range
|
|
call get_constituent_value
|
|
jc include_all_available_data
|
|
get_data_length:
|
|
cmp al,','
|
|
jne invalid_argument
|
|
call get_numeric_constant_value
|
|
test edx,edx
|
|
jz invalid_argument
|
|
mov edi,data_length
|
|
mov ecx,4
|
|
call fit_value
|
|
jc value_out_of_range
|
|
js value_out_of_range
|
|
push esi
|
|
mov ecx,[data_length]
|
|
call initialize_output
|
|
mov esi,[assembly_workspace.memory_start]
|
|
call get_file_data
|
|
test ebx,ebx
|
|
jnz read_from_file
|
|
mov esi,[local_path]
|
|
call get_file_data
|
|
test ebx,ebx
|
|
jz data_file_not_found
|
|
read_from_file:
|
|
call read_file_data
|
|
jc file_data_not_read
|
|
pop esi
|
|
jmp instruction_assembled
|
|
data_file_not_found:
|
|
mov ebx,esi
|
|
mov edx,_source_file_not_found
|
|
call register_error
|
|
pop esi
|
|
jmp instruction_assembled
|
|
include_all_available_data:
|
|
push esi
|
|
mov esi,[assembly_workspace.memory_start]
|
|
call get_file_data
|
|
test ebx,ebx
|
|
jnz measure_available_data
|
|
mov esi,[local_path]
|
|
call get_file_data
|
|
test ebx,ebx
|
|
jz data_file_not_found
|
|
measure_available_data:
|
|
mov ecx,dword [ebx+FileData.length]
|
|
mov edx,dword [ebx+FileData.length+4]
|
|
sub ecx,dword [file_offset]
|
|
sbb edx,dword [file_offset+4]
|
|
jc file_data_not_read
|
|
jnz out_of_memory
|
|
mov [data_length],ecx
|
|
push ebx
|
|
call initialize_output
|
|
pop ebx
|
|
call read_file_data
|
|
jc file_data_not_read
|
|
pop esi
|
|
jmp instruction_assembled
|
|
file_data_not_read:
|
|
mov ebx,esi
|
|
mov edx,_error_reading_file
|
|
call register_error
|
|
pop esi
|
|
jmp instruction_assembled
|
|
|
|
load_value:
|
|
or [symbol_definition],1
|
|
mov dl,SYMCLASS_EXPRESSION
|
|
call identify_symbol
|
|
jc missing_argument
|
|
test ebx,ebx
|
|
jz invalid_identifier
|
|
mov [label_leaf],ebx
|
|
mov [size_specified],0
|
|
call peek_at_constituent_value
|
|
jc load_syntax_error
|
|
cmp al,':'
|
|
je size_after_separator
|
|
cmp al,1Ah
|
|
jne get_load_size
|
|
test edx,edx
|
|
jz get_load_size
|
|
cmp [edx+ValueDefinition.type],VALTYPE_NATIVE_PREPOSITION
|
|
jne get_load_size
|
|
cmp [edx+ValueDefinition.value],PREPOSITION_FROM
|
|
jne load_syntax_error
|
|
and [current_constituent],0
|
|
jmp get_source_address
|
|
size_after_separator:
|
|
and [current_constituent],0
|
|
get_load_size:
|
|
call get_numeric_constant_value
|
|
test edx,edx
|
|
jz load_syntax_error
|
|
or [size_specified],1
|
|
mov edi,value_length
|
|
mov ecx,4
|
|
call fit_value
|
|
jc value_out_of_range
|
|
js value_out_of_range
|
|
call get_constituent_value
|
|
jc load_syntax_error
|
|
cmp al,1Ah
|
|
jne load_syntax_error
|
|
test edx,edx
|
|
jz load_syntax_error
|
|
cmp [edx+ValueDefinition.type],VALTYPE_NATIVE_PREPOSITION
|
|
jne load_syntax_error
|
|
cmp [edx+ValueDefinition.value],PREPOSITION_FROM
|
|
jne load_syntax_error
|
|
get_source_address:
|
|
call peek_at_constituent_value
|
|
jc invalid_argument
|
|
cmp al,':'
|
|
je load_from_output_offset
|
|
mov eax,[current_area]
|
|
mov [data_area],eax
|
|
and [data_area_symbol],0
|
|
and [leave_opening_parentheses],0
|
|
mov edi,[expression_workspace.memory_start]
|
|
call parse_expression
|
|
call peek_at_constituent_value
|
|
jc source_address_parsed
|
|
cmp al,':'
|
|
jne source_address_parsed
|
|
and [current_constituent],0
|
|
mov edi,[expression_workspace.memory_start]
|
|
call get_area_value
|
|
jc invalid_area
|
|
mov [data_area],edx
|
|
mov [data_area_symbol],ebx
|
|
mov edi,[expression_workspace.memory_start]
|
|
call parse_expression
|
|
source_address_parsed:
|
|
call calculate_relative_address
|
|
jc invalid_argument
|
|
mov edi,data_offset
|
|
mov ecx,4
|
|
call fit_value
|
|
jc data_out_of_area
|
|
js data_out_of_area
|
|
mov edx,assembly_workspace
|
|
mov edi,[edx+Workspace.memory_start]
|
|
mov eax,[value_length]
|
|
stosd
|
|
mov ecx,eax
|
|
call reserve_workspace
|
|
mov edx,[data_area]
|
|
call load_from_area
|
|
jc loaded_no_value
|
|
value_loaded:
|
|
mov ebx,[label_leaf]
|
|
call update_value_definition
|
|
test edx,edx
|
|
jz instruction_assembled
|
|
push esi
|
|
mov esi,[assembly_workspace.memory_start]
|
|
mov ecx,[esi]
|
|
add ecx,4
|
|
mov [value_type],VALTYPE_STRING
|
|
call assign_value
|
|
pop esi
|
|
jmp instruction_assembled
|
|
load_syntax_error:
|
|
mov edx,_invalid_argument
|
|
jmp error_while_loading
|
|
data_out_of_area:
|
|
mov edx,_address_out_of_range
|
|
error_while_loading:
|
|
call register_error
|
|
loaded_no_value:
|
|
mov edi,[assembly_workspace.memory_start]
|
|
xor eax,eax
|
|
stosd
|
|
jmp value_loaded
|
|
calculate_relative_address:
|
|
push esi
|
|
mov esi,[expression_workspace.memory_start]
|
|
mov edi,[calculation_workspace.memory_start]
|
|
call calculate_parsed_expression
|
|
jc invalid_relative_address
|
|
mov ebx,edi
|
|
mov edi,[expression_workspace.memory_start]
|
|
mov esi,edi
|
|
mov eax,EXPR_SYMBOL_VALUE
|
|
stosd
|
|
mov edx,[data_area]
|
|
mov eax,[data_area_symbol]
|
|
test eax,eax
|
|
jnz data_area_symbol_ok
|
|
mov eax,[void_symbol]
|
|
mov [eax+SymbolTree_Leaf.definition],edx
|
|
data_area_symbol_ok:
|
|
stosd
|
|
mov eax,edx
|
|
stosd
|
|
mov eax,EXPR_OPERATOR
|
|
stosd
|
|
mov eax,extract_first_term_metadata
|
|
stosd
|
|
mov eax,EXPR_OPERATOR
|
|
stosd
|
|
mov eax,calculate_sub
|
|
stosd
|
|
xor eax,eax
|
|
stosd
|
|
mov edi,ebx
|
|
call calculate_parsed_expression
|
|
jc invalid_relative_address
|
|
call pop_terms
|
|
jc invalid_relative_address
|
|
cmp [size_specified],0
|
|
jne addressed_length_ok
|
|
and [value_length],0
|
|
mov edx,[edi+ExpressionTerm.metadata]
|
|
test edx,edx
|
|
jz addressed_length_ok
|
|
cmp dword [edx],0
|
|
jne addressed_length_ok
|
|
add edx,4
|
|
mov esi,edi
|
|
mov ecx,4
|
|
mov edi,value_length
|
|
call fit_value
|
|
jc invalid_relative_address
|
|
js invalid_relative_address
|
|
mov ecx,[edx]
|
|
cmp dword [edx+4+ecx],0
|
|
jne invalid_relative_address
|
|
mov edi,esi
|
|
addressed_length_ok:
|
|
pop esi
|
|
mov eax,edi
|
|
check_for_uncanceled_terms:
|
|
add eax,sizeof.ExpressionTerm
|
|
cmp [eax+ExpressionTerm.attributes],0
|
|
je relative_address_ok
|
|
cmp [eax+ExpressionTerm.metadata],0
|
|
je check_for_uncanceled_terms
|
|
mov edx,_address_out_of_range
|
|
call register_error
|
|
relative_address_ok:
|
|
call get_term_value
|
|
clc
|
|
retn
|
|
invalid_relative_address:
|
|
pop esi
|
|
stc
|
|
retn
|
|
load_from_output_offset:
|
|
call read_output_offset
|
|
jc value_out_of_range
|
|
mov edx,assembly_workspace
|
|
mov edi,[edx+Workspace.memory_start]
|
|
mov eax,[value_length]
|
|
stosd
|
|
mov ecx,eax
|
|
call reserve_workspace
|
|
push esi
|
|
call read_from_output
|
|
pop esi
|
|
cmp [value_length],0
|
|
jne data_out_of_area
|
|
jmp value_loaded
|
|
read_output_offset:
|
|
and [current_constituent],0
|
|
call get_numeric_constant_value
|
|
test edx,edx
|
|
jz output_offset_out_of_range
|
|
push edi
|
|
mov edi,file_offset
|
|
mov ecx,8
|
|
call fit_value
|
|
pop edi
|
|
jc output_offset_out_of_range
|
|
js output_offset_out_of_range
|
|
cmp [size_specified],0
|
|
jne output_offset_ok
|
|
and [value_length],0
|
|
mov edx,[edi+ExpressionTerm.metadata]
|
|
test edx,edx
|
|
jz output_offset_ok
|
|
cmp dword [edx],0
|
|
jne output_offset_ok
|
|
add edx,4
|
|
mov ecx,4
|
|
mov edi,value_length
|
|
call fit_value
|
|
jc output_offset_out_of_range
|
|
js output_offset_out_of_range
|
|
output_offset_ok:
|
|
clc
|
|
retn
|
|
output_offset_out_of_range:
|
|
stc
|
|
retn
|
|
|
|
store_value:
|
|
mov [size_specified],0
|
|
call get_constant_value
|
|
cmp al,22h
|
|
je store_string_value
|
|
cmp al,30h
|
|
jne invalid_argument
|
|
call keep_value
|
|
call peek_at_constituent_value
|
|
jc invalid_argument
|
|
cmp al,':'
|
|
je size_after_value
|
|
cmp al,1Ah
|
|
jne size_before_value
|
|
test edx,edx
|
|
jz invalid_argument
|
|
cmp [edx+ValueDefinition.type],VALTYPE_NATIVE_PREPOSITION
|
|
je get_destination_address
|
|
size_before_value:
|
|
or [size_specified],1
|
|
call get_kept_value
|
|
mov edi,value_length
|
|
mov ecx,4
|
|
call fit_value
|
|
jc value_out_of_range
|
|
js value_out_of_range
|
|
call get_constant_value
|
|
cmp al,22h
|
|
je value_after_size_ok
|
|
cmp al,30h
|
|
jne invalid_argument
|
|
value_after_size_ok:
|
|
call keep_value
|
|
jmp value_with_size_ready
|
|
store_string_value:
|
|
mov eax,[edx]
|
|
mov [value_length],eax
|
|
call keep_value
|
|
call peek_at_constituent_value
|
|
jc invalid_argument
|
|
cmp al,':'
|
|
jne check_symbol_after_value_with_size
|
|
size_after_value:
|
|
and [current_constituent],0
|
|
call get_constant_value
|
|
cmp al,30h
|
|
jne invalid_argument
|
|
or [size_specified],1
|
|
mov edi,value_length
|
|
mov ecx,4
|
|
call fit_value
|
|
jc value_out_of_range
|
|
js value_out_of_range
|
|
value_with_size_ready:
|
|
call peek_at_constituent_value
|
|
jc invalid_argument
|
|
check_symbol_after_value_with_size:
|
|
cmp al,1Ah
|
|
jne invalid_argument
|
|
test edx,edx
|
|
jz invalid_argument
|
|
cmp [edx+ValueDefinition.type],VALTYPE_NATIVE_PREPOSITION
|
|
jne invalid_argument
|
|
get_destination_address:
|
|
cmp [edx+ValueDefinition.value],PREPOSITION_AT
|
|
jne invalid_argument
|
|
and [current_constituent],0
|
|
call peek_at_constituent_value
|
|
jc invalid_argument
|
|
cmp al,':'
|
|
je store_at_output_offset
|
|
mov eax,[current_area]
|
|
mov [data_area],eax
|
|
and [data_area_symbol],0
|
|
and [leave_opening_parentheses],0
|
|
mov edi,[expression_workspace.memory_start]
|
|
call parse_expression
|
|
call peek_at_constituent_value
|
|
jc destination_address_parsed
|
|
cmp al,':'
|
|
jne destination_address_parsed
|
|
and [current_constituent],0
|
|
mov edi,[expression_workspace.memory_start]
|
|
call get_area_value
|
|
jc invalid_area
|
|
mov ecx,[current_pass]
|
|
cmp [edx+ValueDefinition.pass],ecx
|
|
jne invalid_area
|
|
mov [data_area],edx
|
|
mov [data_area_symbol],ebx
|
|
mov edi,[expression_workspace.memory_start]
|
|
call parse_expression
|
|
destination_address_parsed:
|
|
call calculate_relative_address
|
|
jc invalid_argument
|
|
mov edi,data_offset
|
|
mov ecx,4
|
|
call fit_value
|
|
jc store_out_of_area
|
|
js store_out_of_area
|
|
call prepare_area_to_write
|
|
call get_kept_value
|
|
call fit_value
|
|
jc value_out_of_range
|
|
jmp instruction_assembled
|
|
store_out_of_area:
|
|
mov edx,_address_out_of_range
|
|
call register_error
|
|
jmp instruction_assembled
|
|
store_at_output_offset:
|
|
call read_output_offset
|
|
jc value_out_of_range
|
|
mov ecx,[value_length]
|
|
mov edx,assembly_workspace
|
|
mov edi,[edx+Workspace.memory_start]
|
|
call reserve_workspace
|
|
call get_kept_value
|
|
mov ecx,[value_length]
|
|
call fit_value
|
|
jc value_out_of_range
|
|
push esi
|
|
mov esi,[assembly_workspace.memory_start]
|
|
call rewrite_output
|
|
pop esi
|
|
cmp [value_length],0
|
|
jne store_out_of_area
|
|
jmp instruction_assembled
|
|
|
|
display_data:
|
|
call get_constant_value
|
|
cmp al,30h
|
|
je display_character_data
|
|
cmp al,22h
|
|
jne invalid_argument
|
|
call display_string_data
|
|
display_next_value:
|
|
call get_constituent_value
|
|
jc assembly_line
|
|
cmp al,','
|
|
jne invalid_argument
|
|
jmp display_data
|
|
display_character_data:
|
|
call display_single_byte_data
|
|
jmp display_next_value
|
|
|
|
format_directive:
|
|
mov edx,[ebx+SymbolTree_Leaf.branch]
|
|
call get_symbol_namespace
|
|
and [symbol_definition],0
|
|
mov dl,SYMCLASS_INSTRUCTION
|
|
call identify_symbol_in_namespace
|
|
jc invalid_argument
|
|
test ebx,ebx
|
|
jz invalid_argument
|
|
mov al,[ebx+SymbolTree_Leaf.class]
|
|
cmp al,SYMCLASS_INSTRUCTION
|
|
jne invalid_argument
|
|
call get_available_value
|
|
jc invalid_argument
|
|
jmp prefixed_directive
|
|
format_binary:
|
|
call get_constituent_value
|
|
jc instruction_assembled
|
|
cmp al,1Ah
|
|
jne invalid_argument
|
|
test edx,edx
|
|
jz invalid_argument
|
|
cmp [edx+ValueDefinition.type],VALTYPE_NATIVE_PREPOSITION
|
|
jne invalid_argument
|
|
cmp [edx+ValueDefinition.value],PREPOSITION_AS
|
|
jne invalid_argument
|
|
cmp [output_extension],0
|
|
jne repeated_declaration
|
|
call get_constant_value
|
|
cmp al,22h
|
|
jne invalid_argument
|
|
mov edi,esi
|
|
mov ecx,[edx]
|
|
lea esi,[edx+4]
|
|
mov [output_extension_length],ecx
|
|
mov ebx,[auxiliary_output_areas]
|
|
call get_from_map
|
|
jnc extension_stored
|
|
xor eax,eax
|
|
mov ecx,[output_extension_length]
|
|
call put_into_map
|
|
extension_stored:
|
|
mov [output_extension],esi
|
|
validate_extension:
|
|
mov ebx,characters
|
|
scan_extension:
|
|
test ecx,ecx
|
|
jz extension_valid
|
|
lodsb
|
|
xlatb
|
|
test al,al
|
|
jz invalid_argument
|
|
dec ecx
|
|
jmp scan_extension
|
|
extension_valid:
|
|
mov esi,edi
|
|
jmp instruction_assembled
|
|
|
|
custom_error:
|
|
mov edi,[assembly_workspace.memory_start]
|
|
add edi,4
|
|
create_custom_error_message:
|
|
push edi
|
|
call get_constant_value
|
|
pop edi
|
|
cmp al,30h
|
|
je attach_byte_to_error_message
|
|
cmp al,22h
|
|
jne invalid_argument
|
|
mov ebx,edx
|
|
mov ecx,[edx]
|
|
mov edx,assembly_workspace
|
|
call reserve_workspace
|
|
mov edx,esi
|
|
lea esi,[ebx+4]
|
|
mov ecx,[ebx]
|
|
rep movsb
|
|
mov esi,edx
|
|
jmp collect_next_part_of_message
|
|
attach_byte_to_error_message:
|
|
mov ebx,edx
|
|
mov ecx,1
|
|
mov edx,assembly_workspace
|
|
call reserve_workspace
|
|
mov edx,ebx
|
|
mov ecx,1
|
|
call fit_value
|
|
jc value_out_of_range
|
|
inc edi
|
|
collect_next_part_of_message:
|
|
push edi
|
|
call get_constituent_value
|
|
pop edi
|
|
jc custom_error_message_ready
|
|
cmp al,','
|
|
jne invalid_argument
|
|
jmp create_custom_error_message
|
|
custom_error_message_ready:
|
|
mov edx,[assembly_workspace.memory_start]
|
|
sub edi,edx
|
|
sub edi,4
|
|
mov [edx],edi
|
|
call register_volatile_error
|
|
test edx,edx
|
|
jz instruction_assembled
|
|
or [edx+Error.flags],ERR_CUSTOM
|
|
jmp instruction_assembled
|
|
|
|
choose_to_remove_comments:
|
|
and [preprocessing_mode],not PMODE_RETAIN_COMMENTS
|
|
jmp instruction_assembled
|
|
choose_to_retain_comments:
|
|
or [preprocessing_mode],PMODE_RETAIN_COMMENTS
|
|
jmp instruction_assembled
|
|
choose_to_combine_lines:
|
|
and [preprocessing_mode],not PMODE_ISOLATE_LINES
|
|
jmp instruction_assembled
|
|
choose_to_isolate_lines:
|
|
or [preprocessing_mode],PMODE_ISOLATE_LINES
|
|
jmp instruction_assembled
|
|
|
|
missing_argument:
|
|
mov edx,_missing_argument
|
|
call register_error
|
|
jmp assembly_line
|
|
|
|
invalid_argument:
|
|
mov edx,_invalid_argument
|
|
call register_error
|
|
jmp assembly_line
|
|
|
|
invalid_identifier:
|
|
mov edx,_invalid_identifier
|
|
call register_error
|
|
jmp assembly_line
|
|
|
|
value_out_of_range:
|
|
mov edx,_value_out_of_range
|
|
call register_error
|
|
jmp assembly_line
|
|
|
|
missing_closing_parenthesis:
|
|
mov edx,_missing_closing_parenthesis
|
|
call register_error
|
|
jmp assembly_line
|
|
|
|
unexpected_instruction:
|
|
mov edx,_unexpected_instruction
|
|
call register_error
|
|
jmp assembly_line
|
|
|
|
repeated_declaration:
|
|
mov edx,_repeated_declaration
|
|
call register_error
|
|
jmp assembly_line
|