ワイヤータッピングのデモ

檜山正幸
Fri Sep 29 2006

目次

1. ワイヤータッピングのときに挿入するコンポネント

  1. TokenLogger : トークンの通過を記録する
  2. TokenChecker : トークンの値がnullでないかを検査
  3. TokenCaster : トークン通過を通知する
  4. TokenMonitor : TokenCasterからの通知を受けるインターフェース
  5. LoggingMonitor : トークンの通過を記録するモニター
/* TokenLogger.java */
package sample.misc;

import java.io.*;
import sample.*;

public class TokenLogger implements VSTLexerPI {
  /* -- component ports */
  // @Provide
  public final VSTLexerPI lexerPro; 
  // @Require
  public VSTLexerPI lexerReq; 
  // @Require(Occurence.OPTIONAL)
  public void setOutput(Writer writer) {
    output = new PrintWriter(writer);
  }
  // @Require(Occurence.OPTIONAL)
  public void setOutput(OutputStream stream) {
    setOutput(new OutputStreamWriter(stream));
  }
  /* -- end ports */

  private PrintWriter output;

  public TokenLogger() {
    lexerPro = this;
    setOutput(System.out);
  }

  public VSTToken nextToken() throws IOException {
    VSTToken tok = lexerReq.nextToken();
    if (tok.kind == VSTToken.Kind.TEXT) {
      output.println("'" + tok.value  + "'");
    } else {
      output.println(tok.value);
    }
    output.flush();
    return tok;
  }
}
/* TokenChecker.java */
package sample.misc;

import java.io.*;
import sample.*;

class NullValueViolation extends RuntimeException {
  public NullValueViolation(String msg) {
    super(msg);
  }
}

public class TokenChecker implements VSTLexerPI {
  /* -- component ports */
  // @Provide
  public final VSTLexerPI lexerPro; 
  // @Require
  public VSTLexerPI lexerReq; 
  /* -- end ports */

  public TokenChecker() {
    lexerPro = this;
  }

  public VSTToken nextToken() throws IOException {
    VSTToken tok = lexerReq.nextToken();
    if (tok.value == null) 
      throw new NullValueViolation("value is null. kind=" + tok.kind);
    return tok;
  }
}
/* TokenCaster.java */
package sample.misc;

import java.util.*;
import java.io.*;
import sample.*;
import sample.misc.TokenMonitor;

public class TokenCaster implements VSTLexerPI {
  // ※注意:シングルスレッドのみとして、排他制御はしない

  /* -- component ports */
  // @Provide
  public final VSTLexerPI lexerPro; 
  // @Require
  public VSTLexerPI lexerReq; 
  // @Require(Occurrence.ANY)
  public void addMonitor(TokenMonitor mon) {
    if (!monitorList.contains(mon)) monitorList.add(mon);
  }
  // @Require(Occurrence.ANY)
  public void removeMonitor(TokenMonitor mon) {
    monitorList.remove(mon);
  }
  /* -- end ports */

  public TokenCaster() {
    lexerPro = this;
  }

  public VSTToken nextToken() throws IOException {
    VSTToken tok = lexerReq.nextToken();
    sendTokenPassedEvent(tok);
    return tok;
  }

  private List<TokenMonitor> monitorList = new ArrayList<TokenMonitor>();

  public void sendTokenPassedEvent(VSTToken token) {
    for (TokenMonitor mon : monitorList) {
      mon.tokenPassed(token);
    }
  }
}
/* LoggingMonitor.java */
package sample.misc;

import java.io.*;
import sample.*;
import sample.misc.TokenMonitor;

public class LoggingMonitor implements TokenMonitor {
  /* -- component ports */
  // @Provide
  public final TokenMonitor monitor;
  // @Require(Occurrence.OPTIONAL)
  public void setOutput(Writer writer) {
    output = new PrintWriter(writer);
  }
  // @Require(Occurrence.OPTIONAL)
  public void setOutput(OutputStream stream) {
    setOutput(new OutputStreamWriter(stream));
  }
  /* -- end ports */

  private PrintWriter output;

  public LoggingMonitor() {
    monitor = this;
    setOutput(System.out);
  }

  public void tokenPassed(VSTToken tok) {
    if (tok.kind == VSTToken.Kind.TEXT) {
      output.println("'" + tok.value  + "'");
    } else {
      output.println(tok.value);
    }
    output.flush();
  }
}
/* TokenMonitor.java */
package sample.misc;

import sample.VSTToken;

public interface TokenMonitor {
  public void tokenPassed(VSTToken token);
}
/* LoggingMonitor.java */
package sample.misc;

import java.io.*;
import sample.*;
import sample.misc.TokenMonitor;

public class LoggingMonitor implements TokenMonitor {
  /* -- component ports */
  // @Provide
  public final TokenMonitor monitor;
  // @Require(Occurrence.OPTIONAL)
  public void setOutput(Writer writer) {
    output = new PrintWriter(writer);
  }
  // @Require(Occurrence.OPTIONAL)
  public void setOutput(OutputStream stream) {
    setOutput(new OutputStreamWriter(stream));
  }
  /* -- end ports */

  private PrintWriter output;

  public LoggingMonitor() {
    monitor = this;
    setOutput(System.out);
  }

  public void tokenPassed(VSTToken tok) {
    if (tok.kind == VSTToken.Kind.TEXT) {
      output.println("'" + tok.value  + "'");
    } else {
      output.println(tok.value);
    }
    output.flush();
  }
}

2. ワイヤータッピングのデモ

  1. VSTDemo1 : 標準的な接続
  2. VSTDemo2 : TokenLoggerを挿入
  3. VSTDemo3 : TokenCheckerを挿入
  4. VSTDemo4 : TokenCheckerを挿入し、レクサーをNullLexerに
  5. VSTDemo5 : TokenCasterとLoggingMonitorでログ機能を実現
/* VSTDemo1.java */
package sample;

import java.io.*;

class VSTDemo1 {
  public static void main(String[] args) {
    // inputの準備
    Reader input = null;
    if (args.length == 0) {
      input = new InputStreamReader(System.in);
    } else {
      try {
        input = new FileReader(args[0]);
      } catch (Exception e) {
        System.err.println(e);
        System.exit(1);
      }
    }
    // parserの準備
    VSTParserPI parser;
    // 生成
    VSTLexerCmp lexerCmp = new VSTLexerCmp();
    VSTParserCmp parserCmp = new VSTParserCmp();
    // ワイヤリング
    lexerCmp.setInput(input);
    parserCmp.lexer = lexerCmp.lexer;
    parser = parserCmp.parser;
    // 実行
    try {
      parser.parse();
    } catch (Exception e) {
      System.err.println(e);
      System.exit(1);
    }
    System.exit(0);
  }
}
/* VSTDemo2.java */
package sample;

import java.io.*;
import sample.misc.TokenLogger;

class VSTDemo2 {
  public static void main(String[] args) {
    // inputの準備
    Reader input = null;
    if (args.length == 0) {
      input = new InputStreamReader(System.in);
    } else {
      try {
        input = new FileReader(args[0]);
      } catch (Exception e) {
        System.err.println(e);
        System.exit(1);
      }
    }
    // parserの準備
    VSTParserPI parser;
    // outputの準備
    Writer output = null;
    try {
      output = new FileWriter("tokens.log");
    } catch (Exception e) {
      System.err.println(e);
      System.exit(1);
    }
    // 生成
    VSTLexerCmp lexerCmp = new VSTLexerCmp();
    VSTParserCmp parserCmp = new VSTParserCmp();
    TokenLogger logger = new TokenLogger();
    // ワイヤリング
    lexerCmp.setInput(input);
    logger.setOutput(output);
    logger.lexerReq = lexerCmp.lexer;
    parserCmp.lexer = logger.lexerPro;
    parser = parserCmp.parser;
    // 実行
    try {
      parser.parse();
    } catch (Exception e) {
      System.err.println(e);
      System.exit(1);
    }
    System.exit(0);
  }
}
/* VSTDemo3.java */
package sample;

import java.io.*;
import sample.misc.TokenChecker;

class VSTDemo3 {
  public static void main(String[] args) {
    // inputの準備
    Reader input = null;
    if (args.length == 0) {
      input = new InputStreamReader(System.in);
    } else {
      try {
        input = new FileReader(args[0]);
      } catch (Exception e) {
        System.err.println(e);
        System.exit(1);
      }
    }
    // parserの準備
    VSTParserPI parser;
    // 生成
    VSTLexerCmp lexerCmp = new VSTLexerCmp();
    VSTParserCmp parserCmp = new VSTParserCmp();
    TokenChecker checker = new TokenChecker();
    // ワイヤリング
    lexerCmp.setInput(input);
    checker.lexerReq = lexerCmp.lexer;
    parserCmp.lexer = checker.lexerPro;
    parser = parserCmp.parser;
    // 実行
    try {
      parser.parse();
    } catch (Exception e) {
      System.err.println(e);
      System.exit(1);
    }
    System.exit(0);
  }
}
/* VSTDemo4.java */
package sample;

import java.io.*;
import sample.misc.TokenChecker;

class NullLexer implements VSTLexerPI {
  public VSTToken nextToken() throws IOException {
    return new VSTToken(VSTToken.Kind.TEXT, null);
  }
}

class VSTDemo4 {
  public static void main(String[] args) {
    // inputの準備
    Reader input = null;
    if (args.length == 0) {
      input = new InputStreamReader(System.in);
    } else {
      try {
        input = new FileReader(args[0]);
      } catch (Exception e) {
        System.err.println(e);
        System.exit(1);
      }
    }
    // parserの準備
    VSTParserPI parser;
    // 生成
    VSTParserCmp parserCmp = new VSTParserCmp();
    TokenChecker checker = new TokenChecker();
    // ワイヤリング
    checker.lexerReq = new NullLexer();
    parserCmp.lexer = checker.lexerPro;
    parser = parserCmp.parser;
    // 実行
    try {
      parser.parse();
    } catch (Exception e) {
      System.err.println(e);
      System.exit(1);
    }
    System.exit(0);
  }
}
/* VSTDemo5.java */
package sample;

import java.io.*;
import sample.misc.TokenCaster;
import sample.misc.LoggingMonitor;


class VSTDemo5 {
  public static void main(String[] args) {
    // inputの準備
    Reader input = null;
    if (args.length == 0) {
      input = new InputStreamReader(System.in);
    } else {
      try {
        input = new FileReader(args[0]);
      } catch (Exception e) {
        System.err.println(e);
        System.exit(1);
      }
    }
    // parserの準備
    VSTParserPI parser;
    // outputの準備
    Writer output = null;
    try {
      output = new FileWriter("tokens.log");
    } catch (Exception e) {
      System.err.println(e);
      System.exit(1);
    }
    // 生成
    VSTLexerCmp lexerCmp = new VSTLexerCmp();
    VSTParserCmp parserCmp = new VSTParserCmp();
    TokenCaster caster = new TokenCaster();
    LoggingMonitor logMonitor = new LoggingMonitor();
    // ワイヤリング
    lexerCmp.setInput(input);
    logMonitor.setOutput(output);
    caster.lexerReq = lexerCmp.lexer;
    caster.addMonitor(logMonitor.monitor);    
    parserCmp.lexer = caster.lexerPro;
    parser = parserCmp.parser;
    // 実行
    try {
      parser.parse();
    } catch (Exception e) {
      System.err.println(e);
      System.exit(1);
    }
    System.exit(0);
  }
}