任意顺序的 ANTLR 命名函数参数/参数

发布于 2024-08-14 00:34:00 字数 384 浏览 1 评论 0原文

我一直在寻找一种方法让命名函数参数/参数以任意顺序出现在 ANTLR 中。有谁知道 ANTLR 解析器表达式中是否存在忽略顺序的语法?

假设该语言中有一个函数 foo,它可以采用两个命名参数:xy。由于它们是命名参数,我希望它们能够以任何顺序传递到函数中:

foo(x=1, y=2)

并且

foo(y=2, x=1)

两者都应该是合法的。

我可以只列出 ANTLR 中的所有参数排列,但我希望有一个更优雅的解决方案,特别是因为我有一些可以接受 5 个参数的函数。

任何帮助将不胜感激!

I'm been looking for a way to have named function arguments / parameters appear in any order in ANTLR. Does anyone know if there is syntax to ignore order in an ANTLR parser expression?

Say there is a function foo in the language that can take two named parameters: x and y. Since they are named parameters, I'd like them to be able to be passed into the function in any order:

foo(x=1, y=2)

as well as

foo(y=2, x=1)

should both be legal.

I could just list all the parameter permutations in ANTLR, but I was hoping there would be a more elegant solution, especially since I have some functions that can take 5 parameters.

Any help would be greatly appreciated!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

錯遇了你 2024-08-21 00:34:00

我很确定 ANTLR 中没有内置任何东西来处理这个问题。但是您可以简单地在语法中加入一些常规编程逻辑来重新组织参数。

这是一个小演示语法:

grammar NF;

@parser::header {
    package antlrdemo;
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.Arrays;
}

@lexer::header {
    package antlrdemo;
}

parse   :   concat+
        ;

concat  :   'concat' '(' k1=Key '=' v1=Value ',' k2=Key '=' v2=Value ',' k3=Key '=' v3=Value ')' {
                HashMap<String, String> params = new HashMap<String, String>();
                params.put($k1.text, $v1.text);
                params.put($k2.text, $v2.text);
                params.put($k3.text, $v3.text);
                HashSet<String> expected = new HashSet<String>(Arrays.asList(new String[]{"a", "b", "c"}));
                if(!params.keySet().equals(expected)) {
                    throw new RuntimeException("No soup for you!");
                }
                System.out.println(params.get("a")+params.get("b")+ params.get("c"));
            }
        ;

Key     :   ('a'..'z')+
        ;

Value   :   ('a'..'z' | 'A'..'Z' | '0'..'9')+
        ;

Space   :   (' ' | '\t' | '\r' | '\n'){$channel = HIDDEN;}
        ;

以及一个用于测试它的小类:

package antlrdemo;

import org.antlr.runtime.*;

public class NFDemo {

    static void test(String source) throws RecognitionException {
        ANTLRStringStream in = new ANTLRStringStream(source);
        NFLexer lexer = new NFLexer(in);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        NFParser parser = new NFParser(tokens);
        System.out.print(source+" -> ");
        parser.parse();
    }

    public static void main(String[] args) throws RecognitionException {
        test("concat(a=1, b=2, c=3)");
        test("concat(b=2, c=3, a=1)");
        test("concat(c=3, a=1, b=2)");
        test("concat(c=3, a=1, x=2)");
    }
}

它会产生输出:

concat(a=1, b=2, c=3) -> 123
concat(b=2, c=3, a=1) -> 123
concat(c=3, a=1, b=2) -> 123
concat(c=3, a=1, x=2) -> Exception in thread "main" java.lang.RuntimeException: No soup for you!
    at antlrdemo.NFParser.concat(NFParser.java:137)
    at antlrdemo.NFParser.parse(NFParser.java:70)
    at antlrdemo.NFDemo.test(NFDemo.java:13)
    at antlrdemo.NFDemo.main(NFDemo.java:20)

I'm pretty sure there is nothing built in ANTLR to handle this. But you can simple sprinkle some regular programming logic in your grammar to reorganize the parameters.

Here's a little demo grammar:

grammar NF;

@parser::header {
    package antlrdemo;
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.Arrays;
}

@lexer::header {
    package antlrdemo;
}

parse   :   concat+
        ;

concat  :   'concat' '(' k1=Key '=' v1=Value ',' k2=Key '=' v2=Value ',' k3=Key '=' v3=Value ')' {
                HashMap<String, String> params = new HashMap<String, String>();
                params.put($k1.text, $v1.text);
                params.put($k2.text, $v2.text);
                params.put($k3.text, $v3.text);
                HashSet<String> expected = new HashSet<String>(Arrays.asList(new String[]{"a", "b", "c"}));
                if(!params.keySet().equals(expected)) {
                    throw new RuntimeException("No soup for you!");
                }
                System.out.println(params.get("a")+params.get("b")+ params.get("c"));
            }
        ;

Key     :   ('a'..'z')+
        ;

Value   :   ('a'..'z' | 'A'..'Z' | '0'..'9')+
        ;

Space   :   (' ' | '\t' | '\r' | '\n'){$channel = HIDDEN;}
        ;

And a little class to test it:

package antlrdemo;

import org.antlr.runtime.*;

public class NFDemo {

    static void test(String source) throws RecognitionException {
        ANTLRStringStream in = new ANTLRStringStream(source);
        NFLexer lexer = new NFLexer(in);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        NFParser parser = new NFParser(tokens);
        System.out.print(source+" -> ");
        parser.parse();
    }

    public static void main(String[] args) throws RecognitionException {
        test("concat(a=1, b=2, c=3)");
        test("concat(b=2, c=3, a=1)");
        test("concat(c=3, a=1, b=2)");
        test("concat(c=3, a=1, x=2)");
    }
}

which produces the output:

concat(a=1, b=2, c=3) -> 123
concat(b=2, c=3, a=1) -> 123
concat(c=3, a=1, b=2) -> 123
concat(c=3, a=1, x=2) -> Exception in thread "main" java.lang.RuntimeException: No soup for you!
    at antlrdemo.NFParser.concat(NFParser.java:137)
    at antlrdemo.NFParser.parse(NFParser.java:70)
    at antlrdemo.NFDemo.test(NFDemo.java:13)
    at antlrdemo.NFDemo.main(NFDemo.java:20)
暖风昔人 2024-08-21 00:34:00

明白了...

如果您想在语法中硬连线“foo”,“x”和“y”,请执行以下操作(未编译/测试,但应该给出想法)

foo :
    { SomeType x=null, y=null; }
    'foo' '('
      (     'x' '=' {if (x != null) throw ...;} x=value
      |     'y' '=' {if (y != null) throw ...;} y=value
      )*
    ')'
    { if (x = null || y == null) throw ...; }
    ;

如果您想要更大的灵活性(以支持其他功能) ,按照巴特的建议做一些事情。

Gotcha...

If you want to hardwire "foo", "x" and "y" in your grammar, do the following (not compiled/tested, but should give the idea)

foo :
    { SomeType x=null, y=null; }
    'foo' '('
      (     'x' '=' {if (x != null) throw ...;} x=value
      |     'y' '=' {if (y != null) throw ...;} y=value
      )*
    ')'
    { if (x = null || y == null) throw ...; }
    ;

If you want more flexibility (to support other functions), do something like Bart's suggestion.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文