⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 key_list.cpp

📁 最新的版本ACE-5.6.8,刚从外文网上搬下,与大家分享.
💻 CPP
📖 第 1 页 / 共 5 页
字号:
// -*- C++ -*-

// $Id: Key_List.cpp 84218 2009-01-22 19:21:39Z mitza $

// Copyright (C) 1989 Free Software Foundation, Inc.
// written by Douglas C. Schmidt (schmidt@cs.wustl.edu)

// This file is part of GNU GPERF.

// 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
// of the License, 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

#include "Key_List.h"

ACE_RCSID(src, Key_List, "$Id: Key_List.cpp 84218 2009-01-22 19:21:39Z mitza $")

#if defined (ACE_HAS_GPERF)

#include "Hash_Table.h"
#include "ace/Read_Buffer.h"
#include "ace/Auto_Ptr.h"
#include "ace/OS_Memory.h"
#include "ace/OS_NS_stdio.h"
#include "ace/OS_NS_string.h"

// Default type for generated code.
const char *const Key_List::default_array_type = "char *";

// in_word_set return type, by default.
const char *const Key_List::default_return_type = "char *";

// How wide the printed field width must be to contain the maximum
// hash value.
int Key_List::field_width = 0;
int Key_List::determined_[ACE_STANDARD_CHARACTER_SET_SIZE];

// Destructor dumps diagnostics during debugging.

Key_List::~Key_List (void)
{
  if (option[DEBUGGING])
    this->dump ();

  // Free up all the nodes in the list.
  while (this->head != 0)
    {
      List_Node *temp;

      // Make sure to delete the linked nodes, as well.
      for (List_Node *ptr = this->head->link;
           ptr != 0;
           ptr = temp)
        {
          temp = ptr->link;
          delete ptr;
        }

      temp = this->head->next;
      delete this->head;
      this->head = temp;
    }
}

// Gathers the input stream into a buffer until one of two things occur:
//
// 1. We read a '%' followed by a '%'
// 2. We read a '%' followed by a '}'
//
// The first symbolizes the beginning of the keyword list proper, The
// second symbolizes the end of the C source code to be generated
// verbatim in the output file.
//
// I assume that the keys are separated from the optional preceding
// struct declaration by a consecutive % followed by either % or }
// starting in the first column. The code below uses an expandible
// buffer to scan off and return a pointer to all the code (if any)
// appearing before the delimiter.

char *
Key_List::special_input (char delimiter)
{
  int size = 80;
  char *buf = 0;
  ACE_NEW_RETURN (buf,
                  char[size],
                  0);
  int c;

  for (int i = 0; (c = getchar ()) != EOF; i++)
    {
      if (c == '%')
        {
          c = getchar ();
          if (c == delimiter)
            {
              // Discard newline...
              while ((c = getchar ()) != '\n')
                continue;

              if (i == 0)
                {
                  buf[0] = '\0';
                  return buf;
                }
              else
                {
                  buf[delimiter == '%' && buf[i - 2] == ';'
                     ? i - 2
                     : i - 1] = '\0';
                  return buf;
                }
            }
          else
            buf[i++] = '%';
        }
      else if (i >= size)
        {
          // Yikes, time to grow the buffer!

          char *temp = 0;
          ACE_NEW_RETURN (temp,
                          char[size *= 2],
                          0);
          for (int j = 0; j < i; j++)
            temp[j] = buf[j];

          delete [] buf;
          buf = temp;
        }
      buf[i] = static_cast<char> (c);
    }

  return 0;
}

// Stores any C/C++ source code that must be included verbatim into
// the generated code output.

char *
Key_List::save_include_src (void)
{
  int c = getchar ();

  if (c != '%')
    ACE_OS::ungetc (c, stdin);
  else if ((c = getchar ()) != '{')
    ACE_ERROR_RETURN ((LM_ERROR,
                       "internal error, %c != '{' on line %l in file %N",
                       c),
                       0);
  else
    return special_input ('}');
  return (char *) "";
}

// Determines from the input file whether the user wants to build a
// table from a user-defined struct, or whether the user is content to
// simply use the default array of keys.

char *
Key_List::array_type (void)
{
  return special_input ('%');
}

// Sets up the Return_Type, the Struct_Tag type and the Array_Type
// based upon various user Options.

int
Key_List::output_types (void)
{
  if (option[TYPE])
    {
      array_type_ = array_type ();
      if (array_type_ == 0)
        // Something's wrong, but we'll catch it later on....
        return -1;
      else
        {
          // Yow, we've got a user-defined type...
          size_t struct_tag_length = ACE_OS::strcspn (array_type_,
                                                      "{\n\0");
          if (option[POINTER])      // And it must return a pointer...
            {
              ACE_NEW_RETURN (return_type,
                              char[struct_tag_length + 2],
                              -1);
              ACE_OS::strncpy (return_type,
                               array_type_,
                               struct_tag_length);
              return_type[struct_tag_length] = '*';
              return_type[struct_tag_length + 1] = '\0';
            }

          ACE_NEW_RETURN (struct_tag,
                          char[struct_tag_length + 2],
                          -1);
          ACE_OS::strncpy (struct_tag,
                           array_type_,
                           struct_tag_length);
          if (struct_tag[struct_tag_length] != ' ')
            {
              struct_tag[struct_tag_length] = ' ';
              struct_tag_length++;
            }
          struct_tag[struct_tag_length] = '\0';
        }
    }
  else if (option[POINTER])     // Return a char *.
    return_type = (char *) Key_List::default_array_type;
  return 0;
}

// Reads in all keys from standard input and creates a linked list
// pointed to by Head.  This list is then quickly checked for
// ``links,'' i.e., unhashable elements possessing identical key sets
// and lengths.

int
Key_List::read_keys (void)
{
  this->include_src = this->save_include_src ();
  if (this->include_src == 0)
    return -1;
  else if (this->output_types () == -1)
    return -1;
  else
    {
      ACE_Read_Buffer input (stdin);

      char *buffer = input.read ('\n');

      if (buffer == 0)
        ACE_ERROR_RETURN ((LM_ERROR,
                           "No words in input file, did you forget to prepend %%%%"
                           " or use -t accidentally?\n"),
                          -1);
      // Read in all the keywords from the input file.
      else
        {
          List_Node *temp = 0;
          const char *delimiter = option.delimiter ();
          ACE_NEW_RETURN (this->head,
                          List_Node (buffer,
                                     static_cast<int> (ACE_OS::strcspn (buffer,
                                                        delimiter))),
                          -1);
          for (temp = this->head;
               (0 != (buffer = input.read ('\n')))
                 && ACE_OS::strcmp (buffer, "%%");
               temp = temp->next)
            {
              ACE_NEW_RETURN (temp->next,
                              List_Node (buffer,
                                         static_cast<int> (ACE_OS::strcspn (buffer,
                                                            delimiter))),
                              -1);
              this->total_keys++;
            }

          // See if any additional source code is included at end of
          // this file.
          if (buffer)
            additional_code = 1;

          this->list_len = this->total_keys;

          // Make large hash table for efficiency.
          Hash_Table table (this->list_len * Key_List::TABLE_MULTIPLE);
          List_Node *trail = 0;

          // Test whether there are any links and also set the maximum
          // length an identifier in the keyword list.

          for (temp = head;
               temp != 0;
               temp = temp->next)
            {
              List_Node *ptr = table.find (temp, option[NOLENGTH]);

              // Check for static key links.  We deal with these by
              // building an equivalence class of all duplicate values
              // (i.e., links) so that only 1 keyword is
              // representative of the entire collection.  This
              // *greatly* simplifies processing during later stages
              // of the program.

              if (ptr == 0)
                trail = temp;
              else
                {
                  total_duplicates++;
                  list_len--;
                  trail->next = temp->next;
                  temp->link = ptr->link;
                  ptr->link = temp;

                  // Complain if user hasn't enabled the duplicate
                  // option.
                  if (!option[DUP] || option[DEBUGGING])
                    ACE_ERROR ((LM_ERROR,
                                "Static key link: \"%s\" = \"%s\", with key set \"%s\".\n",
                                temp->key,
                                ptr->key,
                                temp->keysig));
                }

              // Update minimum and maximum keyword length, if needed.
              if (max_key_len < temp->length)
                max_key_len = temp->length;
              if (min_key_len > temp->length)
                min_key_len = temp->length;
            }
        }

      // Exit program if links exists and option[DUP] not set, since
      // we can't continue.
      if (total_duplicates)
        {
          if (option[DUP])
            {
              if (!option[MUTE])
                ACE_ERROR_RETURN ((LM_ERROR,
                                   "%d input keysigs have identical hash values, examine output carefully...\n",
                                   total_duplicates),
                                   0);
            }
          else
            ACE_ERROR_RETURN ((LM_ERROR,
                               "%d input keysigs have identical hash values,\ntry different key positions or use option -D.\n",
                               total_duplicates),
                              -1);
        }
      if (option[ALLCHARS])
        option.keysig_size (max_key_len);
    }

  return 0;
}

// Recursively merges two sorted lists together to form one sorted
// list. The ordering criteria is by frequency of occurrence of
// elements in the key set or by the hash value.  This is a kludge,
// but permits nice sharing of almost identical code without incurring
// the overhead of a function call comparison.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -