1

I have been working through the tutorial at http://bkiers.blogspot.de/2011/03/creating-your-own-programming-language.html. In short, a small language is developed that has a minimal set of arithmetic operations. "println" and "print" are directly mapped functions that call System.out.print().

From this I am trying to implement my own DSL by changing some properties of the language that has been developed in that article series. I want to make java.lang.Math accessible from within my DSL, but can't think of a good way without having to map each function manually.

The language does not support imports whatsoever. I could introduce a new grammar rule to match 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)。你甚至可以用这种方式对函数(a,b) 进行类型检查——如果 java.lang.Math.function(a,b) 不存在(反射这么说),你会记录类型检查错误。

这样,只有一个规则就足够了(doMath)。

在任何情况下,祝你好运;)

于 2012-04-23T14:06:49.917 回答