57create_esctrie_node(
automaton* a,
int special){
68 memset(
e, 0,
sizeof(*
e));
69 e->ntype = NODE_SPECIAL;
70 if((
e->ni.id = special) == 0){
71 const size_t tsize =
sizeof(*
e->trie) * 0x80;
72 if((
e->trie = malloc(tsize)) ==
NULL){
76 memset(
e->trie, 0, tsize);
78 return esctrie_idx(a,
e);
84 for(
unsigned i = 0 ; i < a->
poolused ; ++i){
94 if(
e->ntype != NODE_SPECIAL){
95 logerror(
"can't make node type %d string",
e->ntype);
98 for(
unsigned i = 0 ; i < 0x80 ; ++i){
100 e->trie[i] = esctrie_idx(a, term);
101 }
else if(
e->trie[i] == 0){
102 e->trie[i] = esctrie_idx(a,
e);
110 if(
e->ntype != NODE_SPECIAL){
111 logerror(
"can't make node type %d function",
e->ntype);
115 logerror(
"can't make followed function");
118 e->ntype = NODE_FUNCTION;
125 if(
e->ntype == NODE_STRING){
129 if(
e->ntype != NODE_SPECIAL){
130 logerror(
"can't make node type %d string",
e->ntype);
133 for(
int i = 0 ; i < 0x80 ; ++i){
138 logerror(
"can't make %c-followed string", i);
142 esctrie* newe = esctrie_from_idx(a, create_esctrie_node(a, 0));
146 for(
int i = 0 ; i < 0x80 ; ++i){
150 e->trie[i] = esctrie_idx(a, newe);
154 for(
int i = 0 ; i < 0x80 ; ++i){
158 e->
trie[i] = esctrie_idx(a, newe);
161 if((
e->trie[0x1b] = create_esctrie_node(a, 0)) == 0){
164 e = esctrie_from_idx(a,
e->trie[0x1b]);
166 e->ntype = NODE_SPECIAL;
171 esctrie* term = esctrie_from_idx(a,
e->trie[0x07]);
172 if((
e->trie[0x1b] = create_esctrie_node(a, 0)) == 0){
175 e = esctrie_from_idx(a,
e->trie[0x1b]);
176 e->trie[
'\\'] = esctrie_idx(a, term);
178 term->
ntype = NODE_SPECIAL;
181 logdebug(
"made string: %u", esctrie_idx(a,
e));
187 unsigned eidx = esctrie_idx(a,
e);
192 unsigned termidx = create_esctrie_node(a, 0);
193 unsigned targidx = create_esctrie_node(a, 0);
194 esctrie* term = esctrie_from_idx(a, termidx);
195 esctrie* targ = esctrie_from_idx(a, targidx);
202 if(esctrie_make_kleene(a, targ, follow, term)){
205 e = esctrie_from_idx(a, eidx);
207 for(
unsigned int i = 0 ; i < 0x80 ; ++i){
210 logerror(
"drain terminator already registered");
213 e->trie[follow] = esctrie_idx(a, term);
214 }
else if(
e->trie[i] == 0){
215 e->trie[i] = esctrie_idx(a, targ);
218 targ->
kleene = esctrie_idx(a, targ);
219 return esctrie_from_idx(a,
e->trie[follow]);
229 for(
int i =
'0' ; i <=
'9' ; ++i){
230 if( (targ = esctrie_from_idx(a,
e->trie[i])) ){
231 if(targ->
ntype == NODE_NUMERIC){
232 logtrace(
"found existing phi node %u[%c]->%u", esctrie_idx(a,
e), i, esctrie_idx(a, targ));
244 logerror(
"ten non-phi links from %u", esctrie_idx(a,
e));
247 if((targ = esctrie_from_idx(a, create_esctrie_node(a, 0))) == 0){
250 targ->
ntype = NODE_NUMERIC;
251 for(
int i =
'0' ; i <=
'9' ; ++i){
252 targ->
trie[i] = esctrie_idx(a, targ);
256 return esctrie_idx(a, targ);
262 unsigned phiidx = esctrie_idx(a, phi);
263 unsigned etaidx = phi->
trie[successor];
264 esctrie* eta = esctrie_from_idx(a, etaidx);
267 if((eta = esctrie_from_idx(a, create_esctrie_node(a, 0))) ==
NULL){
270 phi = esctrie_from_idx(a, phiidx);
271 phi->
trie[successor] = esctrie_idx(a, eta);
273 return esctrie_idx(a, eta);
280 unsigned follow,
unsigned eta){
282 for(
int i =
'0' ; i <=
'9' ; ++i){
283 esctrie* chain = esctrie_from_idx(a,
e->trie[i]);
287 }
else if(chain->
ntype == NODE_SPECIAL){
289 add_phi_and_eta_chain(a, esctrie_from_idx(a,
e->trie[i]), phi, follow, eta);
292 if(
e->trie[follow] == 0){
294 e->trie[follow] = eta;
305 int pfxlen,
esctrie* phi,
unsigned follow,
311 add_phi_and_eta_chain(a,
e, esctrie_idx(a, phi), follow, esctrie_idx(a, eta));
319 logerror(
"illegal wildcard in prefix %c", *prefix);
327 unsigned linked_tri_seen_last = UINT_MAX;
328 for(
int i =
'0' ; i <=
'9' ; ++i){
331 e->trie[i] = esctrie_idx(a, phi);
333 if(
e->trie[i] != linked_tri_seen_last){
334 add_phi_and_eta_recurse(a, esctrie_from_idx(a,
e->trie[i]),
335 prefix, pfxlen, phi, follow, eta, 1);
336 linked_tri_seen_last =
e->trie[i];
343 unsigned linked_tri_seen_last = UINT_MAX;
344 for(
int i =
'0' ; i <=
'9' ; ++i){
347 e->trie[i] = esctrie_idx(a, phi);
348 }
else if(
e->trie[i] != esctrie_idx(a,
e) &&
e->trie[i] != linked_tri_seen_last){
349 add_phi_and_eta_recurse(a, esctrie_from_idx(a,
e->trie[i]),
350 prefix, pfxlen, phi, follow, eta, 1);
351 linked_tri_seen_last =
e->trie[i];
355 unsigned char p = *prefix;
357 add_phi_and_eta_recurse(a, esctrie_from_idx(a,
e->trie[p]),
358 prefix + 1, pfxlen - 1, phi, follow, eta, 0);
365add_phi_and_eta(
automaton* a,
const char* prefix,
size_t pfxlen,
371 add_phi_and_eta_recurse(a, esc, prefix, pfxlen, phi, follow, eta, 0);
388link_numeric(
automaton* a,
const char* prefix,
int pfxlen,
390 logdebug(
"adding numeric with follow %c following %*.*s", follow, pfxlen, pfxlen, prefix);
391 unsigned phiidx = get_phi_node(a,
e);
395 esctrie* phi = esctrie_from_idx(a, phiidx);
397 unsigned etaidx = get_eta_node(a, phi, follow);
401 phi = esctrie_from_idx(a, phiidx);
402 esctrie* eta = esctrie_from_idx(a, etaidx);
403 logtrace(
"phi node: %u->%u", esctrie_idx(a,
e), esctrie_idx(a, phi));
404 logtrace(
"eta node: %u philink[%c]: %u", esctrie_idx(a, eta), follow, phi->
trie[follow]);
409 add_phi_and_eta(a, prefix, pfxlen, phi, follow, eta);
414insert_path(
automaton* a,
const char* seq){
416 if((a->
escapes = create_esctrie_node(a, 0)) == 0){
421 bool inescape =
false;
422 const char* seqstart = seq;
424 while( (
c = *seq++) ){
435 logerror(
"illegal numeric terminator");
439 eptr = link_numeric(a, seqstart, seq - 3 - seqstart, eptr,
c);
443 }
else if(
c ==
'S' ||
c ==
'R'){
445 if((eptr = esctrie_make_string(a, eptr,
c ==
'R')) ==
NULL){
452 logerror(
"illegal kleene terminator");
456 eptr = link_kleene(a, eptr,
c);
466 unsigned eidx = esctrie_idx(a, eptr);
469 unsigned tidx = create_esctrie_node(a, 0);
473 eptr = esctrie_from_idx(a, eidx);
474 eptr->
trie[
c] = tidx;
475 }
else if(esctrie_from_idx(a, eptr->
trie[
c])->
ntype == NODE_NUMERIC){
480 if((newe = esctrie_from_idx(a, create_esctrie_node(a, 0))) == 0){
483 eptr = esctrie_from_idx(a, eidx);
484 for(
int i = 0 ; i < 0x80 ; ++i){
487 eptr->
trie[
c] = esctrie_idx(a, newe);
489 eptr = esctrie_from_idx(a, eidx);
490 eptr = esctrie_from_idx(a, eptr->
trie[
c]);
491 logtrace(
"added fixed %c %u as %u",
c,
c, esctrie_idx(a, eptr));
495 logerror(
"illegal escape at end of line");
503 esctrie* eptr = insert_path(a, seq);
509 return esctrie_make_function(eptr,
fxn);
515 if(esc[0] !=
NCKEY_ESC || strlen(esc) < 2){
516 logerror(
"not an escape (0x%x)", special);
519 esctrie* eptr = insert_path(a, esc + 1);
526 if(eptr->
ni.
id != special){
527 logwarn(
"already added escape (got 0x%x, wanted 0x%x)", eptr->
ni.
id, special);
530 eptr->
ni.
id = special;
537 logdebug(
"added 0x%08x to %u", special, esctrie_idx(a, eptr));
548 if(candidate >= 0x80){
549 logerror(
"eight-bit char %u in control sequence", candidate);
554 if(candidate == 0x1b && !a->
instring){
560 if(candidate == 0x1b || candidate == 0x07){
561 a->
state =
e->trie[candidate];
564 e = esctrie_from_idx(a, a->
state);
573 if((a->
state =
e->trie[candidate]) == 0){
574 if(esctrie_idx(a,
e) == a->
escapes){
575 memset(
ni, 0,
sizeof(*
ni));
580 loginfo(
"unexpected transition on %u[%u]",
581 esctrie_idx(a,
e), candidate);
584 e = esctrie_from_idx(a, a->
state);
594 memcpy(
ni, &
e->ni,
sizeof(*
ni));
int walk_automaton(automaton *a, struct inputctx *ictx, unsigned candidate, ncinput *ni)
int inputctx_add_input_escape(automaton *a, const char *esc, uint32_t special, unsigned modifiers)
uint32_t esctrie_id(const esctrie *e)
void input_free_esctrie(automaton *a)
int inputctx_add_cflow(automaton *a, const char *seq, triefunc fxn)
int(* triefunc)(struct inputctx *)
#define logerror(fmt,...)
#define logtrace(fmt,...)
#define logdebug(fmt,...)
struct esctrie * nodepool