【问题标题】:compiling assignment expression to bytecode [closed]将赋值表达式编译为字节码 [关闭]
【发布时间】:2018-08-16 21:14:46
【问题描述】:

我正在尝试将赋值表达式编译为字节码。我正在写我自己的语言,这部分真的让我很难过。我的语言获取源代码并将其转换为令牌,然后直接转换为字节码。例如,类似:

a + 2

变成

TOKEN_NAME
TOKEN_ADD
TOKEN_INT

这将被解析并转换为类似于

的字节码
LOAD_VARIABLE (this is the a)
LOAD_CONSTANT (this is the 2)
ADD

这很简单。但是对于赋值表达式,例如:

a[0][1] = 2

会变成

TOKEN_NAME
TOKEN_L_BRACKET
TOKEN_INT
TOKEN_R_BRACKET
TOKEN_L_BRACKET
TOKEN_INT
TOKEN_R_BRACKET
TOKEN_ASSIGN
TOKEN_INT

我需要加载一个,在该对象上做一个下标(0 下标),然后将 2 存储到 1 下标中。我应该补充一点,解析器实际上是 LL(1),这使得这特别困难。

我想不出一种方法来确保左侧表达式的最后一部分(我分配给的部分)没有被加载,但其中存储了值 (2)。

如果有任何不清楚的地方,请发表评论,我很乐意澄清我的程序。 (很难为编程语言的整个解释器制作 MCVE!)

提前致谢。

【问题讨论】:

  • 你不能得到assign token,然后回到名字或括号吗?
  • 这是一个 LL(1) 解析器,因此我无法回溯。在实际代码中,这些表达式在下标之间可能绝对是巨大的,因此返回将非常低效。
  • 您不能回溯,但您可以将令牌存储在辅助列表中。
  • 这可能适用于下标,但我不确定它是否类似于x = 2 我如何能够确保我将 2 存储在 x 中,而不是先加载 x
  • 嗯,这听起来像是一个递归下降解析器,@DanielGee,而不是一个 LL(1)。递归下降解析器也构建了一个 AST,但它通过一系列堆栈帧体现在调用堆栈上。

标签: c parsing compiler-construction bytecode interpreter


【解决方案1】:

您可以使用简单的回溯方法来构造引用:

  • 像阅读表达式一样编译表达式
  • 如果下一个操作需要左值,请回顾上一个字节码操作
  • 根据下表转换最后一个操作:
    • LOAD_VALUE 转换为 GET_VALUE_REF
    • LOAD_PROPERTY 转换为 GET_PROPERTY_REFLOAD_PROPERTYa.b 生成)
    • LOAD_ELEMENT 转换为 GET_ELEMENT_REFLOAD_ELEMENTa[b] 生成)
    • 任何其他操作码都会生成无效的左值错误。

此方法足以满足最常见的语义。对于 C,您将添加对取消引用运算符 * 的支持:GET_POINTER_VALUE 转换为 GET_POINTER_REF,这实际上是一个无操作。

要实现这一点,您需要跟踪编译器生成的最后一个操作码,并有可能将其修补到另一个字节码中。

表达式a[0][2] 将编译为

LOAD_VARIABLE a (this is the a)
LOAD_CONSTANT 0 (this is the 0)
GET_ELEMENT
LOAD_CONSTANT 2 (this is the 2)
GET_ELEMENT

a[0][2] = 3 转换为

LOAD_VARIABLE a
LOAD_CONSTANT 0
GET_ELEMENT
LOAD_CONSTANT 2
GET_ELEMENT_REF
LOAD_CONSTANT 3
STORE_REF

如果您不需要参考,也可以直接生成特定商店(例如,您需要a[b] += c 的参考)。

a[0][2] = 3 然后转换为

LOAD_VARIABLE a
LOAD_CONSTANT 0
GET_ELEMENT
LOAD_CONSTANT 2
LOAD_CONSTANT 3
STORE_ELEMENT (uses 3 stack slots)

a[0][2] += 3 产生:

LOAD_VARIABLE a
LOAD_CONSTANT 0
GET_ELEMENT
LOAD_CONSTANT 2
GET_ELEMENT_REF
LOAD_REF
LOAD_CONSTANT 3
ADD
STORE_REF

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-20
    • 2011-09-20
    • 1970-01-01
    • 2017-08-16
    • 1970-01-01
    相关资源
    最近更新 更多