1

私はhttp://bkiers.blogspot.de/2011/03/creating-your-own-programming-language.htmlでチュートリアルを進めてきました。要するに、最小限の算術演算のセットを持つ小さな言語が開発されています。「println」と「print」は、を呼び出す直接マップされた関数ですSystem.out.print()

このことから、その一連の記事で開発された言語のいくつかのプロパティを変更することにより、独自のDSLを実装しようとしています。java.lang.MathDSL内からアクセスできるようにしたいのですが、各関数を手動でマップする必要がない限り、良い方法を考えることはできません。

この言語はインポートをまったくサポートしていません。に一致する新しい文法規則を導入できMath.<function>(<parameters>)ます。

4

2 に答える 2

1

これを行うにはMath、予約語を作成し、次の変更を加えます。

文法の追加

functionCall
  :  Identifier '(' exprList? ')'         -> ^(FUNC_CALL Identifier exprList?)
  |  Println '(' expression? ')'          -> ^(FUNC_CALL Println expression?)
  |  Print '(' expression ')'             -> ^(FUNC_CALL Print expression)
  |  Assert '(' expression ')'            -> ^(FUNC_CALL Assert expression)
  |  Size '(' expression ')'              -> ^(FUNC_CALL Size expression)
  |  Math '.' Identifier '(' exprList ')' -> ^(FUNC_CALL Math Identifier exprList) // added
  ;

// ...

Math : 'Math'; // added

ツリー文法の追加

functionCall returns [TLNode node]
  :  ^(FUNC_CALL Identifier exprList?)     {node = new FunctionCallNode($Identifier.text, $exprList.e, functions);}
  |  ^(FUNC_CALL Println expression?)      {node = new PrintlnNode($expression.node);}
  |  ^(FUNC_CALL Print expression)         {node = new PrintNode($expression.node);}
  |  ^(FUNC_CALL Assert expression)        {node = new AssertNode($expression.node);}
  |  ^(FUNC_CALL Size expression)          {node = new SizeNode($expression.node);}
  |  ^(FUNC_CALL Math Identifier exprList) {node = new MathCallNode($Identifier.text, $exprList.e);} // added
  ;

新しい数学ノードクラス

package tl.tree;

import tl.TLValue;
import java.util.ArrayList;
import java.util.List;

public class MathCallNode implements TLNode {

    private String methodName;
    private List<TLNode> params;

    public MathCallNode(String nm, List<TLNode> ps) {
        methodName = nm;
        params = ps;
    }

    @Override
    public TLValue evaluate() {
        if(methodName.equals("sqrt")) 
            return new TLValue(Math.sqrt(params.get(0).evaluate().asDouble()));
        else if(methodName.equals("min")) 
            return new TLValue(Math.min(params.get(0).evaluate().asDouble(), params.get(1).evaluate().asDouble()));  
        // TODO implement more Math-methods
        else
            throw new RuntimeException("unknown method: Math." + methodName + "(...)");
    }
}

これで、すべての個別のメソッドを独自のクラスに実装する必要はありませんが、もちろん、のevaluate()メソッドで呼び出されるメソッドを確認する必要がありMathCallNodeます。

今評価する場合:

println(Math.sqrt(9));
println(Math.min(9, -42));

以下が印刷されます。

3.0
-42.0
于 2012-04-23T20:42:31.230 に答える
0

確かにもっと洗練された方法がありますが、doMath( "function(a、b)")を使用して、リフレクションを使用して、生成されたコードでfunction(a、b)を呼び出すことができます。この方法でfunction(a、b)をタイプチェックすることもできます-java.lang.Math.function(a、b)が存在しなかった場合(リフレクションはそう言う)、タイプチェックエラーをログに記録します。

このように、1つのルールだけで十分です(doMath)。

いずれの場合も幸運を祈ります;)

于 2012-04-23T14:06:49.917 に答える