📄 parser.jj
字号:
| <#ALPHANUM_CHAR: [ "a"-"z", "A"-"Z", "0"-"9" ] >
| <#IDENTIFIER_CHAR: [ "a"-"z", "A"-"Z", "0"-"9", "-", "_" ] >
| <IDENTIFIER: ( <ALPHA_CHAR> | ["_"]) (<IDENTIFIER_CHAR>)* >
| <DOT: "." <ALPHA_CHAR>>
{
/*
* push the alpha char back into the stream so the following identifier
* is complete
*/
input_stream.backup(1);
/*
* and munge the <DOT> so we just get a . when we have normal text that
* looks like a ref.ident
*/
matchedToken.image = ".";
if ( debugPrint )
System.out.print("DOT : switching to " + REFMODIFIER);
SwitchTo(REFMODIFIER);
}
}
<REFERENCE,REFMODIFIER>
TOKEN :
{
<LCURLY: "{">
| <RCURLY: "}">
{
stateStackPop();
}
}
<REFERENCE,REFMODIFIER,REFMOD2>
SPECIAL_TOKEN :
{
<REFERENCE_TERMINATOR: ~[] >
{
/*
* push every terminator character back into the stream
*/
input_stream.backup(1);
inReference = false;
if ( debugPrint )
System.out.print("REF_TERM :");
stateStackPop();
}
}
<PRE_DIRECTIVE>
SPECIAL_TOKEN :
{
<DIRECTIVE_TERMINATOR: ~[] >
{
if ( debugPrint )
System.out.print("DIRECTIVE_TERM :");
input_stream.backup(1);
inDirective = false;
stateStackPop();
}
}
/**
* This method is what starts the whole parsing
* process. After the parsing is complete and
* the template has been turned into an AST,
* this method returns the root of AST which
* can subsequently be traversed by a visitor
* which implements the ParserVisitor interface
* which is generated automatically by JavaCC
*/
SimpleNode process() : {/*@bgen(jjtree) process */
ASTprocess jjtn000 = new ASTprocess(this, JJTPROCESS);
boolean jjtc000 = true;
jjtree.openNodeScope(jjtn000);
/*@egen*/}
{/*@bgen(jjtree) process */
try {
/*@egen*/
( Statement() )* <EOF>/*@bgen(jjtree)*/
{
jjtree.closeNodeScope(jjtn000, true);
jjtc000 = false;
}
/*@egen*/
{ return jjtn000; }/*@bgen(jjtree)*/
} catch (Throwable jjte000) {
if (jjtc000) {
jjtree.clearNodeScope(jjtn000);
jjtc000 = false;
} else {
jjtree.popNode();
}
if (jjte000 instanceof RuntimeException) {
throw (RuntimeException)jjte000;
}
if (jjte000 instanceof ParseException) {
throw (ParseException)jjte000;
}
throw (Error)jjte000;
} finally {
if (jjtc000) {
jjtree.closeNodeScope(jjtn000, true);
}
}
/*@egen*/
}
/**
* These are the types of statements that
* are acceptable in Velocity templates.
*/
void Statement() : {}
{
IfStatement()
| StopStatement()
| LOOKAHEAD(2) Reference()
| Comment()
| SetDirective()
| EscapedDirective()
| Escape()
| Directive()
| Text()
}
/**
* used to separate the notion of a valid directive that has been
* escaped, versus something that looks like a directive and
* is just schmoo. This is important to do as a separate production
* that creates a node, because we want this, in either case, to stop
* the further parsing of the Directive() tree.
*/
void EscapedDirective() : {/*@bgen(jjtree) EscapedDirective */
ASTEscapedDirective jjtn000 = new ASTEscapedDirective(this, JJTESCAPEDDIRECTIVE);
boolean jjtc000 = true;
jjtree.openNodeScope(jjtn000);
/*@egen*/}
{/*@bgen(jjtree) EscapedDirective */
try {
/*@egen*/
{
Token t = null;
}
t = <ESCAPE_DIRECTIVE>/*@bgen(jjtree)*/
{
jjtree.closeNodeScope(jjtn000, true);
jjtc000 = false;
}
/*@egen*/
{
/*
* churn and burn..
*/
t.image = escapedDirective( t.image );
}/*@bgen(jjtree)*/
} finally {
if (jjtc000) {
jjtree.closeNodeScope(jjtn000, true);
}
}
/*@egen*/
}
/**
* Used to catch and process escape sequences in grammatical constructs
* as escapes outside of VTL are just characters. Right now we have both
* this and the EscapeDirective() construction because in the EscapeDirective()
* case, we want to suck in the #<directive> and here we don't. We just want
* the escapes to render correctly
*/
void Escape() : {/*@bgen(jjtree) Escape */
ASTEscape jjtn000 = new ASTEscape(this, JJTESCAPE);
boolean jjtc000 = true;
jjtree.openNodeScope(jjtn000);
/*@egen*/}
{/*@bgen(jjtree) Escape */
try {
/*@egen*/
{
Token t = null;
int count = 0;
boolean control = false;
}
( LOOKAHEAD(2) t = <DOUBLE_ESCAPE>
{
count++;
}
)+/*@bgen(jjtree)*/
{
jjtree.closeNodeScope(jjtn000, true);
jjtc000 = false;
}
/*@egen*/
{
/*
* first, check to see if we have a control directive
*/
switch(t.next.kind ) {
case IF_DIRECTIVE :
case ELSE_DIRECTIVE :
case ELSEIF_DIRECTIVE :
case END :
case STOP_DIRECTIVE :
control = true;
break;
}
/*
* if that failed, lets lookahead to see if we matched a PD or a VM
*/
if ( isDirective( t.next.image.substring(1)))
control = true;
else if ( rsvc.isVelocimacro( t.next.image.substring(1), currentTemplateName))
control = true;
jjtn000.val = "";
for( int i = 0; i < count; i++)
jjtn000.val += ( control ? "\\" : "\\\\");
}/*@bgen(jjtree)*/
} finally {
if (jjtc000) {
jjtree.closeNodeScope(jjtn000, true);
}
}
/*@egen*/
}
void Comment() : {/*@bgen(jjtree) Comment */
ASTComment jjtn000 = new ASTComment(this, JJTCOMMENT);
boolean jjtc000 = true;
jjtree.openNodeScope(jjtn000);
/*@egen*/}
{/*@bgen(jjtree) Comment */
try {
/*@egen*/
<SINGLE_LINE_COMMENT_START> ( <SINGLE_LINE_COMMENT> ) ?
| <MULTI_LINE_COMMENT>
| <FORMAL_COMMENT>/*@bgen(jjtree)*/
} finally {
if (jjtc000) {
jjtree.closeNodeScope(jjtn000, true);
}
}
/*@egen*/
}
void FloatingPointLiteral() : {/*@bgen(jjtree) FloatingPointLiteral */
ASTFloatingPointLiteral jjtn000 = new ASTFloatingPointLiteral(this, JJTFLOATINGPOINTLITERAL);
boolean jjtc000 = true;
jjtree.openNodeScope(jjtn000);
/*@egen*/}
{/*@bgen(jjtree) FloatingPointLiteral */
try {
/*@egen*/
<FLOATING_POINT_LITERAL>/*@bgen(jjtree)*/
} finally {
if (jjtc000) {
jjtree.closeNodeScope(jjtn000, true);
}
}
/*@egen*/
}
void IntegerLiteral() : {/*@bgen(jjtree) IntegerLiteral */
ASTIntegerLiteral jjtn000 = new ASTIntegerLiteral(this, JJTINTEGERLITERAL);
boolean jjtc000 = true;
jjtree.openNodeScope(jjtn000);
/*@egen*/}
{/*@bgen(jjtree) IntegerLiteral */
try {
/*@egen*/
<INTEGER_LITERAL>/*@bgen(jjtree)*/
} finally {
if (jjtc000) {
jjtree.closeNodeScope(jjtn000, true);
}
}
/*@egen*/
}
void StringLiteral() : {/*@bgen(jjtree) StringLiteral */
ASTStringLiteral jjtn000 = new ASTStringLiteral(this, JJTSTRINGLITERAL);
boolean jjtc000 = true;
jjtree.openNodeScope(jjtn000);
/*@egen*/}
{/*@bgen(jjtree) StringLiteral */
try {
/*@egen*/
<STRING_LITERAL>/*@bgen(jjtree)*/
} finally {
if (jjtc000) {
jjtree.closeNodeScope(jjtn000, true);
}
}
/*@egen*/
}
/**
* This method corresponds to variable
* references in Velocity templates.
* The following are examples of variable
* references that may be found in a
* template:
*
* $foo
* $bar
*
*/
void Identifier() : {/*@bgen(jjtree) Identifier */
ASTIdentifier jjtn000 = new ASTIdentifier(this, JJTIDENTIFIER);
boolean jjtc000 = true;
jjtree.openNodeScope(jjtn000);
/*@egen*/}
{/*@bgen(jjtree) Identifier */
try {
/*@egen*/
<IDENTIFIER>/*@bgen(jjtree)*/
} finally {
if (jjtc000) {
jjtree.closeNodeScope(jjtn000, true);
}
}
/*@egen*/
}
void Word() : {/*@bgen(jjtree) Word */
ASTWord jjtn000 = new ASTWord(this, JJTWORD);
boolean jjtc000 = true;
jjtree.openNodeScope(jjtn000);
/*@egen*/}
{/*@bgen(jjtree) Word */
try {
/*@egen*/
<WORD>/*@bgen(jjtree)*/
} finally {
if (jjtc000) {
jjtree.closeNodeScope(jjtn000, true);
}
}
/*@egen*/
}
/**
* Supports the arguments for the Pluggable Directives
*/
int DirectiveArg() : {}
{
Reference()
{
return ParserTreeConstants.JJTREFERENCE;
}
| Word()
{
return ParserTreeConstants.JJTWORD;
}
| StringLiteral()
{
return ParserTreeConstants.JJTSTRINGLITERAL;
}
| IntegerLiteral()
{
return ParserTreeConstants.JJTINTEGERLITERAL;
}
/*
* Need to put this before the floating point expansion
*/
| LOOKAHEAD( <LBRACKET> [<WHITESPACE>] ( Reference() | IntegerLiteral()) [<WHITESPACE>] <DOUBLEDOT> ) IntegerRange()
{
return ParserTreeConstants.JJTINTEGERRANGE;
}
| FloatingPointLiteral()
{
return ParserTreeConstants.JJTFLOATINGPOINTLITERAL;
}
| Map()
{
return ParserTreeConstants.JJTMAP;
}
| ObjectArray()
{
return ParserTreeConstants.JJTOBJECTARRAY;
}
| True()
{
return ParserTreeConstants.JJTTRUE;
}
| False()
{
return ParserTreeConstants.JJTFALSE;
}
}
/**
* Supports the Pluggable Directives
* #foo( arg+ )
*/
SimpleNode Directive() :
{/*@bgen(jjtree) Directive */
ASTDirective jjtn000 = new ASTDirective(this, JJTDIRECTIVE);
boolean jjtc000 = true;
jjtree.openNodeScope(jjtn000);
/*@egen*/
Token t = null;
int argType;
int argPos = 0;
Directive d;
int directiveType;
boolean isVM = false;
boolean doItNow = false;
}
{/*@bgen(jjtree) Directive */
try {
/*@egen*/
/*
* note that if we were escaped, that is now handled by
* EscapedDirective()
*/
((t = <WORD>) | (t = <BRACKETED_WORD>))
{
String directiveName;
if (t.kind == ParserConstants.BRACKETED_WORD)
{
directiveName = t.image.substring(2,t.image.length() - 1);
}
else
{
directiveName = t.image.substring(1);
}
d = (Directive) directives.get(directiveName);
/*
* Velocimacro support : if the directive is macro directive
* then set the flag so after the block parsing, we add the VM
* right then. (So available if used w/in the current template )
*/
if (directiveName.equals("macro"))
{
doItNow = true;
}
/*
* set the directive name from here. No reason for the thing to know
* about parser tokens
*/
jjtn000.setDirectiveName(directiveName);
if ( d == null)
{
/*
* if null, then not a real directive, but maybe a Velocimacro
*/
isVM = rsvc.isVelocimacro(directiveName, currentTemplateName);
if (!isVM)
{
token_source.stateStackPop();
token_source.inDirective = false;
return jjtn000;
}
/*
* Currently, all VMs are LINE directives
*/
directiveType = Directive.LINE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -