如何在简单的 ANTLR 词法分析器中以不同的方式处理 <script> 标签?

Posted

技术标签:

【中文标题】如何在简单的 ANTLR 词法分析器中以不同的方式处理 <script> 标签?【英文标题】:How do I treat <script> tags differently in simple ANTLR lexer? 【发布时间】:2013-01-13 02:50:40 【问题描述】:

我正在编写一个非常简单的词法分析器,用于对任意文本进行语法高亮,其中之一是 html。词法分析器的目标只是提供一个扁平的标记流。

我从 Antlr3 网站上的 XML tutorial 开始,但在使用脚本标签时遇到了一些问题。

导致此问题的 HTML 示例:

<head> <script>alert(2 < 3);</script> </head>

还有语法..

@members 
    boolean inTag = false;


TAG_START_OPEN : '<'
                  inTag = true;  ;
TAG_END_OPEN : '</'
                inTag = true;  ;

TAG_CLOSE :  inTag ?=> '>'  inTag = false;  ;
TAG_SELF_CLOSE :  inTag ?=> '/>'  inTag = false;  ;
PCDATA :  !inTag ?=> (~'<')+ ;

// ... 

问题是词法分析器在看到 javascript 代码中的“' 进行,但是我不确定如何使用 ANTLR 很好地做到这一点。

提前感谢您的帮助。

【问题讨论】:

【参考方案1】:

这里有一个快速演示,说明如何实现这一点:

grammar T;

options 
  output=AST;


tokens 
  DATA;
  ATTRIBUTES;
  ATTRIBUTE;
  ATOMS;


@lexer::members 
  private boolean inTag = false;
  private boolean isScript = false;

  private boolean ahead(String s) 
    for(int i = 0; i < s.length(); i++) 
      int ch = input.LA(i + 1);
      if(ch != s.charAt(i)) 
        return false;
      
    
    return true;
  


parse
 : tag EOF -> tag
 ;

tag
 : TagOpen attributes TagOpenEnd atoms TagClose -> ^(TagOpen attributes atoms)
 ;

attributes
 : attribute* -> ^(ATTRIBUTES attribute*)
 ;

attribute
 : Key Assign Value -> ^(ATTRIBUTE Key Value)
 ;

atoms
 : atom* -> ^(ATOMS atom*)
 ;

atom
 : PCData
 | ScriptData
 | tag
 ;

TagOpen
 : '<' Name 
   
     inTag=true; 
     isScript = $Name.text.equals("script");
     setText($Name.text);
   
 ;

TagClose
 : !inTag?=> '</' Name '>' 
   
     isScript = false;
     setText($Name.text);
   
 ;

TagOpenEnd
 : inTag?=> '>' inTag=false;
 ;

Key
 : inTag?=> Name
 ;

Assign
 : inTag?=> '='
 ;

Value
 : inTag?=> '"' ~'"'* '"'
   
     setText($text.substring(1, $text.length() - 1));
   
 ;

PCData
 : !inTag && !isScript?=> ~'<'+
   
     if($text.trim().isEmpty()) 
       skip();
     
   
 ;

ScriptData
 : !inTag && isScript?=> (!ahead("</script>")?=> . )+
 ;

Space
 : inTag?=> (' ' | '\t' | '\r' | '\n')+ skip();
 ;

fragment Name : ('a'..'z' | 'A'..'Z')+;

如果我现在解析输入:

<head>
  <script> alert(2 < 3); </script> 
  <span key="some value" x="<>">
    Mu <em>foo</em> bar!
  </span>
</head>

生成的解析器将创建以下 AST:

【讨论】:

谢谢,这正是我想要的

以上是关于如何在简单的 ANTLR 词法分析器中以不同的方式处理 <script> 标签?的主要内容,如果未能解决你的问题,请参考以下文章

ANTLR4 词法分析器规则在 perl 语法上产生错误或冲突

Hive 源码解读 Driver 将 HQL 语句转换为 AST

Hive 源码解读 Driver 将 HQL 语句转换为 AST

Hive 源码解读 Driver 将 HQL 语句转换为 AST

ANTLR v4 权威参考笔记(目录)

ANTLR v4 专业术语集