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

时间:2011-11-27 22:52:23

标签: 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一样可以代表一个非常不同的数字(这是我无法影响的。)

所以对于15我得到两个节点一个和五个而不是十五个但我想把它作为一个节点所代表的一个数字。

我不能使用令牌级别的词法分析器,因为在上下文中依赖 ,例如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

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

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

目标是C#:

options {
  language=CSharp3;
  output=AST;
}

我是一个Antlr-noob,所以有没有一个很好的方法将这两个节点与解析器合并,或者我最好在解析后添加一个虚构的令牌并在C#中“手动”连接两个数字?

1 个答案:

答案 0 :(得分:1)

您的解析器规则:

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';

(不是那些规则名称,但是匹配的内容

因此,如果您的词法分析器将获得输入"11",则会创建两个D_1_9标记,并且oneToHundred规则中的2 nd 替代将不会能够匹配(此替代方案需要两个令牌: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,每个atoms组成四个单位(其中atom可以是字母或数字),可能以'%'结尾:< / p>

unit
  :  atoms '%'?
  ;

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

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除外。