【问题标题】:Antlr4 parsing jsp scriptlets expression directiveAntlr4解析jsp scriptlets表达式指令
【发布时间】:2017-06-06 06:40:30
【问题描述】:

我想解析 jsp 文件以识别指令标记、jsp 操作元素、scriptlet 表达式等。为此,我正在尝试扩展现有的 html grammar。 我在区分正常的 html 标签打开和 jsp 标签打开时遇到了问题。现有语法有以下词法规则:

TAG_OPEN
    : '<' -> pushMode(TAG)
    ;
//
// tag declarations
//
mode TAG;

TAG_CLOSE
    : '>' -> popMode
    ;

TAG_SLASH_CLOSE
    : '/>' -> popMode
    ;

TAG_SLASH
    : '/'
    ;

//
// lexing mode for attribute values
//
TAG_EQUALS
    : '=' -> pushMode(ATTVALUE)
    ;

TAG_NAME
    : TAG_NameStartChar TAG_NameChar*
    | TAG_NameStartChar* ':' TAG_NameStartChar*
    ;

TAG_WHITESPACE
    : [ \t\r\n] -> skip
    ;

以及相应的解析器规则:

htmlElement
    : TAG_OPEN htmlTagName htmlAttribute* TAG_CLOSE htmlContent TAG_OPEN TAG_SLASH htmlTagName TAG_CLOSE
    | TAG_OPEN htmlTagName htmlAttribute* TAG_SLASH_CLOSE
    | TAG_OPEN htmlTagName htmlAttribute* TAG_CLOSE
    | TAG_OPEN TAG_SLASH htmlTagName TAG_CLOSE
//  | jspDirective
//  | jspDeclaration
    | scriptlet
    | script
    | style
    ;

我正在尝试使用以下内容扩展上述规则:

scriptlet
    : JSP_TAG_OPEN jspElement jspElementName jspElementAttribute* JSP_TAG_CLOSE 
    //|SCRIPTLET
    ;

jspElementName
    : TAG_NAME
    ;

jspElementAttribute
    : jspAttributeName TAG_EQUALS jspAttributeValue
    ;

jspAttributeName
    : TAG_NAME
    ;

jspAttributeValue
    : ATTVALUE_VALUE
    ;

jspElement
    : jspDirective
    | jspExpression
    | jspDeclaration
    | jspFragment
    ;

jspDirective    
    : JSP_DIRECTIVE_SIGN
    ;

jspExpression
    : JSP_EXPRESSION_SIGN
    ;

jspDeclaration
    : JSP_DECLARATION_SIGN
    ;

jspFragment
    : JSP_FRAGMENT_SIGN
    ;

词法分析器规则是:

JSP_TAG_OPEN
    : '<%' ' '*
    ;

JSP_DIRECTIVE_SIGN
    : '@'
    ;

JSP_EXPRESSION_SIGN
    : '='
    ;

JSP_DECLARATION_SIGN
    : '!'
    ;

JSP_FRAGMENT_SIGN
    : [ ]+
    ;

JSP_TAG_CLOSE
    : '%>'  
    ;

但我猜的问题是,每当遇到&lt; 字符时,TAG_OPEN 的词法分析器规则就会开始运行,而不是等待查看这是否是一个 jsp 标记 &lt;%

所以当我试图解析一个包含以下内容的小 html 时:

<html>
<title>Statement Load page</title>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-html"
    prefix="html"%>

我收到此错误:

line 3:2 no viable alternative at input '@ taglib uri="http://jakarta.apache.org/struts/tags-html"\r\n\tprefix="html"%>\r\n'

【问题讨论】:

    标签: java html antlr4 jsp-tags


    【解决方案1】:

    好的,我现在想出了一个jsp的语法。如果这对其他人有帮助,我会在这里分享。此外,如果有人提出任何更新、指出问题或帮助改进语法,我会很高兴。

    词法分析器语法:

    lexer grammar  HTMLLexer;
    
    
    HTML_COMMENT
        : '<!--' .*? '-->'
        ;
    
    HTML_CONDITIONAL_COMMENT
        : '<![' .*? ']>'
        ;
    
    JSP_COMMENT
        : '<%--' .*? '--%>'
        ;
    
    XML_DECLARATION
        : '<?xml' .*? '>'
        ;
    
    SCRIPT_OPEN
        : '<script' ->pushMode(SCRIPT)
        ;
    
    DIRECTIVE_TAG_OPEN
        : '<%@' -> pushMode(TAG)
        ;
    
    SCRIPTLET_TAG_OPEN
        : ('<%!' | '<%=' | '<%') ->pushMode(SCRIPTVALUE)
        ;
    
    //
    //
    CDATA
        : '<![CDATA[' .*? ']]>'
        ;
    
    DTD
        : '<!' .*? '>'
        ;
    
    //SCRIPTLET
    //    : '<?' .*? '?>'
    //    | '<%' .*? '%>'
    //    ;
    
    SEA_WS
        :  (' '|'\t'|'\r'? '\n')+
        ;
    
    
    LINK_OPEN
        : '<link' ->pushMode(LINK)
        ;
    
    STYLE_OPEN
        : '<style'  ->pushMode(STYLE)
        ;
    
    TAG_OPEN
        : '<' ->pushMode(TAG)
        ;
    
    HTML_TEXT
        : ~'<'+
        ;
    
    //
    // tag declarations
    //
    mode TAG;
    
    JSP_TAG_CLOSE
        : '%>' -> popMode   
        ;
    
    TAG_CLOSE
        : '>' -> popMode
        ;
    
    TAG_SLASH_CLOSE
        : '/>' -> popMode
        ;
    
    TAG_SLASH
        : '/'
        ;
    
    //
    // lexing mode for attribute values
    //
    TAG_EQUALS
        : '=' -> pushMode(ATTVALUE)
        ;
    
    TAG_NAME
        : TAG_NameStartChar TAG_NameChar*
    //  | TAG_NameStartChar* ':' TAG_NameStartChar*
        ;
    
    TAG_COLON
        : ':'
        ;
    
    TAG_WHITESPACE
        : [ \t\r\n] -> channel(HIDDEN)
        ;
    
    fragment
    HEXDIGIT
        : [a-fA-F0-9]
        ;
    
    fragment
    DIGIT
        : [0-9]
        ;
    
    
    TAG_NameChar
        : TAG_NameStartChar
    //  | ':'
        | '-'
        | '_'
        | '.'
        | DIGIT
        |   '\u00B7'
        |   '\u0300'..'\u036F'
        |   '\u203F'..'\u2040'
        ;
    
    
    TAG_NameStartChar
        :   [a-zA-Z]
        |   '\u2070'..'\u218F'
        |   '\u2C00'..'\u2FEF'
        |   '\u3001'..'\uD7FF'
        |   '\uF900'..'\uFDCF'
        |   '\uFDF0'..'\uFFFD'
        ;
    
    //
    // <scripts>
    //
    mode SCRIPT;
    
    SCRIPT_TAG_FULL_CLOSE
        : '</script>' ->popMode
        ;
    
    
    SCRIPT_TAG_CLOSE
        : '>' -> popMode
        ;
    
    SCRIPT_TAG_SLASH_CLOSE
        : '/>' -> popMode
        ;
    
    SCRIPT_EQUALS
        : ' '* '=' ' '*
        ;
    
    SCRIPLET_INSIDE_SCRIPT
        : '<%' ->pushMode(SCRIPTVALUE)
        ;
    
    SCRIPT_ATTRIBUTE
        : SCRIPT_ATTCHARS    
        ;
    
    fragment SCRIPT_ATTCHARS
        : SCRIPT_ATTCHAR+ ' '?
        ;
    
    SCRIPT_WHITESPACE
        : [\r\n\t]+ -> channel(HIDDEN)
        ;
    
    WORD
        : [ a-zA-Z]+
        ;
    
    QUOTE
        : '"' ' '*
        ;
    
    fragment SCRIPT_ATTCHAR
        : '-'
        | '_'
        | '.'
        | '/'
        | ','
        | ';'
        | '\''
        | '"'
        | [0-9a-zA-Z]
        ;       
    
    //
    // <link>
    //
    mode LINK;
    
    LINK_BODY
        : .*? '</link>' ->popMode
        ;
    
    LINK_SHORT_BODY
        : '/>' ->popMode
        ;
    
    LINK_WS
        : [ \r\n\t]+ -> channel(HIDDEN)
        ;
    
    LINK_NONSLASH_BODY
        : .*? '>' ->popMode
        ;
    
    
    //
    // <styles>
    //
    mode STYLE;
    
    STYLE_BODY
        : .*? '</style>' -> popMode
        ;
    
    STYLE_SHORT_BODY
        : .*? '</>' -> popMode
        ;
    
    //
    // attribute values
    //
    mode ATTVALUE;
    
    // an attribute value may have spaces b/t the '=' and the value
    ATTVALUE_VALUE
        : [ ]* ATTRIBUTE -> popMode
        ;
    
    ATTRIBUTE
        : DOUBLE_QUOTE_STRING
        | SINGLE_QUOTE_STRING
        | ATTCHARS
        | HEXCHARS
        | DECCHARS
        ;
    
    fragment ATTCHAR
        : '-'
        | '_'
        | '.'
        | '/'
        | '+'
        | ','
        | '?'
        | '='
        | ':'
        | ';'
        | '#'
        | [0-9a-zA-Z]
        ;
    
    fragment ATTCHARS
        : ATTCHAR+ ' '?
        ;
    
    fragment HEXCHARS
        : '#' [0-9a-fA-F]+
        ;
    
    fragment DECCHARS
        : [0-9]+ '%'?
        ;
    
    fragment DOUBLE_QUOTE_STRING
        : '"' ~[<"]* '"'
        ;
    fragment SINGLE_QUOTE_STRING
        : '\'' ~[<']* '\''
        ;
    
    mode SCRIPTVALUE;
    
    SCRIPTLET_TAG_CLOSE
        : '%>' ->popMode
        ;
    
    VALID_JAVA_CHARS
        : SCRIPTCHARS+
        ;
    
    SCRIPT_WS
        : [\r\n\t]+ -> channel(HIDDEN)
        ;
    
    fragment SCRIPTCHARS
        : SCRIPTCHAR+ ' '?
        ;   
    
    fragment SCRIPTCHAR
        : '-'
        | '_'
        | '.'
        | '/'
        | '+'
        | ','
        | '?'
        | '='
        | ':'
        | ';'
        | '#'
        | '('
        | ')'
        | '}'
        | '{'
        | '@'
        | '*'
        | '!'
        | '%'[0-9]+
        | '&'
        | '['
        | ']'
        | '~'
        | '+'
        | '^'
        | '\r'
        | '\t'
        | '\n'
        | ' '
        | '"'
        | '\''
        | [0-9a-zA-Z]
        ;
    

    解析器语法:

    parser grammar HTMLParser;
    
    options { tokenVocab=HTMLLexer; }
    
    htmlDocument
        : (scriptlet | SEA_WS)* xml? (scriptlet | SEA_WS)* dtd? (scriptlet | SEA_WS)* htmlElements*
        ;
    
    htmlElements
        : htmlMisc* htmlElement htmlMisc*
        ;
    
    htmlElement
        : script
        | link
        | style
        | scriptlet
        | TAG_OPEN htmlTagName htmlAttribute* TAG_CLOSE htmlContent TAG_OPEN TAG_SLASH htmlTagName TAG_CLOSE
        | TAG_OPEN htmlTagName htmlAttribute* TAG_SLASH_CLOSE
        | TAG_OPEN htmlTagName htmlAttribute* TAG_CLOSE
        | TAG_OPEN TAG_SLASH htmlTagName TAG_CLOSE
        ;
    
    htmlContent
        : htmlChardata? ((htmlElement | xhtmlCDATA | htmlComment) htmlChardata?)*
        ;
    
    htmlAttribute
        : htmlAttributeName TAG_EQUALS htmlAttributeValue
        | htmlAttributeName
        ;
    
    htmlAttributeName
        : TAG_NAME
        ;
    
    htmlAttributeValue
        : ATTVALUE_VALUE
        ;
    
    htmlTagName
        : TAG_NAME
        | tagKey TAG_COLON tagVal
        ;
    
    tagKey
        : TAG_NAME
        ;
    
    tagVal
        : TAG_NAME
        ;
    
    htmlChardata
        : HTML_TEXT
        | SEA_WS
        ;
    
    htmlMisc
        : htmlComment
        | jspComment
        | SEA_WS
        ;
    
    htmlComment
        : HTML_COMMENT
        | HTML_CONDITIONAL_COMMENT
        ;
    
    jspComment
        : JSP_COMMENT
        ;
    
    xhtmlCDATA
        : CDATA
        ;
    
    dtd
        : DTD
        ;
    
    xml
        : XML_DECLARATION
        ;
    
    scriptlet
        : DIRECTIVE_TAG_OPEN jspElementName jspElementAttribute* JSP_TAG_CLOSE 
        | SCRIPTLET_TAG_OPEN javaExpression SCRIPTLET_TAG_CLOSE
        ;
    
    jspElementName
        : TAG_NAME
        ;
    
    jspElementAttribute
        : jspAttributeName TAG_EQUALS jspAttributeValue
        ;
    
    jspAttributeName
        : TAG_NAME
        ;
    
    jspAttributeValue
        : ATTVALUE_VALUE
        ;
    
    javaExpression
        : VALID_JAVA_CHARS | SEA_WS*    
        ;
    
    script
        : SCRIPT_OPEN scriptAttribute* SCRIPT_TAG_CLOSE htmlContent* SCRIPT_TAG_FULL_CLOSE
        | SCRIPT_OPEN scriptAttribute* SCRIPT_TAG_SLASH_CLOSE
        ;
    
    scriptAttribute
        : scriptAttributeName SCRIPT_EQUALS QUOTE scriptlet scriptAttributeValue* QUOTE
        | scriptAttributeName SCRIPT_EQUALS scriptAttributeValue
        | scriptAttributeName
        ;
    
    scriptAttributeName
        : WORD
        ;   
    
    scriptAttributeValue
        : SCRIPT_ATTRIBUTE
        ;
    
    link
        : LINK_OPEN ( LINK_BODY | LINK_SHORT_BODY | LINK_NONSLASH_BODY)
        | LINK_OPEN scriptlet* ( LINK_BODY | LINK_SHORT_BODY | LINK_NONSLASH_BODY)
        ;
    
    style
        : STYLE_OPEN ( STYLE_BODY | STYLE_SHORT_BODY)
        ;
    

    编辑:自上次输入以来,我已经修改了 Parser 和 Lexer 语法。我现在在解析jsp文件时遇到问题。一个示例jsp是:

    <html>
    <title>Statement Load page</title>
    
    <script type="text/javascript" src="<%= request.getContextPath() %>"></script>
    <script type="text/javascript" src="<%= request.getContextPath() %>/scripts/Main.js"></script>
    
    <body>
    </body>
    </html>
    

    在解析这个文件时,我得到:

    line 4:0 mismatched input '<script' expecting '<'
    line 5:31 no viable alternative at input '<script type="text/javascript" src'
    

    也就是说,当遇到“

    script
        : SCRIPT_OPEN scriptAttribute* SCRIPT_TAG_CLOSE htmlContent* SCRIPT_TAG_FULL_CLOSE
        | SCRIPT_OPEN scriptAttribute* SCRIPT_TAG_SLASH_CLOSE
        ;
    
    scriptAttribute
        : scriptAttributeName SCRIPT_EQUALS QUOTE scriptlet scriptAttributeValue* QUOTE
        | scriptAttributeName SCRIPT_EQUALS scriptAttributeValue
        | scriptAttributeName
        ;
    
    scriptAttributeName
        : WORD
        ;   
    
    scriptAttributeValue
        : SCRIPT_ATTRIBUTE
        ;
    

    【讨论】:

    • 我一直在修改我的语法以更详细地解析脚本标签。但是我在解析时遇到了问题。 @Bart Kiers 你能看看这个吗?
    猜你喜欢
    • 1970-01-01
    • 2017-01-05
    • 2016-12-20
    • 1970-01-01
    • 2021-05-29
    • 1970-01-01
    • 2013-01-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多