// File: /workspace/github_c_makefile_star2_O0/tstword[P]MIPSAssemblerC/src/assembler.c
// Function: check_directive
int check_directive(struct instruction_node *instr) {
    struct reserved_entry *directive = instr->mnemonic;
    struct operand_node *operand_list = instr->operand_list;

    /* Check if entry is directive */
    if(directive->token != TOK_DIRECTIVE) return 0;

    struct opcode_entry *entry = (struct opcode_entry *)directive->attrptr;

    int assemble_status = 1; /* Assume assembled directive */

    if(!verify_operand_list(directive, operand_list)) {
        destroy_instruction(instr);
        return 0;
    }

    /* Check if segment is text before handling directive */
    switch(entry - opcode_table) {
        case DIRECTIVE_ASCII:
        case DIRECTIVE_ASCIIZ:
        case DIRECTIVE_HALF:
        case DIRECTIVE_BYTE:
            if(cfg_assembler->segment != SEGMENT_DATA) {
                fprintf(stderr, "Directive '%s' is not allowed in the .text segment on line %ld\n", directive->id, cfg_assembler->lineno);
                cfg_assembler->status = ASSEMBLER_STATUS_FAIL;
                destroy_instruction(instr);
                return 0;
            }
            break;
    }

    switch(entry->opcode) {
        case DIRECTIVE_INCLUDE: {
            /* Create tokenizer structure */
            struct tokenizer *tokenizer = create_tokenizer(operand_list->identifier);
            if(tokenizer == NULL) {
                fprintf(stderr, "Failed to include file '%s' on line %ld : ", operand_list->identifier, cfg_assembler->lineno);
                perror(NULL);
                cfg_assembler->status = ASSEMBLER_STATUS_FAIL;
                destroy_instruction(instr);
                assemble_status = 0;
            } 
            else {
                insert_front(cfg_assembler->tokenizer_list, (void *)tokenizer);
                cfg_assembler->tokenizer = tokenizer;
                cfg_assembler->lookahead = get_next_token(tokenizer);
            }
            break;
        }
        case DIRECTIVE_TEXT: 
            cfg_assembler->segment = SEGMENT_TEXT;
            break;
        case DIRECTIVE_DATA:
            cfg_assembler->segment = SEGMENT_DATA;
            cfg_assembler->auto_align = 1;
            break;
        case DIRECTIVE_KTEXT:
            cfg_assembler->segment = SEGMENT_KTEXT;
            break;
        case DIRECTIVE_KDATA:
            cfg_assembler->segment = SEGMENT_KDATA;
            break;
        case DIRECTIVE_ALIGN: {
            if(operand_list->value.integer > 31) {
                fprintf(stderr, "Directive '.align n' expects n to be within the range of [0, 31] on line %ld\n", cfg_assembler->lineno);
                cfg_assembler->status = ASSEMBLER_STATUS_FAIL;
                destroy_instruction(instr);
                assemble_status = 0;
            }
            else if(operand_list->value.integer == 0) {
                /* Disable automatic alignment of .half, .word, directives until next .data segment */
                cfg_assembler->auto_align = 0;
            }
            else {
                align_segment_offset(operand_list->value.integer);
            }
            break;
        }
        case DIRECTIVE_WORD: {
            struct operand_node *current_operand = operand_list;
            while(current_operand != NULL) {
                if(current_operand->operand & OPERAND_LABEL) {
                    /* Check if label has been defined */
                    struct symbol_table_entry *sym_entry = get_symbol_table(cfg_assembler->symbol_table, current_operand->identifier);
                    if(sym_entry->status == SYMBOL_UNDEFINED) {
                        /* Special case, this directive can take multiple undefined labels
                         * We must ensure that this instruction is appended only once */
                        if(assemble_status) insert_front(sym_entry->instr_list, (void *)instr);
                        incr_segment_offset(0x4);
                        assemble_status = 0;
                    }
                    else {
                        offset_t sym_offset = sym_entry->offset;
                        write_segment_memory((void *)&sym_offset, 0x4);
                        incr_segment_offset(0x4);
                    }
                }
                else {
                    int value = current_operand->value.integer;
                    write_segment_memory((void *)&value, 0x4);
                    incr_segment_offset(0x4);
                }
                current_operand = current_operand->next;
            }
            break;
        }
        case DIRECTIVE_HALF: {
            struct operand_node *current_operand = operand_list;
            while(current_operand != NULL) {
                int value = current_operand->value.integer;
                write_segment_memory((void *)&value, 0x2);
                incr_segment_offset(0x2);
                current_operand = current_operand->next;
            }
            break;
        }
        case DIRECTIVE_BYTE: {
            struct operand_node *current_operand = operand_list;
            while(current_operand != NULL) {
                int value = current_operand->value.integer;
                write_segment_memory((void *)&value, 0x1);
                incr_segment_offset(0x1);
                current_operand = current_operand->next;
            }
            break;
        }
        case DIRECTIVE_ASCII: {
            write_escaped_string(operand_list->identifier);
            break;
        }
        case DIRECTIVE_ASCIIZ: {
            int nullterm = '\0';
            write_escaped_string(operand_list->identifier);
            write_segment_memory((void *)&nullterm, 0x1);
            incr_segment_offset(0x1);
            break;
        }
        case DIRECTIVE_SPACE: {
            alloc_segment_memory(operand_list->value.integer);
            incr_segment_offset(operand_list->value.integer);
            break;
        }
    }

    return assemble_status;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x80, %rsp
movq %rdi, -0x10(%rbp)
movq -0x10(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x18(%rbp)
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x20(%rbp)
movq -0x18(%rbp), %rax
cmpl $0xc, 0x8(%rax)
je 0x648c
movl $0x0, -0x4(%rbp)
jmp 0x689d
movq -0x18(%rbp), %rax
movq 0x10(%rax), %rax
movq %rax, -0x28(%rbp)
movl $0x1, -0x2c(%rbp)
movq -0x18(%rbp), %rdi
movq -0x20(%rbp), %rsi
callq 0x4140
cmpl $0x0, %eax
jne 0x64c6
movq -0x10(%rbp), %rdi
callq 0x44d0
movl $0x0, -0x4(%rbp)
jmp 0x689d
movq -0x28(%rbp), %rax
leaq 0x7bff(%rip), %rcx      # 0xe0d0
subq %rcx, %rax
sarq $0x3, %rax
movq %rax, -0x78(%rbp)
addq $-0x3c, %rax
subq $0x3, %rax
jb 0x64f4
jmp 0x64e8
movq -0x78(%rbp), %rax
subq $0x40, %rax
jne 0x6553
jmp 0x64f4
movq 0x90ad(%rip), %rax      # 0xf5a8
movzbl 0x45(%rax), %eax
cmpl $0x1, %eax
je 0x6551
movq 0x7aed(%rip), %rax      # 0xdff8
movq (%rax), %rdi
movq -0x18(%rbp), %rax
movq (%rax), %rdx
movq 0x908c(%rip), %rax      # 0xf5a8
movq 0x98(%rax), %rcx
leaq 0x422a(%rip), %rsi      # 0xa754
movb $0x0, %al
callq 0x30c0
movq 0x9070(%rip), %rax      # 0xf5a8
movb $0x2, 0x44(%rax)
movq -0x10(%rbp), %rdi
callq 0x44d0
movl $0x0, -0x4(%rbp)
jmp 0x689d
jmp 0x6553
movq -0x28(%rbp), %rax
movzbl (%rax), %eax
addl $-0x39, %eax
movl %eax, %ecx
movq %rcx, -0x80(%rbp)
subl $0xb, %eax
ja 0x6897
movq -0x80(%rbp), %rax
leaq 0x3e81(%rip), %rcx      # 0xa3f8
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq -0x20(%rbp), %rax
movq 0x8(%rax), %rdi
callq 0x8e60
movq %rax, -0x38(%rbp)
cmpq $0x0, -0x38(%rbp)
jne 0x65ec
movq 0x7a59(%rip), %rax      # 0xdff8
movq (%rax), %rdi
movq -0x20(%rbp), %rax
movq 0x8(%rax), %rdx
movq 0x8ff7(%rip), %rax      # 0xf5a8
movq 0x98(%rax), %rcx
leaq 0x41d5(%rip), %rsi      # 0xa794
movb $0x0, %al
callq 0x30c0
xorl %eax, %eax
movl %eax, %edi
callq 0x3120
movq 0x8fd2(%rip), %rax      # 0xf5a8
movb $0x2, 0x44(%rax)
movq -0x10(%rbp), %rdi
callq 0x44d0
movl $0x0, -0x2c(%rbp)
jmp 0x6623
movq 0x8fb5(%rip), %rax      # 0xf5a8
movq 0x8(%rax), %rdi
movq -0x38(%rbp), %rsi
callq 0x7210
movq -0x38(%rbp), %rcx
movq 0x8f9d(%rip), %rax      # 0xf5a8
movq %rcx, (%rax)
movq -0x38(%rbp), %rdi
callq 0x8f90
movl %eax, %ecx
movq 0x8f88(%rip), %rax      # 0xf5a8
movl %ecx, 0x40(%rax)
jmp 0x6897
movq 0x8f79(%rip), %rax      # 0xf5a8
movb $0x0, 0x45(%rax)
jmp 0x6897
movq 0x8f69(%rip), %rax      # 0xf5a8
movb $0x1, 0x45(%rax)
movq 0x8f5e(%rip), %rax      # 0xf5a8
movb $0x1, 0x46(%rax)
jmp 0x6897
movq 0x8f4e(%rip), %rax      # 0xf5a8
movb $0x2, 0x45(%rax)
jmp 0x6897
movq 0x8f3e(%rip), %rax      # 0xf5a8
movb $0x3, 0x45(%rax)
jmp 0x6897
movq -0x20(%rbp), %rax
cmpl $0x1f, 0x8(%rax)
jbe 0x66c0
movq 0x7974(%rip), %rax      # 0xdff8
movq (%rax), %rdi
movq 0x8f1a(%rip), %rax      # 0xf5a8
movq 0x98(%rax), %rdx
leaq 0x4123(%rip), %rsi      # 0xa7bf
movb $0x0, %al
callq 0x30c0
movq 0x8efe(%rip), %rax      # 0xf5a8
movb $0x2, 0x44(%rax)
movq -0x10(%rbp), %rdi
callq 0x44d0
movl $0x0, -0x2c(%rbp)
jmp 0x66e5
movq -0x20(%rbp), %rax
cmpl $0x0, 0x8(%rax)
jne 0x66d7
movq 0x8ed7(%rip), %rax      # 0xf5a8
movb $0x0, 0x46(%rax)
jmp 0x66e3
movq -0x20(%rbp), %rax
movl 0x8(%rax), %edi
callq 0x3570
jmp 0x66e5
jmp 0x6897
movq -0x20(%rbp), %rax
movq %rax, -0x40(%rbp)
cmpq $0x0, -0x40(%rbp)
je 0x67b6
movq -0x40(%rbp), %rax
movzbl (%rax), %eax
andl $0x1, %eax
cmpl $0x0, %eax
je 0x6783
movq 0x8e95(%rip), %rax      # 0xf5a8
movq 0x10(%rax), %rdi
movq -0x40(%rbp), %rax
movq 0x8(%rax), %rsi
callq 0x7ef0
movq %rax, -0x48(%rbp)
movq -0x48(%rbp), %rax
movzbl 0x8(%rax), %eax
cmpl $0x0, %eax
jne 0x675f
cmpl $0x0, -0x2c(%rbp)
je 0x674c
movq -0x48(%rbp), %rax
movq 0x18(%rax), %rdi
movq -0x10(%rbp), %rsi
callq 0x7210
movl $0x4, %edi
callq 0x3490
movl $0x0, -0x2c(%rbp)
jmp 0x6781
movq -0x48(%rbp), %rax
movl 0xc(%rax), %eax
movl %eax, -0x4c(%rbp)
leaq -0x4c(%rbp), %rdi
movl $0x4, %esi
callq 0x3740
movl $0x4, %edi
callq 0x3490
jmp 0x67a5
movq -0x40(%rbp), %rax
movl 0x8(%rax), %eax
movl %eax, -0x50(%rbp)
leaq -0x50(%rbp), %rdi
movl $0x4, %esi
callq 0x3740
movl $0x4, %edi
callq 0x3490
movq -0x40(%rbp), %rax
movq 0x10(%rax), %rax
movq %rax, -0x40(%rbp)
jmp 0x66f2
jmp 0x6897
movq -0x20(%rbp), %rax
movq %rax, -0x58(%rbp)
cmpq $0x0, -0x58(%rbp)
je 0x67fa
movq -0x58(%rbp), %rax
movl 0x8(%rax), %eax
movl %eax, -0x5c(%rbp)
leaq -0x5c(%rbp), %rdi
movl $0x2, %esi
callq 0x3740
movl $0x2, %edi
callq 0x3490
movq -0x58(%rbp), %rax
movq 0x10(%rax), %rax
movq %rax, -0x58(%rbp)
jmp 0x67c3
jmp 0x6897
movq -0x20(%rbp), %rax
movq %rax, -0x68(%rbp)
cmpq $0x0, -0x68(%rbp)
je 0x683e
movq -0x68(%rbp), %rax
movl 0x8(%rax), %eax
movl %eax, -0x6c(%rbp)
leaq -0x6c(%rbp), %rdi
movl $0x1, %esi
callq 0x3740
movl $0x1, %edi
callq 0x3490
movq -0x68(%rbp), %rax
movq 0x10(%rax), %rax
movq %rax, -0x68(%rbp)
jmp 0x6807
jmp 0x6897
movq -0x20(%rbp), %rax
movq 0x8(%rax), %rdi
callq 0x37f0
jmp 0x6897
movl $0x0, -0x70(%rbp)
movq -0x20(%rbp), %rax
movq 0x8(%rax), %rdi
callq 0x37f0
leaq -0x70(%rbp), %rdi
movl $0x1, %esi
callq 0x3740
movl $0x1, %edi
callq 0x3490
jmp 0x6897
movq -0x20(%rbp), %rax
movl 0x8(%rax), %eax
movl %eax, %edi
callq 0x35e0
movq -0x20(%rbp), %rax
movl 0x8(%rax), %edi
callq 0x3490
movl -0x2c(%rbp), %eax
movl %eax, -0x4(%rbp)
movl -0x4(%rbp), %eax
addq $0x80, %rsp
popq %rbp
retq
nopl (%rax)