ANTLR语法如何捕获所有字符到行尾

时间:2012-02-28 10:16:28

标签: c# antlr

我正在尝试捕获看起来像的命令 _SC弹钢琴1 到一个有3个节点的树“_SC”“play”和“Piano 1”

我到目前为止的语法是

grammar PBScript;
options {
output = AST;
language = CSharp2;
}

line    :       COMMAND WS ACTION;
COMMAND :   '_SC';
ACTION  :   'play';
WS  :   (' '|'\t')+ ;

当我创建另一条规则以捕捉“钢琴1”部分时,如下:

grammar PBScript;
options {
output = AST;
language = CSharp2;
}

line    :       COMMAND WS ACTION WS PARAMETER;
COMMAND :   '_SC';
ACTION  :   'play';
WS  :   (' '|'\t')+;
PARAMETER
    :       (~('\n'|'\r'))+ ;

我得到一个MismatchedTokenException(6!= 5)。我知道语法是错的,我知道为什么它是错的。这是不明确的,因为WS与PARAMETER重叠。我只是不知道如何解决它。

除了_SC和PARAMETER之外还有其他一些操作应该是可选的,甚至会有一个不同的线型最终看起来像Name: blah blah blah我在树中至少需要“Name”和“blah blah blah”以防万一,但现在我只想弄清楚PARAMETER的用途。

〜汤姆

编辑:字符串“钢琴1”应该是任何非换行符的字符串,所以从播放到行尾之后的第一个非空格。

2 个答案:

答案 0 :(得分:5)

您不能在词法分析器中使用PARAMETER这样的规则。 ANTLR的词法分析器贪婪地匹配令牌:因此PARAMETER会吞噬整行:永远不会创建COMMANDACTION个令牌。

为了能够将某些内容匹配到行尾,您需要一个解析器规则。但是解析器必须有一个新行的概念(即词法分析器需要生成换行符号)。

grammar T;

options {
  output=AST;
}

tokens {
  LINE;
  PARAMS;
}

line
 : COMMAND ACTION rest_of_line NL 
   -> ^(LINE COMMAND ACTION ^(PARAMS rest_of_line))
 ;

rest_of_line
 : ~NL* // match any token other than a line break zero or more times
 ;

COMMAND : '_SC';
ACTION  : 'play';
WORD    : ('a'..'z' | 'A'..'Z')+;
NUMBER  : '0'..'9';
WS      : (' '|'\t')+ {skip();};
NL      : '\r'? '\n' | '\r';

如果你现在解析你的输入"_SC play Piano 1",你最终得到以下AST:

enter image description here

答案 1 :(得分:2)

这个语法会解析你的_SC播放钢琴1声明:

grammar PBScript;
options {
language = CSharp2;
output=AST;
}
tokens
{
COMMAND;
ACTION;
PARAM;
}

program :   lines;

lines   :   line*;

line:   'command:' command  action parameter param_modifier 
    ;

command
    :   IDENTIFIER
    ->  ^(COMMAND IDENTIFIER)
    ;

action  :   IDENTIFIER
    ->      ^(ACTION IDENTIFIER)
    ;

parameter   :   IDENTIFIER
    ->  ^(PARAM IDENTIFIER)
    ;

param_modifier  :   INTEGER
    ;

IDENTIFIER  :   ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*
    ;

INTEGER :   '0'..'9'+ 
    ;


COMMENT
    :   '//' ~('\n'|'\r')* '\r'? '\n' {$channel=HIDDEN;}
    |   '/*' ( options {greedy=false;} : . )* '*/' {$channel=HIDDEN;}
    ;

WS  :   ( ' '
        | '\t'
        | '\r'
        | '\n'
        ) {$channel=HIDDEN;}
    ;

然后输入:

command: _SC play Piano 1

command: _SR doSomething someInstrument 2

您将获得以下解析树:

enter image description here

然后,当你制作AST语法时,你应该为你的命令找到命令的名称,例如:if Name Of command == _SC do something等......