Description: Yash のコマンドの構文規則の形式的な定義

# 構文の形式的定義

ここにプログラミング言語としてのシェルの構文定義を示します。

注 | 以下に示す構文の一部は POSIX 準拠モードでは使用できません。

## トークン分割

入力ソースコードの文字列はまずトークンに分割されます。トークンはソースコード内のより先に現れるトークンができるだけ長くなるように分割します。一つ以上の空白 (blank) 文字の連なりはトークンを分割します。

Yash に存在する演算子トークンは以下の通りです:

`&` `&&` `(` `)` `;` `;;` `|` `||` `<` `<<` `<&` `<(` `<<-` `<<<` `<>` `>` `>>` `>&` `>(` `>>|` `>|` (改行)

注 | 他の一般的なプログラミング言語とは異なり、改行演算子は空白ではなくトークンとして扱われます。

空白ではなく演算子トークンの一部でもない文字は単語 (word) トークンとなります。単語は以下の解析表現文法によって解析されます。

Word

  (WordElement / !SpecialChar .)+

WordElement

  `\` . /
  `'` (!`'` .)* `'` /
  `"` QuoteElement* `"` /
  Parameter /
  Arithmetic /
  CommandSubstitution

QuoteElement

  `\` ([`$`"\`] / <改行>) /
  Parameter /
  Arithmetic /
  CommandSubstitutionQuoted /
  ![``"\`] .

Parameter

  `$` [`@*#?-$!` [:digit:]] /
  `$` PortableName /
  `$` ParameterBody

PortableName

  ![`0`-`9`] [`0`-`9` `ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_`]+

ParameterBody

  `{` ParameterNumber? (ParameterName / ParameterBody / `$` ParameterBody / Arithmetic / CommandSubstitution) ParameterIndex? ParameterMatch? `}`

ParameterNumber

  `#` ![`}+=:/%`] !([`-?#`] !`}`)

ParameterName

  [`@*#?-$!`] /
  [[:alnum:] `_`]+

ParameterIndex

  `[` ParameterIndexWord (`,` ParameterIndexWord)? `]`

ParameterIndexWord

  (WordElement / ![`"'],`] .)+

ParameterMatch

  `:`? [`-+=?`] ParameterMatchWord /
  (`#` / `##` / `%` / `%%`) ParameterMatchWord /
  (`:/` / `/` [`#%/`]?) ParameterMatchWordNoSlash (`/` ParameterMatchWord)?

ParameterMatchWord

  (WordElement / ![`"'}`] .)*

ParameterMatchWordNoSlash

  (WordElement / ![`"'/}`] .)*

Arithmetic

  `$((` ArithmeticBody* `))`

ArithmeticBody

  `\` . /
  Parameter /
  Arithmetic /
  CommandSubstitution /
  `(` ArithmeticBody `)` /
  ![``()`] .

CommandSubstitution

  `$(` CompleteProgram `)` /
  ``` CommandSubstitutionBody* ```

CommandSubstitutionQuoted

  `$(` CompleteProgram `)` /
  ``` CommandSubstitutionBodyQuoted* ```

CommandSubstitutionBody

  `\` [`$`\`] /
  !``` .

CommandSubstitutionBodyQuoted

  `\` [`$`\``] /
  !``` .

SpecialChar

  [`|&;<>()`\"'` [:blank:]] / <改行>

この文法における終端記号の集合は、yash を実行する環境が扱える任意の文字の集合 (実行文字集合) です (ただしナル文字 `'\0'` を除く)。

厳密には、上記の文法定義は完全な解析表現文法ではありません。CommandSubstitution (Quoted) のルールが構文定義の非終端記号である CompleteProgram に依存しているためです。

### トークン分類

単語トークンが生成された後、単語はさらに IO_NUMBER トークン・予約語・名前・代入・通常の単語のどれかに分類されます。通常の単語以外の分類は、その単語が現れる文脈においてその分類のトークンが現れ得る場合のみ採用されます。予約語の一覧と予約語が認識される文脈の要件は、​トークンの解析と予約語を参照してください。

トークンが数字のみから構成されていて直後に `<` または `>` が続くとき、それは IO_NUMBER トークンとなります。

代入 (assignment) トークンは名前 (name) とそれに続く `=` で始まるトークンです:

AssignmentWord

  AssignmentPrefix Word

AssignmentPrefix

  Name `=`

Name

  ![[:digit:]] \[[:alnum:] `_`]+

### コメント

コメントは `#` で始まり、次の改行文字の直前まで続きます。コメントは空白と同様に扱われ、トークンの一部にはなりません。コメントを開始する `#` は、トークンの始まりの位置にあるときのみ有効です。それ以外の位置にある `#` は単に単語トークンの一部と見做されます。

Comment

  `#` (!<改行> .)*

## 構文

トークンが分割された後、その結果であるトークンの並びは以下に示す文脈自由文法によって解析されます。(以下、`*` と `+` と `?` は正規表現と同様の意味を持ちます)

CompleteProgram

  NL* | CompoundList

CompoundList

  NL* AndOrList (​(`;` | `&` | NL) CompleteProgram)?

AndOrList

  Pipeline ((`&&` | `||`) NL* Pipeline)*

Pipeline

  `!`? Command (`|` NL* Command)*

Command

  CompoundCommand Redirection* |
  FunctionDefinition |
  SimpleCommand

CompoundCommand

  Subshell |
  Grouping |
  IfCommand |
  ForCommand |
  WhileCommand |
  CaseCommand |
  DoubleBracketCommand |
  FunctionCommand

Subshell

  `(` CompoundList `)`

Grouping

  `{` CompoundList `}`

IfCommand

  `if` CompoundList `then` CompoundList (`elif` CompoundList `then` CompoundList)* (`else` CompoundList)? `fi`

ForCommand

  `for` Name (​(NL* `in` Word*)? (`;` | NL) NL*)? `do` CompoundList `done`

WhileCommand

  (`while` | `until`) CompoundList `do` CompoundList `done`

CaseCommand

  `case` Word NL* `in` NL* CaseList? `esac`

CaseList

  CaseItem (`;;` NL* CaseList)?

CaseItem

  `(`? Word (`|` Word)* `)` CompleteProgram

DoubleBracketCommand

  `[[` Ors `]]`

Ors

  Ands (`||` Ands)*

Ands

  Nots (`&&` Nots)*

Nots

  `!`* Primary

Primary

  (`-b` | `-c` | `-d` | `-e` | `-f` | `-G` | `-g` | `-h` | `-k` | `-L` | `-N` | `-n` | `-O` | `-o` | `-p` | `-r` | `-S` | `-s` | `-t` | `-u` | `-w` | `-x` | `-z`) Word |
  Word (`-ef` | `-eq` | `-ge` | `-gt` | `-le` | `-lt` | `-ne` | `-nt` | `-ot` | `-veq` | `-vge` | `-vgt` | `-vle` | `-vlt` | `-vne` | `=` | `==` | `===` | `=~` | `!=` | `!==` | `<` | `>`) Word |
  `(` Ors `)` |
  Word

FunctionCommand

  `function` Word (`(` `)`)? NL* CompoundCommand Redirection*

FunctionDefinition

  Name `(` `)` NL* CompoundCommand Redirection*

SimpleCommand

  (Assignment | Redirection) SimpleCommand? |
  Word (Word | Redirection)*

Assignment

  AssignmentWord |
  AssignmentPrefix`(` NL* (Word NL*)* `)`

Redirection

  IO_NUMBER? RedirectionOperator Word |
  IO_NUMBER? `<(` CompleteProgram `)` |
  IO_NUMBER? `>(` CompleteProgram `)`

RedirectionOperator

  `<` | `<>` | `>` | `>|` | `>>` | `>>|` | `<&` | `>&` | `<<` | `<<-` | `<<<`

NL

  <改行>

ルール Primary では、Word トークンは `]]` に一致してはなりません。また、Primary が Word トークンで始まる場合にはその Word は同ルールで認められている単項演算子に一致してはなりません。

ルール SimpleCommand では、Word トークンはそれが Assignment の始まりとは解釈できない場合にのみ採用されます。

ルール Assignment では、AssignmentPrefix と `(` の間に空白を置くことはできません。

上記の文法定義には​ヒアドキュメントの内容とその終わりを表す行の解析のための規則は含まれていません。それらは対応するリダイレクト演算子の後にある最初の改行 (NL) トークンが解析された直後に解析されます。

### エイリアス置換

単語は​エイリアス置換の対象となります。

- 単語が SimpleCommand の Word として解析されようとした時に、通常のエイリアス及びグローバルエイリアスを対象として置換が試みられます。

- 置換結果が空白文字 (blank) で終わるエイリアス置換の次に単語トークンがある場合、その単語も通常のエイリアス及びグローバルエイリアスを対象として置換が試みられます。

- その他の単語は、グローバルエイリアスのみを対象として置換が試みられます。(POSIX 準拠モードを除く)

予約語に分類されたトークンはエイリアス置換の対象からは除外されます。