dawnparser.java
来自「java写的多功能文件编辑器」· Java 代码 · 共 1,051 行 · 第 1/2 页
JAVA
1,051 行
/* * 11:58:05 07/08/00 * * DawnParser.java - Dawn is a RPN based scripting language * Copyright (C) 2000 Romain Guy * romain.guy@jext.org * www.jext.org * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program 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 for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */package org.jext.dawn;import java.io.*;import java.util.Stack;import java.util.Vector;import java.util.Hashtable;import java.util.Enumeration;/** * <code>DawnParser</code> is the Dawn scripting language interpreter. * Dawn is a language based on RPN. Dawn is also a very modulary language. * Basic usage of Dawn is:<br> * <pre> * DawnParser.init(); * // code is a String containing the script * DawnParser parser = new DawnParser(new StringReader(code)); * try * { * parser.exec(); * } catch (DawnRuntimeException dre) { * System.err.println(dre.getMessage()); * } * </pre><p> * Note the call to <code>init()</code>. You may not want to call this method, * but if you don't, then Dawn will provide NO FUNCTION AT ALL. Even basic ones, * like + - * drop sto rcl, won't work !! This is due to the fact Dawn can be * entirely customized.<br> * In fact, <code>init()</code> simply install basic packages (loop, test, * util, stack, math, err, io, string, naming). But you can load only one, or * many, of them and also install your own packages to replace default ones.<br> * You may also load extra packages with the: <code>installPackage()</code> method.<p> * Read the documentation for further informations. * @author Romain Guy * @version 1.1.1 */public class DawnParser{ /** Gives Dawn interpreter version numbering */ public static final String DAWN_VERSION = "Dawn v1.1.1 final [$12:12:55 07/08/00]"; /** Identifier for a stack element containing a numeric value */ public static final int DAWN_NUMERIC_TYPE = 0; /** Identifier for a stack element containing a string */ public static final int DAWN_STRING_TYPE = 1; /** Identifier for a stack element defining a literal (variable name) */ public static final int DAWN_LITERAL_TYPE = 2; /** Identifier for a stack element defining an array */ public static final int DAWN_ARRAY_TYPE = 3; // global functions loaded from packages private static Hashtable functions = new Hashtable(200); // global variables private static Hashtable variables = new Hashtable(); // installed packages private static Vector installedPackages = new Vector(); private static Vector installedRuntimePackages = new Vector(); // init flag private static boolean isInited = false; // it true, the parser stops private boolean stopped = false; // properties set private Hashtable properties = new Hashtable(); // stream tokenizer: this is Dawn parser engine private StreamTokenizer st; // the stack where datas are put private Stack stack; // functions created on runtime private Hashtable runtimeFunctions; // variables created on runtime private Hashtable runtimeVariables; // line number in the script public int lineno = 1; // standard streams public PrintStream out = System.out; public PrintStream err = System.err; public InputStream in = System.in ; /** * Initializes Dawn default packages. This is strongly recommended * to call this method before any use of the parser. */ public static void init() { System.out.println(DAWN_VERSION); installPackage("dawn.array"); installPackage("dawn.err"); installPackage("dawn.io"); installPackage("dawn.javaccess"); installPackage("dawn.loop"); installPackage("dawn.math"); installPackage("dawn.naming"); installPackage("dawn.stack"); installPackage("dawn.string"); installPackage("dawn.test"); installPackage("dawn.util"); System.out.println(); isInited = true; } /** * Returns true if the parser has already been initialized. * Dawn is considered initialized when a call to <code>init()</code> * has been made. */ public static boolean isInitialized() { return isInited; } /** * Installs a package from Dawn archive. * @param packageName The package to load */ public static void installPackage(String packageName) { installPackage(DawnParser.class, packageName, null); } /** * Installs a package specific to a given class. The class will give infos * to both load the package file and the package classes. * @param loader The <code>Class</code> which calls this, if the class is * not part of Dawn standard package * @param packageName The package to load */ public static void installPackage(Class loader, String packageName) { installPackage(loader, packageName, null); } /** * Installs a package specific to a given class. The class will give infos * to both load the package file and the package classes. * @param loader The <code>Class</code> which calls this, if the class is * not part of Dawn standard package * @param packageName The package to load * @param parser If this parameter is not set to null, the package is loaded * as runtime package */ public static void installPackage(Class loader, String packageName, DawnParser parser) { if (packageName == null || loader == null) return; // check first if the package is already installed // (case of packages dependencies) if (installedPackages.contains(packageName)) { System.out.println("Dawn:<installPackage>:package " + packageName + " is already installed"); return; } // get classes to be loaded String[] classes = getClasses(loader, packageName); if (classes == null) { System.out.println("Dawn:<installPackage:err>:couldn't install " + packageName); return; } Object obj = null; Class _class = null; String className = null; Function _function = null; CodeSnippet _codeFunction = null; // ClassLoader classLoader = loader.getClassLoader(); try { // load classes for (int i = 0; i < classes.length; i++) { className = classes[i]; _class = Class.forName(className); //, true, classLoader); if (_class == null) { // if class is null, we get rid of it System.out.println("Dawn:<installPackage:err>:couldn't find class " + className + " in package " + packageName); continue; } // we create an instance of the class to check it obj = _class.newInstance(); if (obj instanceof Function) { // if it is a function, then we add it to the list _function = (Function) obj; (parser == null ? functions : parser.getRuntimeFunctions()).put(_function.getName(), _function); } else if (obj instanceof CodeSnippet) { // it is a coded function, we build it _codeFunction = (CodeSnippet) obj; if (parser == null) createGlobalFunction(_codeFunction.getName(), _codeFunction.getCode()); else parser.createRuntimeFunction(_codeFunction.getName(), _codeFunction.getCode()); } } } catch(Exception e) { System.out.println("Dawn:<installPackage:err>:couldn't load class " + className + " from package " + packageName); System.out.println("Dawn:<installPackage:err>:package " + packageName + " wasn't loaded"); return; } System.out.println("Dawn:<installPackage>:\t" + packageName + (packageName.length() < 8 ? "\t\t" : "\t") + "successfully installed"); (parser == null ? installedPackages : installedRuntimePackages).addElement(packageName); } // reads a package file and get classes-to-be-loaded names. it also checks package // dependencies. if a dependency is found, requested package is loaded private static String[] getClasses(Class loader, String packageName) { Vector buf = new Vector(); InputStream _in = loader.getResourceAsStream(packageName); if (_in == null) return null; BufferedReader in = new BufferedReader(new InputStreamReader(_in)); String line; try { while ((line = in.readLine()) != null) { line = line.trim(); if (line.length() == 0) continue; if (line.charAt(0) == '#') continue; else if (line.startsWith("needs")) { int index = line.indexOf(' '); if (index == -1 || index + 1 == line.length()) { System.out.println("Dawn:<installPackage:err>:package " + packageName + " contains a bad \'needs\' statement"); continue; } installPackage(loader, line.substring(index + 1), null); } else buf.addElement(line); } in.close(); } catch (IOException ioe) { return null; } if (buf.size() > 0) { String[] classes = new String[buf.size()]; buf.copyInto(classes); buf = null; return classes; } else return null; } /** * Creates a new parser. * @param in A <code>Reader</code> which will deliver the script to the parser */ public DawnParser(Reader in) { st = createTokenizer(in); stack = new Stack(); runtimeFunctions = new Hashtable(); runtimeVariables = new Hashtable(); } /** * Sets the parser print stream. Default packages may * pass informations through this stream (println function * for instance). * @param out The new <code>PrintStream</code> */ public void setOut(PrintStream out) { this.out = out; } /** * Sets the parser error print stream. Default packages may * pass informations through this stream. * @param err The new <code>PrintStream</code> used for errors */ public void setErr(PrintStream err) { this.err = err; } /** * Sets the parser input stream. Default packages may * pass informations through this stream (inputLine...) * @param out The new <code>OutputStream</code> */ public void setIn(InputStream in) { this.in = in; } /** * Sets the <code>StreamTokenizer</code> used to execute a script. * It is HIGHLY recommended NOT TO CALL this without a very good * reason. * @param _st The new stream where to get the script from */ public void setStream(StreamTokenizer _st) { st = _st; } /** * Returns current <code>StreamTokenizer</code>. It is mostly used * by functions to parse the script further. 'if' statement from * test package is a good example (see also for and while from the * loop package). */ public StreamTokenizer getStream() { return st; } /** * Creates a new StreamTokenizer, setting its properties according to * the Dawn scripting language specifications. the stream is built * from a Reader which is most of the time a StringReader. * @param in The <code>Reader</code> which will deliver the script */ public StreamTokenizer createTokenizer(Reader in) { StreamTokenizer st = new StreamTokenizer(in); st.resetSyntax(); st.eolIsSignificant(true); st.whitespaceChars(0, ' '); st.wordChars(' ' + 1, 255); st.quoteChar('"'); st.quoteChar('\''); st.commentChar('#'); st.parseNumbers(); st.eolIsSignificant(true); return st; } /** * Returns an Hashtable containing all the current global functions. */ public static Hashtable getFunctions() { return functions; } /** * Returns the set of runtimes functions. This is needed by installPackage() * when the keyword 'needsGlobal' is used in a script. */ public Hashtable getRuntimeFunctions() { return runtimeFunctions; } /** * Returns the stack which containes all the current availables datas. */ public Stack getStack() { return stack; } /** * Checks if a given variable name is valid or not. * @parma function The <code>Function</code> which called this method * @param var The variable name to be tested */ public void checkVarName(Function function, String var) throws DawnRuntimeException { if (var.equals("needs") || var.equals("needsGlobal")) throw new DawnRuntimeException(function, this, "you cannot use reserved keyword" + "\'needs\' or \'needsGlobal\'"); boolean word = false; for (int i = 0; i < var.length(); i++) { if (Character.isDigit(var.charAt(i)) && !word) { throw new DawnRuntimeException(function, this, "bad variable/function name:" + var); } else word = true; } } /** * Checks if stack contains enough datas to feed a function. * @parma function The <code>Function</code> which called this method * @param nb The amount of arguments needed */ public void checkArgsNumber(Function function, int nb) throws DawnRuntimeException { if (stack.size() < nb) throw new DawnRuntimeException(function, this, "bad arguments number, " + nb + " are required"); } /** * Checks if the stack is empty. * @parma function The <code>Function</code> which called this method */ public void checkEmpty(Function function) throws DawnRuntimeException { if (stack.isEmpty()) throw new DawnRuntimeException(function, this, "empty stack"); } /** * Checks if a given level is bound in the limits of the stack. * @parma function The <code>Function</code> which called this method * @param level The level to be tested */ public void checkLevel(Function function, int level) throws DawnRuntimeException { if (level >= stack.size() || level < 0) throw new DawnRuntimeException(function, this, "stack level out of bounds:" + level); } /** * Sets a property in the parser. Properties are used by external functions * to store objects they may need later. * @param name An <code>Object</code> describing the property. It stands for the key * @param property The property value */ public void setProperty(Object name, Object property) { if (name == null || property == null) return; properties.put(name, property); } /** * Returns a property according a given key. * @param name The property key */ public Object getProperty(Object name) { if (name == null) return null; return properties.get(name); } /** * Unsets (remove) a given property. */ public void unsetProperty(Object name) { properties.remove(name); } /** * Stops the parser. */ public void stop() { stopped = true; } /** * Executes loaded script. */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?