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