Try   HackMD

字句解析その1 - シェルもどきをgoで自作する #3

おさらい

シェルもどき「oreshell」を自作している。

前々回、前回

シェルは入力した文字列を読み取って、コマンドと引数群に分割してプロセス生成に渡している。

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

現在の実装では入力文字列を単純に空白で分割している

$ cp hoge age

上記のコマンド文字列の入力を分割した結果は以下の通り。

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

ファイル名/パス名が空白文字を含んでいる場合はどうする?

コマンドの引数として「(space)oge」、「h(space)ge」というファイル名を扱いたいときはどうする?

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

ファイル名/パス名に空白文字を含んでいる場合は、現在の実装である「単純に空白で区切る」では期待した分割をすることができない。
期待した分割をするためには、コマンドと引数群の区切りの空白文字と、ファイル名/パス名に含まれる空白文字とを区別する必要がある。

エスケープ処理

一般的なシェルでは、

  • バックスラッシュ : 対象文字の直前にバックスラッシュをつける
  • クォーテーション(シングル、ダブル) : 対象文字列リテラルをクォーテーションで「くくる」。

を使って、ファイル名/パス名(文字列リテラル)の空白文字と、コマンドと引数群の区切りとの見分けをつけている。
これをエスケープ処理と呼ぶ。エスケープの対象となった文字をエスケープ文字と呼ぶ。

(エスケープによって文字列リテラルとして扱える対象は空白文字だけはないが、細かい説明はここではしない。)

「(space)oge」、「h(space)ge」というファイル名を扱いたい場合のコマンドライン文字列の入力の例は以下の通り。

$ cp \ oge "h ge"

文字のエスケープを考慮したコマンドと引数群の分割は?

ファイル名/パス名の空白文字と、コマンドと引数群の区切りとの見分けをつける指定方法はわかった。
では、今回作っているシェルでは、上記の文字列をどのようにして分割してプロセス生成に渡したらよいのか?

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

字句解析

文字のエスケープを考慮したコマンドと引数群の分割を行うためには、単純に空白で分割するのではなく、もうちょっと手の込んだ分割を行う必要がある。
インタプリタ/コンパイラではこの「もうちょっと手の込んだ分割」を「字句解析」と呼んでいる。

■字句解析とは

プログラムの文字の並び、文字列を 意味のある単語(これをトークンと言います。)に分ける処理を行います。これを字句解析と いいます。
参照

字句解析では、入力した文字列を「トークン」と呼ばれる意味のある単語に分割する。
このトークンには後々の処理がしやすいように種別をつけておく。

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

ここでは、トークンに以下の種別をつけておく。

  • コマンドと引数群の区切りの空白文字
  • 文字列リテラル
    • バックスラッシュ付きの文字列リテラル
    • クオートでくくった文字列リテラル
    • バックスラッシュ、クォートの無い文字列リテラル
  • 入力文字列全体の終端(EOF)

トークンに分割した後、その種別を参照しながら「その他の処理」を行った後にプロセス生成を行う。

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

字句解析器

字句解析を実現するプログラム(またはプログラムの一部の機能)を「字句解析器(lexer)」と呼ぶ。
lexerはステートマシンで設計/実装することがよくある。
go言語の偉い人がステートマシンを使って実装している例があるので、今回はそれを真似する。

参考

文字のエスケープを考慮した字句解析のステートマシン

以下は今回設計した字句解析器の状態遷移図である。

        
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

上記ステートマシンは以下のように入力文字列の上を
P : 文字読み取りポインタ
S : トークン開始位置
の2つを文字列終端へと少しづつずらしながらトークンを切り出して動作する。

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

ステートマシンが文字読み取りポインタとトークン開始位置を使ってトークン切り出す動作の解説は次回。