[Question]
  [
## Background
Variable declaration statement in C consists of three parts: the *name* of the variable, its *base type*, and the *type modifier(s)*.
There are three kinds of type modifiers:
* Pointer `*` (prefix)
* Array `[N]` (postfix)
* Function `()` (postfix)
	+ You can specify a list of function arguments inside the parens, but for the sake of this challenge, let's ignore it and just use `()` (which technically means "the function can take any kind of arguments").
And a way to read out the notations is as follows:
```
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
```
The catch is that we can mix all of these to form a more complicated type, such as *array of arrays* or *array of function pointers* or *pointer to array of pointers*:
```
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
```
How did I read these complicated statements?
1. Start from the variable name. `(name) is ...`
2. Select the modifier with the highest precedence.
3. Read it:
* `[N] -> array of N ...`
* `() -> function returning ...`
* `* -> pointer to ...`
4. Repeat 2 and 3 until the modifiers are exhausted.
5. Finally, read the base type. `... (base type).`
In C, postfix operators take precedence over prefix operators, and type modifiers are no exception. Therefore, `[]` and `()` bind first, then `*`. Anything inside a pair of parens `(...)` (not to be confused with function operator) binds first over anything outside.
Illustrated example:
```
int (*fptrs[10])();
      fptrs           fptrs is ...
           [10]       array of 10 ... // [] takes precedence over *
    (*         )      pointer to ...
                ()    function returning ...
int                   int
```
## Task
Given a line of variable declaration statement written in C, output the English expression that describes the line, using the method shown above.
## Input
The input is a single C statement that includes a single base type, a single variable name, zero or more type modifiers and the ending semicolon. You have to implement all the syntax elements covered above, plus:
* Both the base type and the variable name match the regular expression `[A-Za-z_][A-Za-z0-9_]*`.
* Theoretically, your program should support unlimited number of type modifiers.
You can simplify other C syntax elements in the following ways (full implementation is also welcome):
* The base type is always a single word, e.g. `int`, `float`, `uint32_t`, `myStruct`. Something like `unsigned long long` won't be tested.
* For the array notation `[N]`, the number `N` will always be a single positive integer written in base 10. Things like `int a[5+5]`, `int a[SIZE]` or `int a[0x0f]` won't be tested.
* For the function notation `()`, no parameters will be specified at all, as pointed out above.
* For whitespaces, only the space character `0x20` will be used. You can restrict your program to specific usage of whitespaces, e.g.
	+ Use only one space after the base type
	+ Use a space everywhere between tokens
* However, you cannot use two or more consecutive spaces to convey more information than being a token separator.
According to C syntax, the following three combinations are invalid, and thus won't be tested:
* `f()()` Function returning function
* `f()[N]` Function returning array
* `a[N]()` Array of N functions
C developers use these equivalent forms instead (and all of these are covered in the test cases):
* `(*f())()` Function returning *pointer to function*
* `*f()` Function returning *pointer to array's first element*
* `(*a[N])()` Array of N *pointers to function*
## Output
The output is a single English sentence. You don't need to (but you can if you wish) respect English grammar, e.g. the use of `a, an, the`, singular/plural forms, and the ending dot (period). Each word should be separated by one or more whitespaces (space, tab, newline) so the result is human-readable.
Again, here is the conversion process:
1. Start from the variable name. `(name) is ...`
2. Select the modifier with the highest precedence.
3. Read it:
* `[N] -> array of N ...`
* `() -> function returning ...`
* `* -> pointer to ...`
4. Repeat 2 and 3 until the modifiers are exhausted.
5. Finally, read the base type. `... (base type).`
## Test cases
```
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 */
```
## Scoring & Winning criterion
This is a [code-golf](/questions/tagged/code-golf "show questions tagged 'code-golf'") challenge. The program with the smallest number of bytes wins.
  
[Answer]
# [Python 3](https://docs.python.org/3/), ~~331 312 294 261~~ 240 bytes
```
from re import*
class V(str):__pos__=lambda s:V(s+'pointer to ');__call__=lambda s:V(s+'function returning ');__getitem__=lambda s,i:V(s+'array of %i '%i)
t,e=input().split()
print(eval(sub('\*','+',sub('(\w+)',r'V("\1 is ")',e[:-1],1)))+t)
```
[Try it online!](https://tio.run/##ZZBdS8MwFIbv@ysOgiTpqpjVD1jZhReCVyIyFOlKqF2qgbYJyam6Xz9P1gkTaWma5HnenBO3xQ875LvGbjQswTPGdq23PXgNpnfWY5o0XR0CPPOAXiyUcjYotezq/m1TQ1jQ@ow5awbUHtACE4VSTd11/6B2HBo0dqBsHP1ghvcJftdoUPdHfGYmo/a@3oJt4dQAOzUiwUwvzeBG5OI8uM7QmDhPZ3P9WXc8jG@crVOWsRnL9hO@/poJlnn2zE/WEkyAE5rqcnEmq0wKIWYodtR0or91w/e3kIKUYkeZYIqk7WyNkLZF0m8VXcDYoEIIpbyoiiQysSkupn8qt8yr8vKwxdPWod@zIiKHLJ46UcprgtTT7cPG9mr1@nin5Dwng3bVy@pemaBW9/KKPGLn@WVVXl3fkDJScD6nEiLJD58YOK9@2UqUET@GIzjhceB7z1Hz0YrakSjIpFqD7bXCrdPA09@nGb03eqOmlsXft/gB "Python 3 – Try It Online")
*-19 bytes by switching to python 2 and putting the class definition into an `exec`*
*-18 bytes by changing the regex from `[a-zA-Z_][a-zA-Z0-9_]*` to `\\w+`, thanks to Kevin Cruijssen*
*-33 bytes by working some class definition magic and utilising str, thanks to Lynn, changing back to python 3*
*-21 bytes by merging together multiple regexes, thanks to infmagic2047*
Requires that only one space is contained in the input (between the type and the expression).
I think this is a pretty unique approach to the problem. This mostly uses the fact that Python itself can evaluate strings like `(**((*(**(((*(((**(*p)))[2]))())))[123])[4])[5])` and gets the correct sequence of function calls, array indexes and pointers - and that the user can overload these.
[Answer]
# [Retina 0.8.2](https://github.com/m-ender/retina/wiki/The-Language/a950ad7d925ec9316e3e2fb2cf5d49fd15d23e3d), ~~142~~ ~~138~~ ~~128~~ 117 bytes
```
(\w+) (.+);
($2) $1
\(\)
 function returning
\[(\d+)?]
 array of$#1$* $1
+`\((\**)(.+)\)
$2$1
\*
 pointer to
1` 
 is 
```
[Try it online!](https://tio.run/##VY9NS8QwEIbv@RUDVphJQUzrrocexIO4JxFZEElKtuy2EnCbkqbI/vo62Q9YSUhC5nneTEIbXd/Mt/i6mdH85gR4l1MlMCsIMiUMGhLQTf02Ot9DaOMUetd/C6PR7HJ6qgU0ITQH8F12ozKZpHxjEI2UlLLYz4qUJAUM3vWxDRC9UBsQ4EaYZ74CV4nuxzcRZFeJ/cGOMUzbaCOMWt3XlUhMagLpdOYndVnrh3MJZTfEcGQpIecslANptWTIfjy/7fzerr/eX6wqSja4aj/XK@tGu16pBXvMFuVDrRfLR1YmDi4LbiGReF5SYFFf2Jp0wq/hBJ7wtOHRG4iOVtKuRGKTex39vrXxMLSA8jK2Uwiu3dnTl@n/rP4A "Retina 0.8.2 – Try It Online") Link includes test cases. [Better grammar](https://tio.run/##VY9dS8MwFEDf8ysuLMJNCmLabT70Yfgg7klEBiJNSevWSsAlJU0Z@/XzZh@gNKSFe87hNnTRuvZ0hy/NyTaIVdtZP9VipQ9SAN5nomTICwEtn@VcOuCKadSCQQv95LbRegehi1Nw1n0zXaHeZWJV09xBG0J7BN/zmeIymVmjEbWUIoUpwvOUkyk2eOtiFyB6hvorRaiwAtSHjDgFPB@ZaoCBHeF0IhZsyfof30aQfcn2RzPGMG2jiTBW6qEuWWLSiigu37RNVdTV/DpC2Q8xnFmRkGsL5SAqtSTIvD@97vzebD7fno3KCzJoaj42a2NHs1mrBXnE5sW8rhbLR1ImChc5rZBIvF4pmNc3thZVwv/CCbzg6YVnbxDibCXtjyjIpF1Hv@9MPA4doLw92ykE2@3M5ZfF/1P@Ag "Retina 0.8.2 – Try It Online"). Edit: Saved ~~10~~ 21 bytes by porting @DLosc's Pip solution. Explanation:
```
(\w+) (.+);
($2) $1
```
Move the type to the end and wrap the rest of the declaration in `()`s in case it contains an outer `*`.
```
\(\)
 function returning
```
Process any functions.
```
\[(\d+)?]
 array of$#1$* $1
```
Process any arrays.
```
+`\((\**)(.+)\)
$2$1
```
Move any pointers to the end of their brackets, and delete the brackets, repeatedly working from the outermost set of brackets inwards.
```
\*
 pointer to
```
Process any pointers.
```
1` 
 is 
```
Insert the `is`.
[Answer]
# Bash + [cdecl](https://linux.die.net/man/1/cdecl) + GNU sed, 180
`cdecl` is a venerable Unix utility that does most of what is required here, but in order to match I/O requirements, some `sed` pre- and post-processing is required:
```
sed -r 's/^/explain struct /;s/struct (int|char double|float|void) /\1 /;s/\bfunc/_func/g'|cdecl|sed -r 's/^declare //;s/as/is/;s/struct //g;s/([0-9]+) of/of \1/g;s/\b_func/func/g'
```
* No attempts made to correct grammar.
### sed Pre-processing:
* `s/^/explain struct /` - Add "explain struct " to the start of *every* line
* `s/struct (int|char double|float|void) /\1 /` - Remove `struct` when dealing with C language types
* `s/\bfunc/_func/g` - "func" is recognized as a keyword by cdecl - suppress this
### sed Post-processing:
* `s/^declare //` - remove "declare" at start of line
* `s/as/is/` - self-explanatory
* `s/struct //g` - remove all "struct" keywords
* `s/([0-9]+) of/of \1/g` - correct ordering of "of "
* `s/\b_func/func/g` - revert any "\_func" that was replaced in pre-processing
### In action:
```
$ < cdecls.txt sed -r 's/^/explain struct /;s/struct (int|char double|float|void) /\1 /;s/\bfunc/_func/g'|cdecl|sed -r 's/^declare //;s/as/is/;s/struct //g;s/([0-9]+) of/of \1/g;s/\b_func/func/g'
i is int
f is pointer to float
s is array of 10 my_struct_t
func is function returning int
arr is array of 3 array of 4 int
fptrs is array of 10 pointer to function returning int
p is pointer to array of 16 pointer to float
_WTH_is_TH15 is pointer to function returning pointer to pointer to array of 1234 array of 567 _RANdom_TYPE_123
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
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
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
$ 
```
[Answer]
# [Pip](https://github.com/dloscutoff/pip) `-s`, ~~152~~ ~~150~~ ~~148~~ ~~139~~ ~~137~~ ~~126~~ ~~125~~ ~~123~~ 120 bytes
Third approach!
```
YaRs" ("R`\[(\d+)]`` array of \1`R"()"" function returning"L#aYyR`\((\**)(.+)[);]`{c." pointer to"X#b}{[b"is"g@>2a]}Vy^s
```
Takes the declaration as a command-line input. [Try it online!](https://tio.run/##JYuxCoMwFAB/5fG65EUqqO0klH5AJ4dSiWkTrUqWGGIcRPz2VCgHN90542KsdTUjMKxUI1jzTUgqBdp7vcI0QJOpChkhwrDYLpjJgu/D4q2xIz5Oul6Pj7GGc2JpQoJKqbYuRXCTsaH3ECZ8ndp9Ey2aGcf7Lddyf67vOcZ4nuNyVEX@CcA5O/iLOxK5JEYksryQJC5SXGX5Aw "Pip – Try It Online")
## Explanation
The code is in three parts: initial setup and handling of functions and arrays; a loop that handles parentheses and pointers; and a final rearrangement.
### Setup, functions & arrays
We want the whole declaration to be parenthesized (this helps with the loop later on), so we change `type ...` into `type (...`. Then, observe that no reordering is done with the descriptions of functions and arrays, so we can perform all those replacements first without affecting the final output.
```
Y                         Yank into y variable...
 a                        The result of a (the cmdline arg)...
  R s                     Replace the space
   " ("                    with " ("
  R `\[(\d+)]`            Replace digits in square brackets
   ` array of \1`          with " array of <digits>"
  R "()"                  Replace function parens
   " function returning"   with " function returning"
```
If our original input was `float *((*p()))[16];`, we now have `float (*((*p function returning)) array of 16;`.
### Parentheses and pointers
We run a loop replacing the outermost pair of parentheses and any asterisks that are immediately inside the opening paren.
```
L#a                     Loop len(a) times (enough to complete all replacements):
 Y                      Yank into y variable...
  y                     The result of y...
   R `\((\**)(.+)[);]`  Replace open paren, 0 or more asterisks (group 1), 1 or more
                        characters (group 2), and close paren or semicolon
    {                    with this callback function (b = group 1, c = group 2):
     c .                 The stuff in the middle, concatenated to...
      " pointer to"      that string
       X #b              repeated len(asterisks) times
    }
```
Example steps:
```
float (*((*p function returning)) array of 16;
float ((*p function returning)) array of 16 pointer to
float (*p function returning) array of 16 pointer to
float p function returning pointer to array of 16 pointer to
```
### Cleanup
The only thing remaining is to move the type to the end and add "is":
```
{[b"is"g@>2a]}Vy^s
               y^s  Split y on spaces
{            }V     Use the resulting list as arguments to this function:
 [          ]        Return a list of:
  b                   2nd argument (the variable name)
   "is"               That string
       g@>2           All arguments after the 2nd
           a          1st argument (the type)
                    The resulting list is printed, joining on spaces (-s flag)
```
For definitions like `int x;`, this approach will result in an extra space, which is permitted by the challenge.
[Answer]
# Java 11, ~~469~~ ~~467~~ ~~463~~ 450 bytes
```
s->{String r="",t,S[];for(s=s.replace("()","~");s.contains("(");s=s.replace(t,"").replace("()",""),r+=t+";")t=s.replaceAll(".*(\\([^()]+\\)).*","$1");S=s.split(" ");t=S[0];r+=r.isEmpty()?S[1]:s;S=r.split(";");r=S[0].replaceAll(".*?(\\w+).*","$1 is ");for(var p:S)r+=p.replaceAll("[A-Za-z_]+\\d+|[^\\[\\d]","").replaceAll("\\[(\\d+)","array of $1 ")+(p.contains("~")?"function returning ":"")+"pointer to ".repeat(p.split("\\*").length-1);return r+t;}
```
[Try it online.](https://tio.run/##1VVbb9MwFH7frzAWD3bTRku7DalRqfYwNB6YEJmEIM2ikDgjI02CfTIoY/z1cuwma9q1GhISEupldvyd813szjfRbTS4Sb4s4zxSiryJsuLugJCsACHTKBbkQk8J8UBmxTWJWTNQ3MXn9/jBt4IIsphckIJMyFINXt41KDmhtA99zw/ctJRMTZQtRZVjX0YZp336i3JX2XFZABIrfKjnHRT0KeVbNZT3pTUBi7qUwxp7mueM2j02mzH/ivHAms04t3tY8NzBrh4iVZVnwCjBKUw8/zBwsZG0M3U2r2DB@NTznWCsECtbLHK40mC3eKZI9M1qCUimdFdt8jaSpBp7HFtXGzX@6eBjNPgRamWJ9dO/ms18HAW069EgcYFpjHYbSRktSJkSJKHcYlUnLUxvStO6iCErCyIF1LLQsdMxdrRoVZptJFASqvuLCLC8MTab9ZA1F8U1fB44aNJUE2mBe790D3BXq/pTjrvabO5tmSVkjrzNCfADEvHV2QChsCFykcxFxZkOA2fUHJF2Oc3LCEgv1YhUIzrqzNomfL4IFcg6hhCI8h3cKqxTuu4hEOeQdFCb5VqMDoZxw4cjXbojqkc6dSVS@KPAPzKkONmgHa2HR7vLWS@tQBrVvBGg59viuwH8gbAmQNaruO@cGGnVVo7r7idPxBu@O71Iynl4@eHtWegMR6gZO4fvL8/DTIWX584xKkee4ego8I9PXhi67vL2Dj420FndKRFbr2dIQbY1bSquscVoiKdBC2XNl85iGLRSA@5rtTujeULN8K/N7HzedbinR@trj1vtdOVX/2HGeMW5sa19d5xztK5PG/nfzatyLkJYVIKwXvuKaykzkYSrHzXffOsN7wL2/Nb/2OU/XX1wS5srdX2hmv@5JpPmPs2KqoZ@exmL75WIQSR844qWQtU54EVc2DEzBU243kKBmNtlDXaFSMgLRl/r9bFepdZT2LOGbozYB@r98NMY6igfm9YrTfvBbTtbfMUaxRr8lHp1HAuRiOQZ3mmvoizXo/19mgTvl78B)
**Explanation:**
```
s->{               // Method with String as both parameter and return-type
  String r="",     //  Result-String, starting empty
         t,        //  Temp-String, starting uninitialized
         S[];      //  Temp String-array, starting uninitialized
  for(s=s.replace("()","~");
                   //  Replace all "()" in the input `s` with "~"
      s.contains("(");
                   //  Loop as long as the input `s` still contains "("
      ;            //    After every iteration:
       s=s.replace(t,"")
                   //     Remove `t` from `s`
          .replace("()",""),
                   //     And also remove any redundant parenthesis groups
       r+=t+";")   //     Append `t` and a semi-colon to the result-String
    t=s.replaceAll(".*(\\([^()]+\\)).*","$1");
                   //   Set `t` to the inner-most group within parenthesis
  S=s.split(" ");  //  After the loop, split the remainder of `s` on the space
  t=S[0];          //  Set `t` to the first item (the type)
  r+=              //  Append the result-String with:
    r.isEmpty()?   //   If the result-String is empty
                   //   (so there were no parenthesis groups)
     S[1]          //    Set the result-String to the second item
    :              //   Else:
     s;            //    Simple append the remainder of `s`
  S=r.split(";");  //  Then split `r` on semi-colons
  r=S[0].replaceAll(".*?(\\w+).*",
                   //  Extract the variable name from the first item
     "$1 is ");    //  And set `r` to this name appended with " is "
  for(var p:S)     //  Loop over the parts split by semi-colons:
    r+=            //   Append the result-String with:
      p.replaceAll("[A-Za-z_]+\\d+
                   //    First remove the variable name (may contain digits)
         |[^\\[\\d]","")
                   //    And then keep only digits and "["
       .replaceAll("\\[(\\d+)",
                   //    Extract the number after "["
         "array of $1 ")
                   //    And append the result-String with "array of " and this nr
      +(p.contains("~")?
                   //    If the part contains "~"
         "function returning "
                   //     Append the result-String with "function returning "
       :           //    Else:
        "")        //     Leave the result-String the same
      +"pointer to ".repeat(
                   //    And append "pointer to " repeated
         p.split("\\*").length-1);
                   //    the amount of "*" in the part amount of time
  return r         //  Then return the result-String
          +t;}     //  appended with the temp-String (type)
```
[Answer]
# JavaScript (ES6), ~~316~~ ... ~~268~~ 253 bytes
```
s=>(g=s=>[/\d+(?=])/,/\*/,/!/,/.+ /,/\w+/].some((r,i)=>(S=s.replace(r,s=>(O=[O+`array of ${s} `,O+'pointer to ','function returning '+O,O+s,s+' is '+O][i],'')))!=s)?g(S):'',F=s=>(O='',S=s.replace(/\(([^()]*)\)/,g))!=s?O+F(S):g(s)+O)(s.split`()`.join`!`)
```
[Try it online!](https://tio.run/##vZRdj5pAFIbv/RWzmybMAIX1Y23ShppedLNXpakmTYMUKA4GowyZGXZjmv52e45fILp2r6qCMMx5z/O@DCySp0SlMi/120LM@CbzNsr7SOce7AN3OrPoyAuZa7tTE3Y3sDkWwdNnyw0dJVacUmnnDGrGnnIkL5dJymEIVXwv8K04kTJZE5GRN7/VHxLbvmWUIi80l0QLYthGVhWpzkVBJNeVLPJiTgzLh3nKVpZBcoWnYZCHtmEwxm48xUZzOmbvDcN@8HaN4LDZ351SGvykLDTZFOjn26qRbz1g2ZwqZvmMKkeVy1zHlMXOAojim5htUlEoseTOUsxpRm@Bk@QfbhkjJx/XJTmCweVOqyJbikQTM2sVQUWGFQ3r25nt8tU6UlpWqY40UUH3LtzpQLnC8mOY3TvSmNq5gI2xUnaCgRAwikIXQr9gBnWgZdAPg0FYS4EOjJ7w9OvDwUtK1MxKLbeu2J4MiXCs7a0Z06tI97FTs2RBd3hkBf2yFXvdZnh@N9qy0bdPX2ZiFU1@fP0cdXt98AA9ou@TxyhX0eSxew9OoGOvPwiD@@G7beOOa5LmlPZ9PzfUuHqBtANGsEONDp3IGZrpnuFXoNXvwVJCarrfYUS98MAdsgDRj@DtuK6jkd51Z4j@DwVEvzTetNuY0FKsHV5xj853/vGPboMo4VWCMWAOjSQYRMF2WbhknKw4SWBl/hJP3CaLSmmyEpKDv1lVzBJY02UieaHOWuObMdLrkhNqHr5pJWXOZ9HuwWSnv0P8zUkvPKevXUqY1P8ur32b7uYv "JavaScript (Node.js) – Try It Online")
## Commented
### Helper function
```
g = s =>                             // s = expression to parse
  [                                  // look for the following patterns in s:
    /\d+(?=])/,                      //   array
    /\*/,                            //   pointer
    /!/,                             //   function
    /.+ /,                           //   type
    /\w+/                            //   variable name
  ].some((r, i) =>                   // for each pattern r at index i:
    ( S = s.replace(                 //   S = new string obtained by removing
      r,                             //       the pattern matching r from s
      s => (                         //     using the first match s and the index i,
        O = [                        //     update the output O:
          O + `array of ${s} `,      //       array
          O + 'pointer to ',         //       pointer
          'function returning ' + O, //       function
          O + s,                     //       type
          s + ' is ' + O             //       variable name
        ][i],                        //
        ''                           //     replace the match with an empty string
    )))                              //   end of replace()
    != s                             //   make some() succeed if S is not equal to s
  ) ?                                // end of some(); if truthy:
    g(S)                             //   do a recursive call with S
  :                                  // else:
    ''                               //   stop recursion and return an empty string
```
### Main part
```
s => (                 // s = input
  g = …,               // define the helper function g (see above)
  F = s => (           // F = recursive function, taking a string s
    O = '',            //   O = iteration output, initialized to an empty string
    S = s.replace(     //   S = new string obtained by removing the next expression from s
      /\(([^()]*)\)/,  //     look for the deepest expression within parentheses
      g                //     and process it with the helper function g
    )                  //   end of replace()
  ) != s ?             // if S is not equal to s:
    O + F(S)           //   append O to the final output and do a recursive call with S
  :                    // else (we didn't find an expression within parentheses):
    g(s) + O           //   process the remaining expression with g and return O
)(s.split`()`.join`!`) // initial call to F with all strings '()' in s replaced with '!'
```
[Answer]
# [Perl 6](https://github.com/nxadm/rakudo-pkg), ~~209~~ ~~190~~ ~~171~~ ~~162~~ 153 bytes
```
{~({(.[1]Z'is'),.<e>.&?BLOCK,('array of'X .[2]),('function returning','pointer to'Zxx.[3,0])if $_}(m:g/(\*)*[(\w+)+|\(<e=~~>.][\[(\d+).]*(\(.)*/[1]),$0)}
```
[Try it online!](https://tio.run/##XZBta8IwEIC/@yvyQUyulmpbdbCqYxsDYWMbQ9hmGoJoIwX7Qpoyi9O/3qWt7o2EhDue5@6SNJDbURkVqCPQpNwfyZ5Y1GYLHGYYTGscTK3O1c3D0@29SfBSymWBEoHfkEUdBjol8nilwiRGMlC5jMN4g02cJmGsAolUghe7nUVds88gFKjNDyS63PSIb4BBif/Rhe6nT8bB5HicWoz6OrfugsUM4hMLjJ6eBMx2Hw6l18p0a0HaHJBIZAvrDij0sNnCYpssFTJEHUQFz5TMV4orlFG7z@psBVeTEvgO9Vuoy@jgByCGSJWsJTiBp9LESIHaowblL9eP6yTi8/fnO247rvY0wF/nMx5mfD6zh9rWuOMOGB2OLhor1x1cRw9VweR0VGUddsYZ0Mr4x1dsY1QXqdUUoBYr85cLWm7mzpIo4KpIA0SM81rlUobBmjf/AH@3h73yCw "Perl 6 – Try It Online")
Recursive regex approach. Produces some extra space characters which can be avoided [at the cost of 3 bytes](https://tio.run/##XZBra8IwFIa/@yvyQUxOLdW26mBVxzYGwsY2hrDNNATRRgr2Qpoyi9O/3qWt7kZCQg7Pk/MmaSC3ozIqUEegSbk/iu1SoT2xqM0WOMwwmNY4mFqdq5uHp9t7k@CllMsCJQK/IYs6DHRJ5PFKhUmMZKByGYfxBps4TcJYBRKpBC92O4u6Zp9BKFCbH0h0uekR3wCDEv@jC91Pn4yDyfE4tRj1dW3dBYsZxCcWGD2dBMx2/1B6rUx3FqTNAYlEtrBugEIPmy0stomObYj6EBU8UzJfKa5QRu0@q6sVXAUl8H3UT6Euo4MfgBgiVbKW4ASeriZGCtQeNSh/uX5cJxGfvz/fcdtxtacB/jqf8TDj85k91LbGHXfA6HB00Vi57uA6OlQFk9NSXeuwM86AVsY/vmIbo9pIraYAtViZv1zQcpM7S6KAqyINEDHOY5VLGQZr3vwD/J0e9sov).
### Explanation
```
{     # Anonymous block
 ~(   # Convert list to string
   {  # Block converting a regex match to a nested list
     (.[1]            # Array of 0 or 1 variable names
       Z'is'),        # zipped with string "is"
     .<e>.&?BLOCK,    # Recursive call to block with subexpression
     ('array of'      # String "array of"
       X .[2]),       # prepended to each array size
     ('function returning',  # Strings "function returning"
      'pointer to'           # and "pointer to"
      Zxx             # zipped repetition with
      .[3,0])         # number of function and pointer matches
     if $_            # Only if there's an argument
   }
   (             # Call block
     m:g/        # Input matched against regex
      (\*)*      # Sequence of asterisks, stored in [0]
      [          # Either
       (\w+)+    # the variable name, stored as 1-element array in [1]
       |         # or
       \(        # literal (
         <e=~~>  # the same regex matched recursively, stored in <e>
       .         # )
      ]
      [\[(\d+).]*  # Sequence of "[n]" with sizes stored in [2]
      (\(.)*       # Sequence of "()" stored in [3]
     /
     [1]  # Second match
   ),
   $0     # First match (base type)
 )
}
```
[Answer]
# [Clean](https://github.com/Ourous/curated-clean-linux), 415 bytes
```
import StdEnv,Text
$s#(b,[_:d])=span((<>)' ')(init s)
=join" "(?d++[""<+b])
?[]=[]
?['()':s]=["function returning": ?s]
?['*':s]= ?s++["pointer to"]
?['[':s]#(n,[_:t])=span((<>)']')s
=["array of "<+n: ?t]
?s=case@0s of(['(':h],t)= ?(init h)++ ?t;(h,t)|t>[]= ?h++ ?t=[h<+" is"]
~c=app2((++)[c],id)
@n[c:s]=case c of'('= ~c(@(n+1)s);')'|n>1= ~c(@(n-1)s)=([c],s);_|n>0= ~c(@n s)=span(\c=c<>'('&&c<>'[')[c:s]
@_ e=(e,e)
```
[Try it online!](https://tio.run/##bZHtatswFIZ/x1ch3FJLcQp10naQxEkGK3QwRlkDY6hCqLLcaMSykeRtgdJLX3bkNE0Dw8bifDzve3wk10qYbVUX7VqhSmiz1VVTW4/ufXFjfg2W6o@PTt0JfhxQPi4YyV0jDMbTGUlQQrA22iNHovxnrU2MYjwv0pTG8TR9ZCSaU5ZTBkeCSTJ2EMRla6TXtUFW@dYabZ7iMZq7rqnf9UAUJBoQ9MoiX8ddkYbiCTZhDn80B0uIi0BaWCs2qC4RuBsQ9cC5XAqnFhcO8hjGSMYrNvAETHajr0iaQucEryD77Gc0@K@6XE5X0zRG2oH/i8xF0wwxTlNCJRvogkQLQ2WYNxggCfqgnqMXiRfYpBlxZJKQ5NnMsn3yPCRzHHgocihd7EoGNrj7nweZy@kMhM7OwkkT0nlEC45UjtVAke29F3A9OeoW/mBiXIkGnSKvnId7@L1SVkW9LoImGvV6NIFFIj1J2KCLynUtPOqXb4lqw523rfQcrpJmF@ytEsBwYZgcpWDRdMTo5XEj7peNt50AeQe82uF@Q2h2fUD4t49fi7riyx93NzwbjoCHJv59ecu148vb7ApUABmOLhm9uv5wIFtwGw1h2ADg10@QH7I9wggN1H@Y0L@jwoE7vCGkgwP9jicgcPgPV1eK@02jEO7vH9laq1XBdzsixy@QALLtX1muxZPbnn/@sv20MaLSchfcrYUva1v9Aw "Clean – Try It Online")
[Answer]
# [R](https://www.r-project.org/), ~~225~~ 218 bytes
```
g=gsub
"&"="@"=paste
"["=function(a,b)a&"array of"&b
"+"=function(a)a&"pointer to"
eval(parse(t=g('\\(\\)','@"function returning"',g('(\\w+) (.*?)([A-Za-z_]\\w*)(.*);','\\2"\\3 is"\\4&"\\1"',g('\\*','+',readline())))))
```
[Try it online!](https://tio.run/##VZBRa9swEMff/SmEBrHOScpsp92DZ9o@FPowxiiBsVlGqI4cBIlkJLkjG/vs6clJus4ykrj/73@6O3fsyecl6UfTBW0N80D@EKfkZqeNIvU/ATz58LAfdzJosyW9dSQoP907a16U0cp06ritt358TuiM1vSO1oP0QSW0ofVbHrl4Bjmj0jl5ILanM6Tn7/WoDlaboPAJSxP1IndskM4rFuotSzlnnEO6SO/oxYQFh9EZLIamC0QQ@DUHwq6yW2DN/fKnXP4WLQYzwBhUaOa8oJyXRHs8VjPc8pOX8wzlebq4DIHB9B3/JrFhjzOJyhdUPIMKB8FinGgzDcRDJwPrpxjgMyaFBHshukr6nZWBZH2V7A/CBzd2QQTim/xjW01MbAdTTnecT1O2zeossawfgptYiMg5F8sGaPIbhMTT/deN3Yv1j28PIi9KdKAqvq8fhfZi/Zhfow/Zoly1zfXNJ7SMmLgssIRIsvMWExbthW2hifh7OIInPB5s8g04n@iCaVZvRkAn1urtXolwGBRh2WV1o3NabcSpZfj/r46v "R – Try It Online")
Full program, wrapped in a function on TIO for convenient testing of all test cases at once.
First, we use Regex to convert the input of the form `type ...name...;` to `..."name is"..."type"`. Function notation `()` is then converted to text with a high-precedence concatenation operator. Unfortunately, we also have to replace `*` with `+` as the former is not acceptable as an unary operator. The rest is done by R's `eval` with overloaded operators.
[Answer]
# [APL (Dyalog Unicode)](https://www.dyalog.com/), ~~192~~ 190 bytes
Saved 2 bytes thanks to [@Razetime](https://codegolf.stackexchange.com/users/80214/razetime)
```
'(\w+) is(.+);'⎕R'\2 \1'((('\*',z)⎕R'\1 pointer to'((∊'\('z'\)')(z,'\[(\d+)\]')('\(\)',⍨z←'([A-Za-z0-9_ ]+)')⎕R'\1' '(\1 array of \2)' '(\1 function returning)'))⍣≡'(\w+)(?!\]|\w)'⎕R'\1 is')
```
[Try it online!](https://tio.run/##VY/PSsNAEMbvPsV6mpmkEZPaivQgPQg9iZSCaHZZQpOUhTYb8ofS4FlUqHjxAcSLz5UXqVObHmSXhf3m@30zE@VLL95ES7vY7dL2@QNQrl0SpsQzl0bQvn9OQQZC@oCIIB3oNXQQfZFbk1VJISrLxfblDSRCA5KAsOmBDFHGLknFX66w3Gu3P81fj3DsPUZec@5daaFcBrpIENzfF1FRRBthUyED6qS0zuaVsZkokqouMpMtmKJ2@92@fh1mxutTqZ7kmuA4nymBeCsB6dJGlXDQySn0h2oEJyzq6fg2tis9e7i70X7QF@iwQ9/PJtqUejbxB4TE/qB/ocLB8LLDat65H2iOYzd2zz44UEe/onCPdEBpV4muNnki0DmeeV0UJon1fiuG/t8R/AI "APL (Dyalog Unicode) – Try It Online")
This came out longer than I thought. I may have to go back to using parser combinators instead of just plain regex again.
`z` matches an English phrase such as "foo is pointer to". The parentheses allow the capturing group to be used later.
The main train first adds " is" to such phrases, so `int (*p[3])()` becomes `int is(*p is[3])()`. The negative lookahead `(?!\]|\w)` is used to avoid matching array dimensions.
Then `⍣≡` keeps applying the substitutions to the left of it until there is nothing left to replace. First, parentheses around phrases are removed, `z[d]` is replaced with `(z array of d)`, and `z()` is replaced with `(z function returning)`. The parentheses are necessary in case there are multidimensional arrays - we don't want `*z` to be replaced before we come back to the rest of the dimensions. Then `*z` is replaced with `z pointer to`. So `int is(*p is[3])()` becomes `int is(*(p is array of 3))()` -> `int is(p is array of 3 pointer to)()` -> `int isp is array of 3 pointer to function returning`.
The last part matches the pattern `TYPE isFIRST_PART;` and rearranges it to become `FIRST_PART TYPE`.
[Answer]
# [Red](http://www.red-lang.org), 418 410 bytes
```
func[s][n: t:""a: charset[#"a"-#"z"#"A"-#"Z"#"0"-#"9""_"]parse s[remove[copy x thru" "(t: x)]to a
change[copy x[any a](n: x)]"#"]b: copy[]until[c: next find s"#"switch c/1[#"("[append
b"function returning"take/part c 2]#"["[parse c[remove[skip copy d to"]"(append b
reduce["array of"d])skip]]]#")"#";"[take c c: back back c while[#"*"= c/1][take c
c: back c append b"pointer to"]take c]]s =""]reduce[n"is"b t]]
```
[Try it online!](https://tio.run/##bVFfa9swEH/3pzguL3ZgtEnajjr0oQ@DPo1RAmMTh1FkuRFJZCHJa7Ivn53seCRbsdAdp98/yV7Xp1ddC8qa8tR0VolAwpYQS0RZgtpIH3QUE5T4aYK/cYLPqfnJzW1qHhErJJdQEITX@/aXFqp1RzhA3PgOAfNYwqGg2ILMWM@@jQAh7REk5bY/Z0VasyMfCepsNDuhSrD6EKExtobAgPBuotqAuplxohyFdE7bOltjSh5Na8Hr2Hlr7BtGudU3HCyCgjlNUKAYYqoxZtga1/tBDbFFwnzQg3Xmdd0pLVB6L4/QNlhTkeBErFRwkiWKZMDaHHIt1XbYFLxvzE5zuik@pZx0hmUjTMFogq41Nmrfew8oogBPiHS2t2gCriESnZxnLDSAqZglZn8Hza6VEabN5Wx/rEL0nYpV5L8yu6XLw77we@XFv1O@rViQuPsPnk8bF32vVFzTzu751BVi9nBFrF6fv9btvlr9@Palms0XrMK46vvqpTKhWr3M7lmLWfPFHYn7h89X5I7rYs7xEyc/b8lkTiOLCpGIH9MSZSCmkvcKrih6fhK4kChY4@pOod3rKh6dhnw6fqrz3ui6Gh6uuF5LPP0B "Red – Try It Online")
## Explanation:
```
f: func [ s ] [
    n: t: 0                                         ; n is the name, t is the type
    a: charset [ #"a"-#"z" #"A"-#"Z" #"0"-#"9" "_" ]; characters set for parsing 
    parse s[                                        ; parse the input with the following rules
        remove [ copy x thru " " ](t: x)            ; find the type, save it to t and remove it from the string
        to a                                        ; skip to the next alphanumerical symbol
        change [ copy n [ any a ] (n: x) ] "#"      ; save it to n and replace it with '#'
    ]
    b: copy [ ]                                     ; block for the modifiers 
    until [                                         ; repeat 
       c: next find s "#"                           ; find the place of the name   
       switch c/1 [                                 ; and check what is the next symbol
           #"(" [ append b "function returning"     ; if it's a '('- it's a function - add the modifier       
                  take/part c 2                     ; and drop the "()"
                ]
           #"[" [ parse c [                         ; '[' - an array
                     remove [ skip copy d to "]"    ; save the number
                             (append b reduce [     ; and add the modifier 
                                  "array of" d
                              ] )                   
                             skip ]                 ; and remove it from the string
                     ]
                ]
           #")"                                     ; a closing bracket 
           #";" [ take c                            ; or ';' - drop it
                    c: back back c                  ; go to the left 
                    while [ #"*" = c/1 ]            ; and while there are '*'
                    [
                        take c                      ; drop them
                        c: back c                   ; go to the left
                        append b "pointer to"       ; add the modifier
                    ]
                    take c                          ; drop '(' (or space)
                 ]
       ]
       s = ""                                       ; until the string is exhausted
    ]
    reduce [ n "is" b t ]                     ; display the resul
]
```
[Answer]
# JavaScript 250 Bytes [249?]
This uses 250 Bytes:
```
k=>(a=k.match(/\W|\w+/g),s=[v=j=r=""],f=y=>!j&!a[i+1]||(m=a[i],v?(r+=v=m=='['?`array of ${a[i+=3,i-2]} `:m<')'?(i+=2,"function returning "):s[j-1]=='*'?j--&&"pointer to ":""):m==')'?v=j--|i++:m<'+'?s[j++]=a[i++]:r+=a[v=i++]+" is ",f(),r+a[0]),f(i=2))
```
Explanation:
Basically, it's reading from a buffer `a`, which is the tokenized input. It continuously moves tokens from the buffer `a` to a stack `s`, until evaluation mode is triggered. Evaluation mode will consume postfix operations first `()`, `[]` from the buffer, and then it will consume the prefix operator `*` from the stack. Evaluation mode is triggered when the state is where a word would be (Either the typename is found and consumed, or an ending `)` is found and removed). Evaluation mode is deactivated when no more prefix/postfix operators are found.
```
k=>( // k is input
    a=k.match(/\W|\w+/g), // split by symbol or word
    s=[v=j=r=""], // j=0, v=false, r="", s=[]
    // s is the stack, r is the return string,
    // v is true if we're in evaluation mode (Consume (), [], *)
    // v is false if we're waiting to see a ) or token, which triggers evaluation
    // j is the index of the top of the stack (Stack pointer)
    f=y=>!j&!a[i+1]||( // !j means stack is empty, !a[i+1] means we're at the ;
        m=a[i], // Save a[i] in a variable
        v // Are we evaluating?
        ?(
        r+=v=
            m=='[' // Array
            ?`array of ${a[i+=3,i-2]} ` // Skip three tokens: "[", "10", "]"
                                        // a[i-2] is the "10"
            :m<')' // m == '('
                ?(i+=2,"function returning ") // Skip two tokens: "(", ")"
                :s[j-1]=='*' // Stack has a pointer
                    ?j--&&"pointer to " // Pop the stack
                    :"" // Set v to be false, r+=""
        )
        :m==')'
            ?v=j--|i++ // Pop the '(', skip over the ')', v = Evaluation mode
            :m<'+' // m == '*' || m == '('
                ?s[j++]=a[i++] // push(s, pop(a))
                :r+=a[v=i++]+" is " // Otherwise we have the token
        , f(), r+a[0] // Recurse f(), and return r+a[0]. a[0] is the type.
    ),
    f(i=2) // Set i=2, and call f(), which returns the final value r + type
    // a = ["type", " ", ...], so i=2 give the first real token
    // This soln assumes there is only one space, which is an allowed assumption
)
```
# NOTE
If I understand "Use a space everywhere between tokens" correctly:
```
k=>(a=k.split(" "),s=[v=j=r=""],f=y=>!j&!a[i+1]||(v?(r+=v=a[i]=='['?`array of ${a[i+=3,i-2]} `:a[i]<')'?(i+=2,"function returning "):s[j-1]=='*'?j--&&"pointer to ":""):a[i]==')'?v=j--|i++:a[i]<'+'?s[j++]=a[i++]:r+=a[v=i++]+" is ",f(),r+a[0]),f(i=1))
```
is technically valid, and uses
# 249 Bytes
Assuming that there's a space between every token.
[Answer]
# APL(NARS), chars 625, bytes 1250
```
CH←⎕D,⎕A,⎕a,'_'⋄tkn←nm←∆←''⋄in←⍬⋄⍙←lmt←lin←0
eb←{∊(1(0 1 0)(0 1)(1 0))[⍺⍺¨⍵]}
tb←{x←({⍵='[':3⋄⍵=']':4⋄⍵∊CH,' ':1⋄2}eb⍵)\⍵⋄(x≠' ')⊂x}
gt
tkn←''⋄→0×⍳⍙>lin⋄tkn←∊⍙⊃in⋄⍙+←1⋄→0×⍳(⍙>lin)∨'('≠↑tkn⋄→0×⍳')'≠↑⍙⊃in⋄tkn←tkn,⍙⊃in⋄⍙+←1
r←dcl;n
   n←0
B: gt⋄→D×⍳'*'≠↑tkn⋄n+←1⋄→B×⍳tkn≢''
D: r←ddcl⋄∆←∆,∊n⍴⊂'pointer to '
r←ddcl;q
   r←¯1⋄→0×⍳0>lmt-←1
   →A×⍳∼'('=↑tkn⋄q←dcl⋄→F×⍳')'=↑tkn⋄→0
A: →B×⍳∼(↑tkn)∊CH⋄nm←tkn⋄→F
B: r←¯2⋄→0
F: gt⋄→G×⍳∼tkn≡'()'⋄∆←∆,'function that return '⋄→F
G: →Z×⍳∼'['=↑tkn⋄∆←∆,'array of ',{''≡p←(¯1↓1↓tkn):''⋄p,' '}⋄→F
Z: r←0
r←f w;q
   nm←∆←''⋄in←tb w⋄⍙←1⋄lin←↑⍴in⋄lmt←150⋄gt⋄→A×⍳∼0>q←dcl⋄r←⍕q⋄→0
A: r←nm,' is a ',∆,1⊃in
```
this is just one traslation from C language to APL from code in the book: "Linguaggio C"
by Brian W. Kerninghan and Dennis M. Ritchie chapter 5.12. I don't know how reduce all that
because i had not understood 100% that code, and because I do not know too much on APL...
The function for exercise it is f; i think are only allowed 150 nested parentesis '(' ')'
for error return one strign with one negative value in that or the string descrition
if all is ok. It seems this is not better than the other version even if less chars because
the other sees the errors better. Some test:
```
  f 'int f()()'
f is a function that return function that return int
  f 'int a[]()'
a is a array of function that return int
  f 'int f()[]'
f is a function that return array of int
  f 'int i;'
i is a int
  f 'float *f;'
f is a pointer to float
  f 'my_struct_t s[10];'
s is a array of 10 my_struct_t
  f 'int func();'
func is a function that return int
  f 'int arr[3][4];'
arr is a array of 3 array of 4 int
  f 'int (*fptrs[10])();'
fptrs is a array of 10 pointer to function that return int
  f 'float *(*p)[16]; '
p is a pointer to array of 16 pointer to float
  f '_RANdom_TYPE_123 (**(*_WTH_is_TH15)())[1234][567];'
_WTH_is_TH15 is a pointer to function that return pointer to pointe
  r to array of 1234 array of 567 _RANdom_TYPE_123
  f 'uint32_t (**((*(**(((*(((**(*p)))[2]))())))[123])[4])[5]);'
p is a pointer to pointer to pointer to array of 2 pointer to funct
  ion that return pointer to pointer to array of 123 pointer to
   array of 4 array of 5 pointer to pointer to uint32_t
```
]