Writing An Interpreter In Go その1
その0はこちら。
1.3: Lexer(字句解析器)の実装
1.3: Implement lexer · nibral/monkey_interpreter@66eb6e3 · GitHub
lexer/lexer.go
ソースコードを文字列として受け取って、一文字ずつ読み進めながらトークンの配列に変換する処理を作成。
1文字の識別子だったらそのままトークンとして追加、複数文字の場合はそれが単語なのか数値なのかを判定して対応するトークンを追加していく。範囲を指定して配列の一部を取り出せるgolang最高じゃんという気持ちになった。
func (l *Lexer) readNumber() string { position := l.position for isDigit(l.ch) { l.readChar() } return l.input[position:l.position] <-便利 }
文字種の判定 (isLetter, isDigit) と空白文字読み捨ての処理 (skipWhitespace) もシンプルで、これで十分なんだと安心。
あと、本に書かれているLexerの処理結果がわかりやすかった。
let x = 5 + 5; ↓ [ LET, IDENTIFIER("x"), EQUAL_SIGN, INTEGER(5), PLUS_SIGN, INTEGER(5), SEMICOLON ]
lexer/lexer_test.go
Lexerのテストコードを作成。
満たすべき条件を配列として用意しておいて、ループでチェックする。「テーブルドリブンテスト」といってgolangでは標準的な書き方らしい。
本の内容とは関係ないけど、golangは標準でフォーマットとテストの仕組みがあるのがいいなと思ったり。たとえばJavaScriptだとESLint入れてルール設定したりmocha入れたりで面倒なので…
token/token.go
トークンの構造と種類を定義した。
1文字の識別子 (=, +, etc.) をそのまま扱うのはいいとして、複数文字の場合は事前に定義したテーブルに存在するかチェックして、存在すれば予約語、しなければユーザが定義した識別子として扱うところがなるほどねという感じ。予約語を増やしたければここに追加していけばいいんだなというのがすぐわかる。
1.4: 1文字識別子とキーワードの追加
1.4: Add single character tokens and keywords · nibral/monkey_interpreter@cf28a6d · GitHub
lexer/lexer.go
1文字の識別子に -, !, *, /, <, >, カンマ を追加。caseを増やすだけなのですぐできる。
lexer/lexer_test.go
新たに処理できるようになった識別子のテストコードを追加。
機能が増えるにしたがってテスト内容のテーブルがどんどん長くなるけどこれでいいんだろうか。適当なところで分割とかするべきなのか。
token/token.go
トークンの種類と予約語を追加。* と / を MULTIPLE, DIVIDE ではなく ASTERISK, SLASH にするのはほかの用途でも使うから?
if/else や return を追加したが、現時点ではトークンとして認識できるというだけで制御構文としての意味は一切処理されていない。
Writing An Interpreter In Go その0
コンパイラの勉強がしたくなったので、Thorsten Ballの"Writing An Interpreter In Go"を読むことにした。オライリーから「Go言語でつくるインタプリタ」として日本語版の書籍も出ているが、著者のサイトから続編にあたる"Writing A Compiler In Go"とセットで買うとちょっと安くなるのでいい機会だと思って英語版を入手。Interpreterを読み終わったらCompilerも読む予定。
なぜコンパイラか
足掛け10年ほどコードを書いているが、自分の書いたコードがどうやってバイナリになって実行されているのかの知識が欠落しているという自覚があったため。学生の頃に近しい内容の講義を取ったような記憶もあるが、試験終了と共にさっぱり忘れてしまった。
最初は、Rui Ueyama氏のWeb本(低レイヤを知りたい人のための Cコンパイラ作成入門)とGitHubを参考にCコンパイラを書いていた。ただ、最近C言語書いてなくてコーディング速度が上がらないし、メモリを手動確保する関係で油断するとSEGVするしでだんだんつらくなってきて、結局四則演算ができたところで断念した。最後までやりきれば相当力がつくと思うが…
後輩氏とラーメン屋に向かう車中で冬休みの宿題が欲しいという話になり、ここを見ながらCのコンパイラを書いてみようということになった https://t.co/GaKHqDE3nU
— あみだ (@_nibral) 2018年12月28日
C言語でコンパイラ写経するのつらくなってきた、油断するとすぐSegmentation faultする
— あみだ (@_nibral) 2019年1月4日
写経した9ccで四則演算と括弧の処理ができるところまで到達した。「a=3; b=4; c=8; return c * (a + b);」 という文字列を渡すと56を出力するバイナリができる。https://t.co/AdekyI1olL
— あみだ (@_nibral) 2019年1月4日
どんな本なのか
Writing A Compiler In Go | Thorsten Ball https://t.co/JghZ1G0r3p C言語のコンパイラをC言語で書くのはいまいちモチベ上がらないから、オリジナルの言語をGolangで書く本を買った
— あみだ (@_nibral) 2019年1月9日
Monkeyという架空の言語で書かれたソースコードを解析し、実行するインタプリタを作成する。架空の言語といっても、変数宣言や制御構文などプログラミング言語として一通りの機能は揃っている模様。
// Bind values to names with let-statements let version = 1; let name = "Monkey programming language"; let myArray = [1, 2, 3, 4, 5]; let coolBooleanLiteral = true; // Use expressions to produce values let awesomeValue = (10 / 2) * 5 + 30; let arrayWithValues = [1 + 1, 2 * 2, 3]; // Define a `fibonacci` function let fibonacci = fn(x) { if (x == 0) { 0 // Monkey supports implicit returning of values } else { if (x == 1) { return 1; // ... and explicit return statements } else { fibonacci(x - 1) + fibonacci(x - 2); // Recursion! Yay! } } }; https://interpreterbook.com/#the-monkey-programming-language より
モチベーション維持のために、その日取り組んだ内容のメモを書くことにする。書いたコードはGitHubに置く。
CircleCIでflutter testする
Qiitaからの移転記事です https://qiita.com/nibral/items/93e4052b41c2f477ae2a
ポイント
- CircleCIが用意しているAndroidのdockerイメージを使う
- ロケールが
C.UTF-8
になっていてflutter
コマンド実行時にエラーが出るのでen_US.UTF-8
にしておく
- ロケールが
設定例
version: 2 jobs: build: environment: - LANG: en_US.UTF-8 docker: - image: circleci/android:api-27-alpha steps: - checkout - run: name: Install Flutter SDK command: git clone -b beta https://github.com/flutter/flutter.git ~/flutter - run: name: run tests command: ~/flutter/bin/flutter test
Arch LinuxにChrome Remote Desktopをインストールする
Qiitaからの移転記事です https://qiita.com/nibral/items/ee82e244117f487a1032
Arch LinuxにChrome Remote Desktopを入れたときのメモ。
環境
- デスクトップ環境はMATE、日本語入力はfcitx-mozc
- Google Chromeインストール済(
yaourt -S google-chrome
)
Chrome Remote Desktopのインストール
AURのパッケージをインストール
$ yaourt -S chrome-remote-desktop
初期設定
$ crd --setup
- 作業中のユーザがchrome-remote-desktopグループに追加される
- セッションの設定と画面解像度の設定で都合2回nanoが立ち上がるので、必要な編集をしたあと
Ctrl+X
→Y
で保存する。- セッションの設定では
# exec mate-session
の#
を消す。 - 解像度の設定では好みの解像度を入力する。(コメントは書けないらしい)
- セッションの設定では
Chrome Remote Desktopの有効化
Chromeウェブストアから「Chromeリモートデスクトップ」をインストールし、設定画面を開いて「リモート接続を有効にする」をクリック。PINを設定する。
セッション設定の追加
この段階でリモート接続してみると、Failed to connect to socket /tmp/dbus-**********: Connection refused
というエラーが出て画面が表示されない。MATEがdbusを認識できないのが原因なので、セッションの設定を追加する必要がある。ついでに日本語入力も使えるようにする。
$ vim ~/.chrome-remote-desktop-session
# You will have to... # Remove... # eval $(dbus-launch --sh-syntax) ←ここから export GTK_IM_MODULE=fcitx export QT_IM_MODULE=fcitx export XMODIFIERS="@im=fcitx" ←ここまで追記 exec mate-session
サービス有効化&起動
systemdのサービスを有効化して起動する。
$ systemctl --user enable chrome-remote-desktop $ systemctl --user start chrome-remote-desktop
ユーザがログアウトした状態でもサービスを起動したままにするため、lingerを設定。
$ loginctl enable-linger <ユーザ名>
動作確認
別のマシンにもChromeウェブストアからChromeリモートデスクトップをインストールして、設定したマシンに接続してみる。サーバ側のサービス起動直後は「サーバが応答しない」というエラーが出ることがあるので、1分ほど待ってから接続先マシンのリストを更新するといいかもしれない。
あと、VirtualBox上のマシンにChrome Remote Desktopをインストールした場合で、マウスカーソルが出ない時はVirtualBoxのマウス統合をオフにする。
参考
Amazon LightSailでお手軽にNode.jsを走らせてみた
Qiitaからの移転記事です https://qiita.com/drafts/6165498aa451bb8dc6a9/edit
はじめに
AWS re:Invent 2016でAmazon LightSailが発表された。 $5/monthからVPSが使えるとのことで、早速インスタンスを立ててNode.jsでHello,worldしてみた記録。
Let's get started
マネジメントコンソールを開き、サービスからLightsailをクリック
新キャラ登場。Let's get startedをクリックすると、そのままLightsailインスタンスの新規作成画面が開く。
イメージ選択
まずは作成するインスタンスのイメージ選択。各種アプリケーションがインストール済みの「Apps + OS」とOSのみの「Base OS」がある。WordPressやLAMPスタックといったWeb環境から、GitLabやRedmineなどの管理系も用意されている。デフォルトではWordPressが選択されているが、今回はNode.jsでやってみる。
ちなみに、公式ブログ(Amazon Lightsail – AWSの力、VPSの簡単さ)には
好きなオペレーティングシステム(Amazon Linux AMI,Ubuntu,CentOS,FreeBSD,Debian)、開発環境(LAMP, LEMP, MEAN,Node.js)やアプリケーション(Drupal,Joomla,Redmine,GitLabなど)を立ち上げることができます。
とあるが、現時点ではBase OSを選ぶとAmazon LinuxかUbuntuしか選べない。慣れの問題があるので、Cent OSが使えるようになるとうれしいところ。
料金プラン
続いて料金プランの選択。スペック的には安い方からt2.nano、t2.micro、small、medium、largeといった感じ。$5/monthのプランは最初の一ヶ月(750時間)が無料になるので、とりあえず使い勝手を試すならこのプランでいいと思う。 リージョンはいまのところバージニア(us-east-1)しかないのでそのまま。
インスタンス作成
最後にインスタンスの名前と数量を選ぶ。デフォルトで「<イメージ名>-<スペック>-<リージョン>」な感じの名前が入力されているので、そのままCreate。
リソース一覧画面
インスタンスの作成が始まると自動的に飛ばされる。インスタンスの管理や新しいインスタンスの追加はこの画面から行う。
インスタンスが動き出すと左下のステータスがPendingからRunningになって、アイコンに色がつく。Createを押してからRunningになるまでの時間は10秒くらい。
インスタンス詳細画面
リソース一覧でインスタンス名をクリックすると、インスタンスの詳細が出てくる。インスタンスの停止・再起動、ブラウザ経由のコンソールなどVPSによくある機能は一通り揃っている感じ。この時点でグローバルIPが割り当てられているので、インターネットからアクセスできる。
ファイヤウォールはデフォルトでSSH(22)・HTTP(80)・HTTPS(443)が開いていた。この後Node.jsを動かすので、追加で3000番も開けておく。
ブラウザコンソール
インスタンス詳細画面の「Connect using SSH」というオレンジのボタンを押すと、別ウィンドウでコンソールが開く。
Node.jsのイメージではUbuntu 14.04.5 LTSが使われていた。基本的にAmazon Linuxだと思っていたのでちょっと意外。あと、OSのタイムゾーンがGMTになっているのでログとか漁るときは意識したほうがいいかもしれない。
太平洋の反対側なのでラグはそれなりにあるが、いきなり反応しなくなってコマンド入力にストレスが溜まるといったことはなかった。ログインしているユーザでsudo
も使える。ただ、コンソールの文字が妙に大きく、しかもブラウザの縮小表示が効かないのでちょっとしたメンテナンス以上のことをやるならSSHクライアントを使ったほうが良い。
Hello, LightSail
あとはサーバを書いて、node hello.js
で動かす。
const http = require('http'); http.createServer((req, res) => { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('hello, lightsail\n'); }).listen(3000); console.log('Server running at http://localhost:3000/'); ```` ブラウザで`http://<インスタンスのグローバルIP>:3000`を開くと、ちゃんと見える。 ![スクリーンショット 2016-12-01 9.54.19.png](https://qiita-image-store.s3.amazonaws.com/0/116906/575f31d2-2407-c7a9-fcba-927d1409a82b.png) まとめ ---- * EC2だと、ちょっとした環境立てるだけでもインスタンス立てて、Elastic IP貼って、セキュリティグループ設定して…という感じでやることが多い * 売り文句通り、LightSailはそのあたりの細かいことを自動でいい感じにやってくれる * 開発とかお遊びでちょっとインターネットから見えるサーバが欲しいときにはいいのではないか(もちろんセキュリティの設定は必要だけど) * ap-northeast-1にも来て欲しい * (2017/5/31追記)[東京リージョンでもLightsailが使えるようになりました](https://aws.amazon.com/jp/blogs/news/amazon-lightsail-tokyo-region-launch/)
Amazon LightSailでお手軽にNode.jsを走らせてみた
Qiitaからの移転記事です https://qiita.com/drafts/6165498aa451bb8dc6a9
はじめに
AWS re:Invent 2016でAmazon LightSailが発表された。 $5/monthからVPSが使えるとのことで、早速インスタンスを立ててNode.jsでHello,worldしてみた記録。
Let's get started
マネジメントコンソールを開き、サービスからLightsailをクリック
新キャラ登場。Let's get startedをクリックすると、そのままLightsailインスタンスの新規作成画面が開く。
イメージ選択
まずは作成するインスタンスのイメージ選択。各種アプリケーションがインストール済みの「Apps + OS」とOSのみの「Base OS」がある。WordPressやLAMPスタックといったWeb環境から、GitLabやRedmineなどの管理系も用意されている。デフォルトではWordPressが選択されているが、今回はNode.jsでやってみる。
ちなみに、公式ブログ(Amazon Lightsail – AWSの力、VPSの簡単さ)には
好きなオペレーティングシステム(Amazon Linux AMI,Ubuntu,CentOS,FreeBSD,Debian)、開発環境(LAMP, LEMP, MEAN,Node.js)やアプリケーション(Drupal,Joomla,Redmine,GitLabなど)を立ち上げることができます。
とあるが、現時点ではBase OSを選ぶとAmazon LinuxかUbuntuしか選べない。慣れの問題があるので、Cent OSが使えるようになるとうれしいところ。
料金プラン
続いて料金プランの選択。スペック的には安い方からt2.nano、t2.micro、small、medium、largeといった感じ。$5/monthのプランは最初の一ヶ月(750時間)が無料になるので、とりあえず使い勝手を試すならこのプランでいいと思う。 リージョンはいまのところバージニア(us-east-1)しかないのでそのまま。
インスタンス作成
最後にインスタンスの名前と数量を選ぶ。デフォルトで「<イメージ名>-<スペック>-<リージョン>」な感じの名前が入力されているので、そのままCreate。
リソース一覧画面
インスタンスの作成が始まると自動的に飛ばされる。インスタンスの管理や新しいインスタンスの追加はこの画面から行う。
インスタンスが動き出すと左下のステータスがPendingからRunningになって、アイコンに色がつく。Createを押してからRunningになるまでの時間は10秒くらい。
インスタンス詳細画面
リソース一覧でインスタンス名をクリックすると、インスタンスの詳細が出てくる。インスタンスの停止・再起動、ブラウザ経由のコンソールなどVPSによくある機能は一通り揃っている感じ。この時点でグローバルIPが割り当てられているので、インターネットからアクセスできる。
ファイヤウォールはデフォルトでSSH(22)・HTTP(80)・HTTPS(443)が開いていた。この後Node.jsを動かすので、追加で3000番も開けておく。
ブラウザコンソール
インスタンス詳細画面の「Connect using SSH」というオレンジのボタンを押すと、別ウィンドウでコンソールが開く。
Node.jsのイメージではUbuntu 14.04.5 LTSが使われていた。基本的にAmazon Linuxだと思っていたのでちょっと意外。あと、OSのタイムゾーンがGMTになっているのでログとか漁るときは意識したほうがいいかもしれない。
太平洋の反対側なのでラグはそれなりにあるが、いきなり反応しなくなってコマンド入力にストレスが溜まるといったことはなかった。ログインしているユーザでsudo
も使える。ただ、コンソールの文字が妙に大きく、しかもブラウザの縮小表示が効かないのでちょっとしたメンテナンス以上のことをやるならSSHクライアントを使ったほうが良い。
Hello, LightSail
あとはサーバを書いて、node hello.js
で動かす。
const http = require('http'); http.createServer((req, res) => { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('hello, lightsail\n'); }).listen(3000); console.log('Server running at http://localhost:3000/'); ```` ブラウザで`http://<インスタンスのグローバルIP>:3000`を開くと、ちゃんと見える。 ![スクリーンショット 2016-12-01 9.54.19.png](https://qiita-image-store.s3.amazonaws.com/0/116906/575f31d2-2407-c7a9-fcba-927d1409a82b.png) まとめ ---- * EC2だと、ちょっとした環境立てるだけでもインスタンス立てて、Elastic IP貼って、セキュリティグループ設定して…という感じでやることが多い * 売り文句通り、LightSailはそのあたりの細かいことを自動でいい感じにやってくれる * 開発とかお遊びでちょっとインターネットから見えるサーバが欲しいときにはいいのではないか(もちろんセキュリティの設定は必要だけど) * ap-northeast-1にも来て欲しい * (2017/5/31追記)[東京リージョンでもLightsailが使えるようになりました](https://aws.amazon.com/jp/blogs/news/amazon-lightsail-tokyo-region-launch/)
CentOS 7にMaria DBとPHP 7.0を入れる
Qiitaからの移転記事です https://qiita.com/nibral/items/b3bd01672bcbfe80054f
環境
- CentOS 7
MariaDB
[mariadb] name = MariaDB baseurl = http://yum.mariadb.org/10.1/centos7-amd64 gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB gpgcheck=1
インストール
$ sudo yum install MariaDB-server MariaDB-client
サービスを有効化&起動
$ sudo systemctl enable mariadb $ sudo systemctl start mariadb
最小構成の設定ファイルをコピーして、文字コードを設定
$ sudo cp -p /usr/share/mysql/my-small.cnf /etc/my.cnf.d/server.cnf
[client] default-character-set = utf8 [mysqld] character-set-server = utf8
初期設定
$ sudo /usr/bin/mysql_secure_installation
PHP 7.0
$ sudo yum -y install epel-release
$ wget http://rpms.famillecollet.com/enterprise/remi-release-7.rpm $ sudo rpm -ivh ./remi-release-7.rpm
インストール
$ sudo yum install --enablerepo=remi,remi-php70 php php-devel php-mbstring php-pdo php-gd
MariaDBと接続するドライバのインストール
$ sudo yum install --enablerepo=remi,remi-php70 php-mysqlnd
ドライバを認識してるか確認
$ php -r "phpinfo();" | grep -i PDO /etc/php.d/20-pdo.ini, /etc/php.d/30-pdo_mysql.ini, /etc/php.d/30-pdo_sqlite.ini API Extensions => mysqli,pdo_mysql PDO PDO support => enabled PDO drivers => mysql, sqlite pdo_mysql PDO Driver for MySQL => enabled pdo_mysql.default_socket => /var/lib/mysql/mysql.sock => /var/lib/mysql/mysql.sock pdo_sqlite PDO Driver for SQLite 3.x => enabled