stage-2
郭高旭 ggx21@mails.tsinghua.edu.cn 2021010803
实验内容
增加变量,实现对变量的声明和赋值。同时增加变量相关的语义检查,不能重复声明变量,不能使用未声明的变量
前端
-
lex&parser
此部分内容框架已经提供,通过这里表达出ast树
-
语义分析
修改namer中
visitDeclaration
,visitAssignment
,visitIdentifier
三个函数-
visitDeclaration
- 使用
ctx.lookup
来查找是否已经声明了具有相同名称的变量。 - 如果有,报错。如果没有,创建一个新的
VarSymbol
,并使用ctx.declare
将其放入当前作用域。 - 设置
decl
的 ‘symbol’ 属性。 - 如果存在初始值,对其进行访问。
- 使用
-
visitIdentifier
- 使用
ctx.lookup
来查找是否已经声明了具有相同名称的变量。 - 如果没有,报错。否则将该标识符同样标记为已存在的变量
- 使用
-
visitAssignment
- visit赋值语句的lhs(ident)
- visit赋值语句的rhs (expression)
-
中端
补充tacgen中的类似上述三个函数,由于已经通过了语义检查,这里的工作相对较少,基本上是tac寄存器的分配。
-
visitDeclaration
- 获取
decl
的 ‘symbol’ 属性。 - 使用
mv.freshTemp
获取一个新的临时变量用于该符号。 - 如果声明具有初始值,使用
mv.visitAssignment
来设置它。
- 获取
-
visitIdentifier
将标识符
ident
的 ‘val’ 属性设置为标识符ident
的 ‘symbol’ 属性的临时变量。 -
visitAssignment
- 访问表达式
expr
的右值,并获取左侧的临时变量。 - 使用
mv.visitAssignment
发出一个赋值指令。 - 将表达式
expr
的 ‘val’ 属性设置为赋值指令的值。
- 访问表达式
后端
-
assign语句实际上是特殊的binary操作,所以在riscvasmemitter中补充visitAssign即可,其他内容后端代码均已提供
1
2def visitAssign(self, instr: Assign) -> None:
self.seq.append(Riscv.Move(instr.dst, instr.src))
思考题
1.写出一段 risc-v 汇编代码,将栈帧空间扩大 16 字节
1 | addi sp, sp, -16 |
2.如何修改以允许多次定义同名变量
-
目前declaration实现
- 语义检查(namer)中
1. Use ctx.lookup to find if a variable with the same name has been declared.
2. If not, build a new VarSymbol, and put it into the current scope using ctx.declare.
3. Set the ‘symbol’ attribute of decl.
4. If there is an initial value, visit it
-
修改方法
- 去掉开始对同名变量的检查
- 首先visit赋值语句的init部分
- 总是定义新的varSymbol
在tacgen中,首先visit赋值语句的init部分,然后再进行定义。