#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdint.h>

// ELF64 format structures matching standard Linux RISC-V 64-bit ABI definitions
#define EI_NIDENT 16

typedef struct {
    uint8_t  e_ident[EI_NIDENT];
    uint16_t e_type;
    uint16_t e_machine;
    uint32_t e_version;
    uint64_t e_entry;
    uint64_t e_phoff;
    uint64_t e_shoff;
    uint32_t e_flags;
    uint16_t e_ehsize;
    uint16_t e_phentsize;
    uint16_t e_phnum;
    uint16_t e_shentsize;
    uint16_t e_shnum;
    uint16_t e_shstrndx;
} Elf64_Ehdr;

typedef struct {
    uint32_t p_type;
    uint32_t p_flags;
    uint64_t p_offset;
    uint64_t p_vaddr;
    uint64_t p_paddr;
    uint64_t p_filesz;
    uint64_t p_memsz;
    uint64_t p_align;
} Elf64_Phdr;

// Trim formatting utility
void trim(char* str) {
    char* end;
    while(isspace((unsigned char)*str)) str++;
    if(*str == 0) return;
    end = str + strlen(str) - 1;
    while(end > str && isspace((unsigned char)*end)) end--;
    end[1] = '\0';
}

// Emits an executable Linux ELF64 binary for RISC-V directly to disk
void emit_native_riscv_elf(const char* output_filename, uint8_t* text_payload, size_t text_size) {
    FILE* elf = fopen(output_filename, "wb");
    if (!elf) {
        printf("Error: Cannot create output executable file %s\n", output_filename);
        return;
    }

    Elf64_Ehdr header;
    memset(&header, 0, sizeof(Elf64_Ehdr));
    
    // Identity fields for 64-bit Little-Endian RISC-V Linux Execution targets
    header.e_ident[0] = 0x7F; header.e_ident[1] = 'E'; header.e_ident[2] = 'L'; header.e_ident[3] = 'F';
    header.e_ident[4] = 2;    // ELFCLASS64
    header.e_ident[5] = 1;    // ELFDATA2LSB (Little Endian)
    header.e_ident[6] = 1;    // EV_CURRENT
    header.e_ident[7] = 0;    // ELFOSABI_NONE
    
    header.e_type = 2;        // ET_EXEC (Executable file)
    header.e_machine = 243;   // EM_RISCV
    header.e_version = 1;     // EV_CURRENT
    header.e_entry = 0x10000 + sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr); // Start execution directly after headers
    header.e_phoff = sizeof(Elf64_Ehdr);
    header.e_ehsize = sizeof(Elf64_Ehdr);
    header.e_phentsize = sizeof(Elf64_Phdr);
    header.e_phnum = 1;

    Elf64_Phdr program_header;
    memset(&program_header, 0, sizeof(Elf64_Phdr));
    program_header.p_type = 1; // PT_LOAD
    program_header.p_flags = 5; // PF_R | PF_X (Readable and Executable text section segment)
    program_header.p_offset = 0;
    program_header.p_vaddr = 0x10000;
    program_header.p_paddr = 0x10000;
    program_header.p_filesz = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr) + text_size;
    program_header.p_memsz = program_header.p_filesz;
    program_header.p_align = 0x10000;

    // Write components straight down to binary layout
    fwrite(&header, 1, sizeof(header), elf);
    fwrite(&program_header, 1, sizeof(program_header), elf);
    fwrite(text_payload, 1, text_size, elf);
    
    fclose(elf);
}

int main(int argc, char** argv) {
    if (argc < 5) {
        printf("Autonomous Native PROBOL & PASM ELF-Compiler\n");
        printf("Usage: %s --type=[pasm|probol] <input_file> -o <output_binary>\n", argv[0]);
        return 1;
    }

    char* type = argv[1];
    char* input_filename = argv[2];
    char* output_binary = argv[4];

    FILE* in = fopen(input_filename, "r");
    if (!in) {
        printf("Error: Could not read source code file %s\n", input_filename);
        return 1;
    }

    // Allocate an processing execution buffer for generating RISC-V opcodes
    uint8_t machine_buffer[8192];
    size_t code_ptr = 0;

    char line[256];
    while (fgets(line, sizeof(line), in)) {
        trim(line);
        if (strlen(line) == 0 || line[0] == ';' || line[0] == '*') continue;

        // --- RISC-V MACHINE CODE GENERATION LOOP ---
        // For demonstration, we translate operations into direct native system calls 
        // to gracefully exit, or execute structural tasks.
        if (strstr(line, "EXIT") || strstr(line, "STOP RUN")) {
            // Emitting RISC-V Machine Opcodes Natively:
            // li a7, 93   (System Call ID for exit -> 0x05d00893)
            // li a0, 0    (Return Status Value 0   -> 0x00000513)
            // ecall       (System Call Trigger     -> 0x00000073)
            uint32_t li_a7 = 0x05d00893;
            uint32_t li_a0 = 0x00000513;
            uint32_t ecall = 0x00000073;
            
            memcpy(&machine_buffer[code_ptr], &li_a7, 4); code_ptr += 4;
            memcpy(&machine_buffer[code_ptr], &li_a0, 4); code_ptr += 4;
            memcpy(&machine_buffer[code_ptr], &ecall, 4); code_ptr += 4;
        }
        // Extensions for parsing distribution assignments (MOVP/ADDP) can be packed here
        // as jumps to an internal lightweight runtime payload embedded within the buffer.
    }
    
    // If no explicit exit statement was given, enforce clean termination safety
    if (code_ptr == 0) {
        uint32_t li_a7 = 0x05d00893; uint32_t li_a0 = 0x00000513; uint32_t ecall = 0x00000073;
        memcpy(&machine_buffer[code_ptr], &li_a7, 4); code_ptr += 4;
        memcpy(&machine_buffer[code_ptr], &li_a0, 4); code_ptr += 4;
        memcpy(&machine_buffer[code_ptr], &ecall, 4); code_ptr += 4;
    }

    fclose(in);

    // Emit the valid execution ELF target down to disk
    emit_native_riscv_elf(output_binary, machine_buffer, code_ptr);
    printf("Successfully built standalone executable machine binary: %s\n", output_binary);

    return 0;
}