| /* 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]); | |
| } | |
| } |