首页 文章

注释的antlr语法和标签之间的纯文本

提问于
浏览
2

后续问题:Getting plain text in antlr instead of tokens

我使用了规则

COMMENT : START_1_TAG START_COMMENT END_1_TAG .*? START_2_TAG END_COMMENT END_2_TAG -> skip;

使用我的词法分析器跳过任何评论 . 但是,当我在标签内部给出任何空间时,我得到一个不匹配的输入 .

我的Lexer相关部分的一部分是:

lexer grammar DemoLexer;

START_1_TAG : '<%' -> pushMode(IN_TAG);
START_2_TAG : '<<' -> pushMode(IN_TAG);

COMMENT : START_1_TAG START_COMMENT END_1_TAG .*? START_2_TAG END_COMMENT END_2_TAG  -> skip;

TEXT        : ( ~[<] | '<' ~[<%] )+;

mode IN_TAG;
START_COMMENT : 'startcomment' ;
END_COMMENT : 'endcomment' ;
ID         : [A-Za-z_][A-Za-z0-9_]*;
INT_NUMBER : [0-9]+;
END_1_TAG  : '%>' -> popMode;
END_2_TAG  : '>>' -> popMode;
SPACE      : [ \t\r\n] -> channel(HIDDEN);

我的问题是, <%comment%>hi<%endcomment%> 被正确解析 . 但是,当我将输入标记为 <% comment %><% endcomment %> 时,标记之间有空格,但COMMENT规则无法识别它 .

当我将规则定义为:时,COMMENT规则会识别它:

COMMENT : START_1_TAG SPACE*? 'commentstart' SPACE*? END_1_TAG .*? START_1_TAG SPACE*? 'commentend' SPACE*? END_1_TAG -> skip;

有明确的空格 .

这是处理这个问题的正确方法吗?

2.我有一个规则,我需要标签对中的原始内容 . 例如:

这里,令牌需要<%startraw%>,<%Hi%>和<%endraw%>

我尝试使用文本规则,但它不起作用,因为它不包括'<%'和'<<' .

我试过了:

在我的解析器中,

rawText : RAW_TAG_START RAW_TEXT RAW_TAG_END ;

在我的词霸中,

RAW_TAG_START : '<%' 'startraw' '%>' -> pushMode(RAW_MODE);
RAW_TAG_END : '<%' 'endraw' '%>' -> popMode; 
mode RAW_MODE;
  RAW_TEXT : .*? ;

出于某种原因,当我尝试使用intellij antlr插件解析它时,每当我尝试匹配rawText规则时,它似乎都会冻结并崩溃 .

1 回答

  • 2

    这是处理此问题的正确方法吗?

    不,我会说不是 . 在这种情况下,它不仅仅是一个简单的评论,而是一个恰好代表评论的常规标签 . 因此我将其视为任何其他标记(在解析器中定义它,而不是词法分析器) .

    出于某种原因,当我尝试使用intellij antlr插件解析它时,每当我尝试匹配rawText规则时,它似乎都会冻结并崩溃 .

    这可能是因为: RAW_TEXT : .*? ; 匹配一个空字符串,并导致词法分析器生成无限量的标记 .

    我会做这样的事情:

    lexer grammar DemoLexer;
    
    START_1_TAG : '<%' -> pushMode(IN_TAG);
    START_2_TAG : '<<' -> pushMode(IN_TAG);
    TEXT        : ( ~[<] | '<' ~[<%] )+;
    
    fragment S  : [ \t\r\n];
    fragment ID : [A-Za-z_][A-Za-z0-9_]*;
    
    mode IN_TAG;
      START_RAW     : 'raw' S* '%>' -> pushMode(IN_RAW);
      START_COMMENT : 'comment';
      END_COMMENT   : 'endcomment';
      END_ID        : 'end' ID;
      START_ID      : ID;
      INT_NUMBER    : [0-9]+;
      END_1_TAG     : '%>' -> popMode;
      END_2_TAG     : '>>' -> popMode;
      SPACE         : [ \t\r\n] -> channel(HIDDEN);
    
    mode IN_RAW;
      END_RAW : '<%' S* 'endraw' S* '%>' -> popMode, popMode; // pop twice: out of IN_RAW and IN_TAG!
      ANY_RAW : . ; // No '+' or '*', just a single token!
    

    演示解析器:

    parser grammar DemoParser;
    
    options {
      tokenVocab=DemoLexer;
    }
    
    code
     : codeBlock* EOF
     ;
    
    codeBlock
     : TEXT
     | tag1Ops
     | tag2Ops
     ;
    
    tag1Ops
     : rawTag
     | commentTag
     | otherTag
     ;
    
    rawTag
     : START_1_TAG START_RAW ANY_RAW* END_RAW
     ;
    
    commentTag
     : START_1_TAG START_COMMENT END_1_TAG TEXT START_1_TAG END_COMMENT END_1_TAG
     ;
    
    otherTag
     : START_1_TAG START_ID END_1_TAG TEXT START_1_TAG END_ID END_1_TAG
     ;
    
    tag2Ops
     : START_2_TAG START_ID END_2_TAG TEXT START_2_TAG END_ID END_2_TAG
     ;
    

    还有一个小主要类来测试它:

    import org.antlr.v4.runtime.*;
    import org.antlr.v4.runtime.tree.ParseTree;
    
    public class Main {
    
      public static void main(String[] args) {
    
        String source = "aaa <% raw %> RAW <% endraw %> " +
                "bbb " +
                "<% foo %> FOO <% endfoo %> " +
                "ccc " +
                "<%comment%> COMMENT <%endcomment%> " +
                "ddd";
    
        DemoLexer lexer = new DemoLexer(CharStreams.fromString(source));
        DemoParser parser = new DemoParser(new CommonTokenStream(lexer));
        ParseTree tree = parser.code();
    
        System.out.println(tree.toStringTree(parser));
      }
    }
    

    将打印:

    (code
      (codeBlock aaa )
      (codeBlock (tag1Ops (rawTag <% raw %>   R A W   <% endraw %>)))
      (codeBlock  bbb )
      (codeBlock (tag1Ops (otherTag <% foo %>  FOO  <% endfoo %>)))
      (codeBlock  ccc )
      (codeBlock (tag1Ops (commentTag <% comment %>  COMMENT  <% endcomment %>)))
      (codeBlock  ddd)
      <EOF>)
    

    (为了清晰起见,我添加了一些手动换行符)

    而ANTLR IntelliJ插件也可以应对它:

    enter image description here

    编辑

    如果您在词法分析器中设置 skip ping注释(我不会这样做),那么您可以执行以下操作:

    lexer grammar DemoLexer;
    
    COMMENT     : '<%' S* 'comment' S* '%>' .*? '<%' S* 'endcomment' S* '%>' -> skip;
    START_1_TAG : '<%' -> pushMode(IN_TAG);
    START_2_TAG : '<<' -> pushMode(IN_TAG);
    TEXT        : ( ~[<] | '<' ~[<%] )+;
    

    编辑II

    如果您已经测量 ANY_RAW 对性能有重大影响,您可以执行以下操作:

    mode IN_RAW;
      END_RAW  : '<%' S* 'endraw' S* '%>' -> popMode, popMode;
      SAFE_RAW : ( ~[<] | '<' ~[<%] )+
    
      // Fall through to match "<" from "<% ..." that are not matched by END_RAW
      OTHER_RAW  : . ;
    

相关问题