#include"mbasic.h"

extern void Expression(void);
extern void GetName(void);
extern int InFunction;
extern char current_function[];

#define MAX_FUNCTIONS		128

typedef struct
{
 char * name;
 int nr_params;
} func_decl_t;

static func_decl_t * fun_table[MAX_FUNCTIONS];

static int was_decld(char * n)
{
 int i;
 for(i=0;i<MAX_FUNCTIONS;i++)
 {
  if(fun_table[i] && !strncmp(fun_table[i]->name,n,strlen(n)) &&
     strlen(fun_table[i]->name)==strlen(n)) return i+1;
 }
 return 0;
}

int GetCurNrParams(void)
{
 int p;
 if(!(p=was_decld(current_function)))
  Error("Internal error in file %s, function %s, line %u",__FILE__,__FUNCTION__,__LINE__);
 p--;
 return fun_table[p]->nr_params;
}

static func_decl_t * new_decl(char * n)
{
 int i;
 if(was_decld(n)) Error("Trying to declare function %s twice",n);
 for(i=0;i<MAX_FUNCTIONS;i++)
 {
  if(!fun_table[i])
  {
   fun_table[i]=malloc(sizeof(func_decl_t));
   if(!fun_table[i]) Error("Not enought memory to allocate function table entry");
   fun_table[i]->name=malloc(strlen(n)+1);
   memcpy(fun_table[i]->name,n,strlen(n)+1);
   return fun_table[i];
  }
 }
 Error("Internal error: Grow MAX_FUNCTIONS in file %s",__FILE__);
}
 
void ProcessFunctionDecl(void)
{
 char tmp[128];
 char oldfunc[128];
 func_decl_t * decl;
 int k;
 if(InFunction) Error("Cannot declare function inside function");
 InFunction++;
 GetName();
 STORE_TMP(tmp);
 decl=new_decl(tmp);
 memcpy(oldfunc,current_function,strlen(current_function)+1);
 memcpy(current_function,tmp,strlen(tmp)+1);
 if(!decl) Error("Internal Error: new_decl() returned NULL (file %s)",__FILE__);
 _emit("%s:\n",tmp);
 Match('(');
 GetNum();
 decl->nr_params=atoi(current_token);
 Match(')');
 SkipWhite();
 Block();
 emit("ret\n");
 memcpy(current_function,oldfunc,strlen(oldfunc)+1);
 InFunction--;
}
 
int FuncExpression(void)
{
 int nr_pars=0;
 if(Look==')') goto NOPARM;
 for(;;)
 {
  nr_pars++;
  Expression();
  emit("push eax\n");
  SkipWhite();
  if(Look==',') 
  {
   GetChar();
   SkipWhite();
   continue;
  }
  break;
 }
NOPARM:
 emit("push ebp\n");
 emit("mov ebp,esp\n");
 return nr_pars<<2;
}
