我在解析< script>时遇到了困难使用antlr4标记其中的scriptlet表达式。我从现有的HTMLParser和Lexer语法开始,并尝试根据自己的需要进行修改。 Parser语法是:
parser grammar HTMLParser;
options { tokenVocab=HTMLLexer; }
htmlDocument
: script*
;
script
: SCRIPT_OPEN scriptAttribute* SCRIPT_TAG_CLOSE? WORD? SCRIPT_TAG_FULL_CLOSE
| SCRIPT_OPEN scriptAttribute* SCRIPT_TAG_SLASH_CLOSE
;
scriptAttribute
: scriptAttributeName SCRIPT_EQUALS QUOTE SCRIPLET_INSIDE_SCRIPT javaExpression SCRIPTLET_TAG_CLOSE scriptAttributeValue? QUOTE
| scriptAttributeName SCRIPT_EQUALS QUOTE scriptAttributeValue QUOTE
| scriptAttributeName
;
scriptAttributeName
: WORD
;
scriptAttributeValue
: SCRIPT_ATTRIBUTE
;
scriptlet
: 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*
;
词法分析器语法:
lexer grammar HTMLLexer;
SCRIPT_OPEN
: '<script' ->pushMode(SCRIPT)
;
SCRIPTLET_TAG_OPEN
: ('<%!' | '<%=' | '<%') ->pushMode(SCRIPTVALUE)
;
SEA_WS
: (' '|'\t'|'\r'? '\n')+
;
TAG_NAME
: TAG_NameStartChar TAG_NameChar*
// | TAG_NameStartChar* ':' TAG_NameStartChar*
;
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'
;
TAG_EQUALS
: '=' -> pushMode(ATTVALUE)
;
//
// 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
: '\'' ~[<']* '\''
;
//
// <scripts>
//
mode SCRIPT;
SCRIPT_TAG_FULL_CLOSE
: '</script>' ->popMode
;
SCRIPT_TAG_CLOSE
: '>'
;
SCRIPT_TAG_SLASH_CLOSE
: '/>' -> popMode
;
SCRIPT_EQUALS
: '='
;
SCRIPLET_INSIDE_SCRIPT
: '<%' ->pushMode(SCRIPTVALUE)
;
SCRIPT_ATTRIBUTE
: SCRIPT_ATTCHARS
;
fragment SCRIPT_ATTCHARS
: SCRIPT_ATTCHAR+
;
SCRIPTTAG_WS
: [ \r\n\t]+ -> channel(HIDDEN)
;
WORD
: [a-zA-Z]+
;
QUOTE
: '"'
;
fragment SCRIPT_ATTCHAR
: '-'
| '_'
| '.'
| '/'
| ','
| ';'
| '\''
// | '"'
| [0-9a-zA-Z]
;
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]
;
请注意:目前,我只是在一个非现实简单的两行文件上使用以下文本测试解析器:
<script type="text/javascript" src="<%= request.getContextPath() %>"></script>
<script type="text/javascript" src="<%= request.getContextPath() %>/scripts/Main.js"></script>
输出结果为:
line 1:8 no viable alternative at input '<script type'
^<script^ start start index: 0 start stop index: 6
^<script^ start start index: 0 start stop index: 6
^
^ stop start index: 78 stop stop index: 79
^<script^ start start index: 80 start stop index: 86
^
请注意,停止令牌开始索引是从上一行的换行符开始的。我的最终目标是创建一个jsp语法,我可以在其中识别每个脚本,链接,样式,jsp标记库标记,并用其他东西替换它们。其余的语法都已到位,但我在解析脚本标记时遇到了困难。