next up previous
Next: 2 Envionmentクラス Up: 1 インタプリタの構造 Scheme.java Previous: 1.2 evalの手続き

1.3 Scheme.javaの全体


package jscheme;
import java.io.*;

/** This class represents a Scheme interpreter.
 * See http://www.norvig.com/JSCHEME.html for
 * more documentation.
 * This is version 1.4. 
 * @author Peter Norvig,
 * peter@norvig.com http://www.norvig.com 
 * Copyright 1998 Peter Norvig,
 * see http://www.norvig.com/license.html **/

public class Scheme extends SchemeUtils {

  InputPort input =
      new InputPort(System.in);
  PrintWriter output =
      new PrintWriter(System.out, true);
  Environment globalEnvironment =
      new Environment();

  /** Create a Scheme interpreter and
   *  load an array of files into it.
   * Also load SchemePrimitives.CODE. **/

  public Scheme(String[] files) { 
    Primitive.installPrimitives(globalEnvironment); 
    try {
      load(new
           InputPort(new 
              StringReader(SchemePrimitives.CODE)));
      for (int i = 0;
           i < (files == null ? 0 : files.length);
           i++) {
        load(files[i]);
      } 
    } catch (RuntimeException e) { ; }
  }

  //////////////// Main Loop

  /** Create a new Scheme interpreter,
   * passing in the command line args
   * as files to load, and then enter
   * a read eval write loop. **/

  public static void main(String[] files) {
    new Scheme(files).readEvalWriteLoop();
  }

  /** Prompt, read, eval, and write the result. 
   * Also sets up a catch for any
   * RuntimeExceptions encountered. **/

  public void readEvalWriteLoop() {
    Object x;
    for(;;) {
      try {
        output.print("> "); output.flush();
        if (input.isEOF(x = input.read())) return;
        write(eval(x), output, true); 
        output.println(); output.flush();
      } catch (RuntimeException e) { ; }
    }
  }

  /** Eval all the expressions in a file.
   * Calls load(InputPort). **/

  public Object load(Object fileName) {
    String name = stringify(fileName, false);
    try {
      return load(new
                 InputPort(new
                    FileInputStream(name))); }
    catch (IOException e)
    { return error("can't load " + name); }
  }

  /** Eval all the expressions
   * coming from an InputPort. **/

  public Object load(InputPort in) {
    Object x = null;
    for(;;) {
      if (in.isEOF(x = in.read())) return TRUE;
      eval(x); 
    }
  }
      
  //////////////// Evaluation

  /** Evaluate an object, x, in an environment. **/
  public Object eval(Object x, Environment env) { 
    // The purpose of the while loop is to
    // allow tail recursion.
    // The idea is that in a tail recursive
    // position, we do "x = ..."
    // and loop, rather than doing "return eval(...)".

    while (true) {
      if (x instanceof String) {         // VARIABLE
        return env.lookup((String)x);
      } else if (!(x instanceof Pair)) { // CONSTANT
        return x;
      } else {                           
        Object fn = first(x);
        Object args = rest(x);
        if (fn == "quote") {             // QUOTE
          return first(args);
        } else if (fn == "begin") {      // BEGIN
          for (; rest(args) != null;
               args = rest(args)) {
            eval(first(args), env);
          }
          x = first(args);
        } else if (fn == "define") {     // DEFINE
          if (first(args) instanceof Pair)
            return env.define(first(first(args)),
             eval(cons("lambda",
                   cons(rest(first(args)),
                        rest(args))),
                  env));
          else return env.define(first(args),
                         eval(second(args), env));
        } else if (fn == "set!") {       // SET!
          return env.set(first(args),
                         eval(second(args), env));
        } else if (fn == "if") {         // IF
          x = (truth(eval(first(args), env))) ?
          second(args) : third(args);
        } else if (fn == "cond") {       // COND
          x = reduceCond(args, env);
        } else if (fn == "lambda") {     // LAMBDA
          return new Closure(first(args),
                             rest(args), env);
        } else if (fn == "macro") {      // MACRO
          return new Macro(first(args),
                           rest(args), env);
        } else {              // PROCEDURE CALL:
          fn = eval(fn, env);
          if (fn instanceof Macro) { // (MACRO CALL)
            x = ((Macro)fn).expand(this,
                                   (Pair)x, args);
          } else if (fn instanceof Closure) {
            // (CLOSURE CALL)
            Closure f = (Closure)fn;
            x = f.body;
            env = new Environment(f.parms,
                              evalList(args, env),
                              f.env);
          } else {          // (OTHER PROCEDURE CALL)
            return Procedure.proc(fn).apply(this,
                              evalList(args, env));
          }
        }
      }
    }
  }

  /** Eval in the global environment. **/
  public Object eval(Object x) {
       return eval(x, this.globalEnvironment);
  }

  /** Evaluate each of a list of expressions. **/
  Pair evalList(Object list, Environment env) {
    if (list == null) 
      return null;
    else if (!(list instanceof Pair)) {
      error("Illegal arg list: " + list);
      return null;
    } else 
      return cons(eval(first(list), env),
                  evalList(rest(list), env));
  }

  /** Reduce a cond expression to some code
   * which, when evaluated,
   * gives the value of the cond expression.
   *  We do it that way to
   * maintain tail recursion. **/

  Object reduceCond(Object clauses,
                    Environment env) {
    Object result = null;
    for (;;) {
      if (clauses == null) return FALSE;
      Object clause = first(clauses);
      clauses = rest(clauses);
      if (first(clause) == "else" 
          || truth(result = eval(first(clause), env)))
        if (rest(clause) == null)
          return list("quote", result);
        else if (second(clause) == "=>")
          return list(third(clause),
                      list("quote", result));
        else return cons("begin", rest(clause));
    }
  }
}


generated through LaTeX2HTML. M.Inaba 平成18年5月6日