?? parser.java
字號:
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * The contents of this file are subject to the Netscape Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1997-1999 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): * Mike Ang * Igor Bukanov * Ethan Hugg * Terry Lucas * Mike McCabe * Milen Nankov * * Alternatively, the contents of this file may be used under the * terms of the GNU Public License (the "GPL"), in which case the * provisions of the GPL are applicable instead of those above. * If you wish to allow use of your version of this file only * under the terms of the GPL and not to allow others to use your * version of this file under the NPL, indicate your decision by * deleting the provisions above and replace them with the notice * and other provisions required by the GPL. If you do not delete * the provisions above, a recipient may use your version of this * file under either the NPL or the GPL. */package org.mozilla.javascript;import java.io.Reader;import java.io.IOException;import java.util.Hashtable;/** * This class implements the JavaScript parser. * * It is based on the C source files jsparse.c and jsparse.h * in the jsref package. * * @see TokenStream * * @author Mike McCabe * @author Brendan Eich */public class Parser{ // TokenInformation flags : currentFlaggedToken stores them together // with token type final static int CLEAR_TI_MASK = 0xFFFF, // mask to clear token information bits TI_AFTER_EOL = 1 << 16, // first token of the source line TI_CHECK_LABEL = 1 << 17; // indicates to check for label CompilerEnvirons compilerEnv; private ErrorReporter errorReporter; private String sourceURI; boolean calledByCompileFunction; private TokenStream ts; private int currentFlaggedToken; private int syntaxErrorCount; private IRFactory nf; private int nestingOfFunction; private String encodedSource;// The following are per function variables and should be saved/restored// during function parsing.// XXX Move to separated class? ScriptOrFnNode currentScriptOrFn; private int nestingOfWith; private Hashtable labelSet; // map of label names into nodes private ObjArray loopSet; private ObjArray loopAndSwitchSet;// end of per function variables // Exception to unwind private static class ParserException extends RuntimeException { static final long serialVersionUID = 5882582646773765630L; } public Parser(CompilerEnvirons compilerEnv, ErrorReporter errorReporter) { this.compilerEnv = compilerEnv; this.errorReporter = errorReporter; } protected Decompiler createDecompiler(CompilerEnvirons compilerEnv) { return new Decompiler(); } void addWarning(String messageId, String messageArg) { String message = ScriptRuntime.getMessage1(messageId, messageArg); errorReporter.warning(message, sourceURI, ts.getLineno(), ts.getLine(), ts.getOffset()); } void addError(String messageId) { ++syntaxErrorCount; String message = ScriptRuntime.getMessage0(messageId); errorReporter.error(message, sourceURI, ts.getLineno(), ts.getLine(), ts.getOffset()); } RuntimeException reportError(String messageId) { addError(messageId); // Throw a ParserException exception to unwind the recursive descent // parse. throw new ParserException(); } private int peekToken() throws IOException { int tt = currentFlaggedToken; if (tt == Token.EOF) { tt = ts.getToken(); if (tt == Token.EOL) { do { tt = ts.getToken(); } while (tt == Token.EOL); tt |= TI_AFTER_EOL; } currentFlaggedToken = tt; } return tt & CLEAR_TI_MASK; } private int peekFlaggedToken() throws IOException { peekToken(); return currentFlaggedToken; } private void consumeToken() { currentFlaggedToken = Token.EOF; } private int nextToken() throws IOException { int tt = peekToken(); consumeToken(); return tt; } private int nextFlaggedToken() throws IOException { peekToken(); int ttFlagged = currentFlaggedToken; consumeToken(); return ttFlagged; } private boolean matchToken(int toMatch) throws IOException { int tt = peekToken(); if (tt != toMatch) { return false; } consumeToken(); return true; } private int peekTokenOrEOL() throws IOException { int tt = peekToken(); // Check for last peeked token flags if ((currentFlaggedToken & TI_AFTER_EOL) != 0) { tt = Token.EOL; } return tt; } private void setCheckForLabel() { if ((currentFlaggedToken & CLEAR_TI_MASK) != Token.NAME) throw Kit.codeBug(); currentFlaggedToken |= TI_CHECK_LABEL; } private void mustMatchToken(int toMatch, String messageId) throws IOException, ParserException { if (!matchToken(toMatch)) { reportError(messageId); } } private void mustHaveXML() { if (!compilerEnv.isXmlAvailable()) { reportError("msg.XML.not.available"); } } public String getEncodedSource() { return encodedSource; } public boolean eof() { return ts.eof(); } boolean insideFunction() { return nestingOfFunction != 0; } private Node enterLoop(Node loopLabel) { Node loop = nf.createLoopNode(loopLabel, ts.getLineno()); if (loopSet == null) { loopSet = new ObjArray(); if (loopAndSwitchSet == null) { loopAndSwitchSet = new ObjArray(); } } loopSet.push(loop); loopAndSwitchSet.push(loop); return loop; } private void exitLoop() { loopSet.pop(); loopAndSwitchSet.pop(); } private Node enterSwitch(Node switchSelector, int lineno, Node switchLabel) { Node switchNode = nf.createSwitch(switchSelector, lineno); if (loopAndSwitchSet == null) { loopAndSwitchSet = new ObjArray(); } loopAndSwitchSet.push(switchNode); return switchNode; } private void exitSwitch() { loopAndSwitchSet.pop(); } /* * Build a parse tree from the given sourceString. * * @return an Object representing the parsed * program. If the parse fails, null will be returned. (The * parse failure will result in a call to the ErrorReporter from * CompilerEnvirons.) */ public ScriptOrFnNode parse(String sourceString, String sourceURI, int lineno) { this.sourceURI = sourceURI; this.ts = new TokenStream(this, null, sourceString, lineno); try { return parse(); } catch (IOException ex) { // Should never happen throw new IllegalStateException(); } } /* * Build a parse tree from the given sourceString. * * @return an Object representing the parsed * program. If the parse fails, null will be returned. (The * parse failure will result in a call to the ErrorReporter from * CompilerEnvirons.) */ public ScriptOrFnNode parse(Reader sourceReader, String sourceURI, int lineno) throws IOException { this.sourceURI = sourceURI; this.ts = new TokenStream(this, sourceReader, null, lineno); return parse(); } private ScriptOrFnNode parse() throws IOException { this.decompiler = createDecompiler(compilerEnv); this.nf = new IRFactory(this); currentScriptOrFn = nf.createScript(); int sourceStartOffset = decompiler.getCurrentOffset(); this.encodedSource = null; decompiler.addToken(Token.SCRIPT); this.currentFlaggedToken = Token.EOF; this.syntaxErrorCount = 0; int baseLineno = ts.getLineno(); // line number where source starts /* so we have something to add nodes to until * we've collected all the source */ Node pn = nf.createLeaf(Token.BLOCK); try { for (;;) { int tt = peekToken(); if (tt <= Token.EOF) { break; } Node n; if (tt == Token.FUNCTION) { consumeToken(); try { n = function(calledByCompileFunction ? FunctionNode.FUNCTION_EXPRESSION : FunctionNode.FUNCTION_STATEMENT); } catch (ParserException e) { break; } } else { n = statement(); } nf.addChildToBack(pn, n); } } catch (StackOverflowError ex) { String msg = ScriptRuntime.getMessage0( "mag.too.deep.parser.recursion"); throw Context.reportRuntimeError(msg, sourceURI, ts.getLineno(), null, 0); } if (this.syntaxErrorCount != 0) { String msg = String.valueOf(this.syntaxErrorCount); msg = ScriptRuntime.getMessage1("msg.got.syntax.errors", msg); throw errorReporter.runtimeError(msg, sourceURI, baseLineno, null, 0); } currentScriptOrFn.setSourceName(sourceURI); currentScriptOrFn.setBaseLineno(baseLineno); currentScriptOrFn.setEndLineno(ts.getLineno()); int sourceEndOffset = decompiler.getCurrentOffset(); currentScriptOrFn.setEncodedSourceBounds(sourceStartOffset, sourceEndOffset); nf.initScript(currentScriptOrFn, pn); if (compilerEnv.isGeneratingSource()) { encodedSource = decompiler.getEncodedSource(); } this.decompiler = null; // It helps GC return currentScriptOrFn; } /* * The C version of this function takes an argument list, * which doesn't seem to be needed for tree generation... * it'd only be useful for checking argument hiding, which * I'm not doing anyway... */ private Node parseFunctionBody() throws IOException { ++nestingOfFunction; Node pn = nf.createBlock(ts.getLineno()); try { bodyLoop: for (;;) { Node n; int tt = peekToken(); switch (tt) { case Token.ERROR: case Token.EOF: case Token.RC:
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -