📄 parser.jj
字号:
{
RPARENHandler();
}
}
<REFMOD2>
TOKEN:
{
/*
* in REFMOD2, we don't want to bind the whitespace and \n like we
* do when closing a directive.
*/
<REFMOD2_RPAREN: ")">
{
/*
* need to simply switch back to REFERENCE, not drop down the stack
* because we can (infinitely) chain, ala
* $foo.bar().blargh().woogie().doogie()
*/
SwitchTo( REFERENCE );
}
}
/*----------------------------------------------
*
* escape "\\" handling for the built-in directives
*
*--------------------------------------------- */
TOKEN:
{
/*
* We have to do this, because we want these to be a Text node, and
* whatever follows to be peer to this text in the tree.
*
* We need to touch the ASTs for these, because we want an even # of \'s
* to render properly in front of the block
*
* This is really simplistic. I actually would prefer to find them in
* grammatical context, but I am neither smart nor rested, a receipe
* for disaster, another long night with Mr. Parser, or both.
*/
<ESCAPE_DIRECTIVE : (<DOUBLE_ESCAPE>)* "\\#" <WORD> >
}
/*
* needed because #set is so wacky in it's desired behavior. We want set
* to eat any preceeding whitespace so it is invisible in formatting.
* (As it should be.) If this works well, I am going to chuck the whole MORE:
* token abomination.
*/
TOKEN:
{
<SET_DIRECTIVE: (" "|"\t")* ("#set" | "#{set}") (" ")* "(">
{
if (! inComment)
{
inDirective = true;
if ( debugPrint )
System.out.print("#set : going to " + DIRECTIVE );
stateStackPush();
inSet = true;
SwitchTo(DIRECTIVE);
}
/*
* need the LPAREN action
*/
if (!inComment)
{
lparen++;
/*
* If in REFERENCE and we have seen the dot, then move
* to REFMOD2 -> Modifier()
*/
if (curLexState == REFMODIFIER )
SwitchTo( REFMOD2 );
}
}
}
<*>
MORE :
{
/*
* Note : DOLLARBANG is a duplicate of DOLLAR. They must be identical.
*/
<DOLLAR: ("\\")* "$">
{
if (! inComment)
{
/*
* if we find ourselves in REFERENCE, we need to pop down
* to end the previous ref
*/
if (curLexState == REFERENCE)
{
inReference = false;
stateStackPop();
}
inReference = true;
if ( debugPrint )
System.out.print( "$ : going to " + REFERENCE );
stateStackPush();
SwitchTo(REFERENCE);
}
}
| <DOLLARBANG: ("\\")* "$" ("\\")* "!">
{
if (! inComment)
{
/*
* if we find ourselves in REFERENCE, we need to pop down
* to end the previous ref
*/
if (curLexState == REFERENCE)
{
inReference = false;
stateStackPop();
}
inReference = true;
if ( debugPrint )
System.out.print( "$! : going to " + REFERENCE );
stateStackPush();
SwitchTo(REFERENCE);
}
}
| <"#**" ~["#"]>
{
input_stream.backup(1);
inComment = true;
stateStackPush();
SwitchTo( IN_FORMAL_COMMENT);
}
| "#*"
{
inComment=true;
stateStackPush();
SwitchTo( IN_MULTI_LINE_COMMENT );
}
| <HASH : "#" >
{
if (! inComment)
{
/*
* We can have the situation where #if($foo)$foo#end.
* We need to transition out of REFERENCE before going to DIRECTIVE.
* I don't really like this, but I can't think of a legal way
* you are going into DIRECTIVE while in REFERENCE. -gmj
*/
if (curLexState == REFERENCE || curLexState == REFMODIFIER )
{
inReference = false;
stateStackPop();
}
inDirective = true;
if ( debugPrint )
System.out.print("# : going to " + DIRECTIVE );
stateStackPush();
SwitchTo(PRE_DIRECTIVE);
}
}
}
// treat the single line comment case separately
// to avoid ##<EOF> errors
<*>
TOKEN :
{
<SINGLE_LINE_COMMENT_START: "##">
{
if (!inComment)
{
if (curLexState == REFERENCE)
{
inReference = false;
stateStackPop();
}
inComment = true;
stateStackPush();
SwitchTo(IN_SINGLE_LINE_COMMENT);
}
}
}
TOKEN :
{
<DOUBLE_ESCAPE : "\\\\">
| <ESCAPE: "\\" >
| <TEXT: (~["$", "#", "\\"])+ >
}
/* -----------------------------------------------------------------------
*
* *_COMMENT Lexical tokens
*
*-----------------------------------------------------------------------*/
<IN_SINGLE_LINE_COMMENT>
TOKEN :
{
<SINGLE_LINE_COMMENT: "\n" | "\r" | "\r\n">
{
inComment = false;
stateStackPop();
}
}
<IN_FORMAL_COMMENT>
TOKEN :
{
<FORMAL_COMMENT: "*#" >
{
inComment = false;
stateStackPop();
}
}
<IN_MULTI_LINE_COMMENT>
TOKEN :
{
<MULTI_LINE_COMMENT: "*#" >
{
inComment = false;
stateStackPop();
}
}
<IN_SINGLE_LINE_COMMENT,IN_FORMAL_COMMENT,IN_MULTI_LINE_COMMENT>
SKIP :
{
< ~[] >
}
/* -----------------------------------------------------------------------
*
* DIRECTIVE Lexical State (some of it, anyway)
*
* ---------------------------------------------------------------------- */
<DIRECTIVE,REFMOD2>
TOKEN:
{
<WHITESPACE : ([" ","\t", "\n", "\r"])+ >
}
<DIRECTIVE,REFMOD2>
TOKEN :
{
// <STRING_LITERAL: ( "\"" ( ~["\"","\n","\r"] )* "\"" ) | ( "'" ( ~["'","\n","\r"] )* "'" ) >
< STRING_LITERAL:
("\""
( (~["\"","\\"])
| ("\\"
( ["n","t","b","r","f","\\","'","\""]
| ["0"-"7"] ( ["0"-"7"] )?
| ["0"-"3"] ["0"-"7"] ["0"-"7"]
)
)
| ( "\\" (" ")* "\n")
)*
"\""
)
|
("\'"
( (~["\'"])
| ( "\\" (" ")* "\n")
)*
"\'"
)
>
{
/*
* - if we are in DIRECTIVE and haven't seen ( yet, then also drop out.
* don't forget to account for the beloved yet wierd #set
* - finally, if we are in REFMOD2 (remember : $foo.bar( ) then " is ok!
*/
if( curLexState == DIRECTIVE && !inSet && lparen == 0)
stateStackPop();
}
}
<REFERENCE,DIRECTIVE,REFMODIFIER,REFMOD2>
TOKEN:
{
<TRUE: "true">
| <FALSE: "false">
}
<DIRECTIVE>
TOKEN :
{
<NEWLINE: "\n" | "\r" | "\r\n" >
{
if ( debugPrint )
System.out.println(" NEWLINE :");
stateStackPop();
if (inSet)
inSet = false;
if (inDirective)
inDirective = false;
}
}
<DIRECTIVE>
TOKEN :
{
<MINUS: "-">
| <PLUS: "+">
| <MULTIPLY: "*">
| <DIVIDE: "/">
| <MODULUS: "%">
| <LOGICAL_AND: "&&" | "and" >
| <LOGICAL_OR: "||" | "or" >
| <LOGICAL_LT: "<" | "lt" >
| <LOGICAL_LE: "<=" | "le" >
| <LOGICAL_GT: ">" | "gt" >
| <LOGICAL_GE: ">=" | "ge" >
| <LOGICAL_EQUALS: "==" | "eq" >
| <LOGICAL_NOT_EQUALS: "!=" | "ne" >
| <LOGICAL_NOT: "!" | "not" >
| <EQUALS: "=" >
}
<PRE_DIRECTIVE>
TOKEN :
{
<END: ( "end" ( ( " " | "\t" )* ( "\n" | "\r" | "\r\n" ) )? )
| ("{end}" ( ( " " | "\t" )* ( "\n" | "\r" | "\r\n" ) )? ) >
{
inDirective = false;
stateStackPop();
}
| <IF_DIRECTIVE: "if" | "{if}">
{
SwitchTo(DIRECTIVE);
}
| <ELSEIF_DIRECTIVE: "elseif" | "{elseif}">
{
SwitchTo(DIRECTIVE);
}
| <ELSE_DIRECTIVE:
( "else" ( ( " " | "\t" )* ( "\n" | "\r" | "\r\n" ) )? )
| ( "{else}" ( ( " " | "\t" )* ( "\n" | "\r" | "\r\n" ) )? ) >
{
inDirective = false;
stateStackPop();
}
| <STOP_DIRECTIVE: "stop" | "{stop}" >
{
inDirective = false;
stateStackPop();
}
}
<PRE_DIRECTIVE,DIRECTIVE,REFMOD2>
TOKEN:
{
<#DIGIT: [ "0"-"9" ] >
/*
* treat FLOATING_POINT_LITERAL and INTEGER_LITERAL differently as a range can only handle integers.
*/
/**
* Note -- we also define an integer as ending with a double period,
* in order to avoid 1..3 being defined as floating point (1.) then a period, then a integer
*/
| <INTEGER_LITERAL: ("-")? (<DIGIT>)+ ("..")? >
{
/*
* Remove the double period if it is there
*/
if (matchedToken.image.endsWith("..")) {
input_stream.backup(2);
matchedToken.image = matchedToken.image.substring(0,matchedToken.image.length()-2);
}
/*
* check to see if we are in set
* ex. #set $foo = $foo + 3
* because we want to handle the \n after
*/
if ( lparen == 0 && !inSet && curLexState != REFMOD2)
{
stateStackPop();
}
}
| <FLOATING_POINT_LITERAL:
("-")? (<DIGIT>)+ "." (<DIGIT>)* (<EXPONENT>)?
| ("-")? "." (<DIGIT>)+ (<EXPONENT>)?
| ("-")? (<DIGIT>)+ <EXPONENT>
>
{
/*
* check to see if we are in set
* ex. #set $foo = $foo + 3
* because we want to handle the \n after
*/
if ( lparen == 0 && !inSet && curLexState != REFMOD2)
{
stateStackPop();
}
}
|
<#EXPONENT: ["e","E"] (["+","-"])? (["0"-"9"])+ >
}
<PRE_DIRECTIVE,DIRECTIVE>
TOKEN:
{
<#LETTER: [ "a"-"z", "A" - "Z" ] >
| <#DIRECTIVE_CHAR: [ "a"-"z", "A"-"Z", "0"-"9", "_" ] >
| <WORD: ( <LETTER> | ["_"]) (<DIRECTIVE_CHAR>)* >
| <BRACKETED_WORD: "{" ( <LETTER> | ["_"]) (<DIRECTIVE_CHAR>)* "}" >
}
/* -----------------------------------------------------------------------
*
* REFERENCE Lexical States
*
* This is more than a single state, because of the structure of
* the VTL references. We use three states because the set of tokens
* for each state can be different.
*
* $foo.bar( "arg" )
* ^ ^ ^
* | | |
* ----------- > REFERENCE : state initiated by the '$' character. Continues
* | | until end of the reference, or the . character.
* |------ > REFMODIFIER : state switched to when the <DOT> is encountered.
* | note that this is a switch, not a push. See notes at bottom
* | re stateStack.
* |-- > REFMOD2 : state switch to when the LPAREN is encountered.
* again, this is a switch, not a push.
*
* ---------------------------------------------------------------------------- */
<REFERENCE,REFMODIFIER,REFMOD2>
TOKEN :
{
<#ALPHA_CHAR: ["a"-"z", "A"-"Z"] >
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -