stage2

stage-2

郭高旭 ggx21@mails.tsinghua.edu.cn 2021010803

实验内容

增加变量,实现对变量的声明和赋值。同时增加变量相关的语义检查,不能重复声明变量,不能使用未声明的变量

前端

  • lex&parser

    此部分内容框架已经提供,通过这里表达出ast树

  • 语义分析

    修改namer中 visitDeclaration,visitAssignment,visitIdentifier三个函数

    • visitDeclaration

      1. 使用 ctx.lookup 来查找是否已经声明了具有相同名称的变量。
      2. 如果有,报错。如果没有,创建一个新的 VarSymbol,并使用 ctx.declare 将其放入当前作用域。
      3. 设置 decl 的 ‘symbol’ 属性。
      4. 如果存在初始值,对其进行访问。
    • visitIdentifier

      1. 使用 ctx.lookup 来查找是否已经声明了具有相同名称的变量。
      2. 如果没有,报错。否则将该标识符同样标记为已存在的变量
    • visitAssignment

      1. visit赋值语句的lhs(ident)
      2. visit赋值语句的rhs (expression)

中端

补充tacgen中的类似上述三个函数,由于已经通过了语义检查,这里的工作相对较少,基本上是tac寄存器的分配。

  • visitDeclaration

    1. 获取 decl 的 ‘symbol’ 属性。
    2. 使用 mv.freshTemp 获取一个新的临时变量用于该符号。
    3. 如果声明具有初始值,使用 mv.visitAssignment 来设置它。
  • visitIdentifier

    将标识符 ident 的 ‘val’ 属性设置为标识符 ident 的 ‘symbol’ 属性的临时变量。

  • visitAssignment

    1. 访问表达式 expr 的右值,并获取左侧的临时变量。
    2. 使用 mv.visitAssignment 发出一个赋值指令。
    3. 将表达式 expr 的 ‘val’ 属性设置为赋值指令的值。

后端

  • assign语句实际上是特殊的binary操作,所以在riscvasmemitter中补充visitAssign即可,其他内容后端代码均已提供

    1
    2
    def 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
    
  • 修改方法

    1. 去掉开始对同名变量的检查
    2. 首先visit赋值语句的init部分
    3. 总是定义新的varSymbol

    在tacgen中,首先visit赋值语句的init部分,然后再进行定义。




本文总阅读量