/**************************************************************************************
 * Chaga compiler                                                                     *
 * Copyright (C) 2026 Robert James Bruce                                              *
 *                                                                                    *
 * This file is part of the Chaga compiler.                                           *
 *                                                                                    *
 * The Chaga compiler 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 of the License, or (at your option) any *
 * later version.                                                                     *
 *                                                                                    *
 * The Chaga compiler 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 the Chaga compiler. If not, see <https://www.gnu.org/licenses/>.        *
 **************************************************************************************/
#include "./include/chaga_compiler-diagnostic_tools.h"

void display_token (token_node *token_element)
{
  if (token_element->token != NULL)
  {
    switch (token_element->token_type)
    {
      case TOKEN_EQUAL:
        printf ("==       ");
      break;
      case TOKEN_NOT_EQUAL:
        printf ("!=       ");
      break;
      case TOKEN_LESS_THAN:
        printf ("<        ");
      break;
      case TOKEN_GREATER_THAN:
        printf (">        ");
      break;
      case TOKEN_LESS_THAN_OR_EQUAL:
        printf ("<=       ");
      break;
      case TOKEN_GREATER_THAN_OR_EQUAL:
        printf (">=       ");
      break;
      case TOKEN_IDENTIFIER:
        printf ("%s       ", token_element->token);
      break;
      case TOKEN_IDENTIFIER_INTEGER_CONSTANT:
        printf ("%s       ", token_element->token);
      break;
      case TOKEN_IDENTIFIER_FLOATING_POINT_CONSTANT:
        printf ("%s       ", token_element->token);
      break;
      case TOKEN_AND:
        printf ("&&       ");
      break;
      case TOKEN_OR:
        printf ("||       ");
      break;
      case TOKEN_NOT:
        printf ("!        ");
      break;
      case TOKEN_ARROW_OPERATOR:
        printf ("->       ");
      break;
      case TOKEN_LEFT_PARENTHESIS:
        printf ("(        ");
      break;
      case TOKEN_RIGHT_PARENTHESIS:
        printf (")        ");
      break;
      case TOKEN_PLUS:
        printf ("+        ");
      break;
      case TOKEN_MINUS:
        printf ("-        ");
      break;
      case TOKEN_ASTERISK:
        printf ("*        ");
      break;
      case TOKEN_DIVIDE:
        printf ("/        ");
      break;
      case TOKEN_MODULO:
        printf ("%%        ");
      break;
      case TOKEN_LEFT_BRACKET:
        printf ("[        ");
      break;
      case TOKEN_RIGHT_BRACKET:
        printf ("]        ");
      break;
      case TOKEN_AMPERSAND:
        printf ("&        ");
      break;
      case TOKEN_COMMA:
        printf (",        ");
      break;
      case TOKEN_UNARY_NOT:
        printf ("!        ");
      break;
      case TOKEN_SINGLE_QUOTE:
        printf ("'        ");
      break;
      case TOKEN_DOUBLE_QUOTE:
        printf ("\"       ");
      break;
      case TOKEN_STRING:
        if (token_element->token != NULL)
        {
          printf ("%s       ", token_element->token);
        }
      break;
      case TOKEN_ASSIGNMENT:
        printf ("=        ");
      break;
      case TOKEN_LEFT_CURLY_BRACE:
        printf ("{        ");
      break;
      case TOKEN_RIGHT_CURLY_BRACE:
        printf ("}        ");
      break;
      case TOKEN_SEMICOLON:
        printf (";        ");
      break;
      case TOKEN_COLON:
        printf (":        ");
      break;
      case TOKEN_PERIOD:
        printf (".        ");
      break;
      case TOKEN_TRUE:
        printf ("TRUE     ");
      break;
      case TOKEN_FALSE:
        printf ("FALSE    ");
      break;
      default:
        printf ("UNKNOWN  ");
      break;
    }
  }
}




void display_token_list (token_node *token_list)
{
  token_node *token_element;

  token_element = token_list;
  while (token_element != NULL)
  {
    display_token (token_element);
    token_element = token_element->next;
  }
  printf ("\n");
}




void display_token_list_with_line_numbers (token_node *token_list)
{
  token_node *token_element;

  token_element = token_list;
  while (token_element != NULL)
  {
    printf ("line %llu: ", token_element->line_number);
    if (token_element->token != NULL)
    {
      switch (token_element->token_type)
      {
        case TOKEN_EQUAL:
          printf ("==");
        break;
        case TOKEN_NOT_EQUAL:
          printf ("!=");
        break;
        case TOKEN_LESS_THAN:
          printf ("<");
        break;
        case TOKEN_GREATER_THAN:
          printf (">");
        break;
        case TOKEN_LESS_THAN_OR_EQUAL:
          printf ("<=");
        break;
        case TOKEN_GREATER_THAN_OR_EQUAL:
          printf (">=");
        break;
        case TOKEN_IDENTIFIER:
          printf ("%s", token_element->token);
        break;
        case TOKEN_IDENTIFIER_INTEGER_CONSTANT:
          printf ("%s", token_element->token);
        break;
        case TOKEN_IDENTIFIER_FLOATING_POINT_CONSTANT:
          printf ("%s", token_element->token);
        break;
        case TOKEN_AND:
          printf ("&&");
        break;
        case TOKEN_OR:
          printf ("||");
        break;
        case TOKEN_NOT:
          printf ("!");
        break;
        case TOKEN_ARROW_OPERATOR:
          printf ("->");
        break;
        case TOKEN_LEFT_PARENTHESIS:
          printf ("(");
        break;
        case TOKEN_RIGHT_PARENTHESIS:
          printf (")");
        break;
        case TOKEN_PLUS:
          printf ("+");
        break;
        case TOKEN_MINUS:
          printf ("-");
        break;
        case TOKEN_ASTERISK:
          printf ("*");
        break;
        case TOKEN_DIVIDE:
          printf ("/");
        break;
        case TOKEN_MODULO:
          printf ("%%");
        break;
        case TOKEN_LEFT_BRACKET:
          printf ("[");
        break;
        case TOKEN_RIGHT_BRACKET:
          printf ("]");
        break;
        case TOKEN_AMPERSAND:
          printf ("&");
        break;
        case TOKEN_COMMA:
          printf (",");
        break;
        case TOKEN_UNARY_NOT:
          printf ("!");
        break;
        case TOKEN_SINGLE_QUOTE:
          printf ("'");
        break;
        case TOKEN_DOUBLE_QUOTE:
          printf ("\"");
        break;
        case TOKEN_STRING:
          printf ("%s", token_element->token);
        break;
        case TOKEN_ASSIGNMENT:
          printf ("=");
        break;
        case TOKEN_LEFT_CURLY_BRACE:
          printf ("{");
        break;
        case TOKEN_RIGHT_CURLY_BRACE:
          printf ("}");
        break;
        case TOKEN_SEMICOLON:
          printf (";");
        break;
        case TOKEN_COLON:
          printf (":");
        break;
        case TOKEN_PERIOD:
          printf (".");
        break;
        case TOKEN_TRUE:
          printf ("TRUE");
        break;
        case TOKEN_FALSE:
          printf ("FALSE");
        break;
        default:
          printf ("UNKNOWN");
        break;
      }
    }
    putchar ('\n');
    token_element = token_element->next;
  }
}






void display_concrete_syntax_tree (cst_node *concrete_syntax_tree)
{
  char *current_token;

  if (concrete_syntax_tree != NULL)
  {
    if (concrete_syntax_tree->token != NULL)
    {
      switch (concrete_syntax_tree->token_type)
      {
        case TOKEN_EQUAL:
          printf ("==       ");
        break;
        case TOKEN_NOT_EQUAL:
          printf ("!=       ");
        break;
        case TOKEN_LESS_THAN:
          printf ("<        ");
        break;
        case TOKEN_GREATER_THAN:
          printf (">        ");
        break;
        case TOKEN_LESS_THAN_OR_EQUAL:
          printf ("<=       ");
        break;
        case TOKEN_GREATER_THAN_OR_EQUAL:
          printf (">=       ");
        break;
        case TOKEN_IDENTIFIER:
          printf ("%s       ", concrete_syntax_tree->token);
        break;
        case TOKEN_IDENTIFIER_INTEGER_CONSTANT:
          printf ("%s       ", concrete_syntax_tree->token);
        break;
        case TOKEN_IDENTIFIER_FLOATING_POINT_CONSTANT:
          printf ("%s       ", concrete_syntax_tree->token);
        break;
        case TOKEN_AND:
          printf ("&&       ");
        break;
        case TOKEN_OR:
          printf ("||       ");
        break;
        case TOKEN_NOT:
          printf ("!        ");
        break;
        case TOKEN_LEFT_PARENTHESIS:
          printf ("(        ");
        break;
        case TOKEN_RIGHT_PARENTHESIS:
          printf (")        ");
        break;
        case TOKEN_PLUS:
          printf ("+        ");
        break;
        case TOKEN_MINUS:
          printf ("-        ");
        break;
        case TOKEN_ASTERISK:
          printf ("*        ");
        break;
        case TOKEN_DIVIDE:
          printf ("/        ");
        break;
        case TOKEN_MODULO:
          printf ("%%        ");
        break;
        case TOKEN_LEFT_BRACKET:
          printf ("[        ");
        break;
        case TOKEN_RIGHT_BRACKET:
          printf ("]        ");
        break;
        case TOKEN_AMPERSAND:
          printf ("&        ");
        break;
        case TOKEN_COMMA:
          printf (",        ");
        break;
        case TOKEN_UNARY_NOT:
          printf ("!        ");
        break;
        case TOKEN_SINGLE_QUOTE:
          printf ("'        ");
        break;
        case TOKEN_DOUBLE_QUOTE:
          printf ("\"        ");
        break;
        case TOKEN_STRING:
          if (concrete_syntax_tree->token != NULL)
          {
            printf ("%s       ", concrete_syntax_tree->token);
          }
        break;
        case TOKEN_ASSIGNMENT:
          printf ("=        ");
        break;
        case TOKEN_LEFT_CURLY_BRACE:
          printf ("{        ");
        break;
        case TOKEN_RIGHT_CURLY_BRACE:
          printf ("}        ");
        break;
        case TOKEN_SEMICOLON:
          printf (";        ");
        break;
        case TOKEN_COLON:
          printf (":        ");
        break;
        case TOKEN_PERIOD:
          printf (".        ");
        break;
        case TOKEN_TRUE:
          printf ("TRUE     ");
        break;
        case TOKEN_FALSE:
          printf ("FALSE    ");
        break;
        default:
          printf ("UNKNOWN  ");
        break;
      }
    }
    if (concrete_syntax_tree->sibling != NULL)
    {
      display_concrete_syntax_tree (concrete_syntax_tree->sibling);
    }
    else
    {
      printf ("\n");
    }
    display_concrete_syntax_tree (concrete_syntax_tree->child);
  }
}   




void display_optimization_flags_in_concrete_syntax_tree (cst_node *concrete_syntax_tree)
{
  cst_node *cst_element;
  char *current_token;
  unsigned char set_statement_only_contains_integer_constants_in_numerical_expression;

  cst_element = concrete_syntax_tree;
  while (cst_element != NULL)
  {
    set_statement_only_contains_integer_constants_in_numerical_expression = cst_element->cst_optimization_flags & 0x01;
    if (set_statement_only_contains_integer_constants_in_numerical_expression == 1)
    {
      if (cst_element->token != NULL)
      {
        while (cst_element->sibling != NULL)
        {
          switch (cst_element->token_type)
          {
            case TOKEN_EQUAL:
              printf ("==  ");
            break;
            case TOKEN_NOT_EQUAL:
              printf ("!=  ");
            break;
            case TOKEN_LESS_THAN:
              printf ("<  ");
            break;
            case TOKEN_GREATER_THAN:
              printf (">  ");
            break;
            case TOKEN_LESS_THAN_OR_EQUAL:
              printf ("<=  ");
            break;
            case TOKEN_GREATER_THAN_OR_EQUAL:
              printf (">=  ");
            break;
            case TOKEN_IDENTIFIER:
              printf ("%s  ", cst_element->token);
            break;
            case TOKEN_IDENTIFIER_INTEGER_CONSTANT:
              printf ("%s  ", cst_element->token);
            break;
            case TOKEN_IDENTIFIER_FLOATING_POINT_CONSTANT:
              printf ("%s  ", cst_element->token);
            break;
            case TOKEN_AND:
              printf ("&&  ");
            break;
            case TOKEN_OR:
              printf ("||  ");
            break;
            case TOKEN_NOT:
              printf ("!  ");
            break;
            case TOKEN_ARROW_OPERATOR:
              printf ("->  ");
            break;
            case TOKEN_LEFT_PARENTHESIS:
              printf ("(  ");
            break;
            case TOKEN_RIGHT_PARENTHESIS:
              printf (")  ");
            break;
            case TOKEN_PLUS:
              printf ("+  ");
            break;
            case TOKEN_MINUS:
              printf ("-  ");
            break;
            case TOKEN_ASTERISK:
              printf ("*  ");
            break;
            case TOKEN_DIVIDE:
              printf ("/  ");
            break;
            case TOKEN_LEFT_BRACKET:
              printf ("[  ");
            break;
            case TOKEN_RIGHT_BRACKET:
              printf ("]  ");
            break;
            case TOKEN_AMPERSAND:
              printf ("&  ");
            break;
            case TOKEN_COMMA:
              printf (",  ");
            break;
            case TOKEN_UNARY_NOT:
              printf ("!  ");
            break;
            case TOKEN_SINGLE_QUOTE:
              printf ("'  ");
            break;
            case TOKEN_DOUBLE_QUOTE:
              printf ("\"  ");
            break;
            case TOKEN_STRING:
              printf ("%s  ", cst_element->token);
            break;
            case TOKEN_ASSIGNMENT:
              printf ("=  ");
            break;
            case TOKEN_LEFT_CURLY_BRACE:
              printf ("{  ");
            break;
            case TOKEN_RIGHT_CURLY_BRACE:
              printf ("}  ");
            break;
            case TOKEN_SEMICOLON:
              printf (";  ");
            break;
            case TOKEN_COLON:
              printf (":  ");
            break;
            case TOKEN_PERIOD:
              printf (".  ");
            break;
            default:
              printf ("UNKNOWN  ");
            break;
          }
          cst_element = cst_element->sibling;
        }
        switch (cst_element->token_type)
        {
          case TOKEN_EQUAL:
            printf ("==  ");
          break;
          case TOKEN_NOT_EQUAL:
            printf ("!=  ");
          break;
          case TOKEN_LESS_THAN:
            printf ("<  ");
          break;
          case TOKEN_GREATER_THAN:
            printf (">  ");
          break;
          case TOKEN_LESS_THAN_OR_EQUAL:
            printf ("<=  ");
          break;
          case TOKEN_GREATER_THAN_OR_EQUAL:
            printf (">=  ");
          break;
          case TOKEN_IDENTIFIER:
            printf ("%s  ", cst_element->token);
          break;
          case TOKEN_IDENTIFIER_INTEGER_CONSTANT:
            printf ("%s  ", cst_element->token);
          break;
          case TOKEN_IDENTIFIER_FLOATING_POINT_CONSTANT:
            printf ("%s  ", cst_element->token);
          break;
          case TOKEN_AND:
            printf ("&&  ");
          break;
          case TOKEN_OR:
            printf ("||  ");
          break;
          case TOKEN_NOT:
            printf ("!  ");
          break;
          case TOKEN_ARROW_OPERATOR:
            printf ("->  ");
          break;
          case TOKEN_LEFT_PARENTHESIS:
            printf ("(  ");
          break;
          case TOKEN_RIGHT_PARENTHESIS:
            printf (")  ");
          break;
          case TOKEN_PLUS:
            printf ("+  ");
          break;
          case TOKEN_MINUS:
            printf ("-  ");
          break;
          case TOKEN_ASTERISK:
            printf ("*  ");
          break;
          case TOKEN_DIVIDE:
            printf ("/  ");
          break;
          case TOKEN_LEFT_BRACKET:
            printf ("[  ");
          break;
          case TOKEN_RIGHT_BRACKET:
            printf ("]  ");
          break;
          case TOKEN_AMPERSAND:
            printf ("&  ");
          break;
          case TOKEN_COMMA:
            printf (",  ");
          break;
          case TOKEN_UNARY_NOT:
            printf ("!  ");
          break;
          case TOKEN_SINGLE_QUOTE:
            printf ("'  ");
          break;
          case TOKEN_DOUBLE_QUOTE:
            printf ("\"  ");
          break;
          case TOKEN_STRING:
            printf ("%s  ", cst_element->token);
          break;
          case TOKEN_ASSIGNMENT:
            printf ("=  ");
          break;
          case TOKEN_LEFT_CURLY_BRACE:
            printf ("{  ");
          break;
          case TOKEN_RIGHT_CURLY_BRACE:
            printf ("}  ");
          break;
          case TOKEN_SEMICOLON:
            printf (";  ");
          break;
          case TOKEN_COLON:
            printf (":  ");
          break;
          case TOKEN_PERIOD:
            printf (".  ");
          break;
          default:
            printf ("UNKNOWN  ");
          break;
        }
        putchar ('\n');
      }
    }   
    while (cst_element->sibling != NULL)
    {
      cst_element = cst_element->sibling;
    }
    cst_element = cst_element->child;
  }
}




void display_symbol_table (symtab_node *symbol_table)
{
  symtab_node *symbol_table_element;
  param_node *parameter_list_element;

  symbol_table_element = symbol_table;
  while (symbol_table_element != NULL)
  {
    printf ("IDENTIFIER:            ");
    if (symbol_table_element->identifier != NULL)
    {
      printf ("%s\n", symbol_table_element->identifier);
    }
    else
    {
      printf ("NULL\n");
    }
    printf ("ATTRIBUTE:             ");
    switch (symbol_table_element->attribute_type)
    {
       case _function:
         printf ("function\n");
       break;
       case _procedure:
         printf ("procedure\n");
       break;
       case _datatype:
         printf ("datatype\n");
       break;
       default:
       break;
    }
    if ((symbol_table_element->attribute_type == _function) || (symbol_table_element->attribute_type == _procedure))
    {
      printf ("PARAMETER LIST:        ");
      parameter_list_element = symbol_table_element->parameter_list;
      if (parameter_list_element == NULL)
      {
        printf ("<NULL>\n");
      }
      while (parameter_list_element != NULL)
      {
        switch (parameter_list_element->datatype)
        {
          case _int:
            printf ("int");
          break;
          case _bool:
            printf ("bool");
          break;
          case _char:
            printf ("char");
          break;
          case _date:
            printf ("date");
          break;
          case _file:
            printf ("file");
          break;
          case _time:
            printf ("time");
          break;
          case _void:
            printf ("void");
          break;
          case _float:
            printf ("float");
          break;
          case _string:
            printf ("string");
          break;
          case _complex:
            printf ("complex");
          break;
          case _pointer:
            printf ("pointer");
          break;
          case _datetime:
            printf ("datetime");
          break;
          case _attribute:
            printf ("attribute");
          break;
          case _imaginary:
            printf ("imaginary");
          break;
          default:
            printf ("UNKNOWN");
          break;
        }
        printf (" ");
        if (parameter_list_element->identifier != NULL)
        {
          printf ("%s", parameter_list_element->identifier);
        }
        else
        {
          printf ("<NULL>");
        }
        if (parameter_list_element->next != NULL)
        {
          printf ("  -->  ");
        }
        else
        {
          printf ("\n");
        }
        parameter_list_element = parameter_list_element->next;
      }
    }
    if (symbol_table_element->attribute_type == _function)
    {
      printf ("RETURN PAREMETER LIST: ");
      parameter_list_element = symbol_table_element->return_parameter_list;
      if (parameter_list_element == NULL)
      {
        printf ("<NULL>\n");
      }
      while (parameter_list_element != NULL)
      {
        switch (parameter_list_element->datatype)
        {
          case _int:
            printf ("int");
          break;
          case _bool:
            printf ("bool");
          break;
          case _char:
            printf ("char");
          break;
          case _date:
            printf ("date");
          break;
          case _file:
            printf ("file");
          break;
          case _time:
            printf ("time");
          break;
          case _void:
            printf ("void");
          break;
          case _float:
            printf ("float");
          break;
          case _string:
            printf ("string");
          break;
          case _complex:
            printf ("complex");
          break;
          case _pointer:
            printf ("pointer");
          break;
          case _datetime:
            printf ("datetime");
          break;
          case _attribute:
            printf ("attribute");
          break;
          case _imaginary:
            printf ("imaginary");
          break;
          default:
            printf ("UNKNOWN");
          break;
        }
        if (parameter_list_element->next != NULL)
        {
          printf ("  -->  ");
        }
        else
        {
          printf ("\n");
        }
        parameter_list_element = parameter_list_element->next;
      }
    }
    if (symbol_table_element->attribute_type == _datatype)
    {
      printf ("DATATYPE:              ");
      switch (symbol_table_element->datatype)
      {
        case _int:
          printf ("int\n");
        break;
        case _bool:
          printf ("bool\n");
        break;
        case _char:
          printf ("char\n");
        break;
        case _date:
          printf ("date\n");
        break;
        case _file:
          printf ("file\n");
        break;
        case _time:
          printf ("time\n");
        break;
        case _void:
          printf ("void\n");
        break;
        case _float:
          printf ("float\n");
        break;
        case _string:
          printf ("string\n");
        break;
        case _complex:
          printf ("complex\n");
        break;
        case _pointer:
          printf ("pointer\n");
        break;
        case _datetime:
          printf ("datetime\n");
        break;
        case _attribute:
          printf ("attribute\n");
        break;
        case _imaginary:
          printf ("imaginary\n");
        break;
        default:
          printf ("UNKNOWN\n");
        break;
      }
    }
    if (symbol_table_element->num_array_dimensions > 0)
    {
      printf ("NUM ARRAY DIMENSIONS:  ");
      switch (symbol_table_element->num_array_dimensions)
      {
        case 1:
          printf ("1\n");
          printf ("FIRST INDICE SIZE:     %llu\n", symbol_table_element->first_indice_size);
        break;
        case 2:
          printf ("2\n");
          printf ("FIRST INDICE SIZE:     %llu\n", symbol_table_element->first_indice_size);
          printf ("SECOND INDICE SIZE:    %llu\n", symbol_table_element->second_indice_size);
        break;
        case 3:
          printf ("3\n");
          printf ("FIRST INDICE SIZE:     %llu\n", symbol_table_element->first_indice_size);
          printf ("SECOND INDICE SIZE:    %llu\n", symbol_table_element->second_indice_size);
          printf ("THIRD INDICE SIZE:     %llu\n", symbol_table_element->third_indice_size);
        break;
        default:
        break;
      }
    }
    printf ("SCOPE LEVEL:           %llu\n", symbol_table_element->scope_level);
    printf ("is_internal_use_only_variable: ");
    if (symbol_table_element->is_internal_use_only_variable)
    {
      printf ("TRUE\n");
    }
    else
    {
      printf ("FALSE\n");
    }
    printf ("internal_use_only_stores_string_number_constants: ");
    if (symbol_table_element->internal_use_only_stores_string_number_constants)
    {
      printf ("TRUE\n");
    }
    else
    {
      printf ("FALSE\n");
    }
    printf ("internal_use_only_variable_is_available: ");
    if (symbol_table_element->internal_use_only_variable_is_available)
    {
      printf ("TRUE\n");
    }
    else
    {
      printf ("FALSE\n");
    }
    printf ("\n");
    symbol_table_element = symbol_table_element->next;
  }
}




void display_stackframe_cross_reference_table (stackframe_node *stackframe_cross_reference_table)
{
  stackframe_node *stackframe_element;
  symtab_node     *symbol_table_element;

  stackframe_element = stackframe_cross_reference_table;
  while (stackframe_element != NULL)
  { 
    symbol_table_element = stackframe_element->symbol_table_entry;
    if (symbol_table_element != NULL)
    {
      if (symbol_table_element->identifier != NULL)
      {
        printf ("%s : stack offset = %ld, stackframe storage size: %ld bytes\n", symbol_table_element->identifier, stackframe_element->stackframe_offset, stackframe_element->storage_size_in_bytes);
      }
    }
    stackframe_element = stackframe_element->next;
  }
}




void display_abstract_syntax_tree (ast_node *abstract_syntax_tree)
{
  char *current_token;
  int current_token_type;

  if (abstract_syntax_tree != NULL)
  {
    current_token_type = abstract_syntax_tree->token_type;
    current_token = abstract_syntax_tree->token;
    if (current_token != NULL)
    {
      switch (current_token_type)
      {
        case TOKEN_EQUAL:
          printf ("==       ");
        break;
        case TOKEN_NOT_EQUAL:
          printf ("!=       ");
        break;
        case TOKEN_LESS_THAN:
          printf ("<        ");
        break;
        case TOKEN_GREATER_THAN:
          printf (">        ");
        break;
        case TOKEN_LESS_THAN_OR_EQUAL:
          printf ("<=       ");
        break;
        case TOKEN_GREATER_THAN_OR_EQUAL:
          printf (">=       ");
        break;
        case TOKEN_IDENTIFIER:
          printf ("%s        ", current_token);
        break;
        case TOKEN_IDENTIFIER_INTEGER_CONSTANT:
          printf ("%s        ", current_token);
        break;
        case TOKEN_IDENTIFIER_FLOATING_POINT_CONSTANT:
          printf ("%s       ", current_token);
        break;
        case TOKEN_AND:
          printf ("&&       ");
        break;
        case TOKEN_OR:
          printf ("||       ");
        break;
        case TOKEN_NOT:
          printf ("!        ");
        break;
        case TOKEN_ARROW_OPERATOR:
          printf ("->       ");
        break;
        case TOKEN_LEFT_PARENTHESIS:
          printf ("(        ");
        break;
        case TOKEN_RIGHT_PARENTHESIS:
          printf (")        ");
        break;
        case TOKEN_PLUS:
          printf ("+        ");
        break;
        case TOKEN_MINUS:
          printf ("-        ");
        break;
        case TOKEN_ASTERISK:
          printf ("*        ");
        break;
        case TOKEN_DIVIDE:
          printf ("/        ");
        break;
        case TOKEN_MODULO:
          printf ("%%        ");
        break;
        case TOKEN_LEFT_BRACKET:
          printf ("[        ");
        break;
        case TOKEN_RIGHT_BRACKET:
          printf ("]        ");
        break;
        case TOKEN_AMPERSAND:
          printf ("&        ");
        break;
        case TOKEN_COMMA:
          printf (",        ");
        break;
        case TOKEN_UNARY_NOT:
          printf ("!        ");
        break;
        case TOKEN_SINGLE_QUOTE:
          printf ("'        ");
        break;
        case TOKEN_DOUBLE_QUOTE:
          printf ("\"        ");
        break;
        case TOKEN_STRING:
          printf ("%s        ", current_token);
        break;
        case TOKEN_ASSIGNMENT:
          printf ("=        ");
        break;
        case TOKEN_LEFT_CURLY_BRACE:
          printf ("{        ");
        break;
        case TOKEN_RIGHT_CURLY_BRACE:
          printf ("}        ");
        break;
        case TOKEN_SEMICOLON:
          printf (";        ");
        break;
        case TOKEN_COLON:
          printf (":        ");
        break;
        case TOKEN_PERIOD:
          printf (".        ");
        break;
        case TOKEN_TRUE:
          printf ("TRUE     ");
        break;
        case TOKEN_FALSE:
          printf ("FALSE    ");
        break;
        default:
          printf ("UNKNOWN  ");
        break;
      }
    }
    if (abstract_syntax_tree->sibling != NULL)
    {
      display_abstract_syntax_tree (abstract_syntax_tree->sibling);
    }
    else
    {
      printf ("\n");
    }
    display_abstract_syntax_tree (abstract_syntax_tree->child);
  }
}   




void display_expression_stack (expression_stack_node *expression_stack)
{
  expression_stack_node *expression_stack_element;

  expression_stack_element = expression_stack;
  while (expression_stack_element != NULL)
  {
    if (expression_stack_element->token != NULL)
    {
      if (expression_stack_element->token != NULL)
      {
        printf (" --> %s ", expression_stack_element->token);
      }
    }
    else
    {
      if (expression_stack_element->temporary_variable_identifier != NULL)
      {
        printf (" --> %s ", expression_stack_element->temporary_variable_identifier);
      }
    }
    expression_stack_element = expression_stack_element->next;
  }
  printf (" --> NULL\n");
}




void display_statement_stack (statement_stack_node *statement_stack)
{
  statement_stack_node *statement_stack_element;

  statement_stack_element = statement_stack;
  while (statement_stack_element != NULL)
  {
    switch (statement_stack_element->statement_type)
    {
      case _break:
        printf (" --> break ");
      break;
      case _case:
        printf (" --> case ");
      break;
      case _call:
        printf (" --> call ");
      break;
      case _default:
        printf (" --> default ");
      break;
      case _define:
        printf (" --> define (%llu) ", statement_stack_element->left_curly_brace_count_before_this_statement);
      break;
      case _declare:
        printf (" --> declare ");
      break;
      case _do:
        printf (" --> do ");
      break;
      case _else:
        printf (" --> else (%llu) ", statement_stack_element->left_curly_brace_count_before_this_statement);
      break;
      case _for:
        printf (" --> for ");
      break;
      case _if:
        printf (" --> if (%llu) ", statement_stack_element->left_curly_brace_count_before_this_statement);
      break;
      case _print:
        printf (" --> print ");
      break;
      case _return:
        printf (" --> return ");
      break;
      case _set:
        printf (" --> set ");
      break;
      case _step:
        printf (" --> step ");
      break;
      case _switch:
        printf (" --> switch ");
      break;
      case _then:
        printf (" --> then ");
      break;
      case _to:
        printf (" --> to ");
      break;
      case _while:
        printf (" --> while ");
      break;
      case _left_curly_brace:
        printf (" --> { ");
      break;
      case _right_curly_brace:
        printf (" --> } ");
      break;
      default:
        printf (" --> UNKNOWN ");
      break;
    }
    statement_stack_element = statement_stack_element->next;
  }
  printf (" --> NULL\n");
}




void display_file_buffer (char *file_buffer, size_t file_buffer_size)
{
  size_t i;

  for (i = 0; i < file_buffer_size; i++)
  {
    putchar (file_buffer[i]);
  }
}
