---
# System prepended metadata

title: NTU Compiler Technology Project 4
tags: [NTU_CT, NTU]

---

# NTU Compiler Technology Project 4
###### tags: `NTU_CT` `NTU` `Compiler Techonology of Programming Language` `Code Generation`

[TOC]

## How to run?
First, put your testing file and `main.S` to the folder same as `parser` file
```bash
$ make
$ ./parser [testing file].c
$ aarch64-linux-gnu-gcc -static -O0 main.S
$ qemu-aarch64-static ./a.out
```
Or, you can put the `run.sh` and `main.S` in the same directory and run
```bash
$ ./run.sh [your parser] [the C file]
$ qemu-aarch64-static ./a.out
```
Note that you must change your test file's `main()` to <font color="FF0000">`MAIN()`</font>

## Implementation
Just show the mainly implementation concept
### Assignment statements
```clike
void genAssignStmt(AST_NODE *assignNode)
{
    AST_NODE *it = assignNode;
    unpack(it, id, relop_expr);
    REG reg = genExprRelated(relop_expr);
    genVariableAssign(id, reg);
    freeReg(reg);
}
...
void genVariableAssign(AST_NODE *idNode, REG val)
{
    assert ( idNode->nodeType == IDENTIFIER_NODE );
    assert ( getIDEntry(idNode) != NULL );
    assert ( getIDAttr(idNode)->attributeKind == VARIABLE_ATTRIBUTE );
    TypeDescriptor* typeDescriptor = getIDTypeDescriptor(idNode);

    if(getIDKind(idNode) == ARRAY_ID){
        genArrayAssign(idNode, val);
        return;
    }else{
        REG addr;
        if(getIDGlobal(idNode)){
            addr = getReg();
            fprintf(output, "ldr x%d, =_g_%s\n", addr, getIDName(idNode));
        }else{
            int offset = getIDOffset(idNode);
            addr = genIntLiteral(offset);
            fprintf(output, "sub x%d, x29, x%d\n", addr, addr);
            fprintf(stderr, "Var assign name: %s, offset: %d\n", getIDName(idNode), offset);
        }

        if(idNode->dataType == INT_TYPE){
            fprintf(output, "str w%d, [x%d, #0]\n", val, addr);
        }else{
            fprintf(output, "str s%d, [x%d, #0]\n", val, addr);
        }

        freeReg(addr);
    }
    return;
}
```
### Arithmetic expressions
```clike
REG genRelopExpr(AST_NODE *exprNode)
{
    AST_NODE* it = exprNode->child;

    if (isConstExpr(exprNode))
        return genConstValue(exprNode);

    if (getExprKind(exprNode) == BINARY_OPERATION) {
        unpack(it, lvalue, rvalue);

        REG LReg = genExprRelated(lvalue);
        REG RReg = genExprRelated(rvalue);

        if(lvalue->dataType == INT_TYPE && rvalue->dataType == INT_TYPE){
            switch(getExprOp(exprNode)){
                case BINARY_OP_ADD:
                    fprintf(output, "add w%d, w%d, w%d\n", LReg, LReg, RReg);
                    break;
                case BINARY_OP_SUB:
                    fprintf(output, "sub w%d, w%d, w%d\n", LReg, LReg, RReg);
                    break;
                case BINARY_OP_MUL:
                    fprintf(output, "mul w%d, w%d, w%d\n", LReg, LReg, RReg);
                    break;
                case BINARY_OP_DIV:
                    fprintf(output, "sdiv w%d, w%d, w%d\n", LReg, LReg, RReg);
                    break;

                case BINARY_OP_EQ:
                    fprintf(output, "cmp w%d, w%d\n", LReg, RReg);
                    fprintf(output, "cset w%d, eq\n", LReg);
                    break;
                case BINARY_OP_GE:
                    fprintf(output, "cmp w%d, w%d\n", LReg, RReg);
                    fprintf(output, "cset w%d, ge\n", LReg);
                    break;
                case BINARY_OP_LE:
                    fprintf(output, "cmp w%d, w%d\n", LReg, RReg);
                    fprintf(output, "cset w%d, le\n", LReg);
                    break;
                case BINARY_OP_NE:
                    fprintf(output, "cmp w%d, w%d\n", LReg, RReg);
                    fprintf(output, "cset w%d, ne\n", LReg);
                    break;
                case BINARY_OP_GT:
                    fprintf(output, "cmp w%d, w%d\n", LReg, RReg);
                    fprintf(output, "cset w%d, gt\n", LReg);
                    break;
                case BINARY_OP_LT:
                    fprintf(output, "cmp w%d, w%d\n", LReg, RReg);
                    fprintf(output, "cset w%d, lt\n", LReg);
                    break;

                case BINARY_OP_AND:
                    fprintf(output, "cmp w%d, #0\n", LReg);
                    fprintf(output, "cset w%d, ne\n", LReg);
                    fprintf(output, "cmp w%d, #0\n", RReg);
                    fprintf(output, "cset w%d, ne\n", RReg);
                    fprintf(output, "and w%d, w%d, w%d\n", LReg, LReg, RReg);
                    break;
                case BINARY_OP_OR:
                    fprintf(output, "cmp w%d, #0\n", LReg);
                    fprintf(output, "cset w%d, ne\n", LReg);
                    fprintf(output, "cmp w%d, #0\n", RReg);
                    fprintf(output, "cset w%d, ne\n", RReg);
                    fprintf(output, "orr w%d, w%d, w%d\n", LReg, LReg, RReg);
                    break;
            }
        }else{
            // Float expr
            if(lvalue->dataType == INT_TYPE)
                fprintf(output, "scvtf s%d, w%d\n", LReg, LReg);

            if(rvalue->dataType == INT_TYPE)
                fprintf(output, "scvtf s%d, w%d\n", RReg, RReg);

            switch(getExprOp(exprNode)){
                case BINARY_OP_ADD:
                    fprintf(output, "fadd s%d, s%d, s%d\n", LReg, LReg, RReg);
                    break;
                case BINARY_OP_SUB:
                    fprintf(output, "fsub s%d, s%d, s%d\n", LReg, LReg, RReg);
                    break;
                case BINARY_OP_MUL:
                    fprintf(output, "fmul s%d, s%d, s%d\n", LReg, LReg, RReg);
                    break;
                case BINARY_OP_DIV:
                    fprintf(output, "fdiv s%d, s%d, s%d\n", LReg, LReg, RReg);
                    break;
                case BINARY_OP_EQ:
                    fprintf(output, "fcmp s%d, s%d\n", LReg, RReg);
                    fprintf(output, "cset w%d, eq\n", LReg);
                    break;
                case BINARY_OP_GE:
                    fprintf(output, "fcmp s%d, s%d\n", LReg, RReg);
                    fprintf(output, "cset w%d, ge\n", LReg);
                    break;
                case BINARY_OP_LE:
                    fprintf(output, "fcmp s%d, s%d\n", LReg, RReg);
                    fprintf(output, "cset w%d, le\n", LReg);
                    break;
                case BINARY_OP_NE:
                    fprintf(output, "fcmp s%d, s%d\n", LReg, RReg);
                    fprintf(output, "cset w%d, ne\n", LReg);
                    break;
                case BINARY_OP_GT:
                    fprintf(output, "fcmp s%d, s%d\n", LReg, RReg);
                    fprintf(output, "cset w%d, gt\n", LReg);
                    break;
                case BINARY_OP_LT:
                    fprintf(output, "fcmp s%d, s%d\n", LReg, RReg);
                    fprintf(output, "cset w%d, lt\n", LReg);
                    break;
                case BINARY_OP_AND:
                    fprintf(output, "fcmp s%d, #0\n", LReg);
                    fprintf(output, "cset w%d, ne\n", LReg);
                    fprintf(output, "fcmp s%d, #0\n", RReg);
                    fprintf(output, "cset w%d, ne\n", RReg);
                    fprintf(output, "orr w%d, w%d, w%d\n", LReg, LReg, RReg);
                    break;
                case BINARY_OP_OR:
                    fprintf(output, "fcmp s%d, #0\n", LReg);
                    fprintf(output, "cset w%d, ne\n", LReg);
                    fprintf(output, "fcmp s%d, #0\n", RReg);
                    fprintf(output, "cset w%d, ne\n", RReg);
                    fprintf(output, "orr w%d, w%d, w%d\n", LReg, LReg, RReg);
                    break;
            }
        }
        freeReg(RReg);
        return LReg;
    }else{
        // Unary operation
 
        unpack(it, value);
        REG reg = genExprRelated(value);

        if(value->dataType == INT_TYPE){
            switch(getExprOp(exprNode)){
                case UNARY_OP_POSITIVE:
                    break;
                case UNARY_OP_NEGATIVE:
                    fprintf(output, "neg w%d, w%d", reg, reg);
                    break;
                case UNARY_OP_LOGICAL_NEGATION:
                    fprintf(output, "cmp w%d, #0\n", reg);
                    fprintf(output, "cset w%d, eq\n", reg);
                    break;
            }
        }else{
            switch(getExprOp(exprNode)){
                case UNARY_OP_POSITIVE:
                    break;
                case UNARY_OP_NEGATIVE:
                    fprintf(output, "fneg s%d, s%d", reg, reg);
                    break;
                case UNARY_OP_LOGICAL_NEGATION:
                    fprintf(output, "fcmp s%d, #0\n", reg);
                    fprintf(output, "cset w%d, eq\n", reg);
                    break;
            }
        }
        return reg;
    }
}
```
### Control statements: while, if-then-else
```clike
void genWhile(AST_NODE *whileNode)
{
    AST_NODE *it = whileNode;
    unpack(it, test, stmt);
    int while_n = const_n++;

    fprintf(output, "_WHILE_%d:\n", while_n);
    if (test->nodeType == STMT_NODE && getStmtKind(test) == ASSIGN_STMT){
        genAssignStmt(test);
        test = test->child;
    }
    REG reg = genExprRelated(test);
    if (test->dataType == FLOAT_TYPE)
        fprintf(output, "fcvtzs w%d, s%d\n", reg, reg);

    fprintf(output, "cmp w%d, #0\n", reg);
    freeReg(reg);
    fprintf(output, "beq _WHILE_END_%d\n", while_n);
    genStmt(stmt);
    fprintf(output, "b _WHILE_%d\n", while_n);
    fprintf(output, "_WHILE_END_%d:\n", while_n);
}
...
void genIf(AST_NODE *ifNode)
{
    AST_NODE *it = ifNode;
    unpack(it, test, stmt, elseStmt);
    int if_n = const_n++;
    
    fprintf(output, "_IF_%d:\n", if_n);
    if (test->nodeType == STMT_NODE && getStmtKind(test) == ASSIGN_STMT){
        genAssignStmt(test);
        test = test->child;
    }
    REG reg = genExprRelated(test);
    if (test->dataType == FLOAT_TYPE)
        fprintf(output, "fcvtzs w%d, s%d\n", reg, reg);

    fprintf(output, "cmp w%d, #0\n", reg);
    freeReg(reg);
    fprintf(output, "beq _ELSE_%d\n", if_n);
    genStmt(stmt);
    fprintf(output, "b _END_IF_%d\n", if_n);
   

    fprintf(output, "_ELSE_%d:\n", if_n);
    //if (elseStmt->nodeType != NUL_NODE)
    genStmt(elseStmt);
    fprintf(output, "_END_IF_%d:\n", if_n);
}
```
### Parameterless procedure calls
```clike
void genFunctionCall(AST_NODE *functionCallNode)
{
    AST_NODE *it = functionCallNode;
    unpack(it, id, param);

    char *name = getIDName(id);
    if (!strcmp(name, "write")){
        genWrite(functionCallNode);
    } else if (!strcmp(name, "read")){
        fprintf(output, "bl _read_int\n");
    } else if (!strcmp(name, "fread")){
        fprintf(output, "bl _read_float\n");
    } else {
        fprintf(output, "bl _start_%s\n", name);
    }
}
```
### Read and Write I/O calls
```clike
void genWrite(AST_NODE *functionCallNode){
    AST_NODE *it = functionCallNode;
    unpack(it, id, paramList);
    AST_NODE *param = paramList->child;
    
    REG reg = genExprRelated(param);
    switch(param->dataType){
        case INT_TYPE:
            fprintf(output, "mov w0, w%d\n", reg);
            fprintf(output, "bl _write_int\n");
            break;
        case FLOAT_TYPE:
            fprintf(output, "fmov s0, s%d\n", reg);
            fprintf(output, "bl _write_float\n");
            break;
        case CONST_STRING_TYPE:
            fprintf(output, "mov x0, x%d\n", reg);
            fprintf(output, "bl _write_str\n");
            break;
    }
    freeReg(reg);
}
```

## Experience result
* **assign.c**
![](https://imgur.com/T28oUhu.png)
* **control.c**
![](https://imgur.com/TlyDZzD.png)
* **expr.c**
![](https://imgur.com/9z27ifv.png)
* **func.c**
![](https://imgur.com/1AWaiGC.png)
* **hello.c**
![](https://imgur.com/g9NQuMR.png)
* **io.c**
![](https://imgur.com/Y3XxVPa.png)