简体   繁体   English

如何为 Jasmin 字节码声明嵌套的 function?

[英]How to declare nested function for Jasmin byte code?

I am writing a compiler and I need to convert Mini Pascal (a simple version of Pascal) to Jasmin byte code.我正在编写一个编译器,我需要将 Mini Pascal(Pascal 的一个简单版本)转换为 Jasmin 字节码。

  1. But how do I declare the nested function in the Jasmin language?但是如何在 Jasmin 语言中声明嵌套的 function呢?

  2. Because function tt(I): I can only pass in one Integer (which is rr ) how do I transfer the variable d from function ss to function tt ?因为function tt(I): I只能传入一个 Integer (即rr )如何将变量dfunction ss转移到function tt

C++ (translated from Mini Pascal by myself): C++(自己翻译自Mini Pascal):

#include <iostream>

using namespace std;

int a, b;

int ss(int rr)
{
  int d;

  int tt(int rr)
  {
    int e;
    e = rr * 3;
    return rr + d - e + b;
  }

  d = rr - 4;
  return tt(rr);
}

int main()
{
  b = -5;
  a = ss(3);
  cout << a;

  return 0;
}

Mini Pascal:迷你帕斯卡:

PROGRAM test_nested_function(input, output, error);
VAR a, b : INTEGER;

  FUNCTION ss(rr :INTEGER) : INTEGER;
  VAR d : INTEGER;

    FUNCTION tt(rr : INTEGER) : INTEGER;
    VAR e : INTEGER;
    BEGIN
      e := rr * 3;
      tt := rr + d - e + b;
    END;

  BEGIN
    d := rr - 4;
    ss := tt(rr)
  END;

BEGIN
  b := -5;
  a := ss(3);
  writelnI(a)
END.

When you're translating from a language that has closures to one that doesn't, you have to retain a reference to the outer function somehow.当你从一种有闭包的语言翻译成没有闭包的语言时,你必须以某种方式保留对外部 function 的引用。 There are, broadly speaking, two ways to do that: nested closures and flat closures .从广义上讲,有两种方法可以做到这一点:嵌套闭包平面闭包 The important thing to note is that, in both of these cases, your closure is not an ordinary top level function. It's some structure that happens to be callable.需要注意的重要一点是,在这两种情况下,您的闭包都不是普通的顶级 function。它是某种恰好可调用的结构。

Nested Closures嵌套闭包

In a nested closure, your nested function simply maintains a reference to the enclosing scope as a pointer to some abstract data structure.在嵌套闭包中,嵌套的 function 只是维护对封闭 scope 的引用作为指向某个抽象数据结构的指针。 So, tt maintains a reference to ss (in the abstract) and then can access the d variable via ss.d .因此, tt维护对ss的引用(在抽象中),然后可以通过ss.d访问d变量。 Java pseudo-code for the same: Java 相同的伪代码:

public class SsStructure {
  private int rr;
  private int d;

  public SsStructure(int rr) {
    this.rr = rr;
    this.d = 0;
  }

}

public class TtStructure {
  private SsStructure closure;

  public TtStructure(SsStructure closure) {
    this.closure = closure;
  }

  public int call(int rr) {
    ...
  }
 
}

public class Main {
  public static int ss(int rr) {
    SsStructure ss = new SsStructure(rr);
    TtStructure tt = new TtStructure(ss);
    ss.d = ss.rr - 4;
    return tt.call(ss.rr - 4);
  }
}

In this model, your ss function gets a closure frame in your program.在这个 model 中,你的ss function 在你的程序中得到一个闭包框架。 All of its local variables (or at least, those needed by the closures) get put into that structure rather than being declared as actual local variables.它的所有局部变量(或者至少是闭包所需的局部变量)都被放入该结构中,而不是被声明为实际的局部变量。 Then that closure structure gets passed to any nested function that needs it.然后该闭包结构被传递给任何需要它的嵌套 function。

If you have functions nested multiple layers deep, then a closure maintains a reference to the immediately enclosing scope. If it needs to access variables that exist multiple layers up the closure stack, it will do so through indirect references, since each closure frame retains a reference to its own enclosing scope.如果你有多层嵌套的函数,那么闭包会维护对立即封闭的 scope 的引用。如果它需要访问存在于闭包栈上多层的变量,它将通过间接引用来实现,因为每个闭包框架都保留一个参考其自身的封闭 scope。

Flat Closures平盖

With flat closures, your nested function receives copies of the actual concrete variables from the enclosing scope. Your tt is still a structure, but rather than storing a reference to some other ss structure, it gets the actual int it needs.使用平面闭包,您的嵌套 function 从封闭的 scope 接收实际具体变量的副本。您的tt仍然是一个结构,但它不是存储对其他一些ss结构的引用,而是获取它需要的实际int

public class TtStructure {
  private int d;

  public TtStructure(int d) {
    this.d = d;
  }

  public int call(int rr) {
    ...
  }
 
}

public class Main {
  public static int ss(int rr) {
    int d = rr - 4;
    TtStructure tt = new TtStructure(d);
    return tt.call(rr - 4);
  }
}

This is a more space-efficient approach.这是一种更节省空间的方法。 Rather than storing a bunch of pointers everywhere, you store only the actual data, and the data you need.与其在各处存储一堆指针,不如只存储实际数据和您需要的数据。 Further, if you have nested closures, you automatically flatten them when you create these specialized structures, so there's less indirection.此外,如果你有嵌套的闭包,当你创建这些专门的结构时,你会自动将它们展平,因此间接性更少。

However, care must be taken if you have mutable closures.但是,如果您有可变闭包,则必须小心。 If you have a final variable, then there's no problem.如果你有一个final变量,那就没问题了。 In fact, this is exactly why the Java language forbids non- final variables from being closed over.事实上,这正是Java 语言禁止关闭非final变量的原因。

If you want to allow mutable variables in closures, you'll need to explicitly add in a layer of indirection.如果你想在闭包中允许可变变量,你需要显式地添加一个间接层。 This can be a simple class that stores one instance variable, and then you can use that variable in both the enclosing scope and the closure.这可以是存储一个实例变量的简单 class,然后您可以在封闭的 scope闭包中使用该变量。

public class Cell<T> {
  public T impl;
  public Cell(T impl) {
    this.impl = impl;
  }
}

You need to wrap any local variable in a Cell<T> if it is (a) used in a closure, and (b) reassigned to at any point.您需要将任何局部变量包装在Cell<T>中,如果它 (a) 在闭包中使用,并且(b) 在任何时候重新分配给。 Variables that are final (hence never reassigned) need not be wrapped, and those that are only used locally (never in a closure) need not be wrapped. final变量(因此永远不会重新分配)不需要包装,那些只在本地使用(永远不会在闭包中)的变量不需要包装。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM