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