プログラミング言語の作り方のサンプルとして、言語「samplan」を作った

「samplan」という新しいプログラミング言語を作りました。

ソースはGitHubに上げてあります。

github.com

私のWebページの方に、説明記事を上げておきました。

kmaebashi.com

ざっくりとした見た目はこんな感じになります。

# samplanサンプルプログラム
var hoge int := 10;
var piyo real := 20.0;
var result real := ((hoge + piyo * 2) / 3 - 5);

print("result.." + result);

# 1から、与えられた引数までの数値の和を計算する関数
function sum(value int) int {
  var i int := 1;
  var sum int := 0;

  while (i <= value) {
    sum := sum + i;
    ++i;
  }
  return sum;
}

# 1~10の和は、55
print("sum(10).." + sum(10));

発端

元はみずしまさんが「今から一時間でプログラミング言語を一つ作る」というのをやっておられたのを見て、まあ私には1時間では無理ですが、言語をひとつガシガシと作ってみたくなったのでした。

そこで、10/23土曜日の昼過ぎから作成開始。

正直、うまくいったらこの日のうちに何となくでも動いて、動いたらビールで乾杯、くらいに思っていたのですが、さすがに処理系いっこ、静的型付けありでVMで動く言語となるとそうはいかず、土曜はパーサが動くので精一杯、日曜にまたちょっと作業して、その後の平日もちまちま(1時間かそこらしか時間は取れないのですが)作業したりしなかったりして、金曜の晩に一応最後まで書いて動かしてみたがめちゃくちゃ、次の土曜は晴れたのでいつもの養老コースで走りに行って、夕方に帰宅後ちょっと直してようやくぼちぼち動くようになったのでした。

samplanはどんな言語か

samplan(sample languageの略です)は、CやJavaJavaScriptのような波括弧系の言語ですが、Cとかとは以下の点が異なります。

  • if文とかの{ }は省略できません。その代わりにifの後ろの()は不要です。
  • if文の{ }が省略できないので、Cとかのelse if構文は使えません*1。その代わりに予約語elsifを追加しています。
  • 型は後置です。つまり「int hoge;」ではなくて「var hoge int;」です。思えばCの、「型 変数名;」であるかのように見える(Cでは実は違うのですが)という宣言の構文にどれほど多くのプログラマが惑わされてきたことか!!
  • 代入は=ではなく:=です(Pascal風)。それに伴い、等値比較は「=」になっています。

かつて私は以下のページでcrowbarとかDiksamといった言語を作りましたが、

kmaebashi.com

この時は、if文の{ }は省略不可にしてelsifを導入したものの、型は前置にしましたし、代入は=にしました。if文の( )については、crowbarの最初のバージョンでは不要にしたものの、自分自身間違えてばかりだったので結局戻しました。Cに慣れたプログラマ(私)にとって、Cに近いということはそれなりにメリットがあるだろう、と考えたわけですが、まあ、samplanは、実用的に使おうなどという人が現れるはずもないので好き勝手してもいいかな、と。

実質3人日程度で作った簡易言語なので、配列もありません。作っておいて言うのも何ですが、まあ現状では実用性はありません。でもその分処理系は小さいので、プログラミング言語の作り方を知りたい、という人が眺めるにはよいのではないでしょうか。

実装について

samplanは、レキシカルアナライザやパーサのジェネレータ(Cならlex/yaccJavaならJavaCCとか)を一切使わず、手書きのレキシカルアナライザと、1トークン先読みの再帰下降パーサで構文解析を行っています。

上記のcrowbarやDiksamではlex(flex)とyacc(bison)を使いましたが、構文解析周りは、知らない人からすれば、黒魔術に見えるほど難しい作業に見えると思います。その黒魔術部分を、ブラックボックスのパーサジェネレータに頼ったのでは、魔術を解明したという面白みに欠けるでしょう。再帰下降パーサでプログラミング言語を作る、というのは、私が表に発表したものでいうと、11年以上前に日経ソフトウエアの特集記事に載せていただいたスクリプト言語MILがそれにあたります。

kmaebashi.hatenablog.comただ、MILは、全ソースコードを紙面に乗せようとしたためソースの行数に制約があり、いろいろ試した結果、「解析木を作らずに直接VMのコードを吐く」という形になりました。解析木を作るとなると解析木のための型定義が必要で、VM用のバイトコードを吐かない解析木実行タイプの言語にしたとしても、型定義の分だけで長くなってしまうようです。この時は、解析木を作るものも含め何パターンか実際に処理系を作ってみて、一番処理系のソースが短いものとしてこれを選んだ記憶があります。関数定義も(行数の都合で)入れられなくて、代わりにgosubを付けていますね。

行数が少ない方が読者にはとっつきがよいでしょうし、挫折する人も減るかもしれませんが、「解析木を作らずに直接VMのコードを吐く」言語は、入門書ならともかく、実際にはあまりないでしょう。言語の作り方を学ぶなら、解析木を作るところもやっておきたいところです。また、crowbarや昔のRubyのような「解析木を辿りながら実行する言語」は、最初のうちは確かに楽に作れるのですが、breakやcontinueや中途returnを入れたり、(Cで作るなら)GCのことまで考えると、結構面倒くさくなります。それなら、最初からVMを作った方が手っ取り早いと思います。

そんなわけで、samplanは、コンパイラが生成したバイトコード*2をSamplan Virtual Machine(SVM)が実行するタイプの言語としました。上であげたDiksamもバイトコード実行タイプの言語なので、samplanのコンパイラ構文解析から先はDiksamをJavaに移植したようなものですし、SVMの命令セットはほぼDVM(Diksam Virtual Machine)のサブセットです。samplanのソースを読んでみようという人は、上記「プログラミング言語を作る」のDiksamの解説が役に立つかと思います。

作ってみて

この1週間ばかり、寝食を忘れて、というほどではないですが、帰宅したらそそくさとPCの電源を入れてコードを書く、という生活でした。こういうのは久しぶりです。洗濯機を回したら即コード書きに戻って、気づいたら洗剤入れるの忘れてた、とかね。

俺もまだこんな風にコード書きに熱中できるんだなあ、という感慨はありますが、それが、何度も書いたことがあり過去コードを貼り合わせたような言語処理系、というのはちょっと残念ですね。もちろん過去何度も書いたようなコードでも新しい発見はあるものですが、次は何か、新しいものを作ってみよう……

それはそれとして

ちょっと前ですが、「完全初心者のためのプログラミング入門」にも新章追加してます。こちらもよろしくお願いします。

kmaebashi.com

広告

宣伝しても、今となっては中古本しか手に入らないでしょうから、私の稼ぎにはなりませんが…… (Kindle化って重要)

*1:Cとかにはelse if~という構文がある、と思っている人は割と見かけますが、あれは単に{}を省略したelse節に次のif文がぶらさがっているだけです。

*2:型はintなので「バイト」コードではないですが

Windows8.1時代のLet's Noteを初期化してWindows10に上げた

2015年から使っているLet's Note CF-SX4Windows Updateが勝手に当たって、それはよいのだが音が出なくなってしまったので復旧した、という話。
まあ、リカバリ領域を使って初期化しただけなんですが、Windows8.1時代に購入して無償アップグレードでWindows10に上げたものなので、リカバリするとどこに戻るのか、Windows10に再アップグレードは可能なのか、といった話を書き留めておく。やる前に調べたんですが、自分でやったという人は見つからなくて、こういう情報でもネットに上げておけば助かる人はいるかもと(ただし、誰もが同じ結果になるとは限らないので、真似する人は自己責任でお願いします)。

症状

気づいたのは2021/06/12。おそらくはその数日前のWindows Updateが悪かったと思うんですが、私の普段使いのPC、Let's Note CF-SX4から音が出なくなりました。Windowsの復元ポイントは一つもなくて復元できず。タスクバーのスピーカーアイコンのところに斜線が入っていて、クリックするとトラブルシューティングが走るが原因が特定できませんでしたとか言われて回復せず。PanasonicのサイトからWindows8.1用のサウンドドライバをダウンロードしてインストールしたが回復せず、Windows10用のドライバにはサウンドドライバっぽいものはなかったが、汎用のものに含まれてないかな、とめぼしいものを入れたが回復せず。

必要なものはバックアップしてリカバリ領域使って初期化すれば直るんでしょうが、このPCはもともとはWindows8.1で、無償アップグレードでWindows10に上げたものなので、初期化後、ちゃんとWindows10にできるかどうか確信が持てなくてずるずる延ばしていたところ、意を決して8/8頃にリカバリ実施。

結果から言えば、リカバリしたら8.1に戻ったけれども再度Windows10に上げることは可能でした。

やったこと

スクショとか残してないですが。

  1. BIOS画面からリカバリパーティションを選んでリカバリ実施。Windows8.1に戻った。
    参考サイト

    https://www.monodeasobu.com/entry/2021/01/03/143737

  2. Microsoftアカウントと紐づいたアカウントでログイン(これが必要かどうかは不明)
  3. Windows10のダウンロードサイトからUpdate Assistantをダウンロードして実行。

    https://www.microsoft.com/ja-jp/software-download/windows10

これで、実施時点の最新のWindows10に更新できました。

誰かの参考になりましたら。

JavaScriptってJavaにそっくりだよね

JavaScriptJavaは、違う言語である。それは間違いない。

しかし、「JavaScriptはもともとLiveScriptという名前だったのが、マーケティングの都合だけでJavaScriptに改名されたんです! その名前以外、Javaとは共通点は一つもありません!! JavaJavaScriptはメロンとメロンパンくらい違う!!!」と言われると、それはそれでちょっとおかしいだろう、と思う。「JavaJavaScriptはメロンとメロンパンくらい違う!!!」のところは、インドとインドネシアとか、すっかり大喜利状態になっているけれど、そんなふうに「まったく違う言語」と言い切るには、JavaScriptJavaにあまりにも似すぎている。

gist.github.com

togetter.comこれは、「どちらもC言語を先祖としているから……」といったレベルの話ではない。

web.archive.org

JavaがCに類似する構文を持っているのと同程度に、JavaScriptJavaの構文は似ています。しかし、JavaがCのサブセットではないように、JavaScriptJavaのサブセットではないのです。

Cが先祖である、程度の理由で、文字列のメソッドのstartsWith()とかcharAt()とかlength()とか、そんなことまで一致するはずがない。JavaScriptはあからさまにJavaに似せて作られている。

JavaScriptはもともとLiveScriptという名前でー! マーケティングの都合で―!!」と言いたがる人たちは、LiveScriptなる言語がいったいいつから存在したと思っているのだろう? LiveScriptは、そのさらに前にはMochaと呼ばれていて、Mochaが作られたのはJavaの登場より後だ。Mochaがコーヒーの名前であるあたり、明らかにJavaを意識している。このあたりの話は、JavaScriptの作者であるブレンダンアイク自身が、以下のように語っている(JavaScript Ten Years)。

Javaは、高価なコンポーネントウィジェットのためであるのに対し、Mochaは、Webデザイナー向けの言語である、と言っているわけで、JavaScriptは「Javaスクリプト言語版」であるという、メロンとメロンパンの人たちが否定する位置づけは、それなりには根拠があるように思える。何しろ、JavaScriptは、JavaのDateクラスの2000年問題のバグまでそっくり似せて作られている*1

f:id:kmaebashi:20210704234454p:plain

確かに、JavaScriptは、関数がファーストクラスオブジェクトであったりレキシカルクロージャがあったりと、プログラミング言語の進化の系統樹からすれば、C→C++Javaという系統よりも、Lispから取り入れたものが多い言語だとは思う(あとは、プロトタイプオブジェクト指向言語として、SELFとか)。しかし、それにしても、これほどあからさまに「似せて作られた」ことを無視して「メロンとメロンパン」とか「インドとインドネシア」とか言い募るのは、あまり誠実な態度とは言えないんじゃないですかね。

参考ページ:

https://www.markupdancing.net/archive/20081111-083300.html

 

――というようなことも、「完全初心者のためのプログラミング入門」には書いておりますよ! という宣伝でした。

kmaebashi.com

はじめに――完全初心者のためのプログラミング入門

*1:2021年現在、getYear()が121を返すことだと思われる。

プログラミングを始める前の予備知識って結構多いな、という話

しつこく、「完全初心者のためのプログラミング入門」の話。

完全初心者のためのプログラミング入門

http://kmaebashi.com/programmer/beginner/index.html

だいぶ前ですが、以下のようなツイートをしたことがあります。

で、実際、「完全初心者のためのプログラミング入門」には「ファイルとフォルダ」の項を入れました。

ファイルとフォルダ――完全初心者のためのプログラミング入門

Windowsを毎日使ってWebを見ていたとしても、ファイルやフォルダのことは知らない、エクスプローラーなど起動したこともない、という人は多そうですし、仕事でWordなりExcelなりを使っているからファイルやフォルダのことなんか当然知っている、という人でも、拡張子をデフォルトのまま非表示にしていて思った通りのファイルを作れなかった、というケースがありました。だったらやっぱりここから説明が必要です。いくらなんでもこんなことは知ってるよ、という人は読み飛ばしてもらえばよいとして。

まあ、これくらいのことは最初から覚悟していたのです。でも、いざ書き始めて、BMI計算プログラムを作ったところで、「あ、ここで身長体重に全角文字を入力してしまってはまる人もいるだろうなあ」と思って『「文字コード」とは何か?』を書き始めたりしてまあ時間がかかることかかること。

「文字コード」とは何か?――完全初心者のためのプログラミング入門

文字コードとは何か、を説明するにしても、いまどきJIS X 0201(半角カナ)とかJIS X 0208(シフトJISとかEUCとかの文字セット)とかはいらんのではないか、いきなりUnicodeUTF-8でよいのではないか、とは思いましたが、発端が「身長体重に全角文字を入力してしまってはまる」ことを想定しているわけで、そもそもパソコンを使い始めてからずっとプロポーショナルフォントを見てきた人にしてみれば、これぐらい歴史を追わないと全角・半角の区別などというものがなぜあるのかわからないでしょう。

コンピュータを使う限り、当然、ビットとかバイトの理解も必要ですし(これがわからないと文字コードエンコーディングの概念もわかりませんし)、

ビット、バイト、2進数、16進数――完全初心者のためのプログラミング入門

いろいろ書いているうちに書き手の私がどうしても「処理系」という言葉を使いたくなるわけですが、そうなるとコンパイラとかインタプリタの話題も必要です。

コンパイラとインタプリタ――完全初心者のためのプログラミング入門

本編の、「UFOゲームを作ってみよう」という話題を書き始める前に、この辺でずいぶん時間を取られてしまいました。

それにしても、我々プログラマは、みんな最低限の知識としてこれぐらいのことは身につけているわけです。そりゃまあどんな仕事でもこの程度のことは覚えなければいけないのかもしれませんけれど、プログラマというお仕事も、結構な専門知識が必要であるようです。それこそ「底辺」と呼ばれるような仕事であっても。

自分の仕事に誇りをもって、「給料増やせ!」と叫ぶべきですね。

「完全初心者のためのプログラミング入門」に改題しました

先週公開した「本当の初心者のためのプログラミング入門」ですが、公開後にぐぐってみたら、同名の書籍がKindleにあることがわかりました。向こうが先なので、「完全初心者のためのプログラミング入門」に改題します。

完全初心者のためのプログラミング入門

確かに、かぶっても不思議ではないタイトルでした。事前に確認しておくべきでしたね……

 

「本当の初心者のためのプログラミング入門」始めました

タイトルからして無謀ですが、「本当の初心者のためのプログラミング入門」というのを始めました(始めました、と言いつつ、続くかどうかは評判次第ですが)。

kmaebashi.com

この入門では、JavaScriptを使って、以下のような「UFOゲーム」を作ります。

下にある「キャノン砲」で、飛び回るUFOを撃墜するゲームです。

UFOは1機しかいないし、UFOは撃ってこないし、キャノン砲が発射するビームも画面上には1発しか存在しません(ビームが消えるまで、次のビームが撃てない。昔のスペースインベーダーギャラクシアンはこうだった)。しょぼいゲームですが、最初の一歩はこれでよいかな、と思っています。

実のところこのUFOゲームは、かつて「マイコンBASICマガジン」、略して「ベーマガ」の1982年8月号に載っていた「UFOゲームを作ってみよう」へのオマージュです。ベーマガのUFOゲームは、BASICで作られていて、「AAA」のUFOを「I」のビームで撃墜するようなゲームでした。ゲームとして遊ぶに足るものかどうかはともかく、当時のBASICゲームの作り方を学ぶにはとても参考になりました。当時の私は中1でしたが、それでも十分読みこなせる記事でした。

それに比べ、現在のプログラミング初心者は、どのようにプログラミングを学び始めればよいのでしょうか。スイッチONでBASICが動いた80年代のパソコンと違い、まず開発環境のインストールが必要ですし、Webアプリでも作ろうとするならHTMLとCSSとサーバ側言語とJavaScriptSQLが必要です。とても初心者の手に負えるとは思えません。

JavaScriptでUFOゲームを作るなら、HTMLとJavaScriptさえ覚えれば、あとはメモ帳1本で可能です(あ、絵を描くのにペイントも要るか)。最初は、正体不明のファイルを山ほど自動生成する統合開発環境を使うより、メモ帳なりのテキストエディタガリガリ書いていく方が、自分がやっていることがすべて理解できて勉強になると思います。

――とはいえ、最初の言語にJavaScriptが適切か、ということに関してはずっと思うところがあって。

 とはいえ、Windowsを買ってきたら環境構築なしでいきなり使えて、UFOゲームのようなゲームも作れて、世間に情報が多い言語というとやはりJavaScriptくらいしかないでしょう*1

というわけで書き始めてみると、これが大変で大変で、「本当の初心者」を対象にするのなら「ファイルとフォルダ」の概念くらいは書かなければいけないだろう、とは最初から思っていましたが、書き始めてみるとあれもこれもと書かなければいけないことが増えていって、ずいぶん時間がかかってしまいました(書き始めたの、いつだったっけ?)。

今回公開分で、ひとまずUFOゲームは最後まで作っています。最終的には、これくらいのシューティングゲームくらいまで持っていきたいと思っていますが、さて、どうなりますことやら。

※このシューティングゲームは、以下のリンクから遊べます。

http://kmaebashi.com/programmer/beginner/shooting03/shootinggame.html

 

*1:実のところ私はこの目的で1個言語を作ったりもしたのですが、個人開発の、ライブラリも揃わない、情報もない、バグもありそうな言語に初心者を巻き込めないよね。

ロードバイクは結局時速何kmぐらいで走れるのか

結論から先に書く。信号待ちの時間を含めた、実効速度というか、「1時間で何km先まで行けるか?」という速度で言えば、私の場合、時速15kmくらいだ。

まあ、私は40代も半ばを過ぎてからスポーツバイクに乗り始めたおっさんなので、決して速くはない。他のロードバイクにはしょっちゅう抜かれる。でもまあ、ママチャリやなんちゃってクロスバイクなら、街中ではだいたい100%抜いている(山道で、競争している男子高校生をゴボウ抜きにしたこともある)。ちなみに、鈴鹿の8時間エンデューロでは、私はママチャリに抜かれたことがある。ああいうところでは、ガチで走れる人がふざけてママチャリで出走したりするので(コスプレしている人もいる)、そういう人には抜かれる。ぶっちゃけママチャリだって速い人は速いわけで、ロードに乗れば誰でも速く走れるわけではないし、速い人だって、信号のある公道では、時速20kmを出すのは難しいと思う。

そして1時間後、あなたは何km移動しているでしょうか。15km先でしょうか。20kmだったら、相当の健脚か、コースや風向きに恵まれたのかもしれません。

――「自転車で100kmをラクに走る」p.84

ロードバイクに乗っている人の中には、巡航速度30km/hとか40km/hとか50km/hとか、好き勝手なことを言っている人がいるけれど、実際問題そんなスピードでは走れない。瞬間最大なら平地無風で40kmくらいはいけるかもしれないけれど(私にはちと難しい)、そのスピードでそうそう走り続けられるものではない。自転車競技で「アワーレコード」というものがあって、これは「1時間ひたすら漕いで何km走れるか」を競う競技なので走った距離がそのまま平均時速になる。これの世界記録が55kmくらいらしい。もっともこれは2014年のルール改定以後空力のよいあれこれが使えるようになった後の記録で、2000年のルール改定でエアロフレームが禁止されてから2014年の再改定までは、世界記録保持者でも1時間で50kmは走れなかった。

www.cyclowired.jp自転車の速度を、

  1. 瞬間最大で出せる速度
  2. 信号待ちのように完全に止まった時間を除いた、走っている時間の平均速度(サイクルコンピュータが表示する平均速度がこれ)
  3. 信号待ちを含め、実際に1時間で何km走れるかという速度

に分類したとすると、私の場合は、2.が20km/hくらい、3.が前述の通り15km/hくらいだ。1.は難しくて、当たり前だが下り坂や追い風なら早く走れる。本来なら無風で平坦な道で考えるべきなのだろうが、日本の公道で、延々と続く真っ平な道路などそうそうないし、完全な無風状態が続くこともない。体感的には、普通に走っていて、信号待ちから加速して35km/hくらいにはなるけれど、それでちょっと走ったら次の信号でまた止まる、というくらいか。これで「巡航速度35km/h」くらいと言ってはいけないと思う。その速度で走り続けたわけではないからだ。

ロードバイクは、なんかこうめちゃくちゃ速く走れるというイメージを持っている人が多いようなので、(私にとっての)実態を書いてみた。もちろん速い人は私よりずっと速い。鈴鹿サーキット1周6km弱、私はどうやっても10分はかかるが(かつて1回だけ9分56秒くらいで走ったことはあるが)、速い人は7分くらいで走るらしい。えっちらおっちら走っていて先頭集団に抜かれるときは「すげー」と思う。でも、信号のある公道での実際の速度となると話は別だろう。

これを読んでいる人の中には、ロードバイクを始めてみようと思って、実際どれぐらいのスピードで走れるのだろうと検索して辿り着いた人もいるかもしれない。夢を壊して申し訳ない。まあでも、この程度のスピードでも、1日で100kmとか150kmとか走れるようには割とすぐになるし、名古屋から150km走れば京都まで行ける(新幹線なら35分、とか、そういうことはいったん忘れろ)。遅くても、ペダルを踏めば、必ず前に進むのが自転車だ。楽しいですよ。遅くても。

card-media.money.rakuten.co.jp

ちなみに、しっかり漕いで、道が平坦で迷わない場合だったら、「1キロ移動するのに3分」が街中の自転車移動の目安だと思ってください。

ロードですらないミニベロやママチャリで、簡単に平均時速20kmで走れるようなことが書いてあるWeb記事や本は、一切信じるな

dailyportalz.jp

Googleのナビだと自転車で平均時速15kmで時間を出すようだけど、私がロードでそれくらいなので、普段距離を乗っていない人がそれを真に受けるのは危険だ。私もクロスバイクに乗り始めた最初のうちは、平均時速10km/hくらいで見積もっていた。

そういえば、スポーツバイクに乗るようになるはるか前、2005年にママチャリ買って購入2日後に長島温泉(片道30km)に行ったのだけど、この時の平均速度も10km/hくらいだったようだ。その後クロスバイクでも行ったけど、所要時間に特に差はなかったな。