javaantlr如何忽略部分规则?忽略子规则后的部分

dzjeubhm  于 2021-07-09  发布在  Java
关注(0)|答案(1)|浏览(337)

我正在尝试使用antlr和java创建一个编译器。我有一个问题,我有一个规则,我不能得到只是它的一部分使用。我有一个命令,例如0:halt0,0,0,我想在那之后忽略其他的一切。
e、 g.0:停下,等等,等等,等等,等等,我想忽略这些
我的规则是:

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

亚历克斯

jq6vz3qz

jq6vz3qz1#

这条规则有几个地方有问题:

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

在解析器规则中 ~ 否定lexer生成的整个标记集。所以呢 ~('\n'|'\r') 不匹配除 '\n' 或者 '\r' . 它匹配除匹配的令牌之外的任何令牌 \r 或者 \n .
还有,既然你的雷克瑟 '\n' 以及 '\r' 在隐藏通道上,这些令牌在解析器中不可用。这意味着 '\n'rest 规则永远无法匹配。
简而言之:你不能“告诉”你的解析器一行的结尾是什么,因为这些字符被你的解析器丢弃了 WS 规则。这意味着你没有办法正确地写这样一篇文章 rest 分析器规则。
供您输入:

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

(请注意,我删除了 'rule:' 的)
以下令牌由lexer生成:

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' 无法与lexer匹配,通过查看错误可以看出:

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

一个可能的解决方案是创建一个匹配整数和冒号的lexer规则:

START : INTEGER ':';

让你的 rule 从以下令牌开始:

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

那样,你的 rest 可以匹配零个或多个令牌 START 代币:

rest
 : ~START*
 ;

为了抓住 '=' 以及 'r' 角色,创建 ANY 规则并将此规则放在lexer规则的末尾:

ANY : . ; // match any char

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

另一个解决方案是创建一个 LINE_BREAK 代币:

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

(并移除 \r 以及 \nWS ,当然!)
然后这样做:

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

rest
 : ~LINE_BREAK*
 ;

相关问题