Docker Registry HTTP API v2でDockerイメージのダウンローダを作った話
久しぶりにtechな記事書きます.
コンテナ作るとき,OSのイメージの用意とかめんどうですよね.
僕はdebootstrapとかpacstrapとか使ってました.
でもroot権限が必要だったり,ダウンロードに時間がかかります.
そこでDocker Registry HTTP API v2を使ってみます.
HTTPでdocker pullみたいなことができるすごいやつ.
しかもOCIで標準化されるコンテナイメージの配布方法にはこれをベースにするらしい.
cromwellも内部はこれを採用しています.
今回はこの部分を取り出してCLIツールとして作って公開しました.
ほぼcromwellからの輸入なので開発時間は20分も無いですね.
今回作ったやつ github.com
Rustで開発してるのでcargoですぐにインストール可能です.
$ cargo install oci-fetcher
oci-fetcher + unshare + で非特権コンテナ!
alpineのイメージをとってきて雑に非特権コンテナを作ってみます.
$ oci-fetcher pull -n library/alpine -o alpine-test $ ls alpine-test/ bin cromwell dev etc home lib media mnt opt proc root run sbin srv sys tmp usr var
それっぽいディレクトリができてますね. あとはunshareしてchrootするだけで非特権コンテナっぽい何かができました
$ unshare --user --cgroup --mount --ipc --pid --net --uts -r --fork bash [root@archlinux ~]# chroot alpine-test /bin/sh / # id uid=0(root) gid=0(root) groups=65534(nobody),0(root),65534(nobody)
改善点
DockerHubにしか対応していないので,他のレジストリに対応していきたいですね.
第81回IPSJ全国大会参加レポ
3/14~3/16まで開催されたIPSJ全国大会に参加してきました。
私は「OS・クラウド」の学生セッションで発表させていただきました。
研究の概要
研究についてですが、コンテナランタイムの研究をしています。 今のテーマはVMMなしで、ホスト-コンテナ間、コンテナ間を分離して、 別のユーザのコンテナやホストにを保護する高レベルランタイムを開発することです。 (正直なところ、論文提出した1週間後にpodmanのv1.0.0がリリースされて焦りました)
研究システムの概要
一応システムもOSSとして公開しています。 cromwellはrust製のrootlessコンテナランタイムです。 いわゆるプロセス型のランタイムで、手法としてはpodmanに近いです。 詳しい記事は今週中に投稿したいですね。
OCI対応はまだまだ先なので、やっていきたいですね。 star, PR待ってます。
発表について
緊張してガタガタでした。 会場見渡して、論文で見たことある人や、インターンでお世話になった人、研究室の先輩がおられたので、 心臓バクバクでした。 やっぱり場数をもっと踏んでおきたいと思いましたね。 質疑は一応答えられたと思います。 ただ、冗長な答え方になってしまっていたので、明確に答えてから付け加えることがあれば、話せばいいかなという感じにしたいですね。
結果としては、学生奨励賞を頂きました。 10月ぐらいから時間を見つけて開発、研究してきたので、報われました。
IPSJ-ONE 感想
夕飯まで時間あるし、見ていこうかなぐらいに思ってたIPSJ-ONE、めっちゃ良かった(語彙不足)。 いろんな研究会の人が研究について紹介してくださったのですが、 他分野の人間にもすごくわかりやすくて、ワクワクする紹介でした。 ああいう発表ができるようになりたいなあと憧れますね。
ペパボ訪問
去年の春休みにインターンシップで参加させていただいた、GMOペパボ福岡支社にお邪魔させていただきました。 ペパボ研究所の方々と研究の話ができてよかったです。 また、コンテナランタイムのOCI対応に悩んでいたため、@udzuraさんとお話させていただきました。 低レベルランタイムか、高レベルランタイムのどちらに寄せていくかというヒントもいただきました。 また、他の高レベルランタイムの話(kata, firacracker, gVisor, podman)などの話もさせていただきました。 サーベイが深くまでできてないと感じているので、卒論や来年のIPSJに向けて、時間をかけてやっていきたい気持ちです。
後日、ペパ研の方々や、さくらインターネットの方々に、餃子の李へ連れて行っていただき、餃子をごちそうになりました! 今まで食べた中で一番美味しかったので、最高でした! ごちそうさまでした!!
最高か!? pic.twitter.com/ilBrRUSmB5
— ぐに (@guni1192) March 15, 2019
でかい!!! pic.twitter.com/1oICAvDyH5
— ぐに (@guni1192) March 15, 2019
後日談
発表後日、インターン先でお世話になった@udzuraさんや、@yuuk1tさんにTwitterで褒めて頂いてめっちゃ嬉しかったです。
今日、学生奨励賞を取った @guni1192 とコンテナランタイムとかOCIとかの話をしたけど、学生奨励賞を取ってるだけあってjailとかOpenVZとかも押さえつつpodmanなんかも触っていてすごい、やってるなと思った。
— Uchio KONDO 🔫 (@udzura) 2019年3月14日
昨日の学会発表で、コンテナエンジン自作している学生さんいていいじゃんと思ってたら @guni1192 さんだったことに今頃気づいた。学生奨励賞おめでとうございます。
— ゆううき (@yuuk1t) 2019年3月15日
余談ですが、御二人のツイートのおかげで、Twitterのフォロワーが50人以上増えました。
謝辞
最後に,論文の添削や発表資料の添削、技術的な相談に載ってくださった先輩方に圧倒的感謝です。
2018年振り返り
忘年会で忘れる前にログに残して置こうと思ったので久々のブログ更新
目次
学部3年への進級
学年も上がり,専門的なことを学べる機会が増えてきた気がします.
OOPLやLinuxを学ぶのはもうちょっと早くても良い気がするのですが,うちの大学の事情というものでしょう.
3年になってレポートが一気に増えた気がするので,時間の管理に気を使わなきゃと思いながらもう年末ですよ.
来年からは頑張りたいですね.
SLPの退部
SLP(Student Laboratory Programming)というサークルに属していたのですが,一身上の都合により辞めました.
10月ぐらいに退部届だしましたかね.
2年半ぐらいお世話になったので,メンバーの方々には感謝です.
辞めてから技術的な話ができる場所が減ってしまったので,どこかそういうコミュニティ属するのもありですかね.
TOKYOに住みたい…
slp-kbit | Student Laboratory of Programming
インターンシップへの参加
春休みと夏休みに1社ずつ,インターンシップに行かせていただきました.
参加エントリもかいたのでよければ見ていってください.
ペパボインターンの後にインフラやりたいってなりだしたんですよね.
はてなではAWSでコンテナ周りのこといっぱい触れたし,SREの人から多くの刺激を受けることができました.
そのおかげで,方向性や,今後やっていきたいことをちょっとずつ見えてきました.
初の学会発表
夏休みに,人生初の学会発表しました.
ネタは大したものじゃないんですけど.
研究には時間をかけたいと思いました.はい.
研究室への配属
後期になって研究室に配属しました.
研究分野は分散Webシステムとか,アクセス制御システムなどなど.
新規の研究もインフラ系のことならいろいろ持ち込みできそうな印象でした.
3月ぐらいに学会発表するので,そのネタで卒論するのも有りかなあなどと.
技術的な進捗とか
友人とWebサービス作ったり,研究室のシステム開発の舵を切ったりしてますかね.
インフラがしたいだけなのにバリバリ開発もやってます.
言語は共同開発にはGo,個人開発ではレイヤー低いところ触ったりするのでRustみたいな感じです.
最近C++を書くことが少なくなってきた気がします.
あと,コンテナエンジンっぽいものも作ってます.
衝動で書いたものが意外にハマったのでもっといろいろやっていきたいところです.
最近の興味はコンテナのOCIやCRIの実装です.
haconiwaとかcri-oとかOSSの実装読みながら自分で車輪の再開発みたいなことをしているのが現状ですかね.
また,オーケストレーションも勉強しながらぼちぼち運用してます.
GKE使いすぎて無料枠使い切っちゃいました.
マネージドでなくていいから安いk8sクラスタが欲しいなあなどと.
その他心境の変化
最近はレイヤー低いところも触るようになってきた感じです.
ネットワークとかに強い友人ができたりしたので,ネットワークの勉強もしたいなあというお気持ち.
あと,酒を飲みに行く悪友が増えたもので,1週間の酒の量が増えました.
おかげで,ビール1杯で酔っていた人間が,日本酒2合+ビール2杯ぐらい飲めるようになってしまいました.
また,進路を固めないといけない時期になってきました.
院に行くか,就職するか,インフラエンジニアやSREになるか,研究職につくかなどなど.
未だに進路をちゃんと決められていないので,割と進路困ってる感じですかね.
はてなインターンで最高の夏を過ごしていた話
えー、ブログのネタは鮮度が大事だそうです。
さて、今年の夏は株式会社はてなさんのサマーインターンに参加させていただきました。
2,3ヶ月前っすね。冷蔵庫開けて確認するのが怖くなるぐらいの時間経ってますね。
ごめんなさい。
期間は8/13~9/7の一ヶ月間。
場所は株式会社はてな本社(京都)。
選考
選考は以下の2段階からなります。
- 書類選考
- 面接
書類選考は自己アピール的なことと、GitHubのアカウント、rot13のPythonでの実装を書いて送りました。
面接は、東京にも京都にも気軽にいけるわけではないため、Hangoutでやっていただきました。
自己アピールにも書いてない成果物もGitHubから探し出して聞かれたので正直驚きました。
やっぱりアウトプットは大事(なおブログ)。
事前課題
事前課題では、GoとTypeScriptの勉強をしてきてって感じの内容でした。
具体的には以下のような感じ。
Golang
- Tour of GoのExerciseを全て解く
- mackerel-pluginに挑戦
TypeScript
インターン前日に大急ぎで仕上げてました。
大学のレポートは早めに終わらせましょう。
インターンの内容
前半(講義パート)
前半1週目は、日記アプリを作るということで、午前講義、午後は課題の実装を行いました。
内容は以下の通りです。
GoでWebアプリを作る時にディレクトリ構成とか、設計とかあまり知らなかったので、
そういったことも参考になりました。
また、GraphQLを初めて触ったので結構苦戦しました。
午前の講義では、自分の偏った知識の補完ができるため、とてもためになりました。
課題は、PRなどでレビューをしてもらえるため、貴重な経験となりました。
普段はあまりレビューしたりされてりする機会は多くはないので、
もうちょっとそういう機会を作ったほうが良いなあと思いました。
前半2週目は、以下の通りです。
機械学習を1度はやってみたいと思っていたため、やってみて良かったです。
パラメータ変えても精度が上がらなくて四苦八苦してました。
インフラについての講義は、インフラの歴史から、インフラエンジニアの今後の需要など、 個人的には今後の生存戦略的な意味でとても聞いててよかったです。
はてなの歴史についての講義では、はてなみたいな10年以上サービスを提供している企業がどういった歴史をたどったのか、 技術の発達とともに、企業はどう変化していくのか学べたのは大きいと感じました。
AWSハンズオンでは、WordPressをEC2上に構築し、冗長構成、DBのレプリケーションを行ったり、 前半の講義で作った日記アプリをCodePipelineでECSにデプロイしたりしました。
後半(チーム配属パート)
後半はインターン生は、各コースに配属されて実際にサービスを触りながら、それぞれの課題をやっていきます。
僕は大規模システム開発コースということで、システムプラットフォーム部でお世話になりました。
僕はコンテナに興味があったため、コンテナデプロイ基盤の検証をしていきました。
内容は、はてなの技術ブログに取り上げていただきました。
パブリッククラウドにおけるコンテナを運用するためのCI/CDパイプラインや、冗長構成など コンテナの基盤を作れるようになりたいと思っていたため、 本番環境で運用する際、どのような構成になっていると嬉しいのかなど聞けたりしたので良かったです。
周りにインフラをやってる人があまり多くないので、仕事でインフラをやっている人の話が聞けるのはすごく貴重でした。 研究室とかのサーバ管理などもすることがあると思うので、もっと精進したいです。
シスプラの方々にはとてもお世話になりました。
id:wtatsuruさんにはプロジェクトの進捗管理していただいたり、夕飯おごって頂いたり…
id:cohalzさんにはメンターとして付きっきりで面倒見てもらったり、夕飯おごって頂いたり…
id:masayoshiさんには低レイヤーの濃い話を聞かせていただいたり、夕飯おごって頂いたり…
その他
1ヶ月も京都にいたのに全然お金使わなかった…。
宿泊費、交通費、朝、昼の食事代は出してもらったので、切り崩さないですみました。
夕飯は、社員さんにいろんなところに連れ回してもらったため、美味しいご飯を堪能してきました。
ラーメンめっちゃ美味しかったです。
他のインターン生のエントリ
まとめ・今後
はてなインターンでは、前半後半共に多くのことを学びました。
インターン生同士でも学びがあって最高のメンバーでした!
個人的には、成果発表の順位が悔しくてしょうがないのですが、それはそれ。 次にうまいこと活かせれば何も問題ないので、今後はもっとバリュー出して行きます!!
私事ですが、希望している研究室に無事配属になったので、これから研究頑張るぞいって感じ。
趣味開発はコンテナエンジンの開発を始めました。
OSSのコンテナエンジンの実装を読み漁りながらRustでカキカキしていきます。
ブログでこまめにアウトプットする習慣ってどうやったらつきますかね。
サーバ監視入れてみた話
最近扱うサーバが増えたため、サーバ監視を導入する。 サーバ監視に使うのはPrometeusというGolang製のシステムの監視ツール。
それで今回は、Prometheusの設定を一通りやって行く話。
- PrometheusをDockerで動かす
- docker-compose.ymlに設定をまとめる
- 監視する情報を追加する(prometheus.ymlの記述)
- Nginxにリバースプロキシの設定
- node-exporterを使ってホストの監視をする。
1. PrometheusをDockerで動かす
公式のドキュメントを読んだまま、とりあえずコンテナ立ててみる.
$ docker run --name prometheus -d -p 127.0.0.1:9090:9090 quay.io/prometheus/prometheus
これでhttp://localhost:9090
にアクセスして確認する。
2. 監視する情報を追加する(prometheus.ymlの記述)
このままでは大したものが監視できず、アラートも使えないので、prometheus.yml
を書いて、コンテナ側の/etc/prometheus/prometheus.yml
にバインドさせる。
global: scrape_interval: 15s scrape_configs: - job_name: 'prometheus' scrape_interval: 5s static_configs: - targets: ['localhost:9090']
3. docker-compose.ymlに設定をまとめる
version: '2' services: prometheus: image: prom/prometheus volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml ports: - "9090:9090"
4. Nginxでリバースプロキシの設定
DNSの設定でCNAMEにprometheus
を追加する。
次に、/etc/nginx/prometheus.conf
を以下のように書けばok。
server{ server_name prometheus.example.com; listen 80; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Server $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; location / { proxy_pass http://localhost:9090; } }
server_name
に設定したアドレスにアクセスして確認する。
リバースプロキシもnginx-proxy
使ってできるようにする予定。
これでprometheus自体の監視はできたので、次はホストの監視を行う。
5. node-exporterを使ってホストの監視をする。
ホストの監視をするにはnode-exporterというモニタリングしてデータを集めてくれるツールがある。
ついでなのでこれもDockerで済ませる。
$ docker run -d -p 9100:9100 --net="host" prom/node-exporter
更にprometheus.ymlを以下のように書き直す。
scrape_configs: - job_name: 'Prometheus' scrape_interval: 5s static_configs: - targets: ['localhost:9090'] - job_name: 'Nodes' scrape_interval: 5s static_configs: - targets: ['node1.example.com:9100'] - targets: ['node2.example.com:9100']
これでホストの監視もできるはず。
Alertの設定は後で書く。
ペパボのインターンシップに参加した
ブログ更新するのは久しぶりですかね。
2/14~2/23の間、GMOペパボ福岡支社にインターンシップに参加させていただいた。
友人(@gamerkohei)とともに参加しました。
なるほど、先輩方が勧めるのもわかる。
人権が保証されている。そして何よりも技術的な刺激を多く受けられる。
大学内, サークル内ではなかなか触れられないものに触れる機会がたくさんあった。
その中でも、書いても大丈夫そうなところだけ書いていこうと思う。
インターン中のぐに
得られる刺激が多いからとてもよさ
— ぐに (@guni1192) 2018年2月20日
今までの生活より人権ありすぎて困惑
— ぐに (@guni1192) 2018年2月18日
エモい。エモい以外の語彙がなくなるぐらいよさみ
— ぐに (@guni1192) 2018年2月15日
VueのUnitテストどうすればいいんだあああ
— ぐに (@guni1192) 2018年2月19日
某社、その辺の学生よりイキイキしてるので、普通に楽しい。
— ぐに (@guni1192) 2018年2月21日
インターンの内容
ムームードメイン
ムームードメインのフロントの方を触るのがメインタスクだった。
UI挙動の修正
UIはカートの金額周りの挙動(値段のグルグルするところのフラグ)の修正を行った。
更にES5で記述されたところが多かったので、ES6に書き換えを行った。
実際にレビューしてもらって早めにリリースできた。(個人的にはまだ遅い)
リファクタ
テストを生やすことを最優先にしてみようと思ったが、
テストするVueインスタンスが大きく、テストケースを用意することが難しそうだと思い、
クラス化して分割するか、Vueコンポーネント化するかで迷った。
テストのしやすさ、今後のSPAに移行したりする可能性なども考慮して、Vueコンポーネント化することにした。
仕様と何回もぶつかったけど、なんとかコンポーネントに分けることができた。
テスト
今までほとんどテストを書くことがなかったため、
いきなりJavaScriptのテストを書くのはなかなか大変だった。
モック周りはどうにかなったものの、
非同期処理のテストなどになると、かなり苦戦した。
テストケース単体は普通に実装できたが、
これらのテストケースをすべて並列実行せているため、
テストの結果が他のテストケースに影響を及ぼしてしまい、
それに1時間以上苦しんだ。
解決策として、非同期処理を行っているテストケースを順序実行するようにした。
テストを書き終えたらまたレビューしてもらい、2回めのリリースを迎えた。
Chefのハンズオン
第2リリースが終わって、
最終日が暇だったのでChefのハンズオンを受けた。
内容としては、Chefの環境を構築して、
NginxにRailsのサンプルアプリをデプロイするまでだった。
ちゃんと構成管理ツールを使ったことがなかったので、
「おお!Ruby入った!」って感じでワクワクしながらやっていた。
pmr-checkerの機能追加
リリースもハンズオンも終わり、成果発表まで暇だったのですが、
急にホスティング事業部の@pyama86さんからのタスクが降ってきた。
PHPでできたサイトで、外部に見えてはいけないファイルをチェックするpmrコマンドというのがある。
そのpmrを使って漏れファイルを簡単にチェックを自動化するツールをRubyでpmr-checkerの機能追加をしてほしいとのこと。
具体的にはホワイトリスト形式で、設定ファイル(yaml)に書かれたものをチェック時スルーする機能を追加する。
時間と即興で書く実装力、Ruby力が足りなくてプルリクが最後まで行けなかったことに後悔。
もうちょっと限られた時間でどれだけコードが書けるかという経験も必要かもしれない。
KPTA
インターンを振り返ってKPTA(Keep, Problem, Try, Action)を行った。
自分がやりたいこと、今後の課題を見つめ直すことができた。
Hacker Tackle
2/17日に開催されたHacker Tackleのセッションを聞いてきた。
並列プログラミングの話や、機械学習周りの話が多かった印象。
Rustの話や、@udzuraさんのコンテナのセッションも聞いてきた。
これからどうするよ
大学1~2年の間は色々経験してみようと思って、
Webのフロント、バック、インフラをいろいろさわってみたけど、
本当にやりたいのはインフラだと気づいた。
サービスを作るより仕組みを考えるほうが好きなので、
インフラ周りは楽しいんじゃないかと。
研究室や就職先を選ぶ方向性が定まってきたのも、
このインターンでの大きな収穫だった。
感想
飲み会も多くて、とても楽しかったです❗
僕自身が少食+酒に弱いのがちょっとアレだけども。
多分ご飯についてはもう一人のほう(@gamerkohei)が書いてくれるでしょう。
最終日に技術部やペパ研の方々とも飲みの席で話せて興味がわきました。
実は飲み会の最後に@pyama86さんに「OSSの世界でまた会いましょう!」って言われたのが超嬉しかったのは内緒。
絶対また会いにいける戦闘力を手に入れてやる👊という意気込み。
インターンシップっていい制度だな~。
「あと2年で強くなって戻りたい!」って考えが何回も頭をよぎるぐらい良さでした。
ずるいなあ。そりゃファン増えるわ。
最後になりましたが、素晴らしい体験をさせて頂いたペパボの皆様に感謝を。
ペパボのみなさん、8日間、本当にお世話になりました。
自作言語を作り始めた話
久々のブログ更新でこの1年何もやってなかったことが露呈してしまう。
今回は何を血迷ったか急にプログラミング言語が作りたくなったので、作ってみることにしました。
プログラミング言語 Sobaの開発
とりあえず、四則演算とかできるところまでは作ってみようというわけで、やってみました。
実際に実装した機能は、
- 四則演算
- 変数代入, 参照
- if文
大したものはやってないです。
概要
今回つかったツールは以下のようになります。
Bisonは構文解析を行うパーサーを生成するツールで、yaccの上位互換となっています。
Flexは字句解析器とよばれ、文字列の変換抽出を行います。
実際に、Flexでプログラム中のキーワード(if, for, 演算子、数字など)を抽出し、それをBisonに渡して、Bisonはキーワードの組み合わせを解析し、その組み合わせごとに決められた処理を行わせます。
実装
実際に私が書いたコードは以下の2つのみです。
- soba.l: 字句解析を行ってキーワードをbisonに渡します。
- soba.y: パーサーを生成し、パターンごとの処理をさせます。
src/soba.l
%{ #include <stdio.h> #include <string.h> #include "soba.tab.h" int yywrap(void) { return 1; } %} %% "udon" { fprintf(stderr, "Syntax Error: %s\n", yytext); exit(1); } [+\-*/%=<>:;] { return yytext[0]; } "\n" return LF; "if" return IF; "for" return FOR; "in" return IN; "print" return PRINT; "println" return PRINTLN; [ \t]+ {} \".*\" { yytext[strlen(yytext)-1] = '\0'; yylval.string = strdup(&yytext[1]); printf("%s\n", yylval.string); return STR; } [1-9][0-9]\.\.[1-9][0-9] { yylval.string = strdup(yytext); return RANGE; } [1-9]?[0-9]* { int temp; // 入力から実数を取得 sscanf(yytext, "%d", &temp); yylval.int_value = temp; return INTEGER; } [0-9]*\.[0-9]* { double temp; sscanf(yytext, "%lf", &temp); yylval.double_value = temp; return FLOAT; } [a-zA-Z_]+ { yylval.string = strdup(yytext); return(VAR); } . { fprintf(stderr, "Syntax Error: %s\n", yytext); exit(1); } %%
src/soba.y
%{ #include <stdio.h> #include <stdlib.h> #include <string.h> #define YYDEBUG 1 #define VARSIZE 255 typedef struct { char *name; double value; } variable; int var_used = 0; variable var[VARSIZE]; double get_value(char *name); int substitution(char *name, double value); %} %union { int int_value; double double_value; char *string; } %token <int_value> INTEGER %token <double_value> FLOAT %token <string> VAR STR RANGE %token LF IF PRINT PRINTLN FOR IN %type <int_value> block expr number if_stmt %type <string> string %start program %left '+' '-' %left '*' '/' '%' %% program : | PRINT block LF { printf("%d", $2); } | PRINTLN block LF { printf("%d\n", $2); } | PRINT string LF { printf("%s", $2); } | PRINTLN string LF { printf("%s\n", $2); } | program PRINT block LF { printf("%f", $3); } | program PRINTLN block LF { printf("%d\n", $3); } | program PRINT string LF { printf("%s", $3); } | program PRINTLN string LF { printf("%s\n", $3); } | program block LF { printf("--> %d\n", $2);} | string LF { printf("--> %s\n", $1); } | block LF { printf("--> %d\n", $1);} ; string : STR { $$ = $1; } ; block : expr { $$ = $1; } | VAR '=' expr { substitution($1, $3); $$ = $3; } | if_stmt { $$ = $1; } ; if_stmt : IF expr ':' block { if ( $2 != 0 ) $$ = $4; else $$ = 0; } | block IF block { if ( $3 != 0 ) $$ = $3; else $$ = 0; } ; expr : number { $$ = $1; } | expr '+' expr { $$ = $1 + $3; } | expr '-' expr { $$ = $1 - $3; } | expr '*' expr { $$ = $1 * $3; } | expr '/' expr { $$ = $1 / $3; } | expr '%' expr { $$ = $1 % $3; } ; number : INTEGER { $$ = (double)$1; } | FLOAT { $$ = $1; } | VAR { $$ = get_value($1); } ; %% int search_variable(char *name) { for ( int i = 0; i < var_used; i++ ) { if ( !strcmp(var[i].name, name) ) { return i; } } return -1; } int substitution(char *name, double value) { int i = search_variable(name); if ( i == -1 ) { var[var_used].name = strdup(name); var[var_used].value = value; var_used++; } else { var[i].value = value; } return 0; } double get_value(char *name) { int i = search_variable(name); if ( i != -1 ) { return var[i].value; } printf("%s is not definded\n", name); return 0; } int yyerror(char const *str) { extern char *yytext; fprintf(stderr, "Syntax Error: %s\n", yytext); return 0; } int main(int argc, char* argv[]) { extern int yyparse(void); extern FILE *yyin; if ( argc < 2 ) { yyin = stdin; } else { yyin = fopen(argv[1], "r"); } do { if (yyparse()) { fprintf(stderr, "Error Occured!\n"); exit(1); } } while(!feof(yyin)); }
実行結果
…電卓っすね。
今後の実装予定(言い訳フェイズ)
実装力の限界ッ!
文字列とfor文を今せっせと書いてるところです。
早いとこFizzBuzzできるようになりたいなあ。
今回内容が薄いのは今後に期待という感じでよろしくお願いします。
一応ここに、置いときますね。
https://github.com/guni973/soba
B3になったときのコンパイラの授業が楽しみでならない。
今後も機能追加、改善していくつもりなので、よろしくです。