📄 parser.java
字号:
/* * Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Sun designates this * particular file as subject to the "Classpath" exception as provided * by Sun in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */package com.sun.tools.javac.parser;import java.util.*;import com.sun.tools.javac.tree.*;import com.sun.tools.javac.code.*;import com.sun.tools.javac.util.*;import com.sun.tools.javac.util.List;import static com.sun.tools.javac.util.ListBuffer.lb;import com.sun.tools.javac.tree.JCTree.*;import static com.sun.tools.javac.parser.Token.*;/** The parser maps a token sequence into an abstract syntax * tree. It operates by recursive descent, with code derived * systematically from an LL(1) grammar. For efficiency reasons, an * operator precedence scheme is used for parsing binary operation * expressions. * * <p><b>This is NOT part of any API supported by Sun Microsystems. If * you write code that depends on this, you do so at your own risk. * This code and its internal interfaces are subject to change or * deletion without notice.</b> */public class Parser { /** A factory for creating parsers. */ public static class Factory { /** The context key for the parser factory. */ protected static final Context.Key<Parser.Factory> parserFactoryKey = new Context.Key<Parser.Factory>(); /** Get the Factory instance for this context. */ public static Factory instance(Context context) { Factory instance = context.get(parserFactoryKey); if (instance == null) instance = new Factory(context); return instance; } final TreeMaker F; final Log log; final Keywords keywords; final Source source; final Name.Table names; final Options options; /** Create a new parser factory. */ protected Factory(Context context) { context.put(parserFactoryKey, this); this.F = TreeMaker.instance(context); this.log = Log.instance(context); this.names = Name.Table.instance(context); this.keywords = Keywords.instance(context); this.source = Source.instance(context); this.options = Options.instance(context); } /** * Create a new Parser. * @param S Lexer for getting tokens while parsing * @param keepDocComments true if javadoc comments should be kept * @param genEndPos true if end positions should be generated */ public Parser newParser(Lexer S, boolean keepDocComments, boolean genEndPos) { if (!genEndPos) return new Parser(this, S, keepDocComments); else return new EndPosParser(this, S, keepDocComments); } } /** The number of precedence levels of infix operators. */ private static final int infixPrecedenceLevels = 10; /** The scanner used for lexical analysis. */ private Lexer S; /** The factory to be used for abstract syntax tree construction. */ protected TreeMaker F; /** The log to be used for error diagnostics. */ private Log log; /** The keyword table. */ private Keywords keywords; /** The Source language setting. */ private Source source; /** The name table. */ private Name.Table names; /** Construct a parser from a given scanner, tree factory and log. */ protected Parser(Factory fac, Lexer S, boolean keepDocComments) { this.S = S; S.nextToken(); // prime the pump this.F = fac.F; this.log = fac.log; this.names = fac.names; this.keywords = fac.keywords; this.source = fac.source; Options options = fac.options; this.allowGenerics = source.allowGenerics(); this.allowVarargs = source.allowVarargs(); this.allowAsserts = source.allowAsserts(); this.allowEnums = source.allowEnums(); this.allowForeach = source.allowForeach(); this.allowStaticImport = source.allowStaticImport(); this.allowAnnotations = source.allowAnnotations(); this.keepDocComments = keepDocComments; if (keepDocComments) docComments = new HashMap<JCTree,String>(); this.errorTree = F.Erroneous(); } /** Switch: Should generics be recognized? */ boolean allowGenerics; /** Switch: Should varargs be recognized? */ boolean allowVarargs; /** Switch: should we recognize assert statements, or just give a warning? */ boolean allowAsserts; /** Switch: should we recognize enums, or just give a warning? */ boolean allowEnums; /** Switch: should we recognize foreach? */ boolean allowForeach; /** Switch: should we recognize foreach? */ boolean allowStaticImport; /** Switch: should we recognize annotations? */ boolean allowAnnotations; /** Switch: should we keep docComments? */ boolean keepDocComments; /** When terms are parsed, the mode determines which is expected: * mode = EXPR : an expression * mode = TYPE : a type * mode = NOPARAMS : no parameters allowed for type * mode = TYPEARG : type argument */ static final int EXPR = 1; static final int TYPE = 2; static final int NOPARAMS = 4; static final int TYPEARG = 8; /** The current mode. */ private int mode = 0; /** The mode of the term that was parsed last. */ private int lastmode = 0;/* ---------- error recovery -------------- */ private JCErroneous errorTree; /** Skip forward until a suitable stop token is found. */ private void skip(boolean stopAtImport, boolean stopAtMemberDecl, boolean stopAtIdentifier, boolean stopAtStatement) { while (true) { switch (S.token()) { case SEMI: S.nextToken(); return; case PUBLIC: case FINAL: case ABSTRACT: case MONKEYS_AT: case EOF: case CLASS: case INTERFACE: case ENUM: return; case IMPORT: if (stopAtImport) return; break; case LBRACE: case RBRACE: case PRIVATE: case PROTECTED: case STATIC: case TRANSIENT: case NATIVE: case VOLATILE: case SYNCHRONIZED: case STRICTFP: case LT: case BYTE: case SHORT: case CHAR: case INT: case LONG: case FLOAT: case DOUBLE: case BOOLEAN: case VOID: if (stopAtMemberDecl) return; break; case IDENTIFIER: if (stopAtIdentifier) return; break; case CASE: case DEFAULT: case IF: case FOR: case WHILE: case DO: case TRY: case SWITCH: case RETURN: case THROW: case BREAK: case CONTINUE: case ELSE: case FINALLY: case CATCH: if (stopAtStatement) return; break; } S.nextToken(); } } private JCErroneous syntaxError(int pos, String key, Object... arg) { return syntaxError(pos, null, key, arg); } private JCErroneous syntaxError(int pos, List<JCTree> errs, String key, Object... arg) { setErrorEndPos(pos); reportSyntaxError(pos, key, arg); return toP(F.at(pos).Erroneous(errs)); } private int errorPos = Position.NOPOS; /** * Report a syntax error at given position using the given * argument unless one was already reported at the same position. */ private void reportSyntaxError(int pos, String key, Object... arg) { if (pos > S.errPos() || pos == Position.NOPOS) { if (S.token() == EOF) log.error(pos, "premature.eof"); else log.error(pos, key, arg); } S.errPos(pos); if (S.pos() == errorPos) S.nextToken(); // guarantee progress errorPos = S.pos(); } /** Generate a syntax error at current position unless one was already * reported at the same position. */ private JCErroneous syntaxError(String key) { return syntaxError(S.pos(), key); } /** Generate a syntax error at current position unless one was * already reported at the same position. */ private JCErroneous syntaxError(String key, String arg) { return syntaxError(S.pos(), key, arg); } /** If next input token matches given token, skip it, otherwise report * an error. */ public void accept(Token token) { if (S.token() == token) { S.nextToken(); } else { setErrorEndPos(S.pos()); reportSyntaxError(S.prevEndPos(), "expected", keywords.token2string(token)); } } /** Report an illegal start of expression/type error at given position. */ JCExpression illegal(int pos) { setErrorEndPos(S.pos()); if ((mode & EXPR) != 0) return syntaxError(pos, "illegal.start.of.expr"); else return syntaxError(pos, "illegal.start.of.type"); } /** Report an illegal start of expression/type error at current position. */ JCExpression illegal() { return illegal(S.pos()); } /** Diagnose a modifier flag from the set, if any. */ void checkNoMods(long mods) { if (mods != 0) { long lowestMod = mods & -mods; log.error(S.pos(), "mod.not.allowed.here", Flags.toString(lowestMod).trim()); } }/* ---------- doc comments --------- */ /** A hashtable to store all documentation comments * indexed by the tree nodes they refer to. * defined only if option flag keepDocComment is set. */ Map<JCTree, String> docComments; /** Make an entry into docComments hashtable, * provided flag keepDocComments is set and given doc comment is non-null. * @param tree The tree to be used as index in the hashtable * @param dc The doc comment to associate with the tree, or null.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -