📄 parser.java
字号:
/* Generated By:JJTree&JavaCC: Do not edit this line. Parser.java */
package org.apache.velocity.runtime.parser;
import java.io.*;
import java.util.*;
import org.apache.velocity.runtime.RuntimeServices;
import org.apache.velocity.runtime.parser.node.*;
import org.apache.velocity.runtime.directive.Directive;
import org.apache.velocity.runtime.directive.Macro;
import org.apache.velocity.runtime.directive.MacroParseException;
import org.apache.velocity.util.StringUtils;
/**
* This class is responsible for parsing a Velocity
* template. This class was generated by JavaCC using
* the JJTree extension to produce an Abstract
* Syntax Tree (AST) of the template.
*
* Please look at the Parser.jjt file which is
* what controls the generation of this class.
*
* @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
* @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
* @version $Id: Parser.java,v 1.74 2002/04/27 19:33:30 geirm Exp $
*/
public class Parser/*@bgen(jjtree)*/implements ParserTreeConstants, ParserConstants {/*@bgen(jjtree)*/
protected JJTParserState jjtree = new JJTParserState();/**
* This Hashtable contains a list of all of the dynamic directives.
*/
private Hashtable directives = new Hashtable(0);
/**
* Name of current template we are parsing. Passed to us in parse()
*/
String currentTemplateName = "";
VelocityCharStream velcharstream = null;
private RuntimeServices rsvc = null;
/**
* This constructor was added to allow the re-use of parsers.
* The normal constructor takes a single argument which
* an InputStream. This simply creates a re-usable parser
* object, we satisfy the requirement of an InputStream
* by using a newline character as an input stream.
*/
public Parser( RuntimeServices rs)
{
/*
* need to call the CTOR first thing.
*/
this( new VelocityCharStream(
new ByteArrayInputStream("\n".getBytes()), 1, 1 ));
/*
* now setup a VCS for later use
*/
velcharstream = new VelocityCharStream(
new ByteArrayInputStream("\n".getBytes()), 1, 1 );
/*
* and save the RuntimeServices
*/
rsvc = rs;
}
/**
* This was also added to allow parsers to be
* re-usable. Normal JavaCC use entails passing an
* input stream to the constructor and the parsing
* process is carried out once. We want to be able
* to re-use parsers: we do this by adding this
* method and re-initializing the lexer with
* the new stream that we want parsed.
*/
public SimpleNode parse( Reader reader, String templateName )
throws ParseException
{
SimpleNode sn = null;
currentTemplateName = templateName;
try
{
token_source.clearStateVars();
/*
* reinitialize the VelocityCharStream
* with the new reader
*/
velcharstream.ReInit( reader, 1, 1 );
/*
* now reinit the Parser with this CharStream
*/
ReInit( velcharstream );
/*
* do that voodoo...
*/
sn = process();
}
catch (MacroParseException mee)
{
/*
* thrown by the Macro class when something is amiss in the
* Macro specification
*/
rsvc.error ("Parser Error: #macro() : " + templateName + " : " + StringUtils.stackTrace(mee));
throw new ParseException(mee.getMessage());
}
catch (ParseException pe)
{
rsvc.error ("Parser Exception: " + templateName + " : " + StringUtils.stackTrace(pe));
throw new ParseException (pe.currentToken,
pe.expectedTokenSequences, pe.tokenImage);
}
catch (TokenMgrError tme)
{
throw new ParseException("Lexical error: " + tme.toString());
}
catch (Exception e)
{
rsvc.error ("Parser Error: " + templateName + " : " + StringUtils.stackTrace(e));
}
currentTemplateName = "";
return sn;
}
/**
* This method sets the directives Hashtable
*/
public void setDirectives(Hashtable directives)
{
this.directives = directives;
}
/**
* This method gets a Directive from the directives Hashtable
*/
public Directive getDirective(String directive)
{
return (Directive) directives.get(directive);
}
/**
* This method finds out of the directive exists in the directives
* Hashtable.
*/
public boolean isDirective(String directive)
{
if (directives.containsKey(directive))
return true;
else
return false;
}
/**
* Produces a processed output for an escaped control or
* pluggable directive
*/
private String escapedDirective( String strImage )
{
int iLast = strImage.lastIndexOf("\\");
String strDirective = strImage.substring(iLast + 1);
boolean bRecognizedDirective = false;
/*
* is this a PD or a control directive?
*/
if ( isDirective( strDirective.substring(1)))
{
bRecognizedDirective = true;
}
else if ( rsvc.isVelocimacro( strDirective.substring(1), currentTemplateName))
{
bRecognizedDirective = true;
}
else
{
/* order for speed? */
if ( strDirective.substring(1).equals("if")
|| strDirective.substring(1).equals("end")
|| strDirective.substring(1).equals("set")
|| strDirective.substring(1).equals("else")
|| strDirective.substring(1).equals("elseif")
|| strDirective.substring(1).equals("stop")
)
{
bRecognizedDirective = true;
}
}
/*
* if so, make the proper prefix string (let the escapes do their thing..)
* otherwise, just return what it is..
*/
if (bRecognizedDirective)
return ( strImage.substring(0,iLast/2) + strDirective);
else
return ( strImage );
}
/**
* 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
*/
final public SimpleNode process() throws ParseException {
/*@bgen(jjtree) process */
ASTprocess jjtn000 = new ASTprocess(this, JJTPROCESS);
boolean jjtc000 = true;
jjtree.openNodeScope(jjtn000);
try {
label_1:
while (true) {
switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
case LPAREN:
case RPAREN:
case ESCAPE_DIRECTIVE:
case SET_DIRECTIVE:
case DOUBLE_ESCAPE:
case ESCAPE:
case TEXT:
case SINGLE_LINE_COMMENT:
case FORMAL_COMMENT:
case MULTI_LINE_COMMENT:
case STRING_LITERAL:
case IF_DIRECTIVE:
case STOP_DIRECTIVE:
case NUMBER_LITERAL:
case WORD:
case IDENTIFIER:
case DOT:
case LCURLY:
case RCURLY:
;
break;
default:
jj_la1[0] = jj_gen;
break label_1;
}
Statement();
}
jj_consume_token(0);
jjtree.closeNodeScope(jjtn000, true);
jjtc000 = false;
{if (true) return jjtn000;}
} catch (Throwable jjte000) {
if (jjtc000) {
jjtree.clearNodeScope(jjtn000);
jjtc000 = false;
} else {
jjtree.popNode();
}
if (jjte000 instanceof RuntimeException) {
{if (true) throw (RuntimeException)jjte000;}
}
if (jjte000 instanceof ParseException) {
{if (true) throw (ParseException)jjte000;}
}
{if (true) throw (Error)jjte000;}
} finally {
if (jjtc000) {
jjtree.closeNodeScope(jjtn000, true);
}
}
throw new Error("Missing return statement in function");
}
/**
* These are the types of statements that
* are acceptable in Velocity templates.
*/
final public void Statement() throws ParseException {
switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
case IF_DIRECTIVE:
IfStatement();
break;
case STOP_DIRECTIVE:
StopStatement();
break;
default:
jj_la1[1] = jj_gen;
if (jj_2_1(2)) {
Reference();
} else {
switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
case SINGLE_LINE_COMMENT:
case FORMAL_COMMENT:
case MULTI_LINE_COMMENT:
Comment();
break;
case SET_DIRECTIVE:
SetDirective();
break;
case ESCAPE_DIRECTIVE:
EscapedDirective();
break;
case DOUBLE_ESCAPE:
Escape();
break;
case WORD:
Directive();
break;
case LPAREN:
case RPAREN:
case ESCAPE:
case TEXT:
case STRING_LITERAL:
case NUMBER_LITERAL:
case DOT:
case LCURLY:
case RCURLY:
Text();
break;
default:
jj_la1[2] = jj_gen;
jj_consume_token(-1);
throw new ParseException();
}
}
}
}
/**
* 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.
*/
final public void EscapedDirective() throws ParseException {
/*@bgen(jjtree) EscapedDirective */
ASTEscapedDirective jjtn000 = new ASTEscapedDirective(this, JJTESCAPEDDIRECTIVE);
boolean jjtc000 = true;
jjtree.openNodeScope(jjtn000);
try {
Token t = null;
t = jj_consume_token(ESCAPE_DIRECTIVE);
jjtree.closeNodeScope(jjtn000, true);
jjtc000 = false;
/*
* churn and burn..
*/
t.image = escapedDirective( t.image );
} finally {
if (jjtc000) {
jjtree.closeNodeScope(jjtn000, true);
}
}
}
/**
* 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
*/
final public void Escape() throws ParseException {
/*@bgen(jjtree) Escape */
ASTEscape jjtn000 = new ASTEscape(this, JJTESCAPE);
boolean jjtc000 = true;
jjtree.openNodeScope(jjtn000);
try {
Token t = null;
int count = 0;
boolean control = false;
label_2:
while (true) {
t = jj_consume_token(DOUBLE_ESCAPE);
count++;
if (jj_2_2(2)) {
;
} else {
break label_2;
}
}
jjtree.closeNodeScope(jjtn000, true);
jjtc000 = false;
/*
* 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 ? "\\" : "\\\\");
} finally {
if (jjtc000) {
jjtree.closeNodeScope(jjtn000, true);
}
}
}
final public void Comment() throws ParseException {
/*@bgen(jjtree) Comment */
ASTComment jjtn000 = new ASTComment(this, JJTCOMMENT);
boolean jjtc000 = true;
jjtree.openNodeScope(jjtn000);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -