sourcepawn/compiler/scstate.c
author David Anderson <dvander@alliedmods.net>
Mon Mar 17 01:09:28 2008 +0000 (2008-03-17)
changeset 1941 54539fa4e51f
parent 365 d830b2b0414f
permissions -rw-r--r--
bumped versions
     1 /*  Pawn compiler
     2  *
     3  *  Machine and state maintenance.
     4  *
     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
    14  *    states.
    15  *
    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.
    21  *
    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.
    26  *
    27  *
    28  *  Copyright (c) ITB CompuPhase, 2005-2006
    29  *
    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.
    33  *
    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:
    37  *
    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.
    45  *
    46  *  Version: $Id$
    47  */
    48 #include <assert.h>
    49 #include <limits.h>
    50 #include <stdio.h>
    51 #include <stdlib.h>
    52 #include <string.h>
    53 #include "sc.h"
    54 #if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
    55   #include <sclinux.h>
    56 #endif
    57 
    58 #if defined FORTIFY
    59   #include <alloc/fortify.h>
    60 #endif
    61 
    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 */
    68 } statelist;
    69 
    70 static statelist statelist_tab = { NULL, NULL, 0, 0, 0};   /* state combinations table */
    71 
    72 
    73 static constvalue *find_automaton(const char *name,int *last)
    74 {
    75   constvalue *ptr;
    76 
    77   assert(last!=NULL);
    78   *last=0;
    79   ptr=sc_automaton_tab.next;
    80   while (ptr!=NULL) {
    81     if (strcmp(name,ptr->name)==0)
    82       return ptr;
    83     if (ptr->index>*last)
    84       *last=ptr->index;
    85     ptr=ptr->next;
    86   } /* while */
    87   return NULL;
    88 }
    89 
    90 SC_FUNC constvalue *automaton_add(const char *name)
    91 {
    92   constvalue *ptr;
    93   int last;
    94 
    95   assert(strlen(name)<sizeof(ptr->name));
    96   ptr=find_automaton(name,&last);
    97   if (ptr==NULL) {
    98     assert(last+1 <= SHRT_MAX);
    99     ptr=append_constval(&sc_automaton_tab,name,(cell)0,(short)(last+1));
   100   } /* if */
   101   return ptr;
   102 }
   103 
   104 SC_FUNC constvalue *automaton_find(const char *name)
   105 {
   106   int last;
   107   return find_automaton(name,&last);
   108 }
   109 
   110 SC_FUNC constvalue *automaton_findid(int id)
   111 {
   112   constvalue *ptr;
   113   for (ptr=sc_automaton_tab.next; ptr!=NULL && ptr->index!=id; ptr=ptr->next)
   114     /* nothing */;
   115   return ptr;
   116 }
   117 
   118 
   119 static constvalue *find_state(const char *name,int fsa,int *last)
   120 {
   121   constvalue *ptr;
   122 
   123   assert(last!=NULL);
   124   *last=0;
   125   ptr=sc_state_tab.next;
   126   while (ptr!=NULL) {
   127     if (ptr->index==fsa) {
   128       if (strcmp(name,ptr->name)==0)
   129         return ptr;
   130       if ((int)ptr->value>*last)
   131         *last=(int)ptr->value;
   132     } /* if */
   133     ptr=ptr->next;
   134   } /* while */
   135   return NULL;
   136 }
   137 
   138 SC_FUNC constvalue *state_add(const char *name,int fsa)
   139 {
   140   constvalue *ptr;
   141   int last;
   142 
   143   assert(strlen(name)<sizeof(ptr->name));
   144   ptr=find_state(name,fsa,&last);
   145   if (ptr==NULL) {
   146     assert(fsa <= SHRT_MAX);
   147     ptr=append_constval(&sc_state_tab,name,(cell)(last+1),(short)fsa);
   148   } /* if */
   149   return ptr;
   150 }
   151 
   152 SC_FUNC constvalue *state_find(const char *name,int fsa_id)
   153 {
   154   int last;     /* dummy */
   155   return find_state(name,fsa_id,&last);
   156 }
   157 
   158 SC_FUNC constvalue *state_findid(int id)
   159 {
   160   constvalue *ptr;
   161   for (ptr=sc_state_tab.next; ptr!=NULL && ptr->value!=id; ptr=ptr->next)
   162     /* nothing */;
   163   return ptr;
   164 }
   165 
   166 SC_FUNC void state_buildlist(int **list,int *listsize,int *count,int stateid)
   167 {
   168   int idx;
   169 
   170   assert(list!=NULL);
   171   assert(listsize!=NULL);
   172   assert(*listsize>=0);
   173   assert(count!=NULL);
   174   assert(*count>=0);
   175   assert(*count<=*listsize);
   176 
   177   if (*count==*listsize) {
   178     /* To avoid constantly calling malloc(), the list is grown by 4 states at
   179      * a time.
   180      */
   181     *listsize+=4;
   182     *list=(int*)realloc(*list,*listsize*sizeof(int));
   183     if (*list==NULL)
   184       error(103);               /* insufficient memory */
   185   } /* if */
   186 
   187   /* find the insertion point (the list has to stay sorted) */
   188   for (idx=0; idx<*count && *list[idx]<stateid; idx++)
   189     /* nothing */;
   190   if (idx<*count)
   191     memmove(&(*list)[idx+1],&(*list)[idx],(int)((*count-idx+1)*sizeof(int)));
   192   (*list)[idx]=stateid;
   193   *count+=1;
   194 }
   195 
   196 static statelist *state_findlist(int *list,int count,int fsa,int *last)
   197 {
   198   statelist *ptr;
   199   int i;
   200 
   201   assert(count>0);
   202   assert(last!=NULL);
   203   *last=0;
   204   ptr=statelist_tab.next;
   205   while (ptr!=NULL) {
   206     if (ptr->listid>*last)
   207       *last=ptr->listid;
   208     if (ptr->fsa==fsa && ptr->numstates==count) {
   209       /* compare all states */
   210       for (i=0; i<count && ptr->states[i]==list[i]; i++)
   211         /* nothing */;
   212       if (i==count)
   213         return ptr;
   214     } /* if */
   215     ptr=ptr->next;
   216   } /* while */
   217   return NULL;
   218 }
   219 
   220 static statelist *state_getlist_ptr(int listid)
   221 {
   222   statelist *ptr;
   223 
   224   assert(listid>0);
   225   for (ptr=statelist_tab.next; ptr!=NULL && ptr->listid!=listid; ptr=ptr->next)
   226     /* nothing */;
   227   return ptr;
   228 }
   229 
   230 SC_FUNC int state_addlist(int *list,int count,int fsa)
   231 {
   232   statelist *ptr;
   233   int last;
   234 
   235   assert(list!=NULL);
   236   assert(count>0);
   237   ptr=state_findlist(list,count,fsa,&last);
   238   if (ptr==NULL) {
   239     if ((ptr=(statelist*)malloc(sizeof(statelist)))==NULL)
   240       error(103);       /* insufficient memory */
   241     if ((ptr->states=(int*)malloc(count*sizeof(int)))==NULL) {
   242       free(ptr);
   243       error(103);       /* insufficient memory */
   244     } /* if */
   245     memcpy(ptr->states,list,count*sizeof(int));
   246     ptr->numstates=count;
   247     ptr->fsa=fsa;
   248     ptr->listid=last+1;
   249     ptr->next=statelist_tab.next;
   250     statelist_tab.next=ptr;
   251   } /* if */
   252   assert(ptr!=NULL);
   253   return ptr->listid;
   254 }
   255 
   256 SC_FUNC void state_deletetable(void)
   257 {
   258   statelist *ptr;
   259 
   260   while (statelist_tab.next!=NULL) {
   261     ptr=statelist_tab.next;
   262     /* unlink first */
   263     statelist_tab.next=ptr->next;
   264     /* then delete */
   265     assert(ptr->states!=NULL);
   266     free(ptr->states);
   267     free(ptr);
   268   } /* while */
   269 }
   270 
   271 SC_FUNC int state_getfsa(int listid)
   272 {
   273   statelist *ptr;
   274 
   275   assert(listid>=0);
   276   if (listid==0)
   277     return -1;
   278 
   279   ptr=state_getlist_ptr(listid);
   280   return (ptr!=NULL) ? ptr->fsa : -1; /* fsa 0 exists */
   281 }
   282 
   283 SC_FUNC int state_count(int listid)
   284 {
   285   statelist *ptr=state_getlist_ptr(listid);
   286   if (ptr==NULL)
   287     return 0;           /* unknown list, no states in it */
   288   return ptr->numstates;
   289 }
   290 
   291 SC_FUNC int state_inlist(int listid,int state)
   292 {
   293   statelist *ptr;
   294   int i;
   295 
   296   ptr=state_getlist_ptr(listid);
   297   if (ptr==NULL)
   298     return FALSE;       /* unknown list, state not in it */
   299   for (i=0; i<ptr->numstates; i++)
   300     if (ptr->states[i]==state)
   301       return TRUE;
   302   return FALSE;
   303 }
   304 
   305 SC_FUNC int state_listitem(int listid,int index)
   306 {
   307   statelist *ptr;
   308 
   309   ptr=state_getlist_ptr(listid);
   310   assert(ptr!=NULL);
   311   assert(index>=0 && index<ptr->numstates);
   312   return ptr->states[index];
   313 }
   314 
   315 static int checkconflict(statelist *psrc,statelist *ptgt)
   316 {
   317   int s,t;
   318 
   319   assert(psrc!=NULL);
   320   assert(ptgt!=NULL);
   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 */
   325   return 0;
   326 }
   327 
   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.
   331  */
   332 SC_FUNC void state_conflict(symbol *root)
   333 {
   334   statelist *psrc,*ptgt;
   335   constvalue *srcptr,*tgtptr;
   336   symbol *sym;
   337 
   338   assert(root!=NULL);
   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);
   348       assert(psrc!=NULL);
   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);
   353         assert(ptgt!=NULL);
   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 */
   358       } /* for (tgtptr) */
   359     } /* for (srcptr) */
   360   } /* for (sym) */
   361 }
   362 
   363 /* check whether the two state lists (whose ids are passed in) share any
   364  * states
   365  */
   366 SC_FUNC int state_conflict_id(int listid1,int listid2)
   367 {
   368   statelist *psrc,*ptgt;
   369 
   370   psrc=state_getlist_ptr(listid1);
   371   assert(psrc!=NULL);
   372   ptgt=state_getlist_ptr(listid2);
   373   assert(ptgt!=NULL);
   374   return checkconflict(psrc,ptgt);
   375 }