代码之家  ›  专栏  ›  技术社区  ›  Curunir

C#编译器构建作用域问题

  •  0
  • Curunir  · 技术社区  · 9 年前

    我正在构建一个自定义的小型解释脚本语言,除了作用域之外,一切都很好。 对于实际执行,我使用了访客模式: 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 回复  |  直到 9 年前
        1
  •  0
  •   sepp2k    9 年前

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

    因此,在这些假设下,问题是使用克隆表完成的任何赋值在原始表中都不可见,即使赋值给的变量已经存在于原始表中。

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

    1. 这种方法的另一个快速而肮脏的替代方法是在您的值周围添加一个可变的包装器,即 ValueWrapper 用a分类 setValue 方法假设克隆的表是原始表的浅层副本,这意味着您可以调用 设置值

    2. 最接近当前代码的解决方案是将表转换为链接结构。然后 new VariableTable(vt) 实际上不会复制任何内容,只需创建一个新的空表,其中父链接指向原始表。任何新条目都会插入到新表中,但对旧条目的访问只会传播到父表。

    只使用解决方案3的缺点是,在实现闭包时,您会再次遇到类似的问题。所以它实际上只解决了你当前的问题。