【问题标题】:Creating and Implementing Abstract Syntax Tree in Assembly 86x在 Assembly 86x 中创建和实现抽象语法树
【发布时间】:2015-02-25 08:25:34
【问题描述】:

所以我最近开始学习汇编语言,但在创建抽象语法树 (AST) 并在汇编中实现它们时遇到了麻烦。所以可以说我有这个等式:z = (3 - 2*x)*x - 2*y + 1。那么下面的 AST 是否正确,因为我知道有多个答案,每个答案在实现上都不同?

                             =
                            / \
                           -   *
                          / \   \
                         *   3   *
                        / \     / \
                       2   x   -   +
                              / \  / \
                             x   2 y  1

从那里,我将如何在我的代码中实现它(如果树是正确的)?不幸的是,我不知道从哪里开始。提前致谢。

【问题讨论】:

  • AST 不正确,因为它应该反映获取结果的路径。
  • 至于组装实现,这取决于你,所以到目前为止,这应该被关闭为“太宽泛”。
  • 我将如何修复这棵树?
  • 好吧,记住算术中的运算符优先级,并使树符合将要执行的操作。
  • 我需要视觉来理解,对不起。

标签: assembly x86 abstract-syntax-tree


【解决方案1】:

操纵 AST 的应用程序通常并不小,并且在汇编程序中对它们进行编码并没有什么好处。您最好将 AST 操作编写为更高级别的语言,您可以在其中编写更轻松地处理树的代码。 (有关推动 AST 操作极限的工具,请参阅我的简历)。

如果你坚持,那么关键问题是定义一个AST节点结构。实际上,它应该:

  • 保留父子链接
  • 持有一个节点类型
  • 保持文字值值
  • 适合缓存行

(这些约束来自我们的工具操作的非常大的 AST)。

如果你坚持使用 MASM-x86,下面的结构定义可能是合适的:

  ASTNODE STRUCT
  NodeType dword ?     ; holds type of AST node
  LiteralValue dword ? ; holds child count, literal value or pointer to big literal value, as indicated by the type
  Parent  dword ?
  Children dword ?
  ASTNODE ENDS

[您可以轻松定义 MASM-x64 的等效项。如果你不知道怎么做,你不应该这样做。]

我们假设有很多AST节点类型,为了区分语句、运算符、操作数、标识符……所以我们需要区分它们,因此需要区分NodeType。

基于Node,字面值包含(假设互斥情况): * 没有(没有必要) * 子节点数,如果节点类型是列表节点 * 一个文字常量,如果节点类型是一个持有小值的叶子 * 指向文字常量的指针,如果节点类型是用于持有大于 32 位的文字值的叶子 * 如果节点类型是“标识符”,则指向标识符字符串或符号表条目的指针

“Children”槽很特别:它本质上是指向其他 AST 节点的指针的动态数组。对于许多 AST 节点类型,子节点的数量是隐式已知的;您可以在节点类型上使用表查找,或者代码可以“知道”。对于列表节点,子节点的数量需要与文字字段指定的列表长度相匹配。

任何少于 4 个子节点的节点都适合 32 个字节,并且应该相应地对齐。超过 4 个子节点的节点应该是缓存行对齐的。

您仍然需要构建一个解析器,它必须创建节点并通过填写指针字段将它们链接在一起。

我想你会发现用 AST 构造构建一个解析器是很多工作(尤其是在汇编器中),然后你需要构建一些对树做某事的东西。

【讨论】:

    【解决方案2】:

    您需要设置一个堆栈和一个队列(后进先出和先进先出的内存块)。 您还需要操作的优先级(BEDMAS -(^/*+-= 是一个好的开始,但是快速搜索 Web 将为您提供多达 16 个不同操作员的不同优先级)。 现在遍历你的表达式:

    1. 如果是值,则将其添加到队列中
    2. 当堆栈上有更高优先级的操作时,将其移至队列末尾。
    3. 将操作添加到堆栈中。

    当所有参数都完成后,取出堆栈的剩余部分并将其添加到队列的末尾。

    队列现在处于逆波兰方向 - value1, value2, op 所以你的例子是

    2,x,*,3,-,{right hand branch},=
    

    由于这是一个无效的左手运算符,它会失败但现在忽略它并继续。对于队列中的每个项目:

    1. 如果是值,则将其压入堆栈。
    2. 如果是运算符,则对栈顶元素执行操作,然后将值返回到栈中。
    3. 最终结果将留在堆栈中。

    所以在这种情况下,堆栈会去:

     - {empty}    ; 2
     - 2          ; x
     - 2,x        ; *(multiply top 2 items on stack and push result)
     - {2x}       ; 3
     - {2x},3     ; -(subtract top 2 items on stack and push result)
     - {2x-3}     ; (final result)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-25
      • 1970-01-01
      相关资源
      最近更新 更多