/* This group of functions does the character class compression. | |
It goes over the dfa and relabels the arcs with the partitions | |
of characters in the NFA. The partitions are stored in the | |
array class. | |
* | |
* SOFTWARE RIGHTS | |
* | |
* We reserve no LEGAL rights to the Purdue Compiler Construction Tool | |
* Set (PCCTS) -- PCCTS is in the public domain. An individual or | |
* company may do whatever they wish with source code distributed with | |
* PCCTS or the code generated by PCCTS, including the incorporation of | |
* PCCTS, or its output, into commerical software. | |
* | |
* We encourage users to develop software with PCCTS. However, we do ask | |
* that credit is given to us for developing PCCTS. By "credit", | |
* we mean that if you incorporate our source code into one of your | |
* programs (commercial product, research project, or otherwise) that you | |
* acknowledge this fact somewhere in the documentation, research report, | |
* etc... If you like PCCTS and have developed a nice tool with the | |
* output, please mention that you developed it using PCCTS. In | |
* addition, we ask that this header remain intact in our source code. | |
* As long as these guidelines are kept, we expect to continue enhancing | |
* this system and expect to make other tools available as they are | |
* completed. | |
* | |
* DLG 1.33 | |
* Will Cohen | |
* With mods by Terence Parr; AHPCRC, University of Minnesota | |
* 1989-2001 | |
*/ | |
#include <stdio.h> | |
#include "dlg.h" | |
#ifdef MEMCHK | |
#include "trax.h" | |
#else | |
#ifdef __STDC__ | |
#include <stdlib.h> | |
#else | |
#include <malloc.h> | |
#endif /* __STDC__ */ | |
#endif | |
int class_no = CHAR_RANGE; /* number of classes for labels */ | |
int first_el[CHAR_RANGE]; /* first element in each class partition */ | |
set class_sets[CHAR_RANGE]; /* array holds partitions from class */ | |
/* compression */ | |
/* goes through labels on NFA graph and partitions the characters into | |
* character classes. This reduces the amount of space required for each | |
* dfa node, since only one arc is required each class instead of one arc | |
* for each character | |
* level: | |
* 0 no compression done | |
* 1 remove unused characters from classes | |
* 2 compress equivalent characters into same class | |
* | |
* returns the number of character classes required | |
*/ | |
#ifdef __USE_PROTOS | |
int relabel(nfa_node* start,int level) | |
#else | |
int relabel(start,level) | |
int level; | |
nfa_node *start; | |
#endif | |
{ | |
if (level){ | |
set_free(used_classes); | |
partition(start,level); | |
label_with_classes(start); | |
}else{ | |
/* classes equivalent to all characters in alphabet */ | |
class_no = CHAR_RANGE; | |
} | |
return class_no; | |
} | |
/* makes character class sets for new labels */ | |
#ifdef __USE_PROTOS | |
void partition(nfa_node* start,int level) | |
#else | |
void partition(start,level) | |
nfa_node *start; /* beginning of nfa graph */ | |
int level; /* compression level to uses */ | |
#endif | |
{ | |
set current_class; | |
set unpart_chars; | |
set temp; | |
unpart_chars = set_dup(used_chars); | |
#if 0 | |
/* EOF (-1+1) alway in class 0 */ | |
class_sets[0] = set_of(0); | |
first_el[0] = 0; | |
used_classes = set_of(0); | |
temp = set_dif(unpart_chars, class_sets[0]); | |
set_free(unpart_chars); | |
unpart_chars = temp; | |
class_no = 1; | |
#else | |
class_no = 0; | |
#endif | |
while (!set_nil(unpart_chars)){ | |
/* don't look for equivalent labels if c <= 1 */ | |
if (level <= 1){ | |
current_class = set_of(set_int(unpart_chars)); | |
}else{ | |
current_class = set_dup(unpart_chars); | |
intersect_nfa_labels(start,¤t_class); | |
} | |
set_orel(class_no,&used_classes); | |
first_el[class_no] = set_int(current_class); | |
class_sets[class_no] = current_class; | |
temp = set_dif(unpart_chars,current_class); | |
set_free(unpart_chars); | |
unpart_chars = temp; | |
++class_no; | |
} | |
/* free unpart_chars -ATG 5/6/95 */ | |
set_free(unpart_chars); | |
#if 0 | |
/* group all the other unused characters into a class */ | |
set_orel(class_no,&used_classes); | |
first_el[class_no] = set_int(current_class); | |
class_sets[class_no] = set_dif(normal_chars,used_chars); | |
++class_no; | |
#endif | |
} | |
/* given pointer to beginning of graph and recursively walks it trying | |
* to find a maximal partition. This partion in returned in maximal_class | |
*/ | |
#ifdef __USE_PROTOS | |
void intersect_nfa_labels(nfa_node* start,set* maximal_class) | |
#else | |
void intersect_nfa_labels(start,maximal_class) | |
nfa_node *start; | |
set *maximal_class; | |
#endif | |
{ | |
/* pick a new operation number */ | |
++operation_no; | |
r_intersect(start,maximal_class); | |
} | |
#ifdef __USE_PROTOS | |
void r_intersect(nfa_node* start,set* maximal_class) | |
#else | |
void r_intersect(start,maximal_class) | |
nfa_node *start; | |
set * maximal_class; | |
#endif | |
{ | |
set temp; | |
if(start && start->nfa_set != operation_no) | |
{ | |
start->nfa_set = operation_no; | |
temp = set_and(*maximal_class,start->label); | |
if (!set_nil(temp)) | |
{ | |
set_free(*maximal_class); | |
*maximal_class = temp; | |
}else{ | |
set_free(temp); | |
} | |
r_intersect(start->trans[0],maximal_class); | |
r_intersect(start->trans[1],maximal_class); | |
} | |
} | |
/* puts class labels in place of old character labels */ | |
#ifdef __USE_PROTOS | |
void label_with_classes(nfa_node* start) | |
#else | |
void label_with_classes(start) | |
nfa_node *start; | |
#endif | |
{ | |
++operation_no; | |
label_node(start); | |
} | |
#ifdef __USE_PROTOS | |
void label_node(nfa_node *start) | |
#else | |
void label_node(start) | |
nfa_node *start; | |
#endif | |
{ | |
set new_label; | |
register int i; | |
/* only do node if it hasn't been done before */ | |
if (start && start->nfa_set != operation_no){ | |
start->nfa_set = operation_no; | |
new_label = empty; | |
for (i = 0; i<class_no; ++i){ | |
/* if one element of class in old_label, | |
all elements are. */ | |
if (set_el(first_el[i],start->label)) | |
set_orel(i,&new_label); | |
} | |
set_free(start->label); | |
start->label = new_label; | |
/* do any nodes that can be reached from this one */ | |
label_node(start->trans[0]); | |
label_node(start->trans[1]); | |
} | |
} |