/* Pawn compiler * * Machine and state maintenance. * * Three lists are maintained here: * - A list of automatons (state machines): these hold a name, a unique id * (in the "index" field) and the memory address of a cell that holds the * current state of the automaton (in the "value" field). * - A list of states for each automaton: a name, an automaton id (in the * "index" field) and a unique id for the state (unique in the automaton; * states belonging to different automatons may have the same id). * - A list of state combinations. Each function may belong to a set of states. * This list assigns a unique id to the combination of the automaton and all * states. * * For a function that has states, there is a fourth list, which is attached * to the "symbol" structure. This list contains the code label (in the "name" * field), the id of the state combinations (the state list id; it is stored * in the "index" field) and the code address at which the function starts. * The latter is currently unused. * * At the start of the compiled code, a set of stub functions is generated. * Each stub function looks up the value of the "state selector" value for the * automaton, and goes with a "switch" instruction to the start address of the * function. This happens in SC4.C. * * * Copyright (c) ITB CompuPhase, 2005 * * This software is provided "as-is", without any express or implied warranty. * In no event will the authors be held liable for any damages arising from * the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software in * a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * * Version: $Id$ */ #include #include #include #include #include #include "sc.h" #if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__ #include #endif #if defined FORTIFY #include "fortify.h" #endif typedef struct s_statelist { struct s_statelist *next; int *states; /* list of states in this combination */ int numstates; /* number of items in the above list */ int fsa; /* automaton id */ int listid; /* unique id for this combination list */ } statelist; static statelist statelist_tab = { NULL, NULL, 0, 0, 0}; /* state combinations table */ static constvalue *find_automaton(const char *name,int *last) { constvalue *ptr; assert(last!=NULL); *last=0; ptr=sc_automaton_tab.next; while (ptr!=NULL) { if (strcmp(name,ptr->name)==0) return ptr; if (ptr->index>*last) *last=ptr->index; ptr=ptr->next; } /* while */ return NULL; } SC_FUNC constvalue *automaton_add(const char *name) { constvalue *ptr; int last; assert(strlen(name)name)); ptr=find_automaton(name,&last); if (ptr==NULL) { assert(last+1 <= SHRT_MAX); ptr=append_constval(&sc_automaton_tab,name,(cell)0,(short)(last+1)); /* for every new automaton, create an anonymous (invalid) state */ state_add("",last+1); } /* if */ return ptr; } SC_FUNC constvalue *automaton_find(const char *name) { int last; return find_automaton(name,&last); } SC_FUNC constvalue *automaton_findid(int id) { constvalue *ptr; for (ptr=sc_automaton_tab.next; ptr!=NULL && ptr->index!=id; ptr=ptr->next) /* nothing */; return ptr; } static constvalue *find_state(const char *name,int fsa,int *last) { constvalue *ptr; assert(last!=NULL); *last=0; ptr=sc_state_tab.next; while (ptr!=NULL) { if (ptr->index==fsa) { if (strcmp(name,ptr->name)==0) return ptr; if ((int)ptr->value>*last) *last=(int)ptr->value; } /* if */ ptr=ptr->next; } /* while */ return NULL; } SC_FUNC constvalue *state_add(const char *name,int fsa) { constvalue *ptr; int last; assert(strlen(name)name)); ptr=find_state(name,fsa,&last); if (ptr==NULL) { assert(fsa <= SHRT_MAX); ptr=append_constval(&sc_state_tab,name,(cell)(last+1),(short)fsa); } /* if */ return ptr; } SC_FUNC constvalue *state_find(const char *name,int fsa_id) { int last; /* dummy */ return find_state(name,fsa_id,&last); } SC_FUNC constvalue *state_findid(int id) { constvalue *ptr; for (ptr=sc_state_tab.next; ptr!=NULL && ptr->value!=id; ptr=ptr->next) /* nothing */; return ptr; } SC_FUNC void state_buildlist(int **list,int *listsize,int *count,int stateid) { int idx; assert(list!=NULL); assert(listsize!=NULL); assert(*listsize>=0); assert(count!=NULL); assert(*count>=0); assert(*count<=*listsize); if (*count==*listsize) { /* To avoid constantly calling malloc(), the list is grown by 4 states at * a time. */ *listsize+=4; *list=(int*)realloc(*list,*listsize*sizeof(int)); if (*list==NULL) error(103); /* insufficient memory */ } /* if */ /* find the insertion point (the list has to stay sorted) */ for (idx=0; idx<*count && *list[idx]0); assert(last!=NULL); *last=0; ptr=statelist_tab.next; while (ptr!=NULL) { if (ptr->listid>*last) *last=ptr->listid; if (ptr->fsa==fsa && ptr->numstates==count) { /* compare all states */ for (i=0; istates[i]==list[i]; i++) /* nothing */; if (i==count) return ptr; } /* if */ ptr=ptr->next; } /* while */ return NULL; } static statelist *state_getlist_ptr(int listid) { statelist *ptr; assert(listid>0); for (ptr=statelist_tab.next; ptr!=NULL && ptr->listid!=listid; ptr=ptr->next) /* nothing */; return ptr; } SC_FUNC int state_addlist(int *list,int count,int fsa) { statelist *ptr; int last; assert(list!=NULL); assert(count>0); ptr=state_findlist(list,count,fsa,&last); if (ptr==NULL) { if ((ptr=(statelist*)malloc(sizeof(statelist)))==NULL) error(103); /* insufficient memory */ if ((ptr->states=(int*)malloc(count*sizeof(int)))==NULL) { free(ptr); error(103); /* insufficient memory */ } /* if */ memcpy(ptr->states,list,count*sizeof(int)); ptr->numstates=count; ptr->fsa=fsa; ptr->listid=last+1; ptr->next=statelist_tab.next; statelist_tab.next=ptr; } /* if */ assert(ptr!=NULL); return ptr->listid; } SC_FUNC void state_deletetable(void) { statelist *ptr; while (statelist_tab.next!=NULL) { ptr=statelist_tab.next; /* unlink first */ statelist_tab.next=ptr->next; /* then delete */ assert(ptr->states!=NULL); free(ptr->states); free(ptr); } /* while */ } SC_FUNC int state_getfsa(int listid) { statelist *ptr=state_getlist_ptr(listid); return (ptr!=NULL) ? ptr->fsa : -1; /* fsa 0 exists */ } SC_FUNC int state_count(int listid) { statelist *ptr=state_getlist_ptr(listid); if (ptr==NULL) return 0; /* unknown list, no states in it */ return ptr->numstates; } SC_FUNC int state_inlist(int listid,int state) { statelist *ptr; int i; ptr=state_getlist_ptr(listid); if (ptr==NULL) return FALSE; /* unknown list, state not in it */ for (i=0; inumstates; i++) if (ptr->states[i]==state) return TRUE; return FALSE; } SC_FUNC int state_listitem(int listid,int index) { statelist *ptr; ptr=state_getlist_ptr(listid); assert(ptr!=NULL); assert(index>=0 && indexnumstates); return ptr->states[index]; } /* This function searches whether one of the states in the list of statelist id's * of a symbol exists in any other statelist id's of the same function; it also * verifies that all definitions of the symbol are in the same automaton. */ SC_FUNC void state_conflict(symbol *root) { statelist *psrc,*ptgt; constvalue *srcptr,*tgtptr; int s,t; symbol *sym; assert(root!=NULL); for (sym=root->next; sym!=NULL; sym=sym->next) { if (sym->parent!=NULL || sym->ident!=iFUNCTN) continue; /* hierarchical data type or no function */ if (sym->states==NULL) continue; /* this function has no states */ for (srcptr=sym->states->next; srcptr!=NULL; srcptr=srcptr->next) { if (srcptr->index==-1) continue; /* state list id -1 is a special case */ psrc=state_getlist_ptr(srcptr->index); assert(psrc!=NULL); for (tgtptr=srcptr->next; tgtptr!=NULL; tgtptr=tgtptr->next) { if (tgtptr->index==-1) continue; /* state list id -1 is a special case */ ptgt=state_getlist_ptr(tgtptr->index); assert(ptgt!=NULL); if (psrc->fsa!=ptgt->fsa && strcmp(sym->name,uENTRYFUNC)!=0) error(83,sym->name); /* this function is part of another machine */ for (s=0; snumstates; s++) for (t=0; tnumstates; t++) if (psrc->states[s]==ptgt->states[t]) error(84,sym->name); /* state conflict */ } /* for (tgtptr) */ } /* for (srcptr) */ } /* for (sym) */ }