// This file manages extended assembly.
//	asm <optional stuff> (
//	    "assembler template"
//	    : outputs
//	    : inputs
//	    : clobbers
//	    : labels)
// references https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html and https://www.felixcloutier.com/documents/gcc-asm.html
//
// Special format strings
// In addition to the tokens described by the input, output, and goto operands, these tokens have special meanings in the assembler template:
//
//‘%%’
// Outputs a single ‘%’ into the assembler code.
//
//‘%=’
// Outputs a number that is unique to each instance of the asm statement in the entire compilation. This option is useful when creating local labels and referring to them multiple times in a single template that generates multiple assembler instructions.
//
//‘%{’
//‘%|’
//‘%}’
// Outputs ‘{’, ‘|’, and ‘}’ characters (respectively) into the assembler code.
// When unescaped, these characters have special meaning to indicate multiple assembler dialects.

#include "chibicc.h"

typedef struct
{
    Token *input;      // store the token corresponding to input
    char *variableNumber;     //store the variable %0, %1...
    char *input_value; // store the immediate value
    char *reg;        // store the register that corresponds to the variable size    
    char *reg64;        //store the register 64 bits
    char *regh; //store the high bits of a register like ah
    char *regl; //store the lower bits of a register like al
    char *regw; //store the word register
    char *operand_name; //store the operand name like [dst], [src]
    int index;         // store the index
    char letter;       // store the letter corresponding to input
    int offset;         // store the offset
    int size;          // store the size to determine the operation to do ex movl movb movw movq
    bool isVariable;   // store true if it's a variable otherwise false for immediate value
    bool isAddress;    // store true if it's an address pointer
    bool isArray;       //true if it's an array variable
    bool isStruct;       //true if it's a struct variable
    bool isToNegate;    //true if the value should be negate
    int indexArray;     //store the index element of array
    int offsetArray;     //store the index of array
    int offsetStruct;   //store the offset of the struct
    bool isq;   //true if  q: 8-bit registers (al, bl, cl, dl)
    bool isl;  //true if l: 32-bit registers (eax, ebx, ecx, edx)
    bool is_pure_register; // true if the input is a pure register
    bool isLea; // true if it's a lea operation like &var
    bool isBinaryExpr; // true if input is a simple binary expression
    char bin_op; // '+' or '-'
    bool bin_lhs_is_imm;
    bool bin_rhs_is_imm;
    long bin_lhs_imm;
    long bin_rhs_imm;
    int bin_lhs_offset;
    int bin_rhs_offset;
    int bin_lhs_size;
    int bin_rhs_size;
} AsmInput;

typedef struct
{
    Token *output;    // store the token corresponding to input
    char *variableNumber;     //store the variable %0, %1...
    char *prefix;     //= or +
    char *reg;        // store the register that corresponds to the variable size
    char *reg64;        //store the register 64 bits
    char *regh; //store the high bits of a register like ah
    char *regl; //store the lower bits of a register like al
    char *regw; //store the word register
    char *operand_name; //store the operand name like [dst], [src]
    char letter;      // to store a b r
    int index;        // order in output
    int size;         // store the size to determine the operation to do
    bool isRegister;  // r
    bool isMemory;    // m
    bool isAlpha;     // if is not r neither m is considered Alpha
    int offset;        // store the offset
    bool isVariable;  // store true if it's a variable otherwise false for immediate value
    bool isAddress;   // store true if it's an address pointer
    bool isArray;       //true if it's an array variable
    bool isStruct;       //true if it's a struct variable
    int indexArray;     //store the index element of array
    int offsetArray;     //store the index of array
    int offsetStruct;   //store the offset of the struct
    bool inputToGenerate;   //true if it's the corresponding input should be generated
    bool isq;   //true if  q: 8-bit registers (al, bl, cl, dl)
    bool isl;  //true if l: 32-bit registers (eax, ebx, ecx, edx)
    bool is_pure_register; 
} AsmOutput;

typedef struct
{
    char *templatestr;
    //bool hasPercent;
} AsmTemplate;

typedef struct
{
    char *clobber;    
} AsmClobber;

typedef struct
{
    AsmTemplate *template;
    AsmOutput *output[10];
    AsmInput *input[10];
    AsmClobber *clobber[10];
    int nboutput;
    int nbinput;
    int nbclobber;
    int nblabel;
} AsmExtended;

typedef AsmExtended AsmExtended;

typedef enum
{
    AT_TEMPLATE, // assembler template
    AT_OUTPUT,   // outputs
    AT_INPUT,    // inputs
    AT_CLOBBER,  // clobbers
    AT_LABEL,    // labels
} AsmType;


//
//+ means that the output is actually a read-write value.
//=& means that the output is an early-clobber output. Its initial value is unspecified.
//= means that the output is write-only.
//=@ccCOND is a special case of = that allows you to query the result of a condition code at the end of your assembly statement.

// typedef enum
// {
//     CP_READWRITEREG = 1, // +r
//     CP_READWRITEMEM,     // +m
//     CP_CLOBBEROUTPUTREG, // =&r
//     CP_WRITEONLYREG,     // =r
//     CP_WRITEONLYMEM,     // =m
//     CP_WRITEONLYOTH,     // =a =b =c...
//     CP_COND,             // =@ccCOND
// } ConstraintPrefix;

static AsmExtended *asmExt;
static int nbInput = 0;
static int nbOutput = 0;
static int nbClobber = 0;
static int nbLabel = 0;
static int asmtype = 0;
extern Context *ctx;
static bool hasInput = false;
static bool hasOutput = false;
static bool isToNegate = false;
static bool hasOperandName = false;

static char *register_lower(char *reg);
static char *register_higher(char *reg);
static char *register_word(char *reg);
static bool parse_simple_binary_input(Token **rest, Token *tok, Obj *locals);
static char *arith_opcode(char op, int size);

static bool is_mem_placeholder(char *s) {
    return s && !strcmp(s, "%mem");
}

static Obj *find_obj_by_tok(Obj *locals, Token *tok) {
    if (!locals || !tok || tok->kind != TK_IDENT)
        return NULL;

    for (Obj *var = locals; var; var = var->next) {
        if (!var->name)
            continue;
        if ((int)strlen(var->name) == tok->len && !strncmp(var->name, tok->loc, tok->len))
            return var;
    }
    return NULL;
}

static char *use_fixed_register(char *reg64) {
    // Fixed constraints like "a" or "d" must use the exact register even if
    // other operands are present; flexible constraints should adapt instead.
    if (!check_register_used(reg64))
        add_register_used(reg64);
    return reg64;
}

static void ensure_input_reg(AsmInput *in, char *preferred64) {
    if (in->reg && !is_mem_placeholder(in->reg))
        return;

    in->reg = specific_register_available(preferred64);
    if (!in->reg)
        error("%s:%d: error: in ensure_input_reg :reg is null!", __FILE__, __LINE__);
    in->reg64 = in->reg;
    in->regh = register_higher(in->reg64);
    in->regl = register_lower(in->reg64);
    in->regw = register_word(in->reg64);
}

static void ensure_output_reg(AsmOutput *out, char *preferred64) {
    if (out->reg && !is_mem_placeholder(out->reg))
        return;

    out->reg = specific_register_available(preferred64);
    if (!out->reg)
        error("%s:%d: error: in ensure_output_reg :reg is null!", __FILE__, __LINE__);
    out->reg64 = out->reg;
    out->regh = register_higher(out->reg64);
    out->regl = register_lower(out->reg64);
    out->regw = register_word(out->reg64);
}


char *extended_asm(Node *node, Token **rest, Token *tok, Obj *locals)
{
    char *input_asm_str;
    char *output_loading;
    asmtype = 0;
    nbInput = 0;
    nbOutput = 0;
    nbClobber = 0;
    nbLabel = 0;
    hasInput = false;
    hasOutput = false;
    // Work on a private, writable buffer. Substitutions are done in-place and
    // string_replace() assumes enough capacity (up to 10000 bytes).
    char *template = calloc(1, sizeof(char) * 10000);
    if (!template)
        error("%s:%d: error: in extended_asm : out of memory", __FILE__, __LINE__);
    strncpy(template, tok->str, 9999);
    char *asm_str = calloc(1, sizeof(char) * 10000);
    if (isDebug)
        printf("template==%s\n", template);
    // allocate memory for all structs needed
    asmExt = calloc(1, sizeof(AsmExtended));
    asmExt->template = calloc(1, sizeof(AsmTemplate));
    for (int i = 0; i < 10; i++)
        asmExt->input[i] = calloc(1, sizeof(AsmInput));
    for (int i = 0; i < 10; i++)
        asmExt->output[i] = calloc(1, sizeof(AsmOutput));
    for (int i = 0; i < 10; i++)
        asmExt->clobber[i] = calloc(1, sizeof(AsmClobber));


    //strncpy(asm_str, "", strlen(asm_str) + 1);
    char *output_asm_str = calloc(1, sizeof(char) * 2500);
    char *input_final = calloc(1, sizeof(char) * 2500);
    char *input_for_output = calloc(1, sizeof(char) * 4000);
    asmExt->template->templatestr = template;
    // asmExt->template->hasPercent = check_template(template);

    //clear the registerUsed array
    clear_register_used();
    //mark the register used if found in template
    check_register_in_template(template);
    while (!equal(tok->next, ";") && !equal(tok, ";"))
    {
        switch (asmtype)
        {
        case AT_TEMPLATE: // assembler template
            break;
        case AT_OUTPUT: // outputs
            if (equal(tok, ":"))
                break;
            output_asm(node, rest, tok, locals);
            // generate output instruction for each output variable
            if (asmExt->output[nbOutput]->variableNumber) {

                hasOutput = true;
                output_loading = generate_output_asm(asmExt->output[nbOutput]->variableNumber);
                // replace %9 by the correct register
                if (!output_loading)
                 error("%s:%d: error: in extended_asm function extended_asm :output_loading is null!", __FILE__, __LINE__);
                if (!asmExt->output[nbOutput]->reg)
                error("%s:%d: error: in extended_asm function extended_asm :asmExt->output[nbOutput]->reg is null!", __FILE__, __LINE__);
                 output_loading = subst_asm(output_loading, asmExt->output[nbOutput]->reg, asmExt->output[nbOutput]->variableNumber);
                //generate the ouput instruction
                strncat(output_asm_str, output_loading, strlen(output_loading));
            } else { //to manage the case of no output
                tok = tok->next;
                *rest = tok;
            }
            nbOutput++;
            tok = *rest;
            break;
        case AT_INPUT: // inputs
            // return %0, %1 or %x
            if (equal(tok, ":"))
                break;
            input_asm(node, rest, tok, locals);
            // generate input instruction to load the parameter into register
            // Skip input loading for immediate constants - they will be substituted directly in the template
            if (asmExt->input[nbInput]->variableNumber) {
                hasInput = true;
                input_asm_str = generate_input_asm(asmExt->input[nbInput]->variableNumber);
                //replace %9, by the correct
                if (!input_asm_str)
                    error("%s:%d: error: in extended_asm function extended_asm :input_asm_str is null!", __FILE__, __LINE__);
                if (!asmExt->input[nbInput]->reg)
                    error("%s:%d: error: in extended_asm function extended_asm :asmExt->input[nbInput]->reg is null!", __FILE__, __LINE__);
                if (asmExt->input[nbInput]->isAddress)
                    input_asm_str = subst_asm(input_asm_str, asmExt->input[nbInput]->reg64, asmExt->input[nbInput]->variableNumber);
                else
                    input_asm_str = subst_asm(input_asm_str, asmExt->input[nbInput]->reg, asmExt->input[nbInput]->variableNumber);
                // concatenate the input final strings to add to the assembly
                
                strncat(input_final, input_asm_str, strlen(input_asm_str));
            }  else if (asmExt->input[nbInput]->input_value) {
                // For immediate constants, just mark as having input so proper substitution happens
                hasInput = true;
            } else { //to manage the case of no input
                tok = tok->next;
                *rest = tok;
            }
            nbInput++;
            tok = *rest;
            break;
        case AT_CLOBBER: // clobbers
            if (equal(tok, ":"))
                break;
            asmExt->clobber[nbClobber]->clobber = tok->loc;
            tok = tok->next;
            // if (equal(tok, ","))
            //     tok = tok->next;
            *rest = tok;
            nbClobber++;            
            break;
        case AT_LABEL: // labels
            //nbLabel++;
            tok = tok->next;
            *rest = tok;            
            break;
        default: // error
            error_tok(tok, "%s:%d : in extended_asm function : too much parameters or complex extended assembly not managed!", __FILE__, __LINE__);
        }
        if (equal(tok, ":")) {
            asmtype += 1;
            tok = tok->next;
            continue;
        }

        if (equal(tok, ";"))
            break;

        tok = tok->next;
    }


   //case of no input need to generate input for output
    if (hasOutput && !hasInput){
        input_for_output = generate_input_for_output();        
        if (input_for_output != NULL) {                
                strncat(asm_str, input_for_output, strlen(input_for_output));
                
            }
    }

    if (hasOutput) {
        // First, substitute named operands like %[dst]
        for (int i = 0; i < nbOutput; i++) {
            if (asmExt->output[i]->operand_name) {
                char pattern[32];
                snprintf(pattern, sizeof(pattern), "%%[%s]", asmExt->output[i]->operand_name);
                template = subst_asm(template, asmExt->output[i]->reg, pattern);
            }
        }
        //replace each %9 by the correct output register
        char *tmp_asm = calloc(1, sizeof(char) * 300);
        for (int i = 0; i < nbOutput; i++)
        {
           
            if (asmExt->output[i]->isAddress) {
                char *tmp = calloc(1, sizeof(char) * 30);
                strncat(tmp, "(", 2);
                strncat(tmp, asmExt->output[i]->reg64, strlen(asmExt->output[i]->reg64) );
                strncat(tmp, ")", 2);
                tmp_asm = subst_asm(template, tmp, asmExt->output[i]->variableNumber);
                free(tmp);
            }else {
                  tmp_asm = subst_asm(template, asmExt->output[i]->reg, asmExt->output[i]->variableNumber);                         
                }
        }
            
        //special case %b0 %h0
        for (int i = 0; i < nbOutput; i++) {
            // Replace %bN with regl
            if (asmExt->output[i]->regl) {
                char pattern[8];
                snprintf(pattern, sizeof(pattern), "%%b%d", i);
                tmp_asm = subst_asm(template, asmExt->output[i]->regl, pattern);
            }
            // Replace %hN with regh
            if (asmExt->output[i]->regh) {
                char pattern[8];
                snprintf(pattern, sizeof(pattern), "%%h%d", i);
                tmp_asm = subst_asm(template, asmExt->output[i]->regh, pattern);
                }
            // Replace %wN with regw
            if (asmExt->output[i]->regw) {
                char pattern[8];
                snprintf(pattern, sizeof(pattern), "%%w%d", i);
                tmp_asm = subst_asm(template, asmExt->output[i]->regw, pattern);
                }                
            }
        strncat(asm_str, tmp_asm, strlen(tmp_asm));

    }



    if (hasInput) {
        if (hasOperandName) {
            // First, substitute named operands like %[src]
            for (int i = 0; i < nbInput; i++) {
                if (asmExt->input[i]->operand_name) {
                    char pattern[32];
                    snprintf(pattern, sizeof(pattern), "%%[%s]", asmExt->input[i]->operand_name);
                    template = subst_asm(template, asmExt->input[i]->reg, pattern);
                }
            }
        }
        //printf("template=%s\n", template);
        //replace each %9 by the correct input register
        for (int i = 0; i < nbInput; i++)
        {
            // Replace %bN with regl
            if (asmExt->input[i]->regl) {
                char pattern[8];
                snprintf(pattern, sizeof(pattern), "%%b%d", asmExt->input[i]->index);
                asm_str = subst_asm(template, asmExt->input[i]->regl, pattern);
            }
            // Replace %hN with regh
            if (asmExt->input[i]->regh) {
                char pattern[8];
                snprintf(pattern, sizeof(pattern), "%%h%d", asmExt->input[i]->index);
                asm_str = subst_asm(template, asmExt->input[i]->regh, pattern);
                }
            // Replace %wN with regw
            if (asmExt->input[i]->regw) {
                char pattern[8];
                snprintf(pattern, sizeof(pattern), "%%w%d", asmExt->input[i]->index);
                asm_str = subst_asm(template, asmExt->input[i]->regw, pattern);
            }                
            
            if (asmExt->input[i]->input_value) {
                // For immediate values, substitute the value directly with $ prefix
                char *tmp = calloc(1, sizeof(char) * 30);
                strncat(tmp, "$", 2);
                strncat(tmp, asmExt->input[i]->input_value, strlen(asmExt->input[i]->input_value));
                asm_str = subst_asm(template, tmp, asmExt->input[i]->variableNumber);
                free(tmp);
            } else if (asmExt->input[i]->isAddress && asmExt->input[i]->letter == 'm') {
                char *tmp = calloc(1, sizeof(char) * 30);
                strncat(tmp, "(", 2);
                strncat(tmp, asmExt->input[i]->reg64, strlen(asmExt->input[i]->reg64) );
                strncat(tmp, ")", 2);
                asm_str = subst_asm(template, tmp, asmExt->input[i]->variableNumber);
                free(tmp);
            } else {
                asm_str = subst_asm(template, asmExt->input[i]->reg, asmExt->input[i]->variableNumber); 

            }
        }

        //generate the input instructions before the output 
        if (input_final != NULL)
        {  
            if (nbOutput > 0)
                input_for_output = generate_input_for_output();
            //input_for_output can be NULL if no input to generate for output
            //generate first the input for output and then the input for the rest of the template
            if (input_for_output != NULL && input_final != NULL) {
                strncat(input_for_output, input_final, strlen(input_final));
                strncpy(input_final, input_for_output, strlen(input_for_output) + 1);
                strncat(input_final, asm_str, strlen(asm_str));     
            } else {
                strncat(input_final, asm_str, strlen(asm_str));        
            }
            asm_str = input_final;            

        }
    }


    //generate the output instructions
    if (hasOutput && output_asm_str != NULL)
    {
        strncat(asm_str, output_asm_str, strlen(output_asm_str));
    }

    //case __asm__ __volatile__ ("rep; nop" ::: "memory");  
    if (!hasOutput && !hasInput) {
        if (strlen(template) == 0)
            strncat(asm_str, "\nnop;\n", 7);
        else
        strncat(asm_str, template, strlen(template));
    }
    //replace special characters
    // replace %% by %
    // replace ‘%{’ by '{', ‘%|’ by '|' and ‘%}’ by '}'
    asm_str = subst_asm(asm_str, " %", "%%");
    asm_str = subst_asm(asm_str, " {", "%{");
    asm_str = subst_asm(asm_str, " |", "%|");
    asm_str = subst_asm(asm_str, " }", "%}");
    
    if (isDebug)
        printf("=====template=%s\n====asm_str=%s\n====input_final==%s\n====output_asm_str===%s\n", template, asm_str, input_final, output_asm_str);

    tok = tok->next;
    //printf("tok=%s\n", tok->loc);
    *rest = tok;
    // Don't leak template register "usage" into subsequent codegen.
    clear_register_used();
    // free memory
    for (int i = 0; i < 10; i++)
        free(asmExt->input[i]);
    for (int i = 0; i < 10; i++)
        free(asmExt->output[i]);
    for (int i = 0; i < 10; i++)
        free(asmExt->clobber[i]);
    free(template);
    free(asmExt->template);
    // free(input_for_output);
    // free(output_asm_str);
    // free(input_final);
    free(asmExt);
    return asm_str;
}

static bool parse_simple_binary_input(Token **rest, Token *tok, Obj *locals)
{
    Token *p = tok;
    while (equal(p, "("))
        p = p->next;

    if (p->kind != TK_IDENT && p->kind != TK_NUM)
        return false;

    Token *lhs = p;
    Token *op = lhs->next;
    if (!equal(op, "+") && !equal(op, "-"))
        return false;

    Token *rhs = op->next;
    if (rhs->kind != TK_IDENT && rhs->kind != TK_NUM)
        return false;

    Token *end = rhs->next;
    if (!equal(end, ")"))
        return false;
    while (equal(end, ")"))
        end = end->next;

    AsmInput *in = asmExt->input[nbInput];
    in->isBinaryExpr = true;
    in->bin_op = op->loc[0];
    in->isVariable = false;
    in->isAddress = false;

    if (lhs->kind == TK_IDENT) {
        VarScope *sc = find_var(lhs);
        if (!sc)
            error_tok(lhs, "%s:%d: in input_asm function : variable undefined", __FILE__, __LINE__);
        if (!sc->var->ty)
            error_tok(lhs, "%s:%d: in input_asm function : variable type unknown", __FILE__, __LINE__);
        in->bin_lhs_is_imm = false;
        in->bin_lhs_offset = sc->var->offset;
        in->bin_lhs_size = sc->var->ty->size;
        if (sc->var->funcname) {
            update_offset(sc->var->funcname, locals);
            in->bin_lhs_offset = sc->var->offset;
        }
    } else {
        in->bin_lhs_is_imm = true;
        in->bin_lhs_imm = lhs->val;
        in->bin_lhs_size = 8;
    }

    if (rhs->kind == TK_IDENT) {
        VarScope *sc = find_var(rhs);
        if (!sc)
            error_tok(rhs, "%s:%d: in input_asm function : variable undefined", __FILE__, __LINE__);
        if (!sc->var->ty)
            error_tok(rhs, "%s:%d: in input_asm function : variable type unknown", __FILE__, __LINE__);
        in->bin_rhs_is_imm = false;
        in->bin_rhs_offset = sc->var->offset;
        in->bin_rhs_size = sc->var->ty->size;
        if (sc->var->funcname) {
            update_offset(sc->var->funcname, locals);
            in->bin_rhs_offset = sc->var->offset;
        }
    } else {
        in->bin_rhs_is_imm = true;
        in->bin_rhs_imm = rhs->val;
        in->bin_rhs_size = 8;
    }

    int size = 8;
    if (!in->bin_lhs_is_imm && !in->bin_rhs_is_imm)
        size = MAX(in->bin_lhs_size, in->bin_rhs_size);
    else if (!in->bin_lhs_is_imm)
        size = in->bin_lhs_size;
    else if (!in->bin_rhs_is_imm)
        size = in->bin_rhs_size;

    in->size = size;
    if (!in->reg)
        error_tok(lhs, "%s:%d: error: in input_asm function input_asm :reg is null!", __FILE__, __LINE__);
    in->reg = update_register_size(in->reg, size);

    *rest = end;
    return true;
}


void output_asm(Node *node, Token **rest, Token *tok, Obj *locals)
{
    VarScope *sc;
    while (!equal(tok->next, ":") && !equal(tok->next, ";"))
    {
        //case of operand named
        if (equal(tok, "[") || equal(tok, "{"))
        {
            char closing = equal(tok, "[") ? ']' : '}';
            tok = tok->next;
            //case of operand named [dst] or {src}
            if (tok->kind == TK_IDENT ) {
                char *name = calloc(tok->len + 1, 1);
                memcpy(name, tok->loc, tok->len);
                name[tok->len] = '\0';
                asmExt->output[nbOutput]->operand_name = name;
                asmExt->output[nbOutput]->index = nbOutput;
                tok = tok->next;
                // Now consume the closing ] or }
                if (!equal(tok, (char[]){closing, 0})) {
                    error_tok(tok, "%s:%d: error: in output_asm function : expected closing %c after operand name", __FILE__, __LINE__, closing);
                }
                tok = tok->next;
            }
            
        }

        // register in write only mode
        // check if the register constraint is followed by a variable like "=r" (val)
        if (tok->kind == TK_STR)
        {
            if (!strncmp(tok->str, "=r", tok->len) || !strncmp(tok->str, "+r", tok->len))
            {
                asmExt->output[nbOutput]->isRegister = true;
                if (!strncmp(tok->str, "=r", tok->len))
                    asmExt->output[nbOutput]->prefix = "=";
                else {
                    asmExt->output[nbOutput]->prefix = "+";
                }
                // Let the allocator choose a free GPR. Hardcoding %rax breaks
                // common patterns like "+r"(carry) alongside "a"(low).
                asmExt->output[nbOutput]->reg = register_available();
                if (!asmExt->output[nbOutput]->reg)
                    error("%s:%d: error: in output_asm function :reg is null!", __FILE__, __LINE__);
                asmExt->output[nbOutput]->reg64 = asmExt->output[nbOutput]->reg;
                asmExt->output[nbOutput]->regh = register_higher(asmExt->output[nbOutput]->reg64);
                asmExt->output[nbOutput]->regl = register_lower(asmExt->output[nbOutput]->reg64);
                asmExt->output[nbOutput]->regw = register_word(asmExt->output[nbOutput]->reg64);
                asmExt->output[nbOutput]->letter = 'r';       
                asmExt->output[nbOutput]->variableNumber = retrieveVariableNumber(nbOutput);         
            }
            if (!strncmp(tok->str, "=&r", tok->len) )
            {
                asmExt->output[nbOutput]->isRegister = true;
                asmExt->output[nbOutput]->prefix = "=";
                asmExt->output[nbOutput]->reg = specific_register_available("%r10");
                if (!asmExt->output[nbOutput]->reg)
                    error("%s:%d: error: in output_asm function :reg is null!", __FILE__,  __LINE__);
                asmExt->output[nbOutput]->reg64 = asmExt->output[nbOutput]->reg;
                asmExt->output[nbOutput]->regh = register_higher(asmExt->output[nbOutput]->reg64);
                asmExt->output[nbOutput]->regl = register_lower(asmExt->output[nbOutput]->reg64);
                asmExt->output[nbOutput]->regw = register_word(asmExt->output[nbOutput]->reg64);
                asmExt->output[nbOutput]->letter = 'r';       
                asmExt->output[nbOutput]->variableNumber = retrieveVariableNumber(nbOutput);       
            }

            else if (!strncmp(tok->str, "=m", tok->len) || !strncmp(tok->str, "+m", tok->len))
            {
                asmExt->output[nbOutput]->isMemory = true;
                if (!strncmp(tok->str, "=m", tok->len))
                    asmExt->output[nbOutput]->prefix = "=";
                else {
                    asmExt->output[nbOutput]->prefix = "+";
                }
                // For pure memory outputs, don't reserve a scratch register.
                // We'll substitute %N with the actual memory operand (e.g. -8(%rbp)).
                asmExt->output[nbOutput]->reg = "%mem";
                asmExt->output[nbOutput]->reg64 = "%mem";
                asmExt->output[nbOutput]->letter = 'm';
                asmExt->output[nbOutput]->inputToGenerate = true;
                asmExt->output[nbOutput]->variableNumber = retrieveVariableNumber(nbOutput);
                
            }
            else if (!strncmp(tok->str, "=q", tok->len) || !strncmp(tok->str, "+q", tok->len))
            {
                asmExt->output[nbOutput]->isMemory = true;
                asmExt->output[nbOutput]->isq = true;
                if (!strncmp(tok->str, "=q", tok->len))
                    asmExt->output[nbOutput]->prefix = "=";
                else {
                    asmExt->output[nbOutput]->prefix = "+";
                }
                asmExt->output[nbOutput]->reg = register_available();
                if (!asmExt->output[nbOutput]->reg)
                    error("%s:%d: error: in output_asm function :reg is null!", __FILE__, __LINE__);
                asmExt->output[nbOutput]->reg64 = asmExt->output[nbOutput]->reg; 
                asmExt->output[nbOutput]->regh = register_higher(asmExt->output[nbOutput]->reg64);
                asmExt->output[nbOutput]->regl = register_lower(asmExt->output[nbOutput]->reg64);  
                asmExt->output[nbOutput]->regw = register_word(asmExt->output[nbOutput]->reg64);                             
                asmExt->output[nbOutput]->letter = 'q';
                asmExt->output[nbOutput]->inputToGenerate = true;
                asmExt->output[nbOutput]->variableNumber = retrieveVariableNumber(nbOutput);
                
            }
            else if (!strncmp(tok->str, "=Q", tok->len) || !strncmp(tok->str, "+Q", tok->len))
            {
                asmExt->output[nbOutput]->isMemory = true;
                asmExt->output[nbOutput]->isq = true;
                if (!strncmp(tok->str, "=Q", tok->len))
                    asmExt->output[nbOutput]->prefix = "=";
                else {
                    asmExt->output[nbOutput]->prefix = "+";
                }
                asmExt->output[nbOutput]->reg = register_available();
                if (!asmExt->output[nbOutput]->reg)
                    error("%s:%d: error: in output_asm function :reg is null!", __FILE__, __LINE__);
                asmExt->output[nbOutput]->reg64 = asmExt->output[nbOutput]->reg;    
                asmExt->output[nbOutput]->regh = register_higher(asmExt->output[nbOutput]->reg64);
                asmExt->output[nbOutput]->regl = register_lower(asmExt->output[nbOutput]->reg64);
                asmExt->output[nbOutput]->regw = register_word(asmExt->output[nbOutput]->reg64);
                asmExt->output[nbOutput]->letter = 'Q';
                asmExt->output[nbOutput]->inputToGenerate = true;
                asmExt->output[nbOutput]->variableNumber = retrieveVariableNumber(nbOutput);
                
            }
            else if (!strncmp(tok->str, "=l", tok->len) || !strncmp(tok->str, "+l", tok->len))
            {
                asmExt->output[nbOutput]->isMemory = true;
                asmExt->output[nbOutput]->isl = true;
                if (!strncmp(tok->str, "=l", tok->len))
                    asmExt->output[nbOutput]->prefix = "=";
                else {
                    asmExt->output[nbOutput]->prefix = "+";
                }
                asmExt->output[nbOutput]->reg = register_available();
                if (!asmExt->output[nbOutput]->reg)
                    error("%s:%d: error: in output_asm function :reg is null!", __FILE__, __LINE__);
                asmExt->output[nbOutput]->reg64 = asmExt->output[nbOutput]->reg;
                asmExt->output[nbOutput]->regh = register_higher(asmExt->output[nbOutput]->reg64);
                asmExt->output[nbOutput]->regl = register_lower(asmExt->output[nbOutput]->reg64);
                asmExt->output[nbOutput]->regw = register_word(asmExt->output[nbOutput]->reg64);                                
                asmExt->output[nbOutput]->letter = 'l';
                asmExt->output[nbOutput]->inputToGenerate = true;
                asmExt->output[nbOutput]->variableNumber = retrieveVariableNumber(nbOutput);
                
            }

            // assuming that it's =a =b ???
            else if (!strncmp(tok->str, "=a", tok->len) || !strncmp(tok->str, "=b", tok->len) || !strncmp(tok->str, "=c", tok->len)
             || !strncmp(tok->str, "=d", tok->len) || !strncmp(tok->str, "=&a", tok->len) || !strncmp(tok->str, "=&b", tok->len) ||
              !strncmp(tok->str, "=&c", tok->len) || !strncmp(tok->str, "=&d", tok->len))
            {
                if (!strncmp(tok->str, "=a", tok->len) || !strncmp(tok->str, "=&a", tok->len))
                {
                    asmExt->output[nbOutput]->prefix = "=";
                    asmExt->output[nbOutput]->reg = specific_register_available("%rax");
                    if (!asmExt->output[nbOutput]->reg)
                       error("%s:%d: error: in output_asm function :reg is null!", __FILE__, __LINE__);
                    asmExt->output[nbOutput]->reg64 = asmExt->output[nbOutput]->reg;  
                    asmExt->output[nbOutput]->regh = register_higher(asmExt->output[nbOutput]->reg64);
                    asmExt->output[nbOutput]->regl = register_lower(asmExt->output[nbOutput]->reg64);
                    asmExt->output[nbOutput]->regw = register_word(asmExt->output[nbOutput]->reg64);
                    asmExt->output[nbOutput]->letter = 'a';
                    asmExt->output[nbOutput]->variableNumber = retrieveVariableNumber(nbOutput);

                }
                else if (!strncmp(tok->str, "=b", tok->len) || !strncmp(tok->str, "=&b", tok->len))
                {
                    asmExt->output[nbOutput]->prefix = "=";
                    asmExt->output[nbOutput]->reg = specific_register_available("%rbx");
                    if (!asmExt->output[nbOutput]->reg)
                        error("%s:%d: error: in output_asm function :reg is null!", __FILE__, __LINE__);
                    asmExt->output[nbOutput]->reg64 = asmExt->output[nbOutput]->reg; 
                    asmExt->output[nbOutput]->regh = register_higher(asmExt->output[nbOutput]->reg64);
                    asmExt->output[nbOutput]->regl = register_lower(asmExt->output[nbOutput]->reg64); 
                    asmExt->output[nbOutput]->regw = register_word(asmExt->output[nbOutput]->reg64);                   
                    asmExt->output[nbOutput]->letter = 'b';
                    asmExt->output[nbOutput]->variableNumber = retrieveVariableNumber(nbOutput);
                }
                else if (!strncmp(tok->str, "=c", tok->len) || !strncmp(tok->str, "=&c", tok->len))
                {
                    asmExt->output[nbOutput]->prefix = "=";
                    asmExt->output[nbOutput]->reg = specific_register_available("%rcx");
                    if (!asmExt->output[nbOutput]->reg)
                        error("%s:%d: error: in output_asm function :reg is null!", __FILE__, __LINE__);
                    asmExt->output[nbOutput]->reg64 = asmExt->output[nbOutput]->reg; 
                    asmExt->output[nbOutput]->regh = register_higher(asmExt->output[nbOutput]->reg64);
                    asmExt->output[nbOutput]->regl = register_lower(asmExt->output[nbOutput]->reg64);  
                    asmExt->output[nbOutput]->regw = register_word(asmExt->output[nbOutput]->reg64);                   
                    asmExt->output[nbOutput]->letter = 'c';
                    asmExt->output[nbOutput]->variableNumber = retrieveVariableNumber(nbOutput);
                }
                else if (!strncmp(tok->str, "=d", tok->len) || !strncmp(tok->str, "=&d", tok->len))
                {
                    asmExt->output[nbOutput]->prefix = "=";
                    asmExt->output[nbOutput]->reg = specific_register_available("%rdx");
                    if (!asmExt->output[nbOutput]->reg)
                        error("%s:%d: error: in output_asm function :reg is null!", __FILE__, __LINE__);
                    asmExt->output[nbOutput]->reg64 = asmExt->output[nbOutput]->reg; 
                    asmExt->output[nbOutput]->regh = register_higher(asmExt->output[nbOutput]->reg64);
                    asmExt->output[nbOutput]->regl = register_lower(asmExt->output[nbOutput]->reg64);    
                    asmExt->output[nbOutput]->regw = register_word(asmExt->output[nbOutput]->reg64);                 
                    asmExt->output[nbOutput]->letter = 'd';
                    asmExt->output[nbOutput]->variableNumber = retrieveVariableNumber(nbOutput);
                }                            
                else {
                tok = tok->next;
                SET_CTX(ctx);
                while (equal(tok, ")")) tok = tok->next;
                    *rest = tok;
                return;
                }
                    

                asmExt->output[nbOutput]->isAlpha = true;
                //asmExt->output[nbOutput]->prefix = "=";
                //asmExt->output[nbOutput]->variableNumber = retrieveVariableNumber(nbOutput);
                
                
            }
            else if (!strncmp(tok->str, "+a", tok->len) || !strncmp(tok->str, "+b", tok->len) || !strncmp(tok->str, "+c", tok->len) || !strncmp(tok->str, "+d", tok->len))
            {
                if (!strncmp(tok->str, "+a", tok->len))
                {
                    asmExt->output[nbOutput]->prefix = "+";
                    asmExt->output[nbOutput]->reg = specific_register_available("%rax");
                    if (!asmExt->output[nbOutput]->reg)
                       error("%s:%d: error: in output_asm function :reg is null!", __FILE__, __LINE__);
                    asmExt->output[nbOutput]->reg64 = asmExt->output[nbOutput]->reg; 
                    asmExt->output[nbOutput]->regh = register_higher(asmExt->output[nbOutput]->reg64);
                    asmExt->output[nbOutput]->regl = register_lower(asmExt->output[nbOutput]->reg64);   
                    asmExt->output[nbOutput]->regw = register_word(asmExt->output[nbOutput]->reg64);                  
                    asmExt->output[nbOutput]->letter = 'a';
                    asmExt->output[nbOutput]->variableNumber = retrieveVariableNumber(nbOutput);

                }
                else if (!strncmp(tok->str, "+b", tok->len))
                {
                    asmExt->output[nbOutput]->prefix = "+";
                    asmExt->output[nbOutput]->reg = specific_register_available("%rbx");
                    if (!asmExt->output[nbOutput]->reg)
                        error("%s:%d: error: in output_asm function :reg is null!", __FILE__, __LINE__);
                    asmExt->output[nbOutput]->reg64 = asmExt->output[nbOutput]->reg; 
                    asmExt->output[nbOutput]->regh = register_higher(asmExt->output[nbOutput]->reg64);
                    asmExt->output[nbOutput]->regl = register_lower(asmExt->output[nbOutput]->reg64);     
                    asmExt->output[nbOutput]->regw = register_word(asmExt->output[nbOutput]->reg64);               
                    asmExt->output[nbOutput]->letter = 'b';
                    asmExt->output[nbOutput]->variableNumber = retrieveVariableNumber(nbOutput);
                }
                else if (!strncmp(tok->str, "+c", tok->len))
                {
                    asmExt->output[nbOutput]->prefix = "+";
                    asmExt->output[nbOutput]->reg = specific_register_available("%rcx");
                    if (!asmExt->output[nbOutput]->reg)
                        error("%s:%d: error: in output_asm function :reg is null!", __FILE__, __LINE__);
                    asmExt->output[nbOutput]->reg64 = asmExt->output[nbOutput]->reg; 
                    asmExt->output[nbOutput]->regh = register_higher(asmExt->output[nbOutput]->reg64);
                    asmExt->output[nbOutput]->regl = register_lower(asmExt->output[nbOutput]->reg64);  
                    asmExt->output[nbOutput]->regw = register_word(asmExt->output[nbOutput]->reg64);                  
                    asmExt->output[nbOutput]->letter = 'c';
                    asmExt->output[nbOutput]->variableNumber = retrieveVariableNumber(nbOutput);
                }
                else if (!strncmp(tok->str, "+d", tok->len))
                {
                    asmExt->output[nbOutput]->prefix = "+";
                    asmExt->output[nbOutput]->reg = specific_register_available("%rdx");
                    if (!asmExt->output[nbOutput]->reg)
                        error("%s:%d: error: in output_asm function :reg is null!", __FILE__, __LINE__);
                    asmExt->output[nbOutput]->reg64 = asmExt->output[nbOutput]->reg; 
                    asmExt->output[nbOutput]->regh = register_higher(asmExt->output[nbOutput]->reg64);
                    asmExt->output[nbOutput]->regl = register_lower(asmExt->output[nbOutput]->reg64);  
                    asmExt->output[nbOutput]->regw = register_word(asmExt->output[nbOutput]->reg64);                  
                    asmExt->output[nbOutput]->letter = 'd';
                    asmExt->output[nbOutput]->variableNumber = retrieveVariableNumber(nbOutput);
                }                            
                else {
                tok = tok->next;
                SET_CTX(ctx);
                while (equal(tok, ")")) tok = tok->next;
                    *rest = tok;
                return;
                }
                    

                asmExt->output[nbOutput]->isAlpha = true;
                //asmExt->output[nbOutput]->prefix = "=";
                //asmExt->output[nbOutput]->variableNumber = retrieveVariableNumber(nbOutput);
                
                
            }            
            //D for destination operand
            else if (!strncmp(tok->str, "=D", tok->len) || !strncmp(tok->str, "+D", tok->len))
            {
                asmExt->output[nbOutput]->isMemory = true;
                if (!strncmp(tok->str, "=D", tok->len))
                    asmExt->output[nbOutput]->prefix = "=";
                else {
                    asmExt->output[nbOutput]->prefix = "+";
                }
                asmExt->output[nbOutput]->reg = specific_register_available("%rax");
                if (!asmExt->output[nbOutput]->reg)
                    error("%s:%d: error: in output_asm function :reg is null!", __FILE__, __LINE__);
                asmExt->output[nbOutput]->reg64 = asmExt->output[nbOutput]->reg;    
                asmExt->output[nbOutput]->regh = register_higher(asmExt->output[nbOutput]->reg64);
                asmExt->output[nbOutput]->regl = register_lower(asmExt->output[nbOutput]->reg64);  
                asmExt->output[nbOutput]->regw = register_word(asmExt->output[nbOutput]->reg64);                          
                asmExt->output[nbOutput]->letter = 'D';
                asmExt->output[nbOutput]->inputToGenerate = true;
            }   
            //S for source operand
            else if (!strncmp(tok->str, "=S", tok->len) || !strncmp(tok->str, "+S", tok->len))
            {
                asmExt->output[nbOutput]->isMemory = true;
                if (!strncmp(tok->str, "=S", tok->len))
                    asmExt->output[nbOutput]->prefix = "=";
                else {
                    asmExt->output[nbOutput]->prefix = "+";
                }
                asmExt->output[nbOutput]->reg = specific_register_available("%rax");
                if (!asmExt->output[nbOutput]->reg)
                    error("%s:%d: error: in output_asm function :reg is null!", __FILE__, __LINE__);
                asmExt->output[nbOutput]->reg64 = asmExt->output[nbOutput]->reg;     
                asmExt->output[nbOutput]->regh = register_higher(asmExt->output[nbOutput]->reg64);
                asmExt->output[nbOutput]->regl = register_lower(asmExt->output[nbOutput]->reg64); 
                asmExt->output[nbOutput]->regw = register_word(asmExt->output[nbOutput]->reg64);                          
                asmExt->output[nbOutput]->letter = 'S';
                asmExt->output[nbOutput]->inputToGenerate = true;
            } 

            asmExt->output[nbOutput]->variableNumber = retrieveVariableNumber(nbOutput);
            asmExt->output[nbOutput]->index = nbOutput;

        }
        // skip the comma
        else if (equal(tok, ",")) {
            SET_CTX(ctx);
            tok = skip(tok, ",", ctx); continue;
        }
        // manage the variable inside parenthesis
        else if (equal(tok, "("))
        {
            if (parse_simple_binary_input(rest, tok, locals))
                return;
            SET_CTX(ctx);
            while (equal(tok, "("))
                tok = tok->next;
            // check if the variable is defined
            if (tok->kind == TK_IDENT)
            {
                //TODO potential issue if several variables with same name inside different functions.
                //need to check if the variable is in the correct function
                asmExt->output[nbOutput]->output = tok;
                sc = find_var(tok);
                if (!sc)
                    error_tok(tok, "%s:%d: in output_asm function : variable undefined", __FILE__, __LINE__);
                if (!sc->var->ty)
                    error_tok(tok, "%s:%d: in output_asm function : variable type unknown", __FILE__, __LINE__);
                // retrieve the size of the variable to determine the register to use here we use RAX variation
                asmExt->output[nbOutput]->size = sc->var->ty->size;
                if (!asmExt->output[nbOutput]->reg)
                    error_tok(tok, "%s:%d: in output_asm function : reg is null extended assembly not managed yet", __FILE__, __LINE__);
                asmExt->output[nbOutput]->isVariable = true;
                asmExt->output[nbOutput]->output = tok;
                asmExt->output[nbOutput]->variableNumber = retrieveVariableNumber(nbOutput);

                if (sc->var->funcname) {
                    update_offset(sc->var->funcname, locals);
                    Obj *ov = find_obj_by_tok(locals, tok);
                    if (ov && ov->offset)
                        sc->var->offset = ov->offset;
                    asmExt->output[nbOutput]->offset = (ov && ov->offset) ? ov->offset : sc->var->offset;
                }
                else {
                    asmExt->output[nbOutput]->offset = sc->var->offset;
                }
                int base_off = asmExt->output[nbOutput]->offset;

                //managing specific case of arrays
                Token *bracket = tok->next;
                while (equal(bracket, ")")) bracket = bracket->next;
                if (sc->var->ty->kind == TY_ARRAY && equal(bracket, "[")) {
                    SET_CTX(ctx);
                    tok = skip(bracket, "[", ctx);
                    asmExt->output[nbOutput]->isArray = true;
                    asmExt->output[nbOutput]->isAddress = false;
                    asmExt->output[nbOutput]->indexArray = tok->val;
                    asmExt->output[nbOutput]->size = sc->var->ty->base->size;
                    if (!asmExt->output[nbOutput]->reg)
                        error("%s:%d: error: in output_asm function :reg is null!", __FILE__, __LINE__);
                    if (asmExt->output[nbOutput]->letter != 'm')
                        asmExt->output[nbOutput]->reg = update_register_size(asmExt->output[nbOutput]->reg, asmExt->output[nbOutput]->size);
                    //calculate the offset for each element from the bottom to the top r[0] has the lowest offset example -48, r[1] - 44, r[2] -40, r[3] - 36
                    asmExt->output[nbOutput]->offset = (sc->var->offset ) + (asmExt->output[nbOutput]->indexArray * asmExt->output[nbOutput]->size);
                    asmExt->output[nbOutput]->offsetArray = base_off;
                    if (asmExt->output[nbOutput]->letter == 'm')
                        asmExt->output[nbOutput]->reg = load_variable(asmExt->output[nbOutput]->offset);
                    tok = tok->next;
                    SET_CTX(ctx);
                    tok = skip(tok, "]", ctx);
                    SET_CTX(ctx);
                    while (equal(tok, ")")) tok = tok->next;
                    *rest = tok;
                    return;
                }                
                //special case of array pointer it means that the parameter received is an address.
                Token *bracket_ptr = tok->next;
                while (equal(bracket_ptr, ")")) bracket_ptr = bracket_ptr->next;
                if (sc->var->ty->kind == TY_PTR && equal(bracket_ptr, "[")) {
                    SET_CTX(ctx);
                    tok = skip(bracket_ptr, "[", ctx);
                    asmExt->output[nbOutput]->isArray = true;
                    asmExt->output[nbOutput]->isAddress = true;
                    asmExt->output[nbOutput]->indexArray = tok->val;
                    asmExt->output[nbOutput]->size = sc->var->ty->base->size;
                    if (!asmExt->output[nbOutput]->reg)
                        error_tok(tok, "%s:%d: in output_asm function : reg is null extended assembly not managed yet", __FILE__, __LINE__);
                    ensure_output_reg(asmExt->output[nbOutput], "%r11");
                    asmExt->output[nbOutput]->reg = update_register_size(asmExt->output[nbOutput]->reg, asmExt->output[nbOutput]->size);
                    //calculate the offset for each element from the bottom to the top r[0] has the lowest offset example -48, r[1] - 44, r[2] -40, r[3] - 36
                    asmExt->output[nbOutput]->offset = (asmExt->output[nbOutput]->indexArray * asmExt->output[nbOutput]->size);
                    asmExt->output[nbOutput]->offsetArray = base_off;
                    tok = tok->next;
                    SET_CTX(ctx);
                    tok = skip(tok, "]", ctx);
                    SET_CTX(ctx);
                    while (equal(tok, ")")) tok = tok->next;
                    *rest = tok;
                    return;
                }

                //Trying to fix ISS-164 special case of ptr->value form (ptr to a struct)
                Token *arrow = tok->next;
                while (equal(arrow, ")")) arrow = arrow->next;
                if (sc->var->ty->kind == TY_PTR && equal(arrow, "->")) {
                    if (!sc->var->ty->base)
                        error_tok(tok, "%s:%d: in output_asm function : expecting struct base but base is null!", __FILE__, __LINE__);
                    asmExt->output[nbOutput]->output = tok;
                    SET_CTX(ctx);
                    tok = skip(arrow, "->", ctx);
                    Token * tokmbr = tok;
                    // retrieve the size of the variable to determine the register to use here we use RAX variation
                    asmExt->output[nbOutput]->isAddress = true;  
                    asmExt->output[nbOutput]->isStruct = true;     
                    asmExt->output[nbOutput]->size = sc->var->ty->size;
                    if (!asmExt->output[nbOutput]->reg)
                        error_tok(tok, "%s:%d: in output_asm function : reg is null extended assembly not managed yet", __FILE__, __LINE__);                
                    ensure_output_reg(asmExt->output[nbOutput], "%r11");
                    asmExt->output[nbOutput]->reg = update_register_size(asmExt->output[nbOutput]->reg, asmExt->output[nbOutput]->size);
                    asmExt->output[nbOutput]->variableNumber = retrieveVariableNumber(nbOutput);
                    if (!sc->var->ty->base->members)
                        error_tok(tok, "%s:%d: in output_asm function : expecting members but members is null", __FILE__, __LINE__);
                    if (sc->var->funcname) {
                        update_offset(sc->var->funcname, locals);
                        asmExt->output[nbOutput]->offset = sc->var->offset;
                        asmExt->output[nbOutput]->offsetStruct = sc->var->ty->base->members->offset ;
                    }
                    else {
                        asmExt->output[nbOutput]->offset = 0;
                    }
                    //need to update the specific struct field offset
                    char *toktmp = calloc(1, sizeof(char) * 300);
                    for (Member *mbr = sc->var->ty->base->members; mbr; mbr = mbr->next) {
                        if (mbr->name->len > 59)
                            error_tok(tok, "%s:%d %d: in output_asm function : not enough size for toktmp", __FILE__, __LINE__, mbr->name->len);
                        strncat(toktmp, mbr->name->loc, mbr->name->len);
                        if (equal(tokmbr, toktmp)) {
                            asmExt->output[nbOutput]->offsetStruct = mbr->offset ;
                            asmExt->output[nbOutput]->size = mbr->ty->size ;
                            if (!asmExt->output[nbOutput]->reg)
                                error_tok(tok, "%s:%d: in output_asm function : reg is null extended assembly not managed yet", __FILE__, __LINE__);
                            asmExt->output[nbOutput]->reg = update_register_size(asmExt->output[nbOutput]->reg, asmExt->output[nbOutput]->size);
                        }
                    }
                    tok = tok->next;
                    SET_CTX(ctx);
                    while (equal(tok, ")"))
                        tok = tok->next;
                    *rest = tok;
                    return;
                }

                if (asmExt->output[nbOutput]->letter == 'm')
                    asmExt->output[nbOutput]->reg = load_variable(asmExt->output[nbOutput]->offset);
                else
                    asmExt->output[nbOutput]->reg = update_register_size(asmExt->output[nbOutput]->reg, asmExt->output[nbOutput]->size);
                // skip the variable to go to next token that should be a ")"
                // tok = tok->next;
                tok = tok->next;                
                if (!equal(tok, ")"))
                    error_tok(tok, "%s:%d: in output_asm function : extended assembly not managed yet", __FILE__, __LINE__);
                SET_CTX(ctx);
                while (equal(tok, ")")) tok = tok->next;
                    *rest = tok;
                return;
            }
            // pointer
            else if (equal(tok, "*"))
            {
                consume(&tok, tok, "*");
                if (tok->kind == TK_IDENT)
                {
                    asmExt->output[nbOutput]->isAddress = true;
                    ensure_output_reg(asmExt->output[nbOutput], "%r11");
                    asmExt->output[nbOutput]->output = tok;
                    sc = find_var(tok);
                    if (!sc)
                        error_tok(tok, "%s:%d: in output_asm function : variable undefined2", __FILE__, __LINE__);
                    if (!sc->var->ty)
                        error_tok(tok, "%s:%d: in output_asm function : variable type unknown2", __FILE__, __LINE__);
                    // retrieve the size of the variable to determine the register to use here we use RAX variation
                    // skip the variable to go to next token that should be a ")"
                
                    asmExt->output[nbOutput]->size = sc->var->ty->pointertype->size;
                    if (sc->var->funcname) {
                        update_offset(sc->var->funcname, locals);
                        asmExt->output[nbOutput]->offset = sc->var->offset;                       

                    } else {
                            asmExt->output[nbOutput]->offset = 0;                        

                    }
                    if (!asmExt->output[nbOutput]->reg)
                        error_tok(tok, "%s:%d: in output_asm function : reg is null extended assembly not managed yet", __FILE__, __LINE__);
                    asmExt->output[nbOutput]->reg = update_register_size(asmExt->output[nbOutput]->reg, asmExt->output[nbOutput]->size);
                    asmExt->output[nbOutput]->variableNumber = retrieveVariableNumber(nbOutput);
                    tok = tok->next;

                    SET_CTX(ctx);
                    while (equal(tok, ")")) tok = tok->next;
                    *rest = tok;
                    return;
                } else if (equal(tok, "(") && equal(tok->next, "(")) {
                            // Skip '(('
                            tok = tok->next->next;
                            if (!equal(tok, "void"))
                                error_tok(tok, "%s:%d: in output_asm function : expected cast to (void **)", __FILE__, __LINE__);

                            tok = tok->next;

                            int pointer_depth = 0;
                            while (equal(tok, "*")) {
                                pointer_depth++;
                                tok = tok->next;
                            }

                            if (!equal(tok, ")"))
                                error_tok(tok, "%s:%d: in output_asm function : expected ')' after cast type", __FILE__, __LINE__);

                            tok = tok->next; 

                            if (tok->kind != TK_IDENT)
                                error_tok(tok, "%s:%d: in output_asm function : expected identifier after cast", __FILE__, __LINE__);

                            // At this point: we are at the identifier (like 'ofs')
                            asmExt->output[nbOutput]->isAddress = true;
                            asmExt->output[nbOutput]->output = tok;

                            VarScope *sc = find_var(tok);
                            if (!sc)
                                error_tok(tok, "%s:%d: in output_asm function : variable undefined after cast", __FILE__, __LINE__);
                            if (!sc->var->ty)
                                error_tok(tok, "%s:%d: in output_asm function : variable type unknown after cast", __FILE__, __LINE__);                                

                            asmExt->output[nbOutput]->size = sc->var->ty->size;
                            if (sc->var->funcname) {
                                update_offset(sc->var->funcname, locals);
                                asmExt->output[nbOutput]->offset = sc->var->offset;
                            } else {
                                asmExt->output[nbOutput]->offset = 0;
                            }
                            ensure_output_reg(asmExt->output[nbOutput], "%r11");

                            asmExt->output[nbOutput]->reg = update_register_size(asmExt->output[nbOutput]->reg, asmExt->output[nbOutput]->size);
                            asmExt->output[nbOutput]->variableNumber = retrieveVariableNumber(nbOutput);
                            tok = tok->next;

                            if (!equal(tok, ")"))
                                error_tok(tok, "%s:%d: in output_asm function : expected ')' after cast type", __FILE__, __LINE__);

                            tok = tok->next; //first parenthesis
                            

                            SET_CTX(ctx);
                            while (equal(tok, ")")) tok = tok->next;
                    *rest = tok;
                            return;
                        }

                                    
                else {
                    error_tok(tok, "%s:%d: in output_asm function : extended assembly not managed yet", __FILE__, __LINE__);
                }
            }
        }


        tok = tok->next;
        *rest = tok;
    }
    return;
}

void input_asm(Node *node, Token **rest, Token *tok, Obj *locals)
{
    VarScope *sc;
    char *input_value = calloc(1, sizeof(char) * 300);
    asmExt->input[nbInput]->offset = 0;

    while (!equal(tok->next, ":") && !equal(tok->next, ";"))
    {
        //case of operand named
        if (equal(tok, "[") || equal(tok, "{")) {
            char closing = equal(tok, "[") ? ']' : '}';
            tok = tok->next;                       
            // case of operand named [dst] or {src}
            if (tok->kind == TK_IDENT) {                
                char *name = calloc(tok->len + 1, 1);
                memcpy(name, tok->loc, tok->len);
                name[tok->len] = '\0';              
                asmExt->input[nbInput]->operand_name = name;
                asmExt->input[nbInput]->index = nbInput;
                hasOperandName = true;
                tok = tok->next;                
                // Now consume the closing ] or }
                if (!equal(tok, (char[]){closing, 0})) {
                    error_tok(tok, "%s:%d: error: in input_asm function : expected closing %c after operand name", __FILE__, __LINE__, closing);
                }
                tok = tok->next;                              
            }
        }
        // register in write only mode
        if (tok->kind == TK_STR && (!strncmp(tok->str, "0", tok->len) || !strncmp(tok->str, "%0", tok->len) ))
        {
            asmExt->input[nbInput]->variableNumber = retrieveVariableNumber(0);
            asmExt->input[nbInput]->index = 0;
            asmExt->input[nbInput]->reg = asmExt->output[0]->reg;
            if (!asmExt->input[nbInput]->reg)
                error("%s:%d: error: in input_asm function input_asm :reg is null!", __FILE__, __LINE__);            
            asmExt->input[nbInput]->reg64 = asmExt->output[0]->reg64;
            asmExt->input[nbInput]->regh = register_higher(asmExt->input[nbInput]->reg64);
            asmExt->input[nbInput]->regl = register_lower(asmExt->input[nbInput]->reg64);
            asmExt->input[nbInput]->regw = register_word(asmExt->input[nbInput]->reg64);
        }
        else if (tok->kind == TK_STR && (!strncmp(tok->str, "1", tok->len) || !strncmp(tok->str, "%1", tok->len)))
        {

            asmExt->input[nbInput]->variableNumber = retrieveVariableNumber(1);
            asmExt->input[nbInput]->index = 1;
            asmExt->input[nbInput]->reg = asmExt->output[1]->reg;
            if (!asmExt->input[nbInput]->reg)
                error("%s:%d: error: in input_asm function input_asm :reg is null!", __FILE__, __LINE__);            
            asmExt->input[nbInput]->reg64 = asmExt->output[1]->reg64;
            asmExt->input[nbInput]->regh = register_higher(asmExt->input[nbInput]->reg64);
            asmExt->input[nbInput]->regl = register_lower(asmExt->input[nbInput]->reg64);
            asmExt->input[nbInput]->regw = register_word(asmExt->input[nbInput]->reg64);
        }
        else if (tok->kind == TK_STR && (!strncmp(tok->str, "2", tok->len) || !strncmp(tok->str, "%2", tok->len)))
        {

            asmExt->input[nbInput]->variableNumber = retrieveVariableNumber(2);
            asmExt->input[nbInput]->index = 2;
            asmExt->input[nbInput]->reg = asmExt->output[2]->reg;
            if (!asmExt->input[nbInput]->reg)
                error("%s:%d: error: in input_asm function input_asm :reg is null!", __FILE__, __LINE__);            
            asmExt->input[nbInput]->reg64 = asmExt->output[2]->reg64;
            asmExt->input[nbInput]->regh = register_higher(asmExt->input[nbInput]->reg64);
            asmExt->input[nbInput]->regl = register_lower(asmExt->input[nbInput]->reg64);
            asmExt->input[nbInput]->regw = register_word(asmExt->input[nbInput]->reg64);            
        }
        else if (tok->kind == TK_STR && (!strncmp(tok->str, "3", tok->len) || !strncmp(tok->str, "%3", tok->len)))
        {

            asmExt->input[nbInput]->variableNumber = retrieveVariableNumber(3);
            asmExt->input[nbInput]->index = 3;
            asmExt->input[nbInput]->reg = asmExt->output[3]->reg;
            if (!asmExt->input[nbInput]->reg)
                error("%s:%d: error: in input_asm function input_asm :reg is null!", __FILE__, __LINE__);            

            asmExt->input[nbInput]->reg64 = asmExt->output[3]->reg64;
            asmExt->input[nbInput]->regh = register_higher(asmExt->input[nbInput]->reg64);
            asmExt->input[nbInput]->regl = register_lower(asmExt->input[nbInput]->reg64);
            asmExt->input[nbInput]->regw = register_word(asmExt->input[nbInput]->reg64);            
        }
        else if (tok->kind == TK_STR && (tok->len == 1 && tok->str[0] >= '4' && tok->str[0] <= '9'))
        {
            int digit = tok->str[0] - '0';
            asmExt->input[nbInput]->variableNumber = retrieveVariableNumber(digit);
            asmExt->input[nbInput]->index = digit;
            asmExt->input[nbInput]->reg = asmExt->output[digit]->reg;
            if (!asmExt->input[nbInput]->reg)
                error("%s:%d: error: in input_asm function input_asm :reg is null!", __FILE__, __LINE__);            
            asmExt->input[nbInput]->reg64 = asmExt->output[digit]->reg64;
            asmExt->input[nbInput]->regh = register_higher(asmExt->input[nbInput]->reg64);
            asmExt->input[nbInput]->regl = register_lower(asmExt->input[nbInput]->reg64);
            asmExt->input[nbInput]->regw = register_word(asmExt->input[nbInput]->reg64);            
        }
        else if (tok->kind == TK_STR && !strncmp(tok->str, "a", tok->len))
        {
            asmExt->input[nbInput]->variableNumber = retrieveVariableNumber(nbOutput + nbInput);
            asmExt->input[nbInput]->index = nbOutput + nbInput;
            asmExt->input[nbInput]->letter = 'a';
            //=====ISS-156 case we have no output for the letter
            if (retrieve_output_index_from_letter('a') == -1) {
                asmExt->input[nbInput]->reg = use_fixed_register("%rax");
                if (!asmExt->input[nbInput]->reg)
                    error("%s:%d: error: in input_asm function input_asm :reg is null!", __FILE__, __LINE__);  
                asmExt->input[nbInput]->reg64 = asmExt->input[nbInput]->reg;
                asmExt->input[nbInput]->regh = register_higher(asmExt->input[nbInput]->reg64);
                asmExt->input[nbInput]->regl = register_lower(asmExt->input[nbInput]->reg64);
                asmExt->input[nbInput]->regw = register_word(asmExt->input[nbInput]->reg64);                
                asmExt->input[nbInput]->variableNumber = retrieveVariableNumber(nbOutput + nbInput);
            }
            else {
                asmExt->input[nbInput]->reg = asmExt->output[retrieve_output_index_from_letter('a')]->reg;
                if (!asmExt->input[nbInput]->reg)
                    error("%s:%d: error: in input_asm function input_asm :reg is null!", __FILE__, __LINE__);
                asmExt->input[nbInput]->reg64 = asmExt->output[retrieve_output_index_from_letter('a')]->reg64;
                asmExt->input[nbInput]->regh = register_higher(asmExt->input[nbInput]->reg64);
                asmExt->input[nbInput]->regl = register_lower(asmExt->input[nbInput]->reg64);
                asmExt->input[nbInput]->regw = register_word(asmExt->input[nbInput]->reg64);                
            }
            
        }
        else if (tok->kind == TK_STR && !strncmp(tok->str, "b", tok->len))
        {
            asmExt->input[nbInput]->variableNumber = retrieveVariableNumber(nbOutput + nbInput);
            asmExt->input[nbInput]->index = nbOutput + nbInput;
            asmExt->input[nbInput]->letter = 'b';
            //=====ISS-156 case we have no output for the letter
            if (retrieve_output_index_from_letter('b') == -1) {
                asmExt->input[nbInput]->reg = use_fixed_register("%rbx");
                if (!asmExt->input[nbInput]->reg)
                    error("%s:%d: error: in input_asm function input_asm :reg is null!", __FILE__, __LINE__);  
                asmExt->input[nbInput]->reg64 = asmExt->input[nbInput]->reg;
                asmExt->input[nbInput]->regh = register_higher(asmExt->input[nbInput]->reg64);
                asmExt->input[nbInput]->regl = register_lower(asmExt->input[nbInput]->reg64);
                asmExt->input[nbInput]->regw = register_word(asmExt->input[nbInput]->reg64);                
                asmExt->input[nbInput]->variableNumber = retrieveVariableNumber(nbOutput + nbInput);
            }
            else {            
                asmExt->input[nbInput]->reg = asmExt->output[retrieve_output_index_from_letter('b')]->reg;
                if (!asmExt->input[nbInput]->reg)
                     error("%s:%d: error: in input_asm function input_asm :reg is null!", __FILE__, __LINE__);
                asmExt->input[nbInput]->reg64 = asmExt->output[retrieve_output_index_from_letter('b')]->reg64;
                asmExt->input[nbInput]->regh = register_higher(asmExt->input[nbInput]->reg64);
                asmExt->input[nbInput]->regl = register_lower(asmExt->input[nbInput]->reg64);
                asmExt->input[nbInput]->regw = register_word(asmExt->input[nbInput]->reg64);                
            }
        }
        else if (tok->kind == TK_STR && !strncmp(tok->str, "c", tok->len))
        {

            asmExt->input[nbInput]->variableNumber = retrieveVariableNumber(nbOutput + nbInput);
            asmExt->input[nbInput]->index = nbOutput + nbInput;
            asmExt->input[nbInput]->letter = 'c';
            //=====ISS-156 case we have no output for the letter
            if (retrieve_output_index_from_letter('c') == -1) {
                asmExt->input[nbInput]->reg = use_fixed_register("%rcx");
                if (!asmExt->input[nbInput]->reg)
                    error("%s:%d: error: in input_asm function input_asm :reg is null!", __FILE__, __LINE__);
                asmExt->input[nbInput]->reg64 = asmExt->input[nbInput]->reg;
                asmExt->input[nbInput]->regh = register_higher(asmExt->input[nbInput]->reg64);
                asmExt->input[nbInput]->regl = register_lower(asmExt->input[nbInput]->reg64);
                asmExt->input[nbInput]->regw = register_word(asmExt->input[nbInput]->reg64);                
                asmExt->input[nbInput]->variableNumber = retrieveVariableNumber(nbOutput + nbInput);
            }
            else {
                asmExt->input[nbInput]->reg = asmExt->output[retrieve_output_index_from_letter('c')]->reg;
                if (!asmExt->input[nbInput]->reg)
                     error("%s:%d: error: in input_asm function input_asm :reg is null!", __FILE__, __LINE__);
                asmExt->input[nbInput]->reg64 = asmExt->output[retrieve_output_index_from_letter('c')]->reg64;
                asmExt->input[nbInput]->regh = register_higher(asmExt->input[nbInput]->reg64);
                asmExt->input[nbInput]->regl = register_lower(asmExt->input[nbInput]->reg64);
                asmExt->input[nbInput]->regw = register_word(asmExt->input[nbInput]->reg64);                
            }

        }
        else if (tok->kind == TK_STR && !strncmp(tok->str, "d", tok->len))
        {

            asmExt->input[nbInput]->variableNumber = retrieveVariableNumber(nbOutput + nbInput);
            asmExt->input[nbInput]->index = nbOutput + nbInput;            
            asmExt->input[nbInput]->letter = 'd';            
            //=====ISS-156 case we have no output for the letter
            if (retrieve_output_index_from_letter('d') == -1) {
                asmExt->input[nbInput]->reg = use_fixed_register("%rdx");
                if (!asmExt->input[nbInput]->reg)
                    error("%s:%d: error: in input_asm function input_asm :reg is null!", __FILE__, __LINE__); 
                asmExt->input[nbInput]->reg64 = asmExt->input[nbInput]->reg;
                asmExt->input[nbInput]->regh = register_higher(asmExt->input[nbInput]->reg64);
                asmExt->input[nbInput]->regl = register_lower(asmExt->input[nbInput]->reg64);
                asmExt->input[nbInput]->regw = register_word(asmExt->input[nbInput]->reg64);                
                asmExt->input[nbInput]->variableNumber = retrieveVariableNumber(nbOutput + nbInput);
            }
            else {            
                asmExt->input[nbInput]->reg = asmExt->output[retrieve_output_index_from_letter('d')]->reg;
                if (!asmExt->input[nbInput]->reg)
                    error("%s:%d: error: in input_asm function input_asm :reg is null!", __FILE__, __LINE__); 
                asmExt->input[nbInput]->reg64 = asmExt->output[retrieve_output_index_from_letter('d')]->reg64;
                asmExt->input[nbInput]->regh = register_higher(asmExt->input[nbInput]->reg64);
                asmExt->input[nbInput]->regl = register_lower(asmExt->input[nbInput]->reg64);
                asmExt->input[nbInput]->regw = register_word(asmExt->input[nbInput]->reg64);                
            }            
        }
        else if (tok->kind == TK_STR && !strncmp(tok->str, "g", tok->len))
        {

            asmExt->input[nbInput]->variableNumber = retrieveVariableNumber(nbOutput + nbInput);
            asmExt->input[nbInput]->index = nbOutput + nbInput;            
            asmExt->input[nbInput]->letter = 'g';            
            //=====ISS-156 case we have no output for the letter
            if (retrieve_output_index_from_letter('g') == -1) {
                asmExt->input[nbInput]->reg = register_available();
                if (!asmExt->input[nbInput]->reg)
                    error("%s:%d: error: in input_asm function input_asm :reg is null!", __FILE__, __LINE__); 
                asmExt->input[nbInput]->reg64 = asmExt->input[nbInput]->reg;
                asmExt->input[nbInput]->regh = register_higher(asmExt->input[nbInput]->reg64);
                asmExt->input[nbInput]->regl = register_lower(asmExt->input[nbInput]->reg64);
                asmExt->input[nbInput]->regw = register_word(asmExt->input[nbInput]->reg64);                
                asmExt->input[nbInput]->variableNumber = retrieveVariableNumber(nbOutput + nbInput);
            }
            else {            
                asmExt->input[nbInput]->reg = asmExt->output[retrieve_output_index_from_letter('g')]->reg;
                if (!asmExt->input[nbInput]->reg)
                    error("%s:%d: error: in input_asm function input_asm :reg is null!", __FILE__, __LINE__); 
                asmExt->input[nbInput]->reg64 = asmExt->output[retrieve_output_index_from_letter('g')]->reg64;
                asmExt->input[nbInput]->regh = register_higher(asmExt->input[nbInput]->reg64);
                asmExt->input[nbInput]->regl = register_lower(asmExt->input[nbInput]->reg64);
                asmExt->input[nbInput]->regw = register_word(asmExt->input[nbInput]->reg64);                
            }                 
        }

        else if (tok->kind == TK_STR && !strncmp(tok->str, "Nd", tok->len))
        {

            asmExt->input[nbInput]->variableNumber = retrieveVariableNumber(nbOutput + nbInput);
            asmExt->input[nbInput]->index = nbOutput + nbInput;            
            asmExt->input[nbInput]->letter = 'N';            
            //=====ISS-156 case we have no output for the letter
            if (retrieve_output_index_from_letter('N') == -1) {
                asmExt->input[nbInput]->reg = use_fixed_register("%rdx");
                if (!asmExt->input[nbInput]->reg)
                    error("%s:%d: error: in input_asm function input_asm :reg is null!", __FILE__, __LINE__); 
                asmExt->input[nbInput]->reg64 = asmExt->input[nbInput]->reg;                
                asmExt->input[nbInput]->variableNumber = retrieveVariableNumber(nbOutput + nbInput);
            }
            else {            
                asmExt->input[nbInput]->reg = asmExt->output[retrieve_output_index_from_letter('N')]->reg;
                if (!asmExt->input[nbInput]->reg)
                    error("%s:%d: error: in input_asm function input_asm :reg is null!", __FILE__, __LINE__); 
                asmExt->input[nbInput]->reg64 = asmExt->output[retrieve_output_index_from_letter('N')]->reg64;
            }            
            asmExt->input[nbInput]->regh = register_higher(asmExt->input[nbInput]->reg64);
            asmExt->input[nbInput]->regl = register_lower(asmExt->input[nbInput]->reg64);
            asmExt->input[nbInput]->regw = register_word(asmExt->input[nbInput]->reg64);
        }
        else if (tok->kind == TK_STR && (!strncmp(tok->str, "I", tok->len) || !strncmp(tok->str, "i", tok->len) || 
                                        !strncmp(tok->str, "n", tok->len) || !strncmp(tok->str, "J", tok->len) || !strncmp(tok->str, "K", tok->len)))
        {
            asmExt->input[nbInput]->variableNumber = retrieveVariableNumber(nbOutput + nbInput);
            asmExt->input[nbInput]->index = nbOutput + nbInput;            
            asmExt->input[nbInput]->letter = tok->str[0];
            // Treat as immediate/general register if no output matches
            if (retrieve_output_index_from_letter(tok->str[0]) == -1) {
                asmExt->input[nbInput]->reg = specific_register_available("%rax");
                if (!asmExt->input[nbInput]->reg)
                    error("%s:%d: error: in input_asm function input_asm :reg is null!", __FILE__, __LINE__); 
                asmExt->input[nbInput]->reg64 = asmExt->input[nbInput]->reg;
                asmExt->input[nbInput]->regh = register_higher(asmExt->input[nbInput]->reg64);
                asmExt->input[nbInput]->regl = register_lower(asmExt->input[nbInput]->reg64);
                asmExt->input[nbInput]->regw = register_word(asmExt->input[nbInput]->reg64);
                asmExt->input[nbInput]->variableNumber = retrieveVariableNumber(nbOutput + nbInput);
            }
            else {
                int out_idx = retrieve_output_index_from_letter(tok->str[0]);
                asmExt->input[nbInput]->reg = asmExt->output[out_idx]->reg;
                asmExt->input[nbInput]->reg64 = asmExt->output[out_idx]->reg64;
                asmExt->input[nbInput]->regh = register_higher(asmExt->input[nbInput]->reg64);
                asmExt->input[nbInput]->regl = register_lower(asmExt->input[nbInput]->reg64);
                asmExt->input[nbInput]->regw = register_word(asmExt->input[nbInput]->reg64);
            }
        }
 
        else if (tok->kind == TK_STR && (!strncmp(tok->str, "m", tok->len) ||  !strncmp(tok->str, "rm", tok->len)))
        {

            asmExt->input[nbInput]->variableNumber = retrieveVariableNumber(nbOutput + nbInput);
            asmExt->input[nbInput]->index = nbOutput + nbInput;
            // Pure memory input: don't reserve a scratch register unless we later
            // discover the operand needs an address in a register (e.g. *ptr).
            asmExt->input[nbInput]->reg = "%mem";
            asmExt->input[nbInput]->reg64 = "%mem";
            asmExt->input[nbInput]->letter = 'm';
        }
        else if (tok->kind == TK_STR && !strncmp(tok->str, "q", tok->len))
        {

            asmExt->input[nbInput]->variableNumber = retrieveVariableNumber(nbOutput + nbInput);
            asmExt->input[nbInput]->index = nbOutput + nbInput;
            asmExt->input[nbInput]->reg = specific_register_available("%r10");
            asmExt->input[nbInput]->isq = true;
            if (!asmExt->input[nbInput]->reg)
                 error_tok(tok, "%s:%d: error: in input_asm function input_asm :reg is null!", __FILE__, __LINE__);            
            asmExt->input[nbInput]->reg64 = asmExt->input[nbInput]->reg;
            asmExt->input[nbInput]->regh = register_higher(asmExt->input[nbInput]->reg64);
            asmExt->input[nbInput]->regl = register_lower(asmExt->input[nbInput]->reg64);
            asmExt->input[nbInput]->regw = register_word(asmExt->input[nbInput]->reg64);            
            asmExt->input[nbInput]->letter = 'q';
        }            
        else if (tok->kind == TK_STR && !strncmp(tok->str, "Q", tok->len))
        {

            asmExt->input[nbInput]->variableNumber = retrieveVariableNumber(nbOutput + nbInput);
            asmExt->input[nbInput]->index = nbOutput + nbInput;
            asmExt->input[nbInput]->reg = specific_register_available("%rax");
            asmExt->input[nbInput]->isq = true;
            if (!asmExt->input[nbInput]->reg)
                 error_tok(tok, "%s:%d: error: in input_asm function input_asm :reg is null!", __FILE__, __LINE__);            
            asmExt->input[nbInput]->reg64 = asmExt->input[nbInput]->reg;
            asmExt->input[nbInput]->regh = register_higher(asmExt->input[nbInput]->reg64);
            asmExt->input[nbInput]->regl = register_lower(asmExt->input[nbInput]->reg64);
            asmExt->input[nbInput]->regw = register_word(asmExt->input[nbInput]->reg64);
            asmExt->input[nbInput]->letter = 'Q';
        }        
        else if (tok->kind == TK_STR && !strncmp(tok->str, "l", tok->len))
        {

            asmExt->input[nbInput]->variableNumber = retrieveVariableNumber(nbOutput + nbInput);
            asmExt->input[nbInput]->index = nbOutput + nbInput;
            asmExt->input[nbInput]->reg = specific_register_available("%r10");
            asmExt->input[nbInput]->isl = true;
            if (!asmExt->input[nbInput]->reg)
                 error_tok(tok, "%s:%d: error: in input_asm function input_asm :reg is null!", __FILE__, __LINE__);            
            asmExt->input[nbInput]->reg64 = asmExt->input[nbInput]->reg;
            asmExt->input[nbInput]->regh = register_higher(asmExt->input[nbInput]->reg64);
            asmExt->input[nbInput]->regl = register_lower(asmExt->input[nbInput]->reg64);
            asmExt->input[nbInput]->regw = register_word(asmExt->input[nbInput]->reg64);            
            asmExt->input[nbInput]->letter = 'l';
        }        


        else if ((tok->kind == TK_STR && !strncmp(tok->str, "r", tok->len)) || (tok->kind == TK_STR && !strncmp(tok->str, "rn", tok->len))            )
        {
            asmExt->input[nbInput]->variableNumber = retrieveVariableNumber(nbOutput + nbInput);
            asmExt->input[nbInput]->index = nbOutput + nbInput;
            asmExt->input[nbInput]->reg = specific_register_available("%r10");
            if (!asmExt->input[nbInput]->reg)
                error_tok(tok,"%s:%d: error: in input_asm function input_asm :reg is null!", __FILE__, __LINE__);            
            asmExt->input[nbInput]->reg64 = asmExt->input[nbInput]->reg;
            asmExt->input[nbInput]->regh = register_higher(asmExt->input[nbInput]->reg64);
            asmExt->input[nbInput]->regl = register_lower(asmExt->input[nbInput]->reg64);
            asmExt->input[nbInput]->regw = register_word(asmExt->input[nbInput]->reg64);            
            asmExt->input[nbInput]->letter = 'r';
            if (hasOperandName) {
                asmExt->input[nbInput]->size = 8;
                asmExt->input[nbInput]->is_pure_register = true;                
            }
            
        }
        //D for destination operand
        else if (tok->kind == TK_STR && !strncmp(tok->str, "D", tok->len))
        {
            asmExt->input[nbInput]->variableNumber = retrieveVariableNumber(nbOutput + nbInput);
            asmExt->input[nbInput]->index = nbOutput + nbInput;
            asmExt->input[nbInput]->reg = specific_register_available("%rdx");
            if (!asmExt->input[nbInput]->reg)
                 error_tok(tok,"%s:%d: error: in input_asm function input_asm :reg is null!", __FILE__, __LINE__);            
            asmExt->input[nbInput]->reg64 = asmExt->input[nbInput]->reg;
            asmExt->input[nbInput]->regh = register_higher(asmExt->input[nbInput]->reg64);
            asmExt->input[nbInput]->regl = register_lower(asmExt->input[nbInput]->reg64);
            asmExt->input[nbInput]->regw = register_word(asmExt->input[nbInput]->reg64);            
            asmExt->input[nbInput]->letter = 'D';
            
        }
        //S for source operand
        else if (tok->kind == TK_STR && !strncmp(tok->str, "S", tok->len))
        {
            asmExt->input[nbInput]->variableNumber = retrieveVariableNumber(nbOutput + nbInput);
            asmExt->input[nbInput]->index = nbOutput + nbInput;
            asmExt->input[nbInput]->reg = specific_register_available("%r11");
            if (!asmExt->input[nbInput]->reg)
                 error_tok(tok, "%s:%d: error: in input_asm function input_asm :reg is null!", __FILE__, __LINE__);            
            asmExt->input[nbInput]->reg64 = asmExt->input[nbInput]->reg;
            asmExt->input[nbInput]->regh = register_higher(asmExt->input[nbInput]->reg64);
            asmExt->input[nbInput]->regl = register_lower(asmExt->input[nbInput]->reg64);
            asmExt->input[nbInput]->regw = register_word(asmExt->input[nbInput]->reg64);            
            asmExt->input[nbInput]->letter = 'S';

        }

        else if (equal(tok, "("))
        {
            SET_CTX(ctx);
            while (equal(tok, "("))
                tok = tok->next;
            if (parse_simple_binary_input(rest, tok, locals))
                return;
            // check if the variable is defined
            if (equal(tok, "-")) 
            {
                isToNegate = true;
                consume(&tok, tok, "-");
            }            
            if (tok->kind == TK_IDENT)
            {           
                if (isToNegate) {
                    asmExt->input[nbInput]->isToNegate = isToNegate;
                    isToNegate = false;
                }
                    
                sc = find_var(tok);
                if (!sc)
                    error_tok(tok, "%s:%d: in input_asm function : variable undefined", __FILE__, __LINE__);
                if (!sc->var->ty)
                    error_tok(tok, "%s:%d: in input_asm function : variable type unknown", __FILE__, __LINE__);
                asmExt->input[nbInput]->input = tok;
                asmExt->input[nbInput]->isVariable = true;
                asmExt->input[nbInput]->size = sc->var->ty->size;
                if (sc->var->funcname) {     
                    update_offset(sc->var->funcname, locals);
                    Obj *iv = find_obj_by_tok(locals, tok);
                    if (iv && iv->offset)
                        sc->var->offset = iv->offset;
                    asmExt->input[nbInput]->offset = (iv && iv->offset) ? iv->offset : sc->var->offset;
                } 
                else {
                    asmExt->input[nbInput]->offset = sc->var->offset;
                }
                int base_off = asmExt->input[nbInput]->offset;
                if (!asmExt->input[nbInput]->reg) {
                    error_tok(tok, "%s:%d: error: in input_asm function input_asm :reg is null! %d", __FILE__, __LINE__, nbInput);
                }

                //managing specific case of arrays
                Token *bracket = tok->next;
                while (equal(bracket, ")")) bracket = bracket->next;
                if (sc->var->ty->kind == TY_ARRAY && equal(bracket, "[")) {
                    SET_CTX(ctx);
                    tok = skip(bracket, "[", ctx);
                    asmExt->input[nbInput]->isArray = true;
                    asmExt->input[nbInput]->indexArray = tok->val;
                    asmExt->input[nbInput]->isAddress = false;
                    asmExt->input[nbInput]->size = sc->var->ty->base->size;
                    if (!asmExt->input[nbInput]->reg)
                        error_tok(tok, "%s:%d: error: in input_asm function input_asm :reg is null!", __FILE__, __LINE__);
                    if (asmExt->input[nbInput]->letter != 'm')
                        asmExt->input[nbInput]->reg = update_register_size(asmExt->input[nbInput]->reg, asmExt->input[nbInput]->size);
                    //calculate the offset for each element from the bottom to the top r[0] has the lowest offset example -48, r[1] - 44, r[2] -40, r[3] - 36
                    asmExt->input[nbInput]->offset = (sc->var->offset ) + (asmExt->input[nbInput]->indexArray * asmExt->input[nbInput]->size);
                    asmExt->input[nbInput]->offsetArray = base_off;
                    if (asmExt->input[nbInput]->letter == 'm')
                        asmExt->input[nbInput]->reg = load_variable(asmExt->input[nbInput]->offset);
                    tok = tok->next;
                    SET_CTX(ctx);
                    tok = skip(tok, "]", ctx);
                    SET_CTX(ctx);
                    while (equal(tok, ")")) tok = tok->next;
                    *rest = tok;
                    return;
                }        
                else if ((sc->var->ty->kind == TY_PTR || sc->var->ty->kind == TY_ARRAY) && 
                         ({ Token *p = tok->next; while(equal(p, ")")) p = p->next; equal(p, "["); })) {
                    Token *bracket_ptr = tok->next;
                    while (equal(bracket_ptr, ")")) bracket_ptr = bracket_ptr->next;
                    SET_CTX(ctx);
                    tok = skip(bracket_ptr, "[", ctx);
                    asmExt->input[nbInput]->isArray = true;
                    asmExt->input[nbInput]->isAddress = true;
                    asmExt->input[nbInput]->indexArray = tok->val;
                    asmExt->input[nbInput]->size = sc->var->ty->base->size;
                    if (!asmExt->input[nbInput]->reg)
                        error_tok(tok, "%s:%d: error: in input_asm function input_asm :reg is null!", __FILE__, __LINE__);                    
                    ensure_input_reg(asmExt->input[nbInput], "%r11");
                    asmExt->input[nbInput]->reg = update_register_size(asmExt->input[nbInput]->reg, asmExt->input[nbInput]->size);
                    //calculate the offset for each element from the bottom to the top r[0] has the lowest offset example -48, r[1] - 44, r[2] -40, r[3] - 36
                    asmExt->input[nbInput]->offset = (asmExt->input[nbInput]->indexArray * asmExt->input[nbInput]->size);
                    asmExt->input[nbInput]->offsetArray = base_off;
                    tok = tok->next;
                    SET_CTX(ctx);
                    tok = skip(tok, "]", ctx);
                    SET_CTX(ctx);
                    while (equal(tok, ")")) tok = tok->next;
                    *rest = tok;
                    return;                    
                }
               //Trying to fix ISS-164 special case of ptr->value form (ptr to a struct)
                else if (sc->var->ty->kind == TY_PTR && 
                         ({ Token *p = tok->next; while(equal(p, ")")) p = p->next; (equal(p, "->") || equal(p, ".")); })) {
                    Token *arrow = tok->next;
                    while (equal(arrow, ")")) arrow = arrow->next;
                    if (!sc->var->ty->base)
                        error_tok(tok, "%s:%d: in input_asm function : expecting struct base but base is null!", __FILE__, __LINE__);
                    asmExt->input[nbInput]->input = tok;
                    SET_CTX(ctx);
                    tok = skip(arrow, (char *)(equal(arrow, "->") ? "->" : "."), ctx);
                    Token * tokmbr = tok;
                    // retrieve the size of the variable to determine the register to use here we use RAX variation
                    asmExt->input[nbInput]->isAddress = true;  
                    asmExt->input[nbInput]->isStruct = true;     
                    asmExt->input[nbInput]->size = sc->var->ty->size;
                    if (!asmExt->input[nbInput]->reg)
                        error_tok(tok, "%s:%d: in input_asm function : reg is null extended assembly not managed yet", __FILE__, __LINE__);                
                    ensure_input_reg(asmExt->input[nbInput], "%r11");
                    asmExt->input[nbInput]->reg = update_register_size(asmExt->input[nbInput]->reg, asmExt->input[nbInput]->size);
                    //asmExt->input[nbInput]->variableNumber = retrieveVariableNumber(nbInput);
                    if (!sc->var->ty->base->members)
                        error_tok(tok, "%s:%d: in input_asm function : expecting members but members is null", __FILE__, __LINE__);
                    if (sc->var->funcname) {
                        update_offset(sc->var->funcname, locals);
                        asmExt->input[nbInput]->offset = sc->var->offset;
                    }
                    else {
                        asmExt->input[nbInput]->offset = 0;
                    }
                    //need to update the specific struct field offset
                    char *toktmp = calloc(1, sizeof(char) * 300);                    
                    for (Member *mbr = sc->var->ty->base->members; mbr; mbr = mbr->next) {
                        if (mbr->name->len > 59)
                            error_tok(tok, "%s:%d %d: in input_asm function : not enough size for toktmp", __FILE__, __LINE__, mbr->name->len);
                        strncat(toktmp, mbr->name->loc, mbr->name->len);                            
                        if (equal(tokmbr, toktmp)) {
                            asmExt->input[nbInput]->offsetStruct = mbr->offset ;
                            asmExt->input[nbInput]->size = mbr->ty->size ;
                            if (!asmExt->input[nbInput]->reg)
                                error_tok(tok, "%s:%d: error: in input_asm function input_asm :reg is null!", __FILE__, __LINE__);
                            asmExt->input[nbInput]->reg = update_register_size(asmExt->input[nbInput]->reg, asmExt->input[nbInput]->size);
                        }
                    }
                    tok = tok->next;
                    SET_CTX(ctx);
                    while (equal(tok, ")"))
                        tok = tok->next;
                    *rest = tok;
                    return;
                }

                if (asmExt->input[nbInput]->letter == 'm' && !asmExt->input[nbInput]->isAddress) {
                    asmExt->input[nbInput]->reg = load_variable(asmExt->input[nbInput]->offset);
                } else {
                    ensure_input_reg(asmExt->input[nbInput], "%r11");
                    asmExt->input[nbInput]->reg = update_register_size(asmExt->input[nbInput]->reg, asmExt->input[nbInput]->size);
                }
                if (isDebug) printf("input_asm: TK_IDENT name=%.*s size=%d reg=%s\n", tok->len, tok->loc, asmExt->input[nbInput]->size, asmExt->input[nbInput]->reg);
                tok = tok->next;
                SET_CTX(ctx);
                while (equal(tok, ")"))
                    tok = tok->next;
                *rest = tok;
                return;
            } // immediate value
            else if (tok->kind == TK_NUM)
            {

                int length = snprintf(NULL, 0, "%ld", tok->val);
                if (tok->val == 0)
                    strncat(input_value, "0 ", 3);
                else
                    snprintf(input_value, length + 1, "%ld", tok->val);
                asmExt->input[nbInput]->input = tok;
                asmExt->input[nbInput]->isVariable = false;
                asmExt->input[nbInput]->isAddress = false;
                asmExt->input[nbInput]->input_value = input_value;
                asmExt->input[nbInput]->size = 8;
                if (isDebug) printf("input_asm: TK_NUM val=%ld size=%d\n", tok->val, asmExt->input[nbInput]->size);
                asmExt->input[nbInput]->reg = update_register_size(asmExt->input[nbInput]->reg, asmExt->input[nbInput]->size);                                
                tok = tok->next;
                SET_CTX(ctx);
                while (equal(tok, ")"))
                    tok = tok->next;
                *rest = tok;
                return;
            } // pointer
            else if (equal(tok, "*"))
            {
                consume(&tok, tok, "*");
                if (tok->kind == TK_IDENT)
                {
                    asmExt->input[nbInput]->input = tok;                    
                    sc = find_var(tok);
                    if (!sc)
                        error_tok(tok, "%s:%d: in input_asm function : variable undefined2", __FILE__, __LINE__);
                    asmExt->input[nbInput]->input = tok;
                    asmExt->input[nbInput]->isVariable = true;
                    asmExt->input[nbInput]->isAddress = true;
                    asmExt->input[nbInput]->size = sc->var->ty->size;
                    ensure_input_reg(asmExt->input[nbInput], "%r11");
                    if (sc->var->funcname) {
                        update_offset(sc->var->funcname, locals);

                        asmExt->input[nbInput]->offset = sc->var->offset;
                    } 
                    if (!asmExt->input[nbInput]->reg)
                        error_tok(tok,"%s:%d: error: in input_asm function input_asm :reg is null!", __FILE__, __LINE__);
                    asmExt->input[nbInput]->reg = update_register_size(asmExt->input[nbInput]->reg, asmExt->input[nbInput]->size);
                    tok = tok->next;
                    SET_CTX(ctx);
                    while (equal(tok, ")"))
                        tok = tok->next;
                    *rest = tok;
                    return;
                       // Handle casted input like *((void **)ptr)
                } else  if (equal(tok, "(") && equal(tok->next, "(")) {
                        // Skip '(('
                        tok = tok->next->next;

                        // Parse cast type — here just support 'void **' for now
                        if (!equal(tok, "void"))
                            error_tok(tok, "%s:%d: error: in input_asm function input_asm : expected cast to (void **)!", __FILE__, __LINE__);

                        tok = tok->next;

                        int pointer_depth = 0;
                        while (equal(tok, "*")) {
                            pointer_depth++;
                            tok = tok->next;
                        }

                        if (!equal(tok, ")"))
                            error_tok(tok, "expected ')' after cast type");

                        tok = tok->next; // skip first ')'

                        // Now expect TK_IDENT
                        if (tok->kind != TK_IDENT)
                            error_tok(tok, "expected identifier after cast");

                        asmExt->input[nbInput]->input = tok;
                        asmExt->input[nbInput]->isVariable = true;
                        asmExt->input[nbInput]->isAddress = true;

                        sc = find_var(tok);
                        if (!sc)
                            error_tok(tok, "%s:%d: variable undefined in input_asm", __FILE__, __LINE__);
                        if (!sc->var->ty)
                            error_tok(tok, "%s:%d: variable type undefined in input_asm", __FILE__, __LINE__);

                        asmExt->input[nbInput]->size = sc->var->ty->size;

                        if (sc->var->funcname) {
                            update_offset(sc->var->funcname, locals);
                            asmExt->input[nbInput]->offset = sc->var->offset;
                        }
                        ensure_input_reg(asmExt->input[nbInput], "%r11");
                        asmExt->input[nbInput]->reg = update_register_size(asmExt->input[nbInput]->reg, asmExt->input[nbInput]->size);

                        tok = tok->next;
                        if (!equal(tok, ")"))
                            error_tok(tok, "%s:%d: input_asm: expected ')' after cast", __FILE__, __LINE__);
                        tok = tok->next; 
                        

                        SET_CTX(ctx);
                        while (equal(tok, ")"))
                            tok = tok->next;
                        *rest = tok;
                        return;
                    }
            }
            else if (equal(tok, "&"))
            {
                consume(&tok, tok, "&");
                if (tok->kind == TK_IDENT)
                {
                    asmExt->input[nbInput]->input = tok;
                    sc = find_var(tok);
                    if (!sc)
                        error_tok(tok, "variable undefined in input_asm");
                    asmExt->input[nbInput]->input = tok;
                    asmExt->input[nbInput]->isVariable = true;
                    asmExt->input[nbInput]->isLea = true;
                    asmExt->input[nbInput]->size = 8;
                    if (sc->var->funcname) {
                        update_offset(sc->var->funcname, locals);
                        asmExt->input[nbInput]->offset = sc->var->offset;
                    }
                    if (!asmExt->input[nbInput]->reg)
                         error_tok(tok, "reg is null in input_asm");
                    asmExt->input[nbInput]->reg = update_register_size(asmExt->input[nbInput]->reg, 8);
                    tok = tok->next;
                    SET_CTX(ctx);
                    while (equal(tok, ")"))
                        tok = tok->next;
                    *rest = tok;
                    return;
                }
            }
            else if (equal(tok, "&"))
            {
                consume(&tok, tok, "&");
                if (tok->kind == TK_IDENT)
                {
                    asmExt->output[nbOutput]->output = tok;
                    sc = find_var(tok);
                    if (!sc)
                        error_tok(tok, "%s:%d: in output_asm function : variable undefined", __FILE__, __LINE__);
                    if (!sc->var->ty)
                        error_tok(tok, "%s:%d: in output_asm function : variable type unknown", __FILE__, __LINE__);
                    
                    asmExt->output[nbOutput]->size = sc->var->ty->size;
                    if (sc->var->funcname) {
                        update_offset(sc->var->funcname, locals);
                        asmExt->output[nbOutput]->offset = sc->var->offset;
                    } else {
                        asmExt->output[nbOutput]->offset = 0;
                    }
                    asmExt->output[nbOutput]->isVariable = true;
                    if (!asmExt->output[nbOutput]->reg)
                        error_tok(tok, "%s:%d: in output_asm function : reg is null", __FILE__, __LINE__);
                    asmExt->output[nbOutput]->reg = update_register_size(asmExt->output[nbOutput]->reg, asmExt->output[nbOutput]->size);
                    asmExt->output[nbOutput]->variableNumber = retrieveVariableNumber(nbOutput);
                    tok = tok->next;
                    SET_CTX(ctx);
                    while (equal(tok, ")"))
                        tok = tok->next;
                    *rest = tok;
                    return;
                }
            }
        }
        else if (equal(tok, ",")) {
            SET_CTX(ctx);
            tok = skip(tok, ",", ctx); continue;
        }
        else {            
            error_tok(tok, "%s:%d : in input_asm function : input complex constraint not managed yet! %.*s", __FILE__, __LINE__, tok->len, tok->loc);
        }

        tok = tok->next;
        *rest = tok;
    }
    return;
}


// do the susbtitution into the template
char *subst_asm(char *template, char *output_str, char *input_str)
{
    return string_replace(template, input_str, output_str);
}

// generic string replace function
char *string_replace(char *str, char *oldstr, char *newstr)
{
    size_t cap = 10000;
    char bstr[10000];
    memset(bstr, 0, sizeof(bstr));
    int i;
    for (i = 0; i < strlen(str); i++)
    {
        if (!strncmp(str + i, oldstr, strlen(oldstr)))
        {
            strcat(bstr, newstr);
            i += strlen(oldstr) - 1;
        }
        else
        {
            strncat(bstr, str + i, 1);
        }
        if (strlen(bstr) + 2 >= cap)
            error("%s:%d: error: in string_replace : not enough memory!", __FILE__, __LINE__);
    }

    strncpy(str, bstr, strlen(bstr) + 1);
    if (strlen(str)> 10000)
        error("%s:%d: error: in string_replace : not enough memory!", __FILE__, __LINE__);
    return str;
}




// generate input assembly instruction
char *generate_input_asm(char *input_str)
{
    
    char *tmp = calloc(1, sizeof(char) * 200);
    // For pure memory operands, substitute %N with the memory address and don't emit loads.
    if (asmExt->input[nbInput]->letter == 'm' &&
        asmExt->input[nbInput]->isVariable &&
        !asmExt->input[nbInput]->isAddress &&
        !asmExt->input[nbInput]->isBinaryExpr)
        return tmp;
    if (asmExt->input[nbInput]->isBinaryExpr)
    {
        char imm_buf[32];

        strncat(tmp, "\n", 3);
        strncat(tmp, opcode(asmExt->input[nbInput]->size), strlen(opcode(asmExt->input[nbInput]->size)));
        if (asmExt->input[nbInput]->bin_lhs_is_imm) {
            snprintf(imm_buf, sizeof(imm_buf), "%ld", asmExt->input[nbInput]->bin_lhs_imm);
            strncat(tmp, " $", 3);
            strncat(tmp, imm_buf, strlen(imm_buf));
        } else {
            strncat(tmp, load_variable(asmExt->input[nbInput]->bin_lhs_offset),
                    strlen(load_variable(asmExt->input[nbInput]->bin_lhs_offset)));
        }
        strncat(tmp, ", ", 3);
        strncat(tmp, asmExt->input[nbInput]->variableNumber, strlen(asmExt->input[nbInput]->variableNumber));
        strncat(tmp, ";\n", 3);

        strncat(tmp, arith_opcode(asmExt->input[nbInput]->bin_op, asmExt->input[nbInput]->size),
                strlen(arith_opcode(asmExt->input[nbInput]->bin_op, asmExt->input[nbInput]->size)));
        if (asmExt->input[nbInput]->bin_rhs_is_imm) {
            snprintf(imm_buf, sizeof(imm_buf), "%ld", asmExt->input[nbInput]->bin_rhs_imm);
            strncat(tmp, " $", 3);
            strncat(tmp, imm_buf, strlen(imm_buf));
        } else {
            strncat(tmp, load_variable(asmExt->input[nbInput]->bin_rhs_offset),
                    strlen(load_variable(asmExt->input[nbInput]->bin_rhs_offset)));
        }
        strncat(tmp, ", ", 3);
        strncat(tmp, asmExt->input[nbInput]->variableNumber, strlen(asmExt->input[nbInput]->variableNumber));
        strncat(tmp, ";\n", 3);
        return tmp;
    }
    //case variable
    if (asmExt->input[nbInput]->isVariable && asmExt->input[nbInput]->isToNegate)
    {
        strncat(tmp, "\n", 3);
        strncat(tmp, opcode(asmExt->input[nbInput]->size), strlen(opcode(asmExt->input[nbInput]->size)));
        strncat(tmp, load_variable(asmExt->input[nbInput]->offset), strlen(load_variable(asmExt->input[nbInput]->offset)));
        strncat(tmp, ", ", 3);
        strncat(tmp, asmExt->input[nbInput]->variableNumber, strlen(asmExt->input[nbInput]->variableNumber));
        strncat(tmp, ";\n", 3);
        strncat(tmp, "  neg ", 7);
        strncat(tmp, asmExt->input[nbInput]->variableNumber, strlen(asmExt->input[nbInput]->variableNumber));
        strncat(tmp, ";\n", 3);
        return tmp;
    }
    else if (asmExt->input[nbInput]->isVariable && asmExt->input[nbInput]->isLea)
    {
        strncat(tmp, "\n  leaq ", 10);
        strncat(tmp, load_variable(asmExt->input[nbInput]->offset), strlen(load_variable(asmExt->input[nbInput]->offset)));
        strncat(tmp, ", ", 3);
        strncat(tmp, asmExt->input[nbInput]->variableNumber, strlen(asmExt->input[nbInput]->variableNumber));
        strncat(tmp, ";\n", 3);
        return tmp;
    }
    else if (asmExt->input[nbInput]->isVariable && !asmExt->input[nbInput]->isAddress)
    {
        strncat(tmp, "\n", 3);
        strncat(tmp, opcode(asmExt->input[nbInput]->size), strlen(opcode(asmExt->input[nbInput]->size)));
        strncat(tmp, load_variable(asmExt->input[nbInput]->offset), strlen(load_variable(asmExt->input[nbInput]->offset)));
        strncat(tmp, ", ", 3);
        strncat(tmp, asmExt->input[nbInput]->variableNumber, strlen(asmExt->input[nbInput]->variableNumber));
        strncat(tmp, ";\n", 3);
        return tmp;
    }
    else if (asmExt->input[nbInput]->isAddress)
    {
        strncat(tmp, "\n", 3);
        strncat(tmp, opcode(8), strlen(opcode(8)));
        int off = (asmExt->input[nbInput]->isArray) ? asmExt->input[nbInput]->offsetArray : asmExt->input[nbInput]->offset;
        strncat(tmp, load_variable(off), strlen(load_variable(off)));
        strncat(tmp, ", ", 3);
        strncat(tmp, asmExt->input[nbInput]->variableNumber, strlen(asmExt->input[nbInput]->variableNumber));
        strncat(tmp, ";\n", 3);

        int member_off = 0;
        if (asmExt->input[nbInput]->isArray) member_off = asmExt->input[nbInput]->offset;
        else if (asmExt->input[nbInput]->isStruct) member_off = asmExt->input[nbInput]->offsetStruct;

        if (member_off != 0) {
            char off_str[16];
            snprintf(off_str, sizeof(off_str), "%d", member_off);
            strncat(tmp, "  addq $", 11);
            strncat(tmp, off_str, strlen(off_str));
            strncat(tmp, ", ", 3);
            strncat(tmp, asmExt->input[nbInput]->variableNumber, strlen(asmExt->input[nbInput]->variableNumber));
            strncat(tmp, ";\n", 3);
        }

        if (asmExt->input[nbInput]->letter != 'm') {
            strncat(tmp, opcode(8), 8);
            strncat(tmp, "(", 2);
            strncat(tmp, asmExt->input[nbInput]->reg64, strlen(asmExt->input[nbInput]->reg64));
            strncat(tmp, ")", 2);
            strncat(tmp, ", ", 3);
            strncat(tmp, asmExt->input[nbInput]->reg64, strlen(asmExt->input[nbInput]->reg64));
            strncat(tmp, "\n", 3);        
        }
        return tmp;
    }
    //case immediate value
    else if (asmExt->input[nbInput]->input_value)
    {
        strncat(tmp, "\n", 3);
        strncat(tmp, opcode(asmExt->input[nbInput]->size), strlen(opcode(asmExt->input[nbInput]->size)));        
        strncat(tmp, " $", 3);
        strncat(tmp, asmExt->input[nbInput]->input_value, strlen(asmExt->input[nbInput]->input_value));
        strncat(tmp, ", ", 3);
        strncat(tmp, asmExt->input[nbInput]->variableNumber, strlen(asmExt->input[nbInput]->variableNumber));
        strncat(tmp, ";\n", 3);
        return tmp;
    }
    
    error("%s:%d: error: in extended_asm function generate_input_asm : unexpected error! %s", __FILE__, __LINE__, asmExt->template->templatestr);
    //return NULL;
}

// check if template contains %
bool check_template(char *template)
{
    return strchr(template, '%') != NULL;
}


// generate input assembly instruction
char *generate_output_asm(char *output_str)
{
    
    char *tmp = calloc(1, sizeof(char) * 300);
    // Memory outputs are written by the asm itself (read-modify-write included).
    // Don't emit a "store back" sequence; it can corrupt memory for ptr-based
    // operands like "+m"(rp[0]) used by OpenSSL.
    if (asmExt->output[nbOutput]->letter == 'm')
        return tmp;
    // For pure memory outputs, the asm writes directly to the lvalue.
    if (asmExt->output[nbOutput]->letter == 'm' &&
        asmExt->output[nbOutput]->isVariable &&
        !asmExt->output[nbOutput]->isAddress &&
        !asmExt->output[nbOutput]->isArray &&
        !asmExt->output[nbOutput]->isStruct)
        return tmp;
    //case variable and not an address
    if (asmExt->output[nbOutput]->isVariable && !asmExt->output[nbOutput]->isAddress)
    {
        strncat(tmp, "\n", 3);
        strncat(tmp, opcode(asmExt->output[nbOutput]->size), strlen(opcode(asmExt->output[nbOutput]->size)));
        strncat(tmp, asmExt->output[nbOutput]->variableNumber, strlen(asmExt->output[nbOutput]->variableNumber));
        strncat(tmp, ", ", 3);
        strncat(tmp, load_variable(asmExt->output[nbOutput]->offset), strlen(load_variable(asmExt->output[nbOutput]->offset)));
        strncat(tmp, ";\n", 3);
        return tmp;
    }
    //case not an address it means that it's an immediate value should probably never exists
    else if (!asmExt->output[nbOutput]->isAddress)
    {
        strncat(tmp, opcode(asmExt->output[nbOutput]->size), strlen(opcode(asmExt->output[nbOutput]->size)));
        strncat(tmp, " $", 3);
        strncat(tmp, asmExt->input[nbInput]->input_value, strlen(asmExt->input[nbInput]->input_value));
        strncat(tmp, ", ", 3);
        strncat(tmp, asmExt->input[nbInput]->variableNumber, strlen(asmExt->input[nbInput]->variableNumber));
        strncat(tmp, ";\n", 3);
        return tmp;
    }
    //case it's an array with address we need to generate the correct output for the specified index
    else if (asmExt->output[nbOutput]->isAddress && asmExt->output[nbOutput]->isArray) {
        strncat(tmp, "\n", 3);
        strncat(tmp, "  movq ", 8);
        strncat(tmp, load_variable(asmExt->output[nbOutput]->offsetArray), strlen(load_variable(asmExt->output[nbOutput]->offsetArray)));
        strncat(tmp, ", %rsi\n", 8);
        strncat(tmp, opcode(asmExt->output[nbOutput]->size), strlen(opcode(asmExt->output[nbOutput]->size)));
        strncat(tmp, asmExt->output[nbOutput]->variableNumber, strlen(asmExt->output[nbOutput]->variableNumber));
        //if index 0 we move the value into address pointed by rsi, if index 1 the value will be stored at address pointed by rsi + size of one element
        //if index 2 the value will be stored at address pointed by rsi + (index * size of one element)...
        char *tmp2 = calloc(1, sizeof(char) * 100);
        if (asmExt->output[nbOutput]->indexArray == 0)
            strncat(tmp, ", (%rsi)\n", 11);
        else {
            strncat(tmp, ", ", 3);
            snprintf(tmp2, 100, "%d", asmExt->output[nbOutput]->offset);
            strncat(tmp2, "(%rsi)\n", 9); //to have example 4(%rsi) for index 1, 8(%rsi) for index 2...
            strncat(tmp, tmp2, strlen(tmp2));
        }
        return tmp;
    }

    //Trying to fix ======ISS-164 case it's a struct with address we need to generate the correct output for the specified struct member
    else if (asmExt->output[nbOutput]->isAddress && asmExt->output[nbOutput]->isStruct && strncmp(asmExt->output[nbOutput]->prefix, "=", 2)) {
        strncat(tmp, "\n", 3);
        strncat(tmp, "  movq ", 8);
        strncat(tmp, load_variable(asmExt->output[nbOutput]->offset), strlen(load_variable(asmExt->output[nbOutput]->offset)));
        strncat(tmp, ", %rsi\n", 8);
        strncat(tmp, opcode(asmExt->output[nbOutput]->size), strlen(opcode(asmExt->output[nbOutput]->size)));
        strncat(tmp, asmExt->output[nbOutput]->variableNumber, strlen(asmExt->output[nbOutput]->variableNumber));
        //if index 0 we move the value into address pointed by rsi, if index 1 the value will be stored at address pointed by rsi + size of one element
        //if index 2 the value will be stored at address pointed by rsi + (index * size of one element)...
        char *tmp2 = calloc(1, sizeof(char) * 100);
        if (asmExt->output[nbOutput]->offsetStruct == 0)
            strncat(tmp, ", (%rsi)\n", 11);
        else {
            strncat(tmp, ", ", 3);
            snprintf(tmp2, 100, "%d", asmExt->output[nbOutput]->offsetStruct);
            strncat(tmp2, "(%rsi)\n", 9); //to have example 4(%rsi) for index 1, 8(%rsi) for index 2...
            strncat(tmp, tmp2, strlen(tmp2));
        }
        return tmp;
    }

    //case it's an address 
    else if (asmExt->output[nbOutput]->isAddress)
    {
        if (asmExt->output[nbOutput]->letter == 'm'|| asmExt->output[nbOutput]->letter == 'r' || asmExt->output[nbOutput]->letter == 'q') {
        strncat(tmp, "\n", 3);
        strncat(tmp, "  movq ", 8);
        strncat(tmp, load_variable(asmExt->output[nbOutput]->offset), strlen(load_variable(asmExt->output[nbOutput]->offset)));
        strncat(tmp, ", %rsi\n", 8);
        strncat(tmp, opcode(asmExt->output[nbOutput]->size), strlen(opcode(asmExt->output[nbOutput]->size)));
        strncat(tmp, " (%rsi), ", 11);
        strncat(tmp, asmExt->output[nbOutput]->variableNumber, strlen(asmExt->output[nbOutput]->variableNumber));
        strncat(tmp, "\n", 3);
        return tmp;
        } else {
        strncat(tmp, "\n", 3);
        strncat(tmp, "  movq ", 8);
        strncat(tmp, load_variable(asmExt->output[nbOutput]->offset), strlen(load_variable(asmExt->output[nbOutput]->offset)));
        strncat(tmp, ", %rsi\n", 8);
        strncat(tmp, opcode(asmExt->output[nbOutput]->size), strlen(opcode(asmExt->output[nbOutput]->size)));
        strncat(tmp, asmExt->output[nbOutput]->variableNumber, strlen(asmExt->output[nbOutput]->variableNumber));
        strncat(tmp, ", (%rsi)\n", 11);
        return tmp;
        }
    }

    error("%s:%d: error: in extended_asm function generate_output_asm : unexpected error! %s", __FILE__, __LINE__, asmExt->template->templatestr);

    //return NULL;
}

//codegen.c generates correctly the offset but it's too late.
//two possibilities:
// - write some specific value example %nameofvaroffset% that will be at the end after codegen.c replaced in assembly file
// by the correct value.
// - or trying to do the same job as codegen.c but here. It's the goal of assign_lvar_offsets_assembly in update_offset function
// need to test in several cases
char *load_variable(int offset)
{
    //generic solution to handle all values of offset 
    // if (offset == 0)
    //     error("%s:%d : error: in load_variable : incorrect offset %d or not managed yet!", __FILE__,__LINE__, offset);
    char *targetaddr = calloc(20, sizeof(char));
    
    int length = snprintf(targetaddr, 20, "%d", offset);
    if (length < 0)
        error("%s:%d : error:in load_variable : error during snprintf function! offset=%d length=%d", __FILE__, __LINE__, offset, length);
    strncat(targetaddr, "(%rbp)", 7);
    return targetaddr;
}

char *opcode(int size)
{
    switch (size)
    {
    case 1:
        return "  movb ";
    case 2:
        return "  movw ";
    case 4:
        return "  movl ";
    case 8:
        return "  movq ";
    case 16:
        return "  mov ";        
    default:
        error("%s:%d: error: in opcode : size %d unexpected!", __FILE__, __LINE__, size);
    }
}

static char *arith_opcode(char op, int size)
{
    switch (size)
    {
    case 1:
        return (op == '+') ? "  addb " : "  subb ";
    case 2:
        return (op == '+') ? "  addw " : "  subw ";
    case 4:
        return (op == '+') ? "  addl " : "  subl ";
    case 8:
        return (op == '+') ? "  addq " : "  subq ";
    case 16:
        return (op == '+') ? "  add " : "  sub ";
    default:
        error("%s:%d: error: in arith_opcode : size %d unexpected!", __FILE__, __LINE__, size);
    }
}


// we need to update the offset to be able to use this information later for loading result into output variables.
// TODO we can have an issue here if several functions with same name. Probably need to find in a better way to avoid this issue.
void update_offset(char *funcname, Obj *locals)
{
    //printf(" function %s \n", funcname);
    Obj *fn = find_func(funcname);
    if (fn) {
        //fixing ====ISS-161 issue with some locals missing in fn->locals
        //if (!fn->locals)
        fn->locals = locals;

        // During parsing we may call this before the function is fully marked as
        // a definition. Force offset assignment so inline asm can use (%rbp)-relative
        // slots for locals/params.
        bool saved_def = fn->is_definition;
        fn->is_definition = true;
        fn->is_function = true;

        Type dummy_ty = {0};
        if (!fn->ty)
            fn->ty = &dummy_ty;

        assign_lvar_offsets(fn);
        fn->is_definition = saved_def;
        return;
    }

    // Fallback: assign offsets using a synthetic function object.
    Obj dummy_fn = {0};
    Type dummy_ty = {0};
    dummy_fn.is_function = true;
    dummy_fn.is_definition = true;
    dummy_fn.locals = locals;
    dummy_fn.ty = &dummy_ty;
    assign_lvar_offsets(&dummy_fn);
}



// update register following the size
char *update_register_size(char *reg, int size)
{
    if (!reg)
        error("%s:%d: error: in update_register_size : reg is null!", __FILE__, __LINE__);
    if (!strncmp(reg, "%rax", 4) || !strncmp(reg, "%eax", 4) || !strncmp(reg, "%ax", 3) || !strncmp(reg, "%ah", 3) || !strncmp(reg, "%al", 3))
        return reg_ax(size);
    else if (!strncmp(reg, "%rbx", 4) || !strncmp(reg, "%ebx", 4) || !strncmp(reg, "%bx", 3) || !strncmp(reg, "%bh", 3) || !strncmp(reg, "%bl", 3))
        return reg_bx(size);
    else if (!strncmp(reg, "%rcx", 4) || !strncmp(reg, "%ecx", 4) || !strncmp(reg, "%cx", 3) || !strncmp(reg, "%ch", 3) || !strncmp(reg, "%cl", 3))
        return reg_cx(size);
    else if (!strncmp(reg, "%rdx", 4) || !strncmp(reg, "%edx", 4) || !strncmp(reg, "%dx", 3) || !strncmp(reg, "%dh", 3) || !strncmp(reg, "%dl", 3))
        return reg_dx(size);
    else if (!strncmp(reg, "%rdi", 4) || !strncmp(reg, "%edi", 4) || !strncmp(reg, "%di", 3) || !strncmp(reg, "%dil", 4))
        return reg_di(size);       
    else if (!strncmp(reg, "%rsi", 4) || !strncmp(reg, "%esi", 4) || !strncmp(reg, "%si", 3) || !strncmp(reg, "%sil", 4))
        return reg_si(size);       
    else if (!strncmp(reg, "%r8", 3))
        return reg_r8w(size);
    else if (!strncmp(reg, "%r9", 3))
        return reg_r9w(size);
    else if (!strncmp(reg, "%r10", 4))
        return reg_r10w(size);
    else if (!strncmp(reg, "%r11", 4))
        return reg_r11w(size);
    else if (!strncmp(reg, "%r12", 4))
        return reg_r12w(size);
    else if (!strncmp(reg, "%r13", 4))
        return reg_r13w(size);
    else if (!strncmp(reg, "%r14", 4))
        return reg_r14w(size);
    else if (!strncmp(reg, "%r15", 4))
        return reg_r15w(size);
    else
        return reg;
}


//returns the index corresponding to the letter received in parameter
int retrieve_output_index_from_letter(char letter)
{
    for (int i = 0; i < nbOutput; i++)
    {
        if (asmExt->output[i]->letter == letter)
            return asmExt->output[i]->index;
    }

    return -1;
}

//retrieve the variable number string like M0, %1, %2...
char * retrieveVariableNumber(int index) 
{
    
    if (index > 8)
        error("%s:%d: error: in retrieveVariableNumber : index %d not managed yet!", __FILE__, __LINE__, index);
    char *tmp;        
    char *variableNumberStr = calloc(20, sizeof(char));
    char *indexstr = calloc(20, sizeof(char));
    strncat(variableNumberStr, "%", 2);
    int length = snprintf(indexstr, 20, "%d", index);
    if (length < 0)
        error("%s:%d : error: in retrieveVariableNumber : error during snprintf function! index=%d length=%d", __FILE__, __LINE__, index, length);
    strncat(variableNumberStr, indexstr, strlen(indexstr));
    tmp = variableNumberStr;
    return tmp;
}


//generate the input for the output when + is a prefix for output
char *generate_input_for_output() {
    char *tmp = calloc(1, sizeof(char) * 500);

    for (int i = 0; i < nbOutput; i++)
    {      
  //not sure yet about in which case exactly we need to generate the input for the output
        if (asmExt->output[i]->letter == 'm' && !asmExt->output[i]->isAddress)
            continue;
        if ((asmExt->output[i]->isAddress || (asmExt->output[i]->offset != 0 && !strncmp(asmExt->output[i]->prefix, "+", 2)))) {
            if (asmExt->output[i]->isVariable && !asmExt->output[i]->isAddress)
                {
                    strncat(tmp, "\n", 3);
                    strncat(tmp, opcode(asmExt->output[i]->size), strlen(opcode(asmExt->output[i]->size)));
                    strncat(tmp, load_variable(asmExt->output[i]->offset), strlen(load_variable(asmExt->output[i]->offset)));
                    strncat(tmp, ", ", 3);
                    strncat(tmp, asmExt->output[i]->reg, strlen(asmExt->output[i]->reg));
                    strncat(tmp, ";\n", 3);             

                }else if (asmExt->output[i]->isAddress ) {
                    strncat(tmp, "\n", 3);
                    strncat(tmp, opcode(8), 8);
                    int off = asmExt->output[i]->isArray ? asmExt->output[i]->offsetArray : asmExt->output[i]->offset;
                    strncat(tmp, load_variable(off), strlen(load_variable(off)));
                    strncat(tmp, ", ", 3);
                    strncat(tmp, asmExt->output[i]->reg64, strlen(asmExt->output[i]->reg64));
                    strncat(tmp, ";\n", 3);                       
                    if (asmExt->output[i]->isArray && asmExt->output[i]->offset) {
                        char off_str[16];
                        snprintf(off_str, sizeof(off_str), "%d", asmExt->output[i]->offset);
                        strncat(tmp, "  addq $", 11);
                        strncat(tmp, off_str, strlen(off_str));
                        strncat(tmp, ", ", 3);
                        strncat(tmp, asmExt->output[i]->reg64, strlen(asmExt->output[i]->reg64));
                        strncat(tmp, ";\n", 3);
                    }
                }       
        }

    }
    return tmp;
}



// Returns the high 8-bit register name for the given 64-bit register
static char *register_higher(char *reg) {
    if (!reg) return NULL;
    if (!strncmp(reg, "%rax", 4) || !strncmp(reg, "%eax", 4) || !strncmp(reg, "%ax", 3)) return "%ah";
    if (!strncmp(reg, "%rbx", 4) || !strncmp(reg, "%ebx", 4) || !strncmp(reg, "%bx", 3)) return "%bh";
    if (!strncmp(reg, "%rcx", 4) || !strncmp(reg, "%ecx", 4) || !strncmp(reg, "%cx", 3)) return "%ch";
    if (!strncmp(reg, "%rdx", 4) || !strncmp(reg, "%edx", 4) || !strncmp(reg, "%dx", 3)) return "%dh";
    // %r10-%r11, %rdi, %rsi do not have high 8-bit registers in x86-64
    if (!strncmp(reg, "%r10", 3) || !strncmp(reg, "%r11", 3) ||
        !strncmp(reg, "%rdi", 4) || !strncmp(reg, "%rsi", 4)) return NULL;
    return NULL;
}

// Returns the low 8-bit register name for the given 64-bit register
static char *register_lower(char *reg) {
    if (!reg) return NULL;
    if (!strncmp(reg, "%rax", 4) || !strncmp(reg, "%eax", 4) || !strncmp(reg, "%ax", 3)) return "%al";
    if (!strncmp(reg, "%rbx", 4) || !strncmp(reg, "%ebx", 4) || !strncmp(reg, "%bx", 3)) return "%bl";
    if (!strncmp(reg, "%rcx", 4) || !strncmp(reg, "%ecx", 4) || !strncmp(reg, "%cx", 3)) return "%cl";
    if (!strncmp(reg, "%rdx", 4) || !strncmp(reg, "%edx", 4) || !strncmp(reg, "%dx", 3)) return "%dl";
    if (!strncmp(reg, "%r8", 3)) return "%r8b";
    if (!strncmp(reg, "%r9", 3)) return "%r9b";
    if (!strncmp(reg, "%r10", 4)) return "%r10b";
    if (!strncmp(reg, "%r11", 4)) return "%r11b";
    if (!strncmp(reg, "%r12", 4)) return "%r12b";
    if (!strncmp(reg, "%r13", 4)) return "%r13b";
    if (!strncmp(reg, "%r14", 4)) return "%r14b";
    if (!strncmp(reg, "%r15", 4)) return "%r15b";
    if (!strncmp(reg, "%rdi", 4) || !strncmp(reg, "%edi", 4)) return "%dil";
    if (!strncmp(reg, "%rsi", 4) || !strncmp(reg, "%esi", 4)) return "%sil";
    return NULL;
}

// Returns the 16-bit register name for the given 64-bit register
static char *register_word(char *reg) {
    if (!reg) return NULL;

    if (!strncmp(reg, "%rax", 4) || !strncmp(reg, "%eax", 4)) return "%ax";
    if (!strncmp(reg, "%rbx", 4) || !strncmp(reg, "%ebx", 4)) return "%bx";
    if (!strncmp(reg, "%rcx", 4) || !strncmp(reg, "%ecx", 4)) return "%cx";
    if (!strncmp(reg, "%rdx", 4) || !strncmp(reg, "%edx", 4)) return "%dx";
    if (!strncmp(reg, "%rsi", 4) || !strncmp(reg, "%esi", 4)) return "%si";
    if (!strncmp(reg, "%rdi", 4) || !strncmp(reg, "%edi", 4)) return "%di";
    if (!strncmp(reg, "%r8", 3)) return "%r8w";
    if (!strncmp(reg, "%r9", 3)) return "%r9w";
    if (!strncmp(reg, "%r10", 4)) return "%r10w";
    if (!strncmp(reg, "%r11", 4)) return "%r11w";
    if (!strncmp(reg, "%r12", 4)) return "%r12w";
    if (!strncmp(reg, "%r13", 4)) return "%r13w";
    if (!strncmp(reg, "%r14", 4)) return "%r14w";
    if (!strncmp(reg, "%r15", 4)) return "%r15w";
    if (!strncmp(reg, "%rbp", 5) || !strncmp(reg, "%ebp", 4)) return "%bp";
    if (!strncmp(reg, "%rsp", 5) || !strncmp(reg, "%esp", 4)) return "%sp";

    if (!strncmp(reg, "%r8", 3)) return "%r8w";
    if (!strncmp(reg, "%r9", 3)) return "%r9w";
    if (!strncmp(reg, "%r10", 4)) return "%r10w";
    if (!strncmp(reg, "%r11", 4)) return "%r11w";
    if (!strncmp(reg, "%r12", 4)) return "%r12w";
    if (!strncmp(reg, "%r13", 4)) return "%r13w";
    if (!strncmp(reg, "%r14", 4)) return "%r14w";
    if (!strncmp(reg, "%r15", 4)) return "%r15w";

    return NULL;
}
