gpt4 book ai didi

c# - 我如何在 ANTLR 中实现将两个节点合二为一的解析器规则?

转载 作者:太空宇宙 更新时间:2023-11-03 14:09:24 25 4
gpt4 key购买 nike

以下解析器规则的第二个选择 ((1-9)(0-9)) 在抽象语法树中产生两个节点。

oneToHundred
: ('1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9')
| ('1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9')('0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9')
| '100'
;

(side node: 将数字“Lexing”到 Digit-Tokens 中对我不适用,因为有时像 2-4 这样的 0-9 的子范围可以代表某事. 与数字非常不同(顺便说一句,我无法影响)。)

所以对于 15,我得到两个节点 1 和 5,而不是 15,但我想将其作为一个节点表示的一个数字。

我无法在 token 级别使用词法分析器执行此操作,因为这取决于上下文,例如15 可能意味着两个截然不同的事物,要么是“一个符号和一个五个符号”(绝对应该是两个节点),要么是“十五”和 according to this post 上下文敏感应该留给解析器。


(编辑澄清:)

上下文敏感示例:

输入应该分开/用分号分隔

Input:
11;2102;34%;P11o

this would be split into four parts and
11 - would not be a number but one '1'-symbol and another '1'-symbol
2102 - would not be a number but: '2'-symbol '1'-symbol '0'-symbol '2'-symbol
34% - now here 34 would be the number thirtyfour
P11o: 'P'-symbol '1'-symbol '1'-symbol 'o'-symbol

在这四个 block 中,34% 将被解析器规则识别为百分比 block ,而其他 block 将被识别为符号 block 。所以 AST 应该看起来像这样:

SYMBOL
1
1
SYMBOL
2
1
0
2
PERCENT
34
SYMBOL
P
1
1
o

目标是 C#:

options {
language=CSharp3;
output=AST;
}

我是 Antlr 菜鸟,那么有没有一种好方法可以将这两个节点与解析器合并,或者我最好添加一个虚构的标记并在解析后在 C# 中“手动”连接两个数字?

最佳答案

您的解析器规则:

oneToHundred
: ('1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9')
| ('1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9')('0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9')
| '100'
;

在幕后隐式创建以下 token :

D_1_9 : ('1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9');
D_0_9 : ('0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9');
D_100 : '100';

(不是那些规则名称,而是它们匹配的内容创建的)

因此,如果您的词法分析器将获得输入 "11",则会创建两个 D_1_9 标记,并从 oneToHundred 规则将无法匹配(此替代方案需要两个标记:D_1_9 D_0_9)。

您必须意识到词法分析器独立于解析器运行。解析器向词法分析器“询问”什么类型的标记并不重要:词法分析器有它自己的规则优先级导致 '1'|'2'|'3'|'4'|'5'|' 6'|'7'|'8'|'9' 永远不会被 D_0_9 规则匹配(因为它出现在之后 D_1_9 规则)。


编辑

让我们将您的输入称为 11;2102;34%;P11o,四个单元由每个 atom 组成(其中一个 atom 是字母或数字)可能以 '%' 结尾:

unit
: atoms '%'?
;

如果它以 '%' 结尾,您只需使用重写规则创建一个以 PERCENT 为根的树,否则只需创建一个带有 的树SYMBOL 作为 root:

unit
: (atoms -> ^(/* SYMBOL */)) ('%' -> ^( /* PERCENT */))?
;

一个工作演示:

grammar T;

options {
output=AST;
ASTLabelType=CommonTree;
}

tokens {
ROOT;
SYMBOL;
PERCENT;
NUMBER;
}

parse
: unit (';' unit)* EOF -> ^(ROOT unit+)
;

unit
: (atoms -> ^(SYMBOL atoms))
('%' -> ^(PERCENT {new CommonTree(new CommonToken(NUMBER, $atoms.text))}))?
;

atoms
: atom+
;

atom
: Letter
| Digit
;

Digit : '0'..'9';
Letter : 'a'..'z' | 'A'..'Z';

您可以使用以下类测试解析器:

import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;
import org.antlr.stringtemplate.*;

public class Main {
public static void main(String[] args) throws Exception {
TLexer lexer = new TLexer(new ANTLRStringStream("11;2102;34%;P11o"));
TParser parser = new TParser(new CommonTokenStream(lexer));
CommonTree tree = (CommonTree)parser.parse().getTree();
DOTTreeGenerator gen = new DOTTreeGenerator();
StringTemplate st = gen.toDOT(tree);
System.out.println(st);
}
}

这将产生对应于以下 AST 的 DOT 输出:

enter image description here

在上图中,所有叶子的类型都是LetterDigit,除了"34",它的类型是NUMBER.

关于c# - 我如何在 ANTLR 中实现将两个节点合二为一的解析器规则?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8289762/

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