gpt4 book ai didi

antlr - 我可以在运行时添加 Antlr token 吗?

转载 作者:行者123 更新时间:2023-12-04 03:09:35 26 4
gpt4 key购买 nike

我有一种情况,我的语言包含一些在构建时未知但在运行时已知的单词,导致需要不断重建/重新部署程序以考虑新单词。我在徘徊是否可以在 Antlr 中从配置文件生成一些 token ?

例如在一个简化的例子中,如果我有一个规则

rule : WORDS+;

WORDS : 'abc';

我的语言在运行时遇到了“bcd”,我希望能够修改配置文件以将 bcd 定义为一个词,而不必重新构建然后重新部署。

最佳答案

您可以向词法分析器类添加某种集合。该集合将保存所有运行时字。然后在规则中添加一些可能与这些运行时词匹配的自定义代码,并更改集合中存在的 token 类型。

演示

假设您要解析输入:

"foo bar baz"

在运行时,单词 "foo""baz"应该成为特殊的运行时词。以下语法显示了如何解决这个问题:

grammar RuntimeWords;

tokens {
RUNTIME_WORD;
}

@lexer::members {

private java.util.Set<String> runtimeWords;

public RuntimeWordsLexer(CharStream input, java.util.Set<String> words) {
super(input);
runtimeWords = words;
}
}

parse
: (w=. {System.out.printf("\%-15s :: \%s \n", tokenNames[$w.type], $w.text);})+ EOF
;

Word
: ('a'..'z' | 'A'..'Z')+
{
if(runtimeWords.contains(getText())) {
$type = RUNTIME_WORD;
}
}
;

Space
: ' ' {skip();}
;

还有一个小测试类:

import org.antlr.runtime.*;
import java.util.*;

public class Main {
public static void main(String[] args) throws Exception {
Set<String> words = new HashSet<String>(Arrays.asList("foo", "baz"));
ANTLRStringStream in = new ANTLRStringStream("foo bar baz");
RuntimeWordsLexer lexer = new RuntimeWordsLexer(in, words);
CommonTokenStream tokens = new CommonTokenStream(lexer);
RuntimeWordsParser parser = new RuntimeWordsParser(tokens);
parser.parse();
}
}

这将产生以下输出:
RUNTIME_WORD    :: foo 
Word :: bar
RUNTIME_WORD :: baz

演示二

这是另一个更适合您的问题的演示(一开始我过快地浏览了您的问题,但我将保留我的第一个演示,因为它可能对某人有用)。其中没有太多评论,但我的猜测是,您在理解发生的事情时不会有问题(如果没有,请不要犹豫,要求澄清!)。

grammar RuntimeWords;

@lexer::members {

private java.util.Set<String> runtimeWords;

public RuntimeWordsLexer(CharStream input, java.util.Set<String> words) {
super(input);
runtimeWords = words;
}

private boolean runtimeWordAhead() {
for(String word : runtimeWords) {
if(ahead(word)) {
return true;
}
}
return false;
}

private boolean ahead(String word) {
for(int i = 0; i < word.length(); i++) {
if(input.LA(i+1) != word.charAt(i)) {
return false;
}
}
return true;
}
}

parse
: (w=. {System.out.printf("\%-15s :: \%s \n", tokenNames[$w.type], $w.text);})+ EOF
;

Word
: {runtimeWordAhead()}?=> ('a'..'z' | 'A'..'Z')+
| 'abc'
;

Space
: ' ' {skip();}
;

和类(class):

import org.antlr.runtime.*;
import java.util.*;

public class Main {
public static void main(String[] args) throws Exception {
Set<String> words = new HashSet<String>(Arrays.asList("BBB", "CDEFG"));
ANTLRStringStream in = new ANTLRStringStream("BBB abc CDEFG");
RuntimeWordsLexer lexer = new RuntimeWordsLexer(in, words);
CommonTokenStream tokens = new CommonTokenStream(lexer);
RuntimeWordsParser parser = new RuntimeWordsParser(tokens);
parser.parse();
}
}

将产生:
Word            :: BBB 
Word :: abc
Word :: CDEFG

如果您的某些运行时词以另一个词开头,请小心。例如,如果您的运行时词包含 "stack""stacker" ,你想先检查较长的单词!根据字符串的长度对集合进行排序应该是有序的。

最后提醒一句:如果只有 "stack"在您的运行时单词列表中,词法分析器遇到 "stacker" ,那么您可能不想创建 "stack" -token 离开 "er"悬空。在这种情况下,您需要检查 word 中最后一个字符之后的字符是否为不是字母:

private boolean ahead(String word) {
for(int i = 0; i < word.length(); i++) {
if(input.LA(i+1) != word.charAt(i)) {
return false;
}
}
// charAfterWord = input.LA(word.length())
// assert charAfterWord != letter
// note that charAfterWord could also be EOF
return ... ;
}

关于antlr - 我可以在运行时添加 Antlr token 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6108293/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com