我一直在研究HTML(FreeMarker)中嵌入的一些模板语言的解析器,这里有一个例子:
${abc}
<html>
<head>
<title>Welcome!</title>
</head>
<body>
<h1>
Welcome ${user}<#if user == "Big Joe">, our beloved
leader</#if>!
</h1>
<p>Our latest product:
<a href="${latestProduct}">${latestProduct}</a>!
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
模板语言介于某些特定标签之间,例如'$ {''}','<#''>'.中间的其他原始文本可以被视为相同的令牌(RAW).
这里的关键点是相同的文本,例如整数,对于解析器来说意味着不同的东西取决于它是否在这些标记之间,因此需要被视为不同的标记.
我尝试过以下丑陋的实现,并使用自定义状态来指示它是否在这些标记中.如你所见,我必须在每条规则中检查状态,这让我发疯...
我还想到了以下两种解决方案:
使用多个词法分析器.我可以在这些标签的内部/外部切换两个词法分析器.但是,ANTLR3的文档很差.我不知道如何让一个解析器共享两个不同的词法分析器并在它们之间切换.
在NUMERICAL_ESCAPE规则之后向上移动RAW规则.检查那里的状态,如果它在标签中,则放回令牌并继续尝试左边的规则.这将节省大量的状态检查.但是,我没有找到任何"回放"功能,而ANTLR抱怨一些规则永远无法匹配......
有一个优雅的解决方案吗?
grammar freemarker_simple;
@lexer::members {
int freemarker_type = 0;
}
expression
: primary_expression ;
primary_expression
: number_literal | identifier | parenthesis | builtin_variable
;
parenthesis
: OPEN_PAREN expression CLOSE_PAREN ;
number_literal
: INTEGER | DECIMAL
;
identifier
: ID
;
builtin_variable
: DOT ID
;
string_output
: OUTPUT_ESCAPE …Run Code Online (Sandbox Code Playgroud)