#include<stdio.h>

int g0( int a) { printf("<g0(%d) called> ",a) ; return a ; }
int g1( int a) { printf("<g1(%d) called> ",a) ; return a+100 ; }
int g2( int a) { printf("<g2(%d) called> ",a) ; return a+200; }
int g3( int a) { printf("<g3(%d) called> ",a) ; return a+300 ; }

/* function taking integer and returning 
    a pointer to a function which returns int */

int (*f(int a))() { 
   switch (a) { 
   case 1: return g1 ;
   case 2: return g2 ;
   case 3: return g3 ;
   default: return g0 ;
} }

/* notes, on mips, (*f(int a))(void) doesn't work, let alone
   (*f(int a))(int).
   on gcc, only () or (int) works, (void) and (double) are
   type mismatches.
   
   Harbinson & Steele indicate that the parameter list is not
   part of function type, and therefore () is the ONLY true
   method. (int, int) is no standard, say in following:
*/

int gg1( int i, int j ) { return i+j ; }
int gg2( int i, int j ) { return i-j ; }
int gg0( int i, int j ) { return i*j ; }

/* compiles w/o warnings on both mips and gcc, recommended style  */
int (*ff(int a))() {
   switch(a) {
   case 1:  return gg1 ;
   case 2:  return gg2 ;
   default: return gg0 ;
} }

/* compiles only on gcc
int (*ff(int a))(int, int) {
   switch(a) {
   case 1:  return gg1 ;
   case 2:  return gg2 ;
   default: return gg0 ;
} }
*/

/* warning on gcc, does not complile on cc 
int (*ff(int a))(void) {
   switch(a) {
   case 1:  return gg1 ;
   case 2:  return gg2 ;
   default: return gg0 ;
} }
*/

/* summary: mips seems to not locate "a" correctly if parenthesises
   following are not empty. Gcc goes right to the problem, and something
   like int (*f())(int a) leaves "a" undefined. mips cc reverses things,
   letting (int a) be the parameter of the function now begin defined,
   and () standing for the type of the return. */

main() {
  int (*h(int))(int) ;
  int i, j ;
  for (i=0;i<4;i++) for (j=0;j<4;j++) 
    printf("(f(%d))(%d) = %d\n",j,i,(f(j))(i)) ;
}

