ANTLR:如何跳过多行注释
给定以下lexer:ANTLR:如何跳过多行注释,antlr,lexer,parser-generator,Antlr,Lexer,Parser Generator,给定以下lexer: lexer grammar CodeTableLexer; @header { package ch.bsource.ice.parsers; } CodeTabHeader : OBracket Code ' ' Table ' ' Version CBracket; CodeTable : Code ' '* Table; EndCodeTable : 'end' ' '* Code ' '* Table; Code
lexer grammar CodeTableLexer;
@header {
package ch.bsource.ice.parsers;
}
CodeTabHeader : OBracket Code ' ' Table ' ' Version CBracket;
CodeTable : Code ' '* Table;
EndCodeTable : 'end' ' '* Code ' '* Table;
Code : 'code';
Table : 'table';
Version : '1.0';
Row : 'row';
Tabdef : 'tabdef';
Override : 'override' | 'no_override';
Obsolete : 'obsolete';
Substitute : 'substitute';
Status : 'activ' | 'inactive';
Pkg : 'include_pkg' | 'exclude_pkg';
Ddic : 'include_ddic' | 'exclude_ddic';
Tab : 'tab';
Naming : 'naming';
Dfltlang : 'dfltlang';
Language : 'english' | 'german' | 'french' | 'italian' | 'spanish';
Null : 'null';
Comma : ',';
OBracket : '[';
CBracket : ']';
Boolean
: 'true'
| 'false'
;
Number
: Int* ('.' Digit*)?
;
Identifier
: ('a'..'z' | 'A'..'Z' | '_') ('a'..'z' | 'A'..'Z' | '_' | '$' | '#' | '.' | Digit)*
;
String
@after {
setText(getText().substring(1, getText().length() - 1).replaceAll("\\\\(.)", "$1"));
}
: '"' (~('"'))* '"'
;
Comment
: '--' ~('\r' | '\n')* { skip(); }
| '/*' .* '*/' { skip(); }
;
Space
: (' ' | '\t') { skip(); }
;
NewLine
: ('\r' | '\n' | '\u000C') { skip(); }
;
fragment Int
: '1'..'9'
| '0'
;
fragment Digit
: '0'..'9'
;
。。。以及以下解析器:
parser grammar CodeTableParser;
options {
tokenVocab = CodeTableLexer;
backtrack = true;
output = AST;
}
@header {
package ch.bsource.ice.parsers;
}
parse
: block EOF
;
block
: CodeTabHeader^ codeTable endCodeTable
;
codeTable
: CodeTable^ codeTableData
;
codeTableData
: (Identifier^ obsolete?) (tabdef | row)*
;
endCodeTable
: EndCodeTable
;
tabdef
: Tabdef^ Identifier+
;
row
: Row^ rowData
;
rowData
: (Number^ | (Identifier^ (Comma Number)?))
Override?
obsolete?
status?
Pkg?
Ddic?
(tab | field)*
;
tab
: Tab^ value+
;
field
: (Identifier^ value) | naming
;
value
: OBracket? (Identifier | String | Number | Boolean | Null) CBracket?
;
naming
: Naming^ defaultNaming (l10nNaming)*
;
defaultNaming
: Dfltlang^ String
;
l10nNaming
: Language^ String?
;
obsolete
: Obsolete^ Substitute String
;
status
: Status^ Override?
;
。。。最后,我的类用于使解析器不区分大小写:
package ch.bsource.ice.parsers;
import java.io.IOException;
import org.antlr.runtime.*;
public class ANTLRNoCaseFileStream extends ANTLRFileStream {
public ANTLRNoCaseFileStream(String fileName) throws IOException {
super (fileName, null);
}
public ANTLRNoCaseFileStream(String fileName, String encoding) throws IOException {
super (fileName, null);
}
public int LA(int i) {
if (i == 0) return 0;
if (i < 0) i++;
if ((p + 1 - 1) >= n) return CharStream.EOF
return Character.toLowerCase(data[p + 1 - 1]);
}
}
任何帮助都将不胜感激:-)
谢谢,
j3d使用两条规则来跳过行和阻止注释(为了调试,我在解析过程中打印它们)。为了更好的可读性,它们被分成两部分,块注释确实支持嵌套注释 此外,我不会跳过语法中的下线字符(
\r
和/或\n
),因为我需要它们明确地用于某些规则
LineComment
: '//' ~('\n'|'\r')* //NEWLINE
{System.out.println("lc > " + getText());
skip();}
;
BlockComment
@init { int depthOfComments = 0;}
: '/*' {depthOfComments++;}
( options {greedy=false;}
: ('/' '*')=> BlockComment {depthOfComments++;}
| '/' ~('*')
| ~('/')
)*
'*/' {depthOfComments--;}
{
if (depthOfComments == 0) {
System.out.println("bc >" + getText());
skip();
}
}
;
巴特给了我惊人的支持,我想我们都非常感谢他:-) 无论如何,问题是我用来将解析后的字符流转换为小写的FileStream类中有一个bug。下面是正确的Java源代码:
import java.io.IOException;
import org.antlr.runtime.*;
public class ANTLRNoCaseFileStream extends ANTLRFileStream {
public ANTLRNoCaseFileStream(String fileName) throws IOException {
super (fileName, null);
}
public ANTLRNoCaseFileStream(String fileName, String encoding) throws IOException {
super (fileName, null);
}
public int LA(int i) {
if (i == 0) return 0;
if (i < 0) i++;
if ((p + i - 1) >= n) return CharStream.EOF;
return Character.toLowerCase(data[p + i - 1]);
}
}
import java.io.IOException;
导入org.antlr.runtime.*;
公共类ANTLRNoCaseFileStream扩展了ANTLRFileStream{
公共ANTLRNoCaseFileStream(字符串文件名)引发IOException{
super(文件名,null);
}
公共ANTLRNoCaseFileStream(字符串文件名,字符串编码)引发IOException{
super(文件名,null);
}
公共内部LA(内部i){
如果(i==0)返回0;
if(i<0)i++;
如果((p+i-1)>=n)返回CharStream.EOF;
返回字符.toLowerCase(数据[p+i-1]);
}
}
在antlr4中执行此操作
BlockComment
: '/*' .*? '*/' -> skip
;
看起来OP并没有试图解析嵌套的块注释。但我认为,现在的做法有点冗长。您可以通过使用谓词或嵌入式代码来实现这一点,您可以同时使用这两种方法。像这样的东西怎么样:BlockComment:'/*'(BlockComment |('*'~'/')=>'*''.'~'*')*'/'代码>相反?@BartKiers您的建议在ANTLR4上不受支持(当时可能不存在…)。但是,这是可行的:BLOCKCOMMENT:“/*”(BLOCKCOMMENT |(“~”/”)| ~“*”/”;您的测试输入可能只是缺少一个结束语*/
?但是如果您有多个注释,它不会删除中间的所有内容吗?类似于:/*注释1很长/这里有一些代码更多代码/注释2*/如果我没有弄错的话,语法规则会跳过中间的代码,因为您定义了贪婪的*?
import java.io.IOException;
import org.antlr.runtime.*;
public class ANTLRNoCaseFileStream extends ANTLRFileStream {
public ANTLRNoCaseFileStream(String fileName) throws IOException {
super (fileName, null);
}
public ANTLRNoCaseFileStream(String fileName, String encoding) throws IOException {
super (fileName, null);
}
public int LA(int i) {
if (i == 0) return 0;
if (i < 0) i++;
if ((p + i - 1) >= n) return CharStream.EOF;
return Character.toLowerCase(data[p + i - 1]);
}
}
BlockComment
: '/*' .*? '*/' -> skip
;