二週間自家製のスクリプト言語 - デイ7追加機能機能

7日目の追加機能機能

関数の定義と呼び出しの実行、ストーン言語変数は、関数に割り当てることができるクロージャの導入基本的な、または他の関数の引数としての機能の
一部の機能がサブルーチンとして分類された値を返さない関数の戻り値として分類されます

7.1拡張構文規則

文法は、関数定義文の規則

この本は、DEFの文と呼ばれる定義文を機能します。唯一のコードの最外層ではなく、コードブロック内のユーザ定義関数のステートメントDEF

最終結果の声明(表現)を実行しますストーン言語は関数の戻り値として返されます

文法規則の機能に関連する7.1リスト

param : IDENTIFIER 
params :  param { "," param }
param_list :  "(" [ params ] ")"
def :  "def" IDENTIFIER param_list block 
args :  expr { "," expr }
postfix :  "(" [ args ] ")"
primary :  ( "(" expr ")" | NUMBER | IDENTIFIER | STRING ) { postfix }
simple :  expr [ args ]
program :  [ def | statement ] (";" | EOL)

paramがパラメータ識別子(変数名)です。パラメータは、少なくとも1つの配列がコンマパラメータによって分離され、PARAMをparamsは含みます。
param_listブラケットが空の括弧であってもよい、paramsはであることができます()。
機能がDEF DEF文で定義され、識別子(関数名)、param_listおよびブロック要素。
複数のカンマで区切られたexprの組成によって引数引数。
Postfixは括弧引数とすることができ、それが空の括弧の引数を省略することができます

非終端主な関数呼び出しは、元の基礎に含まれる発現させるための支援を拡大する必要があります。したがって、この章では、主表示5.1の定義を変更します。元のプライマリ番号接尾辞(サフィックス)依然としてプライマリを取得し(0であってもよい)後に添加。postfixのは、ここで括弧引数列で囲まれています

また、簡単な式ステートメントは、関数呼び出し文のサポートを必要としています。したがって、だけでなく、exprの組成により、簡単なの定義を変更する前にこの章では、その後、exprの後の引数の組み合わせも簡単な文です

別のプライマリでは、簡単なargs引数は括弧でサポートされていません。その

simple : expr [ "("  [ args ] ")" ]

間違っている、あなたは次の形式を使用する必要があります

simple : expr [ args ]

7.2をリスト表示7.1デザインの文法のパーサコードのルールに基づいています。どのFuncParserクラス5.2リスト内の第5章Basicparserクラスから継承。これ、基本的な部分のパーサは、既存のコードBasicparserクラスを利用され、FuncParserクラスは、新しい機能を定義します。前述のように、非終端もパーサライブラリの新しい定義を達成します。、7.3リスト7.5リストのコードの後に​​7.4と抽象構文木をリスト更新ノードクラスであります

7.2、多分方法を使用して、初期化paramListフィールドとフィールド後置式リスト。
paramListは、例えば、以下のようにフィールドが定義され

Parser paramList = rule().sep("(").maybe(params).sep(")");

方法と同じオプション、多分また、非終端記号を追加する方法は、モードに省略されてもよいです。
非終端param_list実際の構文規則に対応paramListフィールドは、以下に示します

param_list : "(" [ params ] ")"

ParameterListに作成されたサブツリー省略のparamsオブジェクトツリーのルートです。サブツリーのルートノードはサブツリーツリーない他の子ノードのルートノードを除いて、唯一のノードです。するParameterList子ノード(パラメータリスト)が、元のオブジェクトパラメータを表すために使用されparamsは、ルートノード0の子ノードは、ウェルはパラメータを示していない発生したときに省略されています

でも省略されているパラメータ、抽象構文木は、まだ実際には存在しない、このコンポーネントを表すために、サブツリーのparamsが含まれています。第5章の特別な規定は、避けるために不要なノードを作成し、サブツリーを、対応するサブツリーparamsは、対応する非終端param_listとして直接使用されます

非終端定義された変更は、コンストラクタによって完成されます。コンストラクタ)右括弧が予約されて追加する最初の必要性は、そのような識別子としてそれを認識しません。その後、シンプルモードの終了、主要非終端記号も分野に応じて適切なメソッドを呼び出すために、この目的の必要性のために、添加。例えば、simp1eフィールド法は、オプションを呼び出す必要があります

simple.option(args)

モードBasicparser単純なクラスによって初期化モードの終了の新しいセクションを追加するには、このようにして、オプションの方法。言い換えれば、ときBasicParserは初期化時に、次のステートメントは実行されません

Parser simple = rule(PrimaryExpr.class).ast(expr);

以下のコードが実行されます

Parser simple = rule(PrimaryExpr.class).ast(expr).option(args)

非終端デフデフ文を表示するためのプログラムinsertChoiceフィールドにコンストラクタメソッド呼び出しの最後の行は、プログラムに追加されます。前分岐またはオプションますDEFなどの方法では、対応するプログラムモードに追加します

DEF insertChoice法により添加した後、パターンは、同等のプログラムは、以下に示す定義します

Parser program = rule().or(def,statement,rule(NullStmnt.class)).sep(";",Token.EOL)

デフカウント、表現や枝が3つのオプションに増加しました。新しいオプションと元の2つは、直接枝や方法が、パーサは、最初の調査の選択を競合する文が実行される時点でどの枝を決定する必要があります

7.2リストのサポート機能パーサーFuncParser.javaています

package stone;
import static Stone.Parser.rule;
import stone.ast.ParameterList;
import stone.ast.Arguments;
import stone.ast.DefStmnt;

public class FuncParser extends BasicParser {
    Parser param = rule().identifier(reserved);
    Parser params = rule(ParameterList.class)
                        .ast(param).repeat(rule().sep(",").ast(param));
    Parser paramList = rule().sep("(").maybe(params).sep(")");
    Parser def = rule(DefStmnt.class)
                     .sep("def").identifier(reserved).ast(paramList).ast(block);
    Parser args = rule(Arguments.class)
                      .ast(expr).repeat(rule().sep(",").ast(expr));
    Parser postfix = rule().sep("(").maybe(args).sep(")");

    public FuncParser() {
        reserved.add(")");
        primary.repeat(postfix);
        simple.option(args);
        program.insertChoice(def);
    }
}

7.3 ParameterList.javaリスト

package stone.ast;
import java.util.List;

public class ParameterList extends ASTList {

    public ParameterList(List<ASTree> list) {
        super(list);
    }

    public String name(int i) {
        return ((ASTLeaf) child(i)).token().getText();
    }

    public int size() {
        return numChildren();
    }
}

7.4 DefStmnt.javaリスト

package stone.ast;
import java.util.List;

public class DefStmnt extends ASTList {

    public DefStmnt(List<ASTree> list) {
        super(list);
    }

    public String name() {
        return ((ASTLeaf) child(0)).token().getText();
    }

    public ParameterList parameters() {
        return (ParameterList) child(1);
    }

    public BlockStmnt body() {
        return (BlockStmnt) child(2);
    }

    public String toString() {
        return "(def )" + name() + " " + parameters() + " " + body() + ")";
    }
}

7.5 Arguments.javaリスト

package stone.ast;
import java.util.List;

public class Arguments extends Postfix {
    public Arguments(List<ASTree> c) {
        super(c);
    }

    public int size() {
        return numChildren();
    }
}

7.2適用範囲と寿命

環境変数の変数名と値の対応表です。ほとんどのプログラミング言語は、ローカル変数の関数内でのみ有効なサポート。石の言語でもローカル変数をサポートして作るために、私たちは環境を再設計する必要があります

設計環境

適用範囲(スコープ)

これは、プログラム内の変数に有効なアクセスの可変範囲の範囲を指します。例えば、Java言語のメソッドのパラメータは、メソッド内で参照することができます。すなわち、メソッドの内部にメソッドを定義するスコープパラメータです。

ライフサイクル(範囲)

変数のライフサイクルは、変数の存在の期間です。例えば、Java言語の寿命パラメータpは、メソッドの実行方法です。換言すれば、パラメータpは、メソッドを実行する過程で、常にアクティブです。このメソッド呼び出しの途中で他の方法は、元のメソッドのスコープの外に行く場合は、新しい方法は、基準パラメータp元のメソッドを呼び出すことはできません。パラメータpは、この時間を参照することはできませんが、しかし、それは現在の値の保存、存在し続けます。元の方法に戻るが、パラメータpスコープにバックアップするとき、再びパラメータpを参照することができるであろう。参考パラメータpは自然に元の値を導出します。実行方法の後、寿命パラメータpは、パラメータpの端になります名前と値のペアを、対応する環境が存在しなくなり、保存、もはや有効ではありません。実際には、環境にも名前と値のペアを維持するために継続する必要はありません。もし、プログラムが再びメソッドを呼び出した後、新しい値に関連付けられたp個のパラメータ(引数)

入れ子構造で、典型的には、変数のスコープ。ストーンの言語サポートは、グローバル変数のスコープのプログラム全体で有効であり、範囲内のローカル変数や関数のパラメータ内で有効に機能のみ

パフォーマンスのための入れ子構造の入れ子環境、必要であれば、我々は、各スコープのための個別の環境を準備する必要があり、そして。変数を探しているときに、プログラムが最初に見つからない場合は、再び層によって層を見つけるために、最も内側のスコープに対応した環境を探します。石はまだ関数内で定義された現在の言語機能をサポートし、そのため2つだけのスコープ、つまりグローバル変数のスコープとローカル変数のスコープありません。関数定義関数内言語サポートでは、ネストされた環境の複数の層があるかもしれません

コードの中かっこ{}ブロックで囲まれたJavaのようないくつかの言語は、独立した範囲を持っています。のみブロック内の変数宣言コードブロックを参照します。石は、コードブロックのスコープのために特別に設計ない言語は、現在ではない、それは、各コードブロックのための別のスコープを提供しないであろう。そのため、石言語は常に唯一の2つのスコープになります。

7.6 NestedEnv.javaリスト

package chap7;
import chap6.Environment;
import java.util.HashMap;
import chap7.FuncEvaluator.EnvEx;

public class NestedEnv implements Environment {

    protected HashMap<String, Object> values;
    protected Environment outer;

    public NestedEnv() {
        this(null);
    }

    public NestedEnv(Environment e) {
        values = new HashMap<String, Object>();
        outer = e;
    }

    public void setOuter(Environment e) {
        outer = e;
    }

    public void put(String name, Object value) {
        Environment e = where(name);
        if (e == null)
            e = this;
        ((EnvEx)e).putNew(name,value)
    }

    public void putNew(String name, Object value) {
        values.put(name, value);
    }

    public Environment where(String name) {
        if (values.get(name) != null)
            return this;
        else if (outer == null)
            return null;
        return ((EnvEx) outer).where(name);
    }

    public Object get(String name) {
        Object v = values.get(name);
        if (v == null && outer != null)
            return outer.get(name);
        return v;
    }
}

ネストされた構造環境をサポートするために、クラスの環境インタフェースを再定義する必要があります。7.6は、将来のNestedEnvクラスで定義されているリストを使用する必要があります

加えてBasicEnvクラス、NestedEnvタイプ値フィールドとは異なり、外側のフィールドがあります。参照フィールドスコープ環境に対応する外側の層です。さらに、GETメソッドはまた、外部環境に応じた範囲を見つけるために、それに応じて修正を必要とします。変数の値を更新することができ、正しいputメソッドを確保するために、我々はまた、それに変更を加える必要があります。変数名のパラメータが存在しない現在の環境、およびスコープの名前を含む外層を指定している場合、変数のスコープ外に値を割り当てる方法を置く必要があり。この目的のために、我々はどこ補助メソッドを使用する必要があります。指定された名前とリターンが含まれている環境変数のためのこの方法のルックス。すべての環境は、メソッドがnul1を返す変数名を、含まれていない場合

NestedEnvクラスはメソッドputNewを提供します。この方法の効果は、PUTメソッドBasicEnvクラスと同じです。これは、割り当てで参照外側のスコープの環境外のフィールドを考慮されません。限り、現在の環境変数ではないようにかかわらず、環境の外側の範囲に対応する指定された変数名の存在は、putNew方法は、変数を追加します。

また、この方法NestedEnvクラスを作るために、私たちは環境を経由してインターフェースにアクセスするための環境のインターフェースにいくつかの新しいメソッドを追加する必要があります。修飾子EnvExを定義する修飾子7.7定義されたFuncEvaluatorリスト、それはこれらの新しいメソッドを追加しました。

7.3関数が実行されます

機能を実行するインタプリタができるようにするためには、抽象構文木のノードクラスはEVA1メソッドを追加しなければなりません。これは、7.7の上場FuncEvaluator修飾によって達成されます。

関数の実行には、二つの部分とのコールで定義されています。プログラムを採用してDEF文では、関数を表すオブジェクトを作成する関数の名前を追加し、オブジェクトに関連付けられた環境にする関数を定義します。言い換えれば、プログラムは、オブジェクトが変数の値、変数名と呼ばれる機能をされている環境に変数を追加します。この関数はFunctionオブジェクトによって表されます。7.8定義する関数のクラスをリスト。

サブ修飾子、複数の改質剤7.7 FuncEvaluatorをリスト。ここで、Defstmntクラスに修飾子を追加するためのDefstmntEX EVA1方法。

PrimaryEx PrimaryExprクラス修飾子は、メソッドを追加します。関数呼び出しと非ターミネーター主要対応の抽象構文木表現。非終端主は唯一の今、私たちはその定義を変更するなど、リテラル式や変数名の最も基本的な構成要素を表していた、関数呼び出し式は、プライマリと判断することができます。引数からなる一次括弧付きシーケンスの後、すなわち一次結合式に包含される、次の図は、抽象構文木を構成する機能ステートメント事実(9)によって呼び出され、例えば、です。この変更をサポートするために、我々はPrimaryExprクラスの新しいメソッドの数を追加する必要があります。

図7.1事実(9)AST

ファイル

オペランド方法は、元々示すような一次のような非末端リテラルコンテンツや機能名を返す、または関数名を返します。接尾辞メソッドは、引数配列(存在する場合)を返します。評価方法は、まずオブジェクトのevalメソッドオペランドメソッドリターンを呼び出します。関数の引数配列が存在する場合、それらは、パラメータ、方法はさらに、コールの後置(すなわち引数は、上記の図にObject)メソッドリターン評価の対象となる評価方法であろう

PrimaryExpr新しいクラスメソッドはPostfix postfixの型の値を返します。Postfixは引数のシーケンスを表す具象クラスのクラス引数のサブクラスである抽象クラス(表7.9)、です。EVA1方法ArgumentsEx改質が達成引数クラスは関数の機能を実行する追加され

新しいevalメソッドなどの引数は、関数呼び出しの中核機能です。その二番目のパラメータ値は、抽象構文木を対応のevalメソッド名や関数名を呼び出した結果です。私は、Functionオブジェクトの関数がパラメータ値としてのevalメソッドに渡される呼び出したいです。DEF文で作成された関数オブジェクト。通訳のみの環境から関数オブジェクトを取得することができますevalのメソッドを呼び出しますので、彼らは、同じ関数名や変数名を扱われます

その後、インタプリタ環境の意志callerEnv計算関数の引数は、実行結果です。まず、パラメータは、それ自体で配列引数取得イテレータ方法を提供し、関数オブジェクトのメソッドのパラメータの配列を得ました。そして、インタプリタは順番に評価され、計算された引数の順序に従ってevalは、計算結果が環境に対応するパラメータ名のペアに追加されて呼び出します。ParameterList新しいクラスevalメソッドは、実際の処理を行い、

引数の値は、むしろcallerEnv環境(表7.1)よりも、関数呼び出しを実行するために、新しく作成されたnewEnv環境に追加されます。スコープnewEnv環境は内部関数によって表されます。関数がローカル変数を使用している場合、彼らは環境に追加されます

設計環境中の表7.1関数呼び出し

環境 平均
NEWENV 関数が呼び出されたときに、新しい環境を作成しました。関数のパラメータと記録のために使用する関数内のローカル変数
newEnv.outer newEnvフィールドは、関数スコープを囲む表すことができ、外部環境を参照します。この環境は通常、グローバル変数を記録するために使用されます
callerEnv 関数は声明を呼び出​​している環境。引数を計算するために使用され

最後に、評価方法引数のクラスが作成された新しい環境の中で関数本体を実行します。関数本体は、メソッド本体の関数オブジェクトを呼び出すことによって取得することができます。DEF本体は、中括弧{}包囲部によって機能ステートメントで、本体方法は、対応する抽象構文木を返します。その機能を実行するために、オブジェクトが返さEVA1メソッドを呼び出します

環境newEnvは、関数の実行の終了時に破棄され、関数が呼び出されたときに関数が作成されます起動します。これは、ライフサイクルのパラメータと関数のローカル変数と一致しています。インタプリタが再帰呼び出しを繰り返した場合、それは各コールの時に機能を備えた新しい環境を作成します。この方法でのみ適切に再帰関数を実行することができます

時には引数は、同じ環境で実行された環境callerEnvのDEF文を計算するのに使用されるが、それは必ずしもそうではありません。callerEnvコールは環境表現関数を計算するために使用されます。あなたは、コードの最外層で関数を呼び出す場合、callerEnv環境は、グローバル変数を格納するために使用されます。関数は他の関数によって呼び出された場合は、callerEnv環境は、外側の関数呼び出し機能保全のローカル変数になります。が、環境が入れ子構造をサポートしていますが、その構造は、関数が定義されている場合のみ、ネストされたスコープを反映しています。関数が他の関数を呼び出すと、新しく作成された環境では、このような入れ子構造には表示されません

7.7 FuncEvaluator.javaリスト

package chap7;
import java.util.List;
import javassist.gluonj.*;
import stone.StoneException;
import stone.ast.*;
import chap6.BasicEvaluator;
import chap6.Environment;
import chap6.BasicEvaluator.ASTreeEx;
import chap6.BasicEvaluator.BlockEx;

@Require(BasicEvaluator.class)
@Reviser public class FuncEvaluator {
    @Reviser public static interface EnvEx extends Environment {
        void putNew(String name, Object value);
        Environment where(String name);
        void setOuter(Environment e);
    }
    @Reviser public static class DefStmntEx extends DefStmnt {
        public DefStmntEx(List<ASTree> c) { super(c); }
        public Object eval(Environment env) {
            ((EnvEx)env).putNew(name(), new Function(parameters(), body(), env));
            return name();
        }
    }
    @Reviser public static class PrimaryEx extends PrimaryExpr {
        public PrimaryEx(List<ASTree> c) { super(c); }
        public ASTree operand() { return child(0); }
        public Postfix postfix(int nest) {
            return (Postfix)child(numChildren() - nest - 1);
        }
        public boolean hasPostfix(int nest) { return numChildren() - nest > 1; } 
        public Object eval(Environment env) {
            return evalSubExpr(env, 0);
        }
        public Object evalSubExpr(Environment env, int nest) {
            if (hasPostfix(nest)) {
                Object target = evalSubExpr(env, nest + 1);
                return ((PostfixEx)postfix(nest)).eval(env, target);
            }
            else
                return ((ASTreeEx)operand()).eval(env);
        }
    }
    @Reviser public static abstract class PostfixEx extends Postfix {
        public PostfixEx(List<ASTree> c) { super(c); }
        public abstract Object eval(Environment env, Object value);
    }
    @Reviser public static class ArgumentsEx extends Arguments {
        public ArgumentsEx(List<ASTree> c) { super(c); }
        public Object eval(Environment callerEnv, Object value) {
            if (!(value instanceof Function))
                throw new StoneException("bad function", this);
            Function func = (Function)value;
            ParameterList params = func.parameters();
            if (size() != params.size())
                throw new StoneException("bad number of arguments", this);
            Environment newEnv = func.makeEnv();
            int num = 0;
            for (ASTree a: this)
                ((ParamsEx)params).eval(newEnv, num++,
                                        ((ASTreeEx)a).eval(callerEnv));
            return ((BlockEx)func.body()).eval(newEnv);
        }
    }
    @Reviser public static class ParamsEx extends ParameterList {
        public ParamsEx(List<ASTree> c) { super(c); }
        public void eval(Environment env, int index, Object value) {
            ((EnvEx)env).putNew(name(index), value);
        }
    }
}

7.8 Function.javaリスト

package chap7;
import stone.ast.BlockStmnt;
import stone.ast.ParameterList;
import chap6.Environment;

public class Function {
    protected ParameterList parameters;
    protected BlockStmnt body;
    protected Environment env;
    public Function(ParameterList parameters,BlockStmnt body,Environment env) {
        this.parameters = parameters;
        this.body = body;
        this.env = env;
    }
    
    public ParameterList parameters() {
        return parameters;
    }
    
    public BlockStmnt body() {
        return body;
    }
    
    public Environment makeEnv() {
        return new NestedEnv(env);
    }
    
    public String toString() {
        return "<fun:" + hashCode() + ">";
    }
}

7.9 Postfix.javaリスト

package stone.ast;
import java.util.List;

public class Postfix extends ASTList {

    public Postfix(List<ASTree> list) {
        super(list);
    }
}

7.4計算フィボナッチ

これまでのところ、石がサポートしている言語の関数は、関数を呼び出します。
プログラムコードインタプリタが7.10をされるリスト、
リスト7.11は、プログラムインタプリタを起動することです。
インタプリタはBasicEnvオブジェクトされていない環境が、NestedEnvオブジェクトの発売によって作成されたプログラム

ここでは、機能をテストするために、例えば、フィボナッチ関数呼び出しを計算します。7.12フィボナッチ証書をリストその数はストーン言語コンピュータプログラムによって書かれました。プログラム実行中に、第一の機能は、FIB、計算値とFIB(10)で定義されています。最後に、次の出力

=> fib
=> 55

7.10 FuncInterpreter.javaリスト

package chap6;
import stone.*;
import stone.ast.ASTree;
import stone.ast.NullStmnt;

public class BasicInterpreter {
    public static void main(String[] args) throws ParseException {
        run(new BasicParser(), new BasicEnv());
    }
    public static void run(BasicParser bp, Environment env)
        throws ParseException
    {
        Lexer lexer = new Lexer(new CodeDialog());
        while (lexer.peek(0) != Token.EOF) {
            ASTree t = bp.parse(lexer);
            if (!(t instanceof NullStmnt)) {
                Object r = ((BasicEvaluator.ASTreeEx)t).eval(env);
                System.out.println("=> " + r);
            }
        }
    }
}

7.11 FunRunner.javaリスト

package chap7;
import javassist.gluonj.util.Loader;

public class FuncRunner {
    public static void main(String[] args) throws Throwable {
        Loader.run(FuncInterpreter.class, args, FuncEvaluator.class);
    }
}

数の7.12計算フィボナッチストーン言語プログラムリスト

def fib(n) {
    if n < 2 {
        n
    } else {
        fib(n - 1) + fib(n - 2)
    }
}
fib(10)

7.5クロージャーのサポートを提供

簡単に言えば、クロージャは、変数に割り当てることができる特別な機能、他に渡されたパラメータの関数です。最も外側の層で定義された両方の閉鎖コードは、他の関数で定義することができます。一般的に、閉鎖は名前がありません

ストーンの言語サポートの閉鎖した場合、次のプログラムが正しく実行されます

inc = fun (x) { x + 1 }
inc(3)

このコードは、新たな機能を作成し、その役割は、受信された1つの比のパラメータの大きな値を返すことです。このパラメータは、変数株式会社に割り当てられます。クロージャは、変数に割り当てられています。株式会社は、実際には、この関数は名前がない、関数名ではありません。しかし、INCできるプログラムは、関数呼び出しのパラメータとしてフォーム(3)、及び3です。読者は、このクロージャを呼び出すためのパラメータとしてINCという変数から閉鎖、及び3を得るための手順として理解することができます

7.13をリスト文法規則の閉鎖です。定義されたクロージャを添加したプライマリを変更するルール、

7.13閉鎖文法規則のリスト

primary : " fun " param_list block | 原本的primary定义

クロージャの7.6実装

7.14パーサプログラムをリストクロージャー機能をサポートすることです。パーサが楽しいの初期閉鎖を解析できるように、それは、定義された主非終端を変更します。リスト7.15楽しいクラスは、ノードタイプの閉鎖抽象構文木で表現されます。

evalの方法楽しい上場クラスは7.16 ClosureEvaluator修飾によって増加します。そして、それは関数オブジェクトを作成するよう声明、デフのevalメソッド。コンストラクタ関数のenvオブジェクトは、閉じた形式と実行環境でパッケージを定義されたパラメータを受信する必要があります。

オブジェクトは、オブジェクトや関数名の右による環境へのファンクションキーを作成した後DEFステートメントが追加しましたが、あなたはクロージャを作成するときに、evalの方法は、直接オブジェクトを返します。結果として、ストーン言語は、閉鎖を達成するために、関数構文を変数に機能を割り当てる、または他の関数へのパラメータとして渡すことができるようになります。この場合、実際の変数への代入または関数オブジェクトに渡さを新た関数が作成されます。

7.14サポートをリストClosureParser.javaパーサ破裂します

package Stone;
import static Stone.Parser.rule;
import Stone.ast.Fun;

public class ClosureParser extends FuncParser {
    public ClosureParser() {
        primary.insertChoice(rule(Fun.class).sep("fun").ast(paramList).ast(block));
    }
}

7.15 Fun.javaリスト

package Stone.ast;
import java.util.List;

public class Fun extends ASTList {

    public Fun(List<ASTree> c) {
        super(c);
    }
    
    public ParameterList parameters() {
        return (ParameterList)child(0);
    }
    
    public BlockStmnt body() {
        return (BlockStmnt)child(1);
    }
    
    public String toString() {
        return "(fun " + parameters() + " " + body() + ")";
    }
}

7.16 ClosureEvaluator.javaリスト

package chap7;
import java.util.List;
import stone.ast.ASTree;
import stone.ast.Fun;
import chap6.Environment;
import javassist.gluonj.*;

@Require(FuncEvaluator.class)
@Reviser public class ClosureEvaluator {
    @Reviser public static class FunEx extends Fun {
        public FunEx(List<ASTree> c) {
            super(c);
        }
        
        public Object eval(Environment env) {
            return new Function(parameters(),body(),env);
        }
    }
}

7.17 ClosureInterpreter.javaリスト

package chap7;
import stone.ClosureParser;
import stone.ParseException;
import chap6.BasicInterpreter;

public class ClosureInterpreter extends BasicInterpreter {
    public static void main(String[] args) throws ParseException {
        run(new ClosureParser(),new NestedEnv());
    }
}

新しい関数はFunctionオブジェクト性能により添加しながら、ビューの特定の実装点の観点から、整数値Integerオブジェクトは、文字列オブジェクトがJavaのパフォーマンス、文字列性能があります。

7.17リストサポート閉鎖機能ストーン言語インタプリタです。7.18をリストすると、適切なスタートアップルーチンです

7.18 ClosureRunner.javaリスト

package chap7;

import javassist.gluonj.util.Loader;

public class ClosureRunner {
    public static void main(String[] args) throws Throwable {
        Loader.run(ClosureInterpreter.class, args, ClosureEvaluator.class);
    }
}

プログラムは、同じ言語の宣言のない支援機能とどこ閉鎖、石の言語および他の多くの変数がありますが、すでにグローバル変数が存在する場合、変数は、同じ名前の作成ではありませんが、次の例を言います

x = 1
def foo (i) {
    x = i;
    x + 1
}

関数fooは、xという名前のローカル変数を作成することはできません。最初の基準線Xにグローバル変数xの関数。あなたがfoo(3)を呼び出した場合は、グローバル変数xの値はトラブルになる可能性がある、3になります。ローカル変数を使用したい、グローバル変数の実際の使用は、ここに隠されたエラーの多くがあるように思われます。あなたが長い定義が変更されるように、2つを区別する必要がある場合は、そのグローバル変数$変数名は、ライン上で開始しなければならないこと

おすすめ

転載: www.cnblogs.com/ZCWang/p/12215862.html