gpt4 book ai didi

antlr4 - 解析器中的重新定义标记类型

转载 作者:行者123 更新时间:2023-12-02 22:18:58 25 4
gpt4 key购买 nike

需要为 COS aka MUMPS 实现语法高亮显示
用于可能设计形式的语言

new (new,set,kill)
set kill=new

其中:'new'和'set'是命令,也是变量

grammar cos;

Command_KILL :( ('k'|'K') | ( ('k'|'K')('i'|'I')('l'|'L')('l'|'L') ) );
Command_NEW :( ('n'|'N') | ( ('n'|'N')('e'|'E')('w'|'W') ) );
Command_SET :( ('s'|'S') | ( ('s'|'S')('e'|'E')('t'|'T') ) );


INT : [0-9]+;
ID : [a-zA-Z][a-zA-Z0-9]*;
Space: ' ';
Equal: '=';

newCommand
: Command_NEW Space ID
;
setCommand
: Command_SET Space ID Space* Equal Space* INT
;

我有一个问题,当 ID 像名称一样作为命令时(NEW、SET 等)

最佳答案

根据维基百科页面,MUMPS 没有保留字:

Reserved words: None. Since MUMPS interprets source code by context, there is no need for reserved words. You may use the names of language commands as variables.

Command_KILL 等 Lexer 规则的功能与保留字完全相同:它们旨在确保在遇到输入 “kill” 时不会生成其他标记。因此 token 类型 Command_KILL 将始终在 "kill" 上生成,即使它旨在成为标识符。如果需要,您可以保留命令词法分析器规则,但您也必须像对待 ID 一样对待它们,因为您只是不知道单独基于 token 的 "kill" 指的是什么。

在 ANTLR 中实现 MUMPS 意味着关注 token 的使用和上下文而不是 token 类型。考虑这个语法:

grammar Example;


document : (expr (EOL|EOF))+;
expr : command=ID Space+ value (Space* COMMA Space* value)* #CallExpr
| command=ID Space+ name=ID Space* Equal Space* value #SetExpr
;

value : ID | INT;

INT : [0-9]+;
ID : [a-zA-Z][a-zA-Z0-9]*;
Space : ' ';
Equal : '=';
EOL : [\r\n]+;
COMMA : ',';

解析器规则 expr 知道何时 ID 标记是基于整行布局的命令。

  • 如果输入的标记是ID ID,那么输入是一个CallExpr:第一个ID是命令名,第二个ID 是常规标识符。
  • 如果输入标记是 ID ID Equal ID,那么输入是一个 SetExpr:第一个 ID 将是一个命令(要么"set" 或类似的东西),第二个ID 是目标标识符,第三个ID 是源标识符。

这是一个 Java 测试应用程序,后面是一个类似于您问题中提到的测试用例。

import java.util.List;

import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;

public class ExampleTest {

public static void main(String[] args) {

ANTLRInputStream input = new ANTLRInputStream(
"new new, set, kill\nset kill = new");

ExampleLexer lexer = new ExampleLexer(input);

ExampleParser parser = new ExampleParser(new CommonTokenStream(lexer));

parser.addParseListener(new ExampleBaseListener() {
@Override
public void exitCallExpr(ExampleParser.CallExprContext ctx) {
System.out.println("Call:");
System.out.printf("\tcommand = %s%n", ctx.command.getText());
List<ExampleParser.ValueContext> values = ctx.value();
if (values != null) {
for (int i = 0, count = values.size(); i < count; ++i) {
ExampleParser.ValueContext value = values.get(i);
System.out.printf("\targ[%d] = %s%n", i,
value.getText());
}
}
}

@Override
public void exitSetExpr(ExampleParser.SetExprContext ctx) {
System.out.println("Set:");
System.out.printf("\tcommand = %s%n", ctx.command.getText());
System.out.printf("\tname = %s%n", ctx.name.getText());
System.out.printf("\tvalue = %s%n", ctx.value().getText());
}

});

parser.document();
}
}

输入

new new, set, kill
set kill = new

输出

Call:
command = new
arg[0] = new
arg[1] = set
arg[2] = kill
Set:
command = set
name = kill
value = new

由调用代码确定命令在给定上下文中是否有效。由于 MUMPS 对命令和标识符的松散方法,解析器无法合理地处理这个问题。但这并不像听起来那么糟糕:您将知道哪些命令的功能类似于调用,哪些功能类似于集合,因此您将能够测试来自 ANTLR 生成的 Listener 的输入.例如,在上面的代码中,很容易测试“set”是否是传递给 exitSetExpr 的命令。

一些 MUMPS 语法可能比这更难处理,但一般方法是相同的:让词法分析器像处理 ID 一样处理命令和标识符,并使用解析器规则来确定是否ID 是指基于整行上下文的命令或标识符。

关于antlr4 - 解析器中的重新定义标记类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14014386/

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