シェルスクリプトを使用したコンテキストフリー文法パーサ

シェルスクリプトを使用したコンテキストフリー文法パーサ

以前は技術チームではなくチームのためのスクリプトを作成していましたが、難解なコマンドラインフラグを文章のように読み取るコマンドに置き換える必要があると思いました。

私はコマンドラインを思い出しました。
<script.sh> run tests for <module> ... in <language> ...

キーワード「for」はモジュールのリストを紹介し、「in」は言語のリストを紹介します。 (なお、「in」自体が将来言語コードになることもあります。)

私が解析する方法は、上位構造をとして定義することです。 +="run test"の場合、"for"および"in"キーワードを見つけるために特定の解析を開始します。

次に、構文を次のように変更したいと思います。
<script.sh> run <module> ... tests in <language> ...

私の考えでは、これはもっと読みやすいと思います。

手作りの Bash パラメータの解析でこれを行うことができますが、私の考えではこれは複雑すぎます。別のオプションはLex/Yaccです。スクリプトは一時Lex+Yaccスクリプトを作成し、それを使用してコマンドラインを解析できます。これも出すぎたようです。

上記のコマンドラインを変数に解析するために使用できる単純なコンテキスト自由文法を定義するための優れたシンプルな方法はありますか?本格的な解決策ではなく出発点というニュースを聞くと嬉しい。

ベストアンサー1

かなり愚かですが、正しい方向を教えてください。

解析は、与えられたプログラムを解釈(またはコンパイルおよび実行)するプロセスの1つのステップにすぎません。シェルパラメータを語彙表示として使用すると便利です。解釈に関しては、解析とソルバーのロジックをタスクの実装とは別に維持することをお勧めします。タスクを実行するために明示的に名前付き関数を使用することです。ランダムゲートを使用して作成することも可能であるため、追加の作業を行わなくても追跡およびデバッグできます。処刑の痕跡を見せるbash -x人はまさにあなたの友人です。bash -x ./script.bash

このような解析ロジックで名前付き関数を呼び出すことをお勧めします。作成または変更するのは面倒で、実行された関数の代わりに呼び出された関数のエコー名を変更できる方が簡単です。

#!/usr/bin/env bash

: ${DEBUG:=}; shopt -s extglob; [[ $DEBUG ]] && shopt -p extglob

acceptArg () {
  local spec="$1" cb="$2" arg="$3" status=([args]=0 [matched]=0); shift 3;

  # https://unix.stackexchange.com/a/234415/61350  # how-can-i-use-a-variable-as-a-case-condition
  matcher="@($spec)"
  case "$arg" in
    $matcher) status[matched]=1; $cb ;;
    *) [[ $DEBUG ]] && echo "spec: '$spec' failed to match arg: '$arg'";;
  esac
  [[ $DEBUG ]] && declare -p status
  return $((status[matched] == 1))
}

count=0
incr(){ echo $((++count)); }
handleFirst(){ incr; }
handleSecond(){ incr; }

acceptArg "f|first" handleFirst "$1";
acceptArg "s|second|*2" handleSecond "$2";
[[ $? == 1 ]] && echo done || echo failed

私も同じことに興味があり、数ヶ月、数年間何かを書くことを考えてきました。具体的な問題の説明を書いてくれてありがとう。更新作業中です。https://gist.github.com/mcint/8a589500c44d4dc08dcb09b80882c2fd

おすすめ記事