1 //////////////////////////////////////////////////////////////////////////////
4 // ADLib, Prop and their related set of tools and documentation are in the
5 // public domain. The author(s) of this software reserve no copyrights on
6 // the source code and any code generated using the tools. You are encouraged
7 // to use ADLib and Prop to develop software, in both academic and commercial
8 // settings, and are free to incorporate any part of ADLib and Prop into
11 // Although you are under no obligation to do so, we strongly recommend that
12 // you give away all software developed using our tools.
14 // We also ask that credit be given to us when ADLib and/or Prop are used in
15 // your programs, and that this notice be preserved intact in all the source
18 // This software is still under development and we welcome any suggestions
19 // and help from the users.
23 //////////////////////////////////////////////////////////////////////////////
27 #include <AD/automata/densedfa.h>
29 //#define DEBUGMSG(e) e
32 //////////////////////////////////////////////////////////////////////////
33 // Make hidden types visible
34 //////////////////////////////////////////////////////////////////////////
35 typedef DenseDFA::Symbol Symbol
;
36 typedef DenseDFA::State State
;
38 //////////////////////////////////////////////////////////////////////////
39 // Constructor and destructor
40 //////////////////////////////////////////////////////////////////////////
41 DenseDFA::DenseDFA() : def(0) {}
42 DenseDFA::~DenseDFA() { delete [] def
; }
44 //////////////////////////////////////////////////////////////////////////
45 // Create tables for dense dfa
46 //////////////////////////////////////////////////////////////////////////
47 void DenseDFA::create_tables (int size
, int states
, Symbol min
, Symbol max
)
48 { Super::create_tables(size
,states
,min
,max
);
49 def
= new State
[number_of_states
];
50 for (int i
= 0; i
< number_of_states
; i
++) def
[i
] = 0;
53 //////////////////////////////////////////////////////////////////////////
54 // Increment the size of tables
55 //////////////////////////////////////////////////////////////////////////
56 void DenseDFA::grow_states(int increment
)
57 { State
* new_def
= new State
[number_of_states
+ increment
];
58 memcpy(new_def
, def
, number_of_states
* sizeof(State
));
59 for (int i
= number_of_states
; i
< number_of_states
+ increment
; i
++)
63 Super::grow_states(increment
);
66 //////////////////////////////////////////////////////////////////////////
67 // Start generating tabels and initialize temporary tables
68 //////////////////////////////////////////////////////////////////////////
69 void DenseDFA::start()
71 number_of_symbols
= max_symbol
- min_symbol
+ 1;
72 diffs
[0] = new State
[ number_of_symbols
];
73 diffs
[1] = new State
[ number_of_symbols
];
74 transitions
= new State
[ number_of_symbols
];
75 symbols
= new Symbol
[ number_of_symbols
];
76 my_delta
= new State
[ number_of_symbols
];
77 if (number_of_symbols
<= 32)
78 max_template_diff
= number_of_symbols
/ 3;
79 else if (number_of_symbols
<= 64)
80 max_template_diff
= number_of_symbols
/ 4;
82 max_template_diff
= number_of_symbols
/ 5;
83 max_template_diff
= number_of_symbols
/ 3;
84 max_template_diff
= number_of_symbols
;
87 // Create a template for state 0, the error state
89 templates
[0].state
= 0;
90 templates
[0].delta
= new State
[ number_of_symbols
];
92 templates
[0].uses
= 100000; // prevent us from removing this template
93 for (int i
= 0; i
< number_of_symbols
; i
++)
94 templates
[0].delta
[i
] = error_state
;
95 number_of_templates
= 1;
101 //////////////////////////////////////////////////////////////////////////
102 // Finish generating tables and free up temporary tables
103 //////////////////////////////////////////////////////////////////////////
104 void DenseDFA::finish()
106 for (int i
= 0; i
< number_of_templates
; i
++)
107 delete [] templates
[i
].delta
;
110 delete [] transitions
;
115 //////////////////////////////////////////////////////////////////////////
116 // Add a new state into the automaton
117 //////////////////////////////////////////////////////////////////////////
118 void DenseDFA::add_state
119 (State s
, int fan_out
, const Symbol syms
[], const State delta
[])
121 for (i
= number_of_symbols
- 1; i
>= 0; i
--)
122 my_delta
[i
] = error_state
;
123 for (i
= fan_out
- 1; i
>= 0; i
--)
124 my_delta
[ syms
[ i
] - min_symbol
] = delta
[ i
];
125 add_state(s
, my_delta
);
128 //////////////////////////////////////////////////////////////////////////
129 // Add a new state into the automaton
130 //////////////////////////////////////////////////////////////////////////
131 void DenseDFA::add_state(State s
, const State delta
[])
133 // First compute the current state with the set of templates.
134 // If one of the template is similar enough with the current state,
135 // use the template state as the default basis.
137 int fan_out
; // the fan out, or difference of fan out
138 int available
= 0; // index into the diffs table
139 int best_fan_out
= INT_MAX
; // mimimum fan out
140 int best_template
= -1; // template that fits the best
141 int best_diffs
= 0; // index of the minimal difference
142 const State same_state
= error_state
-1;
144 for (i
= number_of_templates
- 1; i
>= 0; i
--) {
146 // compute the difference between delta and the templates
148 register State
* a_template
= templates
[i
].delta
;
149 register State
* result
= diffs
[available
];
151 for (fan_out
= 0, j
= 0; j
< number_of_symbols
; j
++) {
152 if (a_template
[j
] != delta
[j
]) { result
[j
] = delta
[j
]; fan_out
++; }
153 else result
[j
] = same_state
;
157 // If a better template is found, update the new minimum and
158 // switch the buffer so that the minimal difference is always
159 // available in |diffs[best_diffs]|.
161 if (fan_out
< best_fan_out
) {
162 best_template
= i
; best_fan_out
= fan_out
; best_diffs
= available
;
163 available
= 1 - available
;
167 Bool using_template
; // Are we using a template
168 const State
* out
; // the final out transitions
171 // Check whether a suitable template has been located. If so,
172 // use the template as the default state; otherwise, the error state
173 // is the default state.
175 DEBUGMSG(cerr
<< "[best fan out = " << best_fan_out
176 << " max_template_diff = " << max_template_diff
);
177 if (best_template
>= 0 && best_fan_out
< max_template_diff
) {
178 out
= diffs
[best_diffs
];
179 using_template
= true;
180 templates
[best_template
].uses
++;
181 templates
[best_template
].age
= current_age
;
182 DEBUGMSG(cerr
<< " using template " << best_template
183 << " uses = " << templates
[best_template
].uses
<< "]\n");
186 using_template
= false;
187 DEBUGMSG(cerr
<< "]\n");
191 // Eliminate all transitions from the transition function that
192 // goes to the same state as our template.
194 for (fan_out
= 0, i
= number_of_symbols
- 1; i
>= 0; i
--)
195 if (out
[i
] != same_state
) {
196 symbols
[fan_out
] = i
+ min_symbol
;
197 transitions
[fan_out
] = out
[i
];
202 // Emit into the table using the regular sparse compression
203 // strategy. The idea is that hopefully we'll have a useful template
204 // most of the time and thus being able to ``thin'' out the transitions.
206 Super::add_state(s
, fan_out
, symbols
, transitions
);
209 // Emit the default state of this state, which is the state of
210 // the template if available.
212 def
[s
] = using_template
? templates
[best_template
].state
213 : (State
)error_state
;
216 // Insert new current entry into template queue if it does not
217 // have a template and if the queue is not full.
219 // if ((! using_template ||
220 // (max_template_diff - best_fan_out) < number_of_symbols / 6)
221 // && number_of_templates < Max_templates) {
224 best_fan_out
> 1 && templates
[best_template
].uses
> 10 ||
225 best_fan_out
>= number_of_symbols
/ 3;
228 { if (number_of_templates
< Max_templates
) {
229 // Create new template
230 DEBUGMSG(cerr
<< "[creating template "
231 << number_of_templates
<< "]\n");
232 templates
[number_of_templates
].state
= s
;
233 templates
[number_of_templates
].age
= current_age
;
234 templates
[number_of_templates
].uses
= 0;
236 templates
[number_of_templates
].delta
237 = new State
[ number_of_symbols
],
238 delta
,number_of_symbols
* sizeof(State
));
239 number_of_templates
++;
240 } else if (empty_slots
) {
241 // Replace template with the oldest used template
242 int min_age
= 1000000;
245 for (int j
= 1; j
< Max_templates
; j
++)
246 { if (templates
[j
].age
< min_age
)
247 { target
= j
; min_age
= templates
[j
].age
; }
248 if (templates
[j
].uses
== 0) { min_use
= j
; }
250 if (min_use
>= 0) target
= min_use
;
251 if (target
> 0 && (templates
[target
].uses
== 0 || best_fan_out
> 10))
253 DEBUGMSG(cerr
<< "[replacing template " << target
<< " with age "
254 << min_age
<< " uses = "
255 << templates
[target
].uses
<< "]\n");
256 templates
[target
].state
= s
;
257 templates
[target
].age
= current_age
;
258 templates
[target
].uses
= 0;
259 memcpy(templates
[target
].delta
, delta
,
260 number_of_symbols
* sizeof(State
));
261 } //else empty_slots = false;
267 //////////////////////////////////////////////////////////////////////////
268 // Emit C++ code that reconstructs the tables
269 //////////////////////////////////////////////////////////////////////////
270 std::ostream
& DenseDFA::gen_code (std::ostream
& out
, const char name
[]) const
272 Super::gen_code(out
,name
);
273 gen_state_table(out
,name
,"def",def
+ error_state
,max_state
-error_state
+1);
277 //////////////////////////////////////////////////////////////////////////
278 // Emit C++ code that reconstructs the tables (sans base)
279 //////////////////////////////////////////////////////////////////////////
280 std::ostream
& DenseDFA::gen_check_next_tables
281 (std::ostream
& out
, const char name
[], const char * mytype
) const
283 Super::gen_check_next_tables(out
,name
,mytype
);
284 gen_state_table(out
,name
,"def",def
+ error_state
,max_state
-error_state
+1,