added fasm2 as well

This commit is contained in:
2024-11-25 00:04:53 -05:00
parent 8a974e9c89
commit dceb330571
165 changed files with 78512 additions and 0 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,669 @@
COND_NEGATED = 1 ; only with COND_EVALUATE
COND_TRUE = 1 ; only with COND_DETERMINED
COND_EVALUATE = 2
COND_DETERMINED = 4
get_condition_value:
; in:
; esi = pointer into preprocessed line or the last embedded line
; out:
; esi = pointer advanced past the processed line
; al = logical value
mov ebx,[condition_stack_base]
mov [condition_stack],ebx
mov byte [ebx],COND_EVALUATE
get_logical_value:
call peek_at_constituent_value
cmp al,'~'
jne negation_registered
and [current_constituent],0
mov ebx,[condition_stack]
mov al,[ebx]
test byte [ebx],COND_EVALUATE
jz get_logical_value
xor byte [ebx],COND_NEGATED
jmp get_logical_value
negation_registered:
call parse_logical_value
setnc dh
mov dl,al
jecxz get_logical_operator
mov ebx,[condition_stack]
lea eax,[ebx+ecx+1]
cmp eax,[condition_stack_end]
jbe condition_stack_ready
push ecx edx
mov ecx,eax
mov eax,[condition_stack_base]
sub ecx,eax
sub ebx,eax
call grow_stack
mov [condition_stack_base],eax
add ebx,eax
mov [condition_stack],ebx
add eax,ecx
mov [condition_stack_end],eax
pop edx ecx
condition_stack_ready:
xor al,al
test byte [ebx],COND_EVALUATE
jz store_opening_parentheses
or al,COND_EVALUATE
store_opening_parentheses:
inc ebx
mov [ebx],al
loop store_opening_parentheses
mov [condition_stack],ebx
cmp dx,'~'
je get_logical_value
get_logical_operator:
call peek_at_constituent_value
jc end_of_logical_expression
cmp al,')'
je close_logical_subexpression
cmp al,'|'
je logical_or
cmp al,'&'
jne end_of_logical_expression
logical_and:
and [current_constituent],0
mov ebx,[condition_stack]
mov al,[ebx]
test al,COND_EVALUATE
jnz evaluate_logical_and
test al,COND_DETERMINED
jz get_logical_value
test al,COND_TRUE
jz determined_false
jmp continue_evaluation
evaluate_logical_and:
test al,COND_NEGATED
jnz evaluate_negated_logical_and
call evaluate_logical_value
mov ebx,[condition_stack]
test al,al
jnz continue_evaluation
determined_false:
mov byte [ebx],COND_DETERMINED
jmp get_logical_value
evaluate_negated_logical_and:
call evaluate_logical_value
mov ebx,[condition_stack]
test al,al
jnz determined_false
continue_evaluation:
mov byte [ebx],COND_EVALUATE
jmp get_logical_value
logical_or:
and [current_constituent],0
mov ebx,[condition_stack]
mov al,[ebx]
test al,COND_EVALUATE
jnz evaluate_logical_or
test al,COND_DETERMINED
jz get_logical_value
test al,COND_TRUE
jnz determined_true
jmp continue_evaluation
evaluate_logical_or:
test al,COND_NEGATED
jnz evaluate_negated_logical_or
call evaluate_logical_value
mov ebx,[condition_stack]
test al,al
jnz determined_true
jmp continue_evaluation
evaluate_negated_logical_or:
call evaluate_logical_value
mov ebx,[condition_stack]
test al,al
jnz continue_evaluation
determined_true:
mov byte [ebx],COND_DETERMINED + COND_TRUE
jmp get_logical_value
close_logical_subexpression:
and [current_constituent],0
mov ebx,[condition_stack]
cmp ebx,[condition_stack_base]
je excess_parenthesis
mov al,[ebx]
dec ebx
mov [condition_stack],ebx
test al,COND_DETERMINED
jnz subexpression_determined
cmp al,COND_EVALUATE + COND_NEGATED
jne get_logical_operator
test byte [ebx],COND_EVALUATE
jz get_logical_operator
xor byte [ebx],COND_NEGATED
jmp get_logical_operator
subexpression_determined:
test al,COND_TRUE
jnz subexpression_determined_true
mov [comparator],evaluated_false
jmp get_logical_operator
subexpression_determined_true:
mov [comparator],evaluated_true
jmp get_logical_operator
end_of_logical_expression:
mov ebx,[condition_stack]
cmp ebx,[condition_stack_base]
jne missing_parenthesis
mov al,[ebx]
test al,COND_DETERMINED
jnz condition_determined
test al,COND_NEGATED
jz evaluate_logical_value
call evaluate_logical_value
test al,al
setz al
retn
condition_determined:
and al,COND_TRUE
retn
excess_parenthesis:
mov edx,_excess_closing_parenthesis
call register_error
jmp unknown_condition
missing_parenthesis:
mov edx,_missing_closing_parenthesis
call register_error
unknown_condition:
xor al,al
retn
parse_logical_value:
; in:
; esi = pointer into preprocessed line or the last embedded line
; out:
; [comparator] - evaluating routine
; [expression_workspace.memory_start] - parsed argument sequences
; [expression_end] - end of the parsed argument sequences
; esi = pointer advanced past the parsed value
; al = special character that follows parsed value, zero if no more symbols in line
; ecx = number of parentheses opened before the value that did not get closed
; cf set if value was empty
mov edi,[expression_workspace.memory_start]
xor eax,eax
mov [comparator],eax
or [leave_opening_parentheses],1
call parse_expression
mov [initial_parentheses],ecx
mov [expression_end],edi
call peek_at_constituent_value
jc end_of_line
cmp al,'&'
je end_of_logical_value
cmp al,'|'
je end_of_logical_value
cmp al,'~'
je end_of_logical_value
cmp al,')'
je end_of_logical_value
cmp al,1Ah
je identify_comparator
cmp al,'='
je parse_equal
cmp al,'<'
je parse_less
cmp al,'>'
je parse_greater
jmp end_of_logical_value
identify_comparator:
test edx,edx
jz end_of_logical_value
cmp [edx+ValueDefinition.type],VALTYPE_NATIVE_COMPARATOR
jne end_of_logical_value
and [current_constituent],0
mov eax,[edx+ValueDefinition.value]
jmp set_comparator
parse_less:
and [current_constituent],0
call warp_to_next_symbol
jc parse_less_than
test ecx,ecx
jnz parse_less_than
call peek_at_constituent_value
jc parse_less_than
cmp al,'='
je parse_less_or_equal
cmp al,'>'
je parse_not_equal
parse_less_than:
mov eax,check_if_less
jmp set_comparator
parse_less_or_equal:
and [current_constituent],0
mov eax,check_if_not_greater
jmp set_comparator
parse_not_equal:
and [current_constituent],0
mov eax,check_if_not_equal
jmp set_comparator
parse_greater:
and [current_constituent],0
call warp_to_next_symbol
jc parse_greater_than
test ecx,ecx
jnz parse_greater_than
call peek_at_constituent_value
jc parse_greater_than
cmp al,'='
je parse_greater_or_equal
parse_greater_than:
mov eax,check_if_greater
jmp set_comparator
parse_greater_or_equal:
and [current_constituent],0
mov eax,check_if_not_less
jmp set_comparator
parse_equal:
and [current_constituent],0
mov eax,check_if_equal
set_comparator:
mov edi,[expression_end]
mov [comparator],eax
and [leave_opening_parentheses],0
call parse_expression
mov [expression_end],edi
call peek_at_constituent_value
jnc end_of_logical_value
end_of_line:
xor al,al
end_of_logical_value:
mov ecx,[initial_parentheses]
cmp [comparator],0
jnz logical_value_not_empty
mov [comparator],check_if_not_zero
mov ebx,[expression_workspace.memory_start]
cmp dword [ebx],0
jne logical_value_not_empty
stc
retn
logical_value_not_empty:
clc
retn
evaluate_logical_value:
; in:
; [comparator] - evaluating routine
; [expression_workspace.memory_start] - parsed argument sequences
; out: al = logical value
; note: evaluates value prepared by previous call to parse_logical_value
; preserves: esi
push esi
mov esi,[expression_workspace.memory_start]
jmp [comparator]
evaluated_false:
pop esi
xor al,al
retn
evaluated_true:
pop esi
mov al,1
retn
evaluate_stored_logical_value:
; in: esi - pointer to evaluating routine followed by parsed argument sequences
; out: al = logical value
; preserves: esi
push esi
lodsd
jmp eax
invalid_logical_value:
mov edx,_invalid_expression
call register_error
jmp evaluated_false
check_if_equal:
call get_difference_signum
test al,al
jz evaluated_true
jmp evaluated_false
check_if_not_equal:
call get_difference_signum
test al,al
jnz evaluated_true
jmp evaluated_false
check_if_less:
call get_difference_signum
cmp al,0
jl evaluated_true
jmp evaluated_false
check_if_not_less:
call get_difference_signum
cmp al,0
jnl evaluated_true
jmp evaluated_false
check_if_greater:
call get_difference_signum
cmp al,0
jg evaluated_true
jmp evaluated_false
check_if_not_greater:
call get_difference_signum
cmp al,0
jng evaluated_true
jmp evaluated_false
get_difference_signum:
mov edi,[calculation_workspace.memory_start]
call calculate_parsed_expression
jc signum_error
call calculate_parsed_expression
jc signum_error
mov esi,subtraction_operator
call calculate_parsed_expression
call pop_terms
mov eax,edi
jnc check_difference_for_variable_terms
signum_error:
xor al,al
retn
check_difference_for_variable_terms:
add eax,sizeof.ExpressionTerm
cmp [eax+ExpressionTerm.attributes],0
je difference_terms_ok
cmp [eax+ExpressionTerm.metadata],0
je check_difference_for_variable_terms
mov edx,_values_not_comparable
call register_error
difference_terms_ok:
cmp byte [edi+ExpressionTerm.attributes],EXPR_FLOAT
je get_float_signum
call get_numeric_term_value
mov ecx,1
call fit_value
js signum_negative
jc signum_positive
xor al,al
cmp [edi],al
jne signum_positive
retn
get_float_signum:
call get_term_value
mov esi,edx
call get_float_exponent
jz signum_zero
test [esi+FloatData.attributes],FLOAT_NEGATIVE
jnz signum_negative
signum_positive:
mov al,1
retn
signum_negative:
or al,-1
retn
signum_zero:
xor al,al
retn
check_if_not_zero:
mov edi,[calculation_workspace.memory_start]
call calculate_parsed_expression
jc evaluated_false
call pop_terms
jc evaluated_false
cmp byte [edi+ExpressionTerm.attributes],EXPR_FLOAT
je check_if_not_zero_float
call get_numeric_term_value
mov ecx,1
call fit_value
js evaluated_true
jc evaluated_true
cmp byte [edi],0
jne evaluated_true
check_if_has_variable_terms:
add edi,sizeof.ExpressionTerm
cmp [edi+ExpressionTerm.attributes],0
je evaluated_false
cmp [edi+ExpressionTerm.metadata],0
je check_if_has_variable_terms
jmp evaluated_true
check_if_not_zero_float:
call get_term_value
mov esi,edx
call get_float_exponent
jz check_if_has_variable_terms
jmp evaluated_true
check_if_relative:
mov edi,[calculation_workspace.memory_start]
call calculate_parsed_expression
jc evaluated_false
call calculate_parsed_expression
jc evaluated_false
mov ebx,edi
call pop_terms
jc evaluated_false
mov edx,edi
call pop_terms
jc evaluated_false
cmp [edx+sizeof.ExpressionTerm+ExpressionTerm.attributes],0
je check_difference_terms
xchg edi,edx
cmp [edx+sizeof.ExpressionTerm+ExpressionTerm.attributes],0
je check_difference_terms
mov esi,subtraction_operator
mov edi,ebx
call calculate_parsed_expression
call pop_terms
jc evaluated_false
check_difference_terms:
add edi,sizeof.ExpressionTerm
cmp [edi+ExpressionTerm.attributes],0
je evaluated_true
cmp [edi+ExpressionTerm.metadata],0
je check_difference_terms
jmp evaluated_false
undefined_condition:
mov edx,_invalid_value
call register_error
jmp evaluated_false
check_if_type_equal:
mov edi,[calculation_workspace.memory_start]
call calculate_parsed_expression
jc evaluated_false
call pop_terms
jc evaluated_false
mov eax,[edi+ExpressionTerm.attributes]
mov [result_type],al
call calculate_parsed_expression
jc evaluated_false
call pop_terms
jc evaluated_false
mov eax,[edi+ExpressionTerm.attributes]
cmp al,[result_type]
je evaluated_true
jmp evaluated_false
check_if_value_equal:
mov edi,[calculation_workspace.memory_start]
call calculate_parsed_expression
jc evaluated_false
mov ebx,edi
call pop_terms
jc evaluated_false
mov eax,[edi+ExpressionTerm.attributes]
mov [result_type],al
mov edi,ebx
call calculate_parsed_expression
jc evaluated_false
mov ebx,edi
call pop_terms
jc evaluated_false
mov eax,[edi+ExpressionTerm.attributes]
cmp al,[result_type]
jne evaluated_false
cmp al,EXPR_STRING
jne compare_values_numerically
call get_term_value
mov ecx,[edx]
call pop_terms
call get_term_value
cmp ecx,[edx]
jne evaluated_false
compare_values_numerically:
mov esi,subtraction_operator
mov edi,ebx
call calculate_parsed_expression
call pop_terms
jc evaluated_false
mov eax,edi
check_if_terms_equal:
add eax,sizeof.ExpressionTerm
cmp [eax+ExpressionTerm.attributes],0
je check_if_constant_term_equal
cmp [eax+ExpressionTerm.metadata],0
je check_if_terms_equal
jmp evaluated_false
check_if_constant_term_equal:
cmp byte [edi+ExpressionTerm.attributes],EXPR_FLOAT
je check_if_float_equal
call get_numeric_term_value
xor ecx,ecx
xor edi,edi
call fit_value
jc evaluated_false
jmp evaluated_true
check_if_float_equal:
call get_term_value
mov esi,edx
call get_float_exponent
jnz evaluated_false
jmp evaluated_true
check_if_defined:
xor ecx,ecx
jmp check_if_expression_defined
check_if_defined_earlier:
mov ecx,[current_pass]
check_if_expression_defined:
and [outer_expression],0
and [defined_element],0
lodsd
test eax,eax
jnz checked_expression_invalid
check_expression_element:
lodsd
test eax,eax
jz check_expression_end
cmp al,EXPR_SYMBOL
je check_if_subexpression_defined
cmp al,EXPR_SYMBOL_VALUE
je check_if_symbol_defined
or [defined_element],1
add esi,4
cmp al,EXPR_NUMBER
je check_expression_element
cmp al,EXPR_STRING
je check_expression_element
cmp al,EXPR_FLOAT
je check_expression_element
cmp al,EXPR_OPERATOR
je check_expression_element
cmp al,EXPR_POLYNOMIAL
je check_expression_element
checked_expression_invalid:
jmp invalid_logical_value
check_expression_end:
xor esi,esi
xchg esi,[outer_expression]
test esi,esi
jnz check_expression_element
jecxz checked_expression_defined
cmp [defined_element],0
je checked_expression_invalid
checked_expression_defined:
jmp evaluated_true
check_if_symbol_defined:
lodsd
test eax,eax
jz evaluated_false
lodsd
test eax,eax
jz evaluated_false
check_symbol_value:
or [defined_element],1
jecxz check_expression_element
test [eax+ValueDefinition.flags],VAL_INTERNAL
jnz check_expression_element
cmp [eax+ValueDefinition.pass],ecx
jne evaluated_false
jmp check_expression_element
check_if_subexpression_defined:
mov ebx,[esi]
test ebx,ebx
jz evaluated_false
add esi,4
call get_available_value
mov eax,edx
test eax,eax
jz evaluated_false
cmp [eax+ValueDefinition.type],VALTYPE_SYMBOLIC
jne check_symbol_value
mov [outer_expression],esi
push ecx
call get_subexpression
pop ecx
jnc invalid_logical_value
jmp check_expression_element
get_subexpression:
call clear_line_embeddings
xor esi,esi
xor ecx,ecx
call embed_symbolic_value
mov edi,[expression_workspace.memory_start]
and [leave_opening_parentheses],0
call parse_expression
call get_constituent_value
mov esi,[expression_workspace.memory_start]
retn
check_if_used:
lodsd
test eax,eax
jnz invalid_logical_value
check_if_expression_is_used_symbol:
lodsd
cmp al,EXPR_SYMBOL
je check_for_indirect_symbol
cmp al,EXPR_SYMBOL_VALUE
jne invalid_logical_value
lodsd
mov ebx,eax
lodsd
check_if_used_symbol:
lodsd
test eax,eax
jnz invalid_logical_value
test ebx,ebx
jz evaluated_false
mov ecx,[ebx+SymbolTree_Leaf.last_use_pass]
jecxz symbol_predicted_unused
mov eax,[current_pass]
sub eax,ecx
jz evaluated_true
cmp eax,1
ja symbol_predicted_unused
symbol_predicted_used:
or [ebx+SymbolTree_Leaf.flags],SYM_USAGE_PREDICTED + SYM_PREDICTED_USED
jmp evaluated_true
symbol_predicted_unused:
mov al,[ebx+SymbolTree_Leaf.flags]
or al,SYM_USAGE_PREDICTED
and al,not SYM_PREDICTED_USED
mov [ebx+SymbolTree_Leaf.flags],al
jmp evaluated_false
check_for_indirect_symbol:
lodsd
mov ebx,eax
call get_available_value
test edx,edx
jz check_if_used_symbol
cmp [edx+ValueDefinition.type],VALTYPE_SYMBOLIC
jne check_if_used_symbol
call get_subexpression
jnc invalid_logical_value
jmp check_if_expression_is_used_symbol

View File

@@ -0,0 +1,560 @@
display_string_data:
; in:
; edx - 32-bit length followed by string data
; preserves: esi
test [trace_mode],TRACE_DISPLAY
jnz bypass_display_buffer
cmp [next_pass_needed],0
jne display_ok
mov ecx,[edx]
call reserve_display_buffer
mov ebx,esi
mov esi,edx
lodsd
mov ecx,eax
rep movsb
string_displayed:
mov esi,ebx
display_ok:
retn
bypass_display_buffer:
mov ebx,esi
mov esi,edx
lodsd
mov ecx,eax
jecxz string_displayed
call display_string
jmp string_displayed
reserve_display_buffer:
mov edi,[display_data_length]
add ecx,edi
add edi,[display_buffer]
mov [display_data_length],ecx
cmp ecx,[display_buffer_length]
jbe display_buffer_reserve_ok
mov eax,[display_buffer]
sub edi,eax
push edx
call grow_stack
pop edx
add edi,eax
mov [display_buffer],eax
mov [display_buffer_length],ecx
display_buffer_reserve_ok:
retn
display_single_byte_data:
; in:
; edx - 32-bit length followed by numeric data
; preserves: esi
test [trace_mode],TRACE_DISPLAY
jnz byte_bypassing_display_buffer
cmp [next_pass_needed],0
jne display_ok
mov ecx,1
call reserve_display_buffer
mov ecx,1
call fit_value
jc byte_out_of_range
retn
byte_bypassing_display_buffer:
mov edi,displayed_byte
mov ecx,1
call fit_value
jc byte_out_of_range
mov ebx,esi
mov esi,edi
mov ecx,1
call display_string
jmp string_displayed
byte_out_of_range:
mov edx,_value_out_of_range
call register_error
retn
show_display_data:
test [trace_mode],TRACE_DISPLAY
jnz display_line_feed
mov ecx,[display_data_length]
jecxz display_data_shown
mov esi,[display_buffer]
call display_string
display_line_feed:
mov esi,_new_line
xor ecx,ecx
call display_string
display_data_shown:
retn
show_errors:
mov esi,[first_error]
display_error:
test esi,esi
jz display_data_shown
push esi
mov eax,[esi+sizeof.Error+SourceContext.number_of_entries]
test eax,eax
jz display_error_message
lea ebx,[esi+sizeof.Error+sizeof.SourceContext]
dec eax
imul eax,sizeof.SourceEntry
lea eax,[ebx+eax]
mov [last_source_entry],eax
test [trace_mode],TRACE_ERROR_STACK
jnz show_source_context
and [last_file_source_entry],0
find_last_file_entry:
cmp [eax+SourceEntry.type],SOURCE_FILE
je last_file_entry_found
cmp eax,ebx
je show_source_context
sub eax,sizeof.SourceEntry
jmp find_last_file_entry
last_file_entry_found:
mov [last_file_source_entry],eax
show_source_context:
push ebx
cmp [ebx+SourceEntry.type],SOURCE_MEMORY
je display_memory_source
cmp [ebx+SourceEntry.type],SOURCE_MACRO
jne display_source_name
mov esi,_macro_source
test [ebx+SourceEntry.flags],SRCF_PREPROCESSED
jz display_source_type
mov esi,_preprocessed_source
display_source_type:
xor ecx,ecx
call display_error_string
display_source_name:
mov esi,[ebx+SourceEntry.name]
test esi,esi
jz unnamed_source
mov ecx,[ebx+SourceEntry.name_length]
cmp ecx,-1
je display_source_symbol
call display_error_string
jmp display_line_number
display_source_symbol:
xchg ebx,esi
call show_symbol_name
mov ebx,esi
jmp display_line_number
unnamed_source:
mov esi,_unnamed_source
xor ecx,ecx
call display_error_string
jmp display_line_number
display_memory_source:
mov esi,_memory_source
xor ecx,ecx
call display_error_string
display_line_number:
mov esi,_line_number_prefix
xor ecx,ecx
call display_error_string
mov eax,[ebx+SourceEntry.line_number]
xor edx,edx
call itoa
call display_error_string
mov esi,_line_number_suffix
xor ecx,ecx
call display_error_string
pop ebx
mov esi,[esp]
push ebx
cmp [ebx+SourceEntry.line_number],0
je skip_line_content
test [trace_mode],TRACE_ERROR_STACK
jnz show_source_line
cmp ebx,[last_source_entry]
je last_source_entry_line_content
cmp ebx,[last_file_source_entry]
je show_source_line
skip_line_content:
mov esi,_space
next_source_entry:
pop ebx
find_next_source_entry:
cmp ebx,[last_source_entry]
je source_context_shown
add ebx,sizeof.SourceEntry
test [trace_mode],TRACE_ERROR_STACK
jnz show_source_entry
test [ebx+SourceEntry.flags],SRCF_PREPROCESSED
jnz find_next_source_entry
show_source_entry:
xor ecx,ecx
call display_error_string
jmp show_source_context
last_source_entry_line_content:
test [esi+Error.flags],ERR_CUSTOM
jnz skip_line_content
show_source_line:
cmp [ebx+SourceEntry.type],SOURCE_CALM
je show_calm_source
mov esi,_line_content_prefix
xor ecx,ecx
call display_error_string
call show_line_content
mov esi,_new_line
jmp next_source_entry
show_calm_source:
mov esi,_calm_source
xor ecx,ecx
call display_error_string
mov esi,_new_line
jmp next_source_entry
source_context_shown:
mov esi,_new_line
xor ecx,ecx
call display_error_string
mov ebx,[esp]
test [ebx+Error.flags],ERR_CUSTOM
jnz display_error_message
cmp [ebx+Error.preprocessed_length],0
je display_error_message
mov esi,_preprocessed_text_prefix
xor ecx,ecx
call display_error_string
mov esi,[ebx+Error.preprocessed_data]
mov ecx,[ebx+Error.preprocessed_length]
call show_preprocessed_line
mov esi,_new_line
xor ecx,ecx
call display_error_string
display_error_message:
pop ebx
call show_error_message
mov esi,ebx
next_error:
mov esi,[esi+Error.next]
jmp display_error
show_error_message:
; in:
; ebx - Error
; preserves: ebx
mov esi,_error_prefix
test [ebx+Error.flags],ERR_CUSTOM
jz display_error_prefix
mov esi,_custom_error_prefix
display_error_prefix:
xor ecx,ecx
call display_error_string
mov esi,[ebx+Error.message]
test [ebx+Error.flags],ERR_CUSTOM
jz format_error_message
xor ecx,ecx
call display_error_string
finish_error_message:
mov esi,_message_suffix
xor ecx,ecx
call display_error_string
retn
format_error_message:
mov edx,esi
cut_error_message:
lodsb
test al,al
jz show_error_message_segment
cmp al,'%'
jne cut_error_message
show_error_message_segment:
dec esi
push esi
xchg ecx,esi
sub ecx,edx
mov esi,edx
call display_error_string
pop esi
lodsb
test al,al
jz finish_error_message
lodsb
cmp al,'s'
je insert_string_into_error_message
cmp al,'i'
jne format_error_message
push ebx
mov ebx,[ebx+Error.symbol]
mov ebx,[ebx+SymbolTree_Leaf.branch]
call show_symbol_name
pop ebx
jmp format_error_message
insert_string_into_error_message:
push esi
mov esi,[ebx+Error.symbol]
xor ecx,ecx
call display_error_string
pop esi
jmp format_error_message
show_symbol_name:
; in:
; ebx - SymbolTree_Foliage, may be null
; preserves: esi
test ebx,ebx
jz symbol_name_shown
mov edi,[identifier_workspace.memory_start]
cmp [ebx+SymbolTree_Foliage.name_kind],NAME_NUMERIC
je next_name_segment
compose_symbol_name:
mov ecx,[ebx+SymbolTree_Foliage.name_length]
mov edx,identifier_workspace
mov al,[ebx+SymbolTree_Foliage.name_kind]
cmp al,NAME_CASESENSITIVE
je name_segment_to_copy
cmp al,NAME_ABSTRACT
je name_segment_copied
cmp al,NAME_NUMERIC
je dot_label_name
mov al,'?'
stosb
name_segment_to_copy:
push ecx
add ecx,2
call reserve_workspace
pop ecx
mov edx,[ebx+SymbolTree_Foliage.name_data]
copy_name_segment:
jecxz name_segment_copied
dec ecx
mov al,[edx+ecx]
stosb
jmp copy_name_segment
dot_label_name:
push esi
mov esi,[ebx+SymbolTree_Foliage.name_data]
xor eax,eax
read_dot_count:
jecxz dot_count_read
dec ecx
shl eax,8
mov al,[esi+ecx]
jmp read_dot_count
dot_count_read:
pop esi
push eax
lea ecx,[eax+2]
call reserve_workspace
pop ecx
mov al,'.'
rep stosb
name_segment_copied:
mov edx,[ebx+SymbolTree_Foliage.root]
mov ebx,[edx+SymbolTree_Root.parent_branch]
test [edx+SymbolTree_Root.flags],NAMESPACE_LOCAL or NAMESPACE_CALM
jnz mark_local_symbol_name
test ebx,ebx
jz symbol_name_ready
next_name_segment:
mov al,'.'
stosb
jmp compose_symbol_name
mark_local_symbol_name:
mov al,':'
stosb
test [edx+SymbolTree_Root.flags],NAMESPACE_CALM
jz symbol_name_ready
mov eax,[ebx+SymbolTree_Foliage.name_data]
mov ebx,[eax+SymbolTree_Leaf.branch]
test ebx,ebx
jnz compose_symbol_name
symbol_name_ready:
mov ebx,[identifier_workspace.memory_start]
mov ecx,edi
sub ecx,ebx
jz symbol_name_shown
push esi
mov esi,ebx
reverse_composed_name:
dec edi
cmp ebx,edi
jae show_composed_name
mov al,[ebx]
xchg al,[edi]
mov [ebx],al
inc ebx
jmp reverse_composed_name
show_composed_name:
call display_error_string
pop esi
symbol_name_shown:
retn
show_line_content:
; in:
; ebx - SourceEntry
cmp [ebx+SourceEntry.type],SOURCE_MACRO
je show_line_from_macro
mov esi,[ebx+SourceEntry.text]
add esi,[ebx+SourceEntry.line_offset]
mov ecx,[ebx+SourceEntry.number_of_attached_lines]
inc ecx
mov [number_of_lines],ecx
show_token:
mov al,[esi]
test al,al
jz line_content_shown
cmp al,0Ah
je line_content_shown
cmp al,1Ah
je show_name_token
cmp al,22h
je show_string_token
cmp al,27h
je show_string_token
cmp al,'\'
jne show_basic_token
cmp byte [esi+1],0Ah
jne show_basic_token
dec [number_of_lines]
jnz show_attached_line
show_basic_token:
mov ecx,1
call display_error_string
inc esi
jmp show_token
show_name_token:
add esi,1+4
mov ecx,[esi-4]
call display_error_string
add esi,[esi-4]
add esi,12
jmp show_token
show_string_token:
mov ebx,esi
inc esi
call show_string_token_content
lea esi,[ebx+1]
lodsd
add esi,eax
jmp show_token
show_string_token_content:
lea edi,[esi+4]
mov ecx,[esi]
show_string_segment:
push ecx edi
mov esi,_single_quote
mov ecx,1
call display_error_string
pop edi ecx
jecxz show_end_quote
mov edx,ecx
mov al,27h
repne scasb
sub edx,ecx
mov esi,edi
sub esi,edx
push ecx edi
mov ecx,edx
call display_error_string
pop edi ecx
test ecx,ecx
jnz show_string_segment
show_end_quote:
cmp byte [ebx],27h
je string_token_shown
mov esi,_single_quote
mov ecx,1
call display_error_string
string_token_shown:
retn
show_attached_line:
mov ecx,1
call display_error_string
lea ebx,[esi+2]
mov esi,_line_segment_prefix
xor ecx,ecx
call display_error_string
mov esi,ebx
jmp show_token
show_line_from_macro:
mov edx,[ebx+SourceEntry.text]
mov esi,[edx+ValueDefinition.value]
mov ecx,[edx+ValueDefinition.value_length]
mov eax,[ebx+SourceEntry.line_offset]
add esi,eax
sub ecx,eax
jbe line_content_shown
call show_preprocessed_line
line_content_shown:
retn
show_preprocessed_line:
; in:
; esi - preprocessed tokens
; ecx = total length of preprocessed tokens
lea eax,[esi+ecx]
mov [preprocessed_text_end],eax
show_preprocessed_token:
cmp esi,[preprocessed_text_end]
jae preprocessed_line_shown
mov al,[esi]
test al,al
jz preprocessed_line_shown
cmp al,1Ah
je show_preprocessed_name_token
cmp al,22h
je show_preprocessed_string_token
cmp al,27h
je show_preprocessed_string_token
cmp al,30h
je show_internal_number
cmp al,40h
je show_context_token
mov ecx,1
call display_error_string
inc esi
jmp show_preprocessed_token
show_preprocessed_name_token:
inc esi
lodsd
mov ebx,esi
mov esi,eax
lodsd
mov ecx,eax
call display_error_string
mov esi,ebx
jmp show_preprocessed_token
show_preprocessed_string_token:
mov ebx,esi
mov esi,[esi+1]
call show_string_token_content
lea esi,[ebx+1+4]
jmp show_preprocessed_token
show_internal_number:
inc esi
mov edx,esi
push esi
call convert_number_back
lea esi,[edx+4]
mov ecx,[edx]
call display_error_string
pop esi
add esi,[esi]
add esi,4
jmp show_preprocessed_token
show_context_token:
add esi,1+sizeof.RecognitionContext
jmp show_preprocessed_token
preprocessed_line_shown:
retn
itoa:
; in:
; edx:eax = unsigned number
; out:
; esi - temporary buffer containing decimal digits
; ecx = length of string (number of digits)
mov edi,temporary_value+4
stosd
mov eax,edx
stosd
mov edx,temporary_value
mov dword [edx],8
call convert_number_back
lea esi,[edx+4]
mov ecx,[edx]
retn

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,643 @@
include 'macro/struct.inc'
include '../version.inc'
BUFFER_SIZE = 4000h
STACK_SIZE = 4000h
format MZ
heap 0
stack stack_segment:stack_top-stack_bottom
entry loader:startup
use i386
segment loader use16
startup:
mov ax,1687h
int 2Fh
or ax,ax ; DPMI installed?
jnz short no_dpmi
test bl,1 ; 32-bit programs supported?
jz short no_dpmi
mov word [cs:mode_switch],di
mov word [cs:mode_switch+2],es
mov bx,si ; allocate memory for DPMI data
mov ah,48h
int 21h
jnc switch_to_protected_mode
init_failed:
call startup_error
db 'DPMI initialization failed.',0Dh,0Ah,0
no_dpmi:
call startup_error
db '32-bit DPMI services are not available.',0Dh,0Ah,0
startup_error:
pop si
push cs
pop ds
show_message:
lodsb
test al,al
jz message_shown
mov dl,al
mov ah,2
int 21h
jmp show_message
message_shown:
mov ax,4CFFh
int 21h
switch_to_protected_mode:
mov es,ax
mov ds,[ds:2Ch]
mov ax,1
call far [cs:mode_switch] ; switch to protected mode
jc init_failed
mov cx,1
xor ax,ax
int 31h ; allocate descriptor for code
jc init_failed
mov si,ax
xor ax,ax
int 31h ; allocate descriptor for data
jc init_failed
mov di,ax
mov dx,cs
lar cx,dx
shr cx,8
or cx,0C000h
mov bx,si
mov ax,9
int 31h ; set code descriptor access rights
jc init_failed
mov dx,ds
lar cx,dx
shr cx,8
or cx,0C000h
mov bx,di
int 31h ; set data descriptor access rights
jc init_failed
mov ecx,main
shl ecx,4
mov dx,cx
shr ecx,16
mov ax,7
int 31h ; set data descriptor base address
jc init_failed
mov bx,si
int 31h ; set code descriptor base address
jc init_failed
mov cx,0FFFFh
mov dx,0FFFFh
mov ax,8 ; set segment limit to 4 GB
int 31h
jc init_failed
mov bx,di
int 31h
jc init_failed
mov ax,ds
mov ds,di
mov [main_selector],di
mov [psp_selector],es
mov gs,ax ; environment selector in GS
cli
mov ss,di
mov esp,stack_top
sti
mov es,di
mov cx,1
xor ax,ax
int 31h ; allocate descriptor for BIOS data segment
jc init_failed
mov bx,ax
mov ax,gs
lar cx,ax
shr cx,8
mov ax,9
int 31h ; set descriptor access rights
jc init_failed
xor cx,cx
mov dx,400h
mov ax,7
int 31h ; set base address of BIOS data segment
jc init_failed
xor cx,cx
mov dx,0FFh
mov ax,8
int 31h ; set limit of BIOS data segment
jc init_failed
mov fs,bx ; BIOS data selector in FS
push si
push start
retf
mode_switch dd ?
segment main use32
start:
call system_init
call get_arguments
mov bl,al
cmp [no_logo],0
jne logo_ok
mov esi,_logo
xor ecx,ecx
call display_string
logo_ok:
test bl,bl
jnz display_usage_information
xor al,al
mov ecx,[verbosity_level]
jecxz init
or al,TRACE_ERROR_STACK
dec ecx
jz init
or al,TRACE_DISPLAY
init:
call assembly_init
mov eax,[fs:6Ch]
mov [timer],eax
assemble:
mov esi,[initial_commands]
mov edx,[source_path]
call assembly_pass
jc assembly_done
mov eax,[current_pass]
cmp eax,[maximum_number_of_passes]
jb assemble
call show_display_data
mov esi,_error_prefix
xor ecx,ecx
call display_error_string
mov esi,_code_cannot_be_generated
xor ecx,ecx
call display_error_string
mov esi,_message_suffix
xor ecx,ecx
call display_error_string
jmp assembly_failed
assembly_done:
call show_display_data
cmp [first_error],0
jne assembly_failed
cmp [no_logo],0
jne summary_done
mov eax,[current_pass]
xor edx,edx
call itoa
call display_string
mov esi,_passes
cmp [current_pass],1
jne display_passes_suffix
mov esi,_pass
display_passes_suffix:
xor ecx,ecx
call display_string
mov eax,[fs:6Ch]
sub eax,[timer]
mov ecx,36000
mul ecx
shrd eax,edx,16
shr edx,16
mov ecx,10
div ecx
mov [timer],edx
or edx,eax
jz display_output_length
xor edx,edx
call itoa
call display_string
mov esi,_message_suffix
mov ecx,1
call display_string
mov eax,[timer]
xor edx,edx
call itoa
call display_string
mov esi,_seconds
xor ecx,ecx
call display_string
display_output_length:
call get_output_length
push eax edx
call itoa
call display_string
pop edx eax
mov esi,_bytes
cmp eax,1
jne display_bytes_suffix
test edx,edx
jnz display_bytes_suffix
mov esi,_byte
display_bytes_suffix:
xor ecx,ecx
call display_string
mov esi,_new_line
xor ecx,ecx
call display_string
summary_done:
mov ebx,[source_path]
mov edi,[output_path]
call write_output_file
jc write_failed
call assembly_shutdown
call system_shutdown
mov ax,4C00h
int 21h
assembly_failed:
call show_errors
call assembly_shutdown
call system_shutdown
mov ax,4C02h
int 21h
write_failed:
mov ebx,_write_failed
jmp fatal_error
out_of_memory:
mov ebx,_out_of_memory
jmp fatal_error
fatal_error:
mov esi,_error_prefix
xor ecx,ecx
call display_error_string
mov esi,ebx
xor ecx,ecx
call display_error_string
mov esi,_message_suffix
xor ecx,ecx
call display_error_string
call assembly_shutdown
call system_shutdown
mov ax,4C03h
int 21h
display_usage_information:
mov esi,_usage
xor ecx,ecx
call display_string
call system_shutdown
mov ax,4C01h
int 21h
get_arguments:
push ds
mov ds,[psp_selector]
mov esi,81h
mov edi,command_line
mov ecx,7Fh
move_command_line:
lodsb
cmp al,0Dh
je command_line_moved
stosb
loop move_command_line
command_line_moved:
pop ds
xor eax,eax
stosb
mov [initial_commands],eax
mov [source_path],eax
mov [output_path],eax
mov [no_logo],al
mov [verbosity_level],eax
mov [maximum_number_of_passes],100
mov [maximum_number_of_errors],1
mov [maximum_depth_of_stack],10000
mov esi,command_line
mov edi,parameters
get_argument:
xor ah,ah
read_character:
lodsb
test al,al
jz no_more_arguments
cmp al,22h
je switch_quote
cmp ax,20h
je end_argument
stosb
jmp read_character
end_argument:
xor al,al
stosb
find_next_argument:
mov al,[esi]
test al,al
jz no_more_arguments
cmp al,20h
jne next_argument_found
inc esi
jmp find_next_argument
switch_quote:
xor ah,1
jmp read_character
next_argument_found:
cmp al,'-'
je get_option
cmp al,'/'
je get_option
cmp [source_path],0
je get_source_path
cmp [output_path],0
je get_output_path
error_in_arguments:
or al,-1
retn
get_source_path:
mov [source_path],edi
jmp get_argument
get_output_path:
mov [output_path],edi
jmp get_argument
no_more_arguments:
cmp [source_path],0
je error_in_arguments
xor al,al
stosb
retn
get_option:
inc esi
lodsb
cmp al,'e'
je set_errors_limit
cmp al,'E'
je set_errors_limit
cmp al,'i'
je insert_initial_command
cmp al,'I'
je insert_initial_command
cmp al,'p'
je set_passes_limit
cmp al,'P'
je set_passes_limit
cmp al,'r'
je set_recursion_limit
cmp al,'R'
je set_recursion_limit
cmp al,'v'
je set_verbose_mode
cmp al,'V'
je set_verbose_mode
cmp al,'n'
je set_no_logo
cmp al,'N'
jne error_in_arguments
set_no_logo:
or [no_logo],-1
mov al,[esi]
cmp al,20h
je find_next_argument
test al,al
jnz error_in_arguments
jmp find_next_argument
set_verbose_mode:
call get_option_value
jc error_in_arguments
cmp edx,2
ja error_in_arguments
mov [verbosity_level],edx
jmp find_next_argument
set_errors_limit:
call get_option_value
jc error_in_arguments
test edx,edx
jz error_in_arguments
mov [maximum_number_of_errors],edx
jmp find_next_argument
set_recursion_limit:
call get_option_value
jc error_in_arguments
test edx,edx
jz error_in_arguments
mov [maximum_depth_of_stack],edx
jmp find_next_argument
set_passes_limit:
call get_option_value
jc error_in_arguments
test edx,edx
jz error_in_arguments
mov [maximum_number_of_passes],edx
jmp find_next_argument
get_option_value:
xor eax,eax
mov edx,eax
find_option_value:
cmp byte [esi],20h
jne get_option_digit
inc esi
jmp find_option_value
get_option_digit:
lodsb
cmp al,20h
je option_value_ok
test al,al
jz option_value_ok
sub al,30h
jc invalid_option_value
cmp al,9
ja invalid_option_value
imul edx,10
jo invalid_option_value
add edx,eax
jc invalid_option_value
jmp get_option_digit
option_value_ok:
dec esi
clc
ret
invalid_option_value:
stc
ret
insert_initial_command:
push edi
find_command_segment:
cmp byte [esi],20h
jne command_segment_found
inc esi
jmp find_command_segment
command_segment_found:
xor ah,ah
cmp byte [esi],22h
jne measure_command_segment
inc esi
inc ah
measure_command_segment:
mov ebx,esi
scan_command_segment:
mov ecx,esi
mov al,[esi]
test al,al
jz command_segment_measured
cmp ax,20h
je command_segment_measured
cmp ax,22h
je command_segment_measured
inc esi
cmp al,22h
jne scan_command_segment
command_segment_measured:
sub ecx,ebx
mov edi,[initial_commands]
lea eax,[ecx+2]
test edi,edi
jz allocate_initial_commands_buffer
mov edx,[initial_commands_length]
add edi,edx
add eax,edx
cmp eax,[initial_commands_maximum_length]
ja grow_initial_commands_buffer
copy_initial_command:
xchg esi,ebx
rep movsb
mov esi,ebx
sub edi,[initial_commands]
mov [initial_commands_length],edi
mov al,[esi]
test al,al
jz initial_command_ready
cmp al,20h
jne command_segment_found
initial_command_ready:
mov edi,[initial_commands]
add edi,[initial_commands_length]
mov ax,0Ah
stosw
inc [initial_commands_length]
pop edi
jmp find_next_argument
allocate_initial_commands_buffer:
push ecx
mov ecx,eax
call malloc
mov [initial_commands],eax
mov [initial_commands_maximum_length],ecx
mov edi,eax
pop ecx
jmp copy_initial_command
grow_initial_commands_buffer:
push ecx
mov ecx,eax
mov eax,[initial_commands]
call realloc
mov [initial_commands],eax
mov [initial_commands_maximum_length],ecx
mov edi,eax
add edi,[initial_commands_length]
pop ecx
jmp copy_initial_command
include 'system.inc'
include '../malloc.inc'
include '../assembler.inc'
include '../symbols.inc'
include '../expressions.inc'
include '../conditions.inc'
include '../floats.inc'
include '../directives.inc'
include '../calm.inc'
include '../errors.inc'
include '../map.inc'
include '../reader.inc'
include '../output.inc'
include '../console.inc'
_logo db 'flat assembler version g.',VERSION,13,10,0
_usage db 'Usage: fasmg source [output]',13,10
db 'Optional settings:',13,10
db ' -e limit Set the maximum number of displayed errors (default 1)',13,10
db ' -p limit Set the maximum allowed number of passes (default 100)',13,10
db ' -r limit Set the maximum depth of the stack (default 10000)',13,10
db ' -v flag Enable or disable showing all lines from the stack (default 0)',13,10
db ' -i command Insert instruction at the beginning of source',13,10
db ' -n Do not show logo nor summary',13,10
db 0
_pass db ' pass, ',0
_passes db ' passes, ',0
_dot db '.'
_seconds db ' seconds, ',0
_byte db ' byte.',0
_bytes db ' bytes.',0
_write_failed db 'failed to write the output file',0
_out_of_memory db 'not enough memory to complete the assembly',0
_code_cannot_be_generated db 'could not generate code within the allowed number of passes',0
include '../tables.inc'
include '../messages.inc'
align 4
include '../variables.inc'
psp_selector dw ?
main_selector dw ?
malloc_freelist dd ?
source_path dd ?
output_path dd ?
maximum_number_of_passes dd ?
initial_commands dd ?
initial_commands_length dd ?
initial_commands_maximum_length dd ?
timestamp dq ?
timer dd ?
verbosity_level dd ?
no_logo db ?
command_line db 80h dup ?
parameters db 80h dup ?
segment buffer_segment
buffer = (buffer_segment-main) shl 4
db BUFFER_SIZE dup ?
segment stack_segment
stack_bottom = (stack_segment-main) shl 4
db STACK_SIZE dup ?
stack_top = stack_bottom + $

View File

@@ -0,0 +1,415 @@
LINE_FEED equ 13,10
system_init:
cld
mov [malloc_freelist],0
mov ah,2Ah
int 21h
push dx cx
movzx ecx,cx
mov eax,ecx
sub eax,1970
mov ebx,365
mul ebx
mov ebp,eax
mov eax,ecx
sub eax,1969
shr eax,2
add ebp,eax
mov eax,ecx
sub eax,1901
mov ebx,100
div ebx
sub ebp,eax
mov eax,ecx
xor edx,edx
sub eax,1601
mov ebx,400
div ebx
add ebp,eax
movzx ecx,byte [esp+3]
mov eax,ecx
dec eax
mov ebx,30
mul ebx
add ebp,eax
cmp ecx,8
jbe months_correction
mov eax,ecx
sub eax,7
shr eax,1
add ebp,eax
mov ecx,8
months_correction:
mov eax,ecx
shr eax,1
add ebp,eax
cmp ecx,2
pop cx
jbe day_correction_ok
sub ebp,2
test ecx,11b
jnz day_correction_ok
xor edx,edx
mov eax,ecx
mov ebx,100
div ebx
or edx,edx
jnz day_correction
mov eax,ecx
mov ebx,400
div ebx
or edx,edx
jnz day_correction_ok
day_correction:
inc ebp
day_correction_ok:
pop dx
movzx eax,dl
dec eax
add eax,ebp
mov ebx,24
mul ebx
push eax
mov ah,2Ch
int 21h
pop eax
push dx
movzx ebx,ch
add eax,ebx
mov ebx,60
mul ebx
movzx ebx,cl
add eax,ebx
mov ebx,60
mul ebx
pop bx
movzx ebx,bh
add eax,ebx
adc edx,0
mov dword [timestamp],eax
mov dword [timestamp+4],edx
retn
system_shutdown:
; call mcheck
retn
dos_int:
push 0
push 0
push 0
pushw buffer_segment
pushw buffer_segment
stc
pushfw
push eax
push ecx
push edx
push ebx
push 0
push ebp
push esi
push edi
mov ax,300h
mov bx,21h
xor cx,cx
mov edi,esp
push es ss
pop es
int 31h
pop es
mov edi,[esp]
mov esi,[esp+4]
mov ebp,[esp+8]
mov ebx,[esp+10h]
mov edx,[esp+14h]
mov ecx,[esp+18h]
mov ah,[esp+20h]
sahf
mov eax,[esp+1Ch]
lea esp,[esp+32h]
retn
open:
; in: edx - path to file
; out: ebx = file handle, cf set on error
; preserves: esi, edi
push esi edi
call adapt_path
mov ax,716Ch
mov bx,100000b
mov dx,1
xor cx,cx
xor si,si
call dos_int
jnc open_done
cmp ax,7100h
je old_open
stc
jmp open_done
old_open:
mov ax,3D00h
xor dx,dx
call dos_int
open_done:
mov bx,ax
pop edi esi
retn
adapt_path:
mov esi,edx
mov edi,buffer
copy_path:
lodsb
cmp al,'/'
jne path_char_ok
mov al,'\'
path_char_ok:
stosb
cmp edi,buffer+BUFFER_SIZE
jae out_of_memory
test al,al
jnz copy_path
retn
create:
; in: edx - path to file
; out: ebx = file handle, cf set on error
; preserves: esi, edi
push esi edi
call adapt_path
mov ax,716Ch
mov bx,100001b
mov dx,10010b
xor cx,cx
xor si,si
xor di,di
call dos_int
jnc create_done
cmp ax,7100h
je old_create
stc
jmp create_done
old_create:
mov ah,3Ch
xor cx,cx
xor dx,dx
call dos_int
create_done:
mov bx,ax
pop edi esi
retn
write:
; in: ebx = file handle, edx - data, ecx = number of bytes
; out: cf set on error
; preserves: ebx, esi, edi
push esi edi ebp
mov ebp,ecx
mov esi,edx
write_loop:
mov ecx,BUFFER_SIZE
sub ebp,BUFFER_SIZE
jnc do_write
add ebp,BUFFER_SIZE
mov ecx,ebp
xor ebp,ebp
do_write:
push ecx
mov edi,buffer
rep movsb
pop ecx
mov ah,40h
xor dx,dx
call dos_int
or ebp,ebp
jnz write_loop
pop ebp edi esi
ret
read:
; in: ebx = file handle, edx - buffer, ecx = number of bytes
; out: cf set on error
; preserves: ebx, esi, edi
push esi edi ebp
mov ebp,ecx
mov edi,edx
read_loop:
mov ecx,BUFFER_SIZE
sub ebp,BUFFER_SIZE
jnc do_read
add ebp,BUFFER_SIZE
mov ecx,ebp
xor ebp,ebp
do_read:
push ecx
mov ah,3Fh
xor dx,dx
call dos_int
cmp ax,cx
jne read_eof
mov esi,buffer
pop ecx
rep movsb
or ebp,ebp
jnz read_loop
read_done:
pop ebp edi esi
ret
read_eof:
pop ecx
stc
jmp read_done
close:
; in: ebx = file handle
; preserves: ebx, esi, edi
mov ah,3Eh
int 21h
ret
lseek:
; in: ebx = file handle, cl = method, edx:eax = offset
; out: edx:eax = new offset from the beginning of file, cf set on error
; preserves: ebx, esi, edi
mov dx,ax
xchg ecx,eax
shr ecx,16
mov ah,42h
int 21h
pushf
shl edx,16
popf
mov dx,ax
mov eax,edx
xor edx,edx
ret
get_timestamp:
; out: edx:eax = timestamp
; preserves: ebx, ecx, esi, edi
; note: during the passes of a single assembly this function should always return the same value
mov eax,dword [timestamp]
mov edx,dword [timestamp+4]
retn
display_string:
; in:
; esi - string
; ecx = string length, zero for ASCIIZ string
; preserves: ebx, esi
push ebx
mov ebx,1
jmp write_string
display_error_string:
; in:
; esi - string
; ecx = string length, zero for ASCIIZ string
; preserves: ebx, esi
push ebx
mov ebx,2
write_string:
test ecx,ecx
jnz string_length_ok
xor al,al
mov edi,esi
or ecx,-1
repne scasb
neg ecx
sub ecx,2
string_length_ok:
mov edx,esi
call write
pop ebx
retn
get_environment_variable:
; in:
; esi - name
; edi - buffer for value
; ecx = size of buffer
; out:
; eax = length of value
; preserves: ebx, esi, edi
push ebx esi edi
mov ebx,esi
xor esi,esi
compare_variable_names:
mov edx,ebx
compare_name_character:
lods byte [gs:esi]
mov ah,[edx]
inc edx
cmp al,'='
je end_of_variable_name
test ah,ah
jz next_variable
sub ah,al
jz compare_name_character
cmp ah,20h
jne next_variable
cmp al,41h
jb next_variable
cmp al,5Ah
jna compare_name_character
next_variable:
lods byte [gs:esi]
test al,al
jnz next_variable
cmp byte [gs:esi],0
jne compare_variable_names
mov ah,al
end_of_variable_name:
test ah,ah
jnz next_variable
add ecx,edi
mov edx,esi
copy_variable_value:
lods byte [gs:esi]
cmp edi,ecx
jae variable_value_next_character
stosb
variable_value_next_character:
or al,al
jnz copy_variable_value
lea eax,[esi-1]
sub eax,edx
pop edi esi ebx
ret
VALLOC_MIN = 40000h
valloc:
; in: ecx = requested minimum size
; out: eax - allocated block, ecx = allocated size, zero if failed
; preserves: ebx, esi, edi
cmp ecx,VALLOC_MIN
jbe valloc_size_minimum
dec ecx
and ecx,(-1) shl 12
add ecx,1 shl 12
jmp valloc_size_ready
valloc_size_minimum:
mov ecx,VALLOC_MIN
valloc_size_ready:
push ebx esi edi
push ecx
mov ebx,ecx
shr ebx,16
mov ax,501h
int 31h
movzx eax,cx
pop ecx
jc valloc_failed
shl ebx,16
or eax,ebx
mov edx,main
shl edx,4
sub eax,edx
pop edi esi ebx
ret
valloc_failed:
xor ecx,ecx
pop edi esi ebx
retn

View File

@@ -0,0 +1,177 @@
struct Error
flags dd ? ; ERR_#
message dd ?
symbol dd ?
preprocessed_data dd ?
preprocessed_length dd ?
next dd ? ; pointer to another Error
; source SourceContext
ends
ERR_CUSTOM = 1
register_volatile_error:
; in:
; edx - 32-bit length followed by string data
; ebx - data for message formatting (only relevant for non-custom messages that contain % character)
; out:
; edx - Error
; preserves: eax, ebx, ecx, esi, edi
cmp [next_pass_needed],0
jne error_ignored
push eax ebx ecx esi edi
or [message_volatile],1
jmp get_error_line
register_delayed_error:
; in:
; edx - error message
; esi - SourceContext
; ebx - data for message formatting (only relevant for non-custom messages that contain % character)
; out:
; edx - Error
; preserves: eax, ebx, ecx, esi, edi
cmp [next_pass_needed],0
jne error_ignored
push eax ebx ecx esi edi
and [message_volatile],0
and [error_line_start],0
and [error_line_end],0
jmp add_error
register_error:
; in:
; edx - error message
; ebx - data for message formatting (only relevant for non-custom messages that contain % character)
; out:
; edx - Error, null when error was not registered
; preserves: eax, ebx, ecx, esi, edi
cmp [next_pass_needed],0
jne error_ignored
push eax ebx ecx esi edi
and [message_volatile],0
get_error_line:
mov eax,[line_start]
mov [error_line_start],eax
mov ecx,[line_end]
cmp [number_of_line_embeddings],0
je error_line_end_ok
mov eax,[line_embeddings]
mov ecx,[eax+LineEmbedding.previous_end]
error_line_end_ok:
mov [error_line_end],ecx
xor esi,esi
add_error:
mov [error_symbol],ebx
lea ebx,[first_error]
xor ecx,ecx
find_last_error:
mov eax,[ebx]
test eax,eax
jz last_error_found
lea ebx,[eax+Error.next]
inc ecx
cmp ecx,[maximum_number_of_errors]
jb find_last_error
pop edi esi ecx ebx eax
xor edx,edx
retn
last_error_found:
cmp [message_volatile],0
jne prepare_volatile_error
test esi,esi
jnz prepare_error
mov esi,[source_context]
prepare_error:
mov ecx,[esi+SourceContext.number_of_entries]
imul ecx,sizeof.SourceEntry
add ecx,sizeof.SourceContext
cmp [esi+ecx-sizeof.SourceEntry+SourceEntry.type],SOURCE_CALM
jne error_source_context_ready
mov eax,[calm_instruction_number]
mov [esi+ecx-sizeof.SourceEntry+SourceEntry.line_number],eax
and [error_line_start],0
and [error_line_end],0
error_source_context_ready:
add ecx,sizeof.Error
add ecx,[error_line_end]
sub ecx,[error_line_start]
mov edi,edx
call malloc
mov [ebx],eax
mov [eax+Error.message],edi
mov ecx,[error_symbol]
mov [eax+Error.symbol],ecx
xor ecx,ecx
mov [eax+Error.flags],ecx
mov [eax+Error.next],ecx
lea edi,[eax+sizeof.Error]
push eax
call clone_source_context
pop edx
store_preprocessed_data:
mov [edx+Error.preprocessed_data],edi
mov esi,[error_line_start]
mov ecx,[error_line_end]
sub ecx,esi
mov [edx+Error.preprocessed_length],ecx
rep movsb
pop edi esi ecx ebx eax
retn
error_ignored:
xor edx,edx
retn
prepare_volatile_error:
mov esi,edx
mov eax,[source_context]
mov ecx,[eax+SourceContext.number_of_entries]
imul ecx,sizeof.SourceEntry
add ecx,sizeof.SourceContext
cmp [eax+ecx-sizeof.SourceEntry+SourceEntry.type],SOURCE_CALM
jne volatile_error_source_context_ready
mov edx,[calm_instruction_number]
mov [eax+ecx-sizeof.SourceEntry+SourceEntry.line_number],edx
and [error_line_start],0
and [error_line_end],0
volatile_error_source_context_ready:
add ecx,sizeof.Error
add ecx,[error_line_end]
sub ecx,[error_line_start]
mov edi,ecx
add ecx,[esi]
inc ecx
call malloc
add edi,eax
mov [ebx],eax
mov edx,eax
mov [edx+Error.message],edi
xor eax,eax
mov [edx+Error.next],eax
mov [edx+Error.flags],eax
lodsd
mov ecx,eax
rep movsb
xor al,al
stosb
mov esi,[source_context]
lea edi,[edx+sizeof.Error]
push edx
call clone_source_context
pop edx
jmp store_preprocessed_data
discard_errors:
mov eax,[first_error]
test eax,eax
jnz discard_error
retn
discard_error:
add eax,sizeof.Error
call release_source_context
sub eax,sizeof.Error
mov ebx,[eax+Error.next]
call mfree
mov eax,ebx
test eax,eax
jnz discard_error
mov [first_error],eax
retn

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,536 @@
; flat editor core
; Copyright (c) 1999-2015, Tomasz Grysztar.
; All rights reserved.
insert_block:
test [editor_mode],FEMODE_VERTICALSEL
jz block_to_insert_ok
push esi
or edx,-1
xor ecx,ecx
count_line_characters:
lodsb
cmp al,9
je cannot_insert
cmp al,0Dh
je count_next_line
or al,al
jz at_end_of_line
inc ecx
jmp count_line_characters
at_end_of_line:
dec esi
jmp check_block_width
count_next_line:
lodsb
cmp al,0Ah
je check_block_width
dec esi
check_block_width:
cmp edx,-1
je line_to_insert_ok
cmp edx,ecx
je line_to_insert_ok
cannot_insert:
pop esi
stc
retn
line_to_insert_ok:
mov edx,ecx
xor ecx,ecx
cmp byte [esi],0
jne count_line_characters
pop esi
block_to_insert_ok:
mov eax,[caret_line]
mov ecx,[caret_line_number]
mov edx,[caret_position]
mov [selection_line],eax
mov [selection_line_number],ecx
mov [selection_position],edx
mov ebx,esi
get_line_to_insert:
lodsb
or al,al
jz insert_full_line
cmp al,0Dh
je insert_full_line
cmp al,0Ah
je insert_full_line
cmp al,9
jne get_line_to_insert
push esi
dec esi
mov ecx,esi
sub ecx,ebx
mov esi,ebx
push ecx
call insert_into_line
pop ecx
add [caret_position],ecx
mov ecx,[caret_position]
and ecx,not 111b
sub ecx,[caret_position]
add ecx,8
xor esi,esi
push ecx
call insert_into_line
pop ecx
add [caret_position],ecx
pop esi
mov ebx,esi
jmp get_line_to_insert
insert_full_line:
dec esi
push esi
mov ecx,esi
sub ecx,ebx
mov esi,ebx
push ecx
call insert_into_line
pop ecx
add [caret_position],ecx
pop esi
lodsb
or al,al
jz last_line_inserted
cmp al,0Ah
je lf_first
lodsb
cmp al,0Ah
je next_line_to_insert
dec esi
jmp next_line_to_insert
lf_first:
lodsb
cmp al,0Dh
je next_line_to_insert
dec esi
next_line_to_insert:
mov ebx,[selection_position]
test [editor_mode],FEMODE_VERTICALSEL
jnz insert_in_next_line
test [editor_mode],FEMODE_OVERWRITE
jz insert_new_line
push esi
call clear_rest_of_line
pop esi
xor ebx,ebx
insert_in_next_line:
push esi ebx
mov esi,[caret_line]
call check_line_length
pop ebx
call go_to_next_line
pop esi
mov ebx,esi
jmp get_line_to_insert
last_line_inserted:
mov esi,[caret_line]
call check_line_length
clc
retn
insert_new_line:
push esi
push [caret_line]
push [caret_line_number]
xor ebx,ebx
call break_line
pop [caret_line_number]
pop ebx esi
push [caret_line]
mov [caret_line],ebx
go_to_end_of_first_line:
test byte [ebx],1
jz insert_full_lines
mov ebx,[ebx]
dec ebx
jmp go_to_end_of_first_line
insert_full_lines:
call allocate_segment
jc memory_shortage
call store_allocated_segment_for_undo
mov [ebx],eax
mov ebx,eax
mov eax,[caret_line]
mov [ebx+4],eax
mov [caret_line],ebx
inc [caret_line_number]
inc [lines_count]
call set_line
jc full_lines_inserted
jmp insert_full_lines
full_lines_inserted:
pop edi
mov eax,[caret_line]
mov [edi+4],eax
mov [ebx],edi
call cut_line_break
mov esi,[caret_line]
call check_line_length
clc
retn
set_line:
mov edi,ebx
add edi,SEGMENT_HEADER_LENGTH
mov ecx,SEGMENT_DATA_LENGTH
mov [caret_position],0
push ebx
copy_line:
lodsb
or al,al
jz last_line_set
cmp al,0Ah
je copy_lf
cmp al,0Dh
je copy_cr
cmp al,9
je copy_tab
set_character:
stosb
loop copy_line
extra_segment:
call allocate_segment
jc memory_shortage
call store_allocated_segment_for_undo
mov edi,eax
or eax,1
mov [ebx],eax
or ebx,1
mov [edi+4],ebx
mov ebx,edi
add edi,SEGMENT_HEADER_LENGTH
mov ecx,SEGMENT_DATA_LENGTH
add [caret_position],ecx
jmp copy_line
copy_tab:
mov al,20h
mov edx,SEGMENT_DATA_LENGTH
sub edx,ecx
add edx,[caret_position]
and edx,111b
cmp edx,111b
je set_character
dec esi
jmp set_character
copy_lf:
cmp byte [esi],0Dh
jne copy_new_line
inc esi
jmp copy_new_line
copy_cr:
cmp byte [esi],0Ah
jne copy_new_line
inc esi
copy_new_line:
pop edx
call finish_line
clc
retn
last_line_set:
pop edx
call finish_line
stc
retn
finish_line:
mov eax,SEGMENT_DATA_LENGTH
sub eax,ecx
add eax,[caret_position]
mov [caret_position],eax
mov [edx+8],eax
call register_length
mov al,20h
rep stosb
retn
delete_block:
test [editor_mode],FEMODE_VERTICALSEL
jnz delete_vertical_block
mov eax,[caret_line_number]
cmp eax,[selection_line_number]
je delete_vertical_block
mov esi,[caret_line]
mov ecx,[caret_line_number]
mov edx,[caret_position]
cmp ecx,[selection_line_number]
jbe position_for_deleting_ok
xchg esi,[selection_line]
xchg ecx,[selection_line_number]
xchg edx,[selection_position]
mov [caret_line],esi
mov [caret_line_number],ecx
mov [caret_position],edx
position_for_deleting_ok:
test [editor_mode],FEMODE_OVERWRITE
jnz clear_block
call get_caret_segment
cmp edx,SEGMENT_DATA_LENGTH
jb first_line_of_block
call attach_empty_segments
first_line_of_block:
mov ecx,[caret_position]
sub ecx,edx
skip_rest_of_first_line:
add ecx,SEGMENT_DATA_LENGTH
mov eax,[esi]
btr eax,0
jnc end_of_first_line
mov esi,eax
jmp skip_rest_of_first_line
end_of_first_line:
call store_segment_for_undo
mov edi,esi
mov esi,eax
remove_middle_lines:
cmp esi,[selection_line]
je middle_lines_removed
call store_freed_segment_for_undo
mov ebx,[esi]
call cancel_line
mov esi,ebx
btr esi,0
jnc remove_middle_lines
remove_middle_line_segments:
call store_freed_segment_for_undo
mov esi,[esi]
btr esi,0
jc remove_middle_line_segments
jmp remove_middle_lines
middle_lines_removed:
call store_segment_for_undo
mov eax,esi
or eax,1
mov [edi],eax
mov eax,edi
or eax,1
mov [esi+4],eax
call cancel_line
add ecx,[selection_position]
sub ecx,[caret_position]
call delete_from_line
mov esi,[caret_line]
find_following_line:
mov esi,[esi]
btr esi,0
jc find_following_line
or esi,esi
jz following_line_ok
call store_segment_for_undo
mov eax,[caret_line]
mov [esi+4],eax
following_line_ok:
mov esi,[caret_line]
call check_line_length
block_deleted:
retn
clear_block:
push [caret_line]
push [caret_position]
clear_lines:
call clear_rest_of_line
mov [caret_line],esi
mov [caret_position],0
cmp esi,[selection_line]
jne clear_lines
mov ecx,[selection_position]
call clear_in_line
pop [caret_position]
pop [caret_line]
retn
delete_vertical_block:
push [caret_line]
push [caret_line_number]
mov eax,[caret_position]
cmp eax,[selection_position]
jbe delete_vertical_block_line
xchg eax,[selection_position]
mov [caret_position],eax
delete_vertical_block_line:
mov ecx,[selection_position]
sub ecx,[caret_position]
call delete_from_line
mov esi,[caret_line]
call check_line_length
mov esi,[caret_line]
mov eax,[caret_line_number]
cmp eax,[selection_line_number]
je vertical_block_deleted
ja delete_in_previous_line
delete_in_next_line:
mov esi,[esi]
btr esi,0
jc delete_in_next_line
mov [caret_line],esi
inc [caret_line_number]
jmp delete_vertical_block_line
delete_in_previous_line:
mov esi,[esi+4]
mov [caret_line],esi
dec [caret_line_number]
jmp delete_vertical_block_line
vertical_block_deleted:
pop [caret_line_number]
pop [caret_line]
mov [selection_line],0
retn
get_block_length:
test [editor_mode],FEMODE_VERTICALSEL
jnz get_length_of_vertical_block
mov esi,[caret_line]
mov edx,[caret_position]
mov ebx,[selection_line]
mov ecx,[selection_position]
mov eax,[caret_line_number]
cmp eax,[selection_line_number]
je get_length_of_vertical_block
jb get_length_of_standard_block
xchg esi,ebx
xchg ecx,edx
get_length_of_standard_block:
push ecx
mov ecx,[esi+8]
sub ecx,edx
jae add_length_of_line
xor ecx,ecx
add_length_of_line:
add ecx,2
add [esp],ecx
skip_standard_block_line:
mov esi,[esi]
btr esi,0
jc skip_standard_block_line
cmp esi,ebx
je length_of_block_ok
mov ecx,[esi+8]
jmp add_length_of_line
length_of_block_ok:
pop ecx
retn
get_length_of_vertical_block:
mov edx,[caret_line_number]
sub edx,[selection_line_number]
jae vertical_dimension_ok
neg edx
vertical_dimension_ok:
mov eax,[caret_position]
sub eax,[selection_position]
jae horizontal_dimension_ok
neg eax
horizontal_dimension_ok:
mov ecx,eax
add eax,2
mul edx
add ecx,eax
retn
copy_block:
test [editor_mode],FEMODE_VERTICALSEL
jnz copy_vertical_block
mov esi,[caret_line]
mov edx,[caret_position]
mov ebx,[selection_line]
mov ecx,[selection_position]
mov eax,[caret_line_number]
cmp eax,[selection_line_number]
je copy_vertical_block
jb copy_standard_block
xchg esi,ebx
xchg ecx,edx
copy_standard_block:
push ecx
push ebx
mov ecx,[esi+8]
sub ecx,edx
jb after_line_end
call copy_from_line
jmp block_line_copied
after_line_end:
mov esi,[esi]
btr esi,0
jc after_line_end
block_line_copied:
pop ebx
copy_next_line:
mov ax,0A0Dh
stosw
cmp esi,ebx
je copy_from_last_line
push ebx
mov ecx,[esi+8]
xor edx,edx
call copy_from_line
pop ebx
jmp copy_next_line
copy_from_last_line:
pop ecx
xor edx,edx
call copy_from_line
xor al,al
stosb
retn
copy_vertical_block:
mov esi,[caret_line]
mov ebx,[selection_line]
mov edx,[caret_position]
mov ecx,[selection_position]
mov eax,[caret_line_number]
cmp eax,[selection_line_number]
jbe vertical_block_starting_line_ok
xchg esi,ebx
vertical_block_starting_line_ok:
cmp edx,ecx
jbe vertical_block_starting_position_ok
xchg edx,ecx
vertical_block_starting_position_ok:
sub ecx,edx
copy_line_from_vertical_block:
mov eax,ebx
sub eax,esi
push eax ebx ecx edx
call copy_from_line
pop edx ecx ebx eax
or eax,eax
jz vertical_block_copied
mov ax,0A0Dh
stosw
jmp copy_line_from_vertical_block
vertical_block_copied:
xor al,al
stosb
retn
copy_from_line:
mov ebx,ecx
find_copying_origin:
cmp edx,SEGMENT_DATA_LENGTH
jb copy_line_segment
mov esi,[esi]
btr esi,0
jnc line_data_ended
sub edx,SEGMENT_DATA_LENGTH
jmp find_copying_origin
copy_line_segment:
mov ecx,SEGMENT_DATA_LENGTH
sub ecx,edx
cmp ebx,ecx
jae line_segment_length_ok
mov ecx,ebx
line_segment_length_ok:
sub ebx,ecx
mov eax,[esi]
lea esi,[esi+SEGMENT_HEADER_LENGTH+edx]
rep movsb
mov esi,eax
btr esi,0
jnc line_data_ended
xor edx,edx
jmp copy_line_segment
line_data_ended:
or ebx,ebx
jz line_copy_done
mov ecx,ebx
mov al,20h
rep stosb
line_copy_done:
retn

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,199 @@
; flat editor core
; Copyright (c) 1999-2015, Tomasz Grysztar.
; All rights reserved.
init_editor_memory:
mov ecx,BLOCK_LENGTH
call get_memory
or eax,eax
jz memory_error
mov [editor_memory],eax
mov dword [eax],0
mov dword [eax+4],0
mov dword [eax+8],ebx
lea ebx,[eax+SEGMENT_LENGTH]
mov [unallocated_segments],ebx
mov [memory_search_segment],ebx
add eax,BLOCK_LENGTH
mov [unallocated_segments_end],eax
mov [memory_search_block],eax
mov [released_segments],0
call allocate_segment
mov [first_line],eax
mov [lines_count],1
mov [peak_line_length],0
mov [caret_line],eax
mov [caret_line_number],1
mov [window_line],eax
mov [window_line_number],1
mov edi,eax
xor eax,eax
mov ecx,SEGMENT_HEADER_LENGTH shr 2
rep stosd
mov eax,20202020h
mov ecx,SEGMENT_DATA_LENGTH shr 2
rep stosd
call allocate_segment
jc memory_shortage
mov [lengths_table],eax
mov edi,eax
xor eax,eax
mov ecx,SEGMENT_LENGTH shr 2
rep stosd
mov [caret_position],eax
mov [window_position],eax
mov [selection_line],eax
mov [undo_data],eax
mov [redo_data],eax
mov [search_data],eax
mov [editor_mode],eax
mov [unmodified_state],eax
clc
retn
memory_error:
stc
retn
reset_editor_memory:
mov esi,[editor_memory]
lea eax,[esi+SEGMENT_LENGTH]
mov [unallocated_segments],eax
mov [memory_search_segment],eax
lea eax,[esi+BLOCK_LENGTH]
mov [unallocated_segments_end],eax
mov [memory_search_block],eax
mov [released_segments],0
mov ebx,[esi]
release_blocks:
or ebx,ebx
jz release_done
push dword [ebx]
mov ebx,[ebx+8]
call release_memory
pop ebx
jmp release_blocks
release_done:
mov ebx,[editor_memory]
xor eax,eax
mov [ebx],eax
mov [undo_data],eax
mov [redo_data],eax
mov [search_data],eax
call allocate_segment
jc memory_shortage
mov [first_line],eax
mov [window_line],eax
mov [caret_line],eax
mov edi,eax
xor eax,eax
mov ecx,SEGMENT_HEADER_LENGTH shr 2
rep stosd
mov eax,20202020h
mov ecx,SEGMENT_DATA_LENGTH shr 2
rep stosd
xor eax,eax
mov [selection_line],eax
mov [peak_line_length],eax
mov [window_position],eax
inc eax
mov [window_line_number],eax
mov [caret_line_number],eax
mov [lines_count],eax
call allocate_segment
jc memory_shortage
mov [lengths_table],eax
mov edi,eax
xor eax,eax
mov ecx,SEGMENT_LENGTH shr 2
rep stosd
retn
release_editor_memory:
mov esi,[editor_memory]
release:
push dword [esi]
mov ebx,[esi+8]
call release_memory
pop esi
or esi,esi
jnz release
mov [editor_memory],0
retn
allocate_segment:
mov eax,[unallocated_segments]
cmp eax,[unallocated_segments_end]
je simple_allocation_failed
add [unallocated_segments],SEGMENT_LENGTH
clc
retn
simple_allocation_failed:
push ebx esi
mov ebx,[memory_search_block]
mov esi,[memory_search_segment]
cmp [released_segments],16
jb add_new_block
find_free_segment:
cmp esi,ebx
je find_in_next_block
cmp dword [esi],-1
je reuse_segment
add esi,SEGMENT_LENGTH
cmp esi,[memory_search_segment]
jne find_free_segment
add_new_block:
sub ebx,BLOCK_LENGTH
find_last_memory_block:
cmp dword [ebx],0
je allocate_more_memory
mov ebx,[ebx]
jmp find_last_memory_block
allocate_more_memory:
mov ecx,BLOCK_LENGTH
push ebx
call get_memory
pop esi
or eax,eax
jz allocation_failed
mov [esi],eax
mov dword [eax],0
mov [eax+4],esi
mov [eax+8],ebx
lea ebx,[eax+BLOCK_LENGTH]
mov [unallocated_segments_end],ebx
add eax,SEGMENT_LENGTH
lea ebx,[eax+SEGMENT_LENGTH]
mov [unallocated_segments],ebx
mov [released_segments],0
pop esi ebx
clc
retn
allocation_failed:
xor eax,eax
pop esi ebx
stc
retn
reuse_segment:
mov eax,esi
mov [memory_search_block],ebx
add esi,SEGMENT_LENGTH
mov [memory_search_segment],esi
dec [released_segments]
pop esi ebx
clc
retn
find_in_next_block:
sub ebx,BLOCK_LENGTH
mov esi,[ebx]
lea ebx,[esi+BLOCK_LENGTH]
or esi,esi
jnz find_free_segment
mov ebx,[editor_memory]
mov esi,ebx
add ebx,BLOCK_LENGTH
jmp find_free_segment
memory_shortage:
call undo_changes
jmp not_enough_memory

View File

@@ -0,0 +1,511 @@
; flat editor core
; Copyright (c) 1999-2015, Tomasz Grysztar.
; All rights reserved.
find_line:
mov esi,[first_line]
mov ecx,1
mov edx,[window_line_number]
cmp eax,edx
jae forward_from_window
sub edx,eax
cmp edx,eax
jb backward_from_window
jmp find_forward
forward_from_window:
mov esi,[window_line]
mov ecx,edx
find_forward:
cmp ecx,eax
je line_found
cmp dword [esi],0
je line_found
mov ebx,esi
forward_skip_line:
mov ebx,[ebx]
btr ebx,0
jc forward_skip_line
or ebx,ebx
jz line_found
mov esi,ebx
inc ecx
jmp find_forward
backward_from_window:
mov esi,[window_line]
mov ecx,[window_line_number]
find_backward:
cmp ecx,eax
je line_found
cmp dword [esi+4],0
je line_found
mov esi,[esi+4]
dec ecx
jmp find_backward
line_found:
retn
get_caret_segment:
mov edx,[caret_position]
mov esi,[caret_line]
find_segment:
cmp edx,SEGMENT_DATA_LENGTH
jb segment_found
test byte [esi],1
jz segment_found
mov esi,[esi]
dec esi
sub edx,SEGMENT_DATA_LENGTH
jmp find_segment
segment_found:
retn
check_line_length:
xor edx,edx
mov ebx,esi
count_line_segments:
test byte [esi],1
jz last_line_segment
mov esi,[esi]
dec esi
add edx,SEGMENT_DATA_LENGTH
jmp count_line_segments
last_line_segment:
lea edi,[esi+SEGMENT_LENGTH-1]
mov al,20h
mov ecx,SEGMENT_DATA_LENGTH
std
repe scasb
cld
setne al
movzx eax,al
add ecx,eax
jnz line_segments_ok
or edx,edx
jz line_segments_ok
call store_freed_segment_for_undo
mov eax,[esi]
mov esi,[esi+4]
dec esi
call store_segment_for_undo
mov [esi],eax
sub edx,SEGMENT_DATA_LENGTH
jmp last_line_segment
line_segments_ok:
add ecx,edx
mov edx,ecx
cmp edx,[ebx+8]
je line_length_checked
mov esi,ebx
call store_segment_for_undo
xchg [ebx+8],edx
push edx
mov eax,[ebx+8]
call register_length
pop eax
call unregister_length
line_length_checked:
retn
register_length:
cmp eax,[peak_line_length]
jbe peak_length_ok
mov [peak_line_length],eax
peak_length_ok:
or eax,eax
jz ignore_zero_length
push ebx
call find_lengths_segment
inc dword [ebx+SEGMENT_HEADER_LENGTH+eax*4]
pop ebx
ignore_zero_length:
retn
find_lengths_segment:
mov ebx,[lengths_table]
try_lengths_segment:
cmp eax,SEGMENT_DATA_LENGTH/4
jb length_entry_ok
sub eax,SEGMENT_DATA_LENGTH/4
cmp dword [ebx],0
je add_lengths_segment
mov ebx,[ebx]
jmp try_lengths_segment
add_lengths_segment:
push eax ecx edi
call allocate_segment
jc memory_shortage
call store_allocated_segment_for_undo
mov [ebx],eax
mov edi,eax
xor eax,eax
stosd
mov eax,ebx
stosd
mov eax,[ebx+8]
add eax,SEGMENT_DATA_LENGTH/4
stosd
add edi,SEGMENT_HEADER_LENGTH-12
mov ecx,SEGMENT_DATA_LENGTH shr 2
xor eax,eax
rep stosd
lea ebx,[edi-SEGMENT_LENGTH]
pop edi ecx eax
jmp try_lengths_segment
length_entry_ok:
retn
unregister_length:
or eax,eax
jz ignore_zero_length
push ebx
cmp eax,[peak_line_length]
je unregister_peak_length
call find_lengths_segment
dec dword [ebx+SEGMENT_HEADER_LENGTH+eax*4]
length_unregistered:
pop ebx
retn
unregister_peak_length:
call find_lengths_segment
dec dword [ebx+SEGMENT_HEADER_LENGTH+eax*4]
jnz length_unregistered
find_reduced_peak:
or eax,eax
jz try_earlier_lengths_segment
dec eax
cmp dword [ebx+SEGMENT_HEADER_LENGTH+eax*4],0
je find_reduced_peak
add eax,[ebx+8]
mov [peak_line_length],eax
jmp length_unregistered
try_earlier_lengths_segment:
mov ebx,[ebx+4]
mov eax,SEGMENT_DATA_LENGTH/4
or ebx,ebx
jnz find_reduced_peak
mov [peak_line_length],ebx
jmp length_unregistered
update_window:
mov edx,[window_line_number]
cmp edx,1
je window_vertical_position_ok
add edx,[window_height]
dec edx
cmp edx,[lines_count]
jle window_vertical_position_ok
sub edx,[lines_count]
window_vertical_correction:
mov esi,[window_line]
mov esi,[esi+4]
or esi,esi
jz window_vertical_position_ok
mov [window_line],esi
dec [window_line_number]
dec edx
jnz window_vertical_correction
window_vertical_position_ok:
mov ecx,[peak_line_length]
cmp ecx,[caret_position]
jae caret_position_ok
mov ecx,[caret_position]
caret_position_ok:
cmp [selection_line],0
je selection_position_ok
cmp ecx,[selection_position]
jae selection_position_ok
mov ecx,[selection_position]
selection_position_ok:
mov eax,[window_width]
dec eax
cmp ecx,eax
jae edit_space_width_ok
mov ecx,eax
edit_space_width_ok:
mov [maximum_position],ecx
mov edx,[window_position]
or edx,edx
jz window_horizontal_position_ok
add edx,[window_width]
inc ecx
cmp edx,ecx
jbe window_horizontal_position_ok
sub edx,ecx
sub [window_position],edx
jnc window_horizontal_position_ok
mov [window_position],0
window_horizontal_position_ok:
retn
let_caret_appear:
mov eax,[caret_position]
cmp eax,[window_position]
jl horizontal_correction
mov ecx,[window_width]
jecxz last_position_ok
dec ecx
last_position_ok:
add ecx,[window_position]
mov eax,[caret_position]
sub eax,ecx
jbe horizontal_ok
add eax,[window_position]
horizontal_correction:
mov [window_position],eax
horizontal_ok:
mov esi,[caret_line]
mov ecx,[caret_line_number]
cmp ecx,[window_line_number]
jl vertical_correction
mov eax,[window_height]
or eax,eax
jz vertical_check
dec eax
vertical_check:
neg eax
add eax,[caret_line_number]
cmp [window_line_number],eax
jge vertical_ok
mov esi,[window_line]
mov ecx,[window_line_number]
vertical_find:
mov esi,[esi]
btr esi,0
jc vertical_find
inc ecx
cmp ecx,eax
jl vertical_find
vertical_correction:
mov [window_line],esi
mov [window_line_number],ecx
vertical_ok:
retn
move_line_up:
mov esi,[caret_line]
mov eax,[esi+4]
or eax,eax
jz cannot_move
mov [caret_line],eax
dec [caret_line_number]
clc
retn
cannot_move:
stc
retn
move_line_down:
mov esi,[caret_line]
find_next_line:
mov eax,[esi]
or eax,eax
jz cannot_move
btr eax,0
jnc down_ok
mov esi,eax
jmp find_next_line
down_ok:
mov [caret_line],eax
inc [caret_line_number]
clc
retn
move_page_up:
mov eax,[caret_line_number]
sub eax,[window_height]
ja pgup_caret_ok
mov eax,1
pgup_caret_ok:
call find_line
mov [caret_line],esi
mov [caret_line_number],ecx
mov eax,[window_line_number]
sub eax,[window_height]
ja pgup_window_ok
mov eax,1
cmp [window_line_number],eax
je moved_ok
pgup_window_ok:
call find_line
mov [window_line],esi
mov [window_line_number],ecx
retn
move_page_down:
mov eax,[caret_line_number]
add eax,[window_height]
call find_line
mov [caret_line],esi
mov [caret_line_number],ecx
mov eax,[window_line_number]
mov ecx,[window_height]
add eax,ecx
mov ebx,[lines_count]
sub ebx,ecx
jbe moved_ok
inc ebx
cmp eax,ebx
jb pgdn_window_ok
mov eax,ebx
cmp [window_line_number],eax
je moved_ok
pgdn_window_ok:
call find_line
mov [window_line],esi
mov [window_line_number],ecx
moved_ok:
retn
move_to_previous_word:
call get_caret_segment
mov ecx,[caret_position]
sub ecx,edx
cmp edx,SEGMENT_DATA_LENGTH
jbe find_word_to_the_left
mov edx,SEGMENT_DATA_LENGTH
find_word_to_the_left:
sub edx,1
jc word_in_previous_segment
mov al,[esi+SEGMENT_HEADER_LENGTH+edx]
call recognize_character
jnc find_word_start
jmp find_word_to_the_left
word_in_previous_segment:
mov eax,[esi+4]
or eax,eax
jz previous_word_ok
mov esi,eax
btr esi,0
jnc word_in_previous_line
mov edx,SEGMENT_DATA_LENGTH
sub ecx,edx
jmp find_word_to_the_left
word_in_previous_line:
mov [caret_line],esi
dec [caret_line_number]
mov edx,SEGMENT_DATA_LENGTH
xor ecx,ecx
find_last_segment:
test byte [esi],1
jz find_word_to_the_left
mov esi,[esi]
dec esi
add ecx,SEGMENT_DATA_LENGTH
jmp find_last_segment
find_word_start:
sub edx,1
jc word_on_segment_edge
mov al,[esi+SEGMENT_HEADER_LENGTH+edx]
call recognize_character
jc previous_word_ok
jmp find_word_start
word_on_segment_edge:
mov esi,[esi+4]
btr esi,0
jnc previous_word_ok
mov edx,SEGMENT_DATA_LENGTH
sub ecx,edx
jmp find_word_start
previous_word_ok:
add ecx,edx
inc ecx
mov [caret_position],ecx
retn
move_to_next_word:
mov ecx,[caret_position]
sub ecx,edx
find_word_end:
cmp edx,SEGMENT_DATA_LENGTH
jae word_wraps_segment_edge
mov al,[esi+SEGMENT_HEADER_LENGTH+edx]
call recognize_character
jc find_word_to_the_right
add edx,1
jmp find_word_end
word_wraps_segment_edge:
mov esi,[esi]
or esi,esi
jz move_to_line_end
btr esi,0
jnc word_in_next_line
add ecx,SEGMENT_DATA_LENGTH
sub edx,SEGMENT_DATA_LENGTH
jmp find_word_end
find_word_to_the_right:
cmp edx,SEGMENT_DATA_LENGTH
jae word_in_next_segment
mov al,[esi+SEGMENT_HEADER_LENGTH+edx]
call recognize_character
jnc next_word_ok
add edx,1
jmp find_word_to_the_right
word_in_next_segment:
mov esi,[esi]
or esi,esi
jz move_to_line_end
btr esi,0
jnc word_in_next_line
add ecx,SEGMENT_DATA_LENGTH
sub edx,SEGMENT_DATA_LENGTH
jmp find_word_to_the_right
word_in_next_line:
mov [caret_line],esi
inc [caret_line_number]
xor ecx,ecx
xor edx,edx
jmp find_word_to_the_right
next_word_ok:
add ecx,edx
mov [caret_position],ecx
retn
move_to_line_end:
mov esi,[caret_line]
mov eax,[esi+8]
mov [caret_position],eax
retn
get_word_at_caret:
call get_caret_segment
mov ebx,[caret_position]
sub ebx,edx
find_left_edge:
or edx,edx
jz left_edge_in_previous_segment
cmp edx,SEGMENT_DATA_LENGTH
ja left_edge_ok
mov al,[esi+SEGMENT_HEADER_LENGTH+edx-1]
call recognize_character
jc left_edge_ok
dec edx
jmp find_left_edge
left_edge_in_previous_segment:
mov esi,[esi+4]
btr esi,0
jnc left_edge_ok
mov edx,SEGMENT_DATA_LENGTH
sub ebx,edx
jmp find_left_edge
left_edge_ok:
add ebx,edx
call get_caret_segment
mov ecx,[caret_position]
sub ecx,edx
find_right_edge:
cmp edx,SEGMENT_DATA_LENGTH
jae right_edge_in_next_segment
mov al,[esi+SEGMENT_HEADER_LENGTH+edx]
call recognize_character
jc right_edge_ok
inc edx
jmp find_right_edge
right_edge_in_next_segment:
mov esi,[esi]
btr esi,0
jnc right_edge_ok
xor edx,edx
add ecx,SEGMENT_DATA_LENGTH
jmp find_right_edge
right_edge_ok:
add ecx,edx
sub ecx,ebx
mov edx,ebx
retn

View File

@@ -0,0 +1,529 @@
; flat editor core
; Copyright (c) 1999-2015, Tomasz Grysztar.
; All rights reserved.
find_first:
mov [search_flags],eax
call release_search_data
or esi,esi
jz nothing_to_search_for
mov edi,esi
xor al,al
xor ecx,ecx
sub ecx,edi
repne scasb
lea ebx,[edi-1]
sub ebx,esi
jz nothing_to_search_for
lea ecx,[(256+ebx)*4+ebx]
push ebx
call get_memory
or eax,eax
jz not_enough_memory
mov [search_data],eax
mov [search_handle],ebx
pop ebx
mov edi,eax
lea ecx,[256+ebx]
mov eax,ebx
rep stosd
mov ecx,ebx
mov ebx,[search_data]
mov edx,ecx
test [search_flags],FEFIND_BACKWARD
jnz text_for_backward_search
test [search_flags],FEFIND_CASESENSITIVE
jnz copy_search_text
push ebx
mov ebx,upper_case_table
convert_search_text:
lodsb
xlatb
stosb
loop convert_search_text
pop ebx
jmp make_character_shifts_table
copy_search_text:
rep movsb
jmp make_character_shifts_table
text_for_backward_search:
add edi,ecx
mov edx,ecx
push ebx
mov ebx,upper_case_table
reverse_search_text:
lodsb
test [search_flags],FEFIND_CASESENSITIVE
jnz reverse_store_character
xlatb
reverse_store_character:
dec edi
mov [edi],al
dec ecx
jnz reverse_search_text
pop ebx
add edi,edx
xor ecx,ecx
make_character_shifts_table:
cmp edx,ecx
je character_shifts_table_ok
dec edi
jecxz character_shift_ok
mov al,[edi]
cmp [ebx+eax*4],edx
jne character_shift_ok
mov [ebx+eax*4],ecx
character_shift_ok:
inc ecx
jmp make_character_shifts_table
character_shifts_table_ok:
lea edi,[ebx+(256+ecx)*4]
push edi
lea edi,[edi+ecx-2]
movzx eax,byte [edi+1]
mov edx,[ebx+eax*4]
mov [ebx+256*4],edx
cmp ecx,1
je suffix_match_shifts_table_done
mov ecx,2
mov esi,edi
sub esi,edx
make_suffix_match_shifts_table:
cmp esi,[esp]
jb store_suffix_match_shift
mov al,[esi]
cmp al,[edi]
je store_suffix_match_shift
find_suffix_match:
dec esi
inc edx
cmp esi,[esp]
jb match_part_of_suffix
push ecx esi edi
repe cmpsb
pop edi esi ecx
jne find_suffix_match
jmp store_suffix_match_shift
match_part_of_suffix:
mov eax,[esp]
push ecx esi edi
xchg eax,esi
sub eax,esi
add ecx,eax
repe cmpsb
pop edi esi ecx
jne suffix_match_shifts_table_done
store_suffix_match_shift:
mov [ebx+256*4+(ecx-1)*4],edx
dec esi
dec edi
inc ecx
cmp ecx,[ebx]
jbe make_suffix_match_shifts_table
suffix_match_shifts_table_done:
pop eax
find_next:
mov edi,[search_data]
or edi,edi
jz nothing_to_search_for
push [caret_line]
push [caret_line_number]
push [caret_position]
push [selection_position]
test [search_flags],FEFIND_BACKWARD
jnz search_backward
test [search_flags],FEFIND_INWHOLETEXT
jz search_for_text
mov eax,[first_line]
mov [caret_line],eax
xor eax,eax
mov [caret_position],eax
inc eax
mov [caret_line_number],eax
search_for_text:
mov ecx,[edi]
dec ecx
add ecx,[caret_position]
mov esi,[caret_line]
cmp ecx,[peak_line_length]
jae text_not_in_this_line
mov [caret_position],ecx
call get_caret_segment
mov edi,[search_data]
mov eax,[edi]
lea ebx,[edi+(256+eax)*4]
mov ah,[ebx+eax-1]
mov ebx,upper_case_table
search_in_line:
cmp edx,SEGMENT_DATA_LENGTH
jae text_not_in_this_line
mov al,[esi+SEGMENT_HEADER_LENGTH+edx]
test [search_flags],FEFIND_CASESENSITIVE
jnz compare_last_character
xlatb
compare_last_character:
cmp al,ah
je partial_match
mismatch_shift:
movzx ecx,al
mov ecx,[edi+ecx*4]
shift_search_position:
add edx,ecx
add ecx,[caret_position]
cmp ecx,[peak_line_length]
jae text_not_in_this_line
mov [caret_position],ecx
check_search_position:
cmp edx,SEGMENT_DATA_LENGTH
jb search_in_line
mov ecx,[esi]
btr ecx,0
jnc search_in_line
sub edx,SEGMENT_DATA_LENGTH
mov esi,ecx
jmp check_search_position
partial_match:
mov ecx,[edi]
dec ecx
jz text_found
push edi
lea edi,[edi+(256+ecx+1)*4]
lea edi,[edi+ecx]
compare_text:
sub edx,1
jc compare_in_previous_segment
dec edi
mov al,20h
cmp edx,SEGMENT_DATA_LENGTH
jae compare_character
mov al,[esi+SEGMENT_HEADER_LENGTH+edx]
test [search_flags],FEFIND_CASESENSITIVE
jnz compare_character
xlatb
compare_character:
cmp al,[edi]
loope compare_text
pop edi
je text_found
neg ecx
add ecx,[edi]
dec ecx
add edx,ecx
mov ecx,[edi+(256+ecx-1)*4]
jmp shift_search_position
compare_in_previous_segment:
mov esi,[esi+4]
and esi,not 1
mov edx,SEGMENT_DATA_LENGTH
jmp compare_text
text_not_in_this_line:
mov esi,[esi]
or esi,esi
jz text_not_found
btr esi,0
jc text_not_in_this_line
search_in_next_line:
mov [caret_line],esi
inc [caret_line_number]
mov [caret_position],0
mov edi,[search_data]
jmp search_for_text
text_found:
mov eax,[caret_position]
inc eax
mov [selection_position],eax
sub eax,[edi]
mov [caret_position],eax
jz left_text_edge_ok
test [search_flags],FEFIND_WHOLEWORDS
jz left_text_edge_ok
mov edi,[search_data]
mov ecx,[edi]
mov al,[edi+(256+ecx)*4]
call recognize_character
jc left_text_edge_ok
dec [caret_position]
call get_caret_segment
inc [caret_position]
cmp edx,SEGMENT_DATA_LENGTH
jae left_text_edge_ok
mov al,[esi+SEGMENT_HEADER_LENGTH+edx]
call recognize_character
jnc found_not_acceptable
left_text_edge_ok:
mov eax,[caret_position]
xchg eax,[selection_position]
mov [caret_position],eax
mov edi,[search_data]
mov ecx,[edi]
lea edi,[edi+(256+ecx)*4]
mov al,[edi+ecx-1]
cmp al,20h
je right_text_edge_blank
test [search_flags],FEFIND_WHOLEWORDS
jz right_text_edge_ok
call recognize_character
jc right_text_edge_ok
call get_caret_segment
cmp edx,SEGMENT_DATA_LENGTH
jae right_text_edge_ok
mov al,[esi+SEGMENT_HEADER_LENGTH+edx]
call recognize_character
jc right_text_edge_ok
mov eax,[selection_position]
mov [caret_position],eax
found_not_acceptable:
mov edi,[search_data]
mov ecx,[edi]
mov eax,[edi+(256+ecx-1)*4]
add [caret_position],eax
jmp search_for_text
right_text_edge_blank:
call get_caret_segment
check_for_blank_end:
mov ecx,SEGMENT_DATA_LENGTH
sub ecx,edx
jz blank_end_next_segment
push edi
mov al,20h
lea edi,[esi+SEGMENT_HEADER_LENGTH+edx]
repe scasb
pop edi
jne right_text_edge_ok
blank_end_next_segment:
mov esi,[esi]
or esi,esi
jz text_not_found
btr esi,0
jnc search_in_next_line
xor edx,edx
jmp check_for_blank_end
right_text_edge_ok:
mov eax,[caret_line]
mov ecx,[caret_line_number]
mov [selection_line],eax
mov [selection_line_number],ecx
and [search_flags],not FEFIND_INWHOLETEXT
add esp,16
clc
retn
text_not_found:
pop [selection_position]
pop [caret_position]
pop [caret_line_number]
pop [caret_line]
nothing_to_search_for:
stc
retn
search_backward:
test [search_flags],FEFIND_INWHOLETEXT
jz backward_search_for_text
or eax,-1
call find_line
mov [caret_line],esi
mov [caret_line_number],ecx
call move_to_line_end
backward_search_for_text:
mov ecx,[caret_position]
sub ecx,1
jc backward_text_not_in_this_line
mov [caret_position],ecx
mov edi,[search_data]
mov eax,[edi]
mov al,[edi+(256+eax)*4]
cmp al,20h
jne backward_search_starting_position_ok
mov esi,[caret_line]
mov ecx,[esi+8]
mov edi,[search_data]
mov eax,[edi]
sub ecx,eax
jc backward_text_not_in_this_line
cmp ecx,[caret_position]
jae backward_search_starting_position_ok
mov [caret_position],ecx
backward_search_starting_position_ok:
call get_caret_segment
mov edi,[search_data]
mov eax,[edi]
lea ebx,[edi+(256+eax)*4]
mov ah,[ebx+eax-1]
mov ebx,upper_case_table
cmp edx,SEGMENT_DATA_LENGTH
jb backward_search_in_line
mov ecx,edx
sub ecx,SEGMENT_DATA_LENGTH-1
sub edx,ecx
sub [caret_position],ecx
backward_search_in_line:
mov al,[esi+SEGMENT_HEADER_LENGTH+edx]
test [search_flags],FEFIND_CASESENSITIVE
jnz compare_first_character
xlatb
compare_first_character:
cmp al,ah
je backward_partial_match
backward_mismatch_shift:
movzx ecx,al
mov ecx,[edi+ecx*4]
shift_backward_search_position:
sub edx,ecx
sub [caret_position],ecx
jc backward_text_not_in_this_line
check_backward_search_position:
cmp edx,0
jge backward_search_in_line
mov esi,[esi+4]
and esi,not 1
add edx,SEGMENT_DATA_LENGTH
jmp check_backward_search_position
backward_partial_match:
mov ecx,[edi]
dec ecx
jz backward_text_found
push edi
lea edi,[edi+(256+ecx+1)*4]
lea edi,[edi+ecx]
backward_compare_text:
inc edx
cmp edx,SEGMENT_DATA_LENGTH
jae compare_in_next_segment
dec edi
mov al,[esi+SEGMENT_HEADER_LENGTH+edx]
test [search_flags],FEFIND_CASESENSITIVE
jnz backward_compare_character
xlatb
backward_compare_character:
cmp al,[edi]
loope backward_compare_text
pop edi
je backward_text_found
neg ecx
add ecx,[edi]
dec ecx
sub edx,ecx
mov ecx,[edi+(256+ecx)*4]
jmp shift_backward_search_position
compare_in_next_segment:
sub edx,SEGMENT_DATA_LENGTH
mov esi,[esi]
btr esi,0
jnc compare_blank_space
dec edx
jmp backward_compare_text
compare_blank_space:
pop edi
cmp ecx,[edi]
jbe backward_text_found
backward_text_not_in_this_line:
mov esi,[caret_line]
mov esi,[esi+4]
or esi,esi
jz text_not_found
mov [caret_line],esi
dec [caret_line_number]
mov ecx,[peak_line_length]
mov [caret_position],ecx
jmp backward_search_for_text
backward_text_found:
test [search_flags],FEFIND_WHOLEWORDS
jz backward_left_text_edge_ok
cmp [caret_position],0
je backward_left_text_edge_ok
mov edi,[search_data]
mov ecx,[edi]
lea edi,[edi+(256+ecx)*4]
mov al,[edi+ecx-1]
call recognize_character
jc backward_left_text_edge_ok
dec [caret_position]
call get_caret_segment
inc [caret_position]
cmp edx,SEGMENT_DATA_LENGTH
jae backward_left_text_edge_ok
mov al,[esi+SEGMENT_HEADER_LENGTH+edx]
call recognize_character
jnc backward_found_not_acceptable
backward_left_text_edge_ok:
mov eax,[caret_position]
mov [selection_position],eax
mov edi,[search_data]
mov ecx,[edi]
add eax,ecx
mov [caret_position],eax
test [search_flags],FEFIND_WHOLEWORDS
jz backward_right_text_edge_ok
mov al,[edi+(256+ecx)*4]
call recognize_character
jc backward_right_text_edge_ok
call get_caret_segment
cmp edx,SEGMENT_DATA_LENGTH
jae backward_right_text_edge_ok
mov al,[esi+SEGMENT_HEADER_LENGTH+edx]
call recognize_character
jc backward_right_text_edge_ok
mov eax,[selection_position]
mov [caret_position],eax
backward_found_not_acceptable:
mov edi,[search_data]
mov ecx,[edi]
mov eax,[edi+(256+ecx-1)*4]
sub [caret_position],eax
jbe backward_text_not_in_this_line
jmp backward_search_for_text
backward_right_text_edge_ok:
mov eax,[caret_position]
xchg eax,[selection_position]
mov [caret_position],eax
mov eax,[caret_line]
mov ecx,[caret_line_number]
mov [selection_line],eax
mov [selection_line_number],ecx
and [search_flags],not FEFIND_INWHOLETEXT
add esp,16
clc
retn
get_search_text_length:
mov ecx,[search_data]
test ecx,ecx
jz no_search_text
mov ecx,[ecx]
clc
retn
get_search_text:
mov esi,[search_data]
test esi,esi
jz no_search_text
mov ecx,[esi]
lea esi,[esi+(256+ecx)*4]
test [search_flags],FEFIND_BACKWARD
jnz copy_inverted_text
rep movsb
xor al,al
stosb
clc
retn
copy_inverted_text:
mov al,[esi+ecx-1]
stosb
loop copy_inverted_text
xor al,al
stosb
clc
retn
no_search_text:
stc
retn
release_search_data:
mov edi,[search_data]
test edi,edi
jz search_data_released
mov ebx,[search_handle]
call release_memory
mov [search_data],0
search_data_released:
retn

View File

@@ -0,0 +1,339 @@
; flat editor core
; Copyright (c) 1999-2015, Tomasz Grysztar.
; All rights reserved.
store_status_for_undo:
pusha
test [editor_mode],FEMODE_NOUNDO
jnz undo_disabled
call clear_redo_data
call allocate_segment
jc not_enough_memory
mov dword [eax],0
mov edi,eax
xchg eax,[undo_data]
push eax edi
call allocate_segment
pop edi
jnc store_editor_status
xor eax,eax
stosd
jmp not_enough_memory
store_editor_status:
mov dword [eax],0
mov dword [eax+4],0
stosd
pop eax
stosd
lea esi,[editor_status]
mov ecx,editor_status_size shr 2
rep movsd
mov esi,[lengths_table]
store_lengths_table:
call store_segment_for_undo
mov esi,[esi]
or esi,esi
jnz store_lengths_table
popa
store_status_for_undo_ok:
retn
undo_disabled:
call clear_redo_data
call clear_undo_data
or [unmodified_state],-1
popa
retn
store_segment_for_undo:
pusha
or esi,esi
jz segment_for_undo_done
call clear_redo_data
mov esi,[undo_data]
or esi,esi
jz segment_for_undo_done
mov ebx,[esi]
mov eax,[esp+4]
call prepare_slot_for_undo_storage
jc segment_for_undo_done
push edi
call allocate_segment
pop edi
mov ebx,eax
stosd
mov eax,[esp+4]
stosd
jc memory_shortage
mov esi,eax
mov edi,ebx
mov ecx,SEGMENT_LENGTH shr 2
rep movsd
segment_for_undo_done:
popa
store_segment_for_undo_ok:
retn
prepare_slot_for_undo_storage:
mov esi,[undo_data]
mov esi,[esi]
mov ecx,[esi+4]
lea edi,[esi+8]
repne scasd
jne get_free_slot
stc
retn
get_free_slot:
mov ecx,[esi+4]
lea edi,[esi+8+ecx*8]
inc ecx
cmp ecx,SEGMENT_DATA_LENGTH/8
jbe slot_ok
push esi
call allocate_segment
jc memory_shortage
mov esi,eax
mov ebx,[undo_data]
mov [ebx],esi
pop dword [esi]
mov ecx,1
lea edi,[esi+8]
slot_ok:
mov [esi+4],ecx
clc
retn
store_allocated_segment_for_undo:
pusha
call clear_redo_data
mov eax,[esp+1Ch]
xor edx,edx
mov [eax],edx
mov esi,[undo_data]
or esi,esi
jz segment_for_undo_done
call prepare_slot_for_undo_storage
jc segment_for_undo_done
xor eax,eax
stosd
mov eax,[esp+1Ch]
stosd
popa
retn
store_freed_segment_for_undo:
pusha
call clear_redo_data
mov esi,[undo_data]
or esi,esi
jz segment_for_undo_done
call prepare_slot_for_undo_storage
jc segment_for_undo_done
mov eax,[esp+4]
stosd
xor eax,eax
stosd
popa
retn
undo_changes:
mov esi,[undo_data]
or esi,esi
jz undo_ok
mov ebx,[esi]
mov eax,[redo_data]
xchg eax,[esi+4]
mov [undo_data],eax
mov [redo_data],esi
add esi,8
lea edi,[editor_status]
mov ecx,editor_status_size shr 2
call exchange_data
xor edx,edx
segments_block:
or ebx,ebx
jz undo_finished
mov esi,ebx
xchg ebx,edx
xchg ebx,[esi]
add esi,4
lodsd
mov ecx,eax
jecxz undo_finished
lea esi,[esi+ecx*8]
restore_segments:
sub esi,8
push esi ecx
mov edi,[esi+4]
mov esi,[esi]
or edi,edi
jz restore_next
or esi,esi
jz restore_next
mov ecx,SEGMENT_LENGTH shr 2
call exchange_data
restore_next:
pop ecx esi
loop restore_segments
jmp segments_block
undo_finished:
mov esi,[redo_data]
mov [esi],edx
undo_ok:
retn
exchange_data:
mov eax,[esi]
xchg eax,[edi]
mov [esi],eax
add esi,4
add edi,4
loop exchange_data
retn
redo_changes:
mov esi,[redo_data]
or esi,esi
jz redo_ok
mov ebx,[esi]
mov eax,[undo_data]
xchg eax,[esi+4]
mov [redo_data],eax
mov [undo_data],esi
add esi,8
lea edi,[editor_status]
mov ecx,editor_status_size shr 2
call exchange_data
xor edx,edx
redo_segments_block:
or ebx,ebx
jz redo_finished
mov esi,ebx
xchg ebx,edx
xchg ebx,[esi]
add esi,4
lodsd
mov ecx,eax
jecxz redo_finished
redo_segments:
push esi ecx
mov edi,[esi+4]
mov esi,[esi]
or edi,edi
jz redo_next
or esi,esi
jz redo_next
mov ecx,SEGMENT_LENGTH shr 2
call exchange_data
redo_next:
pop ecx esi
add esi,8
loop redo_segments
jmp redo_segments_block
redo_finished:
mov esi,[undo_data]
mov [esi],edx
redo_ok:
retn
clear_redo_data:
mov esi,[redo_data]
or esi,esi
jz redo_data_ok
clear_redo_block:
or ebx,-1
xchg ebx,[esi]
inc [released_segments]
mov eax,[esi+4]
mov [redo_data],eax
clear_redo_segments:
or ebx,ebx
jz next_redo_block
mov esi,ebx
or ebx,-1
xchg ebx,[esi]
inc [released_segments]
add esi,4
lodsd
mov ecx,eax
jecxz next_redo_block
release_redo_segments:
push esi ecx
mov edi,[esi+4]
mov esi,[esi]
or edi,edi
jz release_next_segment
or eax,-1
or esi,esi
jnz release_data
xchg eax,[edi]
jmp data_released
release_data:
xchg eax,[esi]
data_released:
cmp eax,-1
je release_next_segment
inc [released_segments]
release_next_segment:
pop ecx esi
add esi,8
loop release_redo_segments
jmp clear_redo_segments
next_redo_block:
mov esi,[redo_data]
or esi,esi
je redo_data_ok
cmp esi,[unmodified_state]
jne clear_redo_block
mov [unmodified_state],-1
jmp clear_redo_block
redo_data_ok:
retn
clear_undo_data:
mov esi,[undo_data]
push esi
clear_undo_block:
or esi,esi
jz undo_data_ok
or ebx,-1
xchg ebx,[esi]
inc [released_segments]
add esi,4
lodsd
mov [undo_data],eax
clear_undo_segments:
or ebx,ebx
jz next_undo_block
mov esi,ebx
or ebx,-1
xchg ebx,[esi]
inc [released_segments]
add esi,4
lodsd
mov ecx,eax
jecxz next_undo_block
lea esi,[esi+ecx*8]
release_segments:
sub esi,8
mov edx,[esi]
or edx,edx
jz release_next
or eax,-1
xchg [edx],eax
cmp eax,-1
je release_next
inc [released_segments]
release_next:
loop release_segments
next_undo_block:
mov esi,[undo_data]
cmp esi,[unmodified_state]
jne clear_undo_block
or [unmodified_state],-1
jmp clear_undo_block
undo_data_ok:
pop esi
cmp esi,[unmodified_state]
jne unmodified_ok
mov [unmodified_state],0
unmodified_ok:
retn

View File

@@ -0,0 +1,40 @@
; flat editor core
; Copyright (c) 1999-2015, Tomasz Grysztar.
; All rights reserved.
editor_memory dd ?
label editor_status
first_line dd ?
lines_count dd ?
peak_line_length dd ?
maximum_position dd ?
window_line dd ?
window_position dd ?
window_line_number dd ?
caret_line dd ?
caret_position dd ?
caret_line_number dd ?
selection_line dd ?
selection_position dd ?
selection_line_number dd ?
editor_mode dd ?
editor_status_size = $ - editor_status
window_width dd ?
window_height dd ?
unallocated_segments dd ?
unallocated_segments_end dd ?
released_segments dd ?
memory_search_block dd ?
memory_search_segment dd ?
lengths_table dd ?
undo_data dd ?
redo_data dd ?
search_data dd ?
search_flags dd ?
search_handle dd ?
unmodified_state dd ?

View File

@@ -0,0 +1,39 @@
; flat editor version 3.12
; Copyright (c) 1999-2015, Tomasz Grysztar.
; All rights reserved.
;
; This programs is free for commercial and non-commercial use as long as
; the following conditions are adhered to.
;
; Redistribution and use in source and binary forms, with or without
; modification, are permitted provided that the following conditions are
; met:
;
; 1. Redistributions of source code must retain the above copyright notice,
; this list of conditions and the following disclaimer.
; 2. Redistributions in binary form must reproduce the above copyright
; notice, this list of conditions and the following disclaimer in the
; documentation and/or other materials provided with the distribution.
;
; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
; TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
; PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
; EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
; PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
; LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
;
; The licence and distribution terms for any publically available
; version or derivative of this code cannot be changed. i.e. this code
; cannot simply be copied and put under another distribution licence
; (including the GNU Public Licence).
FEDIT_VERSION_STRING equ "3.12"
FEDIT_VERSION_MAJOR = 3
FEDIT_VERSION_MINOR = 12

View File

@@ -0,0 +1,504 @@
; flat assembler g interface for Windows IDE
; Copyright (c) 2014-2024, Tomasz Grysztar.
; All rights reserved.
flat_assembler:
mov esi,[esp+4]
mov [source_path],esi
mov [maximum_number_of_errors],MAX_ERRORS
xor al,al
call assembly_init
mov eax,[maximum_number_of_passes]
shl eax,16
invoke PostMessage,[hwnd_progress],PBM_SETRANGE,0,eax
invoke PostMessage,[hwnd_progress],PBM_SETPOS,0,0
invoke GetTickCount
mov [timer],eax
assemble:
mov esi,source_header
mov edx,[source_path]
call assembly_pass
jc assembly_done
mov ebx,[current_pass]
invoke PostMessage,[hwnd_progress],PBM_SETPOS,ebx,0
cmp ebx,[maximum_number_of_passes]
jb assemble
call show_display_data
cmp [first_error],0
jne assembly_failed
call assembly_shutdown
mov esi,_code_cannot_be_generated
jmp fatal_error
assembly_done:
call show_display_data
cmp [first_error],0
jne assembly_failed
mov [executable_path],0
mov ebx,[source_path]
mov edi,[output_path]
call write_output_file
jc write_failed
mov eax,[current_pass]
xor edx,edx
call itoa
call display_error_string
mov esi,_passes
cmp [current_pass],1
jne display_passes_suffix
mov esi,_pass
display_passes_suffix:
xor ecx,ecx
call display_error_string
invoke GetTickCount
sub eax,[timer]
xor edx,edx
add eax,50
mov ecx,1000
div ecx
mov ebx,eax
mov eax,edx
xor edx,edx
mov ecx,100
div ecx
mov [timer],eax
xchg eax,ebx
or ebx,eax
jz display_output_length
xor edx,edx
call itoa
call display_error_string
mov esi,_message_suffix
mov ecx,1
call display_error_string
mov eax,[timer]
xor edx,edx
call itoa
call display_error_string
mov esi,_seconds
xor ecx,ecx
call display_error_string
display_output_length:
call get_output_length
push eax edx
call itoa
call display_error_string
pop edx eax
mov esi,_bytes
cmp eax,1
jne display_bytes_suffix
test edx,edx
jnz display_bytes_suffix
mov esi,_byte
display_bytes_suffix:
xor ecx,ecx
call display_error_string
mov esi,_new_line
xor ecx,ecx
call display_error_string
summary_done:
call assembly_shutdown
xor eax,eax
jmp shutdown
assembly_failed:
mov ebx,[first_error]
collect_error:
call show_error_message
xor esi,esi
mov ecx,1
call display_error_string
mov esi,[ebx+Error.preprocessed_data]
mov ecx,[ebx+Error.preprocessed_length]
push ebx
call show_preprocessed_line
pop ebx
xor esi,esi
mov ecx,1
call display_error_string
mov eax,[ebx+sizeof.Error+SourceContext.number_of_entries]
test eax,eax
jz display_error_message
lea esi,[ebx+sizeof.Error+sizeof.SourceContext]
dec eax
imul eax,sizeof.SourceEntry
lea edi,[esi+eax]
push esi edi
lea esi,[edi+SourceEntry.type]
mov ecx,1
call display_error_string
pop edi esi
find_file_source:
cmp [edi+SourceEntry.type],SOURCE_FILE
jne try_next_source_entry
cmp [edi+SourceEntry.line_number],0
jne file_source_found
try_next_source_entry:
cmp edi,esi
je no_file_source
sub edi,sizeof.SourceEntry
jmp find_file_source
file_source_found:
lea esi,[edi+SourceEntry.line_number]
mov ecx,4
push edi
call display_error_string
pop edi
mov esi,[edi+SourceEntry.name]
call display_error_string
jmp error_collected
no_file_source:
xor esi,esi
mov ecx,4
call display_error_string
error_collected:
xor esi,esi
mov ecx,1
call display_error_string
mov ebx,[ebx+Error.next]
test ebx,ebx
jnz collect_error
call assembly_shutdown
mov eax,2
jmp shutdown
write_failed:
call assembly_shutdown
mov esi,_write_failed
jmp fatal_error
out_of_memory:
call assembly_shutdown
mov esi,_out_of_memory
fatal_error:
xor ecx,ecx
call display_error_string
mov eax,1
shutdown:
push eax
invoke PostMessage,[hwnd_compiler],WM_COMMAND,IDOK,0
call [ExitThread]
LINE_FEED equ 13,10
system_init:
invoke HeapCreate,0,20000h,0
mov [memory],eax
test eax,eax
jz out_of_memory
invoke GetSystemTime,systemtime
invoke SystemTimeToFileTime,systemtime,filetime
mov ebx,[filetime.dwLowDateTime]
mov eax,[filetime.dwHighDateTime]
sub ebx,116444736000000000 and 0FFFFFFFFh
sbb eax,116444736000000000 shr 32
xor edx,edx
mov ecx,10000000
div ecx
mov dword [timestamp+4],eax
mov eax,ebx
div ecx
mov dword [timestamp],eax
retn
system_shutdown:
cmp [memory],0
je memory_released
invoke HeapDestroy,[memory]
memory_released:
retn
malloc:
malloc_fixed:
malloc_growable:
; in: ecx = requested size
; out: eax - allocated block, ecx = allocated size, on error jumps to out_of_memory (does not return)
; preserves: ebx, esi, edi
; note:
; use of malloc_fixed hints that block will be kept as is until the end of assembly
; use of malloc_growable hints that block is likely to be resized
invoke HeapAlloc,[memory],0,ecx
test eax,eax
jz out_of_memory
memory_allocated:
push eax
invoke HeapSize,[memory],0,eax
mov ecx,eax
pop eax
cmp ecx,-1
je out_of_memory
retn
realloc:
; in: eax - memory block, ecx = requested size
; out: eax - resized block, ecx = allocated size, on error jumps to out_of_memory (does not return)
; preserves: ebx, esi, edi
invoke HeapReAlloc,[memory],0,eax,ecx
test eax,eax
jnz memory_allocated
jmp out_of_memory
mfree:
; in: eax - memory block
; out: cf set on error
; preserves: ebx, esi, edi
; note: eax may have value 0 or -1, it should be treated as invalid input then
test eax,eax
jz interface_error
cmp eax,-1
je interface_error
invoke HeapFree,[memory],0,eax
test eax,eax
jz interface_error
clc
retn
interface_error:
stc
retn
open:
; in: edx - path to file
; out: ebx = file handle, cf set on error
; preserves: esi, edi
mov ebx,edx
invoke WaitForSingleObject,[mutex],-1
invoke CreateFile,ebx,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0
cmp eax,-1
je release_mutex
mov ebx,eax
clc
retn
create:
; in: edx - path to file
; out: ebx = file handle, cf set on error
; preserves: esi, edi
cmp [executable_path],0
jne path_catching_done
push esi edi
mov esi,edx
mov edi,executable_path
catch_path:
lodsb
stosb
test al,al
jnz catch_path
pop edi esi
path_catching_done:
mov ebx,edx
invoke WaitForSingleObject,[mutex],-1
invoke CreateFile,ebx,GENERIC_WRITE,0,0,CREATE_ALWAYS,0,0
cmp eax,-1
je release_mutex
mov ebx,eax
clc
retn
write:
; in: ebx = file handle, edx - data, ecx = number of bytes
; out: cf set on error
; preserves: ebx, esi, edi
push ecx
invoke WriteFile,ebx,edx,ecx,systmp,0
pop ecx
test eax,eax
jz interface_error
cmp ecx,[systmp]
jne interface_error
clc
retn
read:
; in: ebx = file handle, edx - buffer, ecx = number of bytes
; out: cf set on error
; preserves: ebx, esi, edi
push ecx
invoke ReadFile,ebx,edx,ecx,systmp,0
pop ecx
test eax,eax
jz interface_error
cmp ecx,[systmp]
jne interface_error
clc
retn
close:
; in: ebx = file handle
; preserves: ebx, esi, edi
invoke CloseHandle,ebx
release_mutex:
invoke ReleaseMutex,[mutex] ; this relies on the fact that engine never opens more than one file at once
stc
retn
lseek:
; in: ebx = file handle, cl = method, edx:eax = offset
; out: edx:eax = new offset from the beginning of file, cf set on error
; preserves: ebx, esi, edi
movzx ecx,cl
mov [systmp],edx
invoke SetFilePointer,ebx,eax,systmp,ecx
cmp eax,-1
jne lseek_ok
invoke GetLastError
test eax,eax
jnz interface_error
not eax
lseek_ok:
mov edx,[systmp]
clc
retn
get_timestamp:
; out: edx:eax = timestamp
; preserves: ebx, ecx, esi, edi
; note: during the passes of a single assembly this function should always return the same value
mov eax,dword [timestamp]
mov edx,dword [timestamp+4]
retn
display_string:
; in:
; esi - string
; ecx = string length, zero for ASCIIZ string
; preserves: ebx, esi
push ebx
mov ebx,stdout
jmp write_string
display_error_string:
; in:
; esi - string
; ecx = string length, zero for ASCIIZ string
; preserves: ebx, esi
push ebx esi
mov ebx,stderr
write_string:
test ecx,ecx
jnz write_string_to_buffer
xor al,al
mov edi,esi
or ecx,-1
repne scasb
neg ecx
sub ecx,2
write_string_to_buffer:
mov edi,[ebx]
push ecx
invoke HeapSize,[hheap],0,dword [ebx]
mov edx,eax
sub eax,4
sub eax,[edi]
mov ecx,[esp]
sub ecx,eax
jb string_buffer_ready ; do not fit tight, leave room for terminating zero
add edx,ecx
inc edx
invoke HeapReAlloc,[hheap],0,dword [ebx],edx
test eax,eax
jz shutdown
mov [ebx],eax
mov edi,eax
string_buffer_ready:
pop ecx
mov eax,[edi]
add [edi],ecx
lea edi,[edi+4+eax]
xor al,al
test esi,esi
jz zero_string
rep movsb
stosb
pop esi ebx
retn
zero_string:
rep stosb
pop esi ebx
retn
get_environment_variable:
; in:
; esi - name
; edi - buffer for value
; ecx = size of buffer
; out:
; eax = length of value
; preserves: ebx, esi, edi
push ecx
invoke GetEnvironmentVariable,esi,string_buffer,1000h
invoke GetPrivateProfileString,_section_environment,esi,string_buffer,string_buffer,1000h,ini_path
mov ecx,[esp]
push esi edi
mov esi,string_buffer
copy_env_val:
lodsb
jecxz next_env_char
mov [edi],al
dec ecx
next_env_char:
inc edi
test al,al
jnz copy_env_val
mov eax,edi
pop edi esi ecx
sub eax,edi
retn
include '../../assembler.inc'
include '../../symbols.inc'
include '../../expressions.inc'
include '../../conditions.inc'
include '../../floats.inc'
include '../../directives.inc'
include '../../calm.inc'
include '../../errors.inc'
include '../../map.inc'
include '../../reader.inc'
include '../../output.inc'
include '../../console.inc'
section '.rdata' data readable
include '../../tables.inc'
include '../../messages.inc'
_pass db ' pass, ',0
_passes db ' passes, ',0
_dot db '.'
_seconds db ' seconds, ',0
_byte db ' byte.',0
_bytes db ' bytes.',0
_write_failed db 'Failed to write the output file.',0
_out_of_memory db 'Not enough memory to complete the assembly.',0
_code_cannot_be_generated db 'Could not generate code within the allowed number of passes.',0
version_string db VERSION,0
section '.bss' readable writeable
include '../../variables.inc'
source_string dd ?
source_path dd ?
output_path dd ?
maximum_number_of_passes dd ?
timestamp dq ?
systemtime SYSTEMTIME
filetime FILETIME
memory dd ?
systmp dd ?
timer dd ?
stdout dd ?
stderr dd ?

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,69 @@
; flat editor mode flags
FEMODE_OVERWRITE = 1
FEMODE_VERTICALSEL = 2
FEMODE_NOUNDO = 4
FEMODE_READONLY = 8
; flat editor search flags
FEFIND_CASESENSITIVE = 1
FEFIND_WHOLEWORDS = 2
FEFIND_BACKWARD = 4
FEFIND_INWHOLETEXT = 8
; flat editor styles
FES_AUTOINDENT = 0001h
FES_AUTOBRACKETS = 0002h
FES_SMARTTABS = 0004h
FES_SECURESEL = 0008h
FES_OPTIMALFILL = 0010h
FES_CONSOLECARET = 0020h
FES_REVIVEDEADKEYS = 0040h
FES_TIMESCROLL = 0080h
; flat editor messages
FEM_SETMODE = WM_USER + 0
FEM_GETMODE = WM_USER + 1
FEM_SETPOS = WM_USER + 2
FEM_GETPOS = WM_USER + 3
FEM_SETSYNTAXHIGHLIGHT = WM_USER + 4
FEM_SETRIGHTCLICKMENU = WM_USER + 5
FEM_SETTEXTCOLOR = WM_USER + 6
FEM_SETSELCOLOR = WM_USER + 7
FEM_FINDFIRST = WM_USER + 8
FEM_FINDNEXT = WM_USER + 9
FEM_CANFINDNEXT = WM_USER + 10
FEM_GETLINELENGTH = WM_USER + 11
FEM_GETLINE = WM_USER + 12
FEM_GETWORDATCARET = WM_USER + 13
FEM_BEGINOPERATION = WM_USER + 14
FEM_ENDOPERATION = WM_USER + 15
FEM_MARKUNMODIFIED = WM_USER + 16
FEM_ISUNMODIFIED = WM_USER + 17
FEM_GETSEARCHTEXT = WM_USER + 18
FEM_GETSEARCHFLAGS = WM_USER + 19
FEM_RELEASESEARCH = WM_USER + 20
FEM_REDO = WM_USER + 84
FEM_CANREDO = WM_USER + 85
; flat editor notifications
FEN_SETFOCUS = 01h
FEN_KILLFOCUS = 02h
FEN_TEXTCHANGE = 03h
FEN_POSCHANGE = 04h
FEN_MODECHANGE = 05h
FEN_OUTOFMEMORY = 0Fh
; flat editor position structure
struct FEPOS
selectionPosition dd ?
selectionLine dd ?
caretPosition dd ?
caretLine dd ?
ends

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

View File

@@ -0,0 +1,23 @@
macro ccall proc*,[arg]
{
common
local size,count
mov ebp,esp
if size
sub esp,size
end if
and esp,0FFFFFFF0h
count = 0
if ~ arg eq
forward
mov dword [esp+count*4],arg
count = count + 1
common
end if
size = count*4
call proc
mov esp,ebp
}
macro cinvoke proc*,arg& { ccall [proc],arg }

View File

@@ -0,0 +1,489 @@
format ELF
public main
include '../version.inc'
include 'macro/struct.inc'
include 'macro/proc32.inc'
extrn 'malloc' as libc.malloc
extrn 'realloc' as libc.realloc
extrn 'free' as libc.free
extrn 'fopen' as libc.fopen
extrn 'fclose' as libc.fclose
extrn 'fread' as libc.fread
extrn 'fwrite' as libc.fwrite
extrn 'fseek' as libc.fseek
extrn 'ftell' as libc.ftell
extrn 'time' as libc.time
extrn 'write' as libc.write
extrn getenv
extrn gettimeofday
extrn exit
struct timeval
time_t dd ?
suseconds_t dd ?
ends
section '.text' executable align 16
main:
mov ecx,[esp+4]
mov [argc],ecx
mov ebx,[esp+8]
mov [argv],ebx
call system_init
call get_arguments
mov bl,al
cmp [no_logo],0
jne logo_ok
mov esi,_logo
xor ecx,ecx
call display_string
logo_ok:
test bl,bl
jnz display_usage_information
xor al,al
mov ecx,[verbosity_level]
jecxz init
or al,TRACE_ERROR_STACK
dec ecx
jz init
or al,TRACE_DISPLAY
init:
call assembly_init
ccall gettimeofday,start_time,0
assemble:
mov esi,[initial_commands]
mov edx,[source_path]
call assembly_pass
jc assembly_done
mov eax,[current_pass]
cmp eax,[maximum_number_of_passes]
jb assemble
call show_display_data
mov esi,_error_prefix
xor ecx,ecx
call display_error_string
mov esi,_code_cannot_be_generated
xor ecx,ecx
call display_error_string
mov esi,_message_suffix
xor ecx,ecx
call display_error_string
jmp assembly_failed
assembly_done:
call show_display_data
cmp [first_error],0
jne assembly_failed
cmp [no_logo],0
jne summary_done
mov eax,[current_pass]
xor edx,edx
call itoa
call display_string
mov esi,_passes
cmp [current_pass],1
jne display_passes_suffix
mov esi,_pass
display_passes_suffix:
xor ecx,ecx
call display_string
ccall gettimeofday,end_time,0
mov eax,[end_time.time_t]
sub eax,[start_time.time_t]
mov ecx,1000000
mul ecx
add eax,[end_time.suseconds_t]
adc edx,0
sub eax,[start_time.suseconds_t]
sbb edx,0
add eax,50000
mov ecx,1000000
div ecx
mov ebx,eax
mov eax,edx
xor edx,edx
mov ecx,100000
div ecx
mov [tenths_of_second],eax
xchg eax,ebx
or ebx,eax
jz display_output_length
xor edx,edx
call itoa
call display_string
mov esi,_message_suffix
mov ecx,1
call display_string
mov eax,[tenths_of_second]
xor edx,edx
call itoa
call display_string
mov esi,_seconds
xor ecx,ecx
call display_string
display_output_length:
call get_output_length
push eax edx
call itoa
call display_string
pop edx eax
mov esi,_bytes
cmp eax,1
jne display_bytes_suffix
test edx,edx
jnz display_bytes_suffix
mov esi,_byte
display_bytes_suffix:
xor ecx,ecx
call display_string
mov esi,_new_line
xor ecx,ecx
call display_string
summary_done:
mov ebx,[source_path]
mov edi,[output_path]
call write_output_file
jc write_failed
call assembly_shutdown
call system_shutdown
ccall exit,0
assembly_failed:
call show_errors
call assembly_shutdown
call system_shutdown
ccall exit,2
write_failed:
mov ebx,_write_failed
jmp fatal_error
out_of_memory:
mov ebx,_out_of_memory
jmp fatal_error
fatal_error:
mov esi,_error_prefix
xor ecx,ecx
call display_error_string
mov esi,ebx
xor ecx,ecx
call display_error_string
mov esi,_message_suffix
xor ecx,ecx
call display_error_string
call assembly_shutdown
call system_shutdown
ccall exit,3
display_usage_information:
mov esi,_usage
xor ecx,ecx
call display_string
call system_shutdown
ccall exit,1
get_arguments:
xor eax,eax
mov [initial_commands],eax
mov [source_path],eax
mov [output_path],eax
mov [no_logo],al
mov [verbosity_level],eax
mov [maximum_number_of_passes],100
mov [maximum_number_of_errors],1
mov [maximum_depth_of_stack],10000
mov ecx,[argc]
mov ebx,[argv]
add ebx,4
dec ecx
jz error_in_arguments
get_argument:
mov esi,[ebx]
mov al,[esi]
cmp al,'-'
je get_option
cmp [source_path],0
jne get_output_file
mov [source_path],esi
jmp next_argument
get_output_file:
cmp [output_path],0
jne error_in_arguments
mov [output_path],esi
jmp next_argument
get_option:
inc esi
lodsb
cmp al,'e'
je set_errors_limit
cmp al,'E'
je set_errors_limit
cmp al,'i'
je insert_initial_command
cmp al,'I'
je insert_initial_command
cmp al,'p'
je set_passes_limit
cmp al,'P'
je set_passes_limit
cmp al,'r'
je set_recursion_limit
cmp al,'R'
je set_recursion_limit
cmp al,'v'
je set_verbose_mode
cmp al,'V'
je set_verbose_mode
cmp al,'n'
je set_no_logo
cmp al,'N'
jne error_in_arguments
set_no_logo:
or [no_logo],-1
cmp byte [esi],0
je next_argument
error_in_arguments:
or al,-1
ret
set_verbose_mode:
cmp byte [esi],0
jne get_verbose_setting
dec ecx
jz error_in_arguments
add ebx,4
mov esi,[ebx]
get_verbose_setting:
call get_option_value
cmp edx,2
ja error_in_arguments
mov [verbosity_level],edx
jmp next_argument
set_errors_limit:
cmp byte [esi],0
jne get_errors_setting
dec ecx
jz error_in_arguments
add ebx,4
mov esi,[ebx]
get_errors_setting:
call get_option_value
test edx,edx
jz error_in_arguments
mov [maximum_number_of_errors],edx
jmp next_argument
set_recursion_limit:
cmp byte [esi],0
jne get_recursion_setting
dec ecx
jz error_in_arguments
add ebx,4
mov esi,[ebx]
get_recursion_setting:
call get_option_value
test edx,edx
jz error_in_arguments
mov [maximum_depth_of_stack],edx
jmp next_argument
set_passes_limit:
cmp byte [esi],0
jne get_passes_setting
dec ecx
jz error_in_arguments
add ebx,4
mov esi,[ebx]
get_passes_setting:
call get_option_value
test edx,edx
jz error_in_arguments
mov [maximum_number_of_passes],edx
next_argument:
add ebx,4
dec ecx
jnz get_argument
cmp [source_path],0
je error_in_arguments
xor al,al
ret
get_option_value:
xor eax,eax
mov edx,eax
find_option_value:
cmp byte [esi],20h
jne get_option_digit
inc esi
jmp find_option_value
get_option_digit:
lodsb
test al,al
jz option_value_ok
sub al,30h
jc invalid_option_value
cmp al,9
ja invalid_option_value
imul edx,10
jo invalid_option_value
add edx,eax
jc invalid_option_value
jmp get_option_digit
option_value_ok:
dec esi
clc
ret
invalid_option_value:
stc
ret
insert_initial_command:
cmp byte [esi],0
jne measure_initial_command
dec ecx
jz error_in_arguments
add ebx,4
mov esi,[ebx]
measure_initial_command:
push ebx ecx edi
mov edi,esi
or ecx,-1
xor al,al
repne scasb
not ecx
dec ecx
mov edi,[initial_commands]
lea eax,[ecx+2]
test edi,edi
jz allocate_initial_commands_buffer
mov edx,[initial_commands_length]
add edi,edx
add eax,edx
cmp eax,[initial_commands_maximum_length]
ja grow_initial_commands_buffer
copy_initial_command:
rep movsb
mov ax,0Ah
stosw
dec edi
sub edi,[initial_commands]
mov [initial_commands_length],edi
pop edi ecx ebx
jmp next_argument
allocate_initial_commands_buffer:
push ecx
mov ecx,eax
call malloc
mov [initial_commands],eax
mov [initial_commands_maximum_length],ecx
mov edi,eax
pop ecx
jmp copy_initial_command
grow_initial_commands_buffer:
push ecx
mov ecx,eax
mov eax,[initial_commands]
call realloc
mov [initial_commands],eax
mov [initial_commands_maximum_length],ecx
mov edi,eax
add edi,[initial_commands_length]
pop ecx
jmp copy_initial_command
include 'system.inc'
include '../assembler.inc'
include '../symbols.inc'
include '../expressions.inc'
include '../conditions.inc'
include '../floats.inc'
include '../directives.inc'
include '../calm.inc'
include '../errors.inc'
include '../map.inc'
include '../reader.inc'
include '../output.inc'
include '../console.inc'
section '.data'
_logo db 'flat assembler version g.',VERSION,10,0
_usage db 'Usage: fasmg source [output]',10
db 'Optional settings:',10
db ' -p limit Set the maximum allowed number of passes (default 100)',10
db ' -e limit Set the maximum number of displayed errors (default 1)',10
db ' -r limit Set the maximum depth of the stack (default 10000)',10
db ' -v flag Enable or disable showing all lines from the stack (default 0)',10
db ' -i command Insert instruction at the beginning of source',13,10
db ' -n Do not show logo nor summary',13,10
db 0
_pass db ' pass, ',0
_passes db ' passes, ',0
_dot db '.'
_seconds db ' seconds, ',0
_byte db ' byte.',0
_bytes db ' bytes.',0
_write_failed db 'failed to write the output file',0
_out_of_memory db 'not enough memory to complete the assembly',0
_code_cannot_be_generated db 'could not generate code within the allowed number of passes',0
_open_mode db 'r',0
_create_mode db 'w',0
include '../tables.inc'
include '../messages.inc'
section '.bss' writeable align 4
include '../variables.inc'
source_path dd ?
output_path dd ?
maximum_number_of_passes dd ?
initial_commands dd ?
initial_commands_length dd ?
initial_commands_maximum_length dd ?
argc dd ?
argv dd ?
timestamp dq ?
start_time timeval
end_time timeval
tenths_of_second dd ?
verbosity_level dd ?
no_logo db ?
path_buffer rb 1000h

View File

@@ -0,0 +1,60 @@
include '../../examples/x86/include/80386.inc'
macro format?.ELF? variant
match , variant
format binary as 'o'
include '../../examples/x86/include/format/elf32.inc'
use32
else match =executable? settings, variant:
match brand =at? base:, settings
ELF.Settings.ABI = brand
ELF.Settings.BaseAddress = base
else match =at? base:, settings
ELF.Settings.BaseAddress = base
else match brand:, settings
ELF.Settings.ABI = brand
end match
include '../../examples/x86/include/format/elfexe.inc'
use32
else
err 'invalid argument'
end match
end macro
macro struct? name
macro ends?!
end namespace
esc end struc
virtual at 0
name name
sizeof.name = $
end virtual
purge ends?
end macro
esc struc name
label . : sizeof.name
namespace .
end macro
macro ccall? proc*,args&
local size
mov ebp,esp
if size
sub esp,size
end if
and esp,0FFFFFFF0h
match any, args
iterate arg, args
mov dword [esp+(%-1)*4],arg
if % = 1
size := %%*4
end if
end iterate
else
size := 0
end match
call proc
mov esp,ebp
end macro

View File

@@ -0,0 +1,17 @@
macro struct name*
{
local body
define body struc name \{
irp d, db,rb,dw,rw,dd,rd,dq,rq \{ struc d value& \\{ define body \\\.\\#. d value \\} \}
macro ends
\{
define body \\}
irp d, db,rb,dw,rw,dd,rd,dq,rq \\{ restruc d \\}
irpv line, body \\{ line \\}
virtual at 0
name name
sizeof.#name = $
end virtual
\}
}

View File

@@ -0,0 +1,225 @@
LINE_FEED = 0Ah
system_init:
ccall libc.time,timestamp
retn
system_shutdown:
retn
malloc:
malloc_fixed:
malloc_growable:
; in: ecx = requested size
; out: eax - allocated block, ecx = allocated size, on error jumps to out_of_memory (does not return)
; preserves: ebx, esi, edi
; note:
; use of malloc_fixed hints that block will be kept as is until the end of assembly
; use of malloc_growable hints that block is likely to be resized
push ebx ecx esi edi
ccall libc.malloc,ecx
pop edi esi ecx ebx
test eax,eax
jz out_of_memory
retn
realloc:
; in: eax - memory block, ecx = requested size
; out: eax - resized block, ecx = allocated size, on error jumps to out_of_memory (does not return)
; preserves: ebx, esi, edi
push ebx ecx esi edi
ccall libc.realloc,eax,ecx
pop edi esi ecx ebx
test eax,eax
jz out_of_memory
retn
mfree:
; in: eax - memory block
; out: cf set on error
; preserves: ebx, esi, edi
; note: eax may have value 0 or -1, it should be treated as invalid input then
test eax,eax
jz interface_error
cmp eax,-1
je interface_error
push ebx esi edi
ccall libc.free,eax
pop edi esi ebx
clc
retn
interface_error:
stc
retn
open:
; in: edx - path to file
; out: ebx = file handle, cf set on error
; preserves: esi, edi
push esi edi
call adapt_path
ccall libc.fopen,ebx,_open_mode
pop edi esi
test eax,eax
jz interface_error
mov ebx,eax
clc
retn
adapt_path:
xor ecx,ecx
mov ebx,path_buffer
copy_path:
mov al,[edx+ecx]
cmp al,'\'
jne path_char_ok
mov al,'/'
path_char_ok:
cmp ecx,1000h
jae out_of_memory
mov [ebx+ecx],al
inc ecx
test al,al
jnz copy_path
retn
create:
; in: edx - path to file
; out: ebx = file handle, cf set on error
; preserves: esi, edi
push esi edi
call adapt_path
ccall libc.fopen,ebx,_create_mode
pop edi esi
test eax,eax
jz interface_error
mov ebx,eax
clc
retn
write:
; in: ebx = file handle, edx - data, ecx = number of bytes
; out: cf set on error
; preserves: ebx, esi, edi
push ebx ecx esi edi
ccall libc.fwrite,edx,1,ecx,ebx
pop edi esi ecx ebx
cmp eax,ecx
jne interface_error
clc
ret
read:
; in: ebx = file handle, edx - buffer, ecx = number of bytes
; out: cf set on error
; preserves: ebx, esi, edi
push ebx ecx esi edi
ccall libc.fread,edx,1,ecx,ebx
pop edi esi ecx ebx
cmp eax,ecx
jne interface_error
clc
ret
close:
; in: ebx = file handle
; preserves: ebx, esi, edi
ccall libc.fclose,ebx
ret
lseek:
; in: ebx = file handle, cl = method, edx:eax = offset
; out: edx:eax = new offset from the beginning of file, cf set on error
; preserves: ebx, esi, edi
test edx,edx
jnz interface_error
push esi edi ebx
movzx ecx,cl
ccall libc.fseek,ebx,eax,ecx
test eax,eax
jnz lseek_error
mov ebx,[esp]
ccall libc.ftell,ebx
cmp eax,-1
je lseek_error
xor edx,edx
pop ebx edi esi
clc
ret
lseek_error:
pop ebx edi esi
stc
ret
get_timestamp:
; out: edx:eax = timestamp
; preserves: ebx, ecx, esi, edi
; note: during the passes of a single assembly this function should always return the same value
mov eax,dword [timestamp]
mov edx,dword [timestamp+4]
retn
display_string:
; in:
; esi - string
; ecx = string length, zero for ASCIIZ string
; preserves: ebx, esi
push ebx esi
test ecx,ecx
jnz write_string_to_stdout
xor al,al
mov edi,esi
or ecx,-1
repne scasb
neg ecx
sub ecx,2
write_string_to_stdout:
ccall libc.write,1,esi,ecx
pop esi ebx
retn
display_error_string:
; in:
; esi - string
; ecx = string length, zero for ASCIIZ string
; preserves: ebx, esi
push ebx esi
test ecx,ecx
jnz write_string_to_stderr
xor al,al
mov edi,esi
or ecx,-1
repne scasb
neg ecx
sub ecx,2
write_string_to_stderr:
ccall libc.write,2,esi,ecx
pop esi ebx
retn
get_environment_variable:
; in:
; esi - name
; edi - buffer for value
; ecx = size of buffer
; out:
; eax = length of value
; preserves: ebx, esi, edi
push ebx ecx esi edi
ccall getenv,esi
pop edi esi ecx ebx
test eax,eax
jz no_environment_variable
push esi
mov esi,eax
xor eax,eax
copy_environment_variable:
mov dl,[esi+eax]
cmp eax,ecx
jae next_environment_variable_character
mov [edi+eax],dl
next_environment_variable_character:
inc eax
test dl,dl
jnz copy_environment_variable
pop esi
environment_variable_ok:
ret
no_environment_variable:
mov eax,1
jecxz environment_variable_ok
and byte [edi],0
ret

View File

@@ -0,0 +1,503 @@
include 'macro/struct.inc'
format ELF executable 3
entry start
include '../version.inc'
struct timeval
time_t dd ?
suseconds_t dd ?
ends
segment readable executable
start:
mov ecx,[esp]
mov [argc],ecx
lea ebx,[esp+4]
mov [argv],ebx
lea esi,[esp+4+ecx*4+4]
mov [env],esi
call system_init
call get_arguments
mov bl,al
cmp [no_logo],0
jne logo_ok
mov esi,_logo
xor ecx,ecx
call display_string
logo_ok:
test bl,bl
jnz display_usage_information
xor al,al
mov ecx,[verbosity_level]
jecxz init
or al,TRACE_ERROR_STACK
dec ecx
jz init
or al,TRACE_DISPLAY
init:
call assembly_init
mov eax,78 ; sys_gettimeofday
mov ebx,start_time
xor ecx,ecx
int 0x80
assemble:
mov esi,[initial_commands]
mov edx,[source_path]
call assembly_pass
jc assembly_done
mov eax,[current_pass]
cmp eax,[maximum_number_of_passes]
jb assemble
call show_display_data
mov esi,_error_prefix
xor ecx,ecx
call display_error_string
mov esi,_code_cannot_be_generated
xor ecx,ecx
call display_error_string
mov esi,_message_suffix
xor ecx,ecx
call display_error_string
jmp assembly_failed
assembly_done:
call show_display_data
cmp [first_error],0
jne assembly_failed
cmp [no_logo],0
jne summary_done
mov eax,[current_pass]
xor edx,edx
call itoa
call display_string
mov esi,_passes
cmp [current_pass],1
jne display_passes_suffix
mov esi,_pass
display_passes_suffix:
xor ecx,ecx
call display_string
mov eax,78 ; sys_gettimeofday
mov ebx,end_time
xor ecx,ecx
int 0x80
mov eax,[end_time.time_t]
sub eax,[start_time.time_t]
mov ecx,1000000
mul ecx
add eax,[end_time.suseconds_t]
adc edx,0
sub eax,[start_time.suseconds_t]
sbb edx,0
add eax,50000
mov ecx,1000000
div ecx
mov ebx,eax
mov eax,edx
xor edx,edx
mov ecx,100000
div ecx
mov [tenths_of_second],eax
xchg eax,ebx
or ebx,eax
jz display_output_length
xor edx,edx
call itoa
call display_string
mov esi,_message_suffix
mov ecx,1
call display_string
mov eax,[tenths_of_second]
xor edx,edx
call itoa
call display_string
mov esi,_seconds
xor ecx,ecx
call display_string
display_output_length:
call get_output_length
push eax edx
call itoa
call display_string
pop edx eax
mov esi,_bytes
cmp eax,1
jne display_bytes_suffix
test edx,edx
jnz display_bytes_suffix
mov esi,_byte
display_bytes_suffix:
xor ecx,ecx
call display_string
mov esi,_new_line
xor ecx,ecx
call display_string
summary_done:
mov ebx,[source_path]
mov edi,[output_path]
call write_output_file
jc write_failed
call assembly_shutdown
call system_shutdown
xor ebx,ebx
mov eax,1 ; sys_exit
int 0x80
assembly_failed:
call show_errors
call assembly_shutdown
call system_shutdown
mov ebx,2
mov eax,1 ; sys_exit
int 0x80
write_failed:
mov ebx,_write_failed
jmp fatal_error
out_of_memory:
mov ebx,_out_of_memory
jmp fatal_error
fatal_error:
mov esi,_error_prefix
xor ecx,ecx
call display_error_string
mov esi,ebx
xor ecx,ecx
call display_error_string
mov esi,_message_suffix
xor ecx,ecx
call display_error_string
call assembly_shutdown
call system_shutdown
mov ebx,3
mov eax,1 ; sys_exit
int 0x80
display_usage_information:
mov esi,_usage
xor ecx,ecx
call display_string
call system_shutdown
mov ebx,1
mov eax,1 ; sys_exit
int 0x80
get_arguments:
xor eax,eax
mov [initial_commands],eax
mov [source_path],eax
mov [output_path],eax
mov [no_logo],al
mov [verbosity_level],eax
mov [maximum_number_of_passes],100
mov [maximum_number_of_errors],1
mov [maximum_depth_of_stack],10000
mov ecx,[argc]
mov ebx,[argv]
add ebx,4
dec ecx
jz error_in_arguments
get_argument:
mov esi,[ebx]
mov al,[esi]
cmp al,'-'
je get_option
cmp [source_path],0
jne get_output_file
mov [source_path],esi
jmp next_argument
get_output_file:
cmp [output_path],0
jne error_in_arguments
mov [output_path],esi
jmp next_argument
get_option:
inc esi
lodsb
cmp al,'e'
je set_errors_limit
cmp al,'E'
je set_errors_limit
cmp al,'i'
je insert_initial_command
cmp al,'I'
je insert_initial_command
cmp al,'p'
je set_passes_limit
cmp al,'P'
je set_passes_limit
cmp al,'r'
je set_recursion_limit
cmp al,'R'
je set_recursion_limit
cmp al,'v'
je set_verbose_mode
cmp al,'V'
je set_verbose_mode
cmp al,'n'
je set_no_logo
cmp al,'N'
jne error_in_arguments
set_no_logo:
or [no_logo],-1
cmp byte [esi],0
je next_argument
error_in_arguments:
or al,-1
ret
set_verbose_mode:
cmp byte [esi],0
jne get_verbose_setting
dec ecx
jz error_in_arguments
add ebx,4
mov esi,[ebx]
get_verbose_setting:
call get_option_value
cmp edx,2
ja error_in_arguments
mov [verbosity_level],edx
jmp next_argument
set_errors_limit:
cmp byte [esi],0
jne get_errors_setting
dec ecx
jz error_in_arguments
add ebx,4
mov esi,[ebx]
get_errors_setting:
call get_option_value
test edx,edx
jz error_in_arguments
mov [maximum_number_of_errors],edx
jmp next_argument
set_recursion_limit:
cmp byte [esi],0
jne get_recursion_setting
dec ecx
jz error_in_arguments
add ebx,4
mov esi,[ebx]
get_recursion_setting:
call get_option_value
test edx,edx
jz error_in_arguments
mov [maximum_depth_of_stack],edx
jmp next_argument
set_passes_limit:
cmp byte [esi],0
jne get_passes_setting
dec ecx
jz error_in_arguments
add ebx,4
mov esi,[ebx]
get_passes_setting:
call get_option_value
test edx,edx
jz error_in_arguments
mov [maximum_number_of_passes],edx
next_argument:
add ebx,4
dec ecx
jnz get_argument
cmp [source_path],0
je error_in_arguments
xor al,al
ret
get_option_value:
xor eax,eax
mov edx,eax
find_option_value:
cmp byte [esi],20h
jne get_option_digit
inc esi
jmp find_option_value
get_option_digit:
lodsb
test al,al
jz option_value_ok
sub al,30h
jc invalid_option_value
cmp al,9
ja invalid_option_value
imul edx,10
jo invalid_option_value
add edx,eax
jc invalid_option_value
jmp get_option_digit
option_value_ok:
dec esi
clc
ret
invalid_option_value:
stc
ret
insert_initial_command:
cmp byte [esi],0
jne measure_initial_command
dec ecx
jz error_in_arguments
add ebx,4
mov esi,[ebx]
measure_initial_command:
push ebx ecx edi
mov edi,esi
or ecx,-1
xor al,al
repne scasb
not ecx
dec ecx
mov edi,[initial_commands]
lea eax,[ecx+2]
test edi,edi
jz allocate_initial_commands_buffer
mov edx,[initial_commands_length]
add edi,edx
add eax,edx
cmp eax,[initial_commands_maximum_length]
ja grow_initial_commands_buffer
copy_initial_command:
rep movsb
mov ax,0Ah
stosw
dec edi
sub edi,[initial_commands]
mov [initial_commands_length],edi
pop edi ecx ebx
jmp next_argument
allocate_initial_commands_buffer:
push ecx
mov ecx,eax
call malloc
mov [initial_commands],eax
mov [initial_commands_maximum_length],ecx
mov edi,eax
pop ecx
jmp copy_initial_command
grow_initial_commands_buffer:
push ecx
mov ecx,eax
mov eax,[initial_commands]
call realloc
mov [initial_commands],eax
mov [initial_commands_maximum_length],ecx
mov edi,eax
add edi,[initial_commands_length]
pop ecx
jmp copy_initial_command
include 'system.inc'
include '../malloc.inc'
include '../assembler.inc'
include '../symbols.inc'
include '../expressions.inc'
include '../conditions.inc'
include '../floats.inc'
include '../directives.inc'
include '../calm.inc'
include '../errors.inc'
include '../map.inc'
include '../reader.inc'
include '../output.inc'
include '../console.inc'
segment readable
_logo db 'flat assembler version g.',VERSION,10,0
_usage db 'Usage: fasmg source [output]',10
db 'Optional settings:',10
db ' -p limit Set the maximum allowed number of passes (default 100)',10
db ' -e limit Set the maximum number of displayed errors (default 1)',10
db ' -r limit Set the maximum depth of the stack (default 10000)',10
db ' -v flag Enable or disable showing all lines from the stack (default 0)',10
db ' -i command Insert instruction at the beginning of source',13,10
db ' -n Do not show logo nor summary',13,10
db 0
_pass db ' pass, ',0
_passes db ' passes, ',0
_dot db '.'
_seconds db ' seconds, ',0
_byte db ' byte.',0
_bytes db ' bytes.',0
_write_failed db 'failed to write the output file',0
_out_of_memory db 'not enough memory to complete the assembly',0
_code_cannot_be_generated db 'could not generate code within the allowed number of passes',0
_open_mode db 'r',0
_create_mode db 'w',0
include '../tables.inc'
include '../messages.inc'
segment readable writeable
align 16
include '../variables.inc'
align 16
timestamp dq ?
loff dq ?
argc dd ?
argv dd ?
env dd ?
mmap_args rd 6
malloc_freelist dd ?
source_path dd ?
output_path dd ?
maximum_number_of_passes dd ?
initial_commands dd ?
initial_commands_length dd ?
initial_commands_maximum_length dd ?
start_time timeval
end_time timeval
tenths_of_second dd ?
verbosity_level dd ?
no_logo db ?
path_buffer rb 1000h
segment readable writeable gnustack

View File

@@ -0,0 +1,298 @@
LINE_FEED = 0Ah
O_ACCMODE = 0003o
O_RDONLY = 0000o
O_WRONLY = 0001o
O_RDWR = 0002o
O_CREAT = 0100o
O_EXCL = 0200o
O_NOCTTY = 0400o
O_TRUNC = 1000o
O_APPEND = 2000o
O_NONBLOCK = 4000o
S_ISUID = 4000o
S_ISGID = 2000o
S_ISVTX = 1000o
S_IRUSR = 0400o
S_IWUSR = 0200o
S_IXUSR = 0100o
S_IRGRP = 0040o
S_IWGRP = 0020o
S_IXGRP = 0010o
S_IROTH = 0004o
S_IWOTH = 0002o
S_IXOTH = 0001o
system_init:
mov eax,13 ; sys_time
mov ebx,timestamp
int 0x80
retn
system_shutdown:
retn
open:
; in: edx - path to file
; out: ebx = file handle, cf set on error
; preserves: esi, edi
push esi edi ebp
call adapt_path
mov eax,5 ; sys_open
mov ecx,O_RDONLY
xor edx,edx
int 0x80
pop ebp edi esi
test eax,eax
js interface_error
mov ebx,eax
clc
retn
adapt_path:
xor ecx,ecx
mov ebx,path_buffer
copy_path:
mov al,[edx+ecx]
cmp al,'\'
jne path_char_ok
mov al,'/'
path_char_ok:
cmp ecx,1000h
jae out_of_memory
mov [ebx+ecx],al
inc ecx
test al,al
jnz copy_path
retn
interface_error:
stc
retn
create:
; in: edx - path to file
; out: ebx = file handle, cf set on error
; preserves: esi, edi
push esi edi ebp
call adapt_path
mov eax,5 ; sys_open
mov ecx,O_CREAT+O_TRUNC+O_WRONLY
mov edx,S_IRUSR+S_IWUSR+S_IRGRP+S_IROTH
int 0x80
pop ebp edi esi
test eax,eax
js interface_error
mov ebx,eax
clc
retn
write:
; in: ebx = file handle, edx - data, ecx = number of bytes
; out: cf set on error
; preserves: ebx, esi, edi
push ebx ecx esi edi ebp
mov eax,4 ; sys_write
xchg ecx,edx
int 0x80
pop ebp edi esi ecx ebx
test eax,eax
js interface_error
cmp eax,ecx
jne interface_error
clc
ret
read:
; in: ebx = file handle, edx - buffer, ecx = number of bytes
; out: cf set on error
; preserves: ebx, esi, edi
push ebx ecx esi edi ebp
mov eax,3 ; sys_read
xchg ecx,edx
int 0x80
pop ebp edi esi ecx ebx
test eax,eax
js interface_error
cmp eax,ecx
jne interface_error
clc
ret
close:
; in: ebx = file handle
; preserves: ebx, esi, edi
push ebx esi edi ebp
mov eax,6 ; sys_close
int 0x80
pop ebp edi esi ebx
ret
lseek:
; in: ebx = file handle, cl = method, edx:eax = offset
; out: edx:eax = new offset from the beginning of file, cf set on error
; preserves: ebx, esi, edi
test edx,edx
jnz interface_error
push esi edi ebx ebp
movzx edi,cl
mov ecx,edx
mov edx,eax
mov eax,140 ; sys_llseek
mov esi,loff
int 0x80
pop ebp ebx edi esi
test eax,eax
js interface_error
mov eax,dword [loff]
mov edx,dword [loff+4]
clc
ret
get_timestamp:
; out: edx:eax = timestamp
; preserves: ebx, ecx, esi, edi
; note: during the passes of a single assembly this function should always return the same value
mov eax,dword [timestamp]
mov edx,dword [timestamp+4]
retn
display_string:
; in:
; esi - string
; ecx = string length, zero for ASCIIZ string
; preserves: ebx, esi
push ebx esi ebp
test ecx,ecx
jnz write_string_to_stdout
xor al,al
mov edi,esi
or ecx,-1
repne scasb
neg ecx
sub ecx,2
write_string_to_stdout:
mov eax,4 ; sys_write
mov ebx,1
mov edx,ecx
mov ecx,esi
int 0x80
pop ebp esi ebx
retn
display_error_string:
; in:
; esi - string
; ecx = string length, zero for ASCIIZ string
; preserves: ebx, esi
push ebx esi ebp
test ecx,ecx
jnz write_string_to_stderr
xor al,al
mov edi,esi
or ecx,-1
repne scasb
neg ecx
sub ecx,2
write_string_to_stderr:
mov eax,4 ; sys_write
mov ebx,2
mov edx,ecx
mov ecx,esi
int 0x80
pop ebp esi ebx
retn
get_environment_variable:
; in:
; esi - name
; edi - buffer for value
; ecx = size of buffer
; out:
; eax = length of value
; preserves: ebx, esi, edi
push ebx ecx
mov edx,[env]
scan_environment:
mov ebx,[edx]
test ebx,ebx
jz no_environment_variable
xor ecx,ecx
compare_character:
mov al,[ebx+ecx]
mov ah,[esi+ecx]
inc ecx
cmp al,'='
je end_of_variable_name
test ah,ah
jz next_variable
sub ah,al
je compare_character
cmp ah,20h
jne next_variable
cmp al,'A'
jb next_variable
cmp al,'Z'
jna compare_character
next_variable:
add edx,4
jmp scan_environment
end_of_variable_name:
test ah,ah
jnz next_variable
add ebx,ecx
pop ecx
xor eax,eax
copy_environment_variable:
mov dl,[ebx+eax]
cmp eax,ecx
jae next_environment_variable_character
mov [edi+eax],dl
next_environment_variable_character:
inc eax
test dl,dl
jnz copy_environment_variable
environment_variable_ok:
pop ebx
ret
no_environment_variable:
pop ecx
mov eax,1
jecxz environment_variable_ok
and byte [edi],0
pop ebx
ret
VALLOC_MINIMUM_SIZE = 100000h
valloc:
; in: ecx = requested minimum size
; out: eax - allocated block, ecx = allocated size, zero if failed
; preserves: ebx, esi, edi
cmp ecx,VALLOC_MINIMUM_SIZE
jbe valloc_size_minimum
dec ecx
and ecx,(-1) shl 12
add ecx,1 shl 12
jmp valloc_size_ready
valloc_size_minimum:
mov ecx,VALLOC_MINIMUM_SIZE
valloc_size_ready:
push ebx edi
mov ebx,mmap_args
mov edi,ebx
xor eax,eax
stosd
mov eax,ecx
stosd
mov eax,3 ; PROT_READ + PROT_WRITE
stosd
mov eax,22h ; MAP_PRIVATE + MAP_ANONYMOUS
stosd
or eax,-1
stosd
xor eax,eax
stosd
mov eax,0x5A ; old_mmap
int 0x80
cmp eax,-1
jne valloc_ok
xor ecx,ecx
valloc_ok:
pop edi ebx
retn

View File

@@ -0,0 +1,79 @@
macro use32on64?
define esp rsp
define promote
iterate <reg32,reg64>, eax,rax, ebx,rbx, ecx,rcx, edx,rdx, esi,rsi, edi,rdi, esp,rsp, ebp,rbp
promote.reg32? equ reg64
end iterate
iterate instr, jmp,call
calminstruction instr? arg
local tmp
match [tmp], arg
jyes zero_extend
transform arg, promote
arrange tmp, =instr arg
assemble tmp
exit
zero_extend:
arrange tmp, =mov =r8d,[tmp]
assemble tmp
arrange tmp, =instr =r8
assemble tmp
end calminstruction
end iterate
calminstruction push? arg
local car, cdr
match car cdr?, arg
loop:
transform car, promote
jno non_reg
arrange car, =push car
assemble car
match car cdr?, cdr
jyes loop
exit
non_reg:
arrange tmp, =mov =r8d,arg
assemble tmp
arrange tmp, =push =r8
assemble tmp
exit
end calminstruction
calminstruction pop? arg
local car, cdr
match car cdr?, arg
loop:
transform car, promote
jno non_reg
arrange car, =pop car
assemble car
match car cdr?, cdr
jyes loop
exit
non_reg:
arrange tmp, =pop =r8
assemble tmp
arrange tmp, =mov arg,=r8d
assemble tmp
exit
end calminstruction
macro jecxz? target
if target-($+1) < 80h & target-($+1) >= -80h
jecxz target
else
local j,k
jecxz j
jmp k
j: jmp target
k:
end if
end macro
end macro

View File

@@ -0,0 +1,124 @@
macro use32on64
{
define esp rsp
define promote.eax rax
define promote.ebx rbx
define promote.ecx rcx
define promote.edx rdx
define promote.esi rsi
define promote.edi rdi
define promote.ebp rbp
define promote.esp rsp
macro push args
\{
local list,arg,status
define list
define arg
irps sym, args \\{
define status
match =dword, sym \\\{
define status :
\\\}
match [any, status arg sym \\\{
define arg [any
match [mem], arg \\\\{
match previous, list \\\\\{ define list previous,[mem] \\\\\}
match , list \\\\\{ define list [mem] \\\\\}
define arg
\\\\}
define status :
\\\}
match [, status arg sym \\\{
define arg [
define status :
\\\}
match , status \\\{
match previous, list \\\\{ define list previous,sym \\\\}
match , list \\\\{ define list sym \\\\}
\\\}
\\}
match ops,list \\{
irp op, ops \\\{
if op eqtype eax
push promote.\\\#op
else
mov r8d,op
push r8
end if
\\\}
\\}
\}
macro pop args
\{
local list,arg,status
define list
define arg
irps sym, args \\{
define status
match =dword, sym \\\{
define status :
\\\}
match [any, status arg sym \\\{
define arg [any
match [mem], arg \\\\{
match previous, list \\\\\{ define list previous,[mem] \\\\\}
match , list \\\\\{ define list [mem] \\\\\}
define arg
\\\\}
define status :
\\\}
match [, status arg sym \\\{
define arg [
define status :
\\\}
match , status \\\{
match previous, list \\\\{ define list previous,sym \\\\}
match , list \\\\{ define list sym \\\\}
\\\}
\\}
match ops,list \\{
irp op, ops \\\{
if op eqtype eax
pop promote.\\\#op
else
pop r8
mov op,r8d
end if
\\\}
\\}
\}
irp instr, jmp,call
\{
macro instr op
\\{
if op eqtype [0]
mov r8d,op
instr r8
else if op eqtype 0
instr op
else
instr promote.\\#op
end if
\\}
\}
macro jecxz target
\{
if target-($+1) < 80h & target-($+1) >= -80h
jecxz target
else
local j,k
jecxz j
jmp k
j: jmp target
k:
end if
\}
}

View File

@@ -0,0 +1,546 @@
match ,{
include '32on64.inc'
} match -,{
else
include '32on64.alm'
end match
_ equ }
include 'macro/struct.inc'
format ELF64 executable 3
entry start
include '../../version.inc'
struct timeval
time_t dq ?
suseconds_t dq ?
ends
segment readable executable
start:
mov rcx,[rsp]
mov [argc],rcx
lea rbx,[rsp+8]
mov [argv],rbx
lea rsi,[rsp+8+rcx*8+8]
mov [env],rsi
call system_init
call get_arguments
mov bl,al
cmp [no_logo],0
jne logo_ok
mov esi,_logo
xor ecx,ecx
call display_string
logo_ok:
test bl,bl
jnz display_usage_information
xor al,al
mov ecx,[verbosity_level]
jecxz init
or al,TRACE_ERROR_STACK
dec ecx
jz init
or al,TRACE_DISPLAY
init:
call assembly_init
mov eax,96 ; sys_gettimeofday
mov edi,start_time
xor esi,esi
syscall
assemble:
mov esi,[initial_commands]
mov edx,[source_path]
call assembly_pass
jc assembly_done
mov eax,[current_pass]
cmp eax,[maximum_number_of_passes]
jb assemble
call show_display_data
mov esi,_error_prefix
xor ecx,ecx
call display_error_string
mov esi,_code_cannot_be_generated
xor ecx,ecx
call display_error_string
mov esi,_message_suffix
xor ecx,ecx
call display_error_string
jmp assembly_failed
assembly_done:
call show_display_data
cmp [first_error],0
jne assembly_failed
cmp [no_logo],0
jne summary_done
mov eax,[current_pass]
xor edx,edx
call itoa
call display_string
mov esi,_passes
cmp [current_pass],1
jne display_passes_suffix
mov esi,_pass
display_passes_suffix:
xor ecx,ecx
call display_string
mov eax,96 ; sys_gettimeofday
mov edi,end_time
xor esi,esi
syscall
mov rax,[end_time.time_t]
sub rax,[start_time.time_t]
mov rcx,1000000
mul rcx
add rax,[end_time.suseconds_t]
adc rdx,0
sub rax,[start_time.suseconds_t]
sbb rdx,0
add rax,50000
mov rcx,1000000
div rcx
mov rbx,rax
mov rax,rdx
xor rdx,rdx
mov rcx,100000
div rcx
mov [tenths_of_second],eax
xchg rax,rbx
or rbx,rax
jz display_output_length
mov rdx,rax
shr rdx,32
call itoa
call display_string
mov esi,_message_suffix
mov ecx,1
call display_string
mov eax,[tenths_of_second]
xor edx,edx
call itoa
call display_string
mov esi,_seconds
xor ecx,ecx
call display_string
display_output_length:
call get_output_length
push rax rdx
call itoa
call display_string
pop rdx rax
mov esi,_bytes
cmp eax,1
jne display_bytes_suffix
test edx,edx
jnz display_bytes_suffix
mov esi,_byte
display_bytes_suffix:
xor ecx,ecx
call display_string
mov esi,_new_line
xor ecx,ecx
call display_string
summary_done:
mov ebx,[source_path]
mov edi,[output_path]
call write_output_file
jc write_failed
call assembly_shutdown
call system_shutdown
xor edi,edi ; exit code 0
mov eax,60 ; sys_exit
syscall
assembly_failed:
call show_errors
call assembly_shutdown
call system_shutdown
mov edi,2
mov eax,60 ; sys_exit
syscall
write_failed:
mov ebx,_write_failed
jmp fatal_error
out_of_memory:
mov ebx,_out_of_memory
jmp fatal_error
fatal_error:
mov esi,_error_prefix
xor ecx,ecx
call display_error_string
mov esi,ebx
xor ecx,ecx
call display_error_string
mov esi,_message_suffix
xor ecx,ecx
call display_error_string
call assembly_shutdown
call system_shutdown
mov edi,3
mov eax,60 ; sys_exit
syscall
internal_error:
int3
display_usage_information:
mov esi,_usage
xor ecx,ecx
call display_string
call system_shutdown
mov edi,1
mov eax,60 ; sys_exit
syscall
get_arguments:
xor eax,eax
mov [initial_commands],eax
mov [source_path],eax
mov [output_path],eax
mov [no_logo],al
mov [verbosity_level],eax
mov [maximum_number_of_passes],100
mov [maximum_number_of_errors],1
mov [maximum_depth_of_stack],10000
mov rcx,[argc]
mov rbx,[argv]
add rbx,8
dec ecx
jz error_in_arguments
get_argument:
mov rsi,[rbx]
mov al,[rsi]
cmp al,'-'
je get_option
cmp [source_path],0
jne get_output_file
call strdup
mov [source_path],eax
jmp next_argument
get_output_file:
cmp [output_path],0
jne error_in_arguments
call strdup
mov [output_path],eax
jmp next_argument
get_option:
inc rsi
lodsb
cmp al,'e'
je set_errors_limit
cmp al,'E'
je set_errors_limit
cmp al,'i'
je insert_initial_command
cmp al,'I'
je insert_initial_command
cmp al,'p'
je set_passes_limit
cmp al,'P'
je set_passes_limit
cmp al,'r'
je set_recursion_limit
cmp al,'R'
je set_recursion_limit
cmp al,'v'
je set_verbose_mode
cmp al,'V'
je set_verbose_mode
cmp al,'n'
je set_no_logo
cmp al,'N'
jne error_in_arguments
set_no_logo:
or [no_logo],-1
cmp byte [rsi],0
je next_argument
error_in_arguments:
or al,-1
ret
set_verbose_mode:
cmp byte [rsi],0
jne get_verbose_setting
dec ecx
jz error_in_arguments
add rbx,8
mov rsi,[rbx]
get_verbose_setting:
call get_option_value
cmp edx,2
ja error_in_arguments
mov [verbosity_level],edx
jmp next_argument
set_errors_limit:
cmp byte [rsi],0
jne get_errors_setting
dec ecx
jz error_in_arguments
add rbx,8
mov rsi,[rbx]
get_errors_setting:
call get_option_value
test edx,edx
jz error_in_arguments
mov [maximum_number_of_errors],edx
jmp next_argument
set_recursion_limit:
cmp byte [rsi],0
jne get_recursion_setting
dec ecx
jz error_in_arguments
add rbx,8
mov rsi,[rbx]
get_recursion_setting:
call get_option_value
test edx,edx
jz error_in_arguments
mov [maximum_depth_of_stack],edx
jmp next_argument
set_passes_limit:
cmp byte [rsi],0
jne get_passes_setting
dec ecx
jz error_in_arguments
add rbx,8
mov rsi,[rbx]
get_passes_setting:
call get_option_value
test edx,edx
jz error_in_arguments
mov [maximum_number_of_passes],edx
next_argument:
add rbx,8
dec ecx
jnz get_argument
cmp [source_path],0
je error_in_arguments
xor al,al
ret
get_option_value:
xor eax,eax
mov edx,eax
find_option_value:
cmp byte [rsi],20h
jne get_option_digit
inc rsi
jmp find_option_value
get_option_digit:
lodsb
test al,al
jz option_value_ok
sub al,30h
jc invalid_option_value
cmp al,9
ja invalid_option_value
imul edx,10
jo invalid_option_value
add edx,eax
jc invalid_option_value
jmp get_option_digit
option_value_ok:
dec rsi
clc
ret
invalid_option_value:
stc
ret
insert_initial_command:
cmp byte [rsi],0
jne measure_initial_command
dec ecx
jz error_in_arguments
add rbx,8
mov rsi,[rbx]
measure_initial_command:
push rbx rcx rdi
mov rdi,rsi
or ecx,-1
xor al,al
repne scasb
not ecx
dec ecx
mov edi,[initial_commands]
lea eax,[ecx+2]
test edi,edi
jz allocate_initial_commands_buffer
mov edx,[initial_commands_length]
add edi,edx
add eax,edx
cmp eax,[initial_commands_maximum_length]
ja grow_initial_commands_buffer
copy_initial_command:
rep movsb
mov ax,0Ah
stosw
dec edi
sub edi,[initial_commands]
mov [initial_commands_length],edi
pop rdi rcx rbx
jmp next_argument
allocate_initial_commands_buffer:
push rsi rcx
mov ecx,eax
call malloc
mov [initial_commands],eax
mov [initial_commands_maximum_length],ecx
mov edi,eax
pop rcx rsi
jmp copy_initial_command
grow_initial_commands_buffer:
push rsi rcx
mov ecx,eax
mov eax,[initial_commands]
call realloc
mov [initial_commands],eax
mov [initial_commands_maximum_length],ecx
mov edi,eax
add edi,[initial_commands_length]
pop rcx rsi
jmp copy_initial_command
strdup:
; in: rsi - ASCIIZ string
; out: eax - copy of the string in 32-bit addressable memory
; preserves: rbx, rcx, rsi
push rbx rcx rsi
mov rdi,rsi
or ecx,-1
xor al,al
repne scasb
not ecx
push rsi rcx
call malloc
pop rcx rsi
mov edi,eax
rep movsb
pop rsi rcx rbx
ret
include 'system.inc'
use32on64
include '../../malloc.inc'
include '../../assembler.inc'
include '../../symbols.inc'
include '../../expressions.inc'
include '../../conditions.inc'
include '../../floats.inc'
include '../../directives.inc'
include '../../calm.inc'
include '../../errors.inc'
include '../../map.inc'
include '../../reader.inc'
include '../../output.inc'
include '../../console.inc'
segment readable
_logo db 'flat assembler version g.',VERSION,10,0
_usage db 'Usage: fasmg source [output]',10
db 'Optional settings:',10
db ' -p limit Set the maximum allowed number of passes (default 100)',10
db ' -e limit Set the maximum number of displayed errors (default 1)',10
db ' -r limit Set the maximum depth of the stack (default 10000)',10
db ' -v flag Enable or disable showing all lines from the stack (default 0)',10
db ' -i command Insert instruction at the beginning of source',13,10
db ' -n Do not show logo nor summary',13,10
db 0
_pass db ' pass, ',0
_passes db ' passes, ',0
_dot db '.'
_seconds db ' seconds, ',0
_byte db ' byte.',0
_bytes db ' bytes.',0
_write_failed db 'failed to write the output file',0
_out_of_memory db 'not enough memory to complete the assembly',0
_code_cannot_be_generated db 'could not generate code within the allowed number of passes',0
include '../../tables.inc'
include '../../messages.inc'
segment readable writeable
align 16
include '../../variables.inc'
align 16
timestamp dq ?
argc dq ?
argv dq ?
env dq ?
mmap_hint dd ?
malloc_freelist dd ?
source_path dd ?
output_path dd ?
maximum_number_of_passes dd ?
initial_commands dd ?
initial_commands_length dd ?
initial_commands_maximum_length dd ?
start_time timeval
end_time timeval
tenths_of_second dd ?
verbosity_level dd ?
no_logo db ?
local_heap_available db ?
path_buffer rb 1000h
segment readable writeable
align 1000h
LOCAL_HEAP_SIZE = 1000000h
local_heap rb LOCAL_HEAP_SIZE
segment readable writeable gnustack

View File

@@ -0,0 +1,334 @@
LINE_FEED = 0Ah
O_ACCMODE = 0003o
O_RDONLY = 0000o
O_WRONLY = 0001o
O_RDWR = 0002o
O_CREAT = 0100o
O_EXCL = 0200o
O_NOCTTY = 0400o
O_TRUNC = 1000o
O_APPEND = 2000o
O_NONBLOCK = 4000o
S_ISUID = 4000o
S_ISGID = 2000o
S_ISVTX = 1000o
S_IRUSR = 0400o
S_IWUSR = 0200o
S_IXUSR = 0100o
S_IRGRP = 0040o
S_IWGRP = 0020o
S_IXGRP = 0010o
S_IROTH = 0004o
S_IWOTH = 0002o
S_IXOTH = 0001o
system_init:
mov eax,201 ; sys_time
mov edi,timestamp
syscall
or [local_heap_available],1
retn
system_shutdown:
call mcheck
retn
open:
; in: edx - path to file
; out: ebx = file handle, cf set on error
; preserves: esi, edi
push rsi rdi
call adapt_path
mov eax,2 ; sys_open
mov esi,O_RDONLY
xor edx,edx
syscall
pop rdi rsi
test eax,eax
js interface_error
mov ebx,eax
clc
ret
interface_error:
stc
ret
adapt_path:
xor ecx,ecx
mov edi,path_buffer
copy_path:
mov al,[edx+ecx]
cmp al,'\'
jne path_char_ok
mov al,'/'
path_char_ok:
cmp ecx,1000h
jae out_of_memory
mov [edi+ecx],al
inc ecx
test al,al
jnz copy_path
retn
create:
; in: edx - path to file
; out: ebx = file handle, cf set on error
; preserves: esi, edi
push rsi rdi
call adapt_path
mov esi,O_CREAT+O_TRUNC+O_WRONLY
mov edx,S_IRUSR+S_IWUSR+S_IRGRP+S_IROTH
mov eax,2 ; sys_open
syscall
pop rdi rsi
test eax,eax
js interface_error
mov ebx,eax
clc
retn
write:
; in: ebx = file handle, edx - data, ecx = number of bytes
; out: cf set on error
; preserves: ebx, esi, edi
push rsi rdi
mov eax,1 ; sys_write
mov edi,ebx
mov esi,edx
mov edx,ecx
syscall
pop rdi rsi
test eax,eax
js interface_error
cmp eax,edx
jne interface_error
clc
ret
read:
; in: ebx = file handle, edx - buffer, ecx = number of bytes
; out: cf set on error
; preserves: ebx, esi, edi
push rsi rdi
mov eax,0 ; sys_read
mov edi,ebx
mov esi,edx
mov edx,ecx
syscall
pop rdi rsi
test eax,eax
js interface_error
cmp eax,edx
jne interface_error
clc
ret
close:
; in: ebx = file handle
; preserves: ebx, esi, edi
push rdi
mov edi,ebx
mov eax,3 ; sys_close
syscall
pop rdi
ret
lseek:
; in: ebx = file handle, cl = method, edx:eax = offset
; out: edx:eax = new offset from the beginning of file, cf set on error
; preserves: ebx, esi, edi
push rsi rdi
mov edi,ebx
mov esi,edx
mov eax,eax
shl rsi,32
or rsi,rax
xor edx,edx
mov dl,cl
mov eax,8 ; sys_lseek
syscall
pop rdi rsi
cmp rax,-1
je interface_error
mov rdx,rax
shr rdx,32
clc
ret
get_timestamp:
; out: edx:eax = timestamp
; preserves: ebx, ecx, esi, edi
; note: during the passes of a single assembly this function should always return the same value
mov eax,dword [timestamp]
mov edx,dword [timestamp+4]
retn
display_string:
; in:
; esi - string
; ecx = string length, zero for ASCIIZ string
; preserves: ebx, esi
push rbx rsi rbp
test ecx,ecx
jnz write_string_to_stdout
xor al,al
mov edi,esi
or ecx,-1
repne scasb
neg ecx
sub ecx,2
write_string_to_stdout:
mov eax,1 ; sys_write
mov edi,1
mov edx,ecx
syscall
pop rbp rsi rbx
retn
display_error_string:
; in:
; esi - string
; ecx = string length, zero for ASCIIZ string
; preserves: ebx, esi
push rbx rsi rbp
test ecx,ecx
jnz write_string_to_stderr
xor al,al
mov edi,esi
or ecx,-1
repne scasb
neg ecx
sub ecx,2
write_string_to_stderr:
mov eax,1 ; sys_write
mov edi,2
mov edx,ecx
syscall
pop rbp rsi rbx
retn
get_environment_variable:
; in:
; esi - name
; edi - buffer for value
; ecx = size of buffer
; out:
; eax = length of value
; preserves: ebx, esi, edi
push rbx rcx
mov rdx,[env]
scan_environment:
mov rbx,[rdx]
test rbx,rbx
jz no_environment_variable
xor ecx,ecx
compare_character:
mov al,[rbx+rcx]
mov ah,[esi+ecx]
inc ecx
cmp al,'='
je end_of_variable_name
test ah,ah
jz next_variable
sub ah,al
je compare_character
cmp ah,20h
jne next_variable
cmp al,'A'
jb next_variable
cmp al,'Z'
jna compare_character
next_variable:
add rdx,8
jmp scan_environment
end_of_variable_name:
test ah,ah
jnz next_variable
add rbx,rcx
pop rcx
xor eax,eax
copy_environment_variable:
mov dl,[rbx+rax]
cmp eax,ecx
jae next_environment_variable_character
mov [edi+eax],dl
next_environment_variable_character:
inc eax
test dl,dl
jnz copy_environment_variable
environment_variable_ok:
pop rbx
ret
no_environment_variable:
pop rcx
mov eax,1
jecxz environment_variable_ok
and byte [edi],0
pop rbx
ret
VALLOC_MINIMUM_SIZE = 100000h
valloc:
; in: ecx = requested minimum size
; out: eax - allocated block, ecx = allocated size, zero if failed
; preserves: ebx, esi, edi
cmp ecx,VALLOC_MINIMUM_SIZE
jbe valloc_size_minimum
dec ecx
and ecx,(-1) shl 12
add ecx,1 shl 12
jmp valloc_size_ready
valloc_size_minimum:
mov ecx,VALLOC_MINIMUM_SIZE
valloc_size_ready:
push rbx rsi rdi
cmp [local_heap_available],0
je valloc_mmap
cmp ecx,LOCAL_HEAP_SIZE
ja valloc_mmap
and [local_heap_available],0
mov eax,local_heap
mov ecx,LOCAL_HEAP_SIZE
jmp valloc_ok
valloc_mmap:
xor r9d,r9d
or r8,-1
mov r10d,62h ; MAP_PRIVATE + MAP_ANONYMOUS + MAP_32BIT
mov edx,3 ; PROT_READ + PROT_WRITE
mov esi,ecx
xor edi,edi
mov eax,9 ; sys_mmap
syscall
cmp eax,-1
je valloc_mmap_with_hint
mov ecx,eax
cmp rcx,rax
jne valloc_mmap_unusable
add ecx,esi
jnc mmap_ok
valloc_mmap_unusable:
mov rdi,rax
mov eax,11 ; sys_munmap
syscall
valloc_mmap_with_hint:
mov r10d,22h ; MAP_PRIVATE + MAP_ANONYMOUS
mov edx,3 ; PROT_READ + PROT_WRITE
mov edi,[mmap_hint]
mov eax,9 ; sys_mmap
syscall
cmp eax,-1
je valloc_failed
mov ecx,eax
cmp rcx,rax
jne valloc_failed
add ecx,esi
jc valloc_failed
mmap_ok:
sub ecx,eax
valloc_ok:
lea edx,[eax+ecx]
mov [mmap_hint],edx
pop rdi rsi rbx
retn
valloc_failed:
xor ecx,ecx
pop rdi rsi rbx
retn

View File

@@ -0,0 +1,495 @@
include 'macro/struct.inc'
include 'macro/proc32.inc'
format MachO executable
entry start
include '../version.inc'
interpreter '/usr/lib/dyld'
uses '/usr/lib/libSystem.B.dylib'
import libc.malloc,'_malloc',\
libc.realloc,'_realloc',\
libc.free,'_free',\
libc.fopen,'_fopen',\
libc.fclose,'_fclose',\
libc.fread,'_fread',\
libc.fwrite,'_fwrite',\
libc.fseek,'_fseek',\
libc.ftell,'_ftell',\
libc.time,'_time',\
libc.write,'_write',\
getenv,'_getenv',\
gettimeofday,'_gettimeofday',\
exit,'_exit'
struct timeval
time_t dd ?
suseconds_t dd ?
ends
segment '__TEXT' readable executable
section '__text' align 16
start:
mov ecx,[esp]
mov [argc],ecx
lea ebx,[esp+4]
mov [argv],ebx
call system_init
call get_arguments
mov bl,al
cmp [no_logo],0
jne logo_ok
mov esi,_logo
xor ecx,ecx
call display_string
logo_ok:
test bl,bl
jnz display_usage_information
xor al,al
mov ecx,[verbosity_level]
jecxz init
or al,TRACE_ERROR_STACK
dec ecx
jz init
or al,TRACE_DISPLAY
init:
call assembly_init
ccall gettimeofday,start_time,0
assemble:
mov esi,[initial_commands]
mov edx,[source_path]
call assembly_pass
jc assembly_done
mov eax,[current_pass]
cmp eax,[maximum_number_of_passes]
jb assemble
call show_display_data
mov esi,_error_prefix
xor ecx,ecx
call display_error_string
mov esi,_code_cannot_be_generated
xor ecx,ecx
call display_error_string
mov esi,_message_suffix
xor ecx,ecx
call display_error_string
jmp assembly_failed
assembly_done:
call show_display_data
cmp [first_error],0
jne assembly_failed
cmp [no_logo],0
jne summary_done
mov eax,[current_pass]
xor edx,edx
call itoa
call display_string
mov esi,_passes
cmp [current_pass],1
jne display_passes_suffix
mov esi,_pass
display_passes_suffix:
xor ecx,ecx
call display_string
ccall gettimeofday,end_time,0
mov eax,[end_time.time_t]
sub eax,[start_time.time_t]
mov ecx,1000000
mul ecx
add eax,[end_time.suseconds_t]
adc edx,0
sub eax,[start_time.suseconds_t]
sbb edx,0
add eax,50000
mov ecx,1000000
div ecx
mov ebx,eax
mov eax,edx
xor edx,edx
mov ecx,100000
div ecx
mov [tenths_of_second],eax
xchg eax,ebx
or ebx,eax
jz display_output_length
xor edx,edx
call itoa
call display_string
mov esi,_message_suffix
mov ecx,1
call display_string
mov eax,[tenths_of_second]
xor edx,edx
call itoa
call display_string
mov esi,_seconds
xor ecx,ecx
call display_string
display_output_length:
call get_output_length
push eax edx
call itoa
call display_string
pop edx eax
mov esi,_bytes
cmp eax,1
jne display_bytes_suffix
test edx,edx
jnz display_bytes_suffix
mov esi,_byte
display_bytes_suffix:
xor ecx,ecx
call display_string
mov esi,_new_line
xor ecx,ecx
call display_string
summary_done:
mov ebx,[source_path]
mov edi,[output_path]
call write_output_file
jc write_failed
call assembly_shutdown
call system_shutdown
ccall exit,0
assembly_failed:
call show_errors
call assembly_shutdown
call system_shutdown
ccall exit,2
write_failed:
mov ebx,_write_failed
jmp fatal_error
out_of_memory:
mov ebx,_out_of_memory
jmp fatal_error
fatal_error:
mov esi,_error_prefix
xor ecx,ecx
call display_error_string
mov esi,ebx
xor ecx,ecx
call display_error_string
mov esi,_message_suffix
xor ecx,ecx
call display_error_string
call assembly_shutdown
call system_shutdown
ccall exit,3
display_usage_information:
mov esi,_usage
xor ecx,ecx
call display_string
call system_shutdown
ccall exit,1
get_arguments:
xor eax,eax
mov [initial_commands],eax
mov [source_path],eax
mov [output_path],eax
mov [no_logo],al
mov [verbosity_level],eax
mov [maximum_number_of_passes],100
mov [maximum_number_of_errors],1
mov [maximum_depth_of_stack],10000
mov ecx,[argc]
mov ebx,[argv]
add ebx,4
dec ecx
jz error_in_arguments
get_argument:
mov esi,[ebx]
mov al,[esi]
cmp al,'-'
je get_option
cmp [source_path],0
jne get_output_file
mov [source_path],esi
jmp next_argument
get_output_file:
cmp [output_path],0
jne error_in_arguments
mov [output_path],esi
jmp next_argument
get_option:
inc esi
lodsb
cmp al,'e'
je set_errors_limit
cmp al,'E'
je set_errors_limit
cmp al,'i'
je insert_initial_command
cmp al,'I'
je insert_initial_command
cmp al,'p'
je set_passes_limit
cmp al,'P'
je set_passes_limit
cmp al,'r'
je set_recursion_limit
cmp al,'R'
je set_recursion_limit
cmp al,'v'
je set_verbose_mode
cmp al,'V'
je set_verbose_mode
cmp al,'n'
je set_no_logo
cmp al,'N'
jne error_in_arguments
set_no_logo:
or [no_logo],-1
cmp byte [esi],0
je next_argument
error_in_arguments:
or al,-1
ret
set_verbose_mode:
cmp byte [esi],0
jne get_verbose_setting
dec ecx
jz error_in_arguments
add ebx,4
mov esi,[ebx]
get_verbose_setting:
call get_option_value
cmp edx,2
ja error_in_arguments
mov [verbosity_level],edx
jmp next_argument
set_errors_limit:
cmp byte [esi],0
jne get_errors_setting
dec ecx
jz error_in_arguments
add ebx,4
mov esi,[ebx]
get_errors_setting:
call get_option_value
test edx,edx
jz error_in_arguments
mov [maximum_number_of_errors],edx
jmp next_argument
set_recursion_limit:
cmp byte [esi],0
jne get_recursion_setting
dec ecx
jz error_in_arguments
add ebx,4
mov esi,[ebx]
get_recursion_setting:
call get_option_value
test edx,edx
jz error_in_arguments
mov [maximum_depth_of_stack],edx
jmp next_argument
set_passes_limit:
cmp byte [esi],0
jne get_passes_setting
dec ecx
jz error_in_arguments
add ebx,4
mov esi,[ebx]
get_passes_setting:
call get_option_value
test edx,edx
jz error_in_arguments
mov [maximum_number_of_passes],edx
next_argument:
add ebx,4
dec ecx
jnz get_argument
cmp [source_path],0
je error_in_arguments
xor al,al
ret
get_option_value:
xor eax,eax
mov edx,eax
find_option_value:
cmp byte [esi],20h
jne get_option_digit
inc esi
jmp find_option_value
get_option_digit:
lodsb
test al,al
jz option_value_ok
sub al,30h
jc invalid_option_value
cmp al,9
ja invalid_option_value
imul edx,10
jo invalid_option_value
add edx,eax
jc invalid_option_value
jmp get_option_digit
option_value_ok:
dec esi
clc
ret
invalid_option_value:
stc
ret
insert_initial_command:
cmp byte [esi],0
jne measure_initial_command
dec ecx
jz error_in_arguments
add ebx,4
mov esi,[ebx]
measure_initial_command:
push ebx ecx edi
mov edi,esi
or ecx,-1
xor al,al
repne scasb
not ecx
dec ecx
mov edi,[initial_commands]
lea eax,[ecx+2]
test edi,edi
jz allocate_initial_commands_buffer
mov edx,[initial_commands_length]
add edi,edx
add eax,edx
cmp eax,[initial_commands_maximum_length]
ja grow_initial_commands_buffer
copy_initial_command:
rep movsb
mov ax,0Ah
stosw
dec edi
sub edi,[initial_commands]
mov [initial_commands_length],edi
pop edi ecx ebx
jmp next_argument
allocate_initial_commands_buffer:
push ecx
mov ecx,eax
call malloc
mov [initial_commands],eax
mov [initial_commands_maximum_length],ecx
mov edi,eax
pop ecx
jmp copy_initial_command
grow_initial_commands_buffer:
push ecx
mov ecx,eax
mov eax,[initial_commands]
call realloc
mov [initial_commands],eax
mov [initial_commands_maximum_length],ecx
mov edi,eax
add edi,[initial_commands_length]
pop ecx
jmp copy_initial_command
include 'system.inc'
include '../assembler.inc'
include '../symbols.inc'
include '../expressions.inc'
include '../conditions.inc'
include '../floats.inc'
include '../directives.inc'
include '../calm.inc'
include '../errors.inc'
include '../map.inc'
include '../reader.inc'
include '../output.inc'
include '../console.inc'
section '__cstring' align 4
_logo db 'flat assembler version g.',VERSION,10,0
_usage db 'Usage: fasmg source [output]',10
db 'Optional settings:',10
db ' -p limit Set the maximum allowed number of passes (default 100)',10
db ' -e limit Set the maximum number of displayed errors (default 1)',10
db ' -r limit Set the maximum depth of the stack (default 10000)',10
db ' -v flag Enable or disable showing all lines from the stack (default 0)',10
db ' -i command Insert instruction at the beginning of source',13,10
db ' -n Do not show logo nor summary',13,10
db 0
_pass db ' pass, ',0
_passes db ' passes, ',0
_dot db '.'
_seconds db ' seconds, ',0
_byte db ' byte.',0
_bytes db ' bytes.',0
_write_failed db 'failed to write the output file',0
_out_of_memory db 'not enough memory to complete the assembly',0
_code_cannot_be_generated db 'could not generate code within the allowed number of passes',0
_open_mode db 'r',0
_create_mode db 'w',0
include '../tables.inc'
include '../messages.inc'
segment '__DATA' readable writable
section '__bss' align 4
include '../variables.inc'
source_path dd ?
output_path dd ?
maximum_number_of_passes dd ?
initial_commands dd ?
initial_commands_length dd ?
initial_commands_maximum_length dd ?
argc dd ?
argv dd ?
timestamp dq ?
start_time timeval
end_time timeval
tenths_of_second dd ?
verbosity_level dd ?
no_logo db ?
path_buffer rb 1000h

View File

@@ -0,0 +1,489 @@
include 'macro/struct.inc'
include 'macro/proc32.inc'
format MachO
public main as '_main'
include '../version.inc'
extrn '_malloc' as libc.malloc
extrn '_realloc' as libc.realloc
extrn '_free' as libc.free
extrn '_fopen' as libc.fopen
extrn '_fclose' as libc.fclose
extrn '_fread' as libc.fread
extrn '_fwrite' as libc.fwrite
extrn '_fseek' as libc.fseek
extrn '_ftell' as libc.ftell
extrn '_time' as libc.time
extrn '_write' as libc.write
extrn '_getenv' as getenv
extrn '_gettimeofday' as gettimeofday
extrn '_exit' as exit
struct timeval
time_t dd ?
suseconds_t dd ?
ends
section '__TEXT':'__text' align 16
main:
mov ecx,[esp+4]
mov [argc],ecx
mov ebx,[esp+8]
mov [argv],ebx
call system_init
call get_arguments
mov bl,al
cmp [no_logo],0
jne logo_ok
mov esi,_logo
xor ecx,ecx
call display_string
logo_ok:
test bl,bl
jnz display_usage_information
xor al,al
mov ecx,[verbosity_level]
jecxz init
or al,TRACE_ERROR_STACK
dec ecx
jz init
or al,TRACE_DISPLAY
init:
call assembly_init
ccall gettimeofday,start_time,0
assemble:
mov esi,[initial_commands]
mov edx,[source_path]
call assembly_pass
jc assembly_done
mov eax,[current_pass]
cmp eax,[maximum_number_of_passes]
jb assemble
call show_display_data
mov esi,_error_prefix
xor ecx,ecx
call display_error_string
mov esi,_code_cannot_be_generated
xor ecx,ecx
call display_error_string
mov esi,_message_suffix
xor ecx,ecx
call display_error_string
jmp assembly_failed
assembly_done:
call show_display_data
cmp [first_error],0
jne assembly_failed
cmp [no_logo],0
jne summary_done
mov eax,[current_pass]
xor edx,edx
call itoa
call display_string
mov esi,_passes
cmp [current_pass],1
jne display_passes_suffix
mov esi,_pass
display_passes_suffix:
xor ecx,ecx
call display_string
ccall gettimeofday,end_time,0
mov eax,[end_time.time_t]
sub eax,[start_time.time_t]
mov ecx,1000000
mul ecx
add eax,[end_time.suseconds_t]
adc edx,0
sub eax,[start_time.suseconds_t]
sbb edx,0
add eax,50000
mov ecx,1000000
div ecx
mov ebx,eax
mov eax,edx
xor edx,edx
mov ecx,100000
div ecx
mov [tenths_of_second],eax
xchg eax,ebx
or ebx,eax
jz display_output_length
xor edx,edx
call itoa
call display_string
mov esi,_message_suffix
mov ecx,1
call display_string
mov eax,[tenths_of_second]
xor edx,edx
call itoa
call display_string
mov esi,_seconds
xor ecx,ecx
call display_string
display_output_length:
call get_output_length
push eax edx
call itoa
call display_string
pop edx eax
mov esi,_bytes
cmp eax,1
jne display_bytes_suffix
test edx,edx
jnz display_bytes_suffix
mov esi,_byte
display_bytes_suffix:
xor ecx,ecx
call display_string
mov esi,_new_line
xor ecx,ecx
call display_string
summary_done:
mov ebx,[source_path]
mov edi,[output_path]
call write_output_file
jc write_failed
call assembly_shutdown
call system_shutdown
ccall exit,0
assembly_failed:
call show_errors
call assembly_shutdown
call system_shutdown
ccall exit,2
write_failed:
mov ebx,_write_failed
jmp fatal_error
out_of_memory:
mov ebx,_out_of_memory
jmp fatal_error
fatal_error:
mov esi,_error_prefix
xor ecx,ecx
call display_error_string
mov esi,ebx
xor ecx,ecx
call display_error_string
mov esi,_message_suffix
xor ecx,ecx
call display_error_string
call assembly_shutdown
call system_shutdown
ccall exit,3
display_usage_information:
mov esi,_usage
xor ecx,ecx
call display_string
call system_shutdown
ccall exit,1
get_arguments:
xor eax,eax
mov [initial_commands],eax
mov [source_path],eax
mov [output_path],eax
mov [no_logo],al
mov [verbosity_level],eax
mov [maximum_number_of_passes],100
mov [maximum_number_of_errors],1
mov [maximum_depth_of_stack],10000
mov ecx,[argc]
mov ebx,[argv]
add ebx,4
dec ecx
jz error_in_arguments
get_argument:
mov esi,[ebx]
mov al,[esi]
cmp al,'-'
je get_option
cmp [source_path],0
jne get_output_file
mov [source_path],esi
jmp next_argument
get_output_file:
cmp [output_path],0
jne error_in_arguments
mov [output_path],esi
jmp next_argument
get_option:
inc esi
lodsb
cmp al,'e'
je set_errors_limit
cmp al,'E'
je set_errors_limit
cmp al,'i'
je insert_initial_command
cmp al,'I'
je insert_initial_command
cmp al,'p'
je set_passes_limit
cmp al,'P'
je set_passes_limit
cmp al,'r'
je set_recursion_limit
cmp al,'R'
je set_recursion_limit
cmp al,'v'
je set_verbose_mode
cmp al,'V'
je set_verbose_mode
cmp al,'n'
je set_no_logo
cmp al,'N'
jne error_in_arguments
set_no_logo:
or [no_logo],-1
cmp byte [esi],0
je next_argument
error_in_arguments:
or al,-1
ret
set_verbose_mode:
cmp byte [esi],0
jne get_verbose_setting
dec ecx
jz error_in_arguments
add ebx,4
mov esi,[ebx]
get_verbose_setting:
call get_option_value
cmp edx,2
ja error_in_arguments
mov [verbosity_level],edx
jmp next_argument
set_errors_limit:
cmp byte [esi],0
jne get_errors_setting
dec ecx
jz error_in_arguments
add ebx,4
mov esi,[ebx]
get_errors_setting:
call get_option_value
test edx,edx
jz error_in_arguments
mov [maximum_number_of_errors],edx
jmp next_argument
set_recursion_limit:
cmp byte [esi],0
jne get_recursion_setting
dec ecx
jz error_in_arguments
add ebx,4
mov esi,[ebx]
get_recursion_setting:
call get_option_value
test edx,edx
jz error_in_arguments
mov [maximum_depth_of_stack],edx
jmp next_argument
set_passes_limit:
cmp byte [esi],0
jne get_passes_setting
dec ecx
jz error_in_arguments
add ebx,4
mov esi,[ebx]
get_passes_setting:
call get_option_value
test edx,edx
jz error_in_arguments
mov [maximum_number_of_passes],edx
next_argument:
add ebx,4
dec ecx
jnz get_argument
cmp [source_path],0
je error_in_arguments
xor al,al
ret
get_option_value:
xor eax,eax
mov edx,eax
find_option_value:
cmp byte [esi],20h
jne get_option_digit
inc esi
jmp find_option_value
get_option_digit:
lodsb
test al,al
jz option_value_ok
sub al,30h
jc invalid_option_value
cmp al,9
ja invalid_option_value
imul edx,10
jo invalid_option_value
add edx,eax
jc invalid_option_value
jmp get_option_digit
option_value_ok:
dec esi
clc
ret
invalid_option_value:
stc
ret
insert_initial_command:
cmp byte [esi],0
jne measure_initial_command
dec ecx
jz error_in_arguments
add ebx,4
mov esi,[ebx]
measure_initial_command:
push ebx ecx edi
mov edi,esi
or ecx,-1
xor al,al
repne scasb
not ecx
dec ecx
mov edi,[initial_commands]
lea eax,[ecx+2]
test edi,edi
jz allocate_initial_commands_buffer
mov edx,[initial_commands_length]
add edi,edx
add eax,edx
cmp eax,[initial_commands_maximum_length]
ja grow_initial_commands_buffer
copy_initial_command:
rep movsb
mov ax,0Ah
stosw
dec edi
sub edi,[initial_commands]
mov [initial_commands_length],edi
pop edi ecx ebx
jmp next_argument
allocate_initial_commands_buffer:
push ecx
mov ecx,eax
call malloc
mov [initial_commands],eax
mov [initial_commands_maximum_length],ecx
mov edi,eax
pop ecx
jmp copy_initial_command
grow_initial_commands_buffer:
push ecx
mov ecx,eax
mov eax,[initial_commands]
call realloc
mov [initial_commands],eax
mov [initial_commands_maximum_length],ecx
mov edi,eax
add edi,[initial_commands_length]
pop ecx
jmp copy_initial_command
include 'system.inc'
include '../assembler.inc'
include '../symbols.inc'
include '../expressions.inc'
include '../conditions.inc'
include '../floats.inc'
include '../directives.inc'
include '../calm.inc'
include '../errors.inc'
include '../map.inc'
include '../reader.inc'
include '../output.inc'
include '../console.inc'
section '__TEXT':'__cstring' align 4
_logo db 'flat assembler version g.',VERSION,10,0
_usage db 'Usage: fasmg source [output]',10
db 'Optional settings:',10
db ' -p limit Set the maximum allowed number of passes (default 100)',10
db ' -e limit Set the maximum number of displayed errors (default 1)',10
db ' -r limit Set the maximum depth of the stack (default 10000)',10
db ' -v flag Enable or disable showing all lines from the stack (default 0)',10
db ' -i command Insert instruction at the beginning of source',13,10
db ' -n Do not show logo nor summary',13,10
db 0
_pass db ' pass, ',0
_passes db ' passes, ',0
_dot db '.'
_seconds db ' seconds, ',0
_byte db ' byte.',0
_bytes db ' bytes.',0
_write_failed db 'failed to write the output file',0
_out_of_memory db 'not enough memory to complete the assembly',0
_code_cannot_be_generated db 'could not generate code within the allowed number of passes',0
_open_mode db 'r',0
_create_mode db 'w',0
include '../tables.inc'
include '../messages.inc'
section '__DATA':'__data' align 4
include '../variables.inc'
source_path dd ?
output_path dd ?
maximum_number_of_passes dd ?
initial_commands dd ?
initial_commands_length dd ?
initial_commands_maximum_length dd ?
argc dd ?
argv dd ?
timestamp dq ?
start_time timeval
end_time timeval
tenths_of_second dd ?
verbosity_level dd ?
no_logo db ?
path_buffer rb 1000h

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,225 @@
LINE_FEED = 0Ah
system_init:
ccall libc.time,timestamp
retn
system_shutdown:
retn
malloc:
malloc_fixed:
malloc_growable:
; in: ecx = requested size
; out: eax - allocated block, ecx = allocated size, on error jumps to out_of_memory (does not return)
; preserves: ebx, esi, edi
; note:
; use of malloc_fixed hints that block will be kept as is until the end of assembly
; use of malloc_growable hints that block is likely to be resized
push ebx ecx esi edi
ccall libc.malloc,ecx
pop edi esi ecx ebx
test eax,eax
jz out_of_memory
retn
realloc:
; in: eax - memory block, ecx = requested size
; out: eax - resized block, ecx = allocated size, on error jumps to out_of_memory (does not return)
; preserves: ebx, esi, edi
push ebx ecx esi edi
ccall libc.realloc,eax,ecx
pop edi esi ecx ebx
test eax,eax
jz out_of_memory
retn
mfree:
; in: eax - memory block
; out: cf set on error
; preserves: ebx, esi, edi
; note: eax may have value 0 or -1, it should be treated as invalid input then
test eax,eax
jz interface_error
cmp eax,-1
je interface_error
push ebx esi edi
ccall libc.free,eax
pop edi esi ebx
clc
retn
interface_error:
stc
retn
open:
; in: edx - path to file
; out: ebx = file handle, cf set on error
; preserves: esi, edi
push esi edi
call adapt_path
ccall libc.fopen,ebx,_open_mode
pop edi esi
test eax,eax
jz interface_error
mov ebx,eax
clc
retn
adapt_path:
xor ecx,ecx
mov ebx,path_buffer
copy_path:
mov al,[edx+ecx]
cmp al,'\'
jne path_char_ok
mov al,'/'
path_char_ok:
cmp ecx,1000h
jae out_of_memory
mov [ebx+ecx],al
inc ecx
test al,al
jnz copy_path
retn
create:
; in: edx - path to file
; out: ebx = file handle, cf set on error
; preserves: esi, edi
push esi edi
call adapt_path
ccall libc.fopen,ebx,_create_mode
pop edi esi
test eax,eax
jz interface_error
mov ebx,eax
clc
retn
write:
; in: ebx = file handle, edx - data, ecx = number of bytes
; out: cf set on error
; preserves: ebx, esi, edi
push ebx ecx esi edi
ccall libc.fwrite,edx,1,ecx,ebx
pop edi esi ecx ebx
cmp eax,ecx
jne interface_error
clc
ret
read:
; in: ebx = file handle, edx - buffer, ecx = number of bytes
; out: cf set on error
; preserves: ebx, esi, edi
push ebx ecx esi edi
ccall libc.fread,edx,1,ecx,ebx
pop edi esi ecx ebx
cmp eax,ecx
jne interface_error
clc
ret
close:
; in: ebx = file handle
; preserves: ebx, esi, edi
ccall libc.fclose,ebx
ret
lseek:
; in: ebx = file handle, cl = method, edx:eax = offset
; out: edx:eax = new offset from the beginning of file, cf set on error
; preserves: ebx, esi, edi
test edx,edx
jnz interface_error
push esi edi ebx
movzx ecx,cl
ccall libc.fseek,ebx,eax,ecx
test eax,eax
jnz lseek_error
mov ebx,[esp]
ccall libc.ftell,ebx
cmp eax,-1
je lseek_error
xor edx,edx
pop ebx edi esi
clc
ret
lseek_error:
pop ebx edi esi
stc
ret
get_timestamp:
; out: edx:eax = timestamp
; preserves: ebx, ecx, esi, edi
; note: during the passes of a single assembly this function should always return the same value
mov eax,dword [timestamp]
mov edx,dword [timestamp+4]
retn
display_string:
; in:
; esi - string
; ecx = string length, zero for ASCIIZ string
; preserves: ebx, esi
push ebx esi
test ecx,ecx
jnz write_string_to_stdout
xor al,al
mov edi,esi
or ecx,-1
repne scasb
neg ecx
sub ecx,2
write_string_to_stdout:
ccall libc.write,1,esi,ecx
pop esi ebx
retn
display_error_string:
; in:
; esi - string
; ecx = string length, zero for ASCIIZ string
; preserves: ebx, esi
push ebx esi
test ecx,ecx
jnz write_string_to_stderr
xor al,al
mov edi,esi
or ecx,-1
repne scasb
neg ecx
sub ecx,2
write_string_to_stderr:
ccall libc.write,2,esi,ecx
pop esi ebx
retn
get_environment_variable:
; in:
; esi - name
; edi - buffer for value
; ecx = size of buffer
; out:
; eax = length of value
; preserves: ebx, esi, edi
push ebx ecx esi edi
ccall getenv,esi
pop edi esi ecx ebx
test eax,eax
jz no_environment_variable
push esi
mov esi,eax
xor eax,eax
copy_environment_variable:
mov dl,[esi+eax]
cmp eax,ecx
jae next_environment_variable_character
mov [edi+eax],dl
next_environment_variable_character:
inc eax
test dl,dl
jnz copy_environment_variable
pop esi
environment_variable_ok:
ret
no_environment_variable:
mov eax,1
jecxz environment_variable_ok
and byte [edi],0
ret

View File

@@ -0,0 +1,23 @@
; Adapted and tested by Jacob Young (jacobly.alt@gmail.com)
iterate reg, rdi, rsi, rdx, rcx, r8, r9
arguments.%? equ reg
end iterate
macro ccall? proc*,args&
local size
mov rbp,rsp
and rsp,0FFFFFFFFFFFFFFF0h
match any, args
iterate arg, args
if sizeof (arg)
lea arguments.%,[arg]
else if ~ arg eq arguments.%
mov arguments.%,arg
end if
end iterate
end match
call proc
mov rsp,rbp
end macro

View File

@@ -0,0 +1,540 @@
; Adapted and tested by Jacob Young (jacobly.alt@gmail.com)
include 'macro/struct.inc'
include 'ccall.inc'
format MachO64 executable at 1000h
entry start
include '../../linux/x64/32on64.alm'
include '../../version.inc'
interpreter '/usr/lib/dyld'
uses '/usr/lib/libSystem.B.dylib'
import libc.fopen,'_fopen',\
libc.fclose,'_fclose',\
libc.fread,'_fread',\
libc.fwrite,'_fwrite',\
libc.fseek,'_fseek',\
libc.ftell,'_ftell',\
libc.time,'_time',\
libc.write,'_write',\
mmap,'_mmap',\
munmap,'_munmap',\
getenv,'_getenv',\
gettimeofday,'_gettimeofday',\
exit,'_exit'
struct timeval
time_t dq ?
suseconds_t dd ?,?
ends
segment '__TEXT' readable executable
section '__text' align 16
start:
mov rcx,[rsp]
mov [argc],rcx
lea rbx,[rsp+8]
mov [argv],rbx
call system_init
call get_arguments
mov bl,al
cmp [no_logo],0
jne logo_ok
mov esi,_logo
xor ecx,ecx
call display_string
logo_ok:
test bl,bl
jnz display_usage_information
xor al,al
mov ecx,[verbosity_level]
jecxz init
or al,TRACE_ERROR_STACK
dec ecx
jz init
or al,TRACE_DISPLAY
init:
call assembly_init
ccall gettimeofday,start_time,0
assemble:
mov esi,[initial_commands]
mov edx,[source_path]
call assembly_pass
jc assembly_done
mov eax,[current_pass]
cmp eax,[maximum_number_of_passes]
jb assemble
call show_display_data
mov esi,_error_prefix
xor ecx,ecx
call display_error_string
mov esi,_code_cannot_be_generated
xor ecx,ecx
call display_error_string
mov esi,_message_suffix
xor ecx,ecx
call display_error_string
jmp assembly_failed
assembly_done:
call show_display_data
cmp [first_error],0
jne assembly_failed
cmp [no_logo],0
jne summary_done
mov eax,[current_pass]
xor edx,edx
call itoa
call display_string
mov esi,_passes
cmp [current_pass],1
jne display_passes_suffix
mov esi,_pass
display_passes_suffix:
xor ecx,ecx
call display_string
ccall gettimeofday,end_time,0
mov rax,[end_time.time_t]
sub rax,[start_time.time_t]
mov rcx,1000000
mul rcx
mov ecx,[end_time.suseconds_t]
add ecx,50000
add rax,rcx
adc rdx,0
mov ecx,[start_time.suseconds_t]
sub rax,rcx
sbb rdx,0
mov rcx,1000000
div rcx
mov rbx,rax
mov rax,rdx
xor edx,edx
mov rcx,100000
div rcx
mov [tenths_of_second],eax
xchg rax,rbx
or rbx,rax
jz display_output_length
mov rdx,rax
shr rdx,32
call itoa
call display_string
mov esi,_message_suffix
mov ecx,1
call display_string
mov eax,[tenths_of_second]
xor edx,edx
call itoa
call display_string
mov esi,_seconds
xor ecx,ecx
call display_string
display_output_length:
call get_output_length
push rax rdx
call itoa
call display_string
pop rdx rax
mov esi,_bytes
cmp eax,1
jne display_bytes_suffix
test edx,edx
jnz display_bytes_suffix
mov esi,_byte
display_bytes_suffix:
xor ecx,ecx
call display_string
mov esi,_new_line
xor ecx,ecx
call display_string
summary_done:
mov ebx,[source_path]
mov edi,[output_path]
call write_output_file
jc write_failed
call assembly_shutdown
call system_shutdown
ccall exit,0
assembly_failed:
call show_errors
call assembly_shutdown
call system_shutdown
ccall exit,2
write_failed:
mov ebx,_write_failed
jmp fatal_error
out_of_memory:
mov ebx,_out_of_memory
jmp fatal_error
fatal_error:
mov esi,_error_prefix
xor ecx,ecx
call display_error_string
mov esi,ebx
xor ecx,ecx
call display_error_string
mov esi,_message_suffix
xor ecx,ecx
call display_error_string
call assembly_shutdown
call system_shutdown
ccall exit,3
display_usage_information:
mov esi,_usage
xor ecx,ecx
call display_string
call system_shutdown
ccall exit,1
get_arguments:
xor eax,eax
mov [initial_commands],eax
mov [source_path],eax
mov [output_path],eax
mov [no_logo],al
mov [verbosity_level],eax
mov [maximum_number_of_passes],100
mov [maximum_number_of_errors],1
mov [maximum_depth_of_stack],10000
mov rcx,[argc]
mov rbx,[argv]
add rbx,8
dec ecx
jz error_in_arguments
get_argument:
mov rsi,[rbx]
mov al,[rsi]
cmp al,'-'
je get_option
cmp [source_path],0
jne get_output_file
call strdup
mov [source_path],eax
jmp next_argument
get_output_file:
cmp [output_path],0
jne error_in_arguments
call strdup
mov [output_path],eax
jmp next_argument
get_option:
inc rsi
lodsb
cmp al,'e'
je set_errors_limit
cmp al,'E'
je set_errors_limit
cmp al,'i'
je insert_initial_command
cmp al,'I'
je insert_initial_command
cmp al,'p'
je set_passes_limit
cmp al,'P'
je set_passes_limit
cmp al,'r'
je set_recursion_limit
cmp al,'R'
je set_recursion_limit
cmp al,'v'
je set_verbose_mode
cmp al,'V'
je set_verbose_mode
cmp al,'n'
je set_no_logo
cmp al,'N'
jne error_in_arguments
set_no_logo:
or [no_logo],-1
cmp byte [rsi],0
je next_argument
error_in_arguments:
or al,-1
ret
set_verbose_mode:
cmp byte [rsi],0
jne get_verbose_setting
dec ecx
jz error_in_arguments
add rbx,8
mov rsi,[rbx]
get_verbose_setting:
call get_option_value
cmp edx,2
ja error_in_arguments
mov [verbosity_level],edx
jmp next_argument
set_errors_limit:
cmp byte [rsi],0
jne get_errors_setting
dec ecx
jz error_in_arguments
add rbx,8
mov rsi,[rbx]
get_errors_setting:
call get_option_value
test edx,edx
jz error_in_arguments
mov [maximum_number_of_errors],edx
jmp next_argument
set_recursion_limit:
cmp byte [rsi],0
jne get_recursion_setting
dec ecx
jz error_in_arguments
add rbx,8
mov rsi,[rbx]
get_recursion_setting:
call get_option_value
test edx,edx
jz error_in_arguments
mov [maximum_depth_of_stack],edx
jmp next_argument
set_passes_limit:
cmp byte [rsi],0
jne get_passes_setting
dec ecx
jz error_in_arguments
add rbx,8
mov rsi,[rbx]
get_passes_setting:
call get_option_value
test edx,edx
jz error_in_arguments
mov [maximum_number_of_passes],edx
next_argument:
add rbx,8
dec ecx
jnz get_argument
cmp [source_path],0
je error_in_arguments
xor al,al
ret
get_option_value:
xor eax,eax
mov edx,eax
find_option_value:
cmp byte [rsi],20h
jne get_option_digit
inc rsi
jmp find_option_value
get_option_digit:
lodsb
test al,al
jz option_value_ok
sub al,30h
jc invalid_option_value
cmp al,9
ja invalid_option_value
imul edx,10
jo invalid_option_value
add edx,eax
jc invalid_option_value
jmp get_option_digit
option_value_ok:
dec rsi
clc
ret
invalid_option_value:
stc
ret
insert_initial_command:
cmp byte [rsi],0
jne measure_initial_command
dec ecx
jz error_in_arguments
add rbx,8
mov rsi,[rbx]
measure_initial_command:
push rbx rcx rdi
mov rdi,rsi
or ecx,-1
xor al,al
repne scasb
not ecx
dec ecx
mov edi,[initial_commands]
lea eax,[ecx+2]
test edi,edi
jz allocate_initial_commands_buffer
mov edx,[initial_commands_length]
add edi,edx
add eax,edx
cmp eax,[initial_commands_maximum_length]
ja grow_initial_commands_buffer
copy_initial_command:
rep movsb
mov ax,0Ah
stosw
dec edi
sub edi,[initial_commands]
mov [initial_commands_length],edi
pop rdi rcx rbx
jmp next_argument
allocate_initial_commands_buffer:
push rsi rcx
mov ecx,eax
call malloc
mov [initial_commands],eax
mov [initial_commands_maximum_length],ecx
mov edi,eax
pop rcx rsi
jmp copy_initial_command
grow_initial_commands_buffer:
push rsi rcx
mov ecx,eax
mov eax,[initial_commands]
call realloc
mov [initial_commands],eax
mov [initial_commands_maximum_length],ecx
mov edi,eax
add edi,[initial_commands_length]
pop rcx rsi
jmp copy_initial_command
strdup:
; in: rsi - ASCIIZ string
; out: eax - copy of the string in 32-bit addressable memory
; preserves: rbx, rcx, rsi
push rbx rcx rsi
mov rdi,rsi
or ecx,-1
xor al,al
repne scasb
not ecx
push rsi rcx
call malloc
pop rcx rsi
mov edi,eax
rep movsb
pop rsi rcx rbx
ret
include 'system.inc'
use32on64
include '../../malloc.inc'
include '../../assembler.inc'
include '../../symbols.inc'
include '../../expressions.inc'
include '../../conditions.inc'
include '../../floats.inc'
include '../../directives.inc'
include '../../calm.inc'
include '../../errors.inc'
include '../../map.inc'
include '../../reader.inc'
include '../../output.inc'
include '../../console.inc'
section '__cstring' align 4
_logo db 'flat assembler version g.',VERSION,10,0
_usage db 'Usage: fasmg source [output]',10
db 'Optional settings:',10
db ' -p limit Set the maximum allowed number of passes (default 100)',10
db ' -e limit Set the maximum number of displayed errors (default 1)',10
db ' -r limit Set the maximum depth of the stack (default 10000)',10
db ' -v flag Enable or disable showing all lines from the stack (default 0)',10
db ' -i command Insert instruction at the beginning of source',13,10
db ' -n Do not show logo nor summary',13,10
db 0
_pass db ' pass, ',0
_passes db ' passes, ',0
_dot db '.'
_seconds db ' seconds, ',0
_byte db ' byte.',0
_bytes db ' bytes.',0
_write_failed db 'failed to write the output file',0
_out_of_memory db 'not enough memory to complete the assembly',0
_code_cannot_be_generated db 'could not generate code within the allowed number of passes',0
_open_mode db 'r',0
_create_mode db 'w',0
include '../../tables.inc'
include '../../messages.inc'
segment '__DATA' readable writable
section '__bss' align 4
include '../../variables.inc'
mmap_hint dd ?
malloc_freelist dd ?
source_path dd ?
output_path dd ?
maximum_number_of_passes dd ?
initial_commands dd ?
initial_commands_length dd ?
initial_commands_maximum_length dd ?
files dd ?
files_count dd ?
files_maximum_count dd ?
argc dq ?
argv dq ?
timestamp dq ?
start_time timeval
end_time timeval
tenths_of_second dd ?
verbosity_level dd ?
no_logo db ?
local_heap_available db ?
path_buffer rb 1000h
align 1000h
LOCAL_HEAP_SIZE = 1000000h
local_heap rb LOCAL_HEAP_SIZE

View File

@@ -0,0 +1,287 @@
; Adapted and tested by Jacob Young (jacobly.alt@gmail.com)
LINE_FEED = 0Ah
system_init:
ccall libc.time,timestamp
or [local_heap_available],1
retn
system_shutdown:
retn
open:
; in: edx - path to file
; out: ebx = file handle, cf set on error
; preserves: esi, edi
push rsi rdi
call adapt_path
ccall libc.fopen,rbx,_open_mode
put_file_entry:
pop rdi rsi
test rax,rax
jz interface_error
push rax
mov eax,[files]
mov ecx,[files_count]
mov ebx,ecx
inc ecx
mov [files_count],ecx
cmp ecx,[files_maximum_count]
ja grow_files_buffer
store_file_entry:
pop rdx
mov [eax+ebx*8],rdx
clc
retn
interface_error:
stc
retn
grow_files_buffer:
shl ecx,4
test eax,eax
jz allocate_files_buffer
call realloc
jmp allocated_files_buffer
allocate_files_buffer:
call malloc
allocated_files_buffer:
mov [files],eax
shr ecx,3
mov [files_maximum_count],ecx
jmp store_file_entry
adapt_path:
xor ecx,ecx
mov ebx,path_buffer
copy_path:
mov al,[edx+ecx]
cmp al,'\'
jne path_char_ok
mov al,'/'
path_char_ok:
cmp ecx,1000h
jae out_of_memory
mov [ebx+ecx],al
inc ecx
test al,al
jnz copy_path
retn
create:
; in: edx - path to file
; out: ebx = file handle, cf set on error
; preserves: esi, edi
push rsi rdi
call adapt_path
ccall libc.fopen,rbx,_create_mode
jmp put_file_entry
write:
; in: ebx = file handle, edx - data, ecx = number of bytes
; out: cf set on error
; preserves: ebx, esi, edi
push rbx rcx rsi rdi
mov eax,[files]
mov rax,[eax+ebx*8]
ccall libc.fwrite,rdx,1,rcx,rax
pop rdi rsi rcx rbx
cmp eax,ecx
jne interface_error
clc
ret
read:
; in: ebx = file handle, edx - buffer, ecx = number of bytes
; out: cf set on error
; preserves: ebx, esi, edi
push rbx rcx rsi rdi
mov eax,[files]
mov rax,[eax+ebx*8]
ccall libc.fread,rdx,1,rcx,rax
pop rdi rsi rcx rbx
cmp eax,ecx
jne interface_error
clc
ret
close:
; in: ebx = file handle
; preserves: ebx, esi, edi
push rsi rdi
mov edi,[files]
mov rdi,[edi+ebx*8]
ccall libc.fclose,rdi
pop rdi rsi
ret
lseek:
; in: ebx = file handle, cl = method, edx:eax = offset
; out: edx:eax = new offset from the beginning of file, cf set on error
; preserves: ebx, esi, edi
push rsi rdi rbx
shl rdx,32
or rax,rdx
movzx ecx,cl
mov edi,[files]
mov rdi,[edi+ebx*8]
push rdi
ccall libc.fseek,rdi,rax,rcx
test eax,eax
jnz lseek_error
pop rdi
ccall libc.ftell,rdi
cmp rax,-1
je lseek_error
mov rdx,rax
shr rdx,32
mov eax,eax
pop rbx rdi rsi
clc
ret
lseek_error:
pop rbx rdi rsi
stc
ret
get_timestamp:
; out: edx:eax = timestamp
; preserves: ebx, ecx, esi, edi
; note: during the passes of a single assembly this function should always return the same value
mov eax,dword [timestamp]
mov edx,dword [timestamp+4]
retn
display_string:
; in:
; esi - string
; ecx = string length, zero for ASCIIZ string
; preserves: ebx, esi
push rbx rsi
test ecx,ecx
jnz write_string_to_stdout
xor al,al
mov edi,esi
or ecx,-1
repne scasb
neg ecx
sub ecx,2
write_string_to_stdout:
ccall libc.write,1,rsi,rcx
pop rsi rbx
retn
display_error_string:
; in:
; esi - string
; ecx = string length, zero for ASCIIZ string
; preserves: ebx, esi
push rbx rsi
test ecx,ecx
jnz write_string_to_stderr
xor al,al
mov edi,esi
or ecx,-1
repne scasb
neg ecx
sub ecx,2
write_string_to_stderr:
ccall libc.write,2,rsi,rcx
pop rsi rbx
retn
get_environment_variable:
; in:
; esi - name
; edi - buffer for value
; ecx = size of buffer
; out:
; eax = length of value
; preserves: ebx, esi, edi
push rbx rcx rsi rdi
ccall getenv,rsi
pop rdi rsi rcx rbx
test rax,rax
jz no_environment_variable
push rsi
mov rsi,rax
xor eax,eax
copy_environment_variable:
mov dl,[rsi+rax]
cmp eax,ecx
jae next_environment_variable_character
mov [edi+eax],dl
next_environment_variable_character:
inc eax
test dl,dl
jnz copy_environment_variable
pop rsi
environment_variable_ok:
ret
no_environment_variable:
mov eax,1
jecxz environment_variable_ok
and byte [edi],0
ret
VALLOC_MINIMUM_SIZE = 100000h
valloc:
; in: ecx = requested minimum size
; out: eax - allocated block, ecx = allocated size, zero if failed
; preserves: ebx, esi, edi
cmp ecx,VALLOC_MINIMUM_SIZE
jbe valloc_size_minimum
dec ecx
and ecx,(-1) shl 12
add ecx,1 shl 12
jmp valloc_size_ready
valloc_size_minimum:
mov ecx,VALLOC_MINIMUM_SIZE
valloc_size_ready:
push rbx rsi rdi
cmp [local_heap_available],0
je valloc_mmap
cmp ecx,LOCAL_HEAP_SIZE
ja valloc_mmap
and [local_heap_available],0
mov eax,local_heap
mov ecx,LOCAL_HEAP_SIZE
jmp valloc_ok
valloc_mmap:
push rcx
ccall mmap,0,rcx, \
3, \ ; PROT_READ + PROT_WRITE
9002h, \ ; MAP_PRIVATE + MAP_ANONYMOUS + MAP_32BIT
-1,0
pop rsi
cmp eax,-1
je valloc_mmap_with_hint
mov ecx,eax
cmp rcx,rax
jne valloc_mmap_unusable
add ecx,esi
jnc mmap_ok
valloc_mmap_unusable:
ccall munmap,rax,rsi
valloc_mmap_with_hint:
push rsi
mov edi,[mmap_hint]
ccall mmap,rdi,rsi, \
3, \ ; PROT_READ + PROT_WRITE
1002h, \ ; MAP_PRIVATE + MAP_ANONYMOUS
-1,0
pop rsi
cmp eax,-1
je valloc_failed
mov ecx,eax
cmp rcx,rax
jne valloc_failed
add ecx,esi
jc valloc_failed
mmap_ok:
sub ecx,eax
valloc_ok:
lea edx,[eax+ecx]
mov [mmap_hint],edx
pop rdi rsi rbx
retn
valloc_failed:
xor ecx,ecx
pop rdi rsi rbx
retn

View File

@@ -0,0 +1,343 @@
; a very basic implementation of malloc/realloc
; for porting fasmg to systems that do not have such API natively
struct MemoryHeader
size dd ? ; total size of this block, the lowest bit set for blocks in use
preceding_size dd ? ; total size of the block that precedes this one in memory (zero if this is an initial block of address range)
ends
struct FreeMemory
header MemoryHeader
right dd ? ; next free block in cyclic list
left dd ? ; previous free block in cyclic list
ends
assert defined valloc
; in: ecx = requested minimum size
; out: eax - allocated block, ecx = allocated size, zero if failed
; preserves: ebx, esi, edi
; note:
; valloc is called to request raw memory from the OS;
; it is encouraged to allocate more memory than requested (even entire available memory),
; the obtained memory is kept indefinitely in the pool for malloc
; and should be released by OS automatically when the process ends;
; if the OS does not do it automatically, additional list of the memory areas
; may need to be maintained to release them before exit
malloc:
malloc_fixed:
malloc_growable:
; in: ecx = requested size
; out: eax - allocated block, ecx = allocated size, on error jumps to out_of_memory (does not return)
; preserves: ebx, esi, edi
add ecx,sizeof.MemoryHeader-1
jc out_of_memory
and ecx,(-1) shl 2
add ecx,1 shl 2
jc out_of_memory
cmp ecx,sizeof.FreeMemory
jae malloc_size_ok
mov ecx,sizeof.FreeMemory
malloc_size_ok:
mov eax,[malloc_freelist]
test eax,eax
jz malloc_new
find_fit:
cmp ecx,[eax+MemoryHeader.size]
jbe malloc_use_block
mov eax,[eax+FreeMemory.left]
cmp eax,[malloc_freelist]
jne find_fit
malloc_new:
push ecx
add ecx,sizeof.MemoryHeader
jc out_of_memory
call valloc
test ecx,ecx
jz out_of_memory
xor edx,edx
mov [eax+MemoryHeader.preceding_size],edx
pop edx
push eax
sub ecx,edx
cmp ecx,sizeof.FreeMemory+sizeof.MemoryHeader
jb no_space_for_free_block
mov [eax+MemoryHeader.size],edx
add eax,edx
mov [eax+MemoryHeader.preceding_size],edx
mov edx,ecx
sub edx,sizeof.MemoryHeader
dec edx
and edx,(-1) shl 2
add edx,1 shl 2
mov [eax+MemoryHeader.size],edx
mov ecx,[malloc_freelist]
jecxz freelist_empty
mov [eax+FreeMemory.left],ecx
mov edx,eax
xchg edx,[ecx+FreeMemory.right]
mov [eax+FreeMemory.right],edx
mov [edx+FreeMemory.left],eax
mov edx,[eax+MemoryHeader.size]
jmp free_block_ready
no_space_for_free_block:
sub ecx,sizeof.MemoryHeader
add edx,ecx
mov [eax+MemoryHeader.size],edx
jmp append_limiter
freelist_empty:
mov [eax+FreeMemory.left],eax
mov [eax+FreeMemory.right],eax
free_block_ready:
mov [malloc_freelist],eax
append_limiter:
add eax,edx
mov [eax+MemoryHeader.preceding_size],edx
mov [eax+MemoryHeader.size],sizeof.MemoryHeader or 1 ; cannot be freed
pop eax
finish_malloc:
mov ecx,[eax+MemoryHeader.size]
or [eax+MemoryHeader.size],1
add eax,sizeof.MemoryHeader
sub ecx,sizeof.MemoryHeader
retn
malloc_use_block:
mov edx,[eax+MemoryHeader.size]
sub edx,ecx
cmp edx,sizeof.FreeMemory
jb use_whole_block
mov [eax+MemoryHeader.size],ecx
mov [eax+ecx+MemoryHeader.preceding_size],ecx
add ecx,eax
mov [malloc_freelist],ecx
mov [ecx+MemoryHeader.size],edx
mov [ecx+edx+MemoryHeader.preceding_size],edx
mov edx,[eax+FreeMemory.right]
cmp edx,eax
je update_free_singleton
mov [ecx+FreeMemory.right],edx
mov [edx+FreeMemory.left],ecx
mov edx,[eax+FreeMemory.left]
mov [ecx+FreeMemory.left],edx
mov [edx+FreeMemory.right],ecx
jmp finish_malloc
update_free_singleton:
mov [ecx+FreeMemory.left],ecx
mov [ecx+FreeMemory.right],ecx
jmp finish_malloc
use_whole_block:
mov edx,[eax+FreeMemory.right]
cmp edx,eax
je depleted_freelist
mov ecx,[eax+FreeMemory.left]
mov [ecx+FreeMemory.right],edx
mov [edx+FreeMemory.left],ecx
mov [malloc_freelist],edx
jmp finish_malloc
depleted_freelist:
and [malloc_freelist],0
jmp finish_malloc
mfree:
; in: eax - memory block
; out: cf set on error
; preserves: ebx, esi, edi
; note: eax may have value 0 or -1, it should be treated as invalid input then
test eax,eax
jz mfree_error
cmp eax,-1
je mfree_error
sub eax,sizeof.MemoryHeader
mov ecx,[eax+MemoryHeader.size]
btr ecx,0
jnc mfree_error
cmp ecx,sizeof.FreeMemory
jb mfree_error
cmp [eax+ecx+MemoryHeader.preceding_size],ecx
jne mfree_error
mov [eax+MemoryHeader.size],ecx
mov edx,eax
sub edx,[eax+MemoryHeader.preceding_size]
cmp edx,eax
je no_preceding_block
test [edx+MemoryHeader.size],1
jz coalesce_with_preceding_block
no_preceding_block:
test [eax+ecx+MemoryHeader.size],1
jz coalesce_with_following_block
mov ecx,[malloc_freelist]
jecxz mfree_init_freelist
mov edx,[ecx+FreeMemory.right]
mov [eax+FreeMemory.left],ecx
mov [edx+FreeMemory.left],eax
mov [eax+FreeMemory.right],edx
mov [ecx+FreeMemory.right],eax
mfree_ok:
mov [malloc_freelist],eax
clc
retn
mfree_init_freelist:
mov [eax+FreeMemory.left],eax
mov [eax+FreeMemory.right],eax
jmp mfree_ok
mfree_error:
stc
retn
coalesce_with_preceding_block:
add ecx,[edx+MemoryHeader.size]
test [edx+ecx+MemoryHeader.size],1
jz coalesce_on_both_ends
mov [edx+MemoryHeader.size],ecx
mov [edx+ecx+MemoryHeader.preceding_size],ecx
clc
retn
coalesce_on_both_ends:
lea eax,[edx+ecx]
add ecx,[eax+MemoryHeader.size]
mov [edx+MemoryHeader.size],ecx
mov [edx+ecx+MemoryHeader.preceding_size],ecx
mov [malloc_freelist],edx
mov ecx,[eax+FreeMemory.left]
mov edx,[eax+FreeMemory.right]
mov [edx+FreeMemory.left],ecx
mov [ecx+FreeMemory.right],edx
clc
retn
coalesce_with_following_block:
push ebx
lea ebx,[eax+ecx]
add ecx,[ebx+MemoryHeader.size]
mov [eax+MemoryHeader.size],ecx
mov [eax+ecx+MemoryHeader.preceding_size],ecx
mov ecx,[ebx+FreeMemory.left]
mov edx,[ebx+FreeMemory.right]
mov [ecx+FreeMemory.right],eax
mov [edx+FreeMemory.left],eax
mov ecx,[ebx+FreeMemory.left]
mov edx,[ebx+FreeMemory.right]
mov [eax+FreeMemory.left],ecx
mov [eax+FreeMemory.right],edx
pop ebx
jmp mfree_ok
realloc:
; in: eax - memory block, ecx = requested size
; out: eax - resized block, ecx = allocated size, on error jumps to out_of_memory (does not return)
; preserves: ebx, esi, edi
add ecx,sizeof.MemoryHeader-1
jc out_of_memory
and ecx,(-1) shl 2
add ecx,1 shl 2
jc out_of_memory
sub eax,sizeof.MemoryHeader
mov edx,[eax+MemoryHeader.size]
and edx,not 1
cmp ecx,edx
jbe realloc_retain
test [eax+edx+MemoryHeader.size],1
jnz realloc_and_copy
add edx,[eax+edx+MemoryHeader.size]
cmp ecx,edx
ja realloc_and_copy
sub edx,ecx
cmp edx,sizeof.FreeMemory
jb append_whole_block
push esi edi
push ecx edx
lea edi,[eax+ecx]
xchg ecx,[eax+MemoryHeader.size]
and ecx,not 1
lea esi,[eax+ecx]
mov ecx,[esi+FreeMemory.left]
mov edx,[esi+FreeMemory.right]
mov [edx+FreeMemory.left],edi
mov [ecx+FreeMemory.right],edi
mov ecx,[esi+FreeMemory.left]
mov edx,[esi+FreeMemory.right]
mov [edi+FreeMemory.left],ecx
mov [edi+FreeMemory.right],edx
mov [malloc_freelist],edi
pop edx ecx
mov [edi+MemoryHeader.size],edx
mov [edi+edx+MemoryHeader.preceding_size],edx
mov [edi+MemoryHeader.preceding_size],ecx
pop edi esi
jmp finish_malloc
append_whole_block:
add edx,ecx
mov [eax+edx+MemoryHeader.preceding_size],edx
xchg edx,[eax+MemoryHeader.size]
and edx,not 1
add edx,eax
mov ecx,[edx+FreeMemory.left]
cmp ecx,edx
je depleted_freelist
mov edx,[edx+FreeMemory.right]
mov [ecx+FreeMemory.right],edx
mov [edx+FreeMemory.left],ecx
mov [malloc_freelist],ecx
jmp finish_malloc
realloc_retain:
and [eax+MemoryHeader.size],not 1
jmp finish_malloc
realloc_and_copy:
push esi edi
lea esi,[eax+sizeof.MemoryHeader]
call malloc_growable
push eax ecx
mov edi,eax
mov eax,esi
mov ecx,[esi-sizeof.MemoryHeader+MemoryHeader.size]
shr ecx,2
rep movsd
call mfree
pop ecx eax
pop edi esi
retn
if used mcheck
mcheck:
pushf
push eax ebx ecx edx
mov eax,[malloc_freelist]
test eax,eax
jz integrity_verified
verify_freelist:
mov ebx,eax
verify_preceding_blocks:
mov ecx,[ebx+MemoryHeader.preceding_size]
jecxz preceding_blocks_ok
sub ebx,ecx
mov edx,[ebx+MemoryHeader.size]
and edx,not 1
cmp ecx,edx
je verify_preceding_blocks
jmp internal_error
preceding_blocks_ok:
mov ebx,eax
verify_following_blocks:
mov ecx,[ebx+MemoryHeader.size]
and ecx,not 1
cmp ecx,sizeof.MemoryHeader
je following_blocks_ok
add ebx,ecx
cmp ecx,[ebx+MemoryHeader.preceding_size]
je verify_following_blocks
jmp internal_error
following_blocks_ok:
mov edx,[eax+FreeMemory.right]
cmp eax,[edx+FreeMemory.left]
je verify_next
jmp internal_error
verify_next:
mov eax,edx
cmp eax,[malloc_freelist]
jne verify_freelist
integrity_verified:
pop edx ecx ebx eax
popf
retn
end if

View File

@@ -0,0 +1,237 @@
; this is a simple map used primarily for the source cache
struct Map
hash_mask dd ?
linked_blocks dd ?
free_space dd ?
free_space_length dd ?
ends
struct MapEntry
name dd ?
name_length dd ?
value dd ?
next_entry dd ?
ends
create_string_map:
; in: cl = number of hash bits
; out: ebx - new map
; preserves: esi
mov ebx,1
shl ebx,cl
shl ebx,2
lea ecx,[sizeof.Map+ebx*4]
call malloc_fixed
xchg ebx,eax
mov ecx,eax
dec eax
mov [ebx+Map.hash_mask],eax
lea edi,[ebx+sizeof.Map]
xor eax,eax
rep stosd
mov ecx,1000h
call malloc_fixed
mov [ebx+Map.linked_blocks],eax
xor edx,edx
mov [eax],edx
add eax,10h
mov [ebx+Map.free_space],eax
mov [ebx+Map.free_space_length],1000h-10h
retn
destroy_string_map:
; in: ebx - map
; preserves: esi, edi
mov eax,ebx
mov ebx,[ebx+Map.linked_blocks]
call mfree
free_map_blocks:
test ebx,ebx
jz string_map_destroyed
mov eax,ebx
mov ebx,[ebx]
call mfree
jmp free_map_blocks
string_map_destroyed:
retn
get_from_map:
; in:
; ebx - map
; esi - string
; ecx = string length, zero for ASCIIZ string
; out:
; eax = value
; cf set when no entry found
; preserves: ebx, [esi], edi
; note: when entry is found, esi is replaced with pointer to the same string in persistent storage
call get_bucket
test eax,eax
jz not_found_in_map
call find_map_entry
jc not_found_in_map
mov eax,[eax+MapEntry.value]
retn
get_bucket:
call hash_string
and edx,[ebx+Map.hash_mask]
mov eax,[ebx+sizeof.Map+edx*4]
retn
find_map_entry:
cmp [eax+MapEntry.name_length],ecx
jne next_map_entry
push edi
mov edi,[eax+MapEntry.name]
test edi,edi
jz not_this_map_entry
push ecx esi
repe cmpsb
pop esi ecx
jne not_this_map_entry
mov esi,edi
sub esi,ecx
pop edi
clc
retn
not_this_map_entry:
pop edi
next_map_entry:
mov eax,[eax+MapEntry.next_entry]
test eax,eax
jnz find_map_entry
not_found_in_map:
stc
retn
put_into_map:
; in:
; ebx - map
; esi - string
; ecx = string length, zero for ASCIIZ string
; eax = value
; preserves: ebx, [esi], edi
; note:
; esi is replaced with pointer to the same string in persistent storage,
; an ASCIIZ string is a key with length including the terminating zero
; and when it is put into persistent storage, final zero is copied as well
push eax
call get_bucket
test eax,eax
jz new_bucket
call find_map_entry
jnc put_value_into_map_entry
mov eax,[ebx+sizeof.Map+edx*4]
find_free_map_entry:
cmp [eax+MapEntry.name],0
je fill_map_entry
mov edx,eax
mov eax,[eax+MapEntry.next_entry]
test eax,eax
jnz find_free_map_entry
call allocate_map_entry
mov [edx+MapEntry.next_entry],eax
jmp new_map_entry
new_bucket:
call allocate_map_entry
mov [ebx+sizeof.Map+edx*4],eax
new_map_entry:
mov [eax+MapEntry.next_entry],0
fill_map_entry:
mov [eax+MapEntry.name_length],ecx
push eax
call store_string
pop eax
mov [eax+MapEntry.name],esi
put_value_into_map_entry:
pop [eax+MapEntry.value]
retn
allocate_map_entry:
mov eax,[ebx+Map.free_space]
add [ebx+Map.free_space],sizeof.MapEntry
sub [ebx+Map.free_space_length],sizeof.MapEntry
jc map_out_of_free_space
retn
map_out_of_free_space:
push ecx edx
mov ecx,1000h
call malloc_fixed
mov edx,eax
xchg [ebx+Map.linked_blocks],edx
mov [eax],edx
add eax,10h
mov [ebx+Map.free_space],eax
mov [ebx+Map.free_space_length],1000h-10h
pop edx ecx
jmp allocate_map_entry
remove_from_map:
; in:
; ebx - map
; esi - string
; ecx = string length, zero for ASCIIZ string
; preserves: ebx, [esi], edi
call get_bucket
test eax,eax
jz not_found_in_map
call find_map_entry
jc not_found_in_map
mov dword [eax+MapEntry.name],0
retn
iterate_through_map:
; in:
; ebx - map
; edi - callback function
; callback:
; eax = value
; esi - string
; ecx = string length
; edx - MapEntry
mov ecx,[ebx+Map.hash_mask]
inc ecx
add ebx,sizeof.Map
iterate_through_hash_table:
mov edx,[ebx]
iterate_through_bucket:
test edx,edx
jz end_of_bucket
push ebx ecx edx edi
mov eax,[edx+MapEntry.value]
mov esi,[edx+MapEntry.name]
mov ecx,[edx+MapEntry.name_length]
call edi
pop edi edx ecx ebx
mov edx,[edx+MapEntry.next_entry]
jmp iterate_through_bucket
end_of_bucket:
add ebx,4
loop iterate_through_hash_table
retn
hash_string:
; in: esi - string, ecx = string length, zero for ASCIIZ string
; out: ecx = string length, edx = 32-bit hash
; preserves: ebx, esi, edi
mov edx,FNV_OFFSET
jecxz hash_asciiz
mov eax,ecx
hash_known_length:
xor dl,[esi]
inc esi
imul edx,FNV_PRIME
loop hash_known_length
mov ecx,eax
sub esi,ecx
retn
hash_asciiz:
inc ecx
lodsb
xor dl,al
imul edx,FNV_PRIME
test al,al
jnz hash_asciiz
hash_ready:
sub esi,ecx
retn

View File

@@ -0,0 +1,52 @@
_macro_source db 'macro ',0
_preprocessed_source db 'assemble ',0
_unnamed_source db '?',0
_memory_source db 'eval',0
_space db ' ',0
_line_number_prefix db ' [',0
_line_number_suffix db ']',0
_line_content_prefix db ':'
_line_segment_prefix db LINE_FEED,9,0
_calm_source db ' (CALM)',0
_single_quote db 27h,0
_preprocessed_text_prefix db 'Processed: ',0
_error_prefix db 'Error: ',0
_custom_error_prefix db 'Custom error: ',0
_message_suffix db '.'
_new_line db LINE_FEED,0
_source_file_not_found db "source file '%s' not found",0
_error_reading_file db "error reading file '%s'",0
_missing_end_quote db "missing end quote",0
_illegal_instruction db "illegal instruction",0
_invalid_argument db "invalid argument",0
_missing_argument db "missing argument",0
_extra_characters_on_line db "extra characters on line",0
_invalid_identifier db "invalid identifier",0
_invalid_number db "invalid number",0
_undefined_symbol db "symbol '%i' is undefined or out of scope",0
_invalid_symbol_value db "the value of symbol '%i' is not valid for this use",0
_conflicting_definition db "definition of '%i' in conflict with already defined symbol",0
_cannot_apply_to_constant db "cannot apply this operation to constant",0
_symbolic_self_reference db "detected a circular reference of symbolic values",0
_unexpected_instruction db "unexpected instruction",0
_missing_end_directive db "missing end directive",0
_missing_closing_chevron db "missing closing chevron",0
_invalid_value db "value of type not allowed in this context",0
_invalid_expression db "invalid expression",0
_missing_closing_parenthesis db "missing closing parenthesis",0
_excess_closing_parenthesis db "excess closing parenthesis",0
_value_out_of_range db "value out of allowed range",0
_indeterminate_result db "expression has indeterminate, infinite, or infinitesimal result",0
_misused_variable_term db "variable term used where not expected",0
_nonlinear_polynomial db "cannot multiply variable terms",0
_subdivided_variable_term db "cannot subdivide variable term",0
_values_not_comparable db "values not comparable",0
_assertion_failed db "assertion failed",0
_area_overflow db "exceeded the maximum allowed length of output area",0
_address_out_of_range db "address out of range",0
_invalid_area db "invalid or inaccessible addressing area",0
_stack_limit_exceeded db "exceeded the maximum allowed depth of the stack",0
_repeated_declaration db "choice has already been declared",0
_undefined_jump_target db "the target of the jump is not defined in this instruction",0

View File

@@ -0,0 +1,883 @@
struct OutputArea
cached_offset dq ?
definition dd ? ; pointer to ValueDefinition
ends
struct AreaHeader
flags dd ? ; AREA_#
base_address_length dd ?
uninitialized_length dd ?
ends
AREA_VIRTUAL = 1
AREA_VARIABLE = 2
AREA_SHIFT_TRACKING_DISABLED = 4
create_output_area:
; in:
; esi - base address in format of VALTYPE_NUMERIC value
; ecx = length of base address value
; out:
; ebx - AreaHeader
; edx - ValueDefinition
mov eax,[current_output_area_entry]
test eax,eax
jz create_first_output_area
push ecx
lea ecx,[eax+sizeof.OutputArea*2]
cmp ecx,[output_areas_list_end]
jbe get_next_output_entry
mov eax,[output_areas_list]
sub ecx,eax
sub [current_output_area_entry],eax
sub [initial_output_area_entry],eax
sub [output_areas_list_end],eax
call grow_stack
mov [output_areas_list],eax
add [current_output_area_entry],eax
add [initial_output_area_entry],eax
add eax,ecx
mov edi,eax
xchg [output_areas_list_end],eax
sub ecx,eax
sub edi,ecx
shr ecx,2
xor eax,eax
rep stosd
mov eax,[current_output_area_entry]
get_next_output_entry:
add eax,sizeof.OutputArea
cmp [initial_output_area_entry],0
je another_initial_output_area
mov edi,[eax-sizeof.OutputArea+OutputArea.definition]
mov ecx,[edi+ValueDefinition.value_length]
mov edi,[edi+ValueDefinition.value]
mov ebx,[edi+AreaHeader.uninitialized_length]
sub ecx,sizeof.AreaHeader
sub ecx,[edi+AreaHeader.base_address_length]
jz prior_uninitialized_length_ok
and dword [prior_uninitialized_length],0
and dword [prior_uninitialized_length+4],0
prior_uninitialized_length_ok:
add dword [prior_uninitialized_length],ebx
adc dword [prior_uninitialized_length+4],0
xor edx,edx
add ecx,ebx
adc edx,0
add ecx,dword [eax-sizeof.OutputArea+OutputArea.cached_offset]
adc edx,dword [eax-sizeof.OutputArea+OutputArea.cached_offset+4]
mov dword [eax+OutputArea.cached_offset],ecx
mov dword [eax+OutputArea.cached_offset+4],edx
pop ecx
jmp new_output_entry_ready
another_initial_output_area:
pop ecx
jmp create_initial_output_area
create_first_output_area:
mov eax,[output_areas_list]
create_initial_output_area:
mov [initial_output_area_entry],eax
and dword [eax+OutputArea.cached_offset],0
and dword [eax+OutputArea.cached_offset+4],0
and dword [prior_uninitialized_length],0
and dword [prior_uninitialized_length+4],0
new_output_entry_ready:
mov [current_output_area_entry],eax
lea ebx,[eax+OutputArea.definition]
call create_area
retn
create_area:
; in:
; ebx - where pointer to ValueDefinition should be stored, may already hold a previously used one (should contain null otherwise)
; esi - base address in format of VALTYPE_NUMERIC value
; ecx = length of base address value
; out:
; ebx - AreaHeader
; edx - ValueDefinition
mov [address_length],ecx
mov edx,[ebx]
test edx,edx
jz current_area_definition_unusable
cmp [edx+ValueDefinition.reference_count],1
je area_definition_ready
dec [edx+ValueDefinition.reference_count]
current_area_definition_unusable:
mov ecx,retired_definition
retrieve_retired_detached_value:
mov edx,[ecx]
test edx,edx
jz create_area_definition
cmp [edx+ValueDefinition.reference_count],0
jne retired_detached_value_immutable
xor eax,eax
xchg eax,[edx+ValueDefinition.previous]
mov [ecx],eax
jmp adopt_area_definition
retired_detached_value_immutable:
lea ecx,[edx+ValueDefinition.previous]
jmp retrieve_retired_detached_value
create_area_definition:
mov ecx,sizeof.ValueDefinition
call create_tree_element
mov ecx,eax
xchg ecx,[value_definition_chain]
mov [eax+ValueDefinition.interlink],ecx
mov edx,eax
adopt_area_definition:
mov [ebx],edx
or [edx+ValueDefinition.flags],VAL_DETACHED
inc [edx+ValueDefinition.reference_count]
area_definition_ready:
mov ecx,[address_length]
add ecx,sizeof.AreaHeader
mov eax,[edx+ValueDefinition.block_length]
test eax,eax
jz allocate_area_block
cmp ecx,eax
jbe initialize_area_block
push ecx edx
xor eax,eax
xchg eax,[edx+ValueDefinition.value]
call mfree
pop edx ecx
allocate_area_block:
push edx
call malloc_growable
pop edx
mov [edx+ValueDefinition.value],eax
mov [edx+ValueDefinition.block_length],ecx
initialize_area_block:
mov ebx,[edx+ValueDefinition.value]
lea edi,[ebx+sizeof.AreaHeader]
mov ecx,[address_length]
mov [ebx+AreaHeader.base_address_length],ecx
rep movsb
mov [ebx+AreaHeader.uninitialized_length],ecx
mov [ebx+AreaHeader.flags],ecx
sub edi,ebx
mov [edx+ValueDefinition.value_length],edi
mov [edx+ValueDefinition.type],VALTYPE_AREA
mov ecx,[current_pass]
mov [edx+ValueDefinition.pass],ecx
retn
initialize_output:
; in: ecx = number of bytes that should be added to output
; out: edi - output buffer to be filled with data
; preserves: esi
mov edx,[current_area]
mov ebx,[edx+ValueDefinition.value]
add ecx,[ebx+AreaHeader.uninitialized_length]
jc output_out_of_memory
mov eax,[edx+ValueDefinition.value_length]
lea edi,[ebx+eax]
add ecx,eax
jc output_out_of_memory
mov [edx+ValueDefinition.value_length],ecx
cmp ecx,[edx+ValueDefinition.block_length]
jbe area_reserve_sufficient
mov eax,[edx+ValueDefinition.value]
sub edi,eax
push edx
push ecx
bsr edx,ecx
xchg ecx,edx
dec cl
shr edx,cl
inc edx
shl edx,cl
pop ecx
cmp edx,ecx
jbe output_out_of_memory
xchg ecx,edx
call realloc
pop edx
mov ebx,eax
add edi,eax
mov [edx+ValueDefinition.value],ebx
mov [edx+ValueDefinition.block_length],ecx
area_reserve_sufficient:
mov ecx,[ebx+AreaHeader.uninitialized_length]
jecxz output_buffer_ready
xor eax,eax
rep stosb
mov [ebx+AreaHeader.uninitialized_length],eax
output_buffer_ready:
retn
output_out_of_memory:
jmp out_of_memory
uninitialized_output:
; in: ecx = number of uninitialized bytes to be added to output
; preserves: ebx, ecx, esi, edi
mov edx,[current_area]
mov eax,[edx+ValueDefinition.value]
add [eax+AreaHeader.uninitialized_length],ecx
jc area_overflow
mov edx,[edx+ValueDefinition.value_length]
sub edx,sizeof.AreaHeader
sub edx,[eax+AreaHeader.base_address_length]
add edx,[eax+AreaHeader.uninitialized_length]
jc area_overflow
retn
area_overflow:
mov edx,_area_overflow
call register_error
mov edx,[current_area]
or ecx,-1
mov eax,[edx+ValueDefinition.value]
sub ecx,[edx+ValueDefinition.value_length]
add ecx,sizeof.AreaHeader
add ecx,[eax+AreaHeader.base_address_length]
mov [eax+AreaHeader.uninitialized_length],ecx
retn
trim_output:
; preserves: ecx, esi
xor eax,eax
mov dword [prior_uninitialized_length],eax
mov dword [prior_uninitialized_length+4],eax
mov edi,[current_output_area_entry]
trim_current_output_area:
mov edx,[edi+OutputArea.definition]
mov eax,[edx+ValueDefinition.value]
and [eax+AreaHeader.uninitialized_length],0
mov ebx,[edx+ValueDefinition.value_length]
sub ebx,sizeof.AreaHeader
sub ebx,[eax+AreaHeader.base_address_length]
jnz output_trimmed
cmp edi,[initial_output_area_entry]
je output_trimmed
sub edi,sizeof.OutputArea
jmp trim_current_output_area
output_trimmed:
mov [current_output_area_entry],edi
retn
load_from_area:
; in:
; [value_length] = length of data to load
; edi - buffer for loaded data
; edx - ValueDefinition with VALTYPE_AREA
; [data_area_symbol] - SymbolTree_Leaf linked to the same ValueDefinition with update_value_link (required only for predicted loads, can be null)
; [data_offset] = offset within the area
; out:
; cf set when data could not be loaded
; when cf = 0, buffer filled with loaded data
; preserves: esi
mov eax,[edx+ValueDefinition.value]
mov ecx,[edx+ValueDefinition.pass]
cmp ecx,[current_pass]
je area_ok
test [eax+AreaHeader.flags],AREA_VARIABLE
jnz source_area_inaccessible
area_ok:
mov ebx,[data_offset]
add ebx,[eax+AreaHeader.base_address_length]
jc area_offset_unavailable
add ebx,sizeof.AreaHeader
jc area_offset_unavailable
mov ecx,[edx+ValueDefinition.value_length]
sub ecx,ebx
jb load_out_of_initialized_data
call prepare_load_length
jc area_offset_unavailable
xchg esi,ebx
add esi,eax
rep movsb
mov esi,ebx
cmp [value_length],0
je load_ok
mov ecx,[eax+AreaHeader.uninitialized_length]
jmp load_uninitialized_data
load_out_of_initialized_data:
add ecx,[eax+AreaHeader.uninitialized_length]
jc load_uninitialized_data
xor ecx,ecx
load_uninitialized_data:
call prepare_load_length
jc area_offset_unavailable
xor al,al
rep stosb
cmp [value_length],0
je load_ok
xor ebx,ebx
xchg ebx,[data_area_symbol]
test ebx,ebx
jz area_offset_unavailable
mov edx,[ebx+SymbolTree_Leaf.retired_definition]
test edx,edx
jz area_with_no_history
mov ecx,[current_pass]
sub ecx,[edx+ValueDefinition.pass]
cmp ecx,1
ja area_with_no_history
or [ebx+SymbolTree_Leaf.flags],SYM_LINK_PREDICTED
mov eax,[edx+ValueDefinition.value]
jmp load_from_area
prepare_load_length:
cmp ecx,[value_length]
jbe value_length_ok
mov ecx,[value_length]
value_length_ok:
add [data_offset],ecx
jc load_length_ready
sub [value_length],ecx
load_length_ready:
retn
source_area_inaccessible:
mov edx,_invalid_area
jmp load_failed
area_with_no_history:
or [next_pass_needed],1
area_offset_unavailable:
mov edx,_address_out_of_range
load_failed:
call register_error
stc
retn
load_ok:
clc
retn
prepare_area_to_write:
; in:
; [data_area] - ValueDefinition with VALTYPE_AREA
; [data_offset] = offset within the area
; [value_length] = length of data to be written
; out:
; cf set when writing specified length is not possible
; when cf = 0:
; edi - buffer for specified number of bytes directly within the area
; preserves: esi
mov edx,[data_area]
mov eax,[edx+ValueDefinition.value]
or [eax+AreaHeader.flags],AREA_VARIABLE
mov ebx,[data_offset]
xor ecx,ecx
add ebx,[eax+AreaHeader.base_address_length]
adc ecx,0
add ebx,sizeof.AreaHeader
adc ecx,0
add ebx,[value_length]
adc ecx,0
jnz write_outside_initialized_area
cmp ebx,[edx+ValueDefinition.value_length]
ja write_outside_initialized_area
lea edi,[eax+ebx]
mov ecx,[value_length]
sub edi,ecx
retn
area_to_write_not_accessible:
stc
retn
write_outside_initialized_area:
sub ebx,[edx+ValueDefinition.value_length]
sbb ecx,0
jnz write_outside_boundaries
sub [eax+AreaHeader.uninitialized_length],ebx
jnc extend_area
add [eax+AreaHeader.uninitialized_length],ebx
write_outside_boundaries:
push edx
mov edx,_address_out_of_range
call register_error
pop edx
test ecx,ecx
jnz area_to_write_not_accessible
test [eax+AreaHeader.flags],AREA_VIRTUAL
jz area_to_write_not_accessible
test [edx+ValueDefinition.flags],VAL_IN_USE
jnz area_to_write_not_accessible
and [eax+AreaHeader.uninitialized_length],0
extend_virtual_area:
call expand_value
jmp prepare_area_to_write
extend_area:
test [eax+AreaHeader.flags],AREA_VIRTUAL
jnz extend_virtual_area
call expand_value
call update_output_offsets
jmp prepare_area_to_write
find_output_area:
; in:
; [file_offset] = offset within the output
; out:
; cf set when not found an area that would contain a byte at specified offset
; when cf = 0:
; ebx - OutputArea
; [file_offset] = offset relative to the beginning of the found area (upper 32 bits are zero)
mov esi,[initial_output_area_entry]
mov edi,[current_output_area_entry]
add edi,sizeof.OutputArea
search_areas:
mov ebx,edi
sub ebx,esi
jz output_area_not_found
test ebx,1 shl bsf sizeof.OutputArea
jz bisect_areas_list
sub ebx,sizeof.OutputArea
bisect_areas_list:
shr ebx,1
add ebx,esi
mov eax,dword [file_offset]
mov edx,dword [file_offset+4]
sub eax,dword [ebx+OutputArea.cached_offset]
sbb edx,dword [ebx+OutputArea.cached_offset+4]
jc search_earlier_areas
jnz search_later_areas
mov edx,[ebx+OutputArea.definition]
mov ecx,[edx+ValueDefinition.value_length]
mov edx,[edx+ValueDefinition.value]
sub ecx,sizeof.AreaHeader
sub ecx,[edx+AreaHeader.base_address_length]
add ecx,[edx+AreaHeader.uninitialized_length]
cmp eax,ecx
jae search_later_areas
output_area_found:
mov dword [file_offset],eax
and dword [file_offset+4],0
; clc
retn
output_area_not_found:
stc
retn
search_later_areas:
lea esi,[ebx+sizeof.OutputArea]
jmp search_areas
search_earlier_areas:
mov edi,ebx
jmp search_areas
read_from_output:
; in:
; edi - buffer for read data
; [value_length] = length of data to read
; [file_offset] = offset within the output
; out:
; [value_length] = number of bytes that were not in the existing output and could not be read
push edi
call find_output_area
pop edi
jc output_reading_done
read_output_areas:
cmp [value_length],0
je output_reading_done
mov edx,[ebx+OutputArea.definition]
mov ecx,[edx+ValueDefinition.value_length]
mov eax,ecx
mov edx,[edx+ValueDefinition.value]
sub ecx,sizeof.AreaHeader
sub ecx,[edx+AreaHeader.base_address_length]
sub dword [file_offset],ecx
jnc initialized_load_done
lea esi,[edx+eax]
mov ecx,dword [file_offset]
add esi,ecx
neg ecx
cmp ecx,[value_length]
jbe initialized_load_length_ok
mov ecx,[value_length]
initialized_load_length_ok:
sub [value_length],ecx
rep movsb
mov dword [file_offset],ecx
initialized_load_done:
mov ecx,[edx+AreaHeader.uninitialized_length]
sub dword [file_offset],ecx
jnc uninitialized_load_done
mov ecx,dword [file_offset]
neg ecx
cmp ecx,[value_length]
jbe uninitialized_load_length_ok
mov ecx,[value_length]
uninitialized_load_length_ok:
sub [value_length],ecx
xor al,al
rep stosb
mov dword [file_offset],ecx
uninitialized_load_done:
cmp ebx,[current_output_area_entry]
je output_reading_done
add ebx,sizeof.OutputArea
jmp read_output_areas
output_reading_done:
retn
rewrite_output:
; in:
; esi - data to write
; [value_length] = length of data to write
; [file_offset] = offset within the output
; out:
; [value_length] = number of bytes that were not in the existing output and could not be rewritten
push esi
call find_output_area
pop esi
jc output_rewriting_done
rewrite_output_areas:
cmp [value_length],0
je output_rewriting_done
mov edx,[ebx+OutputArea.definition]
mov ecx,[edx+ValueDefinition.value_length]
mov edx,[edx+ValueDefinition.value]
sub ecx,sizeof.AreaHeader
sub ecx,[edx+AreaHeader.base_address_length]
mov edi,[edx+AreaHeader.uninitialized_length]
add ecx,edi
sub dword [file_offset],ecx
jnc rewrite_next_area
mov eax,[value_length]
xor ecx,ecx
add eax,edi
adc ecx,ecx
add eax,dword [file_offset]
adc ecx,0
jz rewrite_initialized_data
cmp eax,edi
jbe rewrite_uninitialized_data
mov eax,edi
rewrite_uninitialized_data:
test eax,eax
jz rewrite_initialized_data
push ebx
sub [edx+AreaHeader.uninitialized_length],eax
mov edx,[ebx+OutputArea.definition]
mov ebx,eax
call expand_value
call update_output_offsets
pop ebx
rewrite_initialized_data:
mov edx,[ebx+OutputArea.definition]
mov ecx,[edx+ValueDefinition.value_length]
mov edi,[edx+ValueDefinition.value]
or [edi+AreaHeader.flags],AREA_VARIABLE
add edi,[edi+AreaHeader.uninitialized_length]
add edi,ecx
mov ecx,dword [file_offset]
add edi,ecx
neg ecx
cmp ecx,[value_length]
jbe rewrite_length_ok
mov ecx,[value_length]
rewrite_length_ok:
sub [value_length],ecx
rep movsb
mov dword [file_offset],ecx
rewrite_next_area:
cmp ebx,[current_output_area_entry]
je output_rewriting_done
add ebx,sizeof.OutputArea
jmp rewrite_output_areas
output_rewriting_done:
retn
update_output_offsets:
; in:
; edx - ValueDefinition of output area that had some of uninitialized data made initialized
; preserves: esi
mov eax,[current_output_area_entry]
cmp edx,[eax+OutputArea.definition]
je output_offsets_ok
and dword [prior_uninitialized_length],0
and dword [prior_uninitialized_length+4],0
recount_prior_uninitialized_length:
cmp eax,[initial_output_area_entry]
je output_offsets_ok
sub eax,sizeof.OutputArea
mov edi,[eax+OutputArea.definition]
mov ebx,[edi+ValueDefinition.value]
mov ecx,[ebx+AreaHeader.uninitialized_length]
add dword [prior_uninitialized_length],ecx
adc dword [prior_uninitialized_length+4],0
cmp edx,edi
je output_offsets_ok
mov ecx,[edi+ValueDefinition.value_length]
sub ecx,sizeof.AreaHeader
sub ecx,[ebx+AreaHeader.base_address_length]
jz recount_prior_uninitialized_length
output_offsets_ok:
retn
get_current_address_value:
; out:
; esi - address in format of VALTYPE_NUMERIC value
; ecx = length of address value
; note: the returned value is placed in assembly workspace
mov eax,[current_area]
mov esi,[eax+ValueDefinition.value]
mov ebx,[eax+ValueDefinition.value_length]
mov edx,assembly_workspace
mov edi,[edx+Workspace.memory_start]
mov ecx,[esi+AreaHeader.base_address_length]
add ecx,4
call reserve_workspace
mov ecx,[esi+AreaHeader.base_address_length]
sub ebx,ecx
sub ebx,sizeof.AreaHeader
add ebx,[esi+AreaHeader.uninitialized_length]
; jc internal_error
add esi,sizeof.AreaHeader
xor eax,eax
stosd
lodsd
mov ecx,eax
xor edx,edx
jecxz offset_added_to_base_address
add_offset_to_base_address:
lodsb
add al,bl
setc dl
stosb
shr ebx,8
add ebx,edx
loop add_offset_to_base_address
offset_added_to_base_address:
mov edx,[assembly_workspace.memory_start]
add edx,4
mov eax,ebx
cmp byte [esi-1],80h
cmc
sbb eax,0
stosd
optimize_base_address:
movsx eax,byte [edi-2]
cmp ah,[edi-1]
jne base_address_ready
dec edi
cmp edi,edx
jne optimize_base_address
base_address_ready:
mov ecx,edi
sub ecx,edx
mov [edx-4],ecx
mov ecx,esi
measure_variable_terms:
lodsd
test eax,eax
jz variable_terms_measured
lodsd
add esi,eax
jmp measure_variable_terms
variable_terms_measured:
xchg ecx,esi
sub ecx,esi
rep movsb
mov esi,[assembly_workspace.memory_start]
mov ecx,edi
sub ecx,esi
retn
get_output_length:
; out:
; edx:eax = length of current output (not counting uninitialized data)
; preserves: esi
mov ebx,[current_output_area_entry]
mov eax,dword [ebx+OutputArea.cached_offset]
mov edx,dword [ebx+OutputArea.cached_offset+4]
mov edi,[ebx+OutputArea.definition]
mov ecx,[edi+ValueDefinition.value_length]
mov edi,[edi+ValueDefinition.value]
sub ecx,sizeof.AreaHeader
sub ecx,[edi+AreaHeader.base_address_length]
jz current_area_entirely_uninitialized
add eax,ecx
adc edx,0
retn
current_area_entirely_uninitialized:
sub eax,dword [prior_uninitialized_length]
sbb edx,dword [prior_uninitialized_length+4]
retn
get_output_position:
; out:
; edx:eax = current position in the output (including uninitialized data)
; preserves: esi
mov ebx,[current_output_area_entry]
mov eax,dword [ebx+OutputArea.cached_offset]
mov edx,dword [ebx+OutputArea.cached_offset+4]
mov edi,[ebx+OutputArea.definition]
mov ecx,[edi+ValueDefinition.value_length]
mov edi,[edi+ValueDefinition.value]
sub ecx,sizeof.AreaHeader
sub ecx,[edi+AreaHeader.base_address_length]
add ecx,[edi+AreaHeader.uninitialized_length]
add eax,ecx
adc edx,0
retn
create_output_path:
; in:
; ebx - base path and name
; esi - file extension
; ecx = length of the extension
; out:
; edx - output path (generated in temporary storage)
push ecx
mov edi,ebx
xor al,al
or ecx,-1
repne scasb
dec edi
mov ecx,edi
locate_extension:
cmp edi,ebx
je copy_path_name
dec edi
mov al,[edi]
cmp al,'\'
je copy_path_name
cmp al,'/'
je copy_path_name
cmp al,'.'
jne locate_extension
mov ecx,edi
copy_path_name:
sub ecx,ebx
push ecx
mov edi,[preprocessing_workspace.memory_start]
inc ecx
mov edx,preprocessing_workspace
call reserve_workspace
pop ecx
xchg esi,ebx
rep movsb
mov esi,ebx
pop ecx
mov ebx,ecx
add ecx,2
call reserve_workspace
mov ecx,ebx
jecxz extension_attached
mov al,'.'
stosb
rep movsb
extension_attached:
xor al,al
stosb
mov edx,[preprocessing_workspace.memory_start]
retn
write_output_file:
; in:
; ebx - source path
; edi - output path
; out:
; cf set when write failed
; note:
; when output path is null, source path is used with replaced or attached extension
mov [base_path],edi
xor eax,eax
mov [output_failures],eax
mov dword [uninitialized_length],eax
mov dword [uninitialized_length+4],eax
mov edx,edi
test edx,edx
jnz create_output_file
mov [base_path],ebx
mov esi,[output_extension]
mov ecx,[output_extension_length]
call create_output_path
create_output_file:
call create
jc output_write_failed
mov esi,[initial_output_area_entry]
write_area:
mov edx,[esi+OutputArea.definition]
mov eax,[edx+ValueDefinition.value]
mov ecx,[edx+ValueDefinition.value_length]
sub ecx,[eax+AreaHeader.base_address_length]
sub ecx,sizeof.AreaHeader
jz write_next_area
mov eax,dword [uninitialized_length]
or eax,dword [uninitialized_length+4]
jz write_initialized_data
write_uninitialized_data:
mov edi,[assembly_workspace.memory_start]
mov ecx,1000h shr 2
xor eax,eax
rep stosd
mov ecx,1000h
cmp dword [uninitialized_length+4],0
jne portion_length_ok
cmp ecx,dword [uninitialized_length]
jbe portion_length_ok
mov ecx,dword [uninitialized_length]
portion_length_ok:
sub dword [uninitialized_length],ecx
sbb dword [uninitialized_length+4],0
mov edx,[assembly_workspace.memory_start]
call write
jc file_write_failed
mov eax,dword [uninitialized_length]
or eax,dword [uninitialized_length+4]
jnz write_uninitialized_data
write_initialized_data:
mov edx,[esi+OutputArea.definition]
mov eax,[edx+ValueDefinition.value]
mov ecx,[edx+ValueDefinition.value_length]
mov edx,[eax+AreaHeader.base_address_length]
add edx,sizeof.AreaHeader
sub ecx,edx
add edx,eax
call write
jc file_write_failed
write_next_area:
mov edx,[esi+OutputArea.definition]
mov eax,[edx+ValueDefinition.value]
mov eax,[eax+AreaHeader.uninitialized_length]
add dword [uninitialized_length],eax
adc dword [uninitialized_length+4],0
cmp esi,[current_output_area_entry]
je close_output_file
add esi,sizeof.OutputArea
jmp write_area
close_output_file:
call close
mov ebx,[auxiliary_output_areas]
mov edi,write_auxiliary_output_area
call iterate_through_map
cmp [output_failures],0
jne output_write_failed
clc
retn
file_write_failed:
call close
output_write_failed:
stc
retn
write_auxiliary_output_area:
; in:
; eax = ValueDefinition, null for cached extension not used for auxiliary output
; esi - file extension
; ecx = length of the extension
test eax,eax
jz auxiliary_output_processed
mov ebx,[base_path]
test ebx,ebx
jz auxiliary_output_processed
push eax
call create_output_path
call create
pop edx
jc auxiliary_file_creation_failed
mov eax,[edx+ValueDefinition.value]
mov ecx,[edx+ValueDefinition.value_length]
mov edx,[eax+AreaHeader.base_address_length]
add edx,sizeof.AreaHeader
sub ecx,edx
add edx,eax
call write
jc auxiliary_file_write_failed
call close
auxiliary_output_processed:
retn
auxiliary_file_write_failed:
call close
auxiliary_file_creation_failed:
inc [output_failures]
retn

View File

@@ -0,0 +1,451 @@
; note:
; to not interfere with code resolving, all external input must stay unchanged
; in subsequent passes of the assembly; for this reason all data read from files is
; permanently cached (source texts are cached in tokenized form)
struct FileData
length dq ?
cache dd ? ; pointer to FileCache
ends
struct FileCache
offset dq ?
length dd ?
next dd ? ; pointer to another FileCache
ends
read_source:
; in:
; esi - source path
; out:
; eax - tokenized source, null when file not found
; esi - source path in persistent storage
mov ebx,[file_source_cache]
xor ecx,ecx
call get_from_map
jc read_source_file
cmp eax,-1
je get_erroneous_source
retn
read_source_file:
mov edx,esi
call open
jc source_file_not_found
xor eax,eax
mov edx,eax
mov cl,2
call lseek
jc error_reading_file
test edx,edx
jnz out_of_memory
push eax
xor eax,eax
mov edx,eax
mov cl,al
call lseek
jc error_reading_file
pop ecx
inc ecx
mov [source_text_length],ecx
call malloc
mov [source_text],eax
mov edx,eax
mov ecx,[source_text_length]
dec ecx
mov byte [edx+ecx],0
call read
jc error_reading_file
call close
push esi
call tokenize_source
mov eax,[source_text]
call mfree
pop esi
mov eax,[tokenization_buffer]
xor ecx,ecx
mov ebx,[file_source_cache]
call put_into_map
mov eax,[tokenization_buffer]
retn
source_file_not_found:
xor eax,eax
xor ecx,ecx
mov ebx,[file_source_cache]
call put_into_map
xor eax,eax
retn
error_reading_file:
or eax,-1
xor ecx,ecx
mov ebx,[file_source_cache]
call put_into_map
get_erroneous_source:
mov ebx,esi
mov edx,_error_reading_file
call register_error
mov eax,zero_value
retn
use_source:
; in:
; esi - ASCIIZ source string
; out:
; eax - tokenized source
; esi - source text in persistent storage
mov edi,esi
xor al,al
or ecx,-1
repne scasb
not ecx
mov [source_text_length],ecx
mov ebx,[memory_source_cache]
xor eax,eax
call get_from_map
jc adapt_memory_source
retn
adapt_memory_source:
mov [source_text],esi
call tokenize_source
mov eax,[tokenization_buffer]
mov esi,[source_text]
mov ecx,[source_text_length]
mov ebx,[memory_source_cache]
call put_into_map
mov eax,[tokenization_buffer]
retn
tokenize_source:
; in:
; [source_text] - ASCIIZ text
; [source_text_length] = length of text (including terminating character)
; out:
; [tokenization_buffer] - tokenized source
; [tokenization_buffer_length] = length of tokenized source
mov ecx,[source_text_length]
shl ecx,1
add ecx,18
call malloc_growable
mov [tokenization_buffer],eax
mov [tokenization_buffer_length],ecx
add eax,ecx
sub eax,[source_text]
sub eax,[source_text_length]
mov [buffer_end_offset],eax
mov esi,[source_text]
mov edi,[tokenization_buffer]
mov [last_token],0Ah
tokenize:
mov eax,[buffer_end_offset]
add eax,esi
sub eax,edi
cmp eax,18
jae tokenization_buffer_reserve_ok
mov ecx,esi
sub ecx,[source_text]
mov eax,[source_text_length]
mul [tokenization_buffer_length]
div ecx
mov ecx,eax
add ecx,18
mov eax,[tokenization_buffer]
call realloc
sub edi,[tokenization_buffer]
add edi,eax
mov [tokenization_buffer],eax
mov [tokenization_buffer_length],ecx
add eax,ecx
sub eax,[source_text]
sub eax,[source_text_length]
mov [buffer_end_offset],eax
tokenization_buffer_reserve_ok:
movzx eax,byte [esi]
inc esi
mov ah,[characters+eax]
cmp ah,20h
je control_character
test ah,ah
jnz make_name_token
character_token:
stosb
mov [last_token],al
jmp tokenize
make_string_token:
mov dl,al
mov byte [edi],22h
mov [last_token],22h
add edi,5
xor ecx,ecx
copy_string:
mov al,[esi]
cmp al,0Dh
je broken_string
cmp al,0Ah
je broken_string
cmp al,1Ah
je broken_string
test al,al
jz broken_string
inc esi
cmp al,dl
jne copy_string_character
cmp byte [esi],al
jne finish_string_token
inc esi
copy_string_character:
mov [edi+ecx],al
inc ecx
jmp copy_string
broken_string:
mov byte [edi-5],27h
finish_string_token:
mov al,[edi-5]
mov [edi-4],ecx
add edi,ecx
jmp tokenize
make_name_token:
cmp al,22h
je make_string_token
cmp al,27h
je make_string_token
mov byte [edi],1Ah
mov [last_token],1Ah
add edi,5
xor ebx,ebx
mov ecx,FNV_OFFSET
mov edx,ecx
hash_name:
mov [edi+ebx],al
inc ebx
xor cl,al
xor dl,ah
imul ecx,FNV_PRIME
imul edx,FNV_PRIME
movzx eax,byte [esi]
inc esi
mov ah,[characters+eax]
cmp ah,20h
je finish_name_token
test ah,ah
jnz hash_name
finish_name_token:
mov [edi-4],ebx
add edi,ebx
mov [edi],ecx
mov [edi+4],edx
xor ecx,ecx
mov [edi+8],ecx
add edi,12
cmp ah,20h
jne character_token
control_character:
cmp al,20h
je whitespace
cmp al,9
je whitespace
cmp [last_token],20h
je mark_end_of_line
inc edi
mark_end_of_line:
mov byte [edi-1],0Ah
mov [last_token],0Ah
cmp al,0Dh
je cr
cmp al,0Ah
je lf
xor al,al
stosb
mov ecx,edi
mov eax,[tokenization_buffer]
sub ecx,eax
call realloc
mov [tokenization_buffer],eax
mov [tokenization_buffer_length],ecx
retn
cr:
cmp byte [esi],0Ah
jne tokenize
inc esi
jmp tokenize
lf:
cmp byte [esi],0Dh
jne tokenize
inc esi
jmp tokenize
whitespace:
cmp [last_token],0Ah
je tokenize
cmp [last_token],20h
je tokenize
mov al,20h
stosb
mov [last_token],al
jmp tokenize
get_file_data:
; in:
; esi - file path
; out:
; ebx - FileData, null when file not found
; esi - file path in persistent storage
; preserves: edi
mov ebx,[file_data_cache]
xor ecx,ecx
call get_from_map
jc initialize_file_data
mov ebx,eax
retn
initialize_file_data:
mov edx,esi
call open
jc remember_file_not_found
push edi
mov ecx,sizeof.FileData
call malloc_fixed
mov edi,eax
xor eax,eax
mov edx,eax
mov cl,2
call lseek
jc file_not_seekable
mov dword [edi+FileData.length],eax
mov dword [edi+FileData.length+4],edx
call close
mov eax,edi
xor ecx,ecx
mov [eax+FileData.cache],ecx
mov ebx,[file_data_cache]
call put_into_map
mov ebx,edi
pop edi
retn
file_not_seekable:
pop edi
remember_file_not_found:
xor eax,eax
mov ecx,eax
mov ebx,[file_data_cache]
call put_into_map
xor ebx,ebx
retn
read_file_data:
; in:
; esi - file path
; ebx - FileData
; edi - buffer for data
; [file_offset] = offset of data
; [data_length] = length of data
; out:
; cf set when read failed
; preserves: esi
mov [file_data],ebx
lea eax,[ebx+FileData.cache]
mov [file_cache_pointer],eax
mov ebx,[eax]
read_from_file_cache:
mov ecx,[data_length]
test ecx,ecx
jz file_data_read
test ebx,ebx
jz new_trailing_file_cache_entry
mov eax,dword [file_offset]
mov edx,dword [file_offset+4]
sub eax,dword [ebx+FileCache.offset]
sbb edx,dword [ebx+FileCache.offset+4]
jc new_file_cache_entry
jnz next_entry
mov edx,[ebx+FileCache.length]
sub edx,eax
jbe next_entry
cmp ecx,edx
jbe length_to_read_ok
mov ecx,edx
length_to_read_ok:
sub [data_length],ecx
add dword [file_offset],ecx
adc dword [file_offset+4],0
mov edx,esi
lea esi,[ebx+sizeof.FileCache+eax]
rep movsb
mov esi,edx
next_entry:
lea eax,[ebx+FileCache.next]
mov [file_cache_pointer],eax
mov ebx,[eax]
jmp read_from_file_cache
file_data_read:
clc
retn
new_trailing_file_cache_entry:
mov ebx,[file_data]
mov ecx,dword [ebx+FileData.length]
mov edx,dword [ebx+FileData.length+4]
cmp ecx,dword [file_offset]
jne measure_cache_gap
cmp edx,dword [file_offset+4]
jne measure_cache_gap
stc
retn
new_file_cache_entry:
mov ecx,dword [ebx+FileCache.offset]
mov edx,dword [ebx+FileCache.offset+4]
measure_cache_gap:
mov eax,dword [file_offset]
and eax,not 0FFFh
sub ecx,eax
sbb edx,dword [file_offset+4]
jnz compute_aligned_length
cmp ecx,[data_length]
jbe read_into_cache
compute_aligned_length:
mov eax,dword [file_offset]
and eax,0FFFh
add eax,[data_length]
dec eax
shr eax,12
inc eax
shl eax,12
test edx,edx
jnz use_aligned_length
cmp eax,ecx
jae read_into_cache
use_aligned_length:
mov ecx,eax
read_into_cache:
push ecx
add ecx,sizeof.FileCache
call malloc_fixed
mov ebx,eax
mov eax,[file_cache_pointer]
mov edx,ebx
xchg edx,[eax]
mov [ebx+FileCache.next],edx
pop [ebx+FileCache.length]
mov eax,dword [file_offset]
and eax,not 0FFFh
mov edx,dword [file_offset+4]
mov dword [ebx+FileCache.offset],eax
mov dword [ebx+FileCache.offset+4],edx
push ebx edi
mov edi,ebx
mov edx,esi
call open
jc file_access_error
mov eax,dword [edi+FileCache.offset]
mov edx,dword [edi+FileCache.offset+4]
xor cl,cl
call lseek
jc file_access_error
lea edx,[edi+sizeof.FileCache]
mov ecx,[edi+FileCache.length]
call read
jc file_access_error
call close
pop edi ebx
jmp read_from_file_cache
file_access_error:
pop edi ebx
stc
retn

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,649 @@
OPERATOR_PRECEDENCE_MASK = 3Fh
OPERATOR_UNARY = 40h
OPERATOR_RIGHT_ASSOCIATIVE = 80h
SIZE_BYTE = 1
SIZE_WORD = 2
SIZE_DWORD = 4
SIZE_PWORD = 6
SIZE_QWORD = 8
SIZE_TWORD = 10
SIZE_DQWORD = 16
SIZE_QQWORD = 32
SIZE_DQQWORD = 64
PREPOSITION_AT = 0
PREPOSITION_FROM = 1
PREPOSITION_AS = 2
PREPOSITION_DUP = 3
control_characters db 0,9,0Ah,0Dh,1Ah,20h
.count = $-control_characters
syntactical_characters db '+-/*=<>()[]{}:?!,.|&~#`\;'
.count = $-syntactical_characters
include_variable db 'INCLUDE',0
separating_operators:
db '+',VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,1 + OPERATOR_UNARY
dd calculate_to_number
db '-',VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,1 + OPERATOR_UNARY
dd calculate_neg
db '+',VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,1
dd calculate_add
db '-',VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,1
dd calculate_sub
db '*',VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,2
dd calculate_mul
db '/',VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,2
dd calculate_div
db 0
symbols:
db 3,'not',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,6 + OPERATOR_UNARY
dd calculate_not
db 3,'mod',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,3
dd calculate_mod
db 3,'xor',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,4
dd calculate_xor
db 3,'and',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,4
dd calculate_and
db 2,'or',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,4
dd calculate_or
db 3,'shl',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,5
dd calculate_shl
db 3,'shr',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,5
dd calculate_shr
db 3,'bsf',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,6 + OPERATOR_UNARY
dd calculate_bsf
db 3,'bsr',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,6 + OPERATOR_UNARY
dd calculate_bsr
db 5,'bswap',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,5
dd calculate_bswap
db 7,'bappend',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,4
dd calculate_bappend
db 6,'string',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0 + OPERATOR_UNARY
dd calculate_to_string
db 5,'float',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,10 + OPERATOR_UNARY
dd calculate_to_float
db 5,'trunc',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,10 + OPERATOR_UNARY
dd extract_integer_part
db 6,'sizeof',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,10 + OPERATOR_UNARY
dd extract_size
db 8,'lengthof',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,10 + OPERATOR_UNARY
dd count_bytes
db 10,'elementsof',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,10 + OPERATOR_UNARY
dd count_elements
db 7,'element',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,7
dd extract_element
db 5,'scale',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,7
dd extract_scale
db 8,'metadata',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,7
dd extract_metadata
db 9,'elementof',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,8 + OPERATOR_RIGHT_ASSOCIATIVE
dd extract_element_reverse
db 7,'scaleof',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,8 + OPERATOR_RIGHT_ASSOCIATIVE
dd extract_scale_reverse
db 10,'metadataof',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,8 + OPERATOR_RIGHT_ASSOCIATIVE
dd extract_metadata_reverse
db 7,'element',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd define_element
db 3,'equ',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd define_symbolic_variable
db 5,'reequ',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd redefine_symbolic_variable
db 6,'define',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd define_raw_symbolic_variable
db 8,'redefine',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd redefine_raw_symbolic_variable
db 7,'restore',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SYMCLASS_EXPRESSION
dd restore_variables
db 9,'namespace',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd set_namespace
db 7,'display',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd display_data
db 3,'err',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd custom_error
db 7,'include',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd include_source
db 4,'eval',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd evaluate_string
db 6,'assert',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd assert_condition
db 7,'defined',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMPARATOR,VAL_INTERNAL,0
dd check_if_defined
db 4,'used',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMPARATOR,VAL_INTERNAL,0
dd check_if_used
db 8,'definite',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMPARATOR,VAL_INTERNAL,0
dd check_if_defined_earlier
db 6,'eqtype',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMPARATOR,VAL_INTERNAL,0
dd check_if_type_equal
db 2,'eq',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMPARATOR,VAL_INTERNAL,0
dd check_if_value_equal
db 10,'relativeto',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMPARATOR,VAL_INTERNAL,0
dd check_if_relative
db 2,'if',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd conditional_block
db 5,'match',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd match_block
db 6,'rmatch',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd raw_match_block
db 8,'rawmatch',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd raw_match_block
db 5,'while',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd conditionally_repeated_block
db 6,'repeat',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd repeated_block
db 7,'iterate',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd iterator_block
db 4,'rept',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd repeated_block
db 3,'irp',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd iterator_block
db 4,'irpv',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd variable_iterator_block
db 4,'indx',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd set_iterator_index
db 5,'break',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd break_directive
db 4,'else',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd else_directive
db 3,'end',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd end_directive
db 8,'postpone',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd postponed_block
db 5,'macro',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd define_macro
db 5,'struc',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd define_struc
db 3,'esc',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd escape_directive
db 5,'local',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd local_directive
db 8,'outscope',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd outscope_directive
db 5,'purge',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SYMCLASS_INSTRUCTION
dd restore_variables
db 7,'restruc',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SYMCLASS_STRUCTURE
dd restore_variables
db 7,'mvmacro',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SYMCLASS_INSTRUCTION
dd move_variable_values
db 7,'mvstruc',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SYMCLASS_STRUCTURE
dd move_variable_values
db 15,'calminstruction',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd define_calm_instruction
db 14,'removecomments',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd choose_to_remove_comments
db 14,'retaincomments',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd choose_to_retain_comments
db 12,'combinelines',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd choose_to_combine_lines
db 12,'isolatelines',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd choose_to_isolate_lines
db 3,'org',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd set_base_address
db 7,'section',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd begin_new_section
db 10,'restartout',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd restart_output
db 6,'format',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd format_directive
db 4,'emit',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd define_data
db 4,'emit',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd define_labeled_data
db 3,'dbx',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd define_data
db 3,'dbx',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd define_labeled_data
db 2,'db',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_BYTE
dd define_data
db 2,'db',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_BYTE
dd define_labeled_data
db 2,'dw',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_WORD
dd define_data
db 2,'dw',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_WORD
dd define_labeled_data
db 2,'dd',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_DWORD
dd define_data
db 2,'dd',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_DWORD
dd define_labeled_data
db 2,'dp',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_PWORD
dd define_data
db 2,'dp',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_PWORD
dd define_labeled_data
db 2,'dq',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_QWORD
dd define_data
db 2,'dq',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_QWORD
dd define_labeled_data
db 2,'dt',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_TWORD
dd define_data
db 2,'dt',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_TWORD
dd define_labeled_data
db 3,'ddq',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_DQWORD
dd define_data
db 3,'ddq',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_DQWORD
dd define_labeled_data
db 3,'dqq',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_QQWORD
dd define_data
db 3,'dqq',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_QQWORD
dd define_labeled_data
db 4,'ddqq',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_DQQWORD
dd define_data
db 4,'ddqq',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_DQQWORD
dd define_labeled_data
db 2,'rb',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_BYTE
dd reserve_data
db 2,'rb',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_BYTE
dd reserve_labeled_data
db 2,'rw',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_WORD
dd reserve_data
db 2,'rw',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_WORD
dd reserve_labeled_data
db 2,'rd',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_DWORD
dd reserve_data
db 2,'rd',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_DWORD
dd reserve_labeled_data
db 2,'rp',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_PWORD
dd reserve_data
db 2,'rp',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_PWORD
dd reserve_labeled_data
db 2,'rq',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_QWORD
dd reserve_data
db 2,'rq',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_QWORD
dd reserve_labeled_data
db 2,'rt',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_TWORD
dd reserve_data
db 2,'rt',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_TWORD
dd reserve_labeled_data
db 3,'rdq',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_DQWORD
dd reserve_data
db 3,'rdq',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_DQWORD
dd reserve_labeled_data
db 3,'rqq',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_QQWORD
dd reserve_data
db 3,'rqq',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_QQWORD
dd reserve_labeled_data
db 4,'rdqq',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_DQQWORD
dd reserve_data
db 4,'rdqq',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_DQQWORD
dd reserve_labeled_data
db 4,'file',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd include_data
db 4,'file',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd include_labeled_data
db 1,'$',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_FUNCTION,VAL_INTERNAL,0
dd current_address_value
db 2,'$$',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_FUNCTION,VAL_INTERNAL,0
dd base_address_value
db 2,'$@',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_FUNCTION,VAL_INTERNAL,0
dd truncated_address_value
db 2,'$%',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_FUNCTION,VAL_INTERNAL,0
dd current_position_value
db 3,'$%%',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_FUNCTION,VAL_INTERNAL,0
dd truncated_position_value
db 2,'%t',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_FUNCTION,VAL_INTERNAL,0
dd current_time_value
db 8,'__time__',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_FUNCTION,VAL_INTERNAL,0
dd current_time_value
db 10,'__source__',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_FUNCTION,VAL_INTERNAL,0
dd main_file_name_value
db 8,'__file__',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_FUNCTION,VAL_INTERNAL,0
dd current_file_name_value
db 8,'__line__',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_FUNCTION,VAL_INTERNAL,0
dd current_line_number_value
db 4,'byte',SYMCLASS_EXPRESSION,VALTYPE_PLAIN,VAL_INTERNAL,0
dd SIZE_BYTE
db 4,'word',SYMCLASS_EXPRESSION,VALTYPE_PLAIN,VAL_INTERNAL,0
dd SIZE_WORD
db 5,'dword',SYMCLASS_EXPRESSION,VALTYPE_PLAIN,VAL_INTERNAL,0
dd SIZE_DWORD
db 5,'pword',SYMCLASS_EXPRESSION,VALTYPE_PLAIN,VAL_INTERNAL,0
dd SIZE_PWORD
db 5,'fword',SYMCLASS_EXPRESSION,VALTYPE_PLAIN,VAL_INTERNAL,0
dd SIZE_PWORD
db 5,'qword',SYMCLASS_EXPRESSION,VALTYPE_PLAIN,VAL_INTERNAL,0
dd SIZE_QWORD
db 5,'tword',SYMCLASS_EXPRESSION,VALTYPE_PLAIN,VAL_INTERNAL,0
dd SIZE_TWORD
db 5,'tbyte',SYMCLASS_EXPRESSION,VALTYPE_PLAIN,VAL_INTERNAL,0
dd SIZE_TWORD
db 6,'dqword',SYMCLASS_EXPRESSION,VALTYPE_PLAIN,VAL_INTERNAL,0
dd SIZE_DQWORD
db 5,'xword',SYMCLASS_EXPRESSION,VALTYPE_PLAIN,VAL_INTERNAL,0
dd SIZE_DQWORD
db 6,'qqword',SYMCLASS_EXPRESSION,VALTYPE_PLAIN,VAL_INTERNAL,0
dd SIZE_QQWORD
db 5,'yword',SYMCLASS_EXPRESSION,VALTYPE_PLAIN,VAL_INTERNAL,0
dd SIZE_QQWORD
db 7,'dqqword',SYMCLASS_EXPRESSION,VALTYPE_PLAIN,VAL_INTERNAL,0
dd SIZE_DQQWORD
db 5,'zword',SYMCLASS_EXPRESSION,VALTYPE_PLAIN,VAL_INTERNAL,0
dd SIZE_DQQWORD
db 5,'label',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd label_directive
db 7,'virtual',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd virtual_block
db 4,'load',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd load_value
db 5,'store',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd store_value
db 2,'at',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_PREPOSITION,VAL_INTERNAL,0
dd PREPOSITION_AT
db 4,'from',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_PREPOSITION,VAL_INTERNAL,0
dd PREPOSITION_FROM
db 2,'as',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_PREPOSITION,VAL_INTERNAL,0
dd PREPOSITION_AS
db 3,'dup',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_PREPOSITION,VAL_INTERNAL,0
dd PREPOSITION_DUP
db 0
db 3,'end'
db 9,'namespace',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd end_namespace
db 2,'if',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd end_conditional_block
db 5,'match',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd end_match_block
db 6,'rmatch',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd end_raw_match_block
db 8,'rawmatch',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd end_raw_match_block
db 5,'while',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd end_conditionally_repeated_block
db 6,'repeat',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd end_repeated_block
db 7,'iterate',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd end_iterator_block
db 4,'rept',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd end_repeated_block
db 3,'irp',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd end_iterator_block
db 4,'irpv',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd end_variable_iterator_block
db 8,'postpone',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd end_postponed_block
db 5,'macro',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd end_macro
db 5,'struc',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd end_struc
db 7,'virtual',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd end_virtual_block
db 0
db 4,'else'
db 2,'if',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd else_conditional_block
db 5,'match',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd else_match_block
db 6,'rmatch',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd else_raw_match_block
db 8,'rawmatch',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd else_raw_match_block
db 0
db 6,'format'
db 6,'binary',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd format_binary
db 0
db 15,'calminstruction'
db 5,'local',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_local
db 7,'arrange',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_arrange
db 5,'match',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_match
db 8,'assemble',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_assemble
db 9,'transform',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_transform
db 9,'stringify',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_stringify
db 7,'publish',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_publish
db 4,'take',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_take
db 7,'compute',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_compute
db 5,'check',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_check
db 4,'emit',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_emit
db 4,'load',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_load
db 5,'store',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_store
db 7,'display',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_display
db 3,'err',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_err
db 4,'jyes',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_jyes
db 3,'jno',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_jno
db 4,'jump',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_jump
db 4,'call',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_call
db 4,'exit',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_exit
db 3,'end',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd alm_end
db 15,'calminstruction',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_end
db 0
zero_value dd 0
dd 0
singular_value dd 1
db 1
dd 0
subtraction_operator dd EXPR_OPERATOR,calculate_sub
dd 0

View File

@@ -0,0 +1,314 @@
characters db 256 dup ?
maximum_number_of_errors dd ?
maximum_depth_of_stack dd ?
variables:
temporary_value dd 4 dup ?
accumulator dd 3 dup ?
source_file dd ?
include_paths dd ?
storage_blocks dd ?
storage_free_space dd ?
storage_free_space_length dd ?
tree_blocks dd ?
tree_reserve dd ?
tree_reserve_length dd ?
value_definition_chain dd ?
retired_definition dd ?
file_source_cache dd ?
memory_source_cache dd ?
file_data_cache dd ?
operator_table dd ?
root_namespace dd ?
root_parameter_namespace dd ?
local_parameter_namespace dd ?
interceptor_symbol dd ?
label_interceptor_symbol dd ?
other_interceptor_symbol dd ?
proxy_number dd ?
source_context dd ?
source_context_maximum_length dd ?
current_pass dd ?
current_context RecognitionContext
local_namespace dd ?
parameter_namespace dd ?
directives_stack dd ?
directives_stack_base dd ?
directives_stack_end dd ?
current_counter dd ?
counters_stack_base dd ?
counters_stack_end dd ?
first_error dd ?
current_area dd ?
output_areas_list dd ?
output_areas_list_end dd ?
initial_output_area_entry dd ?
current_output_area_entry dd ?
prior_uninitialized_length dq ?
virtual_area dd ?
auxiliary_output_areas dd ?
void_symbol dd ?
base_path dd ?
output_extension dd ?
output_extension_length dd ?
output_failures dd ?
preprocessing_workspace Workspace
assembly_workspace Workspace
identifier_workspace Workspace
value_workspace Workspace
expression_workspace Workspace
calculation_workspace Workspace
auxiliary_workspace Workspace
line_start dd ?
line_end dd ?
line_embeddings dd ?
line_embeddings_maximum_length dd ?
number_of_line_embeddings dd ?
preprocessed_context dd ?
line_context dd ?
embedded_context dd ?
number_of_enclosings dd ?
recognition_context RecognitionContext
name_token dd ?
case_sensitive_hash dd ?
case_insensitive_hash dd ?
kept_symbol dd ?
current_symbol dd ?
tree_stack_base dd ?
tree_stack_end dd ?
symbol_root dd ?
symbol_branch dd ?
minor_identifier dd ?
source_end dd ?
symbol_start dd ?
symbol_data dd ?
symbol_value_start dd ?
symbol_value_end dd ?
interceptor dd ?
label_branch dd ?
label_leaf dd ?
label_interceptor dd ?
label_instruction_start dd ?
label_instruction_context dd ?
display_buffer dd ?
display_buffer_length dd ?
display_data_length dd ?
macro_buffer dd ?
macro_buffer_length dd ?
macro_leaf dd ?
macro_end_position dd ?
constituent_symbol dd ?
constituent_value dd ?
constituent_whitespace dd ?
alm_namespace dd ?
alm_adjusted_context RecognitionContext
calm_code_buffer Workspace
calm_code_cursor dd ?
calm_literals_buffer Workspace
calm_literals_cursor dd ?
calm_auxiliary_buffer Workspace
calm_auxiliary_cursor dd ?
calm_line_number dd ?
calm_instruction_number dd ?
calm_value dd ?
calm_literals dd ?
calm_source_pointer dd ?
calm_rollback_offset dd ?
value_position dd ?
kept_value dd ?
converter_position dd ?
expression_position dd ?
expression_end dd ?
operator_stack dd ?
operator_stack_position dd ?
operator_stack_base dd ?
operator_stack_end dd ?
calculation_position dd ?
source_term dd ?
destination_term dd ?
temporary_terms dd ?
free_temporary_terms dd ?
temporary_floats dd ?
iterations dd ?
exponent dd ?
multiplier dd ?
divisor dd ?
long_dividend_term dd ?
long_divisor_term dd ?
long_divisor_length dd ?
division_temporary_terms dd ?
mantissa_tail dd ?
predicted_shift dd ?
subexpression_end dd ?
condition_stack dd ?
condition_stack_base dd ?
condition_stack_end dd ?
initial_parentheses dd ?
comparator dd ?
outer_expression dd ?
assembly_stack_base dd ?
assembly_stack_end dd ?
previous_symbol_end dd ?
further_whitespace dd ?
zero_digits dd ?
decimal_places dd ?
literal_exponent dd ?
update_function dd ?
argument_start dd ?
macro_parameters_context dd ?
new_local_namespace dd ?
file_name dd ?
string_end dd ?
message_end dd ?
data_area_symbol dd ?
data_area dd ?
data_offset dd ?
file_offset dq ?
data_length dd ?
local_path dd ?
error_line_start dd ?
error_line_end dd ?
error_symbol dd ?
last_source_entry dd ?
last_file_source_entry dd ?
preprocessed_text_end dd ?
source_text dd ?
source_text_length dd ?
tokenization_buffer dd ?
tokenization_buffer_length dd ?
buffer_end_offset dd ?
file_data dd ?
file_cache_pointer dd ?
address_length dd ?
data_unit_length dd ?
uninitialized_length dq ?
directive_block dd ?
number_of_iterations dd ?
number_of_parameters dd ?
number_of_values dd ?
parameter_index dd ?
value_index dd ?
value dd ?
value_length dd ?
metadata_length dd ?
sequence_header_cursor dd ?
sequence_header_length dd ?
expression_sequence_cursor dd ?
expression_sequence_end dd ?
context_boundary dd ?
whitespace_boundary dd ?
transforming_namespace dd ?
pattern_start dd ?
pattern_end dd ?
matched_context dd ?
substitutions_end dd ?
stored_position dd ?
stored_substitution dd ?
stored_context dd ?
stored_pattern dd ?
brackets dd ?
instruction_value dd ?
instruction_branch dd ?
instruction_body dd ?
number_of_lines dd ?
preprocessing_mode db ?
assembly_mode db ?
next_pass_needed db ?
shift_tracking db ?
name_kind db ?
name_volatile db ?
symbol_class db ?
symbol_required db ?
symbol_expected db ?
kept_symbol_flags db ?
chosen_class db ?
expected_class db ?
symbol_definition db ?
symbol_independent db ?
recognizer_setting db ?
label_independent db ?
value_type db ?
waiting_for_digit db ?
literal_exponent_sign db ?
literal_fractional_part db ?
float_literal_status db ?
use_raw_values db ?
last_token db ?
breakpoint_token db ?
current_constituent db ?
kept_value_in_workspace db ?
leave_opening_parentheses db ?
operator_argument_expected db ?
term_type db ?
bit_shift db ?
shift_overflow db ?
multiplier_sign db ?
high_bits_count db ?
first_sign db ?
second_sign db ?
comparator_priority db ?
result_type db ?
defined_element db ?
source_context_affected db ?
raw_value db ?
substitution_active db ?
stored_substitution_activity db ?
unprocessed_matching db ?
whitespace_matching db ?
macro_definition_active db ?
macro_flags db ?
macro_greedy db ?
calm_definition_active db ?
size_specified db ?
message_volatile db ?
displayed_byte db ?
alm_statement db ?
calm_result db ?
hidden_context db ?
contextless_processing db ?
variables_end:
trace_mode db ?

View File

@@ -0,0 +1 @@
VERSION equ "kl0e"

View File

@@ -0,0 +1,255 @@
include 'win32a.inc'
match ,{
include 'localptr.inc'
} match -,{
else
include 'localptr.alm'
end match
_ equ }
format PE large NX DLL
entry DllEntryPoint
include '../../version.inc'
struct MEMORY_REGION
address dd ?
size dd ?
ends
section '.text' code executable
include '../../assembler.inc'
include '../../symbols.inc'
include '../../expressions.inc'
include '../../conditions.inc'
include '../../floats.inc'
include '../../directives.inc'
include '../../calm.inc'
include '../../errors.inc'
include '../../map.inc'
include '../../reader.inc'
include '../../output.inc'
include '../../console.inc'
DllEntryPoint:
mov eax,1
retn 12
fasmg_GetVersion:
mov eax,version_string
retn
fasmg_Assemble:
virtual at ebp - LOCAL_VARIABLES_SIZE
LocalVariables:
include '../../variables.inc'
maximum_number_of_passes dd ?
timestamp dq ?
systemtime SYSTEMTIME
filetime FILETIME
memory dd ?
systmp dd ?
rb (LocalVariables - $) and 11b
LOCAL_VARIABLES_SIZE = $ - LocalVariables
assert $ - ebp = 0
previous_frame dd ?
stored_edi dd ?
stored_esi dd ?
stored_ebx dd ?
return_address dd ?
FunctionParameters:
source_string dd ?
source_path dd ?
output_region dd ?
output_path dd ?
stdout dd ?
stderr dd ?
FUNCTION_PARAMETERS_SIZE = $ - FunctionParameters
end virtual
push ebx esi edi
enter LOCAL_VARIABLES_SIZE,0
call system_init
mov [maximum_number_of_passes],100
mov [maximum_number_of_errors],1000
mov [maximum_depth_of_stack],10000
xor al,al
call assembly_init
assemble:
mov esi,[source_string]
mov edx,[source_path]
call assembly_pass
jc assembly_done
mov eax,[current_pass]
cmp eax,[maximum_number_of_passes]
jb assemble
call show_display_data
call assembly_shutdown
call system_shutdown
mov eax,-2
leave
pop edi esi ebx
retn FUNCTION_PARAMETERS_SIZE
assembly_done:
call show_display_data
cmp [first_error],0
jne assembly_failed
mov esi,[output_region]
test esi,esi
jz output_copied
call get_output_length
test edx,edx
jnz out_of_memory
mov [value_length],eax
xchg eax,[esi+MEMORY_REGION.size]
cmp [esi+MEMORY_REGION.address],0
je new_region_for_output
cmp eax,[value_length]
jae copy_output
invoke VirtualAlloc,[esi+MEMORY_REGION.address],[esi+MEMORY_REGION.size],MEM_COMMIT,PAGE_READWRITE
test eax,eax
jnz copy_output
invoke VirtualFree,[esi+MEMORY_REGION.address],0,MEM_RELEASE
new_region_for_output:
invoke VirtualAlloc,0,[esi+MEMORY_REGION.size],MEM_COMMIT,PAGE_READWRITE
test eax,eax
jz out_of_memory
mov [esi+MEMORY_REGION.address],eax
copy_output:
mov edi,[esi+MEMORY_REGION.address]
xor eax,eax
mov dword [file_offset],eax
mov dword [file_offset+4],eax
call read_from_output
output_copied:
mov ebx,[source_path]
mov edi,[output_path]
mov eax,ebx
or eax,edi
jz output_written
call write_output_file
jc write_failed
output_written:
call assembly_shutdown
call system_shutdown
xor eax,eax
leave
pop edi esi ebx
retn FUNCTION_PARAMETERS_SIZE
assembly_failed:
mov eax,[first_error]
xor ecx,ecx
count_errors:
inc ecx
mov eax,[eax+Error.next]
test eax,eax
jnz count_errors
push ecx
call show_errors
call assembly_shutdown
call system_shutdown
pop eax
leave
pop edi esi ebx
retn FUNCTION_PARAMETERS_SIZE
write_failed:
call assembly_shutdown
call system_shutdown
mov eax,-3
leave
pop edi esi ebx
retn FUNCTION_PARAMETERS_SIZE
out_of_memory:
call assembly_shutdown
call system_shutdown
mov eax,-1
leave
pop edi esi ebx
retn FUNCTION_PARAMETERS_SIZE
include 'system.inc'
section '.rdata' data readable
data import
library kernel32,'KERNEL32.DLL'
import kernel32,\
CloseHandle,'CloseHandle',\
CreateFile,'CreateFileA',\
ExitProcess,'ExitProcess',\
GetCommandLine,'GetCommandLineA',\
GetEnvironmentVariable,'GetEnvironmentVariableA',\
GetStdHandle,'GetStdHandle',\
GetSystemTime,'GetSystemTime',\
GetTickCount,'GetTickCount',\
HeapAlloc,'HeapAlloc',\
HeapCreate,'HeapCreate',\
HeapDestroy,'HeapDestroy',\
HeapFree,'HeapFree',\
HeapReAlloc,'HeapReAlloc',\
HeapSize,'HeapSize',\
VirtualAlloc,'VirtualAlloc',\
VirtualFree,'VirtualFree',\
ReadFile,'ReadFile',\
SetFilePointer,'SetFilePointer',\
SystemTimeToFileTime,'SystemTimeToFileTime',\
WriteFile,'WriteFile',\
GetLastError,'GetLastError'
end data
align 4
data export
export 'FASMG.DLL',\
fasmg_GetVersion,'fasmg_GetVersion',\
fasmg_Assemble,'fasmg_Assemble'
end data
include '../../tables.inc'
include '../../messages.inc'
version_string db VERSION,0
section '.reloc' fixups data readable discardable

View File

@@ -0,0 +1,34 @@
calminstruction push? arg*&
local tmp, more
match =dword? arg, arg
jno regular
match tmp], arg
jyes regular
check arg relativeto ebp & arg - ebp
jno regular
arrange tmp, =push =eax
assemble tmp
arrange tmp, =lea =eax,[arg]
assemble tmp
arrange tmp, =xchg =eax,[=esp]
assemble tmp
exit
regular:
arrange tmp, =push arg
assemble tmp
end calminstruction
calminstruction mov? dest*,src*
local tmp
match tmp], src
jyes regular
check src relativeto ebp & src - ebp
jno regular
arrange tmp, =lea dest,[src]
assemble tmp
exit
regular:
arrange tmp, =mov dest,src
assemble tmp
end calminstruction

View File

@@ -0,0 +1,28 @@
macro pushd arg
{
if arg eqtype +ebp & arg relativeto ebp
if arg - ebp
push eax
lea eax,[arg]
xchg eax,[esp]
else
push ebp
end if
else if ~ arg eq
pushd arg
end if
}
macro mov dest,src
{
if src eqtype +ebp & src relativeto ebp
if src - ebp
lea dest,[src]
else
mov dest,ebp
end if
else
mov dest,src
end if
}

View File

@@ -0,0 +1,214 @@
LINE_FEED equ 13,10
system_init:
invoke HeapCreate,0,20000h,0
mov [memory],eax
test eax,eax
jz out_of_memory
invoke GetSystemTime,systemtime
invoke SystemTimeToFileTime,systemtime,filetime
mov ebx,[filetime.dwLowDateTime]
mov eax,[filetime.dwHighDateTime]
sub ebx,116444736000000000 and 0FFFFFFFFh
sbb eax,116444736000000000 shr 32
xor edx,edx
mov ecx,10000000
div ecx
mov dword [timestamp+4],eax
mov eax,ebx
div ecx
mov dword [timestamp],eax
retn
system_shutdown:
cmp [memory],0
je memory_released
invoke HeapDestroy,[memory]
memory_released:
retn
malloc:
malloc_fixed:
malloc_growable:
; in: ecx = requested size
; out: eax - allocated block, ecx = allocated size, on error jumps to out_of_memory (does not return)
; preserves: ebx, esi, edi
; note:
; use of malloc_fixed hints that block will be kept as is until the end of assembly
; use of malloc_growable hints that block is likely to be resized
invoke HeapAlloc,[memory],0,ecx
test eax,eax
jz out_of_memory
memory_allocated:
push eax
invoke HeapSize,[memory],0,eax
mov ecx,eax
pop eax
cmp ecx,-1
je out_of_memory
retn
realloc:
; in: eax - memory block, ecx = requested size
; out: eax - resized block, ecx = allocated size, on error jumps to out_of_memory (does not return)
; preserves: ebx, esi, edi
invoke HeapReAlloc,[memory],0,eax,ecx
test eax,eax
jnz memory_allocated
jmp out_of_memory
mfree:
; in: eax - memory block
; out: cf set on error
; preserves: ebx, esi, edi
; note: eax may have value 0 or -1, it should be treated as invalid input then
test eax,eax
jz interface_error
cmp eax,-1
je interface_error
invoke HeapFree,[memory],0,eax
test eax,eax
jz interface_error
clc
retn
interface_error:
stc
retn
open:
; in: edx - path to file
; out: ebx = file handle, cf set on error
; preserves: esi, edi
invoke CreateFile,edx,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0
cmp eax,-1
je interface_error
mov ebx,eax
clc
retn
create:
; in: edx - path to file
; out: ebx = file handle, cf set on error
; preserves: esi, edi
invoke CreateFile,edx,GENERIC_WRITE,0,0,CREATE_ALWAYS,0,0
cmp eax,-1
je interface_error
mov ebx,eax
clc
retn
write:
; in: ebx = file handle, edx - data, ecx = number of bytes
; out: cf set on error
; preserves: ebx, esi, edi
push ecx
invoke WriteFile,ebx,edx,ecx,systmp,0
pop ecx
test eax,eax
jz interface_error
cmp ecx,[systmp]
jne interface_error
clc
retn
read:
; in: ebx = file handle, edx - buffer, ecx = number of bytes
; out: cf set on error
; preserves: ebx, esi, edi
push ecx
invoke ReadFile,ebx,edx,ecx,systmp,0
pop ecx
test eax,eax
jz interface_error
cmp ecx,[systmp]
jne interface_error
clc
retn
close:
; in: ebx = file handle
; preserves: ebx, esi, edi
invoke CloseHandle,ebx
retn
lseek:
; in: ebx = file handle, cl = method, edx:eax = offset
; out: edx:eax = new offset from the beginning of file, cf set on error
; preserves: ebx, esi, edi
movzx ecx,cl
mov [systmp],edx
invoke SetFilePointer,ebx,eax,systmp,ecx
cmp eax,-1
jne lseek_ok
invoke GetLastError
test eax,eax
jnz interface_error
not eax
lseek_ok:
mov edx,[systmp]
clc
retn
get_timestamp:
; out: edx:eax = timestamp
; preserves: ebx, ecx, esi, edi
; note: during the passes of a single assembly this function should always return the same value
mov eax,dword [timestamp]
mov edx,dword [timestamp+4]
retn
display_string:
; in:
; esi - string
; ecx = string length, zero for ASCIIZ string
; preserves: ebx, esi
push ebx
mov ebx,[stdout]
jmp write_string
display_error_string:
; in:
; esi - string
; ecx = string length, zero for ASCIIZ string
; preserves: ebx, esi
push ebx
mov ebx,[stderr]
write_string:
test ebx,ebx
jz hidden_display
test ecx,ecx
jnz write_string_to_stdout
xor al,al
mov edi,esi
or ecx,-1
repne scasb
neg ecx
sub ecx,2
write_string_to_stdout:
mov edx,esi
write_portion_to_stdout:
mov eax,51200
cmp ecx,eax
jbe final_write_to_stdout
sub ecx,eax
add eax,edx
push eax ecx
invoke WriteFile,ebx,edx,51200,systmp,0
pop ecx edx
jmp write_portion_to_stdout
final_write_to_stdout:
invoke WriteFile,ebx,edx,ecx,systmp,0
hidden_display:
pop ebx
retn
get_environment_variable:
; in:
; esi - name
; edi - buffer for value
; ecx = size of buffer
; out:
; eax = length of value
; preserves: ebx, esi, edi
push ecx
invoke GetEnvironmentVariable,esi,edi,ecx
pop ecx
cmp eax,ecx
jae environment_variable_ready
mov byte [edi+eax],0
environment_variable_ready:
inc eax
retn

View File

@@ -0,0 +1,520 @@
include 'win32a.inc'
format PE large NX console 4.0
entry start
include '../version.inc'
PE.Settings.Stamp = +VERSION
section '.text' code executable
include 'system.inc'
start:
call system_init
call get_arguments
mov bl,al
cmp [no_logo],0
jne logo_ok
mov esi,_logo
xor ecx,ecx
call display_string
logo_ok:
test bl,bl
jnz display_usage_information
xor al,al
movzx ecx,[verbosity_level]
jecxz init
or al,TRACE_ERROR_STACK
dec ecx
jz init
or al,TRACE_DISPLAY
init:
call assembly_init
invoke GetTickCount
mov [timer],eax
assemble:
mov esi,[initial_commands]
mov edx,[source_path]
call assembly_pass
jc assembly_done
mov eax,[current_pass]
cmp eax,[maximum_number_of_passes]
jb assemble
call show_display_data
mov esi,_error_prefix
xor ecx,ecx
call display_error_string
mov esi,_code_cannot_be_generated
xor ecx,ecx
call display_error_string
mov esi,_message_suffix
xor ecx,ecx
call display_error_string
jmp assembly_failed
assembly_done:
call show_display_data
cmp [first_error],0
jne assembly_failed
cmp [no_logo],0
jne summary_done
mov eax,[current_pass]
xor edx,edx
call itoa
call display_string
mov esi,_passes
cmp [current_pass],1
jne display_passes_suffix
mov esi,_pass
display_passes_suffix:
xor ecx,ecx
call display_string
invoke GetTickCount
sub eax,[timer]
xor edx,edx
add eax,50
mov ecx,1000
div ecx
mov ebx,eax
mov eax,edx
xor edx,edx
mov ecx,100
div ecx
mov [timer],eax
xchg eax,ebx
or ebx,eax
jz display_output_length
xor edx,edx
call itoa
call display_string
mov esi,_message_suffix
mov ecx,1
call display_string
mov eax,[timer]
xor edx,edx
call itoa
call display_string
mov esi,_seconds
xor ecx,ecx
call display_string
display_output_length:
call get_output_length
push eax edx
call itoa
call display_string
pop edx eax
mov esi,_bytes
cmp eax,1
jne display_bytes_suffix
test edx,edx
jnz display_bytes_suffix
mov esi,_byte
display_bytes_suffix:
xor ecx,ecx
call display_string
mov esi,_new_line
xor ecx,ecx
call display_string
summary_done:
mov ebx,[source_path]
mov edi,[output_path]
call write_output_file
jc write_failed
call assembly_shutdown
call system_shutdown
invoke ExitProcess,0
assembly_failed:
call show_errors
call assembly_shutdown
call system_shutdown
invoke ExitProcess,2
write_failed:
mov ebx,_write_failed
jmp fatal_error
out_of_memory:
mov ebx,_out_of_memory
jmp fatal_error
fatal_error:
mov esi,_error_prefix
xor ecx,ecx
call display_error_string
mov esi,ebx
xor ecx,ecx
call display_error_string
mov esi,_message_suffix
xor ecx,ecx
call display_error_string
call assembly_shutdown
call system_shutdown
invoke ExitProcess,3
display_usage_information:
mov esi,_usage
xor ecx,ecx
call display_string
call system_shutdown
invoke ExitProcess,1
get_arguments:
xor eax,eax
mov [initial_commands],eax
mov [source_path],eax
mov [output_path],eax
mov [no_logo],al
mov [verbosity_level],al
mov [maximum_number_of_passes],100
mov [maximum_number_of_errors],1
mov [maximum_depth_of_stack],10000
invoke GetCommandLine
mov esi,eax
mov edi,eax
or ecx,-1
xor al,al
repne scasb
sub edi,esi
mov ecx,edi
call malloc
mov edi,eax
get_argument:
xor ah,ah
read_character:
lodsb
test al,al
jz no_more_arguments
cmp al,22h
je switch_quote
cmp ax,20h
je end_argument
stosb
jmp read_character
end_argument:
xor al,al
stosb
find_next_argument:
mov al,[esi]
test al,al
jz no_more_arguments
cmp al,20h
jne next_argument_found
inc esi
jmp find_next_argument
switch_quote:
xor ah,1
jmp read_character
next_argument_found:
cmp al,'-'
je get_option
cmp al,'/'
je get_option
cmp [source_path],0
je get_source_path
cmp [output_path],0
je get_output_path
error_in_arguments:
or al,-1
retn
get_source_path:
mov [source_path],edi
jmp get_argument
get_output_path:
mov [output_path],edi
jmp get_argument
no_more_arguments:
cmp [source_path],0
je error_in_arguments
xor al,al
stosb
retn
get_option:
inc esi
lodsb
cmp al,'e'
je set_errors_limit
cmp al,'E'
je set_errors_limit
cmp al,'i'
je insert_initial_command
cmp al,'I'
je insert_initial_command
cmp al,'p'
je set_passes_limit
cmp al,'P'
je set_passes_limit
cmp al,'r'
je set_recursion_limit
cmp al,'R'
je set_recursion_limit
cmp al,'v'
je set_verbose_mode
cmp al,'V'
je set_verbose_mode
cmp al,'n'
je set_no_logo
cmp al,'N'
jne error_in_arguments
set_no_logo:
or [no_logo],-1
mov al,[esi]
cmp al,20h
je find_next_argument
test al,al
jnz error_in_arguments
jmp find_next_argument
set_verbose_mode:
call get_option_value
jc error_in_arguments
cmp edx,2
ja error_in_arguments
mov [verbosity_level],dl
jmp find_next_argument
set_errors_limit:
call get_option_value
jc error_in_arguments
test edx,edx
jz error_in_arguments
mov [maximum_number_of_errors],edx
jmp find_next_argument
set_recursion_limit:
call get_option_value
jc error_in_arguments
test edx,edx
jz error_in_arguments
mov [maximum_depth_of_stack],edx
jmp find_next_argument
set_passes_limit:
call get_option_value
jc error_in_arguments
test edx,edx
jz error_in_arguments
mov [maximum_number_of_passes],edx
jmp find_next_argument
get_option_value:
xor eax,eax
mov edx,eax
find_option_value:
cmp byte [esi],20h
jne get_option_digit
inc esi
jmp find_option_value
get_option_digit:
lodsb
cmp al,20h
je option_value_ok
test al,al
jz option_value_ok
sub al,30h
jc invalid_option_value
cmp al,9
ja invalid_option_value
imul edx,10
jo invalid_option_value
add edx,eax
jc invalid_option_value
jmp get_option_digit
option_value_ok:
dec esi
clc
ret
invalid_option_value:
stc
ret
insert_initial_command:
push edi
find_command_segment:
cmp byte [esi],20h
jne command_segment_found
inc esi
jmp find_command_segment
command_segment_found:
xor ah,ah
cmp byte [esi],22h
jne measure_command_segment
inc esi
inc ah
measure_command_segment:
mov ebx,esi
scan_command_segment:
mov ecx,esi
mov al,[esi]
test al,al
jz command_segment_measured
cmp ax,20h
je command_segment_measured
cmp ax,22h
je command_segment_measured
inc esi
cmp al,22h
jne scan_command_segment
command_segment_measured:
sub ecx,ebx
mov edi,[initial_commands]
lea eax,[ecx+2]
test edi,edi
jz allocate_initial_commands_buffer
mov edx,[initial_commands_length]
add edi,edx
add eax,edx
cmp eax,[initial_commands_maximum_length]
ja grow_initial_commands_buffer
copy_initial_command:
xchg esi,ebx
rep movsb
mov esi,ebx
sub edi,[initial_commands]
mov [initial_commands_length],edi
mov al,[esi]
test al,al
jz initial_command_ready
cmp al,20h
jne command_segment_found
initial_command_ready:
mov edi,[initial_commands]
add edi,[initial_commands_length]
mov ax,0Ah
stosw
inc [initial_commands_length]
pop edi
jmp find_next_argument
allocate_initial_commands_buffer:
push ecx
mov ecx,eax
call malloc
mov [initial_commands],eax
mov [initial_commands_maximum_length],ecx
mov edi,eax
pop ecx
jmp copy_initial_command
grow_initial_commands_buffer:
push ecx
mov ecx,eax
mov eax,[initial_commands]
call realloc
mov [initial_commands],eax
mov [initial_commands_maximum_length],ecx
mov edi,eax
add edi,[initial_commands_length]
pop ecx
jmp copy_initial_command
include '../symbols.inc'
include '../assembler.inc'
include '../expressions.inc'
include '../conditions.inc'
include '../floats.inc'
include '../directives.inc'
include '../calm.inc'
include '../errors.inc'
include '../map.inc'
include '../reader.inc'
include '../output.inc'
include '../console.inc'
section '.bss' readable writeable
include '../variables.inc'
source_path dd ?
output_path dd ?
maximum_number_of_passes dd ?
initial_commands dd ?
initial_commands_length dd ?
initial_commands_maximum_length dd ?
stdout dd ?
stderr dd ?
memory dd ?
timestamp dq ?
systemtime SYSTEMTIME
filetime FILETIME
systmp dd ?
timer dd ?
verbosity_level db ?
no_logo db ?
section '.rdata' data readable
data import
library kernel32,'KERNEL32.DLL'
import kernel32,\
CloseHandle,'CloseHandle',\
CreateFile,'CreateFileA',\
ExitProcess,'ExitProcess',\
GetCommandLine,'GetCommandLineA',\
GetEnvironmentVariable,'GetEnvironmentVariableA',\
GetStdHandle,'GetStdHandle',\
GetSystemTime,'GetSystemTime',\
GetTickCount,'GetTickCount',\
HeapAlloc,'HeapAlloc',\
HeapCreate,'HeapCreate',\
HeapDestroy,'HeapDestroy',\
HeapFree,'HeapFree',\
HeapReAlloc,'HeapReAlloc',\
HeapSize,'HeapSize',\
ReadFile,'ReadFile',\
SetFilePointer,'SetFilePointer',\
SystemTimeToFileTime,'SystemTimeToFileTime',\
WriteFile,'WriteFile',\
GetLastError,'GetLastError'
end data
_logo db 'flat assembler version g.',VERSION,13,10,0
_usage db 'Usage: fasmg source [output]',13,10
db 'Optional settings:',13,10
db ' -e limit Set the maximum number of displayed errors (default 1)',13,10
db ' -p limit Set the maximum allowed number of passes (default 100)',13,10
db ' -r limit Set the maximum depth of the stack (default 10000)',13,10
db ' -v flag Enable or disable showing all lines from the stack (default 0)',13,10
db ' -i command Insert instruction at the beginning of source',13,10
db ' -n Do not show logo nor summary',13,10
db 0
_pass db ' pass, ',0
_passes db ' passes, ',0
_dot db '.'
_seconds db ' seconds, ',0
_byte db ' byte.',0
_bytes db ' bytes.',0
_write_failed db 'failed to write the output file',0
_out_of_memory db 'not enough memory to complete the assembly',0
_code_cannot_be_generated db 'could not generate code within the allowed number of passes',0
include '../tables.inc'
include '../messages.inc'

View File

@@ -0,0 +1,218 @@
LINE_FEED equ 13,10
system_init:
invoke GetStdHandle,STD_OUTPUT_HANDLE
mov [stdout],eax
invoke GetStdHandle,STD_ERROR_HANDLE
mov [stderr],eax
invoke HeapCreate,0,20000h,0
mov [memory],eax
test eax,eax
jz out_of_memory
invoke GetSystemTime,systemtime
invoke SystemTimeToFileTime,systemtime,filetime
mov ebx,[filetime.dwLowDateTime]
mov eax,[filetime.dwHighDateTime]
sub ebx,116444736000000000 and 0FFFFFFFFh
sbb eax,116444736000000000 shr 32
xor edx,edx
mov ecx,10000000
div ecx
mov dword [timestamp+4],eax
mov eax,ebx
div ecx
mov dword [timestamp],eax
retn
system_shutdown:
cmp [memory],0
je memory_released
invoke HeapDestroy,[memory]
memory_released:
invoke CloseHandle,[stdout]
invoke CloseHandle,[stderr]
retn
malloc:
malloc_fixed:
malloc_growable:
; in: ecx = requested size
; out: eax - allocated block, ecx = allocated size, on error jumps to out_of_memory (does not return)
; preserves: ebx, esi, edi
; note:
; use of malloc_fixed hints that block will be kept as is until the end of assembly
; use of malloc_growable hints that block is likely to be resized
invoke HeapAlloc,[memory],0,ecx
test eax,eax
jz out_of_memory
memory_allocated:
push eax
invoke HeapSize,[memory],0,eax
mov ecx,eax
pop eax
cmp ecx,-1
je out_of_memory
retn
realloc:
; in: eax - memory block, ecx = requested size
; out: eax - resized block, ecx = allocated size, on error jumps to out_of_memory (does not return)
; preserves: ebx, esi, edi
invoke HeapReAlloc,[memory],0,eax,ecx
test eax,eax
jnz memory_allocated
jmp out_of_memory
mfree:
; in: eax - memory block
; out: cf set on error
; preserves: ebx, esi, edi
; note: eax may have value 0 or -1, it should be treated as invalid input then
test eax,eax
jz interface_error
cmp eax,-1
je interface_error
invoke HeapFree,[memory],0,eax
test eax,eax
jz interface_error
clc
retn
interface_error:
stc
retn
open:
; in: edx - path to file
; out: ebx = file handle, cf set on error
; preserves: esi, edi
invoke CreateFile,edx,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0
cmp eax,-1
je interface_error
mov ebx,eax
clc
retn
create:
; in: edx - path to file
; out: ebx = file handle, cf set on error
; preserves: esi, edi
invoke CreateFile,edx,GENERIC_WRITE,0,0,CREATE_ALWAYS,0,0
cmp eax,-1
je interface_error
mov ebx,eax
clc
retn
write:
; in: ebx = file handle, edx - data, ecx = number of bytes
; out: cf set on error
; preserves: ebx, esi, edi
push ecx
invoke WriteFile,ebx,edx,ecx,systmp,0
pop ecx
test eax,eax
jz interface_error
cmp ecx,[systmp]
jne interface_error
clc
retn
read:
; in: ebx = file handle, edx - buffer, ecx = number of bytes
; out: cf set on error
; preserves: ebx, esi, edi
push ecx
invoke ReadFile,ebx,edx,ecx,systmp,0
pop ecx
test eax,eax
jz interface_error
cmp ecx,[systmp]
jne interface_error
clc
retn
close:
; in: ebx = file handle
; preserves: ebx, esi, edi
invoke CloseHandle,ebx
retn
lseek:
; in: ebx = file handle, cl = method, edx:eax = offset
; out: edx:eax = new offset from the beginning of file, cf set on error
; preserves: ebx, esi, edi
movzx ecx,cl
mov [systmp],edx
invoke SetFilePointer,ebx,eax,systmp,ecx
cmp eax,-1
jne lseek_ok
invoke GetLastError
test eax,eax
jnz interface_error
not eax
lseek_ok:
mov edx,[systmp]
clc
retn
get_timestamp:
; out: edx:eax = timestamp
; preserves: ebx, ecx, esi, edi
; note: during the passes of a single assembly this function should always return the same value
mov eax,dword [timestamp]
mov edx,dword [timestamp+4]
retn
display_string:
; in:
; esi - string
; ecx = string length, zero for ASCIIZ string
; preserves: ebx, esi
push ebx
mov ebx,[stdout]
jmp write_string
display_error_string:
; in:
; esi - string
; ecx = string length, zero for ASCIIZ string
; preserves: ebx, esi
push ebx
mov ebx,[stderr]
write_string:
test ecx,ecx
jnz write_string_to_stdout
xor al,al
mov edi,esi
or ecx,-1
repne scasb
neg ecx
sub ecx,2
write_string_to_stdout:
mov edx,esi
write_portion_to_stdout:
mov eax,51200
cmp ecx,eax
jbe final_write_to_stdout
sub ecx,eax
add eax,edx
push eax ecx
invoke WriteFile,ebx,edx,51200,systmp,0
pop ecx edx
jmp write_portion_to_stdout
final_write_to_stdout:
invoke WriteFile,ebx,edx,ecx,systmp,0
pop ebx
retn
get_environment_variable:
; in:
; esi - name
; edi - buffer for value
; ecx = size of buffer
; out:
; eax = length of value
; preserves: ebx, esi, edi
push ecx
invoke GetEnvironmentVariable,esi,edi,ecx
pop ecx
cmp eax,ecx
jae environment_variable_ready
mov byte [edi+eax],0
environment_variable_ready:
inc eax
retn