kolibrios-fun/programs/fasm/trunk/parser.inc

1023 lines
17 KiB
PHP
Raw Normal View History

; flat assembler core
; Copyright (c) 1999-2005, Tomasz Grysztar.
; All rights reserved.
parser:
mov eax,[memory_end]
mov [labels_list],eax
mov eax,[additional_memory]
mov [free_additional_memory],eax
xor eax,eax
mov [current_locals_prefix],eax
mov [anonymous_reverse],eax
mov [anonymous_forward],eax
mov [hash_tree],eax
push [memory_end]
mov esi,[memory_start]
mov edi,[source_start]
parser_loop:
mov [current_line],esi
lea eax,[edi+100h]
cmp eax,[memory_end]
jae out_of_memory
cmp byte [esi+16],0
je empty_line
mov al,0Fh
stos byte [edi]
mov eax,esi
stos dword [edi]
add esi,16
call parse_line
parse_next_line:
cmp esi,[source_start]
jb parser_loop
xor al,al
stos byte [edi]
mov eax,[error_line]
mov [current_line],eax
cmp [anonymous_forward],0
jne invalid_value
add edi,0Fh
and edi,not 0Fh
mov [code_start],edi
pop [memory_end]
ret
empty_line:
add esi,17
jmp parse_next_line
parse_line:
mov [parenthesis_stack],0
instruction_start:
cmp byte [esi],1Ah
jne empty_instruction
push edi
add esi,2
movzx ecx,byte [esi-1]
cmp byte [esi+ecx],':'
je simple_label
cmp byte [esi+ecx],'='
je constant_label
cmp byte [esi+ecx],1Ah
jne get_main_instruction
push esi ecx
lea esi,[esi+ecx+2]
movzx ecx,byte [esi-1]
mov edi,data_directives
call get_symbol
jnc data_label
pop ecx esi
get_main_instruction:
call get_instruction
jnc parse_instruction
mov edi,data_directives
call get_symbol
jnc data_instruction
mov edi,symbols
call get_symbol
pop edi
jc unknown_instruction
stos word [edi]
jmp parse_arguments
data_instruction:
movzx ebx,ah
mov bx,[data_handlers+ebx*2]
jmp parse_instruction
unknown_instruction:
sub esi,2
jmp parse_arguments
constant_label:
pop edi
call get_label_id
mov byte [edi],3
inc edi
stos dword [edi]
xor al,al
stos byte [edi]
inc esi
jmp parse_arguments
data_label:
pop ecx ebx
pop edi
push eax esi
mov esi,ebx
movzx ecx,byte [esi-1]
call identify_label
mov byte [edi],2
inc edi
stos dword [edi]
pop esi eax
stos byte [edi]
push edi
jmp data_instruction
simple_label:
pop edi
call identify_label
mov byte [edi],2
inc edi
stos dword [edi]
inc esi
xor al,al
stos byte [edi]
jmp instruction_start
identify_label:
cmp byte [esi],'.'
je local_label_name
call get_label_id
cmp eax,10h
jb label_identified
or ebx,ebx
jz anonymous_label_name
dec ebx
mov [current_locals_prefix],ebx
label_identified:
ret
anonymous_label_name:
cmp byte [esi-1],'@'
je anonymous_label_name_ok
mov eax,0Fh
anonymous_label_name_ok:
ret
local_label_name:
call get_label_id
ret
parse_label_directive:
cmp byte [esi],1Ah
jne argument_parsed
inc esi
movzx ecx,byte [esi]
inc esi
mov al,2
stos byte [edi]
call identify_label
stos dword [edi]
xor al,al
stos byte [edi]
jmp argument_parsed
parse_load_directive:
cmp byte [esi],1Ah
jne argument_parsed
inc esi
movzx ecx,byte [esi]
inc esi
mov al,2
stos byte [edi]
call get_label_id
stos dword [edi]
xor al,al
stos byte [edi]
jmp argument_parsed
parse_prefix_instruction:
cmp byte [esi],1Ah
jne parse_arguments
push edi
inc esi
movzx ecx,byte [esi]
inc esi
jmp get_main_instruction
parse_instruction:
pop edi
mov dl,al
mov al,1
stos byte [edi]
mov ax,bx
stos word [edi]
mov al,dl
stos byte [edi]
cmp bx,prefix_instruction-assembler
je parse_prefix_instruction
cmp bx,end_directive-assembler
je parse_prefix_instruction
cmp bx,label_directive-assembler
je parse_label_directive
cmp bx,segment_directive-assembler
je parse_label_directive
cmp bx,load_directive-assembler
je parse_load_directive
cmp bx,extrn_directive-assembler
je parse_extrn_directive
cmp bx,public_directive-assembler
je parse_public_directive
parse_arguments:
lods byte [esi]
cmp al,':'
je instruction_separator
cmp al,','
je separator
cmp al,'='
je separator
cmp al,'|'
je separator
cmp al,'&'
je separator
cmp al,'~'
je separator
cmp al,'>'
je greater
cmp al,'<'
je less
cmp al,')'
je close_parenthesis
or al,al
jz line_parsed
cmp al,'['
je address_argument
cmp al,']'
je separator
cmp al,'{'
je unallowed_character
cmp al,'}'
je unallowed_character
cmp al,'#'
je unallowed_character
cmp al,'`'
je unallowed_character
dec esi
cmp al,1Ah
jne expression_argument
push edi
mov edi,directive_operators
call get_operator
or al,al
jnz operator_argument
inc esi
movzx ecx,byte [esi]
inc esi
mov edi,symbols
call get_symbol
jnc symbol_argument
mov edi,formatter_symbols
call get_symbol
jnc symbol_argument
cmp ecx,1
jne check_argument
cmp byte [esi],'?'
jne check_argument
pop edi
movs byte [edi],[esi]
jmp argument_parsed
symbol_argument:
pop edi
stos word [edi]
jmp argument_parsed
operator_argument:
pop edi
cmp al,85h
je ptr_argument
stos byte [edi]
cmp al,80h
je forced_expression
cmp al,81h
je forced_parenthesis
cmp al,82h
je parse_from_operator
cmp al,89h
je parse_label_operator
jmp argument_parsed
parse_public_directive:
cmp byte [esi],1Ah
jne parse_arguments
inc esi
push esi
movzx ecx,byte [esi]
inc esi
mov al,2
stos byte [edi]
call get_label_id
stos dword [edi]
mov ax,8600h
stos word [edi]
pop ebx
push ebx esi edi
mov edi,directive_operators
call get_operator
pop edi edx ebx
cmp al,86h
je argument_parsed
mov esi,edx
xchg esi,ebx
movzx ecx,byte [esi]
inc esi
mov ax,'('
stos word [edi]
mov eax,ecx
stos dword [edi]
rep movs byte [edi],[esi]
xor al,al
stos byte [edi]
xchg esi,ebx
jmp argument_parsed
parse_extrn_directive:
cmp byte [esi],22h
je parse_quoted_extrn
cmp byte [esi],1Ah
jne parse_arguments
push esi
movzx ecx,byte [esi+1]
add esi,2
mov ax,'('
stos word [edi]
mov eax,ecx
stos dword [edi]
rep movs byte [edi],[esi]
mov ax,8600h
stos word [edi]
pop esi
parse_label_operator:
cmp byte [esi],1Ah
jne argument_parsed
inc esi
movzx ecx,byte [esi]
inc esi
mov al,2
stos byte [edi]
call get_label_id
stos dword [edi]
xor al,al
stos byte [edi]
jmp argument_parsed
parse_from_operator:
cmp byte [esi],22h
jne forced_expression
jmp argument_parsed
parse_quoted_extrn:
inc esi
mov ax,'('
stos word [edi]
lods dword [esi]
mov ecx,eax
stos dword [edi]
rep movs byte [edi],[esi]
xor al,al
stos byte [edi]
push esi edi
mov edi,directive_operators
call get_operator
mov edx,esi
pop edi esi
cmp al,86h
jne argument_parsed
stos byte [edi]
mov esi,edx
jmp parse_label_operator
ptr_argument:
call parse_address
jmp address_parsed
check_argument:
push esi ecx
sub esi,2
mov edi,single_operand_operators
call get_operator
pop ecx esi
or al,al
jnz not_instruction
call get_instruction
jnc parse_instruction
mov edi,data_directives
call get_symbol
jnc data_instruction
not_instruction:
pop edi
sub esi,2
expression_argument:
cmp byte [esi],22h
jne not_string
mov eax,[esi+1]
lea ebx,[esi+5+eax]
push ebx ecx esi edi
mov al,'('
stos byte [edi]
call convert_expression
mov al,')'
stos byte [edi]
pop eax edx ecx ebx
cmp esi,ebx
jne expression_parsed
mov edi,eax
mov esi,edx
string_argument:
inc esi
mov ax,'('
stos word [edi]
lods dword [esi]
mov ecx,eax
stos dword [edi]
shr ecx,1
jnc string_movsb_ok
movs byte [edi],[esi]
string_movsb_ok:
shr ecx,1
jnc string_movsw_ok
movs word [edi],[esi]
string_movsw_ok:
rep movs dword [edi],[esi]
xor al,al
stos byte [edi]
jmp expression_parsed
not_string:
cmp byte [esi],'('
jne expression
mov eax,esp
sub eax,100h
jc stack_overflow
cmp eax,[stack_limit]
jb stack_overflow
push esi edi
inc esi
mov al,'{'
stos byte [edi]
inc [parenthesis_stack]
jmp parse_arguments
expression:
mov al,'('
stos byte [edi]
call convert_expression
mov al,')'
stos byte [edi]
jmp expression_parsed
forced_expression:
mov al,'('
stos byte [edi]
call convert_expression
mov al,')'
stos byte [edi]
jmp argument_parsed
address_argument:
call parse_address
lods byte [esi]
cmp al,']'
jne invalid_address
address_parsed:
mov al,']'
stos byte [edi]
jmp argument_parsed
parse_address:
mov al,'['
stos byte [edi]
cmp word [esi],021Ah
jne convert_address
push esi
add esi,4
lea ebx,[esi+1]
cmp byte [esi],':'
pop esi
jne convert_address
add esi,2
mov ecx,2
push ebx edi
mov edi,symbols
call get_symbol
pop edi esi
jc invalid_address
cmp al,10h
jne invalid_address
mov al,ah
and ah,11110000b
cmp ah,60h
jne invalid_address
stos byte [edi]
convert_address:
cmp byte [esi],1Ah
jne convert_expression
push esi
lods word [esi]
movzx ecx,ah
push edi
mov edi,address_sizes
call get_symbol
pop edi
jc no_size_prefix
mov al,ah
add al,70h
stos byte [edi]
add esp,4
jmp convert_expression
no_size_prefix:
pop esi
jmp convert_expression
forced_parenthesis:
cmp byte [esi],'('
jne argument_parsed
inc esi
mov al,'{'
jmp separator
unallowed_character:
mov al,0FFh
jmp separator
close_parenthesis:
mov al,'}'
separator:
stos byte [edi]
jmp argument_parsed
instruction_separator:
stos byte [edi]
jmp instruction_start
greater:
cmp byte [esi],'='
jne separator
inc esi
mov al,0F2h
jmp separator
less:
cmp byte [edi-1],0F6h
je separator
cmp byte [esi],'>'
je not_equal
cmp byte [esi],'='
jne separator
inc esi
mov al,0F3h
jmp separator
not_equal:
inc esi
mov al,0F1h
jmp separator
argument_parsed:
cmp [parenthesis_stack],0
je parse_arguments
dec [parenthesis_stack]
add esp,8
jmp argument_parsed
expression_parsed:
cmp [parenthesis_stack],0
je parse_arguments
cmp byte [esi],')'
jne argument_parsed
dec [parenthesis_stack]
pop edi esi
jmp expression
empty_instruction:
lods byte [esi]
or al,al
jz line_parsed
cmp al,':'
je invalid_name
cmp al,3Bh
je skip_preprocessed_symbol
dec esi
jmp parse_arguments
skip_preprocessed_symbol:
lods byte [esi]
movzx eax,al
add esi,eax
skip_next:
lods byte [esi]
or al,al
jz line_parsed
cmp al,1Ah
je skip_preprocessed_symbol
cmp al,3Bh
je skip_preprocessed_symbol
cmp al,22h
je skip_preprocessed_string
jmp skip_next
skip_preprocessed_string:
lods dword [esi]
add esi,eax
jmp skip_next
line_parsed:
cmp [parenthesis_stack],0
jne invalid_expression
ret
get_operator:
cmp byte [esi],1Ah
jne get_simple_operator
mov edx,esi
push ebp
inc esi
lods byte [esi]
movzx ebp,al
push edi
mov ecx,ebp
call lower_case
pop edi
check_operator:
mov esi,converted
movzx ecx,byte [edi]
jecxz no_operator
inc edi
mov ebx,edi
add ebx,ecx
cmp ecx,ebp
jne next_operator
repe cmps byte [esi],[edi]
je operator_found
next_operator:
mov edi,ebx
inc edi
jmp check_operator
no_operator:
mov esi,edx
mov ecx,ebp
pop ebp
no_simple_operator:
xor al,al
ret
operator_found:
lea esi,[edx+2+ebp]
mov ecx,ebp
pop ebp
mov al,[edi]
ret
get_simple_operator:
mov al,[esi]
cmp al,22h
je no_simple_operator
simple_operator:
cmp byte [edi],1
jb no_simple_operator
ja simple_next_operator
cmp al,[edi+1]
je simple_operator_found
simple_next_operator:
movzx ecx,byte [edi]
lea edi,[edi+1+ecx+1]
jmp simple_operator
simple_operator_found:
inc esi
mov al,[edi+2]
ret
get_symbol:
mov edx,esi
mov ebp,ecx
push edi
call lower_case
pop edi
scan_symbols:
mov esi,converted
movzx eax,byte [edi]
or al,al
jz no_symbol
mov ecx,ebp
inc edi
mov ebx,edi
add ebx,eax
mov ah,[esi]
cmp ah,[edi]
jb no_symbol
ja next_symbol
cmp cl,al
jne next_symbol
repe cmps byte [esi],[edi]
jb no_symbol
je symbol_ok
next_symbol:
mov edi,ebx
add edi,2
jmp scan_symbols
no_symbol:
mov esi,edx
mov ecx,ebp
stc
ret
symbol_ok:
lea esi,[edx+ebp]
mov ax,[ebx]
clc
ret
get_instruction:
mov edx,esi
mov ebp,ecx
call lower_case
mov ecx,ebp
cmp cl,11
ja no_instruction
sub cl,2
jc no_instruction
movzx edi,word [instructions+ecx*2]
add edi,instructions
scan_instructions:
mov esi,converted
mov al,[edi]
or al,al
jz no_instruction
mov ecx,ebp
mov ebx,edi
add ebx,ecx
repe cmps byte [esi],[edi]
jb no_instruction
je instruction_ok
next_instruction:
mov edi,ebx
add edi,3
jmp scan_instructions
no_instruction:
mov esi,edx
mov ecx,ebp
stc
ret
lower_case:
mov edi,converted
mov ebx,characters
convert_case:
lods byte [esi]
xlat byte [ebx]
stos byte [edi]
loop convert_case
case_ok:
ret
instruction_ok:
lea esi,[edx+ebp]
mov al,[ebx]
mov bx,[ebx+1]
clc
ret
get_label_id:
cmp ecx,100h
jae name_too_long
cmp byte [esi],'@'
je anonymous_label
cmp byte [esi],'.'
jne standard_label
cmp byte [esi+1],'.'
je standard_label
cmp [current_locals_prefix],0
je standard_label
push edi
mov edi,[memory_end]
sub edi,2
sub edi,ecx
push ecx esi
mov esi,[current_locals_prefix]
lods byte [esi]
movzx ecx,al
sub edi,ecx
cmp edi,[esp+8]
jb out_of_memory
mov [memory_end],edi
mov word [edi],0
add edi,2
mov ebx,edi
rep movs byte [edi],[esi]
pop esi ecx
add al,cl
jc name_too_long
rep movs byte [edi],[esi]
pop edi
push esi
movzx ecx,al
mov byte [ebx-1],al
mov esi,ebx
call get_label_id
pop esi
ret
anonymous_label:
cmp ecx,2
jne standard_label
mov al,[esi+1]
mov ebx,characters
xlat byte [ebx]
cmp al,'@'
je new_anonymous
cmp al,'b'
je anonymous_back
cmp al,'r'
je anonymous_back
cmp al,'f'
jne standard_label
add esi,2
mov eax,[anonymous_forward]
or eax,eax
jnz anonymous_ok
mov eax,[current_line]
mov [error_line],eax
mov eax,[labels_list]
sub eax,24
mov [labels_list],eax
mov [anonymous_forward],eax
anonymous_ok:
xor ebx,ebx
ret
anonymous_back:
add esi,2
mov eax,[anonymous_reverse]
or eax,eax
jz invalid_value
jmp anonymous_ok
new_anonymous:
add esi,2
mov eax,[anonymous_forward]
or eax,eax
jnz new_anonymous_ok
mov eax,[labels_list]
sub eax,24
mov [labels_list],eax
new_anonymous_ok:
mov [anonymous_reverse],eax
mov [anonymous_forward],0
jmp anonymous_ok
standard_label:
cmp byte [esi],'%'
je get_predefined_id
cmp byte [esi],'$'
jne find_label
cmp ecx,2
ja find_label
inc esi
jb get_current_offset_id
inc esi
cmp byte [esi-1],'$'
je get_org_origin_id
sub esi,ecx
jmp find_label
get_current_offset_id:
xor eax,eax
ret
get_counter_id:
mov eax,1
ret
get_timestamp_id:
mov eax,2
ret
get_org_origin_id:
mov eax,3
ret
get_predefined_id:
cmp ecx,2
ja find_label
inc esi
cmp cl,1
je get_counter_id
lods byte [esi]
mov ebx,characters
xlat [ebx]
cmp al,'t'
je get_timestamp_id
sub esi,2
find_label:
xor ebx,ebx
mov eax,2166136261
mov ebp,16777619
hash_label:
xor al,[esi+ebx]
mul ebp
inc bl
cmp bl,cl
jb hash_label
mov ebp,eax
shl eax,8
and ebp,0FFh shl 24
xor ebp,eax
or ebp,ebx
mov [label_hash],ebp
push edi esi
push ecx
mov ecx,32
mov ebx,hash_tree
follow_tree:
mov edx,[ebx]
or edx,edx
jz extend_tree
xor eax,eax
shl ebp,1
adc eax,0
lea ebx,[edx+eax*4]
dec ecx
jnz follow_tree
mov [label_leaf],ebx
pop edx
mov eax,[ebx]
or eax,eax
jz add_label
mov ebx,esi
mov ebp,[label_hash]
compare_labels:
mov esi,ebx
mov ecx,edx
mov edi,[eax+4]
repe cmps byte [esi],[edi]
je label_found
mov eax,[eax]
or eax,eax
jnz compare_labels
jmp add_label
label_found:
add esp,4
pop edi
mov ebx,[eax+4]
mov eax,[eax+8]
ret
extend_tree:
mov edx,[free_additional_memory]
lea eax,[edx+8]
cmp eax,[additional_memory_end]
ja out_of_memory
mov [free_additional_memory],eax
xor eax,eax
mov [edx],eax
mov [edx+4],eax
shl ebp,1
adc eax,0
mov [ebx],edx
lea ebx,[edx+eax*4]
dec ecx
jnz extend_tree
mov [label_leaf],ebx
pop edx
add_label:
mov ecx,edx
pop esi
cmp byte [esi-2],0
je label_name_ok
mov al,[esi]
cmp al,30h
jb name_first_char_ok
cmp al,39h
jbe invalid_name
name_first_char_ok:
cmp ecx,1
jne check_for_reserved_word
cmp al,'$'
je reserved_word
check_for_reserved_word:
call get_instruction
jnc reserved_word
mov edi,data_directives
call get_symbol
jnc reserved_word
mov edi,symbols
call get_symbol
jnc reserved_word
mov edi,formatter_symbols
call get_symbol
jnc reserved_word
sub esi,2
mov edi,operators
call get_operator
or al,al
jnz reserved_word
mov edi,single_operand_operators
call get_operator
or al,al
jnz reserved_word
mov edi,directive_operators
call get_operator
or al,al
jnz reserved_word
inc esi
movzx ecx,byte [esi]
inc esi
label_name_ok:
mov edx,[free_additional_memory]
lea eax,[edx+12]
cmp eax,[additional_memory_end]
ja out_of_memory
mov [free_additional_memory],eax
mov [edx+4],esi
mov ebx,esi
add esi,ecx
mov eax,[label_leaf]
mov edi,[eax]
mov [edx],edi
mov [eax],edx
mov eax,[labels_list]
sub eax,24
mov [labels_list],eax
mov [edx+8],eax
pop edi
ret
reserved_word:
mov eax,0Fh
pop edi
ret
operators:
db 1,'+',80h
db 1,'-',81h
db 1,'*',90h
db 1,'/',91h
db 3,'mod',0A0h
db 3,'and',0B0h
db 2,'or',0B1h
db 3,'xor',0B2h
db 3,'shl',0C0h
db 3,'shr',0C1h
db 0
single_operand_operators:
db 1,'+',0
db 1,'-',0D1h
db 3,'not',0D0h
db 3,'rva',0E0h
db 0
directive_operators:
db 2,'as',86h
db 2,'at',80h
db 7,'defined',88h
db 3,'dup',81h
db 2,'eq',0F0h
db 6,'eqtype',0F7h
db 4,'from',82h
db 2,'in',0F6h
db 2,'on',84h
db 3,'ptr',85h
db 4,'used',89h
db 0