バックグラウンド
Cの変数宣言ステートメントは、変数の名前、そのベース型、および型修飾子の3つの部分で構成されています。
タイプ修飾子には次の3種類があります。
- ポインター
*
(プレフィックス) - 配列
[N]
(後置) - 関数
()
(後置)- 括弧内に関数引数のリストを指定できますが、この課題のために、それを無視して使用します
()
(技術的には「関数は任意の種類の引数を取ることができます」)。
- 括弧内に関数引数のリストを指定できますが、この課題のために、それを無視して使用します
また、表記を読み取る方法は次のとおりです。
int i; // i is an int
float *f; // f is a pointer to a float
my_struct_t s[10]; // s is an array of 10 my_struct_t
int func(); // func is a function returning an int
キャッチは、私たちのようなより複雑なタイプ、形成するために、これらのすべてを混在させることができるということである配列の配列や関数ポインタの配列やポインタの配列へのポインタを:
int arr[3][4];
// arr is an array of 3 arrays of 4 ints
int (*fptrs[10])();
// fptrs is an array of 10 pointers to functions returning an int
float *(*p)[16];
// p is a pointer to an array of 16 pointers to float
これらの複雑なステートメントをどのように読みましたか?
- 変数名から始めます。
(name) is ...
- 優先順位が最も高い修飾子を選択します。
- それを読んで:
* -> pointer to ...
[N] -> array of N ...
() -> function returning ...
- 修飾子がなくなるまで2と3を繰り返します。
- 最後に、基本型を読みます。
... (base type).
Cでは、後置演算子は前置演算子よりも優先され、型修飾子も例外ではありません。したがって、[]
そして()
、その後、最初のバインド*
。ペアのペア内にあるもの(...)
(関数演算子と混同しないでください)は、最初に外部のものにバインドします。
図解された例:
int (*fptrs[10])();
fptrs fptrs is ...
[10] array of 10 ... // [] takes precedence over *
(* ) pointer to ...
() function returning ...
int int
仕事
Cで記述された変数宣言ステートメントの行を指定し、上記の方法を使用して、行を説明する英語の式を出力します。
入力
入力は、単一の基本型、単一の変数名、0個以上の型修飾子、および末尾のセミコロンを含む単一のCステートメントです。上記のすべての構文要素に加えて、以下を実装する必要があります。
- 基本型と変数名の両方が正規表現と一致します
[A-Za-z_][A-Za-z0-9_]*
。 - 理論的には、プログラムは無制限の型修飾子をサポートする必要があります。
次の方法で他のC構文要素を単純化できます(完全な実装も歓迎します)。
- 基本型は、常に一つの単語である、例えば
int
、float
、uint32_t
、myStruct
。のようなものunsigned long long
はテストされません。 - 配列表記の
[N]
場合、数値N
は常に基数10で書かれた単一の正の整数になります。のようなものint a[5+5]
、int a[SIZE]
またはint a[0x0f]
テストされません。 - 関数表記では
()
、上で指摘したように、パラメーターはまったく指定されません。 - 空白の場合、スペース文字のみ
0x20
が使用されます。プログラムを空白の特定の使用に制限することができます。例えば- 基本タイプの後にスペースを1つだけ使用します
- トークン間のどこでもスペースを使用する
- ただし、トークンセパレーターよりも多くの情報を伝えるために2つ以上の連続したスペースを使用することはできません。
C構文によると、次の3つの組み合わせは無効であるため、テストされません。
f()()
関数を返す関数f()[]
配列を返す関数a[]()
N個の関数の配列
C開発者は、代わりにこれらの同等の形式を使用します(これらはすべてテストケースでカバーされています)。
(*f())()
関数へのポインターを返す関数*f()
配列の最初の要素へのポインターを返す関数(*a[])()
関数へのN ポインターの配列
出力
出力は単一の英語の文です。英語の文法を尊重する必要はありません(ただし、必要な場合は可能ですa, an, the
)。結果が人間が読めるように、各単語は1つ以上の空白(スペース、タブ、改行)で区切る必要があります。
繰り返しますが、変換プロセスは次のとおりです。
- 変数名から始めます。
(name) is ...
- 優先順位が最も高い修飾子を選択します。
- それを読んで:
* -> pointer to ...
[N] -> array of N ...
() -> function returning ...
- 修飾子がなくなるまで2と3を繰り返します。
- 最後に、基本型を読みます。
... (base type).
テストケース
int i; // i is int
float *f; // f is pointer to float
my_struct_t s[10]; // s is array of 10 my_struct_t
int func(); // func is function returning int
int arr[3][4]; // arr is array of 3 array of 4 int
int (*fptrs[10])(); // fptrs is array of 10 pointer to function returning int
float *(*p)[16]; // p is pointer to array of 16 pointer to float
_RANdom_TYPE_123 (**(*_WTH_is_TH15)())[1234][567];
/* _WTH_is_TH15 is pointer to function returning pointer to pointer to array of
1234 array of 567 _RANdom_TYPE_123 */
uint32_t **(*(**(*(***p)[2])())[123])[4][5];
/* p is pointer to pointer to pointer to array of 2 pointer to function returning
pointer to pointer to array of 123 pointer to array of 4 array of 5 pointer to
pointer to uint32_t */
uint32_t (**((*(**(((*(((**(*p)))[2]))())))[123])[4])[5]);
// Same as above, just more redundant parens
some_type (*(*(*(*(*curried_func())())())())())();
/* curried_func is function returning pointer to function returning pointer to
function returning pointer to function returning pointer to
function returning pointer to function returning some_type */
スコアリングと勝利の基準
これはコードゴルフの挑戦です。最小バイト数のプログラムが勝ちます。
int arr[3][4];
であるan array of 3 arrays of 4 ints
(あなたが言うように)、またはan array of 4 arrays of 3 ints
?
;
には行の終わりが含まれていますか?