; flat assembler core
; Copyright (c) 1999-2020, 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
	mov	[blocks_stack],eax
	mov	[parsed_lines],eax
	mov	esi,[memory_start]
	mov	edi,[source_start]
      parser_loop:
	mov	[current_line],esi
	lea	eax,[edi+100h]
	cmp	eax,[labels_list]
	jae	out_of_memory
	cmp	byte [esi+16],0
	je	empty_line
	cmp	byte [esi+16],3Bh
	je	empty_line
	mov	al,0Fh
	stos	byte [edi]
	mov	eax,esi
	stos	dword [edi]
	inc	[parsed_lines]
	add	esi,16
      parse_line:
	mov	[formatter_symbols_allowed],0
	mov	[decorator_symbols_allowed],0
	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
	call	get_instruction
	jnc	main_instruction_identified
	cmp	byte [esi+ecx],1Ah
	jne	no_data_label
	push	esi ecx
	lea	esi,[esi+ecx+2]
	movzx	ecx,byte [esi-1]
	call	get_data_directive
	jnc	data_label
	pop	ecx esi
      no_data_label:
	call	get_data_directive
	jnc	main_instruction_identified
	pop	edi
	sub	esi,2
	xor	bx,bx
	call	parse_line_contents
	jmp	parse_next_line
      simple_label:
	pop	edi
	call	identify_label
	cmp	byte [esi+1],':'
	je	block_label
	mov	byte [edi],2
	inc	edi
	stos	dword [edi]
	inc	esi
	xor	al,al
	stos	byte [edi]
	jmp	parse_line
      block_label:
	mov	byte [edi],4
	inc	edi
	stos	dword [edi]
	add	esi,2
	jmp	parse_line
      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
	xor	bx,bx
	call	parse_line_contents
	jmp	parse_next_line
      data_label:
	pop	ecx edx
	pop	edi
	push	eax ebx esi
	mov	esi,edx
	movzx	ecx,byte [esi-1]
	call	identify_label
	mov	byte [edi],2
	inc	edi
	stos	dword [edi]
	pop	esi ebx eax
	stos	byte [edi]
	push	edi
      main_instruction_identified:
	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,if_directive-instruction_handler
	je	parse_block
	cmp	bx,repeat_directive-instruction_handler
	je	parse_block
	cmp	bx,while_directive-instruction_handler
	je	parse_block
	cmp	bx,end_directive-instruction_handler
	je	parse_end_directive
	cmp	bx,else_directive-instruction_handler
	je	parse_else
	cmp	bx,assert_directive-instruction_handler
	je	parse_assert
      common_parse:
	call	parse_line_contents
	jmp	parse_next_line
      empty_instruction:
	lods	byte [esi]
	or	al,al
	jz	parse_next_line
	cmp	al,':'
	je	invalid_name
	dec	esi
	mov	[parenthesis_stack],0
	call	parse_argument
	jmp	parse_next_line
      empty_line:
	add	esi,16
      skip_rest_of_line:
	call	skip_foreign_line
      parse_next_line:
	cmp	esi,[source_start]
	jb	parser_loop
      source_parsed:
	cmp	[blocks_stack],0
	je	blocks_stack_ok
	pop	eax
	pop	[current_line]
	jmp	missing_end_directive
      blocks_stack_ok:
	xor	al,al
	stos	byte [edi]
	add	edi,0Fh
	and	edi,not 0Fh
	mov	[code_start],edi
	ret
      parse_block:
	mov	eax,esp
	sub	eax,[stack_limit]
	cmp	eax,100h
	jb	stack_overflow
	push	[current_line]
	mov	ax,bx
	shl	eax,16
	push	eax
	inc	[blocks_stack]
	cmp	bx,if_directive-instruction_handler
	je	parse_if
	cmp	bx,while_directive-instruction_handler
	je	parse_while
	call	parse_line_contents
	jmp	parse_next_line
      parse_end_directive:
	cmp	byte [esi],1Ah
	jne	common_parse
	push	edi
	inc	esi
	movzx	ecx,byte [esi]
	inc	esi
	call	get_instruction
	pop	edi
	jnc	parse_end_block
	sub	esi,2
	jmp	common_parse
      parse_end_block:
	mov	dl,al
	mov	al,1
	stos	byte [edi]
	mov	ax,bx
	stos	word [edi]
	mov	al,dl
	stos	byte [edi]
	lods	byte [esi]
	or	al,al
	jnz	extra_characters_on_line
	cmp	bx,if_directive-instruction_handler
	je	close_parsing_block
	cmp	bx,repeat_directive-instruction_handler
	je	close_parsing_block
	cmp	bx,while_directive-instruction_handler
	je	close_parsing_block
	jmp	parse_next_line
      close_parsing_block:
	cmp	[blocks_stack],0
	je	unexpected_instruction
	cmp	bx,[esp+2]
	jne	unexpected_instruction
	dec	[blocks_stack]
	pop	eax edx
	cmp	bx,if_directive-instruction_handler
	jne	parse_next_line
	test	al,1100b
	jz	parse_next_line
	test	al,10000b
	jnz	parse_next_line
	sub	edi,8
	jmp	parse_next_line
      parse_if:
	push	edi
	call	parse_line_contents
	xor	al,al
	stos	byte [edi]
	xchg	esi,[esp]
	mov	edi,esi
	call	preevaluate_logical_expression
	pop	esi
	cmp	al,'0'
	je	parse_false_condition_block
	cmp	al,'1'
	je	parse_true_condition_block
	or	byte [esp],10000b
	jmp	parse_next_line
      parse_while:
	push	edi
	call	parse_line_contents
	xor	al,al
	stos	byte [edi]
	xchg	esi,[esp]
	mov	edi,esi
	call	preevaluate_logical_expression
	pop	esi
	cmp	al,'0'
	je	parse_false_condition_block
	cmp	al,'1'
	jne	parse_next_line
	stos	byte [edi]
	jmp	parse_next_line
      parse_false_condition_block:
	or	byte [esp],1
	sub	edi,4
	jmp	skip_parsing
      parse_true_condition_block:
	or	byte [esp],100b
	sub	edi,4
	jmp	parse_next_line
      parse_else:
	cmp	[blocks_stack],0
	je	unexpected_instruction
	cmp	word [esp+2],if_directive-instruction_handler
	jne	unexpected_instruction
	lods	byte [esi]
	or	al,al
	jz	parse_pure_else
	cmp	al,1Ah
	jne	extra_characters_on_line
	push	edi
	movzx	ecx,byte [esi]
	inc	esi
	call	get_instruction
	jc	extra_characters_on_line
	pop	edi
	cmp	bx,if_directive-instruction_handler
	jne	extra_characters_on_line
	test	byte [esp],100b
	jnz	skip_true_condition_else
	mov	dl,al
	mov	al,1
	stos	byte [edi]
	mov	ax,bx
	stos	word [edi]
	mov	al,dl
	stos	byte [edi]
	jmp	parse_if
      parse_assert:
	push	edi
	call	parse_line_contents
	xor	al,al
	stos	byte [edi]
	xchg	esi,[esp]
	mov	edi,esi
	call	preevaluate_logical_expression
	pop	esi
	or	al,al
	jz	parse_next_line
	stos	byte [edi]
	jmp	parse_next_line
      skip_true_condition_else:
	sub	edi,4
	or	byte [esp],1
	jmp	skip_parsing_contents
      parse_pure_else:
	bts	dword [esp],1
	jc	unexpected_instruction
	test	byte [esp],100b
	jz	parse_next_line
	sub	edi,4
	or	byte [esp],1
	jmp	skip_parsing
      skip_parsing:
	cmp	esi,[source_start]
	jae	source_parsed
	mov	[current_line],esi
	add	esi,16
      skip_parsing_line:
	cmp	byte [esi],1Ah
	jne	skip_parsing_contents
	inc	esi
	movzx	ecx,byte [esi]
	inc	esi
	cmp	byte [esi+ecx],':'
	je	skip_parsing_label
	push	edi
	call	get_instruction
	pop	edi
	jnc	skip_parsing_instruction
	add	esi,ecx
	jmp	skip_parsing_contents
      skip_parsing_label:
	lea	esi,[esi+ecx+1]
	jmp	skip_parsing_line
      skip_parsing_instruction:
	cmp	bx,if_directive-instruction_handler
	je	skip_parsing_block
	cmp	bx,repeat_directive-instruction_handler
	je	skip_parsing_block
	cmp	bx,while_directive-instruction_handler
	je	skip_parsing_block
	cmp	bx,end_directive-instruction_handler
	je	skip_parsing_end_directive
	cmp	bx,else_directive-instruction_handler
	je	skip_parsing_else
      skip_parsing_contents:
	lods	byte [esi]
	or	al,al
	jz	skip_parsing
	cmp	al,1Ah
	je	skip_parsing_symbol
	cmp	al,3Bh
	je	skip_parsing_symbol
	cmp	al,22h
	je	skip_parsing_string
	jmp	skip_parsing_contents
      skip_parsing_symbol:
	lods	byte [esi]
	movzx	eax,al
	add	esi,eax
	jmp	skip_parsing_contents
      skip_parsing_string:
	lods	dword [esi]
	add	esi,eax
	jmp	skip_parsing_contents
      skip_parsing_block:
	mov	eax,esp
	sub	eax,[stack_limit]
	cmp	eax,100h
	jb	stack_overflow
	push	[current_line]
	mov	ax,bx
	shl	eax,16
	push	eax
	inc	[blocks_stack]
	jmp	skip_parsing_contents
      skip_parsing_end_directive:
	cmp	byte [esi],1Ah
	jne	skip_parsing_contents
	push	edi
	inc	esi
	movzx	ecx,byte [esi]
	inc	esi
	call	get_instruction
	pop	edi
	jnc	skip_parsing_end_block
	add	esi,ecx
	jmp	skip_parsing_contents
      skip_parsing_end_block:
	lods	byte [esi]
	or	al,al
	jnz	extra_characters_on_line
	cmp	bx,if_directive-instruction_handler
	je	close_skip_parsing_block
	cmp	bx,repeat_directive-instruction_handler
	je	close_skip_parsing_block
	cmp	bx,while_directive-instruction_handler
	je	close_skip_parsing_block
	jmp	skip_parsing
      close_skip_parsing_block:
	cmp	[blocks_stack],0
	je	unexpected_instruction
	cmp	bx,[esp+2]
	jne	unexpected_instruction
	dec	[blocks_stack]
	pop	eax edx
	test	al,1
	jz	skip_parsing
	cmp	bx,if_directive-instruction_handler
	jne	parse_next_line
	test	al,10000b
	jz	parse_next_line
	mov	al,0Fh
	stos	byte [edi]
	mov	eax,[current_line]
	stos	dword [edi]
	inc	[parsed_lines]
	mov	eax,1 + (end_directive-instruction_handler) shl 8
	stos	dword [edi]
	mov	eax,1 + (if_directive-instruction_handler) shl 8
	stos	dword [edi]
	jmp	parse_next_line
      skip_parsing_else:
	cmp	[blocks_stack],0
	je	unexpected_instruction
	cmp	word [esp+2],if_directive-instruction_handler
	jne	unexpected_instruction
	lods	byte [esi]
	or	al,al
	jz	skip_parsing_pure_else
	cmp	al,1Ah
	jne	extra_characters_on_line
	push	edi
	movzx	ecx,byte [esi]
	inc	esi
	call	get_instruction
	jc	extra_characters_on_line
	pop	edi
	cmp	bx,if_directive-instruction_handler
	jne	extra_characters_on_line
	mov	al,[esp]
	test	al,1
	jz	skip_parsing_contents
	test	al,100b
	jnz	skip_parsing_contents
	test	al,10000b
	jnz	parse_else_if
	xor	al,al
	mov	[esp],al
	mov	al,0Fh
	stos	byte [edi]
	mov	eax,[current_line]
	stos	dword [edi]
	inc	[parsed_lines]
      parse_else_if:
	mov	eax,1 + (if_directive-instruction_handler) shl 8
	stos	dword [edi]
	jmp	parse_if
      skip_parsing_pure_else:
	bts	dword [esp],1
	jc	unexpected_instruction
	mov	al,[esp]
	test	al,1
	jz	skip_parsing
	test	al,100b
	jnz	skip_parsing
	and	al,not 1
	or	al,1000b
	mov	[esp],al
	jmp	parse_next_line

parse_line_contents:
	mov	[parenthesis_stack],0
      parse_instruction_arguments:
	cmp	bx,prefix_instruction-instruction_handler
	je	allow_embedded_instruction
	cmp	bx,times_directive-instruction_handler
	je	parse_times_directive
	cmp	bx,end_directive-instruction_handler
	je	allow_embedded_instruction
	cmp	bx,label_directive-instruction_handler
	je	parse_label_directive
	cmp	bx,segment_directive-instruction_handler
	je	parse_segment_directive
	cmp	bx,load_directive-instruction_handler
	je	parse_load_directive
	cmp	bx,extrn_directive-instruction_handler
	je	parse_extrn_directive
	cmp	bx,public_directive-instruction_handler
	je	parse_public_directive
	cmp	bx,section_directive-instruction_handler
	je	parse_formatter_argument
	cmp	bx,format_directive-instruction_handler
	je	parse_formatter_argument
	cmp	bx,data_directive-instruction_handler
	je	parse_formatter_argument
	jmp	parse_argument
      parse_formatter_argument:
	or	[formatter_symbols_allowed],-1
      parse_argument:
	lea	eax,[edi+100h]
	cmp	eax,[labels_list]
	jae	out_of_memory
	lods	byte [esi]
	cmp	al,':'
	je	instruction_separator
	cmp	al,','
	je	separator
	cmp	al,'='
	je	expression_comparator
	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	contents_parsed
	cmp	al,'['
	je	address_argument
	cmp	al,']'
	je	separator
	cmp	al,'{'
	je	open_decorator
	cmp	al,'}'
	je	close_decorator
	cmp	al,'#'
	je	unallowed_character
	cmp	al,'`'
	je	unallowed_character
	cmp	al,3Bh
	je	foreign_argument
	cmp	[decorator_symbols_allowed],0
	je	not_a_separator
	cmp	al,'-'
	je	separator
      not_a_separator:
	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
	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
      foreign_argument:
	dec	esi
	call	skip_foreign_line
	jmp	contents_parsed
      symbol_argument:
	pop	edi
	stos	word [edi]
	cmp	byte [esi],'+'
	jne	argument_parsed
	and	ax,0F0FFh
	cmp	ax,6010h
	jne	argument_parsed
	movs	byte [edi],[esi]
	jmp	argument_parsed
      operator_argument:
	pop	edi
	cmp	al,85h
	je	ptr_argument
	stos	byte [edi]
	cmp	al,8Ch
	je	forced_expression
	cmp	al,81h
	je	forced_parenthesis
	cmp	al,80h
	je	parse_at_operator
	cmp	al,82h
	je	parse_from_operator
	cmp	al,89h
	je	parse_label_operator
	cmp	al,0F8h
	je	forced_expression
	jmp	argument_parsed
      instruction_separator:
	stos	byte [edi]
      allow_embedded_instruction:
	cmp	byte [esi],1Ah
	jne	parse_argument
	push	edi
	inc	esi
	movzx	ecx,byte [esi]
	inc	esi
	call	get_instruction
	jnc	embedded_instruction
	call	get_data_directive
	jnc	embedded_instruction
	pop	edi
	sub	esi,2
	jmp	parse_argument
      embedded_instruction:
	pop	edi
	mov	dl,al
	mov	al,1
	stos	byte [edi]
	mov	ax,bx
	stos	word [edi]
	mov	al,dl
	stos	byte [edi]
	jmp	parse_instruction_arguments
      parse_times_directive:
	mov	al,'('
	stos	byte [edi]
	call	convert_expression
	mov	al,')'
	stos	byte [edi]
	cmp	byte [esi],':'
	jne	allow_embedded_instruction
	movs	byte [edi],[esi]
	jmp	allow_embedded_instruction
      parse_segment_directive:
	or	[formatter_symbols_allowed],-1
      parse_label_directive:
	cmp	byte [esi],1Ah
	jne	argument_parsed
	push	esi
	inc	esi
	movzx	ecx,byte [esi]
	inc	esi
	call	identify_label
	pop	ebx
	cmp	eax,0Fh
	je	non_label_identified
	mov	byte [edi],2
	inc	edi
	stos	dword [edi]
	xor	al,al
	stos	byte [edi]
	jmp	argument_parsed
      non_label_identified:
	mov	esi,ebx
	jmp	argument_parsed
      parse_load_directive:
	cmp	byte [esi],1Ah
	jne	argument_parsed
	push	esi
	inc	esi
	movzx	ecx,byte [esi]
	inc	esi
	call	get_label_id
	pop	ebx
	cmp	eax,0Fh
	je	non_label_identified
	mov	byte [edi],2
	inc	edi
	stos	dword [edi]
	xor	al,al
	stos	byte [edi]
	jmp	argument_parsed
      parse_public_directive:
	cmp	byte [esi],1Ah
	jne	parse_argument
	inc	esi
	push	esi
	movzx	ecx,byte [esi]
	inc	esi
	push	esi ecx
	push	edi
	or	[formatter_symbols_allowed],-1
	call	get_symbol
	mov	[formatter_symbols_allowed],0
	pop	edi
	jc	parse_public_label
	cmp	al,1Dh
	jne	parse_public_label
	add	esp,12
	stos	word [edi]
	jmp	parse_public_directive
      parse_public_label:
	pop	ecx 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_argument
	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
	je	argument_parsed
      parse_at_operator:
	cmp	byte [esi],':'
	je	argument_parsed
	jmp	forced_multipart_expression
      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	embedded_instruction
	call	get_data_directive
	jnc	embedded_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
	call	parse_expression
	pop	eax edx ecx ebx
	cmp	esi,ebx
	jne	expression_argument_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_argument_parsed
      parse_expression:
	mov	al,'('
	stos	byte [edi]
	call	convert_expression
	mov	al,')'
	stos	byte [edi]
	ret
      not_string:
	cmp	byte [esi],'('
	jne	expression
	mov	eax,esp
	sub	eax,[stack_limit]
	cmp	eax,100h
	jb	stack_overflow
	push	esi edi
	inc	esi
	mov	al,91h
	stos	byte [edi]
	inc	[parenthesis_stack]
	jmp	parse_argument
      expression_comparator:
	stos	byte [edi]
	jmp	forced_expression
      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	expression_comparator
      expression:
	call	parse_expression
	jmp	expression_argument_parsed
      forced_expression:
	xor	al,al
	xchg	al,[formatter_symbols_allowed]
	push	eax
	call	parse_expression
      forced_expression_parsed:
	pop	eax
	mov	[formatter_symbols_allowed],al
	jmp	argument_parsed
      forced_multipart_expression:
	xor	al,al
	xchg	al,[formatter_symbols_allowed]
	push	eax
	call	parse_expression
	cmp	byte [esi],':'
	jne	forced_expression_parsed
	movs	byte [edi],[esi]
	call	parse_expression
	jmp	forced_expression_parsed
      address_argument:
	call	parse_address
	lods	byte [esi]
	cmp	al,']'
	je	address_parsed
	cmp	al,','
	je	divided_address
	dec	esi
	mov	al,')'
	stos	byte [edi]
	jmp	argument_parsed
      divided_address:
	mov	ax,'),'
	stos	word [edi]
	jmp	expression
      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
	call	get_symbol
	pop	edi esi
	jc	unknown_segment_prefix
	cmp	al,10h
	jne	unknown_segment_prefix
	mov	al,ah
	and	ah,11110000b
	cmp	ah,30h
	jne	unknown_segment_prefix
	add	al,30h
	stos	byte [edi]
	jmp	convert_address
      unknown_segment_prefix:
	sub	esi,5
      convert_address:
	push	edi
	mov	edi,address_sizes
	call	get_operator
	pop	edi
	or	al,al
	jz	convert_expression
	add	al,70h
	stos	byte [edi]
	jmp	convert_expression
      forced_parenthesis:
	cmp	byte [esi],'('
	jne	argument_parsed
	inc	esi
	mov	al,91h
	jmp	separator
      unallowed_character:
	mov	al,0FFh
	jmp	separator
      open_decorator:
	inc	[decorator_symbols_allowed]
	jmp	separator
      close_decorator:
	dec	[decorator_symbols_allowed]
	jmp	separator
      close_parenthesis:
	mov	al,92h
      separator:
	stos	byte [edi]
      argument_parsed:
	cmp	[parenthesis_stack],0
	je	parse_argument
	dec	[parenthesis_stack]
	add	esp,8
	jmp	argument_parsed
      expression_argument_parsed:
	cmp	[parenthesis_stack],0
	je	parse_argument
	cmp	byte [esi],')'
	jne	argument_parsed
	dec	[parenthesis_stack]
	pop	edi esi
	jmp	expression
      contents_parsed:
	cmp	[parenthesis_stack],0
	je	contents_ok
	dec	[parenthesis_stack]
	add	esp,8
	jmp	contents_parsed
      contents_ok:
	ret

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

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
	jb	no_operator
      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:
	push	esi
	mov	ebp,ecx
	call	lower_case
	mov	ecx,ebp
	cmp	cl,11
	ja	no_symbol
	sub	cl,1
	jc	no_symbol
	movzx	ebx,word [symbols+ecx*4]
	add	ebx,symbols
	movzx	edx,word [symbols+ecx*4+2]
      scan_symbols:
	or	edx,edx
	jz	no_symbol
	mov	eax,edx
	shr	eax,1
	lea	edi,[ebp+2]
	imul	eax,edi
	lea	edi,[ebx+eax]
	mov	esi,converted
	mov	ecx,ebp
	repe	cmps byte [esi],[edi]
	ja	symbols_up
	jb	symbols_down
	mov	ax,[edi]
	cmp	al,18h
	jb	symbol_ok
	cmp	al,1Fh
	je	decorator_symbol
	cmp	[formatter_symbols_allowed],0
	je	no_symbol
      symbol_ok:
	pop	esi
	add	esi,ebp
	clc
	ret
      decorator_symbol:
	cmp	[decorator_symbols_allowed],0
	jne	symbol_ok
      no_symbol:
	pop	esi
	mov	ecx,ebp
	stc
	ret
      symbols_down:
	shr	edx,1
	jmp	scan_symbols
      symbols_up:
	lea	ebx,[edi+ecx+2]
	shr	edx,1
	adc	edx,-1
	jmp	scan_symbols

get_data_directive:
	push	esi
	mov	ebp,ecx
	call	lower_case
	mov	ecx,ebp
	cmp	cl,4
	ja	no_instruction
	sub	cl,2
	jc	no_instruction
	movzx	ebx,word [data_directives+ecx*4]
	add	ebx,data_directives
	movzx	edx,word [data_directives+ecx*4+2]
	jmp	scan_instructions

get_instruction:
	push	esi
	mov	ebp,ecx
	call	lower_case
	mov	ecx,ebp
	cmp	cl,17
	ja	no_instruction
	sub	cl,2
	jc	no_instruction
	movzx	ebx,word [instructions+ecx*4]
	add	ebx,instructions
	movzx	edx,word [instructions+ecx*4+2]
      scan_instructions:
	or	edx,edx
	jz	no_instruction
	mov	eax,edx
	shr	eax,1
	lea	edi,[ebp+3]
	imul	eax,edi
	lea	edi,[ebx+eax]
	mov	esi,converted
	mov	ecx,ebp
	repe	cmps byte [esi],[edi]
	ja	instructions_up
	jb	instructions_down
	pop	esi
	add	esi,ebp
	mov	al,[edi]
	mov	bx,[edi+1]
	clc
	ret
      no_instruction:
	pop	esi
	mov	ecx,ebp
	stc
	ret
      instructions_down:
	shr	edx,1
	jmp	scan_instructions
      instructions_up:
	lea	ebx,[edi+ecx+3]
	shr	edx,1
	adc	edx,-1
	jmp	scan_instructions

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,[additional_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,[free_additional_memory]
	jb	out_of_memory
	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	ebx esi
	movzx	ecx,al
	mov	byte [ebx-1],al
	mov	esi,ebx
	call	get_label_id
	pop	esi ebx
	cmp	ebx,[eax+24]
	jne	composed_label_id_ok
	lea	edx,[ebx-2]
	mov	[additional_memory_end],edx
      composed_label_id_ok:
	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
	call	allocate_label
	mov	[anonymous_forward],eax
      anonymous_ok:
	xor	ebx,ebx
	ret
      anonymous_back:
	mov	eax,[anonymous_reverse]
	add	esi,2
	or	eax,eax
	jz	bogus_anonymous
	jmp	anonymous_ok
      bogus_anonymous:
	call	allocate_label
	mov	[anonymous_reverse],eax
	jmp	anonymous_ok
      new_anonymous:
	add	esi,2
	mov	eax,[anonymous_forward]
	or	eax,eax
	jnz	new_anonymous_ok
	call	allocate_label
      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],'$'
	je	current_address_label
	cmp	byte [esi],'?'
	jne	find_label
	cmp	ecx,1
	jne	find_label
	inc	esi
	mov	eax,0Fh
	ret
      current_address_label:
	cmp	ecx,3
	je	current_address_label_3_characters
	ja	find_label
	inc	esi
	cmp	ecx,1
	jbe	get_current_offset_id
	inc	esi
	cmp	byte [esi-1],'$'
	je	get_org_origin_id
	cmp	byte [esi-1],'%'
	je	get_file_offset_id
	sub	esi,2
	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_file_offset_id:
	mov	eax,4
	ret
      current_address_label_3_characters:
	cmp	word [esi+1],'%%'
	jne	find_label
	add	esi,3
      get_actual_file_offset_id:
	mov	eax,5
	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]
	mov	edi,[edi+24]
	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	eax,[eax+4]
	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	numeric_name
      name_first_char_ok:
	cmp	al,'$'
	jne	check_for_reserved_word
      numeric_name:
	add	esi,ecx
      reserved_word:
	mov	eax,0Fh
	pop	edi
	ret
      check_for_reserved_word:
	call	get_instruction
	jnc	reserved_word
	call	get_data_directive
	jnc	reserved_word
	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+8]
	cmp	eax,[additional_memory_end]
	ja	out_of_memory
	mov	[free_additional_memory],eax
	mov	ebx,esi
	add	esi,ecx
	mov	eax,[label_leaf]
	mov	edi,[eax]
	mov	[edx],edi
	mov	[eax],edx
	call	allocate_label
	mov	[edx+4],eax
	mov	[eax+24],ebx
	pop	edi
	ret
      allocate_label:
	mov	eax,[labels_list]
	mov	ecx,LABEL_STRUCTURE_SIZE shr 2
      initialize_label:
	sub	eax,4
	mov	dword [eax],0
	loop	initialize_label
	mov	[labels_list],eax
	ret

LABEL_STRUCTURE_SIZE = 32