主要コンポネント

檜山正幸
Thu Sep 28 2006

目次

1. コンポネント

  1. VSTLexerCmp : Pull型のレクサー
  2. VSTParserCmp : Push型のパーザー
  3. VSTProcessorCmp : テンプレート処理系
  4. VSTMainCmp : 全体をまとめる
/* VSTLexerCmp.java */
// VerySimpleTemplatesのレクサー・コンポネント
package sample;

import java.io.*;

/* レクサー(字句解析系)*/
public class VSTLexerCmp implements VSTLexerPI {
  /* -- componet ports */
  /* @Provide */
  public final VSTLexerPI lexer;
  /* @Require */
  public void setInput(Reader reader) {
    input =  new PushbackReader(reader);
  }
  /* @Require */
  public void setInput(InputStream stream) {
    setInput(new InputStreamReader(stream));
  }
  /* -- end pors */

  private PushbackReader input;

  public VSTLexerCmp() {
    lexer = this;
  }

  public VSTToken nextToken() throws IOException {
    int c = input.read();
    switch (c) {
    case -1:
      return new VSTToken(VSTToken.Kind.EOF, "<EOF>");
    case '{':
      int c2 = input.read(); // 1文字先読み
      if (c2 == '{') // エスケープされた左波括弧
        return new VSTToken(VSTToken.Kind.TEXT, "{");
      if (c2 != -1) input.unread((char)c2); // 先読み分を戻す
      return new VSTToken(VSTToken.Kind.L_BRACE, "<L_BRACE>");
    case '}':
      return new VSTToken(VSTToken.Kind.R_BRACE, "<R_BRACE>");
    default:
      input.unread((char)c);
      return new VSTToken(VSTToken.Kind.TEXT, readText());
    }
  }
  
  // EOF、または'{'か'}'が出現するまでテキストを読む
  private String readText() throws IOException {
    StringBuilder sb = new StringBuilder();
    while (true) {
      int c = input.read();
      if (c == -1 ) {
        break;
      }
      if (c == '{' || c == '}') {
        input.unread((char)c);
        break;
      }
      sb.append((char)c);
    }
    return sb.toString();
  }
}
/* VSTParserCmp.java */
// VerySimpleTemplatesのパーザー・コンポネント
package sample;

import java.io.*;


/* パーザー */
class VSTParserCmp implements VSTParserPI {
  /* -- component ports */
  // @Provide
  public final VSTParserPI parser;
  // @Require(Occurence.OPTIONAL)
  public VSTHandler handler;
  // @Require
  public VSTLexerPI lexer;
  /* -- end ports */

  public VSTParserCmp() {
    parser = this;
    handler = new PrintHandler(); // デフォルト
  }

  private void signalError(String msg) throws VSTParseException {
    handler.error(msg);
    throw new VSTParseException(msg);
  }

  public void parse() throws IOException, VSTParseException {
    boolean withinPlaceholder = false; // 状態
    StringBuilder placeholderContent = new StringBuilder(); // テキスト蓄積用

    handler.startTemplate();
    while (true) {
      VSTToken tok = lexer.nextToken();
      switch (tok.kind) {
      case L_BRACE:
        if (withinPlaceholder) 
          signalError("unexpected left-brace - nested placeholder.");
        withinPlaceholder = true;
        break;
      case R_BRACE: 
        if (!withinPlaceholder) {
          handler.text("}"); // 単なるテキスト扱い
        } else { // withinPlaceholder
          if (placeholderContent.length() == 0) 
            signalError("empty placeholder content.");
          handler.placeholder(placeholderContent.toString());
          withinPlaceholder = false;
          // プレイスホルダー内容をクリア
          placeholderContent.delete(0, placeholderContent.length());
        }
        break;
      case TEXT:
        if (withinPlaceholder) {
          placeholderContent.append(tok.value); // 蓄積
        } else {
          handler.text(tok.value); // すぐにはき出す
        }
        break;
      case EOF:
        if (withinPlaceholder) 
          signalError("unexpected end-of-file - placeholder is not closed.");
        handler.endTemplate();
        return; // 脱出・終了
      default:
        assert false; // アリエナーイ
      }
    }
  }
}
/* VSTProcessorCmp.java */
package sample;

import java.io.*;
import java.util.*;
import sample.model.*;

public class VSTProcessorCmp implements VSTProcessorPI {
  /* -- component ports */
  // @Provide
  public final VSTProcessorPI processor;
  // @Require
  public List<Node> model;
  // @Require
  public Evaluator evaluator;
  // @Require
  public void setOutput(Writer writer) {
    output = new PrintWriter(writer);
  }
  // @Require
  public void setOutput(OutputStream stream) {
    setOutput(new OutputStreamWriter(stream));
  }
  /* -- end ports */

  private PrintWriter output;

  public VSTProcessorCmp() {
    processor = this;
  }

  public void process() {
    for (Node node : model) {
      if (node instanceof TextNode) {
	output.print(node.value);
      } else if (node instanceof PlaceholderNode) {
	String val = evaluator.eval(node.value);
	if (val != null) {
	  output.print(val);
	} else {
	  output.print(node.value);
	}
      }
      output.flush();
    }
  }
}
/* VSTMainCmp.java */
package sample;

import java.io.*;
import java.util.*;
import sample.model.*;

public class VSTMainCmp implements Startable {
  /* -- component ports */

  // @Provide
  public final Startable starter;

  // @Require(Occurence.OPTIONAL)
  public String inputName = null;
  // @Require(Occurence.OPTIONAL)
  public String outputName = null;
  // @Require
  public Evaluator evaluator;
  // @Require
  public ExitReportHandler reportHandler;

  /* -- end ports */

  public VSTMainCmp() {
    starter = this;
  }

  public void start() throws CannotStartException {
    /* ========== 第一段階 ========== */
    // inputの準備
    Reader input = null;
    if (inputName  == null) {
      input = new InputStreamReader(System.in);
    } else {
      try {
        input = new FileReader(inputName);
      } catch (Exception e) {
        reportHandler.aborted(1, e.toString(), e);
        return;
      }
    }
    // parserの準備
    VSTParserPI parser;
    // resultの準備
    Result<List<Node>> result;
    // 生成
    VSTLexerCmp lexerCmp = new VSTLexerCmp();
    VSTParserCmp parserCmp = new VSTParserCmp();
    ModelBuilder builder = new ModelBuilder();
    // ワイヤリング
    lexerCmp.setInput(input);
    parserCmp.lexer = lexerCmp.lexer;
    parserCmp.handler = builder.handler;
    parser = parserCmp.parser;
    result = builder.result;
    // 実行
    try {
      parser.parse();
    } catch (Exception e) {
      reportHandler.aborted(1, e.toString(), e);
      return;
    }
    // 結果取得
    if (!result.isAvailable()) {
      reportHandler.aborted(1, "Unknown error.", null);
      return;
    }
    List<Node> model = null;
    try {
      model = result.result();
    } catch (Exception e) {
      reportHandler.aborted(1, e.toString(), e);
      return;
    }

    /* ========== 第二段階 ========== */
    // outputの準備
    PrintStream output = null;
    if (outputName == null) {
      output = System.out;
    } else {
      try {
        output = new PrintStream(new File(outputName));
      } catch (Exception e) {
	reportHandler.aborted(1, e.toString(), e);
	return;
      }
    }
    // processorの準備
    VSTProcessorPI processor;
    // 生成
    VSTProcessorCmp processorCmp = new VSTProcessorCmp();
    // ワイヤリング
    processorCmp.model = model;
    processorCmp.evaluator  = evaluator;
    processorCmp.setOutput(output);
    processor = processorCmp.processor;
    // 実行
    try {
      processor.process();
    } catch (Exception e) {
      reportHandler.aborted(1, e.toString(), e);
      return;
    }
    // 後始末
    try {
      input.close();
      output.close();
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
    reportHandler.finished(0);
    return;
  }
}