Panda Noir

JavaScript の限界を究めるブログでした。最近は幅広めに書いてます。

シェルを作ってみる その3

この記事は東北大学 計算機科学研究会 Advent Calendarの11日目の記事です。 いよいよクリスマスが近づいてきましたね。僕は彼女がいないのでただの平日ですが。ガッキーみたいな可愛い彼女ほしい

第三回目の記事ですので、第一回第二回を先にご覧ください。

頓挫した理由

シェルを作ってみる企画ですが、頓挫しました。なぜかというと「ログインシェルとして動かすためにはシェルスクリプトの解析が必須だから」です。

ログインシェルとして動かすためには

前回のプログラムを試しにログインシェルとして設定してみました。すると、なんとUbuntuへログインできなくなりました。何も調べずにやってはダメですね。

調べたところ、どうやら最低限シェルとして次の条件を満たしていないと強制ログアウトさせられるようです。

  • /etc/profileを実行可能
  • /etc/profile.d配下のファイルを実行可能

という条件が必要っぽいです。つまりシェルスクリプトを解釈・実行するエンジン制作の必要が出てきました。さすがに構文解析するのは骨が折れるので、ログインシェルとして動かすのは諦めます。いやー、何も調べずに始めたせいでここに来て詰まってしまいました・・・

代わり

このまま「作れませんでしたてへぺろ(・ω<)」で終わるのも味気ないのでboost::spirit::qiの使い方を解説します。

boost::spirit::qiとは

構文解析するためのライブラリです。ザックリ方針を立てるとシェルスクリプトはこんな感じの構文なのではないでしょうか。

文 = 文 ("|" コマンド文 | ">" ファイル)
コマンド文 = コマンド ( 引数 | オプション )*
引数 = 数値 | 文字列
文字列 = ('"' ("\" . | "${" .+ "}" | [^"])* '"')+
オプション = ("--" | "-").+
コマンド = .+
ファイル = .+

雑ですがおおよそこんな感じですよね。Qiに直すとこうなるはずです。まだ理解できてませんが。

sentence = sentence >> ((|' >> commandSentence | ">" >> file)
commandSentence = command >> *( arg | option )
arg = qi::int_ | string
string = ('"' >> ("\" >> ascii::char_ | "${" >> ascii::char_+ "}" | [^"])* '"')+
option = ("--" | "-") >> *ascii::char_
command = *ascii::char_
file = *ascii::char_

今23時なんですが、思ってたより深いライブラリっぽいので続きはまたあとで書きます。というか今タスクが多すぎてパンクしてるのでそのうち書きます。脳みそが死んでいる・・・