抽象树与解析树

Abstract tree vs parser tree

本文关键字:抽象      更新时间:2023-10-16

我需要你的意见,以便在生成解析器树(ST)和生成抽象语法树(AST)之间选择最佳替代方案。这是上下文:

我想解析像C这样的语言(只是C的一个子集,做了一些更改,使其更面向伪代码),但不是为了将其翻译成其他输出语言/文件,而是为了执行其语句,以动画化其执行过程(我使用Qt绘制)。这个C子集的一个特点是它启用了嵌套的作用域。我对我在ST和AST之间的选择产生了怀疑,这源于符号表。总体思路是(使用BoostSpirit):

  1. 通过自定义Boost.espirit解析器解析源代码文件
  2. 语义操作产生一个语法树,只是源代码语法树的副本(或者,BoostSpirit内部语法树的一个副本,但有我自己的类和结构)。因此,没有AST
  3. 有了这个ST,程序按照自上而下的方向读取这个语法树,如下所示:
    1. 执行第一句话
    2. 上传带有新(句子结果)值的符号表
    3. 将符号表的实际状态保存在程序状态堆栈中
    4. 至3.1,直到ST完全处理完毕
    5. 为算法读取和绘制程序状态堆栈制作动画

两个原因:

  1. 如果我使用AST,在解析后,我会丢失有关变量声明及其类型等的信息。因此,我必须通过解析器的语义操作来处理符号表,这使解析器的编写和理解变得复杂。此外,无论实际作用域如何,我都必须始终使用具有所有变量的符号表(如果我在作用域I中,则只需要作用域I,I-1,…,1;而不是整个算法中的所有作用域)。这会消耗内存
  2. 在我的程序状态堆栈中,我只需要实际作用域和以前作用域的变量,以免通过动画使算法的可理解性复杂化。如果我使用ST,在将其保存到堆栈中之前,我必须删除所有不需要的符号。这需要时间
  3. 具有控制范围的静态符号表比动态符号表更难设计和使用。静态符号表必须为每个作用域都有一个标识符(例如),并将树的每个节点与每个标识符关联起来。动态符号表更容易工作,因为如果我在范围I中,只需要两个"向量"(可能是一个双队列和一个堆栈):

    • 一个包含符号及其相关信息的容器(双队列?):容器中的最后一个变量是最近的声明变量
    • 整数的容器(堆栈),显示每个作用域的开头(双队列的索引)

    例如,对于作用域i:

    • 容器1:[x y z x a b z f a z]
    • 容器2:[0 3 6 8]

    如果我离开范围I,只需要擦除最后一个整数和从位置8到末尾的符号。这棵树保持不变。

  4. 由于我必须在执行时间内执行每一句话,ST有助于我的执行。

两个问题:

  1. 哪个更好
  2. 存在任何形式来提取精神的内部树,或者为了不复制而定制它

我认为您正在寻找的是一个抽象语义图(ASG),它表示程序的语义(与语法相反)。你能做的是:

  1. 将源解析为AST,然后
  2. 将AST转换为ASG,最后
  3. 遍历ASG以执行实际代码

此外,我想说,您确实可以构建一个AST,它不是抽象;例如,我目前正在构建自己的脚本语言解释器,AST将包含变量名(这对于调试解析器/解释器以及解析后的程序本身非常有用)。