📄 key_list.cpp
字号:
// -*- C++ -*-// Key_List.cpp,v 4.63 2005/10/03 13:51:58 jwillemsen Exp// 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, "Key_List.cpp,v 4.63 2005/10/03 13:51:58 jwillemsen Exp")#if defined (ACE_HAS_GPERF)#include "ace/Read_Buffer.h"#include "Hash_Table.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] = 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 != '%') 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.intKey_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.intKey_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; (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.List_Node *Key_List::merge (List_Node *list1, List_Node *list2){ if (!list1) return list2; else if (!list2) return list1; else if (occurrence_sort && list1->occurrence < list2->occurrence || hash_sort && list1->hash_value > list2->hash_value || key_sort && ACE_OS::strcmp (list1->key, list2->key) >= 0) { list2->next = merge (list2->next, list1); return list2; } else { list1->next = merge (list1->next, list2); return list1; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -