Antlr4解析jsp scriptlets表达式指令
问题描述:
我想解析jsp文件来识别指令标签,jsp动作元素,scriptlet表达式等。为此,我试图扩展现有的html grammar。 我在正常的html标签打开和jsp标签打开方面存在问题。现有的语法有以下词法规则:Antlr4解析jsp scriptlets表达式指令
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
: '%>'
;
但我想这个问题是,只要遇到<
字符,TAG_OPEN
的词法分析规则开始运行,而不是等着看是否是jsp标记<%
。
所以,当我试图解析一个小的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'
答
好吧,我来为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)
;
编辑:我已经修改了,因为我的最后一个条目解析器和词法语法。我现在正在解析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'
也就是说,尽管遭遇“<脚本”标签解析器没有进入“脚本”的规则,但可能将其视为其他'htmlElement'。但我不确定。
解析器语法的相关部分是:
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可以请你看看这个。 –