D言語によるマルチスレッドプログラミング

thread.d
import core.thread, std.stdio;

void foo() {
  foreach (i; 0..100) {
    writeln("foo");
  }
}

class Foo : Thread {
  this() {
    super(&run);
  }
  void run() {
    foreach (i; 0..100) {
      writeln("Foo");
    }
  }
}

void main() {
  auto thdfoo = new Thread(&foo);
  auto thdFoo = new Foo();
  thdfoo.start();
  thdFoo.start();
}
広告

D言語によるソケットプログラミング

client1.d

import std.socket, std.stdio;

const string HOST = "localhost";
const uint PORT = 8080;
const uint SIZE = 1024;

void main() {
  auto serverTcpSocket = new TcpSocket(new InternetAddress(HOST, PORT));
  serverTcpSocket.send("Are you ready?");
  ubyte[SIZE] buffer;
  int size = serverTcpSocket.receive(buffer);
  if (size > 0) {
    (cast(string)buffer[0..size]).writeln;
  }
  serverTcpSocket.close;
}

server1.d

import std.socket, std.stdio;

const string HOST = "localhost";
const uint PORT = 8080;
const uint SIZE = 1024;

void main() {
  auto serverTcpSocket = new TcpSocket;
  serverTcpSocket.bind(new InternetAddress(HOST, PORT));
  serverTcpSocket.listen(0);
  ubyte[SIZE] buffer;
  for (;;) {
    auto clientTcpSocket = serverTcpSocket.accept;
    for (int size; (size = clientTcpSocket.receive(buffer)) > 0;) {
      (cast(string)buffer[0..size]).writeln;
      clientTcpSocket.send("Sure!");
    }
    clientTcpSocket.close;
  }
  //serverTcpSocket.close;
}

client2.d

import std.socket, std.socketstream, std.stdio;

const string HOST = "localhost";
const uint PORT = 8080;

void main() {
  auto serverSocketStream = new SocketStream(new TcpSocket(new InternetAddress(HOST, PORT)));
  serverSocketStream.writeLine("Are you ready?");
  serverSocketStream.readLine.writeln;
  serverSocketStream.close;
}

server2.d

import std.socket, std.socketstream, std.stdio;

const string HOST = "localhost";
const uint PORT = 8080;

void main() {
  auto serverTcpSocket = new TcpSocket;
  serverTcpSocket.bind(new InternetAddress(HOST, PORT));
  serverTcpSocket.listen(0);
  for (;;) {
    auto clientSocketStream = new SocketStream(serverTcpSocket.accept);
    clientSocketStream.readLine.writeln;
    clientSocketStream.writeLine("Sure!");
    clientSocketStream.close;
  }
  //serverTcpSocket.close;
}

D言語によるファイル入出力

D言語では、f(a, b)a.f(b) のように書き換えることができます。(Uniform Function Call Syntax)
また、下記の file1.d において、“gm”m は、“multiline mode” を表します。“^”“$” を使わない場合は、m を付けても付けなくても同じです。

file1.d

import std.file, std.regex;

void main() {
  "D:\\fout.txt".write("D:\\fin.txt".read);
  //write("D:\\fout.txt", read("D:\\fin.txt"));

  auto text = "D:\\fin.txt".readText;
  //auto text = cast(string)"D:\\fin.txt".read;
  text = text.replace(regex("$", "g"), "[EOF]");   //end of file -> [EOF]
  text = text.replace(regex("$", "gm"), "[EOL]");  //end of line -> [EOL]
  "D:\\fout.txt".write(text);

  foreach (file; dirEntries(".", "*.{htm,txt}", SpanMode.depth)) {
  //foreach (file; dirEntries(std.stdio.readln[0..$-1], "*.{htm,txt}", SpanMode.depth)) {
    file.write(file.readText.replace(regex("^$", "gm"), "[EL]"));  //empty line -> [EL]
    file.write(file.readText.replace(regex("<tag>.*?</tag>", "g"), "<tag>abcde</tag>"));
  }
}

file2.d

import std.stdio;

void main() {
  char[] buffer;

  buffer.readln;   //stdin  -> buffer
  buffer.writeln;  //buffer -> stdout
  readln.writeln;  //stdin  -> stdout

  auto fin = File("D:\\fin.txt", "r");
  auto fout = File("D:\\fout.txt", "w");

  while (fin.readln(buffer)) {
    fout.write(buffer);
  }

  while (!fin.eof) {
    fout.write(fin.readln);
  }

  foreach (line; fin.byLine) {
    fout.writeln(line);
  }
}

file3.d

import std.stream;

void main() {
  ubyte[1] buffer;
  auto fin = new File("D:\\fin.txt");
  auto fout = new File;
  fout.create("D:\\fout.txt");

  while (fin.read(buffer)) {
    fout.write(buffer);
  }

  while (!fin.eof) {
    fout.writeLine(fin.readLine);
  }
}

参考資料

1.std.file
2.std.stdio
3.std.stream

D言語における正規表現

D言語の正規表現でテンプレート引数付きの replace を用いると、グループ化した部分表現(正規表現の中の()で囲まれた部分)にマッチした文字列に演算を施した上で置き換えるプログラムが簡単に作成できます。下記の例では、rule で部分表現にマッチした文字列を操作しています。
尚、r”…” は、生文字列リテラル(raw string literal)を表します。

regexp.d

import std.array:array;
import std.conv, std.regex, std.stdio;

void main() {
  "1-2-3,4-5-6,7-8-9".match(regex("([0-9])-([0-9])-([0-9])")).array.writeln;
  "1-2-3,4-5-6,7-8-9".match(regex("([0-9])-([0-9])-([0-9])", "g")).array.writeln;

  if (auto m = "1-2-3,4-5-6,7-8-9".match(regex("([0-9])-([0-9])-([0-9])"))) {
    writeln(m.captures[0], ",", m.captures[1], ",", m.captures[2], ",", m.captures[3]);
  }

  foreach (m; "1-2-3,4-5-6,7-8-9".match(regex("([0-9])-([0-9])-([0-9])", "g"))) {
    writeln(m.captures[0], ",", m.captures[1], ",", m.captures[2], ",", m.captures[3]);
  }

  "1-2-3,4-5-6,7-8-9".replace(regex("([0-9])-([0-9])-([0-9])"), "$3-$2-$1").writeln;
  "1-2-3,4-5-6,7-8-9".replace(regex("([0-9])-([0-9])-([0-9])", "g"), "$3-$2-$1").writeln;

  auto text = "1+2,3+4,5+6";
  auto regexp = regex(r"([0-9]+)\+([0-9]+)", "g");
  //auto regexp = regex("([0-9]+)\\+([0-9]+)", "g");
  auto rule = (Captures!string captures) => (captures[1].to!int + captures[2].to!int).to!string;
  text.replace!rule(regexp).writeln;
}

実行結果

[["1-2-3", "1", "2", "3"]]
[["1-2-3", "1", "2", "3"], ["4-5-6", "4", "5", "6"], ["7-8-9", "7", "8", "9"]]
1-2-3,1,2,3
1-2-3,1,2,3
4-5-6,4,5,6
7-8-9,7,8,9
3-2-1,4-5-6,7-8-9
3-2-1,6-5-4,9-8-7
3,7,11

参考資料

1.D言語 – 正規表現
2.D Programming Language – Regular expressions
3.D Programming Language – std.regex

D言語による関数型プログラミング

関数型プログラミングでは、変数に関数を代入したり、引数や戻り値を関数にすることができます。
D言語では、function宣言された引数や戻り値には関数リテラルやグローバル関数が適用され、delegate宣言された引数や戻り値には関数リテラルやローカル関数(関数内で定義された関数)、メンバ関数(クラス内で定義された関数)が適用されます。
また、delegate宣言の場合は、適用された関数がその関数の外側の変数や関数にアクセスすることができるのに対し、function宣言の場合はそれができません。クロージャは、delegate のこの機能を利用して作成されます。

注)クロージャは、状態変数を保持した関数のようなもので、任意の値で状態変数を初期化した上で複数のクローンを生成することができます。C言語では、内部にstatic変数を保持した関数がクロージャに相当しますが、デフォルトで状態変数を初期化することしかできず、クローンを生成することもできません。

functional.d
import std.stdio;

int function(int, int) gf = (i, j) {return i + j;};
//auto gf = function(int i, int j) {return i + j;};

int gadd(int i, int j) {
  return i + j;
}

int function(int, int) fadd() {
  return &gadd;
}

/*
int function(int, int) fadd() {
  return (i, j) => i + j;
}
*/

int applyf(int function(int, int) f, int i, int j) {
  return f(i, j);
}

class Arithmetic {
  int add(int i, int j) {
    return i + j;
  }
}

void main() {
  int function(int, int) lf = (i, j) {return i + j;};
  //auto lf = function(int i, int j) {return i + j;};

  int delegate(int, int) ld = (i, j) {return i + j;};
  //auto ld = delegate(int i, int j) {return i + j;};

  int ladd(int i, int j) {
    return i + j;
  }

  int delegate(int, int) dadd() {
    return &ladd;
  }

/*
  int delegate(int, int) dadd() {
    return (i, j) => i + j;
  }
*/

  int applyd(int delegate(int, int) d, int i, int j) {
    return d(i, j);
  }

  int function(int, int) f = &gadd;
  writeln((&gadd)(1, 1));
  writeln(fadd()(1, 1));
  writeln(applyf(f, 1, 1));
  writeln(applyf(gf, 1, 1));
  writeln(applyf(lf, 1, 1));
  writeln(applyf(&gadd, 1, 1));
  writeln(applyf((i, j) => i + j, 1, 1));

  int delegate(int, int) d = &ladd;
  auto arithmetic = new Arithmetic();
  writeln((&ladd)(1, 1));
  writeln(dadd()(1, 1));
  writeln(applyd(d, 1, 1));
  writeln(applyd(ld, 1, 1));
  writeln(applyd(&ladd, 1, 1));
  writeln(applyd((i, j) => i + j, 1, 1));
  writeln(applyd(&arithmetic.add, 1, 1));
}

currying.d
import std.stdio;

auto at1 = (int i, int j) {return i + j;};
auto at2 = (int i) {return (int j) {return i + j;};};

int function(int, int) fp1 = (i, j) {return i + j;};
int delegate(int) function(int) fp2 = (i) {return (j) {return i + j;};};

int add(int i, int j) {
  return i + j;
}

int delegate(int) add(int i) {
  return (int j) {
    return i + j;
  };
}

void main() {
  writeln(at1(1, 1));
  writeln(at2(1)(1));

  writeln(fp1(1, 1));
  writeln(fp2(1)(1));

  writeln(add(1, 1));
  writeln(add(1)(1));
}

closure.d
import std.stdio;

int delegate(int, int) closure(int s) {
  int state = s;
  return (i, j) {
    return (i + j) * state++;
  };
}

/* NG
int function(int, int) closure(int s) {
  int state = s;
  return (i, j) {
    return (i + j) * state++;
  };
}
*/

void main() {
  auto clone1 = closure(0);
  auto clone2 = closure(10);
  foreach (i; 0..10) {
    foreach (j; 0..10) {
      writeln(clone1(i, j));
      writeln(clone2(i, j));
    }
  }
}

function_delegate_auto.d
int function(int, int) gf = (i, j) {return i + j;};       // -> OK
auto gfa = function(int i, int j) {return i + j;};        // -> OK

//int delegate(int, int) gd = (i, j) {return i + j;};     // -> NG
//auto gda = delegate(int i, int j) {return i + j;};      // -> NG

int add(int i, int j) {return i + j;}

void main() {
  int function(int, int) lf = (i, j) {return i + j;};     // -> OK
  auto lfa = function(int i, int j) {return i + j;};      // -> OK

  int delegate(int, int) ld = (i, j) {return i + j;};     // -> OK
  auto lda = delegate(int i, int j) {return i + j;};      // -> OK

  Object o;
  o = cast(Object)gf;
  o = cast(Object)lf;
  o = cast(Object)&add;
  o = cast(Object)((int i, int j) => i + j);
  //o = cast(Object)ld;   // -> NG

  void* p;
  p = gf;
  p = lf;
  p = cast(void*)&add;
  p = (int i, int j) => i + j;
  //p = cast(void*)ld;    // -> Deprecation
}

Javaによる正規表現エンジン(NFA Regex Engine)

Javaで正規表現エンジンを作成しました。使える演算子は、?, *, +, |と(, )です。
プログラムの中で、matchは文字列と正規表現の全体一致(full match)をチェックする関数です。
また、infix2postfixはinfix表記をpostfix表記に変換する関数です。

infix表記とpostfix表記

infix表記          postfix表記
   abc       →       ab.c.
  a|b|c      →       ab|c|

main.java

class Main {
  static void match(String string, String regexp) {
    System.out.println("\"" + string + "\"" + " =~ " + "/" + regexp + "/" + " -> " + new NFA(new RegexConverter().infix2postfix(regexp)).match(string));
  }
  public static void main(String[] args) {
    match("ab", "(a?b)*|(c?d)+");
  }
}

regex_converter.java

class RegexConverter {
  int index;
  String infix2postfix(String infix) {
    StringBuilder postfix = new StringBuilder();
    int countcon = 0; //the counter of concatenation operands
    int countalt = 0; //the counter of alternation operators
    for (int length = infix.length(); index < length; index++) {
      char c = infix.charAt(index);
      if (Character.isLetterOrDigit(c)) {
        if (countcon > 1) {
          postfix.append('.');
        }
        postfix.append(c);
        countcon++;
      }
      else if (c == '?' || c == '*' || c == '+') {
        postfix.append(c);
      }
      else if (c == '|') {
        if (countcon > 1) {
          postfix.append('.');
        }
        if (countalt > 0) {
          postfix.append('|');
        }
        countcon = 0;
        countalt++;
      }
      else if (c == '(') {
        if (countcon > 1) {
          postfix.append('.');
        }
        index++;
        postfix.append(infix2postfix(infix));
        countcon++;
      }
      else if (c == ')') {
        if (countcon > 1) {
          postfix.append('.');
        }
        if (countalt > 0) {
          postfix.append('|');
        }
        return postfix.toString();
      }
      else {
        return null;
      }
    }
    if (countcon > 1) {
      postfix.append('.');
    }
    if (countalt > 0) {
      postfix.append('|');
    }
    return postfix.toString();
  }
}

regex_engine.java

import java.util.*;

abstract class State {
  abstract void addto(List<State> states);
  abstract void transit(char chara, List<State> states);
  abstract void setnextstate(State state);
}

class AcceptState extends State {
  void addto(List<State> states) {
    states.add(this);
  }
  void transit(char chara, List<State> states) {}
  void setnextstate(State state) {}
}

class CharaState extends State {
  char inputchara;
  State nextstate1;
  CharaState(char inputchara) {
    this.inputchara = inputchara;
    this.nextstate1 = null;
  }
  void addto(List<State> states) {
    states.add(this);
  }
  void transit(char chara, List<State> states) {
    if (inputchara == chara) {
      nextstate1.addto(states);
    }
  }
  void setnextstate(State state) {
    nextstate1 = state;
  }
}

class SplitState extends State {
  State nextstate1;
  State nextstate2;
  SplitState() {
    this.nextstate1 = null;
    this.nextstate2 = null;
  }
  void addto(List<State> states) {
    nextstate1.addto(states);
    nextstate2.addto(states);
  }
  void transit(char chara, List<State> states) {
    System.err.println("Regex Error!");
  }
  void setnextstate(State state) {
    nextstate2 = state;
  }
}

class Fragment {
  State initialstate;
  List<State> finalstates;
  Fragment(State initialstate, List<State> finalstates) {
    this.initialstate = initialstate;
    this.finalstates = finalstates;
  }
  void attach(State state) {
    for (State s : finalstates) {
      s.setnextstate(state);
    }
  }
  Fragment patch(Fragment fragment) {
    attach(fragment.initialstate);
    return new Fragment(initialstate, fragment.finalstates);
  }
}

class NFA {
  State initialstate;
  NFA(String postfix) {
    CharaState charastate;
    SplitState splitstate;
    List<State> finalstates;
    Fragment fragment, fragment1, fragment2;
    Stack<Fragment> stack = new Stack<>();
    for (char c : postfix.toCharArray()) {
      switch (c) {
        case '?':
          fragment = stack.pop();
          splitstate = new SplitState();
          splitstate.nextstate1 = fragment.initialstate;
          finalstates = new LinkedList<>();
          finalstates.add(splitstate);
          finalstates.addAll(fragment.finalstates);
          stack.push(new Fragment(splitstate, finalstates));
          break;
        case '*':
          fragment = stack.pop();
          splitstate = new SplitState();
          fragment.attach(splitstate);
          splitstate.nextstate1 = fragment.initialstate;
          finalstates = new LinkedList<>();
          finalstates.add(splitstate);
          stack.push(new Fragment(splitstate, finalstates));
          break;
        case '+':
          fragment = stack.pop();
          splitstate = new SplitState();
          fragment.attach(splitstate);
          splitstate.nextstate1 = fragment.initialstate;
          finalstates = new LinkedList<>();
          finalstates.add(splitstate);
          stack.push(new Fragment(splitstate.nextstate1, finalstates));
          break;
        case '.':
          fragment2 = stack.pop();
          fragment1 = stack.pop();
          stack.push(fragment1.patch(fragment2));
          break;
        case '|':
          fragment2 = stack.pop();
          fragment1 = stack.pop();
          splitstate = new SplitState();
          splitstate.nextstate1 = fragment1.initialstate;
          splitstate.nextstate2 = fragment2.initialstate;
          finalstates = new LinkedList<>();
          finalstates.addAll(fragment1.finalstates);
          finalstates.addAll(fragment2.finalstates);
          stack.push(new Fragment(splitstate, finalstates));
          break;
        default:
          charastate = new CharaState(c);
          finalstates = new LinkedList<>();
          finalstates.add(charastate);
          stack.push(new Fragment(charastate, finalstates));
      }
    }
    fragment = stack.pop();
    fragment.attach(new AcceptState());
    initialstate = fragment.initialstate;
  }
  boolean match(String string) {
    List<State> currentstates = new LinkedList<>();
    initialstate.addto(currentstates);
    for (char c : string.toCharArray()) {
      List<State> nextstates = new LinkedList<>();
      for (State s : currentstates) {
        s.transit(c, nextstates);
      }
      currentstates = nextstates;
    }
    for (State s : currentstates) {
      if (s instanceof AcceptState) {
        return true;
      }
    }
    return false;
  }
}

バグがあれば、ご指摘願います。


参考サイト

1.Implementing Regular Expressions
2.Regular Expression Matching Can Be Simple And Fast
3.NFAベースの正規表現エンジン(Python)
4.Regular Expression Matching: the Virtual Machine Approach
5.PHPで仮想マシンベースの正規表現エンジンを作ってみる

インタプリタのしくみ(その2)

今日紹介するのは、算術演算インタプリタです。但し、一桁の計算しかできませんが...

-- Production Rules --
<expression> ::= <term> | <term> <addsub> <expression>
<term> ::= <factor> | <factor> <muldiv> <term>
<factor> ::= <number> | <addsub> <number> | '(' <expression> ')'
<addsub> ::= '+' | '-'
<muldiv> ::= '*' | '/'
<number> ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'

interpreter.c
#include <stdio.h>
#include <stdlib.h>

int flag;
char token;
void gettoken(void);
int expression(void);
int term(void);
int factor(void);
void error(const char[]);

int main(void) {
  int i;
  for (;;) {
    flag = 0;
    gettoken();
    i = expression();
    if (token == '\n') printf("-> %d\n", i);
  }
  return 0;
}

void gettoken(void) {
  char c;
  do {
    c = getchar();
  } while (c == ' ' || c == '\t');
  token = c;
  if (token == '+' || token == '-' || token == '*' || token == '/') {
    if (flag == 0) flag = 1;
    else error("Syntax Error!");
  }
  else flag = 0;
}

int expression(void) {
  int i = term();
  for (;;) {
    switch (token) {
      case '+': gettoken(); i += term(); break;
      case '-': gettoken(); i -= term(); break;
      default: return i;
    }
  }
}

int term(void) {
  int i = factor();
  for (;;) {
    switch (token) {
      case '*': gettoken(); i *= factor(); break;
      case '/': gettoken(); i /= factor(); break;
      default: return i;
    }
  }
}

int factor(void) {
  int i;
  if ('0' <= token && token <= '9') {
    i = token - '0';
    gettoken();
  }
  else if (token == '+') {
    gettoken();
    i = +factor();
  }
  else if (token == '-') {
    gettoken();
    i = -factor();
  }
  else if (token == '(') {
    gettoken();
    i = expression();
    if (token == ')') gettoken();
    else error("Syntax Error!");
  }
  else error("Syntax Error!");
  return i;
}

void error(const char message[]) {
  fprintf(stderr, "%s\n", message);
  exit(1);
}

使用例
(5*(-1+3))-2*(-3*2)
-> 22