C# 如何在ANTLR中实现将两个节点合并为一个节点的解析器规则?
以下解析器规则的第二个备选方案((1-9)(0-9))在抽象语法树中产生两个节点。C# 如何在ANTLR中实现将两个节点合并为一个节点的解析器规则?,c#,antlr,antlr3,C#,Antlr,Antlr3,以下解析器规则的第二个备选方案((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' ; (侧节点:将数字“词法化”为数字标记不适用于我,因为有时0-9的子范围(如2-4)可以表示与数字非常不同的内容
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'
;
(侧节点:将数字“词法化”为数字标记不适用于我,因为有时0-9的子范围(如2-4)可以表示与数字非常不同的内容(顺便说一句,我无法影响)
所以对于15,我得到了两个节点1和5,而不是15,但我想把它作为一个节点表示的一个数字
我不能在标记级别上使用lexer,因为根据上下文(例如15)可能意味着两个非常不同的东西,“一个符号和五个符号”(肯定应该是两个节点)或“十五”,上下文敏感性应该留给解析器
(编辑澄清:) 上下文敏感度示例: 输入应分开/用分号分隔
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
在这四个块中,34%将被解析器规则识别为百分比块,而其他块将被识别为符号块。所以AST应该是这样的:
SYMBOL
1
1
SYMBOL
2
1
0
2
PERCENT
34
SYMBOL
P
1
1
o
目标是C#: 我是一个Antlr noob,那么有没有一种好方法可以将这两个节点与解析器合并,或者在解析后添加一个虚构的标记并在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'
;
在幕后隐式创建以下令牌:
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';
(不使用这些规则名称,但将创建它们匹配的内容)
因此,如果您的lexer将获得输入“11”
,将创建两个D_1_9
令牌,并且将无法匹配oneToHundred
规则中的第二个备选方案(此备选方案需要两个令牌:D_1_9 D_0_9
)
您必须认识到lexer独立于解析器运行。解析器“询问”词法分析器的标记类型并不重要:词法分析器有自己的规则优先级,导致'1''2''3''4''5''6''7''8''9'
永远不会与D|0|9
规则匹配(因为它在D|1|9
规则之后)
编辑 让我们调用您的输入,
11;2102;34%;P11o
,四个单元,每个单元由原子组成(其中原子是字母或数字),可能以“%”结尾:
单位
:原子“%”?
;
如果以'%'
结尾,只需使用重写规则创建一个以百分比作为根的树,否则只需创建一个以符号作为根的树:
单位
:(原子->^(/*SYMBOL*/)('%'->^(/*PERCENT*/)?
;
工作演示:
语法T;
选择权{
输出=AST;
ASTLabelType=CommonTree;
}
代币{
根;
象征;
百分比
数量;
}
作语法分析
:单位(“;”单位)*EOF->^(根单位+)
;
单元
:(原子->^(符号原子))
('%'->^(百分比{new CommonTree(new CommonToken(NUMBER,$atoms.text))})?
;
原子
:原子+
;
原子
字体字母
|数字
;
数字:“0”…'9';
字母:'a'..'z'|'a'..'z';
可以使用以下类测试解析器:
import org.antlr.runtime.*;
导入org.antlr.runtime.tree.*;
导入org.antlr.stringtemplate.*;
公共班机{
公共静态void main(字符串[]args)引发异常{
TLexer lexer=新的TLexer(新的AntlStringStream(“11;2102;34%;P11o”);
TParser parser=newtparser(newcommontokenstream(lexer));
CommonTree=(CommonTree)parser.parse().getTree();
DOTTreeGenerator gen=新的DOTTreeGenerator();
StringTemplate st=gen.toDOT(树);
系统输出打印LN(st);
}
}
将产生对应于以下AST的点输出:
在上图中,所有的叶子都是字母
或数字
,除了“34”
类型是数字
,非常感谢您的回答“隐式令牌创建”部分已经帮助我更好地理解了这一点。至于“简单地在你的Lexer部分匹配一个数字”,我不确定我是否正确理解你,因为我认为这根本不能解决我的上下文敏感问题(我问题的第三段),这是我问题的核心。我想,仅仅提到一条解析器规则,我并没有非常清楚地说明我将添加一个示例以进行澄清。
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';