当前位置: 首页 > 知识库问答 >
问题:

用于注释和标记之间的纯文本的antlr语法

张建华
2023-03-14

1.我使用了一个规则

注释:START_1_TAG START_COMMENT END_1_TAG.*?START_2_TAG END_COMMENT END_2_TAG->跳过;

跳过任何使用我的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);

当我将规则定义为:

注释:START_1_TAG空格*?“commentstart”空格*?END_1_TAG.*?START_1_TAG空格*?“commentend”空格*?END_1_TAG->跳过;

带有显式空格。

在这里,内标识需要是<%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个答案

史昊焱
2023-03-14

这是正确的处理方法吗?

不,我会说不是。在这种情况下,它不仅仅是一个普通的注释,而是一个恰好代表注释的常规标记。因此,我会把它当作任何其他标记(在解析器中定义它,而不是在lexer中定义它)。

由于某种原因,当我试图用intellij antlr插件解析这个时,每当我试图匹配rawText规则时,它似乎就会冻结和崩溃。

这可能是因为:raw_text:.*?;匹配空字符串,并使lexer生成无限量的令牌。

我会做这样的事情:

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>)

如果您在lexer中设置了skipping注释(我不会这样做),那么您可以执行如下操作:

lexer grammar DemoLexer;

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

如果您已经测量到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  : . ; 
 类似资料:
  • 本文向大家介绍SGML(标准通用标记语言)和HTML(超文本标记语言),XML(可扩展标记语言)和HTML的之间有什么关系?相关面试题,主要包含被问及SGML(标准通用标记语言)和HTML(超文本标记语言),XML(可扩展标记语言)和HTML的之间有什么关系?时的应答技巧和注意事项,需要的朋友参考一下

  • 我正在尝试使用BeautifulSoup转换HTML文本块。以下是一个示例: 我试着做了这样的事情: ...但是这样我的span元素总是在新行上。这当然是一个简单的例子。有没有办法在超文本标记语言页面中获取文本,就像它在浏览器中呈现的方式一样(不需要css规则,只是div、spans、li等元素呈现的常规方式)在Python中?

  • 我有一位客户/朋友正在准备通过agencyaccess发送电子邮件。他们需要一个包含所有内容的html文档,并在一个html文档中包含电子邮件的纯文本版本。我想我有一个基本的理解,但有点困惑。我通常使用Mailchimp来处理我的电子邮件营销。 因此,我们将使用常规的html文档 但是,我们是否在此下方的某个地方为纯文本版本声明了另一种mime类型,然后电子邮件客户端选择要显示的类型?这两者是否都

  • 我正在尝试将下面的文本与ANTLR语法匹配: ANTLR语法是: 我得到的错误是: 我猜语法是合理的,但为什么会出现错误呢? null 要匹配的文档: 语法1: 在语法1中,跳过了T1,但不跳过T2中的T1部分。T2将在lexer阶段匹配输入文本。(即使我们把T2放在T1之后,T2还是会匹配的。我认为ANTLR为了最长的令牌做了一些贪婪的匹配。) 因此,正如@macmoonshine所说,我确实必

  • 我试图获取提供的html(跨度)之间的数据(在本例中为31) 以下是原始代码(来自chrome中的inspect elements) 我有一个包含页面源代码的富文本框,下面是相同的代码,但是在富文本框的第51行: 我将如何做到这一点?我已经尝试了几种方法,但似乎都不适合我。 我试图从这一页检索点值:http://www.subxcess.com/sub4sub.php根据谁潜艇你的数量变化。

  • 问题内容: 今天,我试图使用Hibernate作为ORM创建一个应用程序。因此在创建时我有一个疑问。使用Hibernate映射文件(.hbm文件)或注释的最佳实践是什么?它的优缺点是什么?请帮助我理解。 问题答案: 没有功能上的差异。您可以使用两种方法(几乎)执行相同的操作 xml文件是在Java具有注释(在1.5中添加)之前使用的,因此可以将它们视为过时的映射方式 通常首选使用JPA注释,而不是