next up previous
Next: 9 SchemeUtilsクラス Up: ソフトウェア特論 講義資料 JavaによるScheme言語処理系: Jscheme Previous: 7 Continuationクラス

8 InputPortクラス

InputPortはSchemeUtilsのサブクラスとして定義されています.

package jscheme;
import java.io.*;

/** InputPort is to Scheme as InputStream
 * is to Java. 
 * @author Peter Norvig,
 * peter@norvig.com http://www.norvig.com  
 * Copyright 1998 Peter Norvig,
 * see http://www.norvig.com/license.html **/

public class InputPort extends SchemeUtils {

  static  String EOF = "#!EOF";
  boolean isPushedToken = false;
  boolean isPushedChar = false;
  Object  pushedToken = null;
  int     pushedChar = -1;
  Reader  in;
  StringBuffer buff = new StringBuffer();

  /** Construct an InputPort from an InputStream. **/
  public InputPort(InputStream in) {
    this.in = new InputStreamReader(in);
  }

  /** Construct an InputPort from a Reader. **/
  public InputPort(Reader in) { this.in = in;}

  /** Read and return a Scheme character or EOF. **/
  public Object readChar() {
    try {
      if (isPushedChar) {
        isPushedChar = false;
        if (pushedChar == -1) return EOF;
        else return chr((char)pushedChar);
      } else {
        int ch = in.read();
        if (ch == -1) return EOF;
        else return chr((char)ch);
      }
    } catch (IOException e) {
      warn("On input, exception: " + e);
      return EOF;
    }
  }

  /** Peek at and return the next Scheme
   * character (or EOF).
   * However, don't consume the character. **/
  public Object peekChar() {
    int p = peekCh();
    if (p == -1) return EOF;
    else return chr((char)p);
  }

  /** Push a character back
      to be re-used later. **/
  int pushChar(int ch) {
    isPushedChar = true;
    return pushedChar = ch;
  }

  /** Pop off the previously
      pushed character. **/
  int popChar() {
    isPushedChar = false;
    return pushedChar;
  }

  /** Peek at and return the next Scheme
   *   character as an int, -1 for EOF.
   * However, don't consume the character. **/
  public int peekCh() {
    try {
       return isPushedChar ?
              pushedChar : pushChar(in.read());
    }
    catch (IOException e) {
      warn("On input, exception: " + e);
      return -1;
    }
  }

  /** Read and return a Scheme expression,
       or EOF. **/
  public Object read() {
    try {
      Object token = nextToken(); 
      if (token == "(")
        return readTail(false);
      else if (token == ")")
        { warn("Extra ) ignored."); return read(); }
      else if (token == ".")
        { warn("Extra . ignored."); return read(); }
      else if (token == "'")
        return list("quote", read());
      else if (token == "`")
        return list("quasiquote", read());
      else if (token == ",")
        return list("unquote", read());
      else if (token == ",@")
        return list("unquote-splicing", read());
      else 
        return token;
    } catch (IOException e) {
      warn("On input, exception: " + e);
      return EOF;
    }
  }

  /** Close the port.  Return TRUE if ok. **/
  public Object close() {
    try { this.in.close(); return TRUE; }
    catch (IOException e) {
      return error("IOException: " + e); }
  }

  /** Is the argument the EOF object? **/
  public static boolean isEOF(Object x) {
     return x == EOF; }

  Object readTail(boolean dotOK)
        throws IOException {
    Object token = nextToken(); 
    if (token == EOF)
      return error("EOF during read.");
    else if (token == ")")
      return null;
    else if (token == ".") {
      Object result = read();
      token = nextToken(); 
      if (token != ")")
          warn("Where's the ')'? Got " +
                         token + " after .");
      return result;
    } else {
      isPushedToken = true;
      pushedToken = token;
      return cons(read(), readTail(true));
    }
  }

  Object nextToken() throws IOException {
    int ch;

    // See if we should re-use a pushed char or token
    if (isPushedToken) {
      isPushedToken = false;
      return pushedToken;
    } else if (isPushedChar) {
      ch = popChar();
    } else {
      ch = in.read();
    }

    // Skip whitespace
    while (Character.isWhitespace((char)ch))
        ch = in.read();

    // See what kind of non-white character we got
    switch(ch) {
    case -1: return EOF;
    case '(' : return "(";
    case ')':  return ")";
    case '\'': return "'";
    case '`':  return "`";
    case ',': 
      ch = in.read();
      if (ch == '@') return ",@";
      else { pushChar(ch); return ","; }
    case ';': 
      // Comment: skip to end of line and
      //   then read next token
      while(ch != -1 && ch != '\n' && ch != '\r')
         ch = in.read();
      return nextToken();
    case '"':
      // Strings are represented as char[]
      buff.setLength(0);
      while ((ch = in.read()) != '"' && ch != -1) {
        buff.append((char) ((ch == '\\') ?
                in.read() : ch));
      }
      if (ch == -1) warn("EOF inside of a string.");
      return buff.toString().toCharArray(); 
    case '#':
      switch (ch = in.read()) {
      case 't': case 'T': return TRUE;
      case 'f': case 'F': return FALSE;
      case '(':
        pushChar('(');
        return listToVector(read());
      case '\\': 
        ch = in.read();
        if (ch == 's' || ch == 'S' ||
                 ch == 'n' || ch == 'N') {
          pushChar(ch);
          Object token = nextToken();
          if (token == "space")
            return chr(' ');
          else if (token == "newline")
            return chr('\n');
          else {
            isPushedToken = true;
            pushedToken = token;
            return chr((char)ch);
          }
        } else {
          return chr((char)ch);
        }
      case 'e':
      case 'i':
      case 'd': return nextToken();
      case 'b': case 'o': case 'x':
        warn("#" + ((char)ch) +
              " not implemented, ignored."); 
        return nextToken();
      default: 
        warn("#" + ((char)ch) +
              " not recognized, ignored."); 
        return nextToken();
      }
    default: 
      buff.setLength(0);
      int c = ch;
      do { 
        buff.append((char)ch);
        ch = in.read();
      } while (!Character.isWhitespace((char)ch) &&
               ch != -1 &&
               ch != '(' && ch != ')' &&
               ch != '\'' && ch != ';' &&
               ch != '"' && ch != ',' &&
               ch != '`');
      pushChar(ch);
      // Try potential numbers,
      // but catch any format errors.
      if (c == '.' || c == '+' || c == '-' ||
                  (c >= '0' && c <= '9')) {
        try { return new Double(buff.toString()); }
        catch (NumberFormatException e) { ; }
      }
      return buff.toString().toLowerCase().intern();
    }
  }
}


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