sourcepawn/compiler/scstate.c
author David Anderson <danderson@mozilla.com>
Thu Aug 08 09:40:23 2013 -0700 (2013-08-08)
changeset 3976 bc77cfde7c5c
parent 1952 b7aa2b626807
permissions -rw-r--r--
Add -Wno-narrowing to support building on GCC-4.7 (no bug, r=me).
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
}