ANTLR:如何跳过多行注释

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:

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
    ;