CMakeの構文調べてみた

https://cmake.org/cmake/help/v3.0/manual/cmake-language.7.html#grammar-token-newline
で、CMakeの構文しらべてみたのでメモ。

#全体の構文
```
file         ::=  file_element*
file_element ::=  command_invocation line_ending |
                  (bracket_comment|space)* line_ending
line_ending  ::=  line_comment? newline
space        ::=  <match '[ \t]+'>
newline      ::=  <match '\n'>
```
- `file`は、`file_element`の繰り返し
- ```file_element```は下記のいずれか
  - `コマンド呼び出し`+ `line_ending`
  - `bracket_comment`と空白の任意の繰り返し  + `line_ending`
- `line_ending`は、`行コメント``` + 改行
 
ざっくりまとめると **コメント以外はコマンド呼び出しですよ**ということ。
条件分岐も`if()`、`else()`のように全てコマンド呼び出しの形となっている。


# コマンド呼び出しの構文
```
command_invocation  ::=  space* identifier space* '(' arguments ')'
identifier          ::=  <match '[A-Za-z_][A-Za-z0-9_]*'>
arguments           ::=  argument? separated_arguments*
separated_arguments ::=  separation+ argument? |
                         separation* '(' arguments ')'
separation          ::=  space | line_ending
```

コマンド呼び出しは下記の形

- コマンド名(引数) の形。(`hoge(arg)`の形)。
- コマンド名の前後に空白が入っていてもよい。
- コマンド名の先頭はアルファベット or アンダーバー。2文字目以降は数字でもOK。
- 引数無しも可。
- 引数は複数でも可。
- 複数の引数の間は、空白または改行で区切られる。
- 引数はネストして()で囲われている場合もある


# コマンドの引数

```argument ::=  bracket_argument | quoted_argument | unquoted_argument```


コマンドの引数には

- bracket引数
- quated引数
- unquated引数

の３種類がある。

## bracket引数
```
bracket_argument ::=  bracket_open bracket_content bracket_close
bracket_open     ::=  '[' '='{len} '['
bracket_content  ::=  <any text not containing a bracket_close
                       of the same {len} as the bracket_open>
bracket_close    ::=  ']' '='{len} ']'
```

- ブラケット引数は、`[[bracket_content]]` もしくは`[=[bracket_content]=]` もしくは `[==[bracket_content]==]` 、、、の形
- `bracket_content`には、対応する「とじかっこ」以外の任意の文字列を含むことができる。

通常は

```
message([[
複数行にわたる文字列を
引数にいれたいぞ]])
```
のように、"[["、"]]"を使えば良い。
「"]]"を引数に入れたい」 という、超マニアックな要求がある場合にのみ

```
message([=[
こうすれば]]も含めることができるぞ]=])
```
のように、`[=[`などを使う。

ブラケット引数はver 3.0より前では使えないので注意。


## quated引数

```
quoted_argument     ::=  '"' quoted_element* '"'
quoted_element      ::=  <any character except '\' or '"'> |
                         escape_sequence |
                         quoted_continuation
quoted_continuation ::=  '\' newline
```

- ダブルクオーテーション`"`で囲まれた引数
- `\`、`"`以外のすべての文字と、エスケープシーケンスを含むことができる。
- `\`の直後に改行することで、改行後も連続できる

## unquated 引数

```
unquoted_argument ::=  unquoted_element+ | unquoted_legacy
unquoted_element  ::=  <any character except whitespace or one of '()#"\'> |
                       escape_sequence
unquoted_legacy   ::=  <see note in text>
```

- かっこで囲われてない引数。
- 空白、```(```、```)```、```#```、```\```を含まない(エスケープされている場合をのぞく。
- ただし、過去の経緯によりダブルクオーテーションで囲われている文字列や、```$()```で囲われた文字列もエラーにはならない。

# エスケープシーケンス

```
escape_sequence  ::=  escape_identity | escape_encoded | escape_semicolon
escape_identity  ::=  '\(' | '\)' | '\#' | '\"' | '\ ' |
                      '\\' | '\$' | '\@' | '\^'
escape_encoded   ::=  '\t' | '\r' | '\n'
escape_semicolon ::=  '\;'
```

| 記号　|　意味 |
|:-----|------|
| '\\t' |　タブ文字|
| '\\r' | 同じ行の先頭に戻る|
| '\\n' |　改行、復帰|
| '\\;' | ';'文字|
| '\\(' | '('文字 |
| '\\)' | ')'文字 |
| '\\#' | '#'文字 |
| '\\"'|  '"'文字|
| '\\ '  | ' '文字(空白文字) |
| '\\\\\' |'\\'文字 |
| '\\$'   |'$'文字 |
| '\\@'  |'@'文字 |
| '\\^' |';'文字|




# 変数の参照

変数は、quqted 引数とunquated 引数の中で、`${valuable}`の形式で参照される。bracket argumentの中では${}で囲んでも変数展開されない。


# コメント
コメントは ```#```で開始される。
ただし、以下の場合はコメント開始されない
- bracket引数の中
- quated引数の中
- unquqted引数の中で、なおかつ`\`でエスケープされている場合

## bracketコメント

```bracket_comment ::=  '#' bracket_argument```

`#` の直後にbracket引数の形が続く場合、bracket引数の終了までがコメントとなる。
これにより、複数行にわたるコメントを作ることが可能。
(C言語の`/* */` に相当)。

# 行コメント

```
line_comment ::=  '#' <any text not starting in a bracket_argument
                       and not containing a newline>
```
C言語`//` に相当。

# 制御構造

## 条件分岐
`if()`、`elseif()`、`else()`、`endif()`で条件分岐可能。

## Loop
`foreach()`、` endforeach()`、`while()`、`endwhile()`、`break()`でループを組むことが可能。

## コマンド定義

`macro()`、`endmacro()`、`function()`、`endfunction()`でコマンド定義が可能。



# 変数
- `set()`で値を代入、`unset()`で解除できる。
- 変数は、大文字/小文字 を区別する。(コマンドと違うので注意)
- 変数は任意の文字で作れるが、英数字と`_`、`-`だけで作ることを推奨。
- 基本的には変数の型は文字列（数値型はない)だが、コマンドによっては文字列を他の型と認識する　(例えば、`if()`は`true`という文字を「真」として認識する。

## 変数のスコープ

変数には３種類のスコープがある

### Function スコープ
- function()コマンドによって作られるコマンド内のスコープ
- コマンド内でset()/unset()された変数はコマンドの外からは見えない。

### Directory スコープ
- 各ディレクトリのCMakeLists.txtを処理するときのスコープ。(つまり、最も普通のスコープ)
- 各ディレクトリのCMakeLists.txtを処理開始する前に、親ディレクトリのCMakeLists.txtで定義されていた全ての変数がコピーされる。

### Persistent キャッシュ
- 最もグローバルなスコープ。CMakeをなんども繰り返しても保存されている特殊な変数。
- set()/unset() で`CACHE`オプションをつけるなどの方法で書き換え可能

変数の評価は、**Function スコープ** -> **Directory スコープ** -> **Persistent キャッシュ** の順に行われる。

# リスト

Unquated 引数の評価時などでは、`;`で区切られた文字列はリストとして扱われる。
`;`そのものをリスト内の文字列に服見たい場合は`\;`のようにエスケープする。

なお、リストは「単純なユースケース」を意図して設計されているので、複雑なデータ処理に使うべきではない。