C# 如何在ANTLR中实现将两个节点合并为一个节点的解析器规则?

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)可以表示与数字非常不同的内容

以下解析器规则的第二个备选方案((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)可以表示与数字非常不同的内容(顺便说一句,我无法影响)

所以对于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';