|
ds@1952
|
1 |
/* Pawn compiler |
|
ds@1952
|
2 |
* |
|
ds@1952
|
3 |
* Machine and state maintenance. |
|
ds@1952
|
4 |
* |
|
ds@1952
|
5 |
* Three lists are maintained here: |
|
ds@1952
|
6 |
* - A list of automatons (state machines): these hold a name, a unique id |
|
ds@1952
|
7 |
* (in the "index" field) and the memory address of a cell that holds the |
|
ds@1952
|
8 |
* current state of the automaton (in the "value" field). |
|
ds@1952
|
9 |
* - A list of states for each automaton: a name, an automaton id (in the |
|
ds@1952
|
10 |
* "index" field) and a unique id for the state (unique in the automaton; |
|
ds@1952
|
11 |
* states belonging to different automatons may have the same id). |
|
ds@1952
|
12 |
* - A list of state combinations. Each function may belong to a set of states. |
|
ds@1952
|
13 |
* This list assigns a unique id to the combination of the automaton and all |
|
ds@1952
|
14 |
* states. |
|
ds@1952
|
15 |
* |
|
ds@1952
|
16 |
* For a function/variable that has states, there is a fourth list, which is |
|
ds@1952
|
17 |
* attached to the "symbol" structure. This list contains the code label (in |
|
ds@1952
|
18 |
* the "name" field, only for functions), the id of the state combinations (the |
|
ds@1952
|
19 |
* state list id; it is stored in the "index" field) and the code address at |
|
ds@1952
|
20 |
* which the function starts. The latter is currently unused. |
|
ds@1952
|
21 |
* |
|
ds@1952
|
22 |
* At the start of the compiled code, a set of stub functions is generated. |
|
ds@1952
|
23 |
* Each stub function looks up the value of the "state selector" value for the |
|
ds@1952
|
24 |
* automaton, and goes with a "switch" instruction to the start address of the |
|
ds@1952
|
25 |
* function. This happens in SC4.C. |
|
ds@1952
|
26 |
* |
|
ds@1952
|
27 |
* |
|
ds@1952
|
28 |
* Copyright (c) ITB CompuPhase, 2005-2006 |
|
ds@1952
|
29 |
* |
|
ds@1952
|
30 |
* This software is provided "as-is", without any express or implied warranty. |
|
ds@1952
|
31 |
* In no event will the authors be held liable for any damages arising from |
|
ds@1952
|
32 |
* the use of this software. |
|
ds@1952
|
33 |
* |
|
ds@1952
|
34 |
* Permission is granted to anyone to use this software for any purpose, |
|
ds@1952
|
35 |
* including commercial applications, and to alter it and redistribute it |
|
ds@1952
|
36 |
* freely, subject to the following restrictions: |
|
ds@1952
|
37 |
* |
|
ds@1952
|
38 |
* 1. The origin of this software must not be misrepresented; you must not |
|
ds@1952
|
39 |
* claim that you wrote the original software. If you use this software in |
|
ds@1952
|
40 |
* a product, an acknowledgment in the product documentation would be |
|
ds@1952
|
41 |
* appreciated but is not required. |
|
ds@1952
|
42 |
* 2. Altered source versions must be plainly marked as such, and must not be |
|
ds@1952
|
43 |
* misrepresented as being the original software. |
|
ds@1952
|
44 |
* 3. This notice may not be removed or altered from any source distribution. |
|
ds@1952
|
45 |
* |
|
ds@1952
|
46 |
* Version: $Id$ |
|
ds@1952
|
47 |
*/ |
|
ds@1952
|
48 |
#include <assert.h> |
|
ds@1952
|
49 |
#include <limits.h> |
|
ds@1952
|
50 |
#include <stdio.h> |
|
ds@1952
|
51 |
#include <stdlib.h> |
|
ds@1952
|
52 |
#include <string.h> |
|
ds@1952
|
53 |
#include "sc.h" |
|
ds@1952
|
54 |
#if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__ |
|
ds@1952
|
55 |
#include <sclinux.h> |
|
ds@1952
|
56 |
#endif |
|
ds@1952
|
57 |
|
|
ds@1952
|
58 |
#if defined FORTIFY |
|
ds@1952
|
59 |
#include <alloc/fortify.h> |
|
ds@1952
|
60 |
#endif |
|
ds@1952
|
61 |
|
|
ds@1952
|
62 |
typedef struct s_statelist { |
|
ds@1952
|
63 |
struct s_statelist *next; |
|
ds@1952
|
64 |
int *states; /* list of states in this combination */ |
|
ds@1952
|
65 |
int numstates; /* number of items in the above list */ |
|
ds@1952
|
66 |
int fsa; /* automaton id */ |
|
ds@1952
|
67 |
int listid; /* unique id for this combination list */ |
|
ds@1952
|
68 |
} statelist; |
|
ds@1952
|
69 |
|
|
ds@1952
|
70 |
static statelist statelist_tab = { NULL, NULL, 0, 0, 0}; /* state combinations table */ |
|
ds@1952
|
71 |
|
|
ds@1952
|
72 |
|
|
ds@1952
|
73 |
static constvalue *find_automaton(const char *name,int *last) |
|
ds@1952
|
74 |
{ |
|
ds@1952
|
75 |
constvalue *ptr; |
|
ds@1952
|
76 |
|
|
ds@1952
|
77 |
assert(last!=NULL); |
|
ds@1952
|
78 |
*last=0; |
|
ds@1952
|
79 |
ptr=sc_automaton_tab.next; |
|
ds@1952
|
80 |
while (ptr!=NULL) { |
|
ds@1952
|
81 |
if (strcmp(name,ptr->name)==0) |
|
ds@1952
|
82 |
return ptr; |
|
ds@1952
|
83 |
if (ptr->index>*last) |
|
ds@1952
|
84 |
*last=ptr->index; |
|
ds@1952
|
85 |
ptr=ptr->next; |
|
ds@1952
|
86 |
} /* while */ |
|
ds@1952
|
87 |
return NULL; |
|
ds@1952
|
88 |
} |
|
ds@1952
|
89 |
|
|
ds@1952
|
90 |
SC_FUNC constvalue *automaton_add(const char *name) |
|
ds@1952
|
91 |
{ |
|
ds@1952
|
92 |
constvalue *ptr; |
|
ds@1952
|
93 |
int last; |
|
ds@1952
|
94 |
|
|
ds@1952
|
95 |
assert(strlen(name)<sizeof(ptr->name)); |
|
ds@1952
|
96 |
ptr=find_automaton(name,&last); |
|
ds@1952
|
97 |
if (ptr==NULL) { |
|
ds@1952
|
98 |
assert(last+1 <= SHRT_MAX); |
|
ds@1952
|
99 |
ptr=append_constval(&sc_automaton_tab,name,(cell)0,(short)(last+1)); |
|
ds@1952
|
100 |
} /* if */ |
|
ds@1952
|
101 |
return ptr; |
|
ds@1952
|
102 |
} |
|
ds@1952
|
103 |
|
|
ds@1952
|
104 |
SC_FUNC constvalue *automaton_find(const char *name) |
|
ds@1952
|
105 |
{ |
|
ds@1952
|
106 |
int last; |
|
ds@1952
|
107 |
return find_automaton(name,&last); |
|
ds@1952
|
108 |
} |
|
ds@1952
|
109 |
|
|
ds@1952
|
110 |
SC_FUNC constvalue *automaton_findid(int id) |
|
ds@1952
|
111 |
{ |
|
ds@1952
|
112 |
constvalue *ptr; |
|
ds@1952
|
113 |
for (ptr=sc_automaton_tab.next; ptr!=NULL && ptr->index!=id; ptr=ptr->next) |
|
ds@1952
|
114 |
/* nothing */; |
|
ds@1952
|
115 |
return ptr; |
|
ds@1952
|
116 |
} |
|
ds@1952
|
117 |
|
|
ds@1952
|
118 |
|
|
ds@1952
|
119 |
static constvalue *find_state(const char *name,int fsa,int *last) |
|
ds@1952
|
120 |
{ |
|
ds@1952
|
121 |
constvalue *ptr; |
|
ds@1952
|
122 |
|
|
ds@1952
|
123 |
assert(last!=NULL); |
|
ds@1952
|
124 |
*last=0; |
|
ds@1952
|
125 |
ptr=sc_state_tab.next; |
|
ds@1952
|
126 |
while (ptr!=NULL) { |
|
ds@1952
|
127 |
if (ptr->index==fsa) { |
|
ds@1952
|
128 |
if (strcmp(name,ptr->name)==0) |
|
ds@1952
|
129 |
return ptr; |
|
ds@1952
|
130 |
if ((int)ptr->value>*last) |
|
ds@1952
|
131 |
*last=(int)ptr->value; |
|
ds@1952
|
132 |
} /* if */ |
|
ds@1952
|
133 |
ptr=ptr->next; |
|
ds@1952
|
134 |
} /* while */ |
|
ds@1952
|
135 |
return NULL; |
|
ds@1952
|
136 |
} |
|
ds@1952
|
137 |
|
|
ds@1952
|
138 |
SC_FUNC constvalue *state_add(const char *name,int fsa) |
|
ds@1952
|
139 |
{ |
|
ds@1952
|
140 |
constvalue *ptr; |
|
ds@1952
|
141 |
int last; |
|
ds@1952
|
142 |
|
|
ds@1952
|
143 |
assert(strlen(name)<sizeof(ptr->name)); |
|
ds@1952
|
144 |
ptr=find_state(name,fsa,&last); |
|
ds@1952
|
145 |
if (ptr==NULL) { |
|
ds@1952
|
146 |
assert(fsa <= SHRT_MAX); |
|
ds@1952
|
147 |
ptr=append_constval(&sc_state_tab,name,(cell)(last+1),(short)fsa); |
|
ds@1952
|
148 |
} /* if */ |
|
ds@1952
|
149 |
return ptr; |
|
ds@1952
|
150 |
} |
|
ds@1952
|
151 |
|
|
ds@1952
|
152 |
SC_FUNC constvalue *state_find(const char *name,int fsa_id) |
|
ds@1952
|
153 |
{ |
|
ds@1952
|
154 |
int last; /* dummy */ |
|
ds@1952
|
155 |
return find_state(name,fsa_id,&last); |
|
ds@1952
|
156 |
} |
|
ds@1952
|
157 |
|
|
ds@1952
|
158 |
SC_FUNC constvalue *state_findid(int id) |
|
ds@1952
|
159 |
{ |
|
ds@1952
|
160 |
constvalue *ptr; |
|
ds@1952
|
161 |
for (ptr=sc_state_tab.next; ptr!=NULL && ptr->value!=id; ptr=ptr->next) |
|
ds@1952
|
162 |
/* nothing */; |
|
ds@1952
|
163 |
return ptr; |
|
ds@1952
|
164 |
} |
|
ds@1952
|
165 |
|
|
ds@1952
|
166 |
SC_FUNC void state_buildlist(int **list,int *listsize,int *count,int stateid) |
|
ds@1952
|
167 |
{ |
|
ds@1952
|
168 |
int idx; |
|
ds@1952
|
169 |
|
|
ds@1952
|
170 |
assert(list!=NULL); |
|
ds@1952
|
171 |
assert(listsize!=NULL); |
|
ds@1952
|
172 |
assert(*listsize>=0); |
|
ds@1952
|
173 |
assert(count!=NULL); |
|
ds@1952
|
174 |
assert(*count>=0); |
|
ds@1952
|
175 |
assert(*count<=*listsize); |
|
ds@1952
|
176 |
|
|
ds@1952
|
177 |
if (*count==*listsize) { |
|
ds@1952
|
178 |
/* To avoid constantly calling malloc(), the list is grown by 4 states at |
|
ds@1952
|
179 |
* a time. |
|
ds@1952
|
180 |
*/ |
|
ds@1952
|
181 |
*listsize+=4; |
|
ds@1952
|
182 |
*list=(int*)realloc(*list,*listsize*sizeof(int)); |
|
ds@1952
|
183 |
if (*list==NULL) |
|
ds@1952
|
184 |
error(103); /* insufficient memory */ |
|
ds@1952
|
185 |
} /* if */ |
|
ds@1952
|
186 |
|
|
ds@1952
|
187 |
/* find the insertion point (the list has to stay sorted) */ |
|
ds@1952
|
188 |
for (idx=0; idx<*count && *list[idx]<stateid; idx++) |
|
ds@1952
|
189 |
/* nothing */; |
|
ds@1952
|
190 |
if (idx<*count) |
|
ds@1952
|
191 |
memmove(&(*list)[idx+1],&(*list)[idx],(int)((*count-idx+1)*sizeof(int))); |
|
ds@1952
|
192 |
(*list)[idx]=stateid; |
|
ds@1952
|
193 |
*count+=1; |
|
ds@1952
|
194 |
} |
|
ds@1952
|
195 |
|
|
ds@1952
|
196 |
static statelist *state_findlist(int *list,int count,int fsa,int *last) |
|
ds@1952
|
197 |
{ |
|
ds@1952
|
198 |
statelist *ptr; |
|
ds@1952
|
199 |
int i; |
|
ds@1952
|
200 |
|
|
ds@1952
|
201 |
assert(count>0); |
|
ds@1952
|
202 |
assert(last!=NULL); |
|
ds@1952
|
203 |
*last=0; |
|
ds@1952
|
204 |
ptr=statelist_tab.next; |
|
ds@1952
|
205 |
while (ptr!=NULL) { |
|
ds@1952
|
206 |
if (ptr->listid>*last) |
|
ds@1952
|
207 |
*last=ptr->listid; |
|
ds@1952
|
208 |
if (ptr->fsa==fsa && ptr->numstates==count) { |
|
ds@1952
|
209 |
/* compare all states */ |
|
ds@1952
|
210 |
for (i=0; i<count && ptr->states[i]==list[i]; i++) |
|
ds@1952
|
211 |
/* nothing */; |
|
ds@1952
|
212 |
if (i==count) |
|
ds@1952
|
213 |
return ptr; |
|
ds@1952
|
214 |
} /* if */ |
|
ds@1952
|
215 |
ptr=ptr->next; |
|
ds@1952
|
216 |
} /* while */ |
|
ds@1952
|
217 |
return NULL; |
|
ds@1952
|
218 |
} |
|
ds@1952
|
219 |
|
|
ds@1952
|
220 |
static statelist *state_getlist_ptr(int listid) |
|
ds@1952
|
221 |
{ |
|
ds@1952
|
222 |
statelist *ptr; |
|
ds@1952
|
223 |
|
|
ds@1952
|
224 |
assert(listid>0); |
|
ds@1952
|
225 |
for (ptr=statelist_tab.next; ptr!=NULL && ptr->listid!=listid; ptr=ptr->next) |
|
ds@1952
|
226 |
/* nothing */; |
|
ds@1952
|
227 |
return ptr; |
|
ds@1952
|
228 |
} |
|
ds@1952
|
229 |
|
|
ds@1952
|
230 |
SC_FUNC int state_addlist(int *list,int count,int fsa) |
|
ds@1952
|
231 |
{ |
|
ds@1952
|
232 |
statelist *ptr; |
|
ds@1952
|
233 |
int last; |
|
ds@1952
|
234 |
|
|
ds@1952
|
235 |
assert(list!=NULL); |
|
ds@1952
|
236 |
assert(count>0); |
|
ds@1952
|
237 |
ptr=state_findlist(list,count,fsa,&last); |
|
ds@1952
|
238 |
if (ptr==NULL) { |
|
ds@1952
|
239 |
if ((ptr=(statelist*)malloc(sizeof(statelist)))==NULL) |
|
ds@1952
|
240 |
error(103); /* insufficient memory */ |
|
ds@1952
|
241 |
if ((ptr->states=(int*)malloc(count*sizeof(int)))==NULL) { |
|
ds@1952
|
242 |
free(ptr); |
|
ds@1952
|
243 |
error(103); /* insufficient memory */ |
|
ds@1952
|
244 |
} /* if */ |
|
ds@1952
|
245 |
memcpy(ptr->states,list,count*sizeof(int)); |
|
ds@1952
|
246 |
ptr->numstates=count; |
|
ds@1952
|
247 |
ptr->fsa=fsa; |
|
ds@1952
|
248 |
ptr->listid=last+1; |
|
ds@1952
|
249 |
ptr->next=statelist_tab.next; |
|
ds@1952
|
250 |
statelist_tab.next=ptr; |
|
ds@1952
|
251 |
} /* if */ |
|
ds@1952
|
252 |
assert(ptr!=NULL); |
|
ds@1952
|
253 |
return ptr->listid; |
|
ds@1952
|
254 |
} |
|
ds@1952
|
255 |
|
|
ds@1952
|
256 |
SC_FUNC void state_deletetable(void) |
|
ds@1952
|
257 |
{ |
|
ds@1952
|
258 |
statelist *ptr; |
|
ds@1952
|
259 |
|
|
ds@1952
|
260 |
while (statelist_tab.next!=NULL) { |
|
ds@1952
|
261 |
ptr=statelist_tab.next; |
|
ds@1952
|
262 |
/* unlink first */ |
|
ds@1952
|
263 |
statelist_tab.next=ptr->next; |
|
ds@1952
|
264 |
/* then delete */ |
|
ds@1952
|
265 |
assert(ptr->states!=NULL); |
|
ds@1952
|
266 |
free(ptr->states); |
|
ds@1952
|
267 |
free(ptr); |
|
ds@1952
|
268 |
} /* while */ |
|
ds@1952
|
269 |
} |
|
ds@1952
|
270 |
|
|
ds@1952
|
271 |
SC_FUNC int state_getfsa(int listid) |
|
ds@1952
|
272 |
{ |
|
ds@1952
|
273 |
statelist *ptr; |
|
ds@1952
|
274 |
|
|
ds@1952
|
275 |
assert(listid>=0); |
|
ds@1952
|
276 |
if (listid==0) |
|
ds@1952
|
277 |
return -1; |
|
ds@1952
|
278 |
|
|
ds@1952
|
279 |
ptr=state_getlist_ptr(listid); |
|
ds@1952
|
280 |
return (ptr!=NULL) ? ptr->fsa : -1; /* fsa 0 exists */ |
|
ds@1952
|
281 |
} |
|
ds@1952
|
282 |
|
|
ds@1952
|
283 |
SC_FUNC int state_count(int listid) |
|
ds@1952
|
284 |
{ |
|
ds@1952
|
285 |
statelist *ptr=state_getlist_ptr(listid); |
|
ds@1952
|
286 |
if (ptr==NULL) |
|
ds@1952
|
287 |
return 0; /* unknown list, no states in it */ |
|
ds@1952
|
288 |
return ptr->numstates; |
|
ds@1952
|
289 |
} |
|
ds@1952
|
290 |
|
|
ds@1952
|
291 |
SC_FUNC int state_inlist(int listid,int state) |
|
ds@1952
|
292 |
{ |
|
ds@1952
|
293 |
statelist *ptr; |
|
ds@1952
|
294 |
int i; |
|
ds@1952
|
295 |
|
|
ds@1952
|
296 |
ptr=state_getlist_ptr(listid); |
|
ds@1952
|
297 |
if (ptr==NULL) |
|
ds@1952
|
298 |
return FALSE; /* unknown list, state not in it */ |
|
ds@1952
|
299 |
for (i=0; i<ptr->numstates; i++) |
|
ds@1952
|
300 |
if (ptr->states[i]==state) |
|
ds@1952
|
301 |
return TRUE; |
|
ds@1952
|
302 |
return FALSE; |
|
ds@1952
|
303 |
} |
|
ds@1952
|
304 |
|
|
ds@1952
|
305 |
SC_FUNC int state_listitem(int listid,int index) |
|
ds@1952
|
306 |
{ |
|
ds@1952
|
307 |
statelist *ptr; |
|
ds@1952
|
308 |
|
|
ds@1952
|
309 |
ptr=state_getlist_ptr(listid); |
|
ds@1952
|
310 |
assert(ptr!=NULL); |
|
ds@1952
|
311 |
assert(index>=0 && index<ptr->numstates); |
|
ds@1952
|
312 |
return ptr->states[index]; |
|
ds@1952
|
313 |
} |
|
ds@1952
|
314 |
|
|
ds@1952
|
315 |
static int checkconflict(statelist *psrc,statelist *ptgt) |
|
ds@1952
|
316 |
{ |
|
ds@1952
|
317 |
int s,t; |
|
ds@1952
|
318 |
|
|
ds@1952
|
319 |
assert(psrc!=NULL); |
|
ds@1952
|
320 |
assert(ptgt!=NULL); |
|
ds@1952
|
321 |
for (s=0; s<psrc->numstates; s++) |
|
ds@1952
|
322 |
for (t=0; t<ptgt->numstates; t++) |
|
ds@1952
|
323 |
if (psrc->states[s]==ptgt->states[t]) |
|
ds@1952
|
324 |
return 1; /* state conflict */ |
|
ds@1952
|
325 |
return 0; |
|
ds@1952
|
326 |
} |
|
ds@1952
|
327 |
|
|
ds@1952
|
328 |
/* This function searches whether one of the states in the list of statelist id's |
|
ds@1952
|
329 |
* of a symbol exists in any other statelist id's of the same function; it also |
|
ds@1952
|
330 |
* verifies that all definitions of the symbol are in the same automaton. |
|
ds@1952
|
331 |
*/ |
|
ds@1952
|
332 |
SC_FUNC void state_conflict(symbol *root) |
|
ds@1952
|
333 |
{ |
|
ds@1952
|
334 |
statelist *psrc,*ptgt; |
|
ds@1952
|
335 |
constvalue *srcptr,*tgtptr; |
|
ds@1952
|
336 |
symbol *sym; |
|
ds@1952
|
337 |
|
|
ds@1952
|
338 |
assert(root!=NULL); |
|
ds@1952
|
339 |
for (sym=root->next; sym!=NULL; sym=sym->next) { |
|
ds@1952
|
340 |
if (sym->parent!=NULL || sym->ident!=iFUNCTN) |
|
ds@1952
|
341 |
continue; /* hierarchical data type or no function */ |
|
ds@1952
|
342 |
if (sym->states==NULL) |
|
ds@1952
|
343 |
continue; /* this function has no states */ |
|
ds@1952
|
344 |
for (srcptr=sym->states->next; srcptr!=NULL; srcptr=srcptr->next) { |
|
ds@1952
|
345 |
if (srcptr->index==-1) |
|
ds@1952
|
346 |
continue; /* state list id -1 is a special case */ |
|
ds@1952
|
347 |
psrc=state_getlist_ptr(srcptr->index); |
|
ds@1952
|
348 |
assert(psrc!=NULL); |
|
ds@1952
|
349 |
for (tgtptr=srcptr->next; tgtptr!=NULL; tgtptr=tgtptr->next) { |
|
ds@1952
|
350 |
if (tgtptr->index==-1) |
|
ds@1952
|
351 |
continue; /* state list id -1 is a special case */ |
|
ds@1952
|
352 |
ptgt=state_getlist_ptr(tgtptr->index); |
|
ds@1952
|
353 |
assert(ptgt!=NULL); |
|
ds@1952
|
354 |
if (psrc->fsa!=ptgt->fsa && strcmp(sym->name,uENTRYFUNC)!=0) |
|
ds@1952
|
355 |
error(83,sym->name); /* this function is part of another machine */ |
|
ds@1952
|
356 |
if (checkconflict(psrc,ptgt)) |
|
ds@1952
|
357 |
error(84,sym->name); /* state conflict */ |
|
ds@1952
|
358 |
} /* for (tgtptr) */ |
|
ds@1952
|
359 |
} /* for (srcptr) */ |
|
ds@1952
|
360 |
} /* for (sym) */ |
|
ds@1952
|
361 |
} |
|
ds@1952
|
362 |
|
|
ds@1952
|
363 |
/* check whether the two state lists (whose ids are passed in) share any |
|
ds@1952
|
364 |
* states |
|
ds@1952
|
365 |
*/ |
|
ds@1952
|
366 |
SC_FUNC int state_conflict_id(int listid1,int listid2) |
|
ds@1952
|
367 |
{ |
|
ds@1952
|
368 |
statelist *psrc,*ptgt; |
|
ds@1952
|
369 |
|
|
ds@1952
|
370 |
psrc=state_getlist_ptr(listid1); |
|
ds@1952
|
371 |
assert(psrc!=NULL); |
|
ds@1952
|
372 |
ptgt=state_getlist_ptr(listid2); |
|
ds@1952
|
373 |
assert(ptgt!=NULL); |
|
ds@1952
|
374 |
return checkconflict(psrc,ptgt); |
|
ds@1952
|
375 |
} |