jyami
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # 構文解析と抽象構文木 - シェルもどきをgoで自作する #9 ## おさらい これまで - [シェルってなに?コマンドラインインタプリタってなに? - シェルもどきをgoで自作する#1](https://hackmd.io/@jyami/HJzohRn2D) - [コマンドと引数の分解、環境変数PATHから探索、外部コマンドと内部コマンド - シェルもどきをgoで自作する #2](https://hackmd.io/@jyami/HyeSkkThP) - [字句解析その1 - シェルもどきをgoで自作する #3](https://hackmd.io/@jyami/Hk3bWSMQO) - [字句解析その2 - シェルもどきをgoで自作する #4](https://hackmd.io/@jyami/S1BkltxQu) - [リダイレクションってなに? - シェルもどきをgoで自作する #5](https://hackmd.io/@jyami/S113NQx8u) - [リダイレクションの種類 - シェルもどきをgoで自作する #6](https://hackmd.io/@jyami/rJ3XmClqd) - [リダイレクションの構文 - シェルもどきをgoで自作する #7](https://hackmd.io/@jyami/BJ04J2Upd) - [コマンドプロセスを作成する際のファイルディスクリプタの操作 - シェルもどきをgoで自作する #8](https://hackmd.io/@jyami/Hy7nSciMt) シェルもどき「[oreshell](https://github.com/jyami/oreshell)」を自作している。 現状のoreshellはリダイレクションを行うとエラーになるのでリダイレクションできるように修正する。 前回はファイルディスクリプタ操作部分の実装を検討した。 今回はリダイレクション対応に合わせた字句解析器の修正と「構文解析器」の実装、動作確認。 ## 字句解析器の修正 今回までに行った字句解析についての説明は[コチラ](https://hackmd.io/@jyami/Hk3bWSMQO#%E5%AD%97%E5%8F%A5%E8%A7%A3%E6%9E%90)。 リダイレクションに対応するために、リダイレクション文字、ファイルディスクリプタ番号、リダイレクション先ファイル名の切り出してトークンの羅列を作成できるように字句解析器を修正する。 修正内容の細かい説明は省略。 注意する点は以下の通り。 - コマンド引数(ファイル名など)とリダイレクション文字の間にスペースが入らない場合がある。(区切りは空白文字だけではない) - 例 ``` $ ls a b c d>list ``` 「d」「>」「list」の間に空白はないがそれぞれ別トークンとなる。 - ファイルディスクリプタ番号はその次の文字がリダイレクション文字の時だけ、ファイルディスクリプタ番号として扱う。 - 例 ``` $ ls 3 2 1>list ``` 「3」「2」はコマンド引数(ここではファイル名)、「1」はファイルディスクリプタ番号としてトークンになる。 ## 「構文解析器の実装」ってあるけど「構文解析」ってなに? 一般的なインタプリタは、その入力に対して 1.字句解析 2.構文解析 3.評価 を順に処理を行う。 それぞれの処理を「字句解析器」「構文解析器」「評価器」が行う。 それぞれの出力(結果)が次の処理の入力となる。 関係を以下に図で示す。 ```plantuml file 入力 cloud 字句解析器 #palegreen;line:green;line.dashed;text:green file 字句解析結果 cloud 構文解析器 #palegreen;line:green;line.dashed;text:green file 抽象構文木 cloud 評価器 #palegreen;line:green;line.dashed;text:green file 結果 入力 -> 字句解析器 字句解析器 -> 字句解析結果 字句解析結果 -> 構文解析器 構文解析器 -> 抽象構文木 抽象構文木 -> 評価器 評価器 -> 結果 ``` 構文解析では、「字句解析の結果が定義した構文のとおりであるかどうか」を調べ、構文通りであれば「抽象構文木」と呼ばれるデータ構造を作成する。評価では、抽象構文木が表すデータ構造に基づいて実際の処理の実行を行う。 oreshellの字句解析結果の例は[コチラ](https://hackmd.io/@jyami/S1BkltxQu#%E7%B5%82%E7%AB%AF%E3%81%AE%E5%88%87%E3%82%8A%E5%87%BA%E3%81%97)。 oreshellのリダイレクションの構文は[コチラ](https://hackmd.io/sCenAHRJQuGFHW1L9hSjHA#%E3%83%AA%E3%83%80%E3%82%A4%E3%83%AC%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E5%AF%BE%E5%BF%9C%E5%BE%8C%E3%81%AE%E6%A7%8B%E6%96%87)。 ■構文解析とは > プログラミング言語やマークアップ言語などのコンピュータ言語で書かれた文を構成要素に分解し、要素間の関係を元に特定のデータ構造に変換する操作を構文解析という。 > [e-words](https://e-words.jp/w/%E6%A7%8B%E6%96%87%E8%A7%A3%E6%9E%90.html) ■抽象構文木とは > 抽象構文木(英: abstract syntax tree、AST)は、通常の構文木(具象構文木あるいは解析木とも言う)から、言語の意味に関係ない情報を取り除き、意味に関係ある情報のみを取り出した(抽象した)木構造の木である。 > [wikipedia](https://ja.wikipedia.org/wiki/%E6%8A%BD%E8%B1%A1%E6%A7%8B%E6%96%87%E6%9C%A8 ) ■構文木とは > 構文木(こうぶんぎ)とは、構文解析の経過や結果(またはそれら両方)を木構造で表したもの。 > [wikipedia](https://ja.wikipedia.org/wiki/%E6%A7%8B%E6%96%87%E6%9C%A8 ) ## 今回の抽象構文木 今回のoreshellリダイレクション対応では以下の図ような抽象構文木が必要になる。 ```plantuml node SimpleCommand card コマンド名 node CommandSuffix collections コマンド引数 collections リダイレクション群 card 入力または出力方向 card ファイルディスクリプタ番号 card ファイルパス SimpleCommand -- コマンド名 SimpleCommand -- CommandSuffix CommandSuffix -- コマンド引数 CommandSuffix -- リダイレクション群 リダイレクション群 -- 入力または出力方向 リダイレクション群 -- ファイルディスクリプタ番号 リダイレクション群 -- ファイルパス ``` goで書くと以下の通り。 ```go= package ast type Direction int const ( IN Direction = iota OUT ) type Redirection struct { Direction Direction FdNum int FilePath string } type CommandSuffix struct { Args []string Redirections []Redirection } type SimpleCommand struct { CommandName string CommandSuffix CommandSuffix } ``` ## 構文解析器(パーサ)の実装 リダイレクション対応するために上記のような抽象構文木を作成する構文解析器を実装する。 実装の細かい説明は省略。 今回パーサを作ってみて「こうしておいたほうが結局楽だな」と思った点は以下の通り。 - できる限りツリーの各ノード毎にパーサを個別に準備し、ツリーを下りながらパーサを再帰的に呼び出すように作る。 - 字句解析結果からトークン要素を取り出すときは、Peekできると便利。Peekとは次の要素を取り出さずに「覗き見」する処理のこと。いま手に持っている要素をどのように扱うかは次の要素の正体がわからないと決められないことがある。 ## 実装完了 字句解析、構文解析を呼び出している様子 ```go= // 入力文字列をトリム trimedL := strings.Trim(string(line), " ") if len(trimedL) == 0 { continue } // 字句解析 l := lexer.Lex(trimedL) // 構文解析 simpleCommand, err := parser.ParseSimpleCommand(l) if err != nil { fmt.Fprintln(os.Stderr, err) continue } log.Logger.Printf("simpleCommand: %v\n", simpleCommand) // 先頭の単語に該当するコマンドを探して実行する // 内部コマンドか? internalCommand, ok := internalCommands[simpleCommand.CommandName] if ok { // 内部コマンドを実行 err = internalCommand(simpleCommand) } else { // 外部コマンドを実行 err = execExternalCommand(simpleCommand) } ``` [ソースコード](https://github.com/jyami/oreshell/commits/v0.4) ## リダイレクション対応したoreshellの実行例 実装が完了したので動作確認する。 ``` $ go run main.go (ore) > echo "abc" > abc.txt (ore) > cat abc.txt abc (ore) > ls abc.txt 1>list def.txt 2>errlist (ore) > cat list abc.txt (ore) > cat errlist ls: 'def.txt' にアクセスできません: そのようなファイルやディレクトリはありません (ore) > ls abc.txt ghi.txt>list 2> errlist (ore) > cat list abc.txt (ore) > cat errlist ls: 'ghi.txt' にアクセスできません: そのようなファイルやディレクトリはありません (ore) > cat < list abc.txt (ore) > cat <abc.txt>abc2.txt (ore) > cat abc2.txt abc ```

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully