【问题标题】:Java ANTLR how to ignore part of rule? ignore part after subruleJava ANTLR 如何忽略部分规则?忽略子规则后的部分
【发布时间】:2012-08-24 17:58:57
【问题描述】:

我正在尝试使用 ANTLR 和 Java 创建编译器。我有这个问题,我有一个规则,我不能只使用它的一部分。我有一个命令,例如0:HALT 0,0,0,之后我想忽略其他所有内容。

e.g.0: HALT 0,0,0 blah blah blah,我想忽略 blah blah blah

我的规则是:

    rule returns [String value]
    :
    INTEGER':' ro=rocommand i1=INTEGER',' i2=INTEGER ',' i3=INTEGER rest {$value = $ro.text+" "+$i1.text+","+$i2.text+","+$i3.text;   }
    | INTEGER':' rm=rmcommand j1=INTEGER ',' j2=INTEGER '('j3=INTEGER')' rest {$value = $rm.text+" "+$j1.text+","+$j2.text+"("+$j3.text+")"; }
;

我的代码是:

CharStream charStream = new ANTLRStringStream(strLine);
simulatorLexer lexer = new simulatorLexer(charStream);
TokenStream tokenStream = new CommonTokenStream(lexer);
simulatorParser parser = new simulatorParser(tokenStream);
System.out.println(parser.rule());

我得到的是:

0: rule:IN 0,0,0
1: rule:LDC 1,1,0
line 1:15 no viable alternative at character 'r'
line 1:18 no viable alternative at character '='
line 1:15 no viable alternative at character 'i'

对于正文:

0: rule:IN 0,0,0
1: rule:LDC 1,1,0 r1=0

所以它应该正确解析第一行和第二行直到 0。然后它应该忽略 r1=0。到目前为止它工作正常,但它显示了许多错误,我想摆脱它们。请帮帮我!

编辑

我正在发布整个语法,以便您可以更好地帮助我。我只想认清规则部分。

program:
    rule+
;


rocommand:
    'HALT'|'IN'|'OUT'|'ADD'|'SUB'|'MUL'|'DIV'|'LDC'
;

rmcommand:
    'LD'|'LDA'|'LDC'|'ST'|'JLT'|'JLE'|'JGE'|'JGT'|'JEQ'|'JNE' 
;

rest:
  ~('\n'|'\r')* '\r'? ('\n'|EOF)
;

rule returns [String value]
    :
    INTEGER':' ro=rocommand i1=INTEGER',' i2=INTEGER ',' i3=INTEGER rest {$value = $ro.text+" "+$i1.text+","+$i2.text+","+$i3.text;   }
    | INTEGER':' rm=rmcommand j1=INTEGER ',' j2=INTEGER '('j3=INTEGER')' rest {$value = $rm.text+" "+$j1.text+","+$j2.text+"("+$j3.text+")"; }
;

WS  : (' '|'\r'|'\t'|'\u000C'|'\n') {$channel=HIDDEN;};
INTEGER : '0'..'9'+;
IGNORELINE : '*' ~('\n'|'\r')* '\r'? '\n' {$channel=HIDDEN;};

【问题讨论】:

  • 您能否发布一个自包含语法,以便我(或其他人)可以针对您的输入运行生成的解析器?如果不了解更多语法,就不可能知道哪里出了问题。
  • 是的,你是对的,我刚刚编辑了原始帖子并发布了我的语法。希望你能帮助我,谢谢!

标签: java antlr rules


【解决方案1】:

这个规则有几个问题:

rest:
  ~('\n'|'\r')* '\r'? ('\n'|EOF)
;

在解析器规则中,~ 否定词法分析器生成的整个标记集。所以~('\n'|'\r') 匹配'\n''\r' 以外的单个字符。它匹配除匹配\r\n 的令牌之外的任何令牌

此外,由于您的词法分析器将 '\n''\r' 放在隐藏通道上,因此这些标记在您的解析器中将不可用。这意味着rest 规则中的'\n' 永远无法匹配。

简而言之:你不能“告诉”你的解析器一行的结尾是什么,因为这些字符被你的WS 规则丢弃了。这意味着您无法正确编写这样的rest 解析器规则。

供您参考:

0: IN 0,0,0
1: LDC 1,1,0 r1=0

(注意我删除了'rule:''s)

以下标记由您的词法分析器生成:

token[type=INTEGER text='0']
token[type=':'     text=':']
token[type='IN'    text='IN']
token[type=INTEGER text='0']
token[type=','     text=',']
token[type=INTEGER text='0']
token[type=','     text=',']
token[type=INTEGER text='0']
token[type=INTEGER text='1']
token[type=':'     text=':']
token[type='LDC'   text='LDC']
token[type=INTEGER text='1']
token[type=','     text=',']
token[type=INTEGER text='1']
token[type=','     text=',']
token[type=INTEGER text='0']
token[type=INTEGER text='1']
token[type=INTEGER text='0']

所以这些是您的解析器规则中可用的标记。

请注意以下两个字符:'=''r' 无法被词法分析器匹配,您可以通过查看错误看到:

line 2:13 no viable alternative at character 'r'
line 2:15 no viable alternative at character '='

一种可能的解决方案是创建一个匹配整数和冒号的词法分析器规则:

START : INTEGER ':';

让你的rule 以这个令牌开头:

rule
 : START ro=rocommand i1=INTEGER ',' i2=INTEGER ',' i3=INTEGER rest ...
 | ...
 ;

这样,您的rest 可以匹配除START 标记之外的零个或多个标记:

rest
 : ~START*
 ;

要捕获'=''r' 字符,请创建ANY 规则并将此规则放在词法分析器规则的末尾:

ANY : . ; // match any char

这样,解析器将创建以下解析树:

另一种解决方案是创建一个LINE_BREAK 令牌:

LINE_BREAK : '\r'? '\n' | '\r';

(当然要从WS 中删除\r\n!)

然后做这样的事情:

rule
 : INTEGER ':' ro=rocommand i1=INTEGER ',' i2=INTEGER ',' i3=INTEGER rest LINE_BREAK ...
 | ...
 ;

rest
 : ~LINE_BREAK*
 ;

【讨论】:

  • 您先生,是我的英雄!谢谢十亿!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-02-03
  • 1970-01-01
  • 2013-08-24
  • 2020-10-27
  • 1970-01-01
  • 2023-03-25
  • 1970-01-01
相关资源
最近更新 更多