/* ########################################################################

			     browser_pars.c

   File: browser_pars.c
   Path: /home/fournigault/c/X11/xcoral-2.31/browser_pars.c
   Description: 
   Created: Fri Jan 27 10:48:44 MET 1995
   Author: Dominique Leveque
   Modified: Fri Jan 27 10:48:45 MET 1995
   Last maintained by: Dominique Leveque

   RCS $Revision$ $State$
   

   ########################################################################

   Note: 

   ########################################################################

   Copyright (c) : Dominique Leveque

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

   ######################################################################## */

#if HAVE_STRING_H
#include <string.h>
#else
#include <strings.h>
#endif
#include <stdio.h>

#include "result_types.h"
#include "file_dict.h"
#include "proc_dict.h"
#include "global_dict.h"
#include "class_dict.h"
#include "browser_pars.h"
#include "browser_util.h"

FileRec*  parsed_file = Null;

ClassRec* class_cache = Null;


/*------------------------------------------------------------------------------
*/
BrowserError add_proc_impl(proc_name, proc_type, impl_line,decl,hide)
    char*      proc_name;
    ProcType   proc_type;
    LineNumber impl_line;
    unsigned   decl;
    unsigned   hide;
{
  ProcRec* current_proc;
  
  current_proc = create_proc(proc_name, decl & STATIC_PROC, parsed_file);
  if (current_proc != Null) {
    if (current_proc->_impl_file == Null) {
      current_proc->_impl_file = parsed_file;
      current_proc->_impl_line = impl_line;
      current_proc->_decl = decl;
      if ((current_proc->_hide = hide) != 0)
	HIDE(current_proc->_name);
      return(NO_BERROR);
    }
    else {
      if ( OpVerbose () == True ) {
	fprintf(stderr, "Browser :warning in %s line %d\n",
		parsed_file->_name, impl_line);
	fprintf(stderr, "          procedure \"%s\" already implemented at line %d in file %s\n",
		proc_name,
		current_proc->_impl_line,
		current_proc->_impl_file->_name);
      }
    }
  }
  return(BERROR);
}


/*------------------------------------------------------------------------------
*/
BrowserError add_global_impl(global_name, staticp, impl_line, hide)
    char*      global_name;
    int        staticp;
    LineNumber impl_line;
    unsigned   hide;
{
  GlobalRec* current_global;
  
  current_global = create_global(global_name, staticp, parsed_file->_name);
  if (current_global != Null) {
    if (current_global->_impl_file == Null) {
      current_global->_impl_file = parsed_file;
      current_global->_impl_line = impl_line;
      current_global->_static = staticp;
      if ((current_global->_hide = hide) != 0)
	HIDE(current_global->_name);
      return(NO_BERROR);
    }
    else {
      if ( OpVerbose () == True ) {
	fprintf(stderr, "Browser : warning in %s line %d\n",
		parsed_file->_name, impl_line);
	fprintf(stderr, "          variable \"%s\" already implemented at line %d in file %s\n",
		global_name,
		current_global->_impl_line,
		current_global->_impl_file->_name);
      }
    }
  }
  return(BERROR);
}



/*------------------------------------------------------------------------------
*/
BrowserError add_class_decl(class_name, decl_line, decl, hide)
    char*      class_name;
    LineNumber decl_line;
    unsigned   decl;
    unsigned   hide;
{
  ClassRec* current_class;
  
  if ((class_cache != Null) && (strcmp(class_cache->_name, class_name) == 0))
    current_class = class_cache;
  else {
    current_class = create_class(class_name, decl);
    class_cache   = current_class;
  }
  if (current_class != Null) {
    if (
	(current_class->_decl_file == Null)
	|| (ISA_TYPEDEF(current_class->_decl) && (! ISA_TYPEDEF(decl)))
	|| ((! ISA_TYPEDEF(current_class->_decl)) && 
	    (! ISA_TYPEDEF(decl)) &&
	    (! current_class->_parents_list) &&
	    (! current_class->_methods_list) &&
	    (! current_class->_attributes_list))) {
      current_class->_decl_file = parsed_file;
      current_class->_decl_line = decl_line;
      current_class->_decl = decl;
      if ((current_class->_hide = hide) != 0)
	HIDE(current_class->_name);
      return(NO_BERROR);
    }
    else {
      if ((! ((! ISA_TYPEDEF(current_class->_decl)) && ISA_TYPEDEF(decl))) &&
	  ( OpVerbose () == True )) {
	fprintf(stderr, "Browser : warning in %s line %d\n",
		parsed_file->_name, decl_line);
	fprintf(stderr, "          class \"%s\" already declared at line %d in file %s\n",
		class_name,
		current_class->_decl_line,
		current_class->_decl_file->_name);
      }
    }
  }
  return(BERROR);
}
	

/*------------------------------------------------------------------------------
*/

static int inherits_itself(current_class, parent_class)
    ClassRec*    current_class;
    ClassRec*    parent_class;
{
  ParentRec* parent_list;
  
  if (! parent_class)
    return 0;
  
  if (parent_class == current_class)
    return 1;
  
  for (parent_list = parent_class->_parents_list;
       parent_list;
       parent_list = parent_list->_next)
    if (inherits_itself(current_class, find_class(parent_list->_name)))
      return 1;
  
  return 0;
}

BrowserError add_parent(class_name, parent_name, decl_line, scope)
    char*      class_name;
    char*      parent_name;
    int        decl_line;
    ScopeType  scope; 
{
  ClassRec*    current_class;
  ParentRec*   current_parent;
  ParentRec**  head;
  int          x_size;
  
  if ((class_cache != Null) && (strcmp(class_cache->_name, class_name) == 0))
    current_class = class_cache;
  else {
    current_class = find_class(class_name);
    class_cache   = current_class;
  }
  if (current_class != Null) {
    head = & (current_class->_parents_list);
    search_Rec(parent_name, ParentRec, head, current_parent);
    if (current_parent == Null) {
      if (inherits_itself(current_class, find_class(parent_name))) {
	if ( OpVerbose () == True ) {
	  fprintf(stderr, "Browser : warning in %s line %d\n",
		  parsed_file->_name, decl_line);
	  fprintf(stderr, "          class \"%s\" inherits itself !\n",
		  class_name);
	}
	return (BERROR);
      }
      x_size = sizeof(ParentRec) + CLASS_PLENGTH + strlen(parent_name) + 1;
      current_parent = (ParentRec*) xmalloc(x_size);
      if (current_parent != Null) {
        create_Rec(parent_name, ParentRec, head, current_parent, CLASS_PREFIX, CLASS_PLENGTH);
	current_parent->_scope = scope;
	current_class->_parents_count++;
	current_parent->_decl_line = decl_line;
	return(NO_BERROR);
      }
    }
    else {
      if (current_parent->_scope == UNKNOWN_SCOPE) {
	current_parent->_scope = scope;
	current_class->_parents_count++;
	current_parent->_decl_line = decl_line;
	return(NO_BERROR);
      }
      else {
	if ( OpVerbose () == True ) {
	  fprintf(stderr, "Browser : warning in %s line %d\n",
		  parsed_file->_name, decl_line);
	  fprintf(stderr, "          For class \"%s\" parent \"%s\" already declared\n",
		  class_name, parent_name);
	}
      }
    }
  }
  else {
    if ( OpVerbose () == True ) {
      fprintf(stderr, "Browser : warning in %s line %d\n",
	      parsed_file->_name, decl_line);
      fprintf(stderr, "          class \"%s\" not declared\n",
	      class_name);
    }
  }
  return(BERROR);
}


/*------------------------------------------------------------------------------
*/
BrowserError add_method_decl(class_name, method_name, scope, decl, decl_line,
			     hide)
    char*      class_name; 
    char*      method_name;
    ScopeType  scope;
    int decl;
    LineNumber decl_line;
    unsigned   hide;
{
  ClassRec*   current_class;
  MethodRec** head;
  MethodRec*  current_method;
  int         x_size;
  
  if ((class_cache != Null) && (strcmp(class_cache->_name, class_name) == 0))
    current_class = class_cache;
  else {
    current_class = find_class(class_name);
    class_cache   = current_class;
  }
  if (current_class != Null) {
    head = & (current_class->_methods_list);
    search_Rec(method_name, MethodRec, head, current_method);
    if (current_method == Null) {
      x_size = sizeof(MethodRec) + METHOD_PLENGTH + strlen(method_name) + 1;
      current_method = (MethodRec*) xmalloc(x_size);
      if (current_method != Null) {
	create_Rec(method_name, MethodRec, head, current_method, METHOD_PREFIX, METHOD_PLENGTH);
	current_method->_class_name   = current_class->_name;
	current_method->_scope        = scope;
	current_method->_decl 	      = decl;
	current_method->_decl_file    = parsed_file;
	current_method->_decl_line    = decl_line;
	current_method->_impl_file    = Null;
	current_method->_impl_line    = 0;
	current_method->_next_marked  = Null;
	if ((current_method->_hide = hide) != 0)
	  HIDE(current_method->_name);
        return(NO_BERROR);
      }
    }
    else if (current_method->_decl_file == Null) {
      current_method->_scope        = scope;
      current_method->_decl 	    = decl;
      current_method->_decl_file    = parsed_file;
      current_method->_decl_line    = decl_line;
      if ((current_method->_hide = hide) != 0)
	HIDE(current_method->_name);
      return(NO_BERROR);
    }
    else if ( OpVerbose () == True ) {
      fprintf(stderr, "Browser : warning in %s line %d\n",
	      parsed_file->_name, decl_line);
      fprintf(stderr, "          method \"%s\" already declared at line %d in file %s\n",
	      method_name,
	      current_method->_decl_line,
	      current_method->_decl_file->_name);
    }
  }
  else {
    if ( OpVerbose () == True ) {
      fprintf(stderr, "Browser : warning in %s line %d\n",
	      parsed_file->_name, decl_line);
      fprintf(stderr, "          class \"%s\" not declared\n", class_name);
    }
  }
  return(BERROR);
}


/*------------------------------------------------------------------------------
*/
BrowserError add_method_impl(class_name, method_name, impl_line,
			     hide)
    char*      class_name;
    char*      method_name;
    LineNumber impl_line;
    unsigned    hide;
{
  ClassRec*   current_class;
  MethodRec** head;
  MethodRec*  current_method;
  int         x_size;
  
  if ((class_cache != Null) && (strcmp(class_cache->_name, class_name) == 0))
    current_class = class_cache;
  else {
    current_class = create_class(class_name, 0);
    class_cache   = current_class;
  }
  if (current_class != Null) {
    head = & (current_class->_methods_list);
    search_Rec(method_name, MethodRec, head, current_method);
    if (current_method == Null) {
      x_size = sizeof(MethodRec) + METHOD_PLENGTH + strlen(method_name) + 1;
      current_method = (MethodRec*) xmalloc(x_size);
      if (current_method != Null) {
	create_Rec(method_name, MethodRec, head, current_method, METHOD_PREFIX, METHOD_PLENGTH);
	current_method->_class_name   = current_class->_name;
	current_method->_scope        = UNKNOWN_SCOPE;
	current_method->_decl = 0;
	current_method->_decl_file    = Null;
	current_method->_decl_line    = 0;
	current_method->_impl_file    = parsed_file;
	current_method->_impl_line    = impl_line;
	current_method->_next_marked  = Null;
	if ((current_method->_hide = hide) != 0)
	  HIDE(current_method->_name);
        return(NO_BERROR);
      }
    }
    else if (current_method->_impl_file == Null) {
      current_method->_impl_file = parsed_file;
      current_method->_impl_line = impl_line;
      if ((current_method->_hide = hide) != 0)
	HIDE(current_method->_name);
      return(NO_BERROR);
    }
    else {
      if ( OpVerbose () == True ) {
	fprintf(stderr, "Browser : warning in %s line %d\n",
		parsed_file->_name, impl_line);
	fprintf(stderr, "          method \"%s\" already implemented at line %d in file %s\n",
		method_name,
		current_method->_impl_line,
		current_method->_impl_file->_name);
      }
    }
  }
  return(BERROR);
}


/*------------------------------------------------------------------------------
*/
BrowserError add_attribute_decl(class_name, attr_name, scope, decl, decl_line,
				hide)
    char*      class_name; 
    char*      attr_name;
    ScopeType  scope;
    int	       decl;
    LineNumber decl_line;
    unsigned   hide;
{
  ClassRec*   current_class;
  AttributeRec** head;
  AttributeRec*  current_attr;
  int         x_size;
  
  if ((class_cache != Null) && (strcmp(class_cache->_name, class_name) == 0))
    current_class = class_cache;
  else {
    current_class = find_class(class_name);
    class_cache   = current_class;
  }
  if (current_class != Null) {
    head = & (current_class->_attributes_list);
    search_Rec(attr_name, AttributeRec, head, current_attr);
    if (current_attr == Null) {
      x_size = sizeof(AttributeRec) + ATTRIBUTE_PLENGTH + strlen(attr_name) + 1;
      current_attr = (AttributeRec*) xmalloc(x_size);
      if (current_attr != Null) {
	create_Rec(attr_name, AttributeRec, head, current_attr, ATTRIBUTE_PREFIX, ATTRIBUTE_PLENGTH);
	current_attr->_class_name   = current_class->_name;
	current_attr->_scope        = scope;
	current_attr->_decl         = decl;
	current_attr->_decl_file    = parsed_file;
	current_attr->_decl_line    = decl_line;
	current_attr->_next_marked  = Null;
	if ((current_attr->_hide = hide) != 0)
	  HIDE(current_attr->_name);
	return(NO_BERROR);
      }
    }
    else if (current_attr->_decl_file == Null) {
      current_attr->_scope        = scope;
      current_attr->_decl_file    = parsed_file;
      current_attr->_decl_line    = decl_line;
      if ((current_attr->_hide = hide) != 0)
	HIDE(current_attr->_name);
      return(NO_BERROR);
    }
    else if ((! ATTRIBUT_IS_STATIC(current_attr->_decl)) ||
	     (! strcmp(current_attr->_decl_file->_name, parsed_file->_name))) {
      if ( OpVerbose () == True ) {
	fprintf(stderr, "Browser : warning in %s line %d\n",
		parsed_file->_name, decl_line);
	fprintf(stderr, "          attribute \"%s\" already declared at line %d in file %s\n",
		attr_name,
		current_attr->_decl_line,
		current_attr->_decl_file->_name);
      }
    }
  }
  else {
    if ( OpVerbose () == True ) {
      fprintf(stderr, "Browser : warning in %s line %d\n",
	      parsed_file->_name, decl_line);
      fprintf(stderr, "          class \"%s\" not declared\n", class_name);
    }
  }
  return(BERROR);
}

