/* do not edit automatically generated by mc from symbolKey.  */
/* symbolKey.mod provides binary tree operations for storing symbols.

Copyright (C) 2015-2025 Free Software Foundation, Inc.
Contributed by Gaius Mulley <gaius@glam.ac.uk>.

This file is part of GNU Modula-2.

GNU Modula-2 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 3, or (at your option)
any later version.

GNU Modula-2 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 GNU Modula-2; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */

#include "config.h"
#include "system.h"
#include <stdbool.h>
#   if !defined (PROC_D)
#      define PROC_D
       typedef void (*PROC_t) (void);
       typedef struct { PROC_t proc; } PROC;
#   endif

#   if !defined (FALSE)
#      define FALSE (1==0)
#   endif

#   include "GStorage.h"
#if defined(__cplusplus)
#   undef NULL
#   define NULL 0
#endif
#define _symbolKey_C

#include "GsymbolKey.h"
#   include "GStorage.h"
#   include "GStrIO.h"
#   include "GNumberIO.h"
#   include "GDebug.h"
#   include "GnameKey.h"

#   define symbolKey_NulKey NULL
typedef struct symbolKey_isSymbol_p symbolKey_isSymbol;

typedef struct symbolKey_performOperation_p symbolKey_performOperation;

typedef struct symbolKey__T1_r symbolKey__T1;

typedef symbolKey__T1 *symbolKey_symbolTree__opaque;

struct symbolKey__T1_r {
                         nameKey_Name name;
                         void * key;
                         symbolKey_symbolTree__opaque left;
                         symbolKey_symbolTree__opaque right;
                       };

extern "C" symbolKey_symbolTree symbolKey_initTree (void);
extern "C" void symbolKey_killTree (symbolKey_symbolTree *t);
extern "C" void * symbolKey_getSymKey (symbolKey_symbolTree t, nameKey_Name name);
extern "C" void symbolKey_putSymKey (symbolKey_symbolTree t, nameKey_Name name, void * key);

/*
   delSymKey - deletes an entry in the binary tree.

               NB in order for this to work we must ensure that the InitTree sets
               both left and right to NIL.
*/

extern "C" void symbolKey_delSymKey (symbolKey_symbolTree t, nameKey_Name name);

/*
   isEmptyTree - returns true if symbolTree, t, is empty.
*/

extern "C" bool symbolKey_isEmptyTree (symbolKey_symbolTree t);

/*
   doesTreeContainAny - returns true if symbolTree, t, contains any
                        symbols which in turn return true when procedure,
                        p, is called with a symbol as its parameter.
                        The symbolTree root is empty apart from the field,
                        left, hence we need two procedures.
*/

extern "C" bool symbolKey_doesTreeContainAny (symbolKey_symbolTree t, symbolKey_isSymbol p);

/*
   foreachNodeDo - for each node in symbolTree, t, a procedure, p,
                   is called with the node symbol as its parameter.
                   The tree root node only contains a legal left pointer,
                   therefore we need two procedures to examine this tree.
*/

extern "C" void symbolKey_foreachNodeDo (symbolKey_symbolTree t, symbolKey_performOperation p);

/*
   findNodeAndParentInTree - find a node, child, in a binary tree, t, with name equal to n.
                             if an entry is found, father is set to the node above child.
*/

static void findNodeAndParentInTree (symbolKey_symbolTree__opaque t, nameKey_Name n, symbolKey_symbolTree__opaque *child, symbolKey_symbolTree__opaque *father);

/*
   searchForAny - performs the search required for doesTreeContainAny.
                  The root node always contains a nul data value,
                  therefore we must skip over it.
*/

static bool searchForAny (symbolKey_symbolTree__opaque t, symbolKey_isSymbol p);

/*
   searchAndDo - searches all the nodes in symbolTree, t, and
                 calls procedure, p, with a node as its parameter.
                 It traverse the tree in order.
*/

static void searchAndDo (symbolKey_symbolTree__opaque t, symbolKey_performOperation p);


/*
   findNodeAndParentInTree - find a node, child, in a binary tree, t, with name equal to n.
                             if an entry is found, father is set to the node above child.
*/

static void findNodeAndParentInTree (symbolKey_symbolTree__opaque t, nameKey_Name n, symbolKey_symbolTree__opaque *child, symbolKey_symbolTree__opaque *father)
{
  /* remember to skip the sentinal value and assign father and child  */
  (*father) = t;
  if (t == NULL)
    {
      Debug_Halt ((const char *) "parameter t should never be NIL", 31, (const char *) "../../gcc/m2/mc/symbolKey.mod", 29, (const char *) "findNodeAndParentInTree", 23, 203);
    }
  (*child) = t->left;
  if ((*child) != NULL)
    {
      do {
        if (n < (*child)->name)
          {
            (*father) = (*child);
            (*child) = (*child)->left;
          }
        else if (n > (*child)->name)
          {
            /* avoid dangling else.  */
            (*father) = (*child);
            (*child) = (*child)->right;
          }
      } while (! (((*child) == NULL) || (n == (*child)->name)));
    }
}


/*
   searchForAny - performs the search required for doesTreeContainAny.
                  The root node always contains a nul data value,
                  therefore we must skip over it.
*/

static bool searchForAny (symbolKey_symbolTree__opaque t, symbolKey_isSymbol p)
{
  if (t == NULL)
    {
      return false;
    }
  else
    {
      return (((*p.proc) (t->key)) || (searchForAny (t->left, p))) || (searchForAny (t->right, p));
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   searchAndDo - searches all the nodes in symbolTree, t, and
                 calls procedure, p, with a node as its parameter.
                 It traverse the tree in order.
*/

static void searchAndDo (symbolKey_symbolTree__opaque t, symbolKey_performOperation p)
{
  if (t != NULL)
    {
      searchAndDo (t->right, p);
      (*p.proc) (t->key);
      searchAndDo (t->left, p);
    }
}

extern "C" symbolKey_symbolTree symbolKey_initTree (void)
{
  symbolKey_symbolTree__opaque t;

  Storage_ALLOCATE ((void **) &t, sizeof (symbolKey__T1));  /* The value entity  */
  t->left = static_cast<symbolKey_symbolTree__opaque> (NULL);
  t->right = static_cast<symbolKey_symbolTree__opaque> (NULL);
  return static_cast<symbolKey_symbolTree> (t);
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}

extern "C" void symbolKey_killTree (symbolKey_symbolTree *t)
{
  if ((*t) != NULL)
    {
      symbolKey_killTree (reinterpret_cast<symbolKey_symbolTree *> (&static_cast<symbolKey_symbolTree__opaque> ((*t))->left));
      symbolKey_killTree (reinterpret_cast<symbolKey_symbolTree *> (&static_cast<symbolKey_symbolTree__opaque> ((*t))->right));
      Storage_DEALLOCATE ((void **) &(*t), sizeof (symbolKey__T1));
      (*t) = static_cast<symbolKey_symbolTree> (NULL);
    }
}

extern "C" void * symbolKey_getSymKey (symbolKey_symbolTree t, nameKey_Name name)
{
  symbolKey_symbolTree__opaque father;
  symbolKey_symbolTree__opaque child;

  if (t == NULL)
    {
      return symbolKey_NulKey;
    }
  else
    {
      findNodeAndParentInTree (static_cast<symbolKey_symbolTree__opaque> (t), name, &child, &father);
      if (child == NULL)
        {
          return symbolKey_NulKey;
        }
      else
        {
          return child->key;
        }
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}

extern "C" void symbolKey_putSymKey (symbolKey_symbolTree t, nameKey_Name name, void * key)
{
  symbolKey_symbolTree__opaque father;
  symbolKey_symbolTree__opaque child;

  findNodeAndParentInTree (static_cast<symbolKey_symbolTree__opaque> (t), name, &child, &father);
  if (child == NULL)
    {
      /* no child found, now is name less than father or greater?  */
      if (father == t)
        {
          /* empty tree, add it to the left branch of t  */
          Storage_ALLOCATE ((void **) &child, sizeof (symbolKey__T1));
          father->left = child;
        }
      else
        {
          if (name < father->name)
            {
              Storage_ALLOCATE ((void **) &child, sizeof (symbolKey__T1));
              father->left = child;
            }
          else if (name > father->name)
            {
              /* avoid dangling else.  */
              Storage_ALLOCATE ((void **) &child, sizeof (symbolKey__T1));
              father->right = child;
            }
        }
      child->right = static_cast<symbolKey_symbolTree__opaque> (NULL);
      child->left = static_cast<symbolKey_symbolTree__opaque> (NULL);
      child->key = key;
      child->name = name;
    }
  else
    {
      Debug_Halt ((const char *) "symbol already stored", 21, (const char *) "../../gcc/m2/mc/symbolKey.mod", 29, (const char *) "putSymKey", 9, 119);
    }
}


/*
   delSymKey - deletes an entry in the binary tree.

               NB in order for this to work we must ensure that the InitTree sets
               both left and right to NIL.
*/

extern "C" void symbolKey_delSymKey (symbolKey_symbolTree t, nameKey_Name name)
{
  symbolKey_symbolTree__opaque i;
  symbolKey_symbolTree__opaque child;
  symbolKey_symbolTree__opaque father;

  findNodeAndParentInTree (static_cast<symbolKey_symbolTree__opaque> (t), name, &child, &father);  /* find father and child of the node  */
  if ((child != NULL) && (child->name == name))
    {
      /* Have found the node to be deleted  */
      if (father->right == child)
        {
          /* most branch of child^.left.  */
          if (child->left != NULL)
            {
              /* Scan for right most node of child^.left  */
              i = child->left;
              while (i->right != NULL)
                {
                  i = i->right;
                }
              i->right = child->right;
              father->right = child->left;
            }
          else
            {
              /* (as in a single linked list) to child^.right  */
              father->right = child->right;
            }
          Storage_DEALLOCATE ((void **) &child, sizeof (symbolKey__T1));
        }
      else
        {
          /* branch of child^.right  */
          if (child->right != NULL)
            {
              /* Scan for left most node of child^.right  */
              i = child->right;
              while (i->left != NULL)
                {
                  i = i->left;
                }
              i->left = child->left;
              father->left = child->right;
            }
          else
            {
              /* (as in a single linked list) to child^.left.  */
              father->left = child->left;
            }
          Storage_DEALLOCATE ((void **) &child, sizeof (symbolKey__T1));
        }
    }
  else
    {
      Debug_Halt ((const char *) "trying to delete a symbol that is not in the tree - the compiler never expects this to occur", 92, (const char *) "../../gcc/m2/mc/symbolKey.mod", 29, (const char *) "delSymKey", 9, 186);
    }
}


/*
   isEmptyTree - returns true if symbolTree, t, is empty.
*/

extern "C" bool symbolKey_isEmptyTree (symbolKey_symbolTree t)
{
  return static_cast<symbolKey_symbolTree__opaque> (t)->left == NULL;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   doesTreeContainAny - returns true if symbolTree, t, contains any
                        symbols which in turn return true when procedure,
                        p, is called with a symbol as its parameter.
                        The symbolTree root is empty apart from the field,
                        left, hence we need two procedures.
*/

extern "C" bool symbolKey_doesTreeContainAny (symbolKey_symbolTree t, symbolKey_isSymbol p)
{
  return searchForAny (static_cast<symbolKey_symbolTree__opaque> (t)->left, p);
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   foreachNodeDo - for each node in symbolTree, t, a procedure, p,
                   is called with the node symbol as its parameter.
                   The tree root node only contains a legal left pointer,
                   therefore we need two procedures to examine this tree.
*/

extern "C" void symbolKey_foreachNodeDo (symbolKey_symbolTree t, symbolKey_performOperation p)
{
  searchAndDo (static_cast<symbolKey_symbolTree__opaque> (t)->left, p);
}

extern "C" void _M2_symbolKey_init (__attribute__((unused)) int argc, __attribute__((unused)) char *argv[], __attribute__((unused)) char *envp[])
{
}

extern "C" void _M2_symbolKey_fini (__attribute__((unused)) int argc, __attribute__((unused)) char *argv[], __attribute__((unused)) char *envp[])
{
}