Bug Summary

File:minimize.c
Warning:line 155, column 24
Access to field 'index' results in a dereference of a null pointer (loaded from variable 'Agenda_head')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name minimize.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/tmp/build/foma/foma-0.10.0+g279~a2d32b38 -resource-dir /usr/lib/llvm-16/lib/clang/16 -D _GNU_SOURCE -I /tmp/build/foma/foma-0.10.0+g279~a2d32b38 -internal-isystem /usr/lib/llvm-16/lib/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-missing-field-initializers -Wno-deprecated -Wno-unused-parameter -std=c18 -fdebug-compilation-dir=/tmp/build/foma/foma-0.10.0+g279~a2d32b38 -ferror-limit 19 -fvisibility=hidden -fgnuc-version=4.2.1 -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/build/foma/scan-build/2024-09-11-155945-2678-1 -x c /tmp/build/foma/foma-0.10.0+g279~a2d32b38/minimize.c
1/* Foma: a finite-state toolkit and library. */
2/* Copyright © 2008-2021 Mans Hulden */
3
4/* This file is part of foma. */
5
6/* Licensed under the Apache License, Version 2.0 (the "License"); */
7/* you may not use this file except in compliance with the License. */
8/* You may obtain a copy of the License at */
9
10/* http://www.apache.org/licenses/LICENSE-2.0 */
11
12/* Unless required by applicable law or agreed to in writing, software */
13/* distributed under the License is distributed on an "AS IS" BASIS, */
14/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
15/* See the License for the specific language governing permissions and */
16/* limitations under the License. */
17
18#include <stdlib.h>
19#include <assert.h>
20#include <limits.h>
21#include <stdint.h>
22#include "foma.h"
23
24static struct fsm *fsm_minimize_brz(struct fsm *net);
25static struct fsm *fsm_minimize_hop(struct fsm *net);
26static struct fsm *rebuild_machine(struct fsm *net);
27
28static int *single_sigma_array, *double_sigma_array, *memo_table, *temp_move, *temp_group, maxsigma, epsilon_symbol, num_states, num_symbols, num_finals, mainloop, total_states;
29
30static _Bool *finals;
31
32struct statesym {
33 int target;
34 unsigned short int symbol;
35 struct state_list *states;
36 struct statesym *next;
37};
38
39struct state_list {
40 int state;
41 struct state_list *next;
42};
43
44struct p {
45 struct e *first_e;
46 struct e *last_e;
47 struct p *current_split;
48 struct p *next;
49 struct agenda *agenda;
50 int count;
51 int t_count;
52 int inv_count;
53 int inv_t_count;
54};
55
56struct e {
57 struct p *group;
58 struct e *left;
59 struct e *right;
60 int inv_count;
61};
62
63struct agenda {
64 struct p *p;
65 struct agenda *next;
66 _Bool index;
67};
68
69struct trans_list {
70 int inout;
71 int source;
72} *trans_list_minimize;
73
74struct trans_array {
75 struct trans_list *transitions;
76 unsigned int size;
77 unsigned int tail;
78} *trans_array_minimize;
79
80
81
82static struct p *P, *Phead, *Pnext, *current_w;
83static struct e *E;
84static struct agenda *Agenda_head, *Agenda_top, *Agenda_next, *Agenda;
85
86static INLINEinline int refine_states(int sym);
87static void init_PE();
88static void agenda_add(struct p *pptr, int start);
89static void sigma_to_pairs(struct fsm *net);
90/* static void single_symbol_to_symbol_pair(int symbol, int *symbol_in, int *symbol_out); */
91static INLINEinline int symbol_pair_to_single_symbol(int in, int out);
92static void generate_inverse(struct fsm *net);
93
94struct fsm *fsm_minimize(struct fsm *net) {
95 extern int g_minimal;
96 extern int g_minimize_hopcroft;
97
98 if (net == NULL((void*)0)) { return NULL((void*)0); }
1
Assuming 'net' is not equal to NULL
2
Taking false branch
99 /* The network needs to be deterministic and trim before we minimize */
100 if (net->is_deterministic != YES1)
3
Assuming field 'is_deterministic' is equal to YES
4
Taking false branch
101 net = fsm_determinize(net);
102 if (net->is_pruned != YES1)
5
Assuming field 'is_pruned' is equal to YES
103 net = fsm_coaccessible(net);
104 if (net->is_minimized != YES1 && g_minimal == 1) {
6
Assuming field 'is_minimized' is not equal to YES
7
Assuming 'g_minimal' is equal to 1
8
Taking true branch
105 if (g_minimize_hopcroft != 0) {
9
Assuming 'g_minimize_hopcroft' is not equal to 0
10
Taking true branch
106 net = fsm_minimize_hop(net);
11
Calling 'fsm_minimize_hop'
107 }
108 else
109 net = fsm_minimize_brz(net);
110 fsm_update_flags(net,YES1,YES1,YES1,YES1,UNK2,UNK2);
111 }
112 return(net);
113}
114
115static struct fsm *fsm_minimize_brz(struct fsm *net) {
116 return(fsm_determinize(fsm_reverse(fsm_determinize(fsm_reverse(net)))));
117}
118
119static struct fsm *fsm_minimize_hop(struct fsm *net) {
120
121 struct e *temp_E;
122 struct trans_array *tptr;
123 struct trans_list *transitions;
124 int i,j,minsym,next_minsym,current_i, stateno, thissize, source;
125 unsigned int tail;
126
127 fsm_count(net);
128 if (net->finalcount == 0) {
12
Assuming field 'finalcount' is not equal to 0
13
Taking false branch
129 fsm_destroy(net);
130 return(fsm_empty_set());
131 }
132
133 num_states = net->statecount;
134
135 P = NULL((void*)0);
136
137 /*
138 1. generate the inverse lookup table
139 2. generate P and E (partitions, states linked list)
140 3. Init Agenda = {Q, Q-F}
141 4. Split until Agenda is empty
142 */
143
144 sigma_to_pairs(net);
145
146 init_PE();
14
Calling 'init_PE'
22
Returning from 'init_PE'
147
148 if (total_states
22.1
'total_states' is not equal to 'num_states'
== num_states) {
23
Taking false branch
149 goto bail;
150 }
151
152 generate_inverse(net);
153
154
155 Agenda_head->index = 0;
24
Access to field 'index' results in a dereference of a null pointer (loaded from variable 'Agenda_head')
156 if (Agenda_head->next != NULL((void*)0))
157 Agenda_head->next->index = 0;
158
159 for (Agenda = Agenda_head; Agenda != NULL((void*)0); ) {
160 /* Remove current_w from agenda */
161 current_w = Agenda->p;
162 current_i = Agenda->index;
163 Agenda->p->agenda = NULL((void*)0);
164 Agenda = Agenda->next;
165
166 /* Store current group state number in tmp_group */
167 /* And figure out minsym */
168 /* If index is 0 we start splitting from the first symbol */
169 /* Otherwise we split from where we left off last time */
170
171 thissize = 0;
172 minsym = INT_MAX2147483647;
173 for (temp_E = current_w->first_e; temp_E != NULL((void*)0); temp_E = temp_E->right) {
174 stateno = temp_E - E;
175 *(temp_group+thissize) = stateno;
176 thissize++;
177 tptr = trans_array_minimize+stateno;
178 /* Clear tails if symloop should start from 0 */
179 if (current_i == 0)
180 tptr->tail = 0;
181
182 tail = tptr->tail;
183 transitions = (tptr->transitions)+tail;
184 if (tail < tptr->size && transitions->inout < minsym) {
185 minsym = transitions->inout;
186 }
187 }
188
189 for (next_minsym = INT_MAX2147483647; minsym != INT_MAX2147483647 ; minsym = next_minsym, next_minsym = INT_MAX2147483647) {
190
191 /* Add states to temp_move */
192 for (i = 0, j = 0; i < thissize; i++) {
193 tptr = trans_array_minimize+*(temp_group+i);
194 tail = tptr->tail;
195 transitions = (tptr->transitions)+tail;
196 while (tail < tptr->size && transitions->inout == minsym) {
197 source = transitions->source;
198 if (*(memo_table+(source)) != mainloop) {
199 *(memo_table+(source)) = mainloop;
200 *(temp_move+j) = source;
201 j++;
202 }
203 tail++;
204 transitions++;
205 }
206 tptr->tail = tail;
207 if (tail < tptr->size && transitions->inout < next_minsym) {
208 next_minsym = transitions->inout;
209 }
210 }
211 if (j == 0) {
212 continue;
213 }
214 mainloop++;
215 if (refine_states(j) == 1) {
216 break; /* break loop if we split current_w */
217 }
218 }
219 if (total_states == num_states) {
220 break;
221 }
222 }
223
224 net = rebuild_machine(net);
225
226 free(trans_array_minimize);
227 free(trans_list_minimize);
228
229 bail:
230
231 free(Agenda_top);
232
233 free(memo_table);
234 free(temp_move);
235 free(temp_group);
236
237
238 free(finals);
239 free(E);
240 free(Phead);
241 free(single_sigma_array);
242 free(double_sigma_array);
243
244 return(net);
245}
246
247static struct fsm *rebuild_machine(struct fsm *net) {
248 int i,j, group_num, source, target, new_linecount = 0, arccount = 0;
249 struct fsm_state *fsm;
250 struct p *myp;
251 struct e *thise;
252
253 if (net->statecount == total_states) {
254 return(net);
255 }
256 fsm = net->states;
257
258 /* We need to make sure state 0 is first in its group */
259 /* to get the proper numbering of states */
260
261 if (E->group->first_e != E) {
262 E->group->first_e = E;
263 }
264
265 /* Recycling t_count for group numbering use here */
266
267 group_num = 1;
268 myp = P;
269 while (myp != NULL((void*)0)) {
270 myp->count = 0;
271 myp = myp->next;
272 }
273
274 for (i=0; (fsm+i)->state_no != -1; i++) {
275 thise = E+((fsm+i)->state_no);
276 if (thise->group->first_e == thise) {
277 new_linecount++;
278 if ((fsm+i)->start_state == 1) {
279 thise->group->t_count = 0;
280 thise->group->count = 1;
281 } else if (thise->group->count == 0) {
282 thise->group->t_count = group_num++;
283 thise->group->count = 1;
284 }
285 }
286 }
287
288 for (i=0, j=0; (fsm+i)->state_no != -1; i++) {
289 thise = E+((fsm+i)->state_no);
290 if (thise->group->first_e == thise) {
291 source = thise->group->t_count;
292 target = ((fsm+i)->target == -1) ? -1 : (E+((fsm+i)->target))->group->t_count;
293 add_fsm_arc(fsm, j, source, (fsm+i)->in, (fsm+i)->out, target, finals[(fsm+i)->state_no], (fsm+i)->start_state);
294 arccount = ((fsm+i)->target == -1) ? arccount : arccount+1;
295 j++;
296 }
297 }
298
299 add_fsm_arc(fsm, j, -1, -1, -1, -1, -1, -1);
300 fsm = realloc(fsm,sizeof(struct fsm_state)*(new_linecount+1));
301 net->states = fsm;
302 net->linecount = j+1;
303 net->arccount = arccount;
304 net->statecount = total_states;
305 return(net);
306}
307
308static INLINEinline int refine_states(int invstates) {
309 int i, selfsplit;
310 struct e *thise;
311 struct p *tP, *newP = NULL((void*)0);
312
313 /*
314 1. add inverse(P,a) to table of inverses, disallowing duplicates
315 2. first pass on S, touch each state once, increasing P->t_count
316 3. for each P where counter != count, split and add to agenda
317 */
318
319 /* Inverse to table of inverses */
320 selfsplit = 0;
321
322 /* touch and increase P->counter */
323 for (i=0; i < invstates; i++) {
324 ((E+(*(temp_move+i)))->group)->t_count++;
325 ((E+(*(temp_move+i)))->group)->inv_t_count += ((E+(*(temp_move+i)))->inv_count);
326 assert((E+(*(temp_move+i)))->group->t_count <= (E+(*(temp_move+i)))->group->count)(((E+(*(temp_move+i)))->group->t_count <= (E+(*(temp_move
+i)))->group->count) ? (void) (0) : __assert_fail ("(E+(*(temp_move+i)))->group->t_count <= (E+(*(temp_move+i)))->group->count"
, "/tmp/build/foma/foma-0.10.0+g279~a2d32b38/minimize.c", 326
, __extension__ __PRETTY_FUNCTION__))
;
327 }
328
329 /* Split (this is the tricky part) */
330
331 for (i=0; i < invstates; i++) {
332
333 thise = E+*(temp_move+i);
334 tP = thise->group;
335
336 /* Do we need to split?
337 if we've touched as many states as there are in the partition
338 we don't split */
339
340 if (tP->t_count == tP->count) {
341 tP->t_count = 0;
342 tP->inv_t_count = 0;
343 continue;
344 }
345
346 if ((tP->t_count != tP->count) && (tP->count > 1) && (tP->t_count > 0)) {
347
348 /* Check if we already split this */
349 newP = tP->current_split;
350 if (newP == NULL((void*)0)) {
351 /* printf("tP [%i] newP [%i]\n",tP->inv_count,tP->inv_t_count); */
352 /* Create new group newP */
353 total_states++;
354 if (total_states == num_states)
355 return(1); /* Abort now, machine is already minimal */
356 tP->current_split = Pnext++;
357 newP = tP->current_split;
358 newP->first_e = newP->last_e = thise;
359 newP->count = 0;
360 newP->inv_count = tP->inv_t_count;
361 newP->inv_t_count = 0;
362 newP->t_count = 0;
363 newP->current_split = NULL((void*)0);
364 newP->agenda = NULL((void*)0);
365
366 /* Add to agenda */
367
368 /* If the current block (tP) is on the agenda, we add both back */
369 /* to the agenda */
370 /* In practice we need only add newP since tP stays where it is */
371 /* However, we mark the larger one as not starting the symloop */
372 /* from zero */
373 if (tP->agenda != NULL((void*)0)) {
374 /* Is tP smaller */
375 if (tP->inv_count < tP->inv_t_count) {
376 agenda_add(newP, 1);
377 tP->agenda->index = 0;
378 }
379 else {
380 agenda_add(newP, 0);
381 }
382 /* In the event that we're splitting the partition we're currently */
383 /* splitting with, we can simply add both new partitions to the agenda */
384 /* and break out of the entire sym loop after we're */
385 /* done with the current sym and move on with the agenda */
386 /* We process the larger one for all symbols */
387 /* and the smaller one for only the ones remaining in this symloop */
388
389 } else if (tP == current_w) {
390 agenda_add(((tP->inv_count < tP->inv_t_count) ? tP : newP),0);
391 agenda_add(((tP->inv_count >= tP->inv_t_count) ? tP : newP),1);
392 selfsplit = 1;
393 } else {
394 /* If the block is not on the agenda, we add */
395 /* the smaller of tP, newP and start the symloop from 0 */
396 agenda_add((tP->inv_count < tP->inv_t_count ? tP : newP),0);
397 }
398 /* Add to middle of P-chain */
399 newP->next = P->next;
400 P->next = newP;
401 }
402
403 thise->group = newP;
404 newP->count++;
405
406 /* need to make tP->last_e point to the last untouched e */
407 if (thise == tP->last_e)
408 tP->last_e = thise->left;
409 if (thise == tP->first_e)
410 tP->first_e = thise->right;
411
412 /* Adjust links */
413 if (thise->left != NULL((void*)0))
414 thise->left->right = thise->right;
415 if (thise->right != NULL((void*)0))
416 thise->right->left = thise->left;
417
418 if (newP->last_e != thise) {
419 newP->last_e->right = thise;
420 thise->left = newP->last_e;
421 newP->last_e = thise;
422 }
423
424 thise->right = NULL((void*)0);
425 if (newP->first_e == thise)
426 thise->left = NULL((void*)0);
427
428 /* Are we done for this block? Adjust counters */
429 if (newP->count == tP->t_count) {
430 tP->count = tP->count - newP->count;
431 tP->inv_count = tP->inv_count - tP->inv_t_count;
432 tP->current_split = NULL((void*)0);
433 tP->t_count = 0;
434 tP->inv_t_count = 0;
435 }
436 }
437 }
438 /* We return 1 if we just split the partition we were working with */
439 return (selfsplit);
440}
441
442static void agenda_add(struct p *pptr, int start) {
443
444 /* Use FILO strategy here */
445
446 struct agenda *ag;
447 //ag = malloc(sizeof(struct agenda));
448 ag = Agenda_next++;
449 if (Agenda != NULL((void*)0))
450 ag->next = Agenda;
451 else
452 ag->next = NULL((void*)0);
453 ag->p = pptr;
454 ag->index = start;
455 Agenda = ag;
456 pptr->agenda = ag;
457}
458
459static void init_PE() {
460 /* Create two members of P
461 (nonfinals,finals)
462 and put both of them on the agenda
463 */
464
465 int i;
466 struct e *last_f, *last_nonf;
467 struct p *nonFP, *FP;
468 struct agenda *ag;
469
470 mainloop = 1;
471 memo_table = calloc(num_states,sizeof(int));
472 temp_move = calloc(num_states,sizeof(int));
473 temp_group = calloc(num_states,sizeof(int));
474 Phead = P = Pnext = calloc(num_states+1, sizeof(struct p));
475 nonFP = Pnext++;
476 FP = Pnext++;
477 nonFP->next = FP;
478 nonFP->count = num_states-num_finals;
479 FP->next = NULL((void*)0);
480 FP->count = num_finals;
481 FP->t_count = 0;
482 nonFP->t_count = 0;
483 FP->current_split = NULL((void*)0);
484 nonFP->current_split = NULL((void*)0);
485 FP->inv_count = nonFP->inv_count = FP->inv_t_count = nonFP->inv_t_count = 0;
486
487 /* How many groups can we put on the agenda? */
488 Agenda_top = Agenda_next = calloc(num_states*2, sizeof(struct agenda));
489 Agenda_head = NULL((void*)0);
15
Null pointer value stored to 'Agenda_head'
490
491 P = NULL((void*)0);
492 total_states = 0;
493
494 if (num_finals
15.1
'num_finals' is <= 0
> 0) {
16
Taking false branch
495 ag = Agenda_next++;
496 FP->agenda = ag;
497 P = FP;
498 P->next = NULL((void*)0);
499 ag->p = FP;
500 Agenda_head = ag;
501 ag->next = NULL((void*)0);
502 total_states++;
503 }
504 if (num_states - num_finals > 0) {
17
Assuming the condition is false
18
Taking false branch
505 ag = Agenda_next++;
506 nonFP->agenda = ag;
507 ag->p = nonFP;
508 ag->next = NULL((void*)0);
509 total_states++;
510 if (Agenda_head != NULL((void*)0)) {
511 Agenda_head->next = ag;
512 P->next = nonFP;
513 P->next->next = NULL((void*)0);
514 } else {
515 P = nonFP;
516 P->next = NULL((void*)0);
517 Agenda_head = ag;
518 }
519 }
520
521 /* Initialize doubly linked list E */
522 E = calloc(num_states,sizeof(struct e));
523
524 last_f = NULL((void*)0);
525 last_nonf = NULL((void*)0);
526
527 for (i=0; i
18.1
'i' is >= 'num_states'
< num_states; i++) {
19
Loop condition is false. Execution continues on line 550
528 if (finals[i]) {
529 (E+i)->group = FP;
530 (E+i)->left = last_f;
531 if (i > 0 && last_f != NULL((void*)0))
532 last_f->right = (E+i);
533 if (last_f == NULL((void*)0))
534 FP->first_e = (E+i);
535 last_f = (E+i);
536 FP->last_e = (E+i);
537 } else {
538 (E+i)->group = nonFP;
539 (E+i)->left = last_nonf;
540 if (i > 0 && last_nonf != NULL((void*)0))
541 last_nonf->right = (E+i);
542 if (last_nonf == NULL((void*)0))
543 nonFP->first_e = (E+i);
544 last_nonf = (E+i);
545 nonFP->last_e = (E+i);
546 }
547 (E+i)->inv_count = 0;
548 }
549
550 if (last_f
19.1
'last_f' is equal to NULL
!= NULL((void*)0))
20
Taking false branch
551 last_f->right = NULL((void*)0);
552 if (last_nonf
20.1
'last_nonf' is equal to NULL
!= NULL((void*)0))
21
Taking false branch
553 last_nonf->right = NULL((void*)0);
554}
555
556static int trans_sort_cmp(const void *a, const void *b) {
557 return (((const struct trans_list *)a)->inout - ((const struct trans_list *)b)->inout);
558}
559
560static void generate_inverse(struct fsm *net) {
561
562 struct fsm_state *fsm;
563 struct trans_array *tptr;
564 struct trans_list *listptr;
565
566 int i, source, target, offsetcount, symbol, size;
567 fsm = net->states;
568 trans_array_minimize = calloc(net->statecount, sizeof(struct trans_array));
569 trans_list_minimize = calloc(net->arccount, sizeof(struct trans_list));
570
571 /* Figure out the number of transitions each one has */
572 for (i=0; (fsm+i)->state_no != -1; i++) {
573 if ((fsm+i)->target == -1) {
574 continue;
575 }
576 target = (fsm+i)->target;
577 (E+target)->inv_count++;
578 (E+target)->group->inv_count++;
579 (trans_array_minimize+target)->size++;
580 }
581 offsetcount = 0;
582 for (i=0; i < net->statecount; i++) {
583 (trans_array_minimize+i)->transitions = trans_list_minimize + offsetcount;
584 offsetcount += (trans_array_minimize+i)->size;
585 }
586 for (i=0; (fsm+i)->state_no != -1; i++) {
587 if ((fsm+i)->target == -1) {
588 continue;
589 }
590 symbol = symbol_pair_to_single_symbol((fsm+i)->in,(fsm+i)->out);
591 source = (fsm+i)->state_no;
592 target = (fsm+i)->target;
593 tptr = trans_array_minimize + target;
594 ((tptr->transitions)+(tptr->tail))->inout = symbol;
595 ((tptr->transitions)+(tptr->tail))->source = source;
596 tptr->tail++;
597 }
598 /* Sort arcs */
599 for (i=0; i < net->statecount; i++) {
600 listptr = (trans_array_minimize+i)->transitions;
601 size = (trans_array_minimize+i)->size;
602 if (size > 1)
603 qsort(listptr, size, sizeof(struct trans_list), trans_sort_cmp);
604 }
605}
606
607static void sigma_to_pairs(struct fsm *net) {
608
609 int i, j, x, y, z, next_x = 0;
610 struct fsm_state *fsm;
611
612 fsm = net->states;
613
614 epsilon_symbol = -1;
615 maxsigma = sigma_max(net->sigma);
616
617 maxsigma++;
618
619 single_sigma_array = malloc(2*maxsigma*maxsigma*sizeof(int));
620 double_sigma_array = malloc(maxsigma*maxsigma*sizeof(int));
621
622 for (i=0; i < maxsigma; i++) {
623 for (j=0; j< maxsigma; j++) {
624 *(double_sigma_array+maxsigma*i+j) = -1;
625 }
626 }
627
628 /* f(x) -> y,z sigma pair */
629 /* f(y,z) -> x simple entry */
630 /* if exists f(n) <-> EPSILON, EPSILON, save n */
631 /* symbol(x) x>=1 */
632
633 /* Forward mapping: */
634 /* *(double_sigma_array+maxsigma*in+out) */
635
636 /* Backmapping: */
637 /* *(single_sigma_array+(symbol*2) = in(symbol) */
638 /* *(single_sigma_array+(symbol*2+1) = out(symbol) */
639
640 /* Table for checking whether a state is final */
641
642 finals = calloc(num_states, sizeof(_Bool));
643 x = 0; num_finals = 0;
644 net->arity = 1;
645 for (i=0; (fsm+i)->state_no != -1; i++) {
646 if ((fsm+i)->final_state == 1 && finals[(fsm+i)->state_no] != 1) {
647 num_finals++;
648 finals[(fsm+i)->state_no] = 1;
649 }
650 y = (fsm+i)->in;
651 z = (fsm+i)->out;
652 if (y != z || y == UNKNOWN1 || z == UNKNOWN1)
653 net->arity = 2;
654 if ((y == -1) || (z == -1))
655 continue;
656 if (*(double_sigma_array+maxsigma*y+z) == -1) {
657 *(double_sigma_array+maxsigma*y+z) = x;
658 *(single_sigma_array+next_x) = y;
659 next_x++;
660 *(single_sigma_array+next_x) = z;
661 next_x++;
662 if (y == EPSILON0 && z == EPSILON0) {
663 epsilon_symbol = x;
664 }
665 x++;
666 }
667 }
668 num_symbols = x;
669}
670
671static INLINEinline int symbol_pair_to_single_symbol(int in, int out) {
672 return(*(double_sigma_array+maxsigma*in+out));
673}