上一节中,我们已经实现了全局变量的声明、赋值和计算,本节中我们将会实现计较运算符的计算。
==, !=, <, >, <=, >=
修改词法分析
首先增加新的单词类型
// 单词类型
enum
{
T_EOF,
T_ADD, T_SUB, T_MUL, T_DIV, T_MOD, T_EQ, T_NE, T_LT, T_GT, T_LE, T_GE,
T_INT, T_SEM, T_PRINT, T_EQU, T_IDENT, T_KEYINT
};
我们必须区分 = 和 ==,< 和 <=,> 和 >=。因此我们将需要从输入中读取一个额外的字符,然后在不需要时将其放回原处,修改scan()代码如下:
// 扫描并返回在输入中找到的下一个单词。
// 如果标记有效则返回 1,如果没有标记则返回 0
int scan(struct token *t)
{
int c, tokentype;
c = skip_getchr();
switch (c)
{
case EOF: t->token = T_EOF; return 0;
case '+': t->token = T_ADD; break;
case '-': t->token = T_SUB; break;
case '*': t->token = T_MUL; break;
case '/': t->token = T_DIV; break;
case '%': t->token = T_MOD; break;
case ';': t->token = T_SEM; break;
case '=':
if((c = get_nextchr()) == '=')
{
t->token = T_EQ;
}
else
{
t->token = T_EQU;
put_backchr(c);
}
break;
case '!': if((c = get_nextchr()) == '=')
{
t->token = T_NE;
}
else
{
fprintf(stderr, "Unrecognised character:%c on line %d\n", c, Line);
exit(1);
}
break;
case '<': if((c = get_nextchr()) == '=')
{
t->token = T_LE;
}
else
{
t->token = T_LT;
put_backchr(c);
}
break;
case '>': if((c = get_nextchr()) == '=')
{
t->token = T_GE;
}
else
{
t->token = T_GT;
put_backchr(c);
}
break;
default: if (isdigit(c))
{
t->intvalue = scan_int(c);
t->token = T_INT;
break;
}
else if(isalpha(c) || '_' == c)
{
scan_ident(c, Text, TEXTLEN);
if (tokentype = match_keyword(Text))
{
t->token = tokentype;
break;
}
t->token = T_IDENT;
break;
}
printf("Unrecognised character %c on line %d\n", c, Line);
exit(1);
}
return 1;
}
修改语法分析
增加AST节点类型
// AST节点类型
enum
{
A_ADD = 1, A_SUB, A_MUL, A_DIV, A_MOD, A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE,
A_INT, A_IDENT, A_ASSIGN, A_LVIDENT
};
修改单词到AST节点的映射
// 将单词转换为AST操作
int token_op(int tokentype)
{
if(tokentype > T_EOF && tokentype < T_INT)
{
return tokentype;
}
fprintf(stderr, "unknown token in token_op() on line %d\n", Line);
exit(1);
}
注意到,我们简化了映射函数操作,为此,我们在前面的单词类型和AST节点类型要按一定顺序排列
修改AST节点的运算优先级
// 每个AST节点的运算符优先级
int OpPrec[] = {0, 10, 10, 20, 20, 20, 30, 30, 40, 40, 40, 40};
修改代码生成
在代码生成函数code_generator()
中加入六种比较运算
// 给定AST,生成汇编代码,返回值为结果所在寄存器号
int code_generator(struct ASTnode *n, int reg)
{
int leftreg, rightreg;
if (n->left) leftreg = code_generator(n->left, -1);
if (n->right) rightreg = code_generator(n->right, leftreg);
switch (n->op)
{
case A_ADD: return (arm_add(leftreg, rightreg));
case A_SUB: return (arm_sub(leftreg, rightreg));
case A_MUL: return (arm_mul(leftreg, rightreg));
case A_DIV: return (arm_div(leftreg, rightreg));
case A_MOD: return (arm_mod(leftreg, rightreg));
case A_EQ: return (arm_equal(leftreg, rightreg));
case A_NE: return (arm_notequal(leftreg, rightreg));
case A_LT: return (arm_lessthan(leftreg, rightreg));
case A_GT: return (arm_greaterthan(leftreg, rightreg));
case A_LE: return (arm_lessequal(leftreg, rightreg));
case A_GE: return (arm_greaterequal(leftreg, rightreg));
case A_INT: return (arm_load_int(n->v.intvalue));
case A_IDENT: return (arm_load_global(n->v.id));
case A_LVIDENT:return (arm_stor_global(reg, n->v.id));
case A_ASSIGN: return rightreg;
default: fprintf(stderr, "Unknown AST operator %d\n", n->op);
exit(1);
}
}
修改汇编代码
ARM比较需要先调用CMP Rm Rn
指令,进行Rm-Rn,并修改CPSR。然后我们调用对应条件的MOV{S} Rd, #<imm8>
指令赋值1,再调用相反条件的MOV指令赋值0,最后对赋值寄存器进行字节到字的扩展,因为有条件MOV{S}
只能赋值8位立即数。
CPSR(ARM状态寄存器)的最后四位分别是N、Z、C、V。
符号 | 名称 | 作用 |
---|---|---|
N | 符号标志 | N=1表示运算结果为负数,N=0表示运算结果为整数 |
Z | 全0标志 | Z=1则表示运算结果为0,否则Z=0 |
C | 进位标志 | 加法有进位时C=1(加法运算是数据溢出),无进位时C=0;减法有借位时C=0,无借位时C=1 |
V | 数据溢出标志 | 加法运算结果有溢出是V=1,否则V=0 |
S条件如下:
助记符后缀 | 标志 | 含义 | 符号 |
---|---|---|---|
EQ | Z置位 | 相等 | = |
NE | Z清零 | 不相等 | ≠ |
LT | N不等于V | 带符号数小于 | < |
GT | Z清零且(N不等于V) | 带符号数大于 | > |
LE | Z置位或(N不等于V) | 带符号数小于或等于 | ≤ |
GE | N等于V | 带符号数大于或等于 | ≥ |
// 比较函数:第一个寄存器减去第二个寄存器并修改CPSR
int arm_compare(int r1, int r2)
{
fprintf(Outfile, "\tcmp\tr%d, r%d\n", r1, r2);
}
// '=='汇编函数
int arm_equal(int r1, int r2)
{
arm_compare(r1, r2);
fprintf(Outfile, "\tmoveq\tr%d, #1\n", r1);
fprintf(Outfile, "\tmovne\tr%d, #0\n", r1);
fprintf(Outfile, "\tuxtb\tr%d, r%d\n", r1, r1);
arm_free_register(r2);
return r1;
}
// '!='汇编函数
int arm_notequal(int r1, int r2)
{
arm_compare(r1, r2);
fprintf(Outfile, "\tmovne\tr%d, #1\n", r1);
fprintf(Outfile, "\tmoveq\tr%d, #0\n", r1);
fprintf(Outfile, "\tuxtb\tr%d, r%d\n", r1, r1);
arm_free_register(r2);
return r1;
}
// '<'汇编函数
int arm_lessthan(int r1, int r2)
{
arm_compare(r1, r2);
fprintf(Outfile, "\tmovlt\tr%d, #1\n", r1);
fprintf(Outfile, "\tmovge\tr%d, #0\n", r1);
fprintf(Outfile, "\tuxtb\tr%d, r%d\n", r1, r1);
arm_free_register(r2);
return r1;
}
// '>'汇编函数
int arm_greaterthan(int r1, int r2)
{
arm_compare(r1, r2);
fprintf(Outfile, "\tmovgt\tr%d, #1\n", r1);
fprintf(Outfile, "\tmovle\tr%d, #0\n", r1);
fprintf(Outfile, "\tuxtb\tr%d, r%d\n", r1, r1);
arm_free_register(r2);
return r1;
}
// '<='汇编函数
int arm_lessequal(int r1, int r2)
{
arm_compare(r1, r2);
fprintf(Outfile, "\tmovle\tr%d, #1\n", r1);
fprintf(Outfile, "\tmovgt\tr%d, #0\n", r1);
fprintf(Outfile, "\tuxtb\tr%d, r%d\n", r1, r1);
arm_free_register(r2);
return r1;
}
// '>='汇编函数
int arm_greaterequal(int r1, int r2)
{
arm_compare(r1, r2);
fprintf(Outfile, "\tmovge\tr%d, #1\n", r1);
fprintf(Outfile, "\tmovlt\tr%d, #0\n", r1);
fprintf(Outfile, "\tuxtb\tr%d, r%d\n", r1, r1);
arm_free_register(r2);
return r1;
}
结果测试
输入:
int x;
x = 1 < 1; print x;
x = 1 < 2; print x;
x = 2 < 1; print x;
x = 3 <= 3; print x;
x = 3 <= 4; print x;
x = 4 <= 3; print x;
x = 4 != 5; print x;
x = 5 != 5; print x;
x = 6 == 6; print x;
x = 6 == 7; print x;
x = 7 > 7; print x;
x = 6 > 7; print x;
x = 7 > 6; print x;
x = 8 >= 8; print x;
x = 8 >= 9; print x;
x = 9 >= 8; print x;
输出(out.s):
.text
.global __aeabi_idiv
.section .rodata
.align 2
.LC0:
.ascii "%d\012\000"
.text
.align 2
.global main
.type main, %function
main:
push {fp, lr}
add fp, sp, #4
.text
.comm x,4,4
mov r4, #1
mov r5, #1
cmp r4, r5
movlt r4, #1
movge r4, #0
uxtb r4, r4
ldr r3, .L2+0
str r4, [r3]
ldr r3, .L2+0
ldr r4, [r3]
mov r1, r4
ldr r0, .L3
bl printf
mov r4, #1
mov r5, #2
cmp r4, r5
movlt r4, #1
movge r4, #0
uxtb r4, r4
ldr r3, .L2+0
str r4, [r3]
ldr r3, .L2+0
ldr r4, [r3]
mov r1, r4
ldr r0, .L3
bl printf
mov r4, #2
mov r5, #1
cmp r4, r5
movlt r4, #1
movge r4, #0
uxtb r4, r4
ldr r3, .L2+0
str r4, [r3]
ldr r3, .L2+0
ldr r4, [r3]
mov r1, r4
ldr r0, .L3
bl printf
mov r4, #3
mov r5, #3
cmp r4, r5
movle r4, #1
movgt r4, #0
uxtb r4, r4
ldr r3, .L2+0
str r4, [r3]
ldr r3, .L2+0
ldr r4, [r3]
mov r1, r4
ldr r0, .L3
bl printf
mov r4, #3
mov r5, #4
cmp r4, r5
movle r4, #1
movgt r4, #0
uxtb r4, r4
ldr r3, .L2+0
str r4, [r3]
ldr r3, .L2+0
ldr r4, [r3]
mov r1, r4
ldr r0, .L3
bl printf
mov r4, #4
mov r5, #3
cmp r4, r5
movle r4, #1
movgt r4, #0
uxtb r4, r4
ldr r3, .L2+0
str r4, [r3]
ldr r3, .L2+0
ldr r4, [r3]
mov r1, r4
ldr r0, .L3
bl printf
mov r4, #4
mov r5, #5
cmp r4, r5
movne r4, #1
moveq r4, #0
uxtb r4, r4
ldr r3, .L2+0
str r4, [r3]
ldr r3, .L2+0
ldr r4, [r3]
mov r1, r4
ldr r0, .L3
bl printf
mov r4, #5
mov r5, #5
cmp r4, r5
movne r4, #1
moveq r4, #0
uxtb r4, r4
ldr r3, .L2+0
str r4, [r3]
ldr r3, .L2+0
ldr r4, [r3]
mov r1, r4
ldr r0, .L3
bl printf
mov r4, #6
mov r5, #6
cmp r4, r5
moveq r4, #1
movne r4, #0
uxtb r4, r4
ldr r3, .L2+0
str r4, [r3]
ldr r3, .L2+0
ldr r4, [r3]
mov r1, r4
ldr r0, .L3
bl printf
mov r4, #6
mov r5, #7
cmp r4, r5
moveq r4, #1
movne r4, #0
uxtb r4, r4
ldr r3, .L2+0
str r4, [r3]
ldr r3, .L2+0
ldr r4, [r3]
mov r1, r4
ldr r0, .L3
bl printf
mov r4, #7
mov r5, #7
cmp r4, r5
movgt r4, #1
movle r4, #0
uxtb r4, r4
ldr r3, .L2+0
str r4, [r3]
ldr r3, .L2+0
ldr r4, [r3]
mov r1, r4
ldr r0, .L3
bl printf
mov r4, #6
mov r5, #7
cmp r4, r5
movgt r4, #1
movle r4, #0
uxtb r4, r4
ldr r3, .L2+0
str r4, [r3]
ldr r3, .L2+0
ldr r4, [r3]
mov r1, r4
ldr r0, .L3
bl printf
mov r4, #7
mov r5, #6
cmp r4, r5
movgt r4, #1
movle r4, #0
uxtb r4, r4
ldr r3, .L2+0
str r4, [r3]
ldr r3, .L2+0
ldr r4, [r3]
mov r1, r4
ldr r0, .L3
bl printf
mov r4, #8
mov r5, #8
cmp r4, r5
movge r4, #1
movlt r4, #0
uxtb r4, r4
ldr r3, .L2+0
str r4, [r3]
ldr r3, .L2+0
ldr r4, [r3]
mov r1, r4
ldr r0, .L3
bl printf
mov r4, #8
mov r5, #9
cmp r4, r5
movge r4, #1
movlt r4, #0
uxtb r4, r4
ldr r3, .L2+0
str r4, [r3]
ldr r3, .L2+0
ldr r4, [r3]
mov r1, r4
ldr r0, .L3
bl printf
mov r4, #9
mov r5, #8
cmp r4, r5
movge r4, #1
movlt r4, #0
uxtb r4, r4
ldr r3, .L2+0
str r4, [r3]
ldr r3, .L2+0
ldr r4, [r3]
mov r1, r4
ldr r0, .L3
bl printf
mov r3, #0
mov r0, r3
pop {fp, pc}
.L3:
.word .LC0
.size main, .-main
.L2:
.word x
输出(out):
0
1
0
1
1
0
1
0
1
0
0
0
1
1
0
1
总结
在这一节中,我们实现了六种比较运算符的运算,在下一节中,我们将利用这些比较运算符实现IF语句。