自作プログラミング言語

NoFollowと自作プログラミング言語

自作のプログラミング言語のページです。

辿らない言語

NoFollowは僕の作ったプログラミング言語です。その名の通り、「辿らないこと」を目標にしています。
普通、Cのコードはこのように書きます。

#include <stdio.h>
int test(int x, int y){
  return (x + y);
}
int main(void){
  int x;
  int y;
  int a;
  x = 5;
  y = 7;
  a = test(x,y);
  printf("%d\n", a);
}

このC言語のコードでは、testを辿っていくことで、プログラムの理解へと近づきます。
NFは、こういう時、「プログラマが明示することで、辿らなくても大体のプログラムは分かる」ようにするための言語です。
例えば、
int main(void)
だけでも、このように分析出来ます。
int: func type;
main: func name;
void: func argument;
そして、それらはdefinitionです。
ですが、長くなってしまうと、そういうことを、コードを見て少し考えないと、分からなくなってしまいます。
このNFでは、このような「プログラムをあとで理解する思考コスト」を削減します。
そして、出来る限り、見ただけで分かるようにします。入門書を読む必要を無くします。
そういうわけで、NFでは以下のようなプログラムになります。

@def &main {
  @head {
    @type: main
    @return_type: int
    @arguments{
      $$_ { @type: void }
    }
  }
  @body {
    @def {
      $x { @type: int }
      $y { @type: int }
      $a { @type: int }
    }
    @run {
      $x = 5
      $y = 7
      $a = [return] [run] &test {
        $$value1 = $x
        $$value2 = $y
      }
      [run] &printf {
        $$format = "%d\n"
        $$option = $a
      }
    }
  }
}
@def &test {
  @head {
    @type: method
    @return_type: int
    @arguments{
      $$value1 { @type: int }
      $$value2 { @type: int }
    }
  }
  @body {
    @run {
      [run] &return { [run] &calculation { ($$value1 + $$value2) } }
    }
  }
}

なんとなく、最後の方のreturnやcalculationを何故引数の名前を明記しないのか、など、課題は残りますが、とりあえず、変数の引数まで名前をきちんと明記するような、そういう言語にしたいと思っています。
あまり意味がないですが、最近Rustと言う言語に関心があります。自分が見て、こうしたら良いと思うな、などと思うこともあります。技術力をつけて、Rustの改良が出来るようになったら良いなと思っています。
2016.12.15

ロボット

この言語を用いて、僕の人工知能のロボットを書いてみました。

[headers]
#include <stdio.h>
#include <stdlib.h>

@def _obj:: {
  @type: struct
  @items {
    $o { @type: int }
    $n { @type: int }
  }
}

@def &action {
  @head {
    @type: mathod
    @return_type: void
    @arguments{
      $$[p]p { @type: [p]int }
      $$[p]obj { @type: [p]struct _obj:: }
    }
  }
  @body {
[block "action-body"] //インデントを一度解除します。

[run] &case {

  @if "1" : //今回はPython風のインデントです。
    @match: { ($$*p == 0) }
    @run { [run] &printf { $$format = "[1] テレビは、つまらない\n"} }

  @if "2" :
    @match: { ($$*p == 1) }
    @run { [run] &printf { $$format = "[2] テレビは、面白い\n"} }

  @if "3" :
    @match: { ($$*p == 2) }
    @run { [run] &printf { $$format = "[3] パソコンは、つまらない\n"} }

  @if "4" :
    @match: { ($$*p == 3) }
    @run { [run] &printf { $$format = "[4] パソコンは、面白い\n"} }

  @if "5" :
    @match: { ($$*p == 4) }
    @run { [run] &printf { $$format = "[5] テレビやパソコンは、機械だ。\n"} }

  @if "6" :
    @match: { ($$*p == 5) }
    @run { [run] &printf { $$format = "[6] テレビやパソコンは、生き物ではない。\n"} }

  @if "7" :
    @match: { ($$*p == 6) }
    @run { [run] &printf { $$format = "[7] テレビって何なのだろう。\n"} }

  @if "8" :
    @match: { ($$*p == 7) }
    @run { [run] &printf { $$format = "[8] テレビとパソコンは好きだ。\n"} }

  @if "9" :
    @match: { ($$*p == 8) }
    @run { [run] &printf { $$format = "[9] テレビとパソコンは嫌いだ。\n"} }

  @if "10" :
    @match: { ($$*p == 9) }
    @run { [run] &case {
      @if "A" :
        @match: { ($$obj->$n == 0) }
        @run { [run] &printf { $$format = "[10] 比較すると、テレビの方が普通だ。\n"} }

      @if "B" :
        @match: { ($$obj->$n == 1) }
        @run { [run] &printf { $$format = "[11] 比較すると、パソコンの方が普通だ。\n"} }

    }

  @if "11":
    @match: { ($$*p == 10) }
    @run { [run] &case {
      @if "C" :
        @match: { ($$obj->$n == 0) }
        @run {
          [run] &printf { $$format = "[12] テレビよりパソコンの方が普通かな。\n"}
          $$obj->$n = 1
        }

      @else_if "D" :
        @match: { ($$obj->$n == 1) }
        @run {
          [run] &printf { $$format = "[13] パソコンよりテレビの方が普通かな。\n"}
          $$obj->$n = 0
        }
    }


  @if "12":
    @match: { ($$*p == 11) }
    @run { [run] &case {
      @if "E" :
        @match: { ($$obj->$o == 0) }
        @run { [run] &printf { $$format = "[14] リンゴが好きです。\n"} }

      @if "F" :
        @match: { ($$obj->$o == 1) }
        @run { [run] &printf { $$format = "[15] みかんが好きです。\n"} }
    }

  @if "13":
    @match: { ($$*p == 12) }
    @run { [run] &case {
      @if "G" :
        @match: { ($$obj->$o == 0) }
        @run {
          [run] &printf { $$format = "[16] リンゴより、みかんが好きになりました。\n"}
          $$obj->$o = 1
        }

      @else_if "H" :
        @match: { ($$obj->$o == 1) }
        @run {
          [run] &printf { $$format = "[17] みかんより、リンゴが好きになりました。\n"}
          $$obj->$o = 0
        }
    }
  }
[/block "action-body"]

  }
}

@def &main {
  @head {
    @type: main
    @return_type: int
    @arguments{
      $$_ { @type: void }
    }
  }
  @body {
    @def {
      $p { @type: int }
      $obj { @type: struct _obj:: }
    }
    @run {
      $p = 0
      $obj.$o = 0
      $obj.$n = 0

      [run] &loop {
        @terms { (1) }
        @run {
          $p = [run] &calc { [run] &rand {} % 13 }
          [run] &action {
            $$[p]p = &($p)
            $$[p]obj = &($obj)
          }
        }
      }
    }
  }
}

色々と大変だ。これで読みやすくなったとは言うが、自分が見てもただ無駄に長くなっただけだ。
2016.12.16

マクロテンプレート

ちなみに、この言語ではマクロテンプレートと言うものを用意して、ファイル処理やWindowsメッセージループを簡単に見やすく書けるようにします。
メッセージループの場合:

@@windows_msg {
  @msg "button1のクリック" {
    @event: button_click
    @select: button1
    @run: { }
  }

  @msg "button2のクリック" {
    @event: button_click
    @select: button2
    @run: { }
  }
}

ファイル処理の場合

@@file_open {
  @open {
    @file: <DATAFILE>
    @path: /home/myname/file
    @loop {
      @get { $line = <DATAFILE> }
      @run {
        [run] &print { $$format =  "$line\n" }
      }
    }
}

WindowsからPerlまで、何でもこなせる優れた言語が、NFです。
出来れば、jQueryのような、セレクタに対してイベントが起きた時の処理をするような、そういう言語にしたいです。
マクロテンプレートは、プラグインのようなものだと思ってください。標準では、メッセージループとファイル処理を搭載して、誰もが手軽に作れるようにします。
コンパイラはありません。頑張って、C言語に変換出来るようになると良いと思います。誰か、作ってください!
2016.12.17

テキスト処理

テキスト処理はこういう風に書く。

@@text {
  @file: "file.txt"
  @block '<p>' to '</p>' {
    @rep {'\(.*\):\(.*\)<br>' to '\1->\2\n'}
  }
}

どこからどこまでの範囲で - @block、何をどのように置換するか - \(.*\) to \1、を簡単に書ける。
以下のようにすると、最初の1~2行だけを編集できる。

@@text {
  @line (1-2) { }
}

2017.02.07

GUI

GUIはこういう風にする。

@@method_def {
  @def: { %image: &show/&copy }
  @def: { %text: &edit/&copy }
  @def: { %link: &go}
}

まず、マウスをクリックした時は、その領域を選択(処理ではなく、選択)する。
そして、画像なら、showとcopyのメニューを表示する。
テキストなら、editとcopyのメニューを表示する。
リンクなら、goのメニューを表示する。
そして、それらのメニューをクリックした時に、それぞれの処理を行う。
メインメニューと言うよりは、コンテキスト・メニューに近い。
2017.03.06

奴隷的言語

ツイッターに投稿した、奴隷的言語について。
2017-03-20より。
僕は、今のところパソコンが人間に忠実に従っているが、これがパソコンが人間に意見するようになると、それですでにパソコンは人間だと思う。何かをする時に、パソコンの方から「こういう風に操作してはいかがですか?」と言ったことを問いかけるようにする。人工知能を作るより、その方が先進的だ。
ただ、プログラムを描く、と言う中で、いつも関数の実行の側に主導権があるが、これを関数の呼ばれる側に主導権を作っても良い。関数を呼び出した時の処理を、関数の中で変えられるようにし、関数を変えることで全ての処理を変えられるようにする。グローバル・メソッドと言う名前にしても良い。
自分でも、グローバル・メソッドが何を意味しているのか、良く分かっていない。要は、実行の主導権を呼び出される側に与える、と言うことだから、

gm(3,4);

とするのではなく、

[id:1]gm();

として

gm(void){
  if(id==1) action1(3,4);
}

とするのだと思う。
分からない。書いている本人も分かっていない。本当は、ただ従うだけではなく、相手から注文をつけてくるような、そういう言語を作りたかった。

int calc(int x, int y){
  [method1: x=3;y=4;]
  [method2: x=2;y=1;]
  return x+y;
}

int method1{
  calc[method1](?);
}

int method2{
  calc[method2](?);
}

とする。
ある意味、相手によって言うことを変える、二枚舌のようなプログラミング言語になった。
僕は、もう少し改良して、人間が呼び出すコードを関数の方で変えられるようにしたい。

int main(){
  [action(block1)]
  printf("\n");
  [action(block2)]
}

void action(){
  [block1]{gm1();}
  [block2]{gm2();}
}

これで、呼び出し元にあるblock1とblock2の宣言場所で、action関数を実行し、gm1関数とgm2関数を関数の中で実行することが出来る。
人間みたいになった。今までは人間が主導権を持って関数を実行していた。人間がコマンドを打ち込む感覚だ。今からは、関数が主導権を持つ。コマンドの方が人間がやることを決める、と言う感覚だ。
ただ、それならもっと違う形態で、main関数の中にあるブロックを関数から実行出来る。

int main(){
  [action(): test(int x) {printf("%d", x); } ]
}

void action(){
  test(2);
}

となる。
要は、パソコンの方にコマンドを打ってほしい。その中でやることは自分が決める。そういう、「奴隷的言語」がこの言語だ。
2017.03.20

MetaC

ツイッターに投稿した、構文を関数として実装することで、自由に構文を定義することの出来るメタ言語「MetaC」について。
2017-04-03より。
僕は、C言語で言うifやforなどの文で、特に{}で囲まれた部分を変数や引数とすることで、C言語の構文を少なくし、ユーザーが自由に定義出来るようにし、ifやforも関数で実現することが出来ると思う。それは、エレガントで美しい。
ある意味、言語的仕様を少なくすることで、構文を関数の範疇として、全てを関数にすることが出来る。あるいは、関数でもなく、全てをブロック的実行とすることも出来る。ある意味、代入や演算も何かもっと根源的なものとして、実装出来るかもしれない。
オブジェクト指向では全てをオブジェクトにするが、それは僕はあまり良い実装ではないような気がする。()と{}の違いを無くするならLispのようにも出来る。Rubyのようにしても良い。if () {}をもっと変えることで、if () {} {} {}のようにも出来るのだ。
例えば、spifと言う関数を宣言して、if(){}とする代わりに、spif(){}(){}と出来るかもしれない。そこでどんな風に処理を実行するかは、プログラマの自由だ。
ある意味、この言語はNFと融和して、「言語を作る言語」にすると面白い。JavaC++PerlRubyPHPなど、全部の言語をこの言語の拡張として実装する。そして、誰でも外部の人間が自由に言語を作れるようにする。spifだけではなく、newを改良してspnewにも出来る。
例えば、

spnew(Object_name, Class_name).Function_name(x,y,z).{print;save;}

のように、ありえないほど高度で複雑怪奇な言語を作れる。ただ、全てを関数として実行するだけで、構文を独自に定義し、メタ言語を作れる。
むしろ、

Class::Object.Function(values){Messages(Events){Code}}

と言う風にするのは、美しい。そういう風に、関数を定義すると良いかもしれない。
例えば、

View::v.list(page1){open(clicked(menu1)){new_open(this)};close(clicked(menu2)){kill(this)};}

と言うコードが書ける。
頑張れば、GUIのイベント駆動型プログラムを一行で書くことも出来るだろう。メタ言語のCだから、名前は「MetaC」とする。
2017.04.03

マルチスレッド言語

2017-04-05より。
なんとなく、こんな並列処理言語があっても良い。

multi-thread {
  while(1){printf("1\n");}
} {
  while(1){printf("2\n");}
}

これを、ifやforの拡張として、関数として実現すると、面白い。
2017.04.05

オペレーション言語

オペレーション言語と言うものを作ってみた。プログラミングを技術や計算ではなく、操作と考える。

file_open ($file) {
  @name: 'text.txt';
  %message(1) 'convert' {
    @run: { &regex ($file, 'right' to 'left') };
  }
  %message(2) 'print' {
    @before: { &display ( 'Document is coverting from "right" to "left"' ) };
    @after: { &display ( 'end' ) };
    @main: { &loop { 'print $1', (&read_line_next($file)) }; }
  }
}
file_close($file);

もっと、いかにも「メッセージを送ってオペレーションするぞ」と言った言語にしたい。
2017.05.09

文章の書式と変数の型・オブジェクト

文章の書式を指定したい時は、以下のようにする。

string:"text\n" //textに改行を加えた文字列
string_noformat:"text\a\a" //text\a\aと言う文字列(\が付けられても特殊文字と解釈しない)
int:3 //数字の3
string:3 //文字列の3

また、オブジェクト指向については、「型」と「オブジェクト」を同一のものと見なす。
int型は即座にintオブジェクトであり、WindowForm型は即座にWindowFormオブジェクトである。
そして、型は継承やカプセル化の出来るオブジェクトであると同時に、コンパイルする時の静的な型チェックもすることが出来る。
また、オブジェクト指向として、プロパティ操作指向を行う。全てはメソッドを呼び出した時、そのクラスの「内部処理」として操作を行う。
これにより、CORBAのような万能コンポーネントを一言語的に実現することが出来る。
printを行った時にも、setやgetを行って変数を変えた時にも、クラスとオブジェクトの内部で処理を行う。
そのために、それぞれに処理が分散するのではなく、それぞれのオブジェクトの関係性として、メッセージの伝達をすることが出来る。
そうすることで、コンポーネントを作りやすくする。
Adobe Illustratorのようなソフトウェアを作る時に、何かを「伝える側」はメッセージを送るだけにし、「伝わった側」はその時その時の処理を単純に行う。
その上で、「伝える側」が「高度に伝えること」も可能にする。そのように、「アーキテクチャ指向」のようなプログラミングが可能になる。

$filename = string_path:"text.txt";
@def: window::&open (FILE: $$file) { 処理 }
@def: window::&view (string: $$output) { 処理 }
@def: window::&update (string: $$output) { 処理 }
@def: window::&calc (int: $$int) { 処理 }
$w = window: new window{};
@@messages => $w {
  [run] &open{ $$file = (FILE)$filename};
  [run] &view{ $$output = string:"hello"};
  [run] &update{ $$output = string:"world"};
  [run] &calc{ $$int = int:2+3};
}
@def_ex window_ex @ex_from window;
@def_ex window_ex:: @ex_method:&open (FILE: $$file) { 処理 };
$w2 = window_ex: new window_ex{};
@@messages => $w2 {
  [run] &open { $$file = (FILE)string_path:"image.jpg"};
}

2017.07.10

新言語「Emerald」

こんな言語を作ってみた。

shared_datas ClassType {
  int num;
  String str;
}

method func1 (val int x, ref String y) for ClassType @ct {
  print(x);
  y = "text";
  @ct.num = x;
  @ct.str = y;
}

method func2 (ref ClassType ct) {
  func1 (42, "format") using ct;
}

method main(val int argc, val String[] argv) {
  ClassType ct = new ClassType;
  String str = "document";
  func1(32, str) using ct;
  func2(ct);
}

継承や委譲、インターフェースの実装もできるようにしたい。
2018.11.05

宣言、代入、変数、関数をエレガントに

僕は、プログラミング言語の基本は、宣言、代入、変数、関数だと思う。これをエレガントに書きたい。
たとえば、クラスの宣言は以下のように書ける。

Test = class;
Test.datas = {
  @num = int;
  @str = String;
};
Test.methods = {
  func1 = func (return int) (args val int x, ref String y) {
    print(x);
    y = "text";
    @num = x;
    @str = y;
    return (x * 2);
  }
};
test = (Test) new Test;
str = (String) "document";
print(test.func1());

頭を柔らかくして考えること。ある意味、宣言と代入は同じものであると考えることができる。変数や関数も、一種の宣言であり、代入であると考えられる。
このコードはJavaScriptのプロトタイプチェーンに近いかもしれない。上の方のコードはDelphiやAdaに近い。
2018.12.09

新しい言語Gold

こんな言語はどうか。

main.start();

  data1 is data named XAndY = { int x; int y; };
  
  data1.new();
  
  func1 is func (d is data as XAndY) = {
    print("{0}, {1}", d.x, d.y);
  }
  
  func1.run(-d=data1);
  
  data.end();

main.end();

メソッドの始まりと終わりであるstart();とend();は、他のプログラム言語である{}に相当する。この言語では{}すら関数として書く。
そして、変数はnew();とend();でインスタンスを作る。上のstart()とend()と全く同じ仕組みであり、関数のend()と変数のend()を統一的に記述できる。
ガーベッジコレクションは行わない。その代り、ヒープ領域をリアルタイムで監視する「ヒープ監視ツール」を作る。これをモニタリングすることで、メモリリークを「デバッガのように」監視できるようにする。
関数に引数を与える時は、UNIXのコマンドのように-d=dataとする。これにより、可読性が向上する。
上のコードはstart(), end()と{}が混在しているが、これをどうするかが課題である。
また、この言語では、単なる関数だけではなく、組み込みの命令文を多くサポートする。シェルスクリプトのようなものに近い。ifやforなどは、この組み込みの命令文で実現する。よってifではなく%ifと表記する。また、ポインタはpointerで宣言する。ただしアロー演算子(->)は使わない。

func1 is func(d is pointer to data as XAndY) = {
    %if (d.x == d.y) {
        print("x = y");
    }
}

returnは関数定義に記述する。また、dataは省略できる。データ構造体は-d.x=1, -d.y=2のように、引数や代入で使う場合、Perlのリストのように要素の羅列として書くことができる。

func2 is func(d is pointer as XAndY) return as int = {
    return d.x + d.y;
}

c = func2.run(-d.x = 1, -d.y = 2);
print("{0}", c);

関数定義は単なる代入であるため、変数に格納して持ち運んだり、別の関数の引数に渡すことができる。実行はfunc1.run();とする。func1();では実行できない。
2019.02.21