
執筆者: кемо
最終更新: 2025/10/25
やあ
今回はOUCRCに空前の自作言語ブームが到来したので、自作言語を作ることにしました。ほかの二人のほうが凄いのを作ってるので見てあげてね。
ところで弊学では4・5月に「プログラミング技法」という講義が開講されています。この講義は「どのようにしたらよいコードが書けるのか」という作法的なことを学ぶ非常に面白い講義です。
しかし、ここで逆転の発想を思いつきました。
「クソコードしか書けない言語なら平等なのでは?」
初心者も上級者もゴミしか書けなければ、技法だとか作法だとかは必要ありません。ということで、すべてに逆張りしましょう。
プログラミング技法の教え | 新言語 |
|---|---|
丁寧なコメントを書け | コメントは書けない |
変数・関数名は分かりやすく | すべて連番で管理 |
副作用に注意 | 副作用まみれ |
ここまですれば勝ったようなものでは?
ということでお見せしましょう。
SigNumとは記号と数字だけで構成される、究極にシンプルなプログラミング言語です。SigNumという名前はSign + Numberを合わせたものに由来し、同時にラテン語で記号を意味します。
SigNumは文字列リテラルを除く、すべてが記号と数字によって記述されます。
これはREADMEに書いてある紹介です。まあこの紹介とコンセプトで察しがついたと思いますが、定番の"Hello world"はこれです。
< "Hello, world!";結構いい感じでは?
ではさらに定番の"FizzBuzz"行きましょう
_001{
?($#0 % 15 == 0) {
< "FizzBuzz";
}
??($#0 % 3 == 0) {
< "Fizz";
}
??($#0 % 5 == 0) {
< "Buzz";
}
??? {
< $#0;
}
}
$#0 = 1;
&($#0 <= 100) {
$_001;
$#0 = $#0 + 1;
}まあそんなに普通の言語と変わらないんですね。話だけ聞くと、Brainf*uk系の言語をご存じの方はそれを想像すると思いますが,こいつはそれほど難しい言語ではありません。記号と数字だけと言いながら文字列は普通にアルファベットですし。余談ですが、文字列もすべて文字コードで管理しようとしていましたが、めんどくさくて断念しました。
中身は普通のC++インタープリタですが、コンセプトで宣言した通りになってます。変数・関数名が連番である都合上、指定した個数しかそれらを宣言できないほか、副作用まみれにするためスコープという概念がありません。
もっと詳細を説明してもいいんですけど、確実に長くなるのでチュートリアルをみてください。まあ未完成なので全機能を網羅できてないんですけどね。
ここまで読んだ人ならわかると思いますが、この言語はなんの役にも立ちません。ほかの部員が作った生産的で勉強になる自作言語を見たほうがいいですよ。
中身の話を少ししましょう。前述のとおりこの言語はC++インタープリタです。字句解析・構文解析・意味解析・評価のすべてをC++でハードコードしているので読みにくいったらありません。拡張性も皆無で、バグ探しにも苦労しました。
例えばメモリ参照の字句解析は以下のようになってます。
std::string Lexer::parseMemoryRef() {
std::string memref = "";
memref += source[pos++]; // "$"
while (pos < source.size() && (source[pos] == '#' || source[pos] == '@' || source[pos] == '~' || source[pos] == '%' || source[pos] == '^')) {
memref += source[pos++]; // 型記号
column++;
if (memref.back() == '^' && pos < source.size()) {
if (source[pos] == '#' || source[pos] == '@' || source[pos] == '~' || source[pos] == '%') {
memref += source[pos++]; // マップ型記号
column++;
}
}
// ネストされた参照の場合
if (pos < source.size() && source[pos] == '$') {
memref += parseMemoryRef(); // 再帰
}
// 通常の数字の場合
else {
while (pos < source.size() && isdigit(source[pos])) {
memref += source[pos++];
column++;
}
}
}
return memref;
}優秀なオープンソースツールがあるのに、なぜ使わなかったのか?
こんな感じのコードが延々と続きます。現在、コンパイラの講義を受けているのですが、こんなにも簡単に構文解析までできるのかと驚愕しています。
優秀なオープンソースツールがあるのに、なぜ使わなかったのか?
まだベータ版ですがリリースしてます。触ってみた感想を聞かせてくれると嬉しいです。