C#编译器构建范围问题

时间:2017-07-16 20:21:38

标签: c# compiler-construction

我正在构建一个自定义的小型解释脚本语言,除了范围之外,一切正常。 对于实际执行,我使用访问者模式:enter image description here

我修改了模式以通过变量表:

public void visit(ProgrammTree proTree){
        VariableTable vt = new VariableTable();
        foreach (var t in proTree.getChildren()) {
            t.accept(this, vt);
        }   
    }

这就是问题的起点:

  public void visit(WhileTree whiletree, VariableTable vt) {
            var cond = (ConditionTree)whiletree.getChild(0);

            while (cond.accept(this, vt).toBoolean()) {
                 var clonedSubTable = new VariableTable(vt)
                foreach (Tree t in whiletree.getChildren()) {
                    t.accept(this, clonedSubTable );
                }

            }
        }

问题是循环内的更改不在外部作用域中执行。 你有一个聪明的方法来实现这个吗?

1 个答案:

答案 0 :(得分:0)

你留下了一些含糊不清的东西,所以我要做出以下假设(请指出任何错误):

  • 您的VariableTable将变量名称直接映射到其关联值
  • 无论何时分配值,都可以直接将该值设置为表中的条目(不经过任何间接层)
  • 您的克隆变量表不会保留对原始文件的引用,也不会传播对原始文件的任何更改

因此,在这些假设下,问题是即使在原始表中已经存在已分配的变量的情况下,使用克隆表完成的任何分配也不会在原始表中可见。

要解决此问题,有多种方法:

  1. 您可以将表映射变量设置为内存位置而不是值。然后,您将拥有另一个将内存位置映射到值的表(或只是一个普通数组)。这样,变量的表项永远不会改变:一旦定义了变量,它就会获得一个内存地址,并且该地址不会发生变化,直到变量消失。只有地址的值可能会改变。

  2. 这种方法的快速而又脏的替代方法可以让您不必管理自己的内存,就是在值周围添加一个可变的包装器,即ValueWrapper类{{1} }} 方法。假设您的克隆表是原始的浅表副本,这意味着您可以在克隆表的条目上调用setValue,如果该条目已存在于原始表中,则更改也将反映出来在原始表格中。

  3. 与您当前代码保持最接近的解决方案是将您的表格转换为链接结构。然后setValue实际上不会复制任何内容,而只是创建一个新的空表,其父链接指向原始表。任何新条目都将插入到新表中,但对旧条目的访问将简单地传播到父表。

  4. 即使您选择使用选项1或2来解决当前问题,出于性能原因,使用父链接而不是不断复制表也是一个好主意。

    仅使用解决方案3的缺点是,当您实现闭包时,您将再次遇到类似的问题。所以它真的只能解决你当前的确切问题。

    解决方案1的优点是它允许您完全控制内存,因此您可以随心所欲地实现与内存相关的功能。不利方面是一样的。