如何检查 ANTLR4 中一行的第一个字符是否为“*”?
How can I check if first character of a line is "*" in ANTLR4?
我正在尝试为一种相对简单但特殊的语言编写解析器。
简单地说,规则之一是注释行用星号表示仅当星号是该行的第一个字符时。我怎样才能在 ANTLR4 中将这样的规则形式化?我考虑过使用:
START_LINE_COMMENT: '\n*' .*? '\n' -> skip;
但我敢肯定,这不适用于连续多行注释,因为末尾的换行符将作为 START_LINE_COMMENT
令牌的一部分使用,这意味着任何后续注释行都将被使用缺少所需的初始换行符,这是行不通的。有没有一种方法可以检查该行是否以 '*'
开头,而无需使用之前的 '\n'
?
匹配注释行并不容易。当我每年写一个语法时,我不得不抓住 The Definitive ANTLR Reference 来刷新我的大脑。试试这个:
grammar Question;
/* Comment line having an * in column 1. */
question
: line+
;
line
// : ( ID | INT )+
: ( ID | INT | MULT )+
;
LINE_COMMENT
: '*' {getCharPositionInLine() == 1}? ~[\r\n]* -> channel(HIDDEN) ;
ID : [a-zA-Z]+ ;
INT : [0-9]+ ;
//WS : [ \t\r\n]+ -> channel(HIDDEN) ;
WS : [ \t\r\n]+ -> skip ;
MULT : '*' ;
编译并执行:
$ echo $CLASSPATH
.:/usr/local/lib/antlr-4.6-complete.jar:
$ alias
alias a4='java -jar /usr/local/lib/antlr-4.6-complete.jar'
alias grun='java org.antlr.v4.gui.TestRig'
$ a4 Question.g4
$ javac Q*.java
$ grun Question question -tokens data.txt
[@0,0:3='line',<ID>,1:0]
[@1,5:5='1',<INT>,1:5]
[@2,9:12='line',<ID>,2:2]
[@3,14:14='2',<INT>,2:7]
[@4,16:26='* comment 1',<LINE_COMMENT>,channel=1,3:0]
[@5,32:35='line',<ID>,4:4]
[@6,37:37='4',<INT>,4:9]
[@7,39:48='*comment 2',<LINE_COMMENT>,channel=1,5:0]
[@8,51:78='* comment 3 after empty line',<LINE_COMMENT>,channel=1,7:0]
[@9,81:81='*',<'*'>,8:1]
[@10,83:85='not',<ID>,8:3]
[@11,87:87='a',<ID>,8:7]
[@12,89:95='comment',<ID>,8:9]
[@13,97:100='line',<ID>,9:0]
[@14,102:102='9',<INT>,9:5]
[@15,107:107='*',<'*'>,9:10]
[@16,109:110='no',<ID>,9:12]
[@17,112:118='comment',<ID>,9:15]
[@18,120:119='<EOF>',<EOF>,10:0]
使用以下 data.text 文件:
line 1
line 2
* comment 1
line 4
*comment 2
* comment 3 after empty line
* not a comment
line 9 * no comment
请注意,如果解析器规则中某处没有 MULT
标记或 '*'
,则标记中未列出星号,但解析器会抱怨:
line 8:1 token recognition error at: '*'
如果显示解析树
$ grun Question question -gui data.txt
你会看到整个文件都被一行规则吸收了。如果您需要识别线条,请像这样更改线条和白色 space 规则:
line
: ( ID | INT | MULT )+ NL
| NL
;
//WS : [ \t\r\n]+ -> skip ;
NL : [\r\n] ;
WS : [ \t]+ -> skip ;
我正在尝试为一种相对简单但特殊的语言编写解析器。
简单地说,规则之一是注释行用星号表示仅当星号是该行的第一个字符时。我怎样才能在 ANTLR4 中将这样的规则形式化?我考虑过使用:
START_LINE_COMMENT: '\n*' .*? '\n' -> skip;
但我敢肯定,这不适用于连续多行注释,因为末尾的换行符将作为 START_LINE_COMMENT
令牌的一部分使用,这意味着任何后续注释行都将被使用缺少所需的初始换行符,这是行不通的。有没有一种方法可以检查该行是否以 '*'
开头,而无需使用之前的 '\n'
?
匹配注释行并不容易。当我每年写一个语法时,我不得不抓住 The Definitive ANTLR Reference 来刷新我的大脑。试试这个:
grammar Question;
/* Comment line having an * in column 1. */
question
: line+
;
line
// : ( ID | INT )+
: ( ID | INT | MULT )+
;
LINE_COMMENT
: '*' {getCharPositionInLine() == 1}? ~[\r\n]* -> channel(HIDDEN) ;
ID : [a-zA-Z]+ ;
INT : [0-9]+ ;
//WS : [ \t\r\n]+ -> channel(HIDDEN) ;
WS : [ \t\r\n]+ -> skip ;
MULT : '*' ;
编译并执行:
$ echo $CLASSPATH
.:/usr/local/lib/antlr-4.6-complete.jar:
$ alias
alias a4='java -jar /usr/local/lib/antlr-4.6-complete.jar'
alias grun='java org.antlr.v4.gui.TestRig'
$ a4 Question.g4
$ javac Q*.java
$ grun Question question -tokens data.txt
[@0,0:3='line',<ID>,1:0]
[@1,5:5='1',<INT>,1:5]
[@2,9:12='line',<ID>,2:2]
[@3,14:14='2',<INT>,2:7]
[@4,16:26='* comment 1',<LINE_COMMENT>,channel=1,3:0]
[@5,32:35='line',<ID>,4:4]
[@6,37:37='4',<INT>,4:9]
[@7,39:48='*comment 2',<LINE_COMMENT>,channel=1,5:0]
[@8,51:78='* comment 3 after empty line',<LINE_COMMENT>,channel=1,7:0]
[@9,81:81='*',<'*'>,8:1]
[@10,83:85='not',<ID>,8:3]
[@11,87:87='a',<ID>,8:7]
[@12,89:95='comment',<ID>,8:9]
[@13,97:100='line',<ID>,9:0]
[@14,102:102='9',<INT>,9:5]
[@15,107:107='*',<'*'>,9:10]
[@16,109:110='no',<ID>,9:12]
[@17,112:118='comment',<ID>,9:15]
[@18,120:119='<EOF>',<EOF>,10:0]
使用以下 data.text 文件:
line 1
line 2
* comment 1
line 4
*comment 2
* comment 3 after empty line
* not a comment
line 9 * no comment
请注意,如果解析器规则中某处没有 MULT
标记或 '*'
,则标记中未列出星号,但解析器会抱怨:
line 8:1 token recognition error at: '*'
如果显示解析树
$ grun Question question -gui data.txt
你会看到整个文件都被一行规则吸收了。如果您需要识别线条,请像这样更改线条和白色 space 规则:
line
: ( ID | INT | MULT )+ NL
| NL
;
//WS : [ \t\r\n]+ -> skip ;
NL : [\r\n] ;
WS : [ \t]+ -> skip ;