ANTLR4标记行的第一个非空白非注释字符 我正在寻找一种方法来标记一个“是”,这是一个行的第一个非空白,非注释字符(这与标准C++预处理指令要求完全相同)。注意第一个非空白空间要求,它意味着可以用空白和多行注释(例如,使用C++预处理指令作为例子):

ANTLR4标记行的第一个非空白非注释字符 我正在寻找一种方法来标记一个“是”,这是一个行的第一个非空白,非注释字符(这与标准C++预处理指令要求完全相同)。注意第一个非空白空间要求,它意味着可以用空白和多行注释(例如,使用C++预处理指令作为例子):,antlr4,Antlr4,及 “#”的前面和后面可以是跨越>1行和空格的多行注释。其他“#”可以作为运算符出现在行中,因此作为行中的第一个有效字符是关键要求 我们如何标记第一个有效字符 我试过这个 FIRSTHASH: {getCharPositionInLine() == 0}? ('/*' .*? '*/' | [ \t\f])* '#'; 但这是错误的,因为这样的输入 /* */other line /* S*/ /*SS*/# 被错误地认为是2个标记(1个大注释+一个“#”)。i、 e.*?错误地消耗了两

“#”的前面和后面可以是跨越>1行和空格的多行注释。其他“#”可以作为运算符出现在行中,因此作为行中的第一个有效字符是关键要求

我们如何标记第一个有效字符

我试过这个

FIRSTHASH: {getCharPositionInLine() == 0}? ('/*' .*? '*/' | [ \t\f])* '#';
但这是错误的,因为这样的输入

/* */other line
 /* S*/ /*SS*/# 

被错误地认为是2个标记(1个大注释+一个“#”)。i、 e.
*?
错误地消耗了两条
*/
导致两行合并为一条注释。(是否可以将多行注释中的
*?
替换为明确排除
*/
?)的内容。

我会在解析阶段甚至解析之后不受约束地对其进行检查

将“#”放在别处可能不符合语法,但不会使解析无效=>将其移动到更容易检测到的稍后阶段

如果您真的想“早”完成(即不是在解析之后),请在解析阶段完成。 词法分析不依赖于它(即与字符串或注释不同),因此在词法分析阶段进行词法分析没有任何意义

这是C#中的一个示例。 它检查所有3个定义(前两个正常,第三个不正常)

解析器:

parser grammar hashParse;
options { tokenVocab=hashLex; }

compileUnit
    :   (allKindOfStuff | preproc)*
    EOF
    ;

preproc :   PreProcStart .*? PreProcEnd
    ;

allKindOfStuff
    :   Identifier
    |   LParen
    |   RParen
    ;
样本:

/* 
can be preceded by multiline comment spreading across >1 lines

123 */ /* abc */# /* */define xyz(a) #a 

/* def */# /* */define xyz(a) #a 

some other code // #


illegal #define a b
public class hashTest
{

    public static void test()
    {
        var sample = File.ReadAllText(@"ANTLR\unrelated\hashTest.txt");
        var sampleStream = new Antlr4.Runtime.AntlrInputStream(sample);

        var lexer = new hashLex(input: sampleStream);
        var tokenStream = new CommonTokenStream(tokenSource: lexer);
        var parser = new hashParse(input: tokenStream);
        var result = parser.compileUnit();

        var visitor = new HashVisitor(tokenStream: tokenStream);
        var visitResult = visitor.Visit(result);



    }
}

public class HashVisitor : hashParseBaseVisitor<object>
{
    private readonly CommonTokenStream tokenStream;

    public HashVisitor(CommonTokenStream tokenStream)
    {
        this.tokenStream = tokenStream;
    }
    public override object VisitPreproc(hashParse.PreprocContext context)
    {
        ;
        var startSymbol = context.PreProcStart().Symbol;
        var tokenIndex = startSymbol.TokenIndex;

        var startLine = startSymbol.Line;

        var previousTokens_reversed = tokenStream.GetTokens(0, tokenIndex - 1).Reverse();

        var ok = true;
        var allowedTypes = new[] { hashLex.RangeComment, hashLex.WS, };
        foreach (var token in previousTokens_reversed)
        {
            if (token.Line < startLine)
                break;

            if (allowedTypes.Contains(token.Type) == false)
            {
                ok = false;
                break;
            }
            ;
        }

        if (!ok)
        {
            ; // handle error
        }

        return base.VisitPreproc(context);
    }
}
lexer grammar hashLex;


PreProcStart : Hash -> pushMode(PRE_PROC_MODE)
    ;

Identifier:
        Identifier_
    ;

LParen : '(';
RParen : ')';



WS
    : WS_-> channel(HIDDEN)
    ;

LineComment
    :   '//'
        ~('\r'|'\n')*
        (LineBreak|EOF)
    -> channel(HIDDEN)
    ;

RangeComment
    :   '/*'
        .*?
        '*/'
    -> channel(HIDDEN)
    ;




mode PRE_PROC_MODE;
PreProcIdentifier : Identifier_;
PreProcHash : Hash;

PreProcEnd :
               (EOF|LineBreak) -> popMode
           ;
PreProcWS : [ \t]+    -> channel(HIDDEN)
          ;
PreProcLParen : '(';
PreProcRParen : ')';
PreProcRangeComment
    :   '/*'
        (~('\r' | '\n'))*?
        '*/'
    -> channel(HIDDEN)
    ;




fragment LineBreak
    :   '\r' '\n'?
    |   '\n'
    ;

fragment Identifier_:
        [a-zA-Z]+
    ;
fragment Hash : '#' 
    ;
fragment WS_
    : [ \t\r\n]+    
    ;
parser grammar hashParse;
options { tokenVocab=hashLex; }

compileUnit
    :   (allKindOfStuff | preproc)*
    EOF
    ;

preproc :   PreProcStart .*? PreProcEnd
    ;

allKindOfStuff
    :   Identifier
    |   LParen
    |   RParen
    ;
/* 
can be preceded by multiline comment spreading across >1 lines

123 */ /* abc */# /* */define xyz(a) #a 

/* def */# /* */define xyz(a) #a 

some other code // #


illegal #define a b