NTU Compiler Technology Project 4

NTU Compiler Technology Project 4

tags: NTU_CT NTU Compiler Techonology of Programming Language Code Generation

How to run?

First, put your testing file and main.S to the folder same as parser file

1
2
3
4
$ 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

1
2
$ ./run.sh [your parser] [the C file]
$ qemu-aarch64-static ./a.out

Note that you must change your test file’s main() to `MAIN()`

Implementation

Just show the mainly implementation concept

Assignment statements

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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
  • control.c
  • expr.c
  • func.c
  • hello.c
  • io.c