⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fmparser.jj

📁 freemaker安装软件
💻 JJ
📖 第 1 页 / 共 5 页
字号:
/*
 * Copyright (c) 2003 The Visigoth Software Society. All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution, if
 *    any, must include the following acknowledgement:
 *       "This product includes software developed by the
 *        Visigoth Software Society (http://www.visigoths.org/)."
 *    Alternately, this acknowledgement may appear in the software itself,
 *    if and wherever such third-party acknowledgements normally appear.
 *
 * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the 
 *    project contributors may be used to endorse or promote products derived
 *    from this software without prior written permission. For written
 *    permission, please contact visigoths@visigoths.org.
 *
 * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth"
 *    nor may "FreeMarker" or "Visigoth" appear in their names
 *    without prior written permission of the Visigoth Software Society.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Visigoth Software Society. For more
 * information on the Visigoth Software Society, please see
 * http://www.visigoths.org/
 */

options
{
   STATIC=false;
   UNICODE_INPUT=true;
//   DEBUG_TOKEN_MANAGER=true;
//   DEBUG_PARSER=true;
}

PARSER_BEGIN(FMParser)

package freemarker.core;

import freemarker.template.*;
import freemarker.template.utility.StringUtil;
import freemarker.template.utility.DeepUnwrap;
import java.io.*;
import java.util.*;

/**
 * This class is generated by JavaCC from a grammar file.
 */
public class FMParser {

// Necessary for adding macros and setting location info.
  Template template;
  private String templateName;

// variables that keep track of whether we are in a loop or a switch.
  private int loopNesting, switchNesting;
  private boolean inMacro, inFunction, stripWhitespace, stripText;
  private LinkedList escapes = new LinkedList();
  private int contentNesting; // for stripText
  
  /**
   * Create an FM expression parser using a string.
   */
  static public FMParser createExpressionParser(String s) {
      SimpleCharStream scs = new SimpleCharStream(new StringReader(s), 1, 1, s.length());
      FMParserTokenManager token_source = new FMParserTokenManager(scs);
      token_source.SwitchTo(FMParserConstants.FM_EXPRESSION);
      return new FMParser(token_source);
  }
  
  /**
   * Constructs a new parser object.
   * @param template The template associated with this parser.
   * @param reader The character stream to use as input
   * @param strictEscapeSyntax Whether FreeMarker directives must start with a #
   */
  public FMParser(Template template, Reader reader, boolean strictEscapeSyntax, boolean stripWhitespace) {
      this(reader);
      this.template = template;
      token_source.strictEscapeSyntax = strictEscapeSyntax;
      this.templateName = template != null ? template.getName() : "";
      token_source.templateName = templateName;
      this.stripWhitespace = stripWhitespace;
  }
  
  public FMParser(Template template, Reader reader, boolean strictEscapeSyntax, boolean stripWhitespace, int tagSyntax) {
      this(template, reader, strictEscapeSyntax, stripWhitespace);
      switch (tagSyntax) {
          case Configuration.AUTO_DETECT_TAG_SYNTAX : 
	     token_source.autodetectTagSyntax = true;
	     break;
	  case Configuration.ANGLE_BRACKET_TAG_SYNTAX :
	     token_source.altDirectiveSyntax = false;
	     break;
	  case Configuration.SQUARE_BRACKET_TAG_SYNTAX :
	     token_source.altDirectiveSyntax = true;
	     break;
	  default : throw new IllegalArgumentException("Illegal argument for tagSyntax");
      }
  }
  
  public FMParser(String template) {
      this(null, new StringReader(template), true, true);
  }
  
  private String getErrorStart(Token t) {
      return "Error in template: " + template.getName()
            + "\non line " + t.beginLine + ", column " + t.beginColumn;
  }

  /**
   * Throw an exception if the expression passed in is a String
   * Literal
   */
  private void notStringLiteral(Expression exp, String expected) throws ParseException {
      if (exp instanceof StringLiteral) {
         String msg = "Error " + exp.getStartLocation()
                     + "\nFound string literal: " + exp
                     + "\nExpecting: " + expected;
         throw new ParseException(msg, exp);
      }
  }

  /**
   * Throw an exception if the expression passed in is a Number
   * Literal
   */
  private void notNumberLiteral(Expression exp, String expected) throws ParseException {
      if (exp instanceof NumberLiteral) {
         String msg = "Error " + exp.getStartLocation()
                     + "\nFound number literal: " + exp.getCanonicalForm()
                     + "\nExpecting " + expected;
         throw new ParseException(msg, exp);
      }
  }

  /**
   * Throw an exception if the expression passed in is a boolean
   * Literal
   */
  private void notBooleanLiteral(Expression exp, String expected) throws ParseException {
      if (exp instanceof BooleanLiteral) {
         String msg = "Error " + exp.getStartLocation()
                     + "\nFound: " + exp.getCanonicalForm()
                     + "\nExpecting " + expected;
         throw new ParseException(msg, exp);
      }
  }

  /**
   * Throw an exception if the expression passed in is a Hash
   * Literal
   */
  private void notHashLiteral(Expression exp, String expected) throws ParseException {
        if (exp instanceof HashLiteral) {
         String msg = "Error " + exp.getStartLocation()
                     + "\nFound hash literal: " + exp.getCanonicalForm()
                     + "\nExpecting " + expected;
         throw new ParseException(msg, exp);
      }
  }

  /**
   * Throw an exception if the expression passed in is a List
   * Literal
   */

  private void notListLiteral(Expression exp, String expected)
      throws ParseException
  {
        if (exp instanceof ListLiteral) {
         String msg = "Error " + exp.getStartLocation()
                     + "\nFound list literal: " + exp.getCanonicalForm()
                     + "\nExpecting " + expected;
         throw new ParseException(msg, exp);
      }
  }
  /**
   * Throw an exception if the expression passed in is a literal
   * other than of the numerical type
   */
  private void numberLiteralOnly(Expression exp) throws ParseException {
      notStringLiteral(exp, "number");
      notListLiteral(exp, "number");
      notHashLiteral(exp, "number");
      notBooleanLiteral(exp, "number");
  }

  /**
   * Throw an exception if the expression passed in is
   * not a string.
   */
  private void stringLiteralOnly(Expression exp) throws ParseException {
      notNumberLiteral(exp, "number");
      notListLiteral(exp, "number");
      notHashLiteral(exp, "number");
      notBooleanLiteral(exp, "number");
  }

  /**
   * Throw an exception if the expression passed in is a literal
   * other than of the boolean type
   */
  private void booleanLiteralOnly(Expression exp) throws ParseException {
      notStringLiteral(exp, "boolean (true/false)");
      notListLiteral(exp, "boolean (true/false)");
      notHashLiteral(exp, "boolean (true/false)");
      notNumberLiteral(exp, "boolean (true/false)");
  }

  private Expression escapedExpression(Expression exp) {
      if(!escapes.isEmpty()) {
          return ((EscapeBlock)escapes.getFirst()).doEscape(exp);
      }
      return exp;
  }
  
  private boolean getBoolean(Expression exp) throws ParseException {
      TemplateModel tm = null;
      try {
          tm = exp.getAsTemplateModel(null);
      } catch (Exception e) {
         throw new ParseException(e.getMessage() 
                                  + "\nCould not evaluate expression: "
                                  + exp.getCanonicalForm()
                                  + exp.getStartLocation(), exp);
      }
      if (tm instanceof TemplateBooleanModel) {
          try {
             return ((TemplateBooleanModel) tm).getAsBoolean();
          } catch (TemplateModelException tme) {
          }
      }
      if (tm instanceof TemplateScalarModel) {
          try {
              return StringUtil.getYesNo(((TemplateScalarModel) tm).getAsString());
          } catch (Exception e) {
              throw new ParseException(e.getMessage()
                                       + "\nExpecting yes/no, found: " + exp.getCanonicalForm()
                                       + exp.getStartLocation(), exp);
          }
      }
      throw new ParseException("Expecting boolean (yes/no) parameter" + exp.getStartLocation(), exp);
  }
}

PARSER_END(FMParser)

/**
 * The lexer portion defines 5 lexical states:
 * DEFAULT, FM_EXPRESSION, IN_PAREN, NO_PARSE, and EXPRESSION_COMMENT.
 * The DEFAULT state is when you are parsing
 * text but are not inside a FreeMarker expression.
 * FM_EXPRESSION is the state you are in
 * when the parser wants a FreeMarker expression.
 * IN_PAREN is almost identical really. The difference
 * is that you are in this state when you are within
 * FreeMarker expression and also within (...).
 * This is a necessary subtlety because the
 * ">" and ">=" symbols can only be used
 * within parentheses because otherwise, it would
 * be ambiguous with the end of a directive.
 * So, for example, you enter the FM_EXPRESSION state
 * right after a ${ and leave it after the matching }.
 * Or, you enter the FM_EXPRESSION state right after
 * an "<if" and then, when you hit the matching ">"
 * that ends the if directive,
 * you go back to DEFAULT lexical state.
 * If, within the FM_EXPRESSION state, you enter a
 * parenthetical expression, you enter the IN_PAREN
 * state.
 * Note that whitespace is ignored in the
 * FM_EXPRESSION and IN_PAREN states
 * but is passed through to the parser as PCDATA in the DEFAULT state.
 * NO_PARSE and EXPRESSION_COMMENT are extremely simple
 * lexical states. NO_PARSE is when you are in a comment
 * block and EXPRESSION_COMMENT is when you are in a comment
 * that is within an FTL expression.
 */

TOKEN_MGR_DECLS :
{

/**
  The noparseTag is set when we enter
  a block of text that the parser more or less ignores.
  These are <noparse> and <comment>. This variable
  tells us what the closing tag should be, and when
  we hit that, we resume parsing. Note that with this
  scheme, <comment> and <noparse> tags cannot nest
  recursively, but it is not clear how important that is.
*/
    String noparseTag;

/**
    Keeps track of how deeply nested
    we have the hash literals.
    This is necessary since we need to be
    able to distinguish the } used to close
    a hash literal and the one used to
    close a ${
 */
 private int hashLiteralNesting;
 private int parenthesisNesting;
 private int bracketNesting;
 private boolean inFTLHeader;
 boolean strictEscapeSyntax, 
         onlyTextOutput, 
         altDirectiveSyntax,
	 autodetectTagSyntax,
         directiveSyntaxEstablished;
 String templateName;

 
 // This method checks if we are in a strict mode where all
 // FreeMarker directives must start with <#

 private void strictSyntaxCheck(Token tok, int newLexState) {
     if (onlyTextOutput) {
        tok.kind = PRINTABLE_CHARS;
        return;
     }
     char firstChar = tok.image.charAt(0);
     if (autodetectTagSyntax && !directiveSyntaxEstablished) {
         altDirectiveSyntax = (firstChar == '[');
     }
     if ((firstChar == '[' && !altDirectiveSyntax) || (firstChar == '<' && altDirectiveSyntax)) {
        tok.kind = PRINTABLE_CHARS;
        return;
     }
     if (!strictEscapeSyntax) {
        SwitchTo(newLexState);
        return;
     }
     if (!altDirectiveSyntax) {
         if (!tok.image.startsWith("<#") && !tok.image.startsWith("</#")) {
            tok.kind = PRINTABLE_CHARS;
            return;
         }
     }
     directiveSyntaxEstablished = true;
     SwitchTo(newLexState);
 }
 
 private void unifiedCall(Token tok) {
     char firstChar = tok.image.charAt(0);
     if (autodetectTagSyntax && !directiveSyntaxEstablished) {
         altDirectiveSyntax = (firstChar == '[');
     }
     if (altDirectiveSyntax && firstChar == '<') {
        tok.kind = PRINTABLE_CHARS;
        return;
     } 
     if (!altDirectiveSyntax && firstChar == '[') {
        tok.kind = PRINTABLE_CHARS;
        return;
     }
     directiveSyntaxEstablished = true;
     SwitchTo(NO_SPACE_EXPRESSION);
 }
 
 private void unifiedCallEnd(Token tok) {
     char firstChar = tok.image.charAt(0);
     if (altDirectiveSyntax && firstChar == '<') {
        tok.kind = PRINTABLE_CHARS;
        return;
     } 
     if (!altDirectiveSyntax && firstChar == '[') {
        tok.kind = PRINTABLE_CHARS;
        return;
     }
 }
 
 private void closeBracket(Token tok) {
     if (bracketNesting >0) {
        --bracketNesting;
     } else {
        tok.kind=DIRECTIVE_END;
        if (inFTLHeader) {
           eatNewline(); 
           inFTLHeader = false; 
        }     
        SwitchTo(DEFAULT);     
     }
 }
 

 private void eatNewline() {
     int charsRead = 0;
     try {
        while (true) {
           char c = input_stream.readChar();
           ++charsRead;
           if (!Character.isWhitespace(c)) {
              input_stream.backup(charsRead);
	      return;
           } else if (c=='\r') {
              char next = input_stream.readChar();
              ++charsRead;
              if (next != '\n') {
                 input_stream.backup(1);
              }
              return;
           } else if (c=='\n') {
              return;
           }
        }
     } catch (IOException ioe) {
        input_stream.backup(charsRead);
     }
 }
 
 private void ftlHeader(Token matchedToken) {
       if (!directiveSyntaxEstablished) {
           altDirectiveSyntax = matchedToken.image.charAt(0) == '[';
	   directiveSyntaxEstablished = true;
	   autodetectTagSyntax = false;
       }
       String img = matchedToken.image;
       char firstChar = img.charAt(0);
       char lastChar = img.charAt(img.length() -1);
       if ((firstChar == '[' && !altDirectiveSyntax) || (firstChar == '<' && altDirectiveSyntax)) {
          matchedToken.kind = PRINTABLE_CHARS;
       } 
       if (matchedToken.kind != PRINTABLE_CHARS) {
          if (lastChar != '>' && lastChar != ']') {
              SwitchTo(FM_EXPRESSION);
              inFTLHeader = true;
          } else {
            eatNewline();
          }
       }
 }
}

TOKEN:
{
    <#BLANK : [" ", "\t", "\n", "\r"]>
    |
    <#START_TAG : "<" | "<#" | "[#">
    |
    <#END_TAG : "</" | "</#" | "[/#">
    |
    <#CLOSE_TAG1 : (<BLANK>)* (">" | "]")>
    |
    <#CLOSE_TAG2 : (<BLANK>)* ("/")? (">" | "]")>
    |
    <ATTEMPT : <START_TAG> "attempt" <CLOSE_TAG1>> {strictSyntaxCheck(matchedToken, DEFAULT);}
    |
    <RECOVER : <START_TAG> "recover" <CLOSE_TAG1>> {strictSyntaxCheck(matchedToken, DEFAULT);} 
    |
    <IF : <START_TAG> "if" <BLANK>> {strictSyntaxCheck(matchedToken, FM_EXPRESSION);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -