determine.ha (8974B)
1 // DFA transition table 2 type dfa_transition = struct { 3 trans_states: []*dfa_transition_state, 4 }; 5 6 // DFA transition state (row) 7 type dfa_transition_state = struct { 8 states: []*state, 9 transitions: []*dfa_transition_trans, 10 }; 11 12 // DFA transition transition (col) 13 type dfa_transition_trans = struct { 14 from: *dfa_transition_state, 15 to: *dfa_transition_state, 16 input: dfa_input, 17 }; 18 19 type dfa_input = (dfa_accept | dfa_negate | dfa_dot); 20 type dfa_accept = rune; 21 type dfa_negate = []rune; 22 type dfa_dot = void; // only when gathering inputs, then use negate empty 23 24 fn dfa_transition_finish(dfa: *dfa_transition) void = { 25 for (let state .. dfa.trans_states) { 26 dfa_transition_state_finish(state); 27 free(state); 28 }; 29 free(dfa.trans_states); 30 }; 31 32 fn dfa_transition_state_finish(dfa_state: *dfa_transition_state) void = { 33 for (let trans .. dfa_state.transitions) { 34 dfa_transition_trans_finish(trans); 35 free(trans); 36 }; 37 free(dfa_state.transitions); 38 free(dfa_state.states); 39 }; 40 41 fn dfa_transition_trans_finish(dfa_trans: *dfa_transition_trans) void = { 42 if (dfa_trans.input is dfa_negate) 43 free(dfa_trans.input as dfa_negate); 44 }; 45 46 // Build a DFA from an NDFA. The input automata can then be finished. 47 export fn determine(mata: *automata) (automata | nomem) = { 48 let dfa = dfa_transition { ... }; 49 defer dfa_transition_finish(&dfa); 50 51 fill_dfa_transition(&dfa, mata.start)?; 52 53 const new = automata { 54 curindex = 0z, 55 curtree = 1z, 56 start = null: *state, 57 deterministic = true, 58 ... 59 }; 60 append(new.results, mata.results...)?; 61 62 fill_states(&new, &dfa)?; 63 new.start = new.states[0]; 64 65 return new; 66 }; 67 68 // Build a dfa transition table from a group of state. 69 fn fill_dfa_transition( 70 dfa: *dfa_transition, 71 states: *state... 72 ) (*dfa_transition_state | nomem) = { 73 let states = crawl_elipsis(states...)?; 74 defer free(states); 75 76 match (get_state(dfa, states)) { 77 case null => void; 78 case let out: *dfa_transition_state => return out; 79 }; 80 81 const dfa_state = alloc(dfa_transition_state { 82 ... 83 })?; 84 append(dfa_state.states, states...)?; 85 append(dfa.trans_states, dfa_state)?; 86 87 const all_trans = gather_trans(states)?; 88 defer free(all_trans); 89 90 const inputs = trans_inputs(all_trans)?; 91 defer free(inputs); 92 93 const groups = group_trans_input(all_trans, inputs)?; 94 defer { 95 for (let group .. groups) { 96 free(group.1); 97 }; 98 free(groups); 99 }; 100 101 for (let group .. groups) { 102 const next_states: []*state = []; 103 defer free(next_states); 104 for (let trans .. group.1) { 105 append(next_states, trans.to)?; 106 }; 107 const next = fill_dfa_transition(dfa, next_states...)?; 108 const new = alloc(dfa_transition_trans { 109 from = dfa_state, 110 to = next, 111 input = group.0, 112 })?; 113 append(dfa_state.transitions, new)?; 114 }; 115 116 return dfa_state; 117 }; 118 119 // Gather all reachable states through elipsises. 120 fn crawl_elipsis(locs: *state...) ([]*state | nomem) = { 121 let out: []*state = []; 122 for: root (let loc .. locs) { 123 for (let out .. out) if (out == loc) continue: root; 124 append(out, loc)?; 125 for: trans (let trans .. loc.transitions) { 126 if (0 != len(trans.accepts)) continue; 127 for (let out .. out) if (out == trans.to) continue: trans; 128 let new = crawl_elipsis(trans.to)?; 129 defer free(new); 130 for: new (let new .. new) 131 for (let out .. out) if (out == new) continue: new; 132 append(out, new...)?; 133 }; 134 }; 135 return out; 136 }; 137 138 // Return the dfa transition state for a group of state when already builded. 139 fn get_state( 140 dfa: *dfa_transition, 141 exp_states: []*state, 142 ) nullable *dfa_transition_state = { 143 for (let trans_state .. dfa.trans_states) { 144 if (len(trans_state.states) != len(exp_states)) 145 continue; 146 let matched = 0z; 147 for : root (let state .. trans_state.states) { 148 for (let _state .. exp_states) { 149 if (state == _state) { 150 matched += 1; 151 continue : root; 152 }; 153 }; 154 }; 155 if (matched == len(exp_states)) return trans_state; 156 }; 157 return null; 158 }; 159 160 // All trans from a group of state that are not elipsises. 161 fn gather_trans(states: []*state) ([]*transition | nomem) = { 162 let trans: []*transition = []; 163 for (let state .. states) { 164 for (let _trans .. state.transitions) { 165 if (len(_trans.accepts) == 0) { 166 continue; 167 }; 168 append(trans, _trans)?; 169 }; 170 }; 171 return trans; 172 }; 173 174 // Gather all inputs from a group of trans. 175 fn trans_inputs(trans: []*transition) ([]dfa_input | nomem) = { 176 let out: []dfa_input = []; 177 178 for (let trans .. trans) { 179 for: accept (let accept .. trans.accepts) { 180 match (accept) { 181 case dot => 182 append(out, dfa_dot)?; 183 continue; 184 case let r: rune => 185 // check already appended 186 for (let out .. out) { 187 match (out) { 188 case let out: dfa_accept => 189 if (out == r) 190 continue: accept; 191 case => void; 192 }; 193 }; 194 append(out, r)?; 195 case let r: (rune, rune) => 196 const a = r.0: u32; 197 const b = r.1: u32; 198 const min = if (a < b) a else b; 199 const max = if (a < b) b else a; 200 for: range (let i = min; i <= max; i += 1) { 201 let r = i: rune; 202 // check already appended 203 for (let out .. out) { 204 match (out) { 205 case let out: dfa_accept => 206 if (out == r) 207 continue: range; 208 case => void; 209 }; 210 }; 211 append(out, r)?; 212 }; 213 }; 214 }; 215 }; 216 217 return out; 218 }; 219 220 // Group all accepted transitions per input. 221 fn group_trans_input( 222 trans: []*transition, 223 inputs: []dfa_input 224 ) ([](dfa_input, []*transition) | nomem) = { 225 let out: [](dfa_input, []*transition) = []; 226 227 let neg: dfa_negate = []; 228 defer free(neg); 229 230 let work: []*transition = []; 231 defer free(work); 232 233 for (let input .. inputs) { 234 match (input) { 235 case dfa_dot => void; 236 case dfa_negate => abort("unreachable"); 237 case let input: dfa_accept => 238 for (let trans .. trans) { 239 if (accept(trans, input)) { 240 append(work, trans)?; 241 }; 242 }; 243 append(neg, input)?; 244 }; 245 if (len(work) != 0) { 246 append(out, (input, []))?; 247 let new = &out[len(out) - 1]; 248 append(new.1, work...)?; 249 delete(work[..]); 250 }; 251 }; 252 for: trans (let trans .. trans) { 253 for (let a .. trans.accepts) { 254 if (!(a is dot)) continue; 255 append(work, trans)?; 256 continue: trans; 257 }; 258 if (!(trans.negate)) continue; 259 let allfound = true; 260 for (let a .. trans.accepts) { 261 let found = false; 262 match (a) { 263 case let a: rune => 264 for (let input .. neg) { 265 if (input == a) { 266 found = true; 267 break; 268 }; 269 }; 270 case => found = false; 271 }; 272 if (!found) { 273 allfound = false; 274 break; 275 }; 276 }; 277 if (allfound) { 278 append(work, trans)?; 279 }; 280 }; 281 if (len(work) != 0) { 282 let newneg: dfa_negate = []; 283 append(newneg, neg...)?; 284 append(out, (newneg, []))?; 285 let new = &out[len(out) - 1]; 286 append(new.1, work...)?; 287 }; 288 289 return out; 290 }; 291 292 // Build states from a dfa transition table. 293 fn fill_states( 294 mata: *automata, 295 dfa: *dfa_transition, 296 ) (void | nomem) = { 297 // Produce a hashmap (dfa_state -> state). 298 let dfa2mata: [](*dfa_transition_state, *state) = []; 299 defer free(dfa2mata); 300 for (let dfa_state .. dfa.trans_states) { 301 const state = alloc(state { 302 index = mata.curindex, 303 result = void, 304 ... 305 })?; 306 mata.curindex += 1; 307 for (let _state .. dfa_state.states) { 308 if (_state.result is size) { 309 state.result = _state.result; 310 break; 311 }; 312 }; 313 append(dfa2mata, (dfa_state, state))?; 314 append(mata.states, state)?; 315 }; 316 317 // Add all states linearly 318 for (let i = 0z; i < len(dfa.trans_states); i += 1) { 319 const dfa_state = dfa.trans_states[i]; 320 const from = dfa2mata[i].1; 321 for: trans (let dfa_trans .. dfa_state.transitions) { 322 let to: nullable *state = null; 323 for (let dfa2mata .. dfa2mata) { 324 if (dfa2mata.0 == dfa_trans.to) { 325 to = dfa2mata.1; 326 break; 327 }; 328 }; 329 let to = to as *state; 330 331 // Append accepts to existing trans. 332 for (let trans .. from.transitions) { 333 if (trans.to != to) continue; 334 match (dfa_trans.input) { 335 case let acc: dfa_accept => 336 if (trans.negate) continue; 337 append_to_accepts(&trans.accepts, acc)?; 338 case let neg: dfa_negate => 339 if (!trans.negate) continue; 340 for (let neg .. neg) { 341 append_to_accepts(&trans.accepts, neg)?; 342 }; 343 }; 344 continue: trans; 345 }; 346 347 // Or create a new trans. 348 const trans = alloc(transition { 349 from = from, 350 to = to, 351 tree = 0, 352 ... 353 })?; 354 match (dfa_trans.input) { 355 case let acc: dfa_accept => 356 append(trans.accepts, acc)?; 357 case let neg: dfa_negate => 358 trans.negate = true; 359 for (let neg .. neg) 360 append(trans.accepts, neg)?; 361 }; 362 append(mata.transitions, trans)?; 363 append(from.transitions, trans)?; 364 }; 365 }; 366 }; 367 368 fn append_to_accepts(accepts: *[]runeset, r: rune) (void | nomem) = { 369 assert(len(accepts) != 0); 370 match (&accepts[len(accepts) - 1]) { 371 case let lastr: *rune => 372 if (*lastr: u32 == r: u32 - 1) { 373 const lastr = *lastr; 374 delete(accepts[len(accepts) - 1]); 375 append(accepts, (lastr, r))?; 376 return; 377 }; 378 case let lastrange: *(rune, rune) => 379 if (lastrange.1: u32 == r: u32 - 1) { 380 lastrange.1 = r; 381 return; 382 }; 383 }; 384 append(accepts, r)?; 385 };