3 * Machine and state maintenance.
5 * Three lists are maintained here:
6 * - A list of automatons (state machines): these hold a name, a unique id
7 * (in the "index" field) and the memory address of a cell that holds the
8 * current state of the automaton (in the "value" field).
9 * - A list of states for each automaton: a name, an automaton id (in the
10 * "index" field) and a unique id for the state (unique in the automaton;
11 * states belonging to different automatons may have the same id).
12 * - A list of state combinations. Each function may belong to a set of states.
13 * This list assigns a unique id to the combination of the automaton and all
16 * For a function/variable that has states, there is a fourth list, which is
17 * attached to the "symbol" structure. This list contains the code label (in
18 * the "name" field, only for functions), the id of the state combinations (the
19 * state list id; it is stored in the "index" field) and the code address at
20 * which the function starts. The latter is currently unused.
22 * At the start of the compiled code, a set of stub functions is generated.
23 * Each stub function looks up the value of the "state selector" value for the
24 * automaton, and goes with a "switch" instruction to the start address of the
25 * function. This happens in SC4.C.
28 * Copyright (c) ITB CompuPhase, 2005-2006
30 * This software is provided "as-is", without any express or implied warranty.
31 * In no event will the authors be held liable for any damages arising from
32 * the use of this software.
34 * Permission is granted to anyone to use this software for any purpose,
35 * including commercial applications, and to alter it and redistribute it
36 * freely, subject to the following restrictions:
38 * 1. The origin of this software must not be misrepresented; you must not
39 * claim that you wrote the original software. If you use this software in
40 * a product, an acknowledgment in the product documentation would be
41 * appreciated but is not required.
42 * 2. Altered source versions must be plainly marked as such, and must not be
43 * misrepresented as being the original software.
44 * 3. This notice may not be removed or altered from any source distribution.
54 #if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
59 #include <alloc/fortify.h>
62 typedef struct s_statelist {
63 struct s_statelist *next;
64 int *states; /* list of states in this combination */
65 int numstates; /* number of items in the above list */
66 int fsa; /* automaton id */
67 int listid; /* unique id for this combination list */
70 static statelist statelist_tab = { NULL, NULL, 0, 0, 0}; /* state combinations table */
73 static constvalue *find_automaton(const char *name,int *last)
79 ptr=sc_automaton_tab.next;
81 if (strcmp(name,ptr->name)==0)
90 SC_FUNC constvalue *automaton_add(const char *name)
95 assert(strlen(name)<sizeof(ptr->name));
96 ptr=find_automaton(name,&last);
98 assert(last+1 <= SHRT_MAX);
99 ptr=append_constval(&sc_automaton_tab,name,(cell)0,(short)(last+1));
104 SC_FUNC constvalue *automaton_find(const char *name)
107 return find_automaton(name,&last);
110 SC_FUNC constvalue *automaton_findid(int id)
113 for (ptr=sc_automaton_tab.next; ptr!=NULL && ptr->index!=id; ptr=ptr->next)
119 static constvalue *find_state(const char *name,int fsa,int *last)
125 ptr=sc_state_tab.next;
127 if (ptr->index==fsa) {
128 if (strcmp(name,ptr->name)==0)
130 if ((int)ptr->value>*last)
131 *last=(int)ptr->value;
138 SC_FUNC constvalue *state_add(const char *name,int fsa)
143 assert(strlen(name)<sizeof(ptr->name));
144 ptr=find_state(name,fsa,&last);
146 assert(fsa <= SHRT_MAX);
147 ptr=append_constval(&sc_state_tab,name,(cell)(last+1),(short)fsa);
152 SC_FUNC constvalue *state_find(const char *name,int fsa_id)
154 int last; /* dummy */
155 return find_state(name,fsa_id,&last);
158 SC_FUNC constvalue *state_findid(int id)
161 for (ptr=sc_state_tab.next; ptr!=NULL && ptr->value!=id; ptr=ptr->next)
166 SC_FUNC void state_buildlist(int **list,int *listsize,int *count,int stateid)
171 assert(listsize!=NULL);
172 assert(*listsize>=0);
175 assert(*count<=*listsize);
177 if (*count==*listsize) {
178 /* To avoid constantly calling malloc(), the list is grown by 4 states at
182 *list=(int*)realloc(*list,*listsize*sizeof(int));
184 error(103); /* insufficient memory */
187 /* find the insertion point (the list has to stay sorted) */
188 for (idx=0; idx<*count && *list[idx]<stateid; idx++)
191 memmove(&(*list)[idx+1],&(*list)[idx],(int)((*count-idx+1)*sizeof(int)));
192 (*list)[idx]=stateid;
196 static statelist *state_findlist(int *list,int count,int fsa,int *last)
204 ptr=statelist_tab.next;
206 if (ptr->listid>*last)
208 if (ptr->fsa==fsa && ptr->numstates==count) {
209 /* compare all states */
210 for (i=0; i<count && ptr->states[i]==list[i]; i++)
220 static statelist *state_getlist_ptr(int listid)
225 for (ptr=statelist_tab.next; ptr!=NULL && ptr->listid!=listid; ptr=ptr->next)
230 SC_FUNC int state_addlist(int *list,int count,int fsa)
237 ptr=state_findlist(list,count,fsa,&last);
239 if ((ptr=(statelist*)malloc(sizeof(statelist)))==NULL)
240 error(103); /* insufficient memory */
241 if ((ptr->states=(int*)malloc(count*sizeof(int)))==NULL) {
243 error(103); /* insufficient memory */
245 memcpy(ptr->states,list,count*sizeof(int));
246 ptr->numstates=count;
249 ptr->next=statelist_tab.next;
250 statelist_tab.next=ptr;
256 SC_FUNC void state_deletetable(void)
260 while (statelist_tab.next!=NULL) {
261 ptr=statelist_tab.next;
263 statelist_tab.next=ptr->next;
265 assert(ptr->states!=NULL);
271 SC_FUNC int state_getfsa(int listid)
279 ptr=state_getlist_ptr(listid);
280 return (ptr!=NULL) ? ptr->fsa : -1; /* fsa 0 exists */
283 SC_FUNC int state_count(int listid)
285 statelist *ptr=state_getlist_ptr(listid);
287 return 0; /* unknown list, no states in it */
288 return ptr->numstates;
291 SC_FUNC int state_inlist(int listid,int state)
296 ptr=state_getlist_ptr(listid);
298 return FALSE; /* unknown list, state not in it */
299 for (i=0; i<ptr->numstates; i++)
300 if (ptr->states[i]==state)
305 SC_FUNC int state_listitem(int listid,int index)
309 ptr=state_getlist_ptr(listid);
311 assert(index>=0 && index<ptr->numstates);
312 return ptr->states[index];
315 static int checkconflict(statelist *psrc,statelist *ptgt)
321 for (s=0; s<psrc->numstates; s++)
322 for (t=0; t<ptgt->numstates; t++)
323 if (psrc->states[s]==ptgt->states[t])
324 return 1; /* state conflict */
328 /* This function searches whether one of the states in the list of statelist id's
329 * of a symbol exists in any other statelist id's of the same function; it also
330 * verifies that all definitions of the symbol are in the same automaton.
332 SC_FUNC void state_conflict(symbol *root)
334 statelist *psrc,*ptgt;
335 constvalue *srcptr,*tgtptr;
339 for (sym=root->next; sym!=NULL; sym=sym->next) {
340 if (sym->parent!=NULL || sym->ident!=iFUNCTN)
341 continue; /* hierarchical data type or no function */
342 if (sym->states==NULL)
343 continue; /* this function has no states */
344 for (srcptr=sym->states->next; srcptr!=NULL; srcptr=srcptr->next) {
345 if (srcptr->index==-1)
346 continue; /* state list id -1 is a special case */
347 psrc=state_getlist_ptr(srcptr->index);
349 for (tgtptr=srcptr->next; tgtptr!=NULL; tgtptr=tgtptr->next) {
350 if (tgtptr->index==-1)
351 continue; /* state list id -1 is a special case */
352 ptgt=state_getlist_ptr(tgtptr->index);
354 if (psrc->fsa!=ptgt->fsa && strcmp(sym->name,uENTRYFUNC)!=0)
355 error(83,sym->name); /* this function is part of another machine */
356 if (checkconflict(psrc,ptgt))
357 error(84,sym->name); /* state conflict */
363 /* check whether the two state lists (whose ids are passed in) share any
366 SC_FUNC int state_conflict_id(int listid1,int listid2)
368 statelist *psrc,*ptgt;
370 psrc=state_getlist_ptr(listid1);
372 ptgt=state_getlist_ptr(listid2);
374 return checkconflict(psrc,ptgt);