made a copy faluco
authorBorja Ferrer <faluco@alliedmods.net>
Fri Jul 14 02:02:18 2006 +0000 (2006-07-14)
branchfaluco
changeset 59d43660ac558
parent 4 6939c78a1e27
parent 3 779f7763d1d0
child 6 abfa1699dd95
made a copy
compiler-init/compiler-init/amx.h
compiler-init/compiler-init/amxdbg.h
compiler-init/compiler-init/libpawnc.c
compiler-init/compiler-init/libpawnc.rc
compiler-init/compiler-init/lstring.c
compiler-init/compiler-init/lstring.h
compiler-init/compiler-init/memfile.c
compiler-init/compiler-init/memfile.h
compiler-init/compiler-init/osdefs.h
compiler-init/compiler-init/pawn.ico
compiler-init/compiler-init/pawncc.c
compiler-init/compiler-init/sc.h
compiler-init/compiler-init/sc1.c
compiler-init/compiler-init/sc2.c
compiler-init/compiler-init/sc3.c
compiler-init/compiler-init/sc4.c
compiler-init/compiler-init/sc5.c
compiler-init/compiler-init/sc5.scp
compiler-init/compiler-init/sc6.c
compiler-init/compiler-init/sc7.c
compiler-init/compiler-init/sc7.scp
compiler-init/compiler-init/scexpand.c
compiler-init/compiler-init/sci18n.c
compiler-init/compiler-init/sclist.c
compiler-init/compiler-init/scmemfil.c
compiler-init/compiler-init/scstate.c
compiler-init/compiler-init/scvars.c
compiler-init/compiler-init/spcomp.sln
compiler-init/compiler-init/spcomp.vcproj
compiler-init/compiler-init/svnrev.h
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/compiler-init/compiler-init/amx.h	Fri Jul 14 02:02:18 2006 +0000
     1.3 @@ -0,0 +1,462 @@
     1.4 +/*  Pawn Abstract Machine (for the Pawn language)
     1.5 + *
     1.6 + *  Copyright (c) ITB CompuPhase, 1997-2006
     1.7 + *
     1.8 + *  This software is provided "as-is", without any express or implied warranty.
     1.9 + *  In no event will the authors be held liable for any damages arising from
    1.10 + *  the use of this software.
    1.11 + *
    1.12 + *  Permission is granted to anyone to use this software for any purpose,
    1.13 + *  including commercial applications, and to alter it and redistribute it
    1.14 + *  freely, subject to the following restrictions:
    1.15 + *
    1.16 + *  1.  The origin of this software must not be misrepresented; you must not
    1.17 + *      claim that you wrote the original software. If you use this software in
    1.18 + *      a product, an acknowledgment in the product documentation would be
    1.19 + *      appreciated but is not required.
    1.20 + *  2.  Altered source versions must be plainly marked as such, and must not be
    1.21 + *      misrepresented as being the original software.
    1.22 + *  3.  This notice may not be removed or altered from any source distribution.
    1.23 + *
    1.24 + *  Version: $Id: amx.h 3579 2006-06-06 13:35:29Z thiadmer $
    1.25 + */
    1.26 +
    1.27 +#ifndef AMX_H_INCLUDED
    1.28 +#define AMX_H_INCLUDED
    1.29 +
    1.30 +#include <stdlib.h>   /* for size_t */
    1.31 +#include <limits.h>
    1.32 +
    1.33 +#if defined FREEBSD && !defined __FreeBSD__
    1.34 +  #define __FreeBSD__
    1.35 +#endif
    1.36 +#if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
    1.37 +  #include <sclinux.h>
    1.38 +#endif
    1.39 +
    1.40 +#if defined HAVE_STDINT_H
    1.41 +  #include <stdint.h>
    1.42 +#else
    1.43 +  #if defined __LCC__ || defined __DMC__ || defined LINUX || (defined __WATCOMC__ && __WATCOMC__ >= 1200)
    1.44 +    #if defined HAVE_INTTYPES_H
    1.45 +      #include <inttypes.h>
    1.46 +    #else
    1.47 +      #include <stdint.h>
    1.48 +    #endif
    1.49 +  #elif !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L
    1.50 +    /* The ISO C99 defines the int16_t and int_32t types. If the compiler got
    1.51 +     * here, these types are probably undefined.
    1.52 +     */
    1.53 +    #if defined __MACH__
    1.54 +      #include <ppc/types.h>
    1.55 +      typedef unsigned short int  uint16_t;
    1.56 +      typedef unsigned long int   uint32_t;
    1.57 +    #elif defined __FreeBSD__
    1.58 +      #include <inttypes.h>
    1.59 +    #else
    1.60 +      typedef short int           int16_t;
    1.61 +      typedef unsigned short int  uint16_t;
    1.62 +      #if defined SN_TARGET_PS2
    1.63 +        typedef int               int32_t;
    1.64 +        typedef unsigned int      uint32_t;
    1.65 +      #else
    1.66 +        typedef long int          int32_t;
    1.67 +        typedef unsigned long int uint32_t;
    1.68 +      #endif
    1.69 +      #if defined __WIN32__ || defined _WIN32 || defined WIN32
    1.70 +        typedef __int64	          int64_t;
    1.71 +        typedef unsigned __int64  uint64_t;
    1.72 +        #define HAVE_I64
    1.73 +      #elif defined __GNUC__
    1.74 +        typedef long long         int64_t;
    1.75 +        typedef unsigned long long uint64_t;
    1.76 +        #define HAVE_I64
    1.77 +      #endif
    1.78 +    #endif
    1.79 +  #endif
    1.80 +  #define HAVE_STDINT_H
    1.81 +#endif
    1.82 +#if defined _LP64 || defined WIN64 || defined _WIN64
    1.83 +  #if !defined __64BIT__
    1.84 +    #define __64BIT__
    1.85 +  #endif
    1.86 +#endif
    1.87 +
    1.88 +#if HAVE_ALLOCA_H
    1.89 +  #include <alloca.h>
    1.90 +#endif
    1.91 +#if defined __WIN32__ || defined _WIN32 || defined WIN32 /* || defined __MSDOS__ */
    1.92 +  #if !defined alloca
    1.93 +    #define alloca(n)   _alloca(n)
    1.94 +  #endif
    1.95 +#endif
    1.96 +
    1.97 +#if !defined arraysize
    1.98 +  #define arraysize(array)  (sizeof(array) / sizeof((array)[0]))
    1.99 +#endif
   1.100 +#if !defined assert_static
   1.101 +  /* see "Compile-Time Assertions" by Ralf Holly,
   1.102 +   * C/C++ Users Journal, November 2004
   1.103 +   */
   1.104 +  #define assert_static(e) \
   1.105 +    do { \
   1.106 +      enum { assert_static__ = 1/(e) }; \
   1.107 +    } while (0)
   1.108 +#endif
   1.109 +
   1.110 +#ifdef  __cplusplus
   1.111 +extern  "C" {
   1.112 +#endif
   1.113 +
   1.114 +#if defined PAWN_DLL
   1.115 +  #if !defined AMX_NATIVE_CALL
   1.116 +    #define AMX_NATIVE_CALL __stdcall
   1.117 +  #endif
   1.118 +  #if !defined AMXAPI
   1.119 +    #define AMXAPI          __stdcall
   1.120 +  #endif
   1.121 +#endif
   1.122 +
   1.123 +/* calling convention for native functions */
   1.124 +#if !defined AMX_NATIVE_CALL
   1.125 +  #define AMX_NATIVE_CALL
   1.126 +#endif
   1.127 +/* calling convention for all interface functions and callback functions */
   1.128 +#if !defined AMXAPI
   1.129 +  #if defined STDECL
   1.130 +    #define AMXAPI      __stdcall
   1.131 +  #elif defined CDECL
   1.132 +    #define AMXAPI      __cdecl
   1.133 +  #elif defined GCC_HASCLASSVISIBILITY
   1.134 +    #define AMXAPI __attribute__ ((visibility("default")))
   1.135 +  #else
   1.136 +    #define AMXAPI
   1.137 +  #endif
   1.138 +#endif
   1.139 +#if !defined AMXEXPORT
   1.140 +  #define AMXEXPORT
   1.141 +#endif
   1.142 +
   1.143 +/* File format version (in CUR_FILE_VERSION)
   1.144 + *   0 (original version)
   1.145 + *   1 (opcodes JUMP.pri, SWITCH and CASETBL)
   1.146 + *   2 (compressed files)
   1.147 + *   3 (public variables)
   1.148 + *   4 (opcodes SWAP.pri/alt and PUSHADDR)
   1.149 + *   5 (tagnames table)
   1.150 + *   6 (reformatted header)
   1.151 + *   7 (name table, opcodes SYMTAG & SYSREQ.D)
   1.152 + *   8 (opcode STMT, renewed debug interface)
   1.153 + *   9 (macro opcodes)
   1.154 + * MIN_FILE_VERSION is the lowest file version number that the current AMX
   1.155 + * implementation supports. If the AMX file header gets new fields, this number
   1.156 + * often needs to be incremented. MAX_AMX_VERSION is the lowest AMX version that
   1.157 + * is needed to support the current file version. When there are new opcodes,
   1.158 + * this number needs to be incremented.
   1.159 + * The file version supported by the JIT may run behind MIN_AMX_VERSION. So
   1.160 + * there is an extra constant for it: MAX_FILE_VER_JIT.
   1.161 + */
   1.162 +#define CUR_FILE_VERSION  9     /* current file version; also the current AMX version */
   1.163 +#define MIN_FILE_VERSION  6     /* lowest supported file format version for the current AMX version */
   1.164 +#define MIN_AMX_VERSION   9     /* minimum AMX version needed to support the current file format */
   1.165 +#define MAX_FILE_VER_JIT  8     /* file version supported by the JIT */
   1.166 +#define MIN_AMX_VER_JIT   8     /* AMX version supported by the JIT */
   1.167 +
   1.168 +#if !defined PAWN_CELL_SIZE
   1.169 +  #define PAWN_CELL_SIZE 32     /* by default, use 32-bit cells */
   1.170 +#endif
   1.171 +#if PAWN_CELL_SIZE==16
   1.172 +  typedef uint16_t  ucell;
   1.173 +  typedef int16_t   cell;
   1.174 +#elif PAWN_CELL_SIZE==32
   1.175 +  typedef uint32_t  ucell;
   1.176 +  typedef int32_t   cell;
   1.177 +#elif PAWN_CELL_SIZE==64
   1.178 +  typedef uint64_t  ucell;
   1.179 +  typedef int64_t   cell;
   1.180 +#else
   1.181 +  #error Unsupported cell size (PAWN_CELL_SIZE)
   1.182 +#endif
   1.183 +
   1.184 +#define UNPACKEDMAX   (((cell)1 << (sizeof(cell)-1)*8) - 1)
   1.185 +#define UNLIMITED     (~1u >> 1)
   1.186 +
   1.187 +struct tagAMX;
   1.188 +typedef cell (AMX_NATIVE_CALL *AMX_NATIVE)(struct tagAMX *amx, cell *params);
   1.189 +typedef int (AMXAPI *AMX_CALLBACK)(struct tagAMX *amx, cell index,
   1.190 +                                   cell *result, cell *params);
   1.191 +typedef int (AMXAPI *AMX_DEBUG)(struct tagAMX *amx);
   1.192 +typedef int (AMXAPI *AMX_IDLE)(struct tagAMX *amx, int AMXAPI Exec(struct tagAMX *, cell *, int));
   1.193 +#if !defined _FAR
   1.194 +  #define _FAR
   1.195 +#endif
   1.196 +
   1.197 +#if defined _MSC_VER
   1.198 +  #pragma warning(disable:4103)  /* disable warning message 4103 that complains
   1.199 +                                  * about pragma pack in a header file */
   1.200 +  #pragma warning(disable:4100)  /* "'%$S' : unreferenced formal parameter" */
   1.201 +#endif
   1.202 +
   1.203 +/* Some compilers do not support the #pragma align, which should be fine. Some
   1.204 + * compilers give a warning on unknown #pragmas, which is not so fine...
   1.205 + */
   1.206 +#if (defined SN_TARGET_PS2 || defined __GNUC__) && !defined AMX_NO_ALIGN
   1.207 +  #define AMX_NO_ALIGN
   1.208 +#endif
   1.209 +
   1.210 +#if defined __GNUC__
   1.211 +  #define PACKED        __attribute__((packed))
   1.212 +#else
   1.213 +  #define PACKED
   1.214 +#endif
   1.215 +
   1.216 +#if !defined AMX_NO_ALIGN
   1.217 +  #if defined LINUX || defined __FreeBSD__
   1.218 +    #pragma pack(1)         /* structures must be packed (byte-aligned) */
   1.219 +  #elif defined MACOS && defined __MWERKS__
   1.220 +	#pragma options align=mac68k
   1.221 +  #else
   1.222 +    #pragma pack(push)
   1.223 +    #pragma pack(1)         /* structures must be packed (byte-aligned) */
   1.224 +    #if defined __TURBOC__
   1.225 +      #pragma option -a-    /* "pack" pragma for older Borland compilers */
   1.226 +    #endif
   1.227 +  #endif
   1.228 +#endif
   1.229 +
   1.230 +typedef struct tagAMX_NATIVE_INFO {
   1.231 +  const char _FAR *name PACKED;
   1.232 +  AMX_NATIVE func       PACKED;
   1.233 +} AMX_NATIVE_INFO;
   1.234 +
   1.235 +#define AMX_USERNUM     4
   1.236 +#define sEXPMAX         19      /* maximum name length for file version <= 6 */
   1.237 +#define sNAMEMAX        31      /* maximum name length of symbol name */
   1.238 +
   1.239 +typedef struct tagAMX_FUNCSTUB {
   1.240 +  ucell address         PACKED;
   1.241 +  char name[sEXPMAX+1]  PACKED;
   1.242 +} AMX_FUNCSTUB;
   1.243 +
   1.244 +typedef struct tagFUNCSTUBNT {
   1.245 +  ucell address         PACKED;
   1.246 +  uint32_t nameofs      PACKED;
   1.247 +} AMX_FUNCSTUBNT;
   1.248 +
   1.249 +/* The AMX structure is the internal structure for many functions. Not all
   1.250 + * fields are valid at all times; many fields are cached in local variables.
   1.251 + */
   1.252 +typedef struct tagAMX {
   1.253 +  unsigned char _FAR *base PACKED; /* points to the AMX header plus the code, optionally also the data */
   1.254 +  unsigned char _FAR *data PACKED; /* points to separate data+stack+heap, may be NULL */
   1.255 +  AMX_CALLBACK callback PACKED;
   1.256 +  AMX_DEBUG debug       PACKED; /* debug callback */
   1.257 +  /* for external functions a few registers must be accessible from the outside */
   1.258 +  cell cip              PACKED; /* instruction pointer: relative to base + amxhdr->cod */
   1.259 +  cell frm              PACKED; /* stack frame base: relative to base + amxhdr->dat */
   1.260 +  cell hea              PACKED; /* top of the heap: relative to base + amxhdr->dat */
   1.261 +  cell hlw              PACKED; /* bottom of the heap: relative to base + amxhdr->dat */
   1.262 +  cell stk              PACKED; /* stack pointer: relative to base + amxhdr->dat */
   1.263 +  cell stp              PACKED; /* top of the stack: relative to base + amxhdr->dat */
   1.264 +  int flags             PACKED; /* current status, see amx_Flags() */
   1.265 +  /* user data */
   1.266 +  long usertags[AMX_USERNUM] PACKED;
   1.267 +  void _FAR *userdata[AMX_USERNUM] PACKED;
   1.268 +  /* native functions can raise an error */
   1.269 +  int error             PACKED;
   1.270 +  /* passing parameters requires a "count" field */
   1.271 +  int paramcount;
   1.272 +  /* the sleep opcode needs to store the full AMX status */
   1.273 +  cell pri              PACKED;
   1.274 +  cell alt              PACKED;
   1.275 +  cell reset_stk        PACKED;
   1.276 +  cell reset_hea        PACKED;
   1.277 +  cell sysreq_d         PACKED; /* relocated address/value for the SYSREQ.D opcode */
   1.278 +  #if defined JIT
   1.279 +    /* support variables for the JIT */
   1.280 +    int reloc_size      PACKED; /* required temporary buffer for relocations */
   1.281 +    long code_size      PACKED; /* estimated memory footprint of the native code */
   1.282 +  #endif
   1.283 +} AMX;
   1.284 +
   1.285 +/* The AMX_HEADER structure is both the memory format as the file format. The
   1.286 + * structure is used internaly.
   1.287 + */
   1.288 +typedef struct tagAMX_HEADER {
   1.289 +  int32_t size          PACKED; /* size of the "file" */
   1.290 +  uint16_t magic        PACKED; /* signature */
   1.291 +  char    file_version  PACKED; /* file format version */
   1.292 +  char    amx_version   PACKED; /* required version of the AMX */
   1.293 +  int16_t flags         PACKED;
   1.294 +  int16_t defsize       PACKED; /* size of a definition record */
   1.295 +  int32_t cod           PACKED; /* initial value of COD - code block */
   1.296 +  int32_t dat           PACKED; /* initial value of DAT - data block */
   1.297 +  int32_t hea           PACKED; /* initial value of HEA - start of the heap */
   1.298 +  int32_t stp           PACKED; /* initial value of STP - stack top */
   1.299 +  int32_t cip           PACKED; /* initial value of CIP - the instruction pointer */
   1.300 +  int32_t publics       PACKED; /* offset to the "public functions" table */
   1.301 +  int32_t natives       PACKED; /* offset to the "native functions" table */
   1.302 +  int32_t libraries     PACKED; /* offset to the table of libraries */
   1.303 +  int32_t pubvars       PACKED; /* the "public variables" table */
   1.304 +  int32_t tags          PACKED; /* the "public tagnames" table */
   1.305 +  int32_t nametable     PACKED; /* name table */
   1.306 +} AMX_HEADER;
   1.307 +
   1.308 +#if PAWN_CELL_SIZE==16
   1.309 +  #define AMX_MAGIC     0xf1e2
   1.310 +#elif PAWN_CELL_SIZE==32
   1.311 +  #define AMX_MAGIC     0xf1e0
   1.312 +#elif PAWN_CELL_SIZE==64
   1.313 +  #define AMX_MAGIC     0xf1e1
   1.314 +#endif
   1.315 +
   1.316 +enum {
   1.317 +  AMX_ERR_NONE,
   1.318 +  /* reserve the first 15 error codes for exit codes of the abstract machine */
   1.319 +  AMX_ERR_EXIT,         /* forced exit */
   1.320 +  AMX_ERR_ASSERT,       /* assertion failed */
   1.321 +  AMX_ERR_STACKERR,     /* stack/heap collision */
   1.322 +  AMX_ERR_BOUNDS,       /* index out of bounds */
   1.323 +  AMX_ERR_MEMACCESS,    /* invalid memory access */
   1.324 +  AMX_ERR_INVINSTR,     /* invalid instruction */
   1.325 +  AMX_ERR_STACKLOW,     /* stack underflow */
   1.326 +  AMX_ERR_HEAPLOW,      /* heap underflow */
   1.327 +  AMX_ERR_CALLBACK,     /* no callback, or invalid callback */
   1.328 +  AMX_ERR_NATIVE,       /* native function failed */
   1.329 +  AMX_ERR_DIVIDE,       /* divide by zero */
   1.330 +  AMX_ERR_SLEEP,        /* go into sleepmode - code can be restarted */
   1.331 +  AMX_ERR_INVSTATE,     /* invalid state for this access */
   1.332 +
   1.333 +  AMX_ERR_MEMORY = 16,  /* out of memory */
   1.334 +  AMX_ERR_FORMAT,       /* invalid file format */
   1.335 +  AMX_ERR_VERSION,      /* file is for a newer version of the AMX */
   1.336 +  AMX_ERR_NOTFOUND,     /* function not found */
   1.337 +  AMX_ERR_INDEX,        /* invalid index parameter (bad entry point) */
   1.338 +  AMX_ERR_DEBUG,        /* debugger cannot run */
   1.339 +  AMX_ERR_INIT,         /* AMX not initialized (or doubly initialized) */
   1.340 +  AMX_ERR_USERDATA,     /* unable to set user data field (table full) */
   1.341 +  AMX_ERR_INIT_JIT,     /* cannot initialize the JIT */
   1.342 +  AMX_ERR_PARAMS,       /* parameter error */
   1.343 +  AMX_ERR_DOMAIN,       /* domain error, expression result does not fit in range */
   1.344 +  AMX_ERR_GENERAL,      /* general error (unknown or unspecific error) */
   1.345 +};
   1.346 +
   1.347 +/*      AMX_FLAG_CHAR16   0x01     no longer used */
   1.348 +#define AMX_FLAG_DEBUG    0x02  /* symbolic info. available */
   1.349 +#define AMX_FLAG_COMPACT  0x04  /* compact encoding */
   1.350 +#define AMX_FLAG_SLEEP    0x08  /* script uses the sleep instruction (possible re-entry or power-down mode) */
   1.351 +#define AMX_FLAG_NOCHECKS 0x10  /* no array bounds checking; no BREAK opcodes */
   1.352 +#define AMX_FLAG_NTVREG 0x1000  /* all native functions are registered */
   1.353 +#define AMX_FLAG_JITC   0x2000  /* abstract machine is JIT compiled */
   1.354 +#define AMX_FLAG_BROWSE 0x4000  /* busy browsing */
   1.355 +#define AMX_FLAG_RELOC  0x8000  /* jump/call addresses relocated */
   1.356 +
   1.357 +#define AMX_EXEC_MAIN   (-1)    /* start at program entry point */
   1.358 +#define AMX_EXEC_CONT   (-2)    /* continue from last address */
   1.359 +
   1.360 +#define AMX_USERTAG(a,b,c,d)    ((a) | ((b)<<8) | ((long)(c)<<16) | ((long)(d)<<24))
   1.361 +
   1.362 +#if !defined AMX_COMPACTMARGIN
   1.363 +  #define AMX_COMPACTMARGIN 64
   1.364 +#endif
   1.365 +
   1.366 +/* for native functions that use floating point parameters, the following
   1.367 + * two macros are convenient for casting a "cell" into a "float" type _without_
   1.368 + * changing the bit pattern
   1.369 + */
   1.370 +#if PAWN_CELL_SIZE==32
   1.371 +  #define amx_ftoc(f)   ( * ((cell*)&f) )   /* float to cell */
   1.372 +  #define amx_ctof(c)   ( * ((float*)&c) )  /* cell to float */
   1.373 +#elif PAWN_CELL_SIZE==64
   1.374 +  #define amx_ftoc(f)   ( * ((cell*)&f) )   /* float to cell */
   1.375 +  #define amx_ctof(c)   ( * ((double*)&c) ) /* cell to float */
   1.376 +#else
   1.377 +  #error Unsupported cell size
   1.378 +#endif
   1.379 +
   1.380 +#define amx_StrParam(amx,param,result)                                      \
   1.381 +    do {                                                                    \
   1.382 +      cell *amx_cstr_; int amx_length_;                                     \
   1.383 +      amx_GetAddr((amx), (param), &amx_cstr_);                              \
   1.384 +      amx_StrLen(amx_cstr_, &amx_length_);                                  \
   1.385 +      if (amx_length_ > 0 &&                                                \
   1.386 +          ((result) = (void*)alloca((amx_length_ + 1) * sizeof(*(result)))) != NULL) \
   1.387 +        amx_GetString((char*)(result), amx_cstr_, sizeof(*(result))>1, amx_length_ + 1); \
   1.388 +      else (result) = NULL;                                                 \
   1.389 +    } while (0)
   1.390 +
   1.391 +uint16_t * AMXAPI amx_Align16(uint16_t *v);
   1.392 +uint32_t * AMXAPI amx_Align32(uint32_t *v);
   1.393 +#if defined _I64_MAX || defined HAVE_I64
   1.394 +  uint64_t * AMXAPI amx_Align64(uint64_t *v);
   1.395 +#endif
   1.396 +int AMXAPI amx_Allot(AMX *amx, int cells, cell *amx_addr, cell **phys_addr);
   1.397 +int AMXAPI amx_Callback(AMX *amx, cell index, cell *result, cell *params);
   1.398 +int AMXAPI amx_Cleanup(AMX *amx);
   1.399 +int AMXAPI amx_Clone(AMX *amxClone, AMX *amxSource, void *data);
   1.400 +int AMXAPI amx_Exec(AMX *amx, cell *retval, int index);
   1.401 +int AMXAPI amx_FindNative(AMX *amx, const char *name, int *index);
   1.402 +int AMXAPI amx_FindPublic(AMX *amx, const char *funcname, int *index);
   1.403 +int AMXAPI amx_FindPubVar(AMX *amx, const char *varname, cell *amx_addr);
   1.404 +int AMXAPI amx_FindTagId(AMX *amx, cell tag_id, char *tagname);
   1.405 +int AMXAPI amx_Flags(AMX *amx,uint16_t *flags);
   1.406 +int AMXAPI amx_GetAddr(AMX *amx,cell amx_addr,cell **phys_addr);
   1.407 +int AMXAPI amx_GetNative(AMX *amx, int index, char *funcname);
   1.408 +int AMXAPI amx_GetPublic(AMX *amx, int index, char *funcname);
   1.409 +int AMXAPI amx_GetPubVar(AMX *amx, int index, char *varname, cell *amx_addr);
   1.410 +int AMXAPI amx_GetString(char *dest,const cell *source, int use_wchar, size_t size);
   1.411 +int AMXAPI amx_GetTag(AMX *amx, int index, char *tagname, cell *tag_id);
   1.412 +int AMXAPI amx_GetUserData(AMX *amx, long tag, void **ptr);
   1.413 +int AMXAPI amx_Init(AMX *amx, void *program);
   1.414 +int AMXAPI amx_InitJIT(AMX *amx, void *reloc_table, void *native_code);
   1.415 +int AMXAPI amx_MemInfo(AMX *amx, long *codesize, long *datasize, long *stackheap);
   1.416 +int AMXAPI amx_NameLength(AMX *amx, int *length);
   1.417 +AMX_NATIVE_INFO * AMXAPI amx_NativeInfo(const char *name, AMX_NATIVE func);
   1.418 +int AMXAPI amx_NumNatives(AMX *amx, int *number);
   1.419 +int AMXAPI amx_NumPublics(AMX *amx, int *number);
   1.420 +int AMXAPI amx_NumPubVars(AMX *amx, int *number);
   1.421 +int AMXAPI amx_NumTags(AMX *amx, int *number);
   1.422 +int AMXAPI amx_Push(AMX *amx, cell value);
   1.423 +int AMXAPI amx_PushArray(AMX *amx, cell *amx_addr, cell **phys_addr, const cell array[], int numcells);
   1.424 +int AMXAPI amx_PushString(AMX *amx, cell *amx_addr, cell **phys_addr, const char *string, int pack, int use_wchar);
   1.425 +int AMXAPI amx_RaiseError(AMX *amx, int error);
   1.426 +int AMXAPI amx_Register(AMX *amx, const AMX_NATIVE_INFO *nativelist, int number);
   1.427 +int AMXAPI amx_Release(AMX *amx, cell amx_addr);
   1.428 +int AMXAPI amx_SetCallback(AMX *amx, AMX_CALLBACK callback);
   1.429 +int AMXAPI amx_SetDebugHook(AMX *amx, AMX_DEBUG debug);
   1.430 +int AMXAPI amx_SetString(cell *dest, const char *source, int pack, int use_wchar, size_t size);
   1.431 +int AMXAPI amx_SetUserData(AMX *amx, long tag, void *ptr);
   1.432 +int AMXAPI amx_StrLen(const cell *cstring, int *length);
   1.433 +int AMXAPI amx_UTF8Check(const char *string, int *length);
   1.434 +int AMXAPI amx_UTF8Get(const char *string, const char **endptr, cell *value);
   1.435 +int AMXAPI amx_UTF8Len(const cell *cstr, int *length);
   1.436 +int AMXAPI amx_UTF8Put(char *string, char **endptr, int maxchars, cell value);
   1.437 +
   1.438 +#if PAWN_CELL_SIZE==16
   1.439 +  #define amx_AlignCell(v) amx_Align16(v)
   1.440 +#elif PAWN_CELL_SIZE==32
   1.441 +  #define amx_AlignCell(v) amx_Align32(v)
   1.442 +#elif PAWN_CELL_SIZE==64 && (defined _I64_MAX || defined HAVE_I64)
   1.443 +  #define amx_AlignCell(v) amx_Align64(v)
   1.444 +#else
   1.445 +  #error Unsupported cell size
   1.446 +#endif
   1.447 +
   1.448 +#define amx_RegisterFunc(amx, name, func) \
   1.449 +  amx_Register((amx), amx_NativeInfo((name),(func)), 1);
   1.450 +
   1.451 +#if !defined AMX_NO_ALIGN
   1.452 +  #if defined LINUX || defined __FreeBSD__
   1.453 +    #pragma pack()    /* reset default packing */
   1.454 +  #elif defined MACOS && defined __MWERKS__
   1.455 +    #pragma options align=reset
   1.456 +  #else
   1.457 +    #pragma pack(pop) /* reset previous packing */
   1.458 +  #endif
   1.459 +#endif
   1.460 +
   1.461 +#ifdef  __cplusplus
   1.462 +}
   1.463 +#endif
   1.464 +
   1.465 +#endif /* AMX_H_INCLUDED */
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/compiler-init/compiler-init/amxdbg.h	Fri Jul 14 02:02:18 2006 +0000
     2.3 @@ -0,0 +1,172 @@
     2.4 +/*  Abstract Machine for the Pawn compiler, debugger support
     2.5 + *
     2.6 + *  This file contains extra definitions that are convenient for debugger
     2.7 + *  support.
     2.8 + *
     2.9 + *  Copyright (c) ITB CompuPhase, 2005-2006
    2.10 + *
    2.11 + *  This software is provided "as-is", without any express or implied warranty.
    2.12 + *  In no event will the authors be held liable for any damages arising from
    2.13 + *  the use of this software.
    2.14 + *
    2.15 + *  Permission is granted to anyone to use this software for any purpose,
    2.16 + *  including commercial applications, and to alter it and redistribute it
    2.17 + *  freely, subject to the following restrictions:
    2.18 + *
    2.19 + *  1.  The origin of this software must not be misrepresented; you must not
    2.20 + *      claim that you wrote the original software. If you use this software in
    2.21 + *      a product, an acknowledgment in the product documentation would be
    2.22 + *      appreciated but is not required.
    2.23 + *  2.  Altered source versions must be plainly marked as such, and must not be
    2.24 + *      misrepresented as being the original software.
    2.25 + *  3.  This notice may not be removed or altered from any source distribution.
    2.26 + *
    2.27 + *  Version: $Id: amxdbg.h 3519 2006-02-17 17:57:04Z thiadmer $
    2.28 + */
    2.29 +
    2.30 +#ifndef AMXDBG_H_INCLUDED
    2.31 +#define AMXDBG_H_INCLUDED
    2.32 +
    2.33 +#ifndef AMX_H_INCLUDED
    2.34 +  #include "amx.h"
    2.35 +#endif
    2.36 +
    2.37 +#ifdef  __cplusplus
    2.38 +extern  "C" {
    2.39 +#endif
    2.40 +
    2.41 +/* Some compilers do not support the #pragma align, which should be fine. Some
    2.42 + * compilers give a warning on unknown #pragmas, which is not so fine...
    2.43 + */
    2.44 +#if defined SN_TARGET_PS2 || defined __GNUC__
    2.45 +  #define AMX_NO_ALIGN
    2.46 +#endif
    2.47 +
    2.48 +#if defined __GNUC__
    2.49 +  #define PACKED        __attribute__((packed))
    2.50 +#else
    2.51 +  #define PACKED
    2.52 +#endif
    2.53 +
    2.54 +#if !defined AMX_NO_ALIGN
    2.55 +  #if defined LINUX || defined __FreeBSD__
    2.56 +    #pragma pack(1)         /* structures must be packed (byte-aligned) */
    2.57 +  #elif defined MACOS && defined __MWERKS__
    2.58 +	#pragma options align=mac68k
    2.59 +  #else
    2.60 +    #pragma pack(push)
    2.61 +    #pragma pack(1)         /* structures must be packed (byte-aligned) */
    2.62 +    #if defined __TURBOC__
    2.63 +      #pragma option -a-    /* "pack" pragma for older Borland compilers */
    2.64 +    #endif
    2.65 +  #endif
    2.66 +#endif
    2.67 +
    2.68 +typedef struct tagAMX_DBG_HDR {
    2.69 +  int32_t size          PACKED; /* size of the debug information chunk */
    2.70 +  uint16_t magic        PACKED; /* signature, must be 0xf1ef */
    2.71 +  char    file_version  PACKED; /* file format version */
    2.72 +  char    amx_version   PACKED; /* required version of the AMX */
    2.73 +  int16_t flags         PACKED; /* currently unused */
    2.74 +  int16_t files         PACKED; /* number of entries in the "file" table */
    2.75 +  int16_t lines         PACKED; /* number of entries in the "line" table */
    2.76 +  int16_t symbols       PACKED; /* number of entries in the "symbol" table */
    2.77 +  int16_t tags          PACKED; /* number of entries in the "tag" table */
    2.78 +  int16_t automatons    PACKED; /* number of entries in the "automaton" table */
    2.79 +  int16_t states        PACKED; /* number of entries in the "state" table */
    2.80 +} PACKED AMX_DBG_HDR;
    2.81 +#define AMX_DBG_MAGIC   0xf1ef
    2.82 +
    2.83 +typedef struct tagAMX_DBG_FILE {
    2.84 +  ucell   address       PACKED; /* address in the code segment where generated code (for this file) starts */
    2.85 +  const char name[1]    PACKED; /* ASCII string, zero-terminated */
    2.86 +} PACKED AMX_DBG_FILE;
    2.87 +
    2.88 +typedef struct tagAMX_DBG_LINE {
    2.89 +  ucell   address       PACKED; /* address in the code segment where generated code (for this line) starts */
    2.90 +  int32_t line          PACKED; /* line number */
    2.91 +} PACKED AMX_DBG_LINE;
    2.92 +
    2.93 +typedef struct tagAMX_DBG_SYMBOL {
    2.94 +  ucell   address       PACKED; /* address in the data segment or relative to the frame */
    2.95 +  int16_t tag           PACKED; /* tag for the symbol */
    2.96 +  ucell   codestart     PACKED; /* address in the code segment from which this symbol is valid (in scope) */
    2.97 +  ucell   codeend       PACKED; /* address in the code segment until which this symbol is valid (in scope) */
    2.98 +  char    ident         PACKED; /* kind of symbol (function/variable) */
    2.99 +  char    vclass        PACKED; /* class of symbol (global/local) */
   2.100 +  int16_t dim           PACKED; /* number of dimensions */
   2.101 +  const char name[1]    PACKED; /* ASCII string, zero-terminated */
   2.102 +} PACKED AMX_DBG_SYMBOL;
   2.103 +
   2.104 +typedef struct tagAMX_DBG_SYMDIM {
   2.105 +  int16_t tag           PACKED; /* tag for the array dimension */
   2.106 +  ucell   size          PACKED; /* size of the array dimension */
   2.107 +} PACKED AMX_DBG_SYMDIM;
   2.108 +
   2.109 +typedef struct tagAMX_DBG_TAG {
   2.110 +  int16_t tag           PACKED; /* tag id */
   2.111 +  const char name[1]    PACKED; /* ASCII string, zero-terminated */
   2.112 +} PACKED AMX_DBG_TAG;
   2.113 +
   2.114 +typedef struct tagAMX_DBG_MACHINE {
   2.115 +  int16_t automaton     PACKED; /* automaton id */
   2.116 +  ucell address         PACKED; /* address of state variable */
   2.117 +  const char name[1]    PACKED; /* ASCII string, zero-terminated */
   2.118 +} PACKED AMX_DBG_MACHINE;
   2.119 +
   2.120 +typedef struct tagAMX_DBG_STATE {
   2.121 +  int16_t state         PACKED; /* state id */
   2.122 +  int16_t automaton     PACKED; /* automaton id */
   2.123 +  const char name[1]    PACKED; /* ASCII string, zero-terminated */
   2.124 +} PACKED AMX_DBG_STATE;
   2.125 +
   2.126 +typedef struct tagAMX_DBG {
   2.127 +  AMX_DBG_HDR     *hdr           PACKED; /* points to the AMX_DBG header */
   2.128 +  AMX_DBG_FILE    **filetbl      PACKED;
   2.129 +  AMX_DBG_LINE    *linetbl       PACKED;
   2.130 +  AMX_DBG_SYMBOL  **symboltbl    PACKED;
   2.131 +  AMX_DBG_TAG     **tagtbl       PACKED;
   2.132 +  AMX_DBG_MACHINE **automatontbl PACKED;
   2.133 +  AMX_DBG_STATE   **statetbl     PACKED;
   2.134 +} PACKED AMX_DBG;
   2.135 +
   2.136 +#if !defined iVARIABLE
   2.137 +  #define iVARIABLE  1  /* cell that has an address and that can be fetched directly (lvalue) */
   2.138 +  #define iREFERENCE 2  /* iVARIABLE, but must be dereferenced */
   2.139 +  #define iARRAY     3
   2.140 +  #define iREFARRAY  4  /* an array passed by reference (i.e. a pointer) */
   2.141 +  #define iFUNCTN    9
   2.142 +#endif
   2.143 +
   2.144 +
   2.145 +int AMXAPI dbg_FreeInfo(AMX_DBG *amxdbg);
   2.146 +int AMXAPI dbg_LoadInfo(AMX_DBG *amxdbg, FILE *fp);
   2.147 +
   2.148 +int AMXAPI dbg_LookupFile(AMX_DBG *amxdbg, ucell address, const char **filename);
   2.149 +int AMXAPI dbg_LookupFunction(AMX_DBG *amxdbg, ucell address, const char **funcname);
   2.150 +int AMXAPI dbg_LookupLine(AMX_DBG *amxdbg, ucell address, long *line);
   2.151 +
   2.152 +int AMXAPI dbg_GetFunctionAddress(AMX_DBG *amxdbg, const char *funcname, const char *filename, ucell *address);
   2.153 +int AMXAPI dbg_GetLineAddress(AMX_DBG *amxdbg, long line, const char *filename, ucell *address);
   2.154 +int AMXAPI dbg_GetAutomatonName(AMX_DBG *amxdbg, int automaton, const char **name);
   2.155 +int AMXAPI dbg_GetStateName(AMX_DBG *amxdbg, int state, const char **name);
   2.156 +int AMXAPI dbg_GetTagName(AMX_DBG *amxdbg, int tag, const char **name);
   2.157 +int AMXAPI dbg_GetVariable(AMX_DBG *amxdbg, const char *symname, ucell scopeaddr, const AMX_DBG_SYMBOL **sym);
   2.158 +int AMXAPI dbg_GetArrayDim(AMX_DBG *amxdbg, const AMX_DBG_SYMBOL *sym, const AMX_DBG_SYMDIM **symdim);
   2.159 +
   2.160 +
   2.161 +#if !defined AMX_NO_ALIGN
   2.162 +  #if defined LINUX || defined __FreeBSD__
   2.163 +    #pragma pack()    /* reset default packing */
   2.164 +  #elif defined MACOS && defined __MWERKS__
   2.165 +    #pragma options align=reset
   2.166 +  #else
   2.167 +    #pragma pack(pop) /* reset previous packing */
   2.168 +  #endif
   2.169 +#endif
   2.170 +
   2.171 +#ifdef  __cplusplus
   2.172 +}
   2.173 +#endif
   2.174 +
   2.175 +#endif /* AMXDBG_H_INCLUDED */
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/compiler-init/compiler-init/libpawnc.c	Fri Jul 14 02:02:18 2006 +0000
     3.3 @@ -0,0 +1,257 @@
     3.4 +/*	LIBPAWNC.C
     3.5 + *
     3.6 + *	A "glue file" for building the Pawn compiler as a DLL or shared library.
     3.7 + *
     3.8 + *	Copyright (c) ITB CompuPhase, 2000-2006
     3.9 + *
    3.10 + *	This software is provided "as-is", without any express or implied warranty.
    3.11 + *	In no event will the authors be held liable for any damages arising from
    3.12 + *	the use of this software.
    3.13 + *
    3.14 + *	Permission is granted to anyone to use this software for any purpose,
    3.15 + *	including commercial applications, and to alter it and redistribute it
    3.16 + *	freely, subject to the following restrictions:
    3.17 + *
    3.18 + *	1.	The origin of this software must not be misrepresented; you must not
    3.19 + *			claim that you wrote the original software. If you use this software in
    3.20 + *			a product, an acknowledgment in the product documentation would be
    3.21 + *			appreciated but is not required.
    3.22 + *	2.	Altered source versions must be plainly marked as such, and must not be
    3.23 + *			misrepresented as being the original software.
    3.24 + *	3.	This notice may not be removed or altered from any source distribution.
    3.25 + *
    3.26 + *	Version: $Id: libsc.c 3114 2005-03-17 14:48:29Z thiadmer $
    3.27 + */
    3.28 +#include <assert.h>
    3.29 +#include <stdio.h>
    3.30 +#include <stdlib.h>
    3.31 +#include <string.h>
    3.32 +#include <malloc.h>
    3.33 +#include "sc.h"
    3.34 +#include "memfile.h"
    3.35 +
    3.36 +/* pc_printf()
    3.37 + * Called for general purpose "console" output. This function prints general
    3.38 + * purpose messages; errors go through pc_error(). The function is modelled
    3.39 + * after printf().
    3.40 + */
    3.41 +int pc_printf(const char *message,...)
    3.42 +{
    3.43 +	int ret;
    3.44 +	va_list argptr;
    3.45 +
    3.46 +	va_start(argptr,message);
    3.47 +	ret=vprintf(message,argptr);
    3.48 +	va_end(argptr);
    3.49 +
    3.50 +	return ret;
    3.51 +}
    3.52 +
    3.53 +/* pc_error()
    3.54 + * Called for producing error output.
    3.55 + *		number			the error number (as documented in the manual)
    3.56 + *		message		 a string describing the error with embedded %d and %s tokens
    3.57 + *		filename		the name of the file currently being parsed
    3.58 + *		firstline	 the line number at which the expression started on which
    3.59 + *								the error was found, or -1 if there is no "starting line"
    3.60 + *		lastline		the line number at which the error was detected
    3.61 + *		argptr			a pointer to the first of a series of arguments (for macro
    3.62 + *								"va_arg")
    3.63 + * Return:
    3.64 + *		If the function returns 0, the parser attempts to continue compilation.
    3.65 + *		On a non-zero return value, the parser aborts.
    3.66 + */
    3.67 +int pc_error(int number,char *message,char *filename,int firstline,int lastline,va_list argptr)
    3.68 +{
    3.69 +static char *prefix[3]={ "error", "fatal error", "warning" };
    3.70 +
    3.71 +	if (number!=0) {
    3.72 +		char *pre;
    3.73 +
    3.74 +		pre=prefix[number/100];
    3.75 +		if (firstline>=0)
    3.76 +			fprintf(stderr,"%s(%d -- %d) : %s %03d: ",filename,firstline,lastline,pre,number);
    3.77 +		else
    3.78 +			fprintf(stderr,"%s(%d) : %s %03d: ",filename,lastline,pre,number);
    3.79 +	} /* if */
    3.80 +	vfprintf(stderr,message,argptr);
    3.81 +	fflush(stderr);
    3.82 +	return 0;
    3.83 +}
    3.84 +
    3.85 +/* pc_opensrc()
    3.86 + * Opens a source file (or include file) for reading. The "file" does not have
    3.87 + * to be a physical file, one might compile from memory.
    3.88 + *		filename		the name of the "file" to read from
    3.89 + * Return:
    3.90 + *		The function must return a pointer, which is used as a "magic cookie" to
    3.91 + *		all I/O functions. When failing to open the file for reading, the
    3.92 + *		function must return NULL.
    3.93 + * Note:
    3.94 + *		Several "source files" may be open at the same time. Specifically, one
    3.95 + *		file can be open for reading and another for writing.
    3.96 + */
    3.97 +void *pc_opensrc(char *filename)
    3.98 +{
    3.99 +	return fopen(filename,"rt");
   3.100 +}
   3.101 +
   3.102 +/* pc_createsrc()
   3.103 + * Creates/overwrites a source file for writing. The "file" does not have
   3.104 + * to be a physical file, one might compile from memory.
   3.105 + *		filename		the name of the "file" to create
   3.106 + * Return:
   3.107 + *		The function must return a pointer which is used as a "magic cookie" to
   3.108 + *		all I/O functions. When failing to open the file for reading, the
   3.109 + *		function must return NULL.
   3.110 + * Note:
   3.111 + *		Several "source files" may be open at the same time. Specifically, one
   3.112 + *		file can be open for reading and another for writing.
   3.113 + */
   3.114 +void *pc_createsrc(char *filename)
   3.115 +{
   3.116 +	return fopen(filename,"wt");
   3.117 +}
   3.118 +
   3.119 +/* pc_closesrc()
   3.120 + * Closes a source file (or include file). The "handle" parameter has the
   3.121 + * value that pc_opensrc() returned in an earlier call.
   3.122 + */
   3.123 +void pc_closesrc(void *handle)
   3.124 +{
   3.125 +	assert(handle!=NULL);
   3.126 +	fclose((FILE*)handle);
   3.127 +}
   3.128 +
   3.129 +/* pc_resetsrc()
   3.130 + * "position" may only hold a pointer that was previously obtained from
   3.131 + * pc_getpossrc()
   3.132 + */
   3.133 +void pc_resetsrc(void *handle,void *position)
   3.134 +{
   3.135 +	assert(handle!=NULL);
   3.136 +	fsetpos((FILE*)handle,(fpos_t *)position);
   3.137 +}
   3.138 +
   3.139 +/* pc_readsrc()
   3.140 + * Reads a single line from the source file (or up to a maximum number of
   3.141 + * characters if the line in the input file is too long).
   3.142 + */
   3.143 +char *pc_readsrc(void *handle,unsigned char *target,int maxchars)
   3.144 +{
   3.145 +	return fgets((char*)target,maxchars,(FILE*)handle);
   3.146 +}
   3.147 +
   3.148 +/* pc_writesrc()
   3.149 + * Writes to to the source file. There is no automatic line ending; to end a
   3.150 + * line, write a "\n".
   3.151 + */
   3.152 +int pc_writesrc(void *handle,unsigned char *source)
   3.153 +{
   3.154 +	return fputs((char*)source,(FILE*)handle) >= 0;
   3.155 +}
   3.156 +
   3.157 +void *pc_getpossrc(void *handle)
   3.158 +{
   3.159 +	static fpos_t lastpos;	/* may need to have a LIFO stack of such positions */
   3.160 +
   3.161 +	fgetpos((FILE*)handle,&lastpos);
   3.162 +	return &lastpos;
   3.163 +}
   3.164 +
   3.165 +int pc_eofsrc(void *handle)
   3.166 +{
   3.167 +	return feof((FILE*)handle);
   3.168 +}
   3.169 +
   3.170 +/* should return a pointer, which is used as a "magic cookie" to all I/O
   3.171 + * functions; return NULL for failure
   3.172 + */
   3.173 +void *pc_openasm(char *filename)
   3.174 +{
   3.175 +	#if defined __MSDOS__ || defined SC_LIGHT
   3.176 +		return fopen(filename,"w+t");
   3.177 +	#else
   3.178 +		return mfcreate(filename);
   3.179 +	#endif
   3.180 +}
   3.181 +
   3.182 +void pc_closeasm(void *handle, int deletefile)
   3.183 +{
   3.184 +	#if defined __MSDOS__ || defined SC_LIGHT
   3.185 +		if (handle!=NULL)
   3.186 +			fclose((FILE*)handle);
   3.187 +		if (deletefile)
   3.188 +			remove(outfname);
   3.189 +	#else
   3.190 +		if (handle!=NULL) {
   3.191 +			if (!deletefile)
   3.192 +				mfdump((MEMFILE*)handle);
   3.193 +			mfclose((MEMFILE*)handle);
   3.194 +		} /* if */
   3.195 +	#endif
   3.196 +}
   3.197 +
   3.198 +void pc_resetasm(void *handle)
   3.199 +{
   3.200 +	assert(handle!=NULL);
   3.201 +	#if defined __MSDOS__ || defined SC_LIGHT
   3.202 +		fflush((FILE*)handle);
   3.203 +		fseek((FILE*)handle,0,SEEK_SET);
   3.204 +	#else
   3.205 +		mfseek((MEMFILE*)handle,0,SEEK_SET);
   3.206 +	#endif
   3.207 +}
   3.208 +
   3.209 +int pc_writeasm(void *handle,char *string)
   3.210 +{
   3.211 +	#if defined __MSDOS__ || defined SC_LIGHT
   3.212 +		return fputs(string,(FILE*)handle) >= 0;
   3.213 +	#else
   3.214 +		return mfputs((MEMFILE*)handle,string);
   3.215 +	#endif
   3.216 +}
   3.217 +
   3.218 +char *pc_readasm(void *handle, char *string, int maxchars)
   3.219 +{
   3.220 +	#if defined __MSDOS__ || defined SC_LIGHT
   3.221 +		return fgets(string,maxchars,(FILE*)handle);
   3.222 +	#else
   3.223 +		return mfgets((MEMFILE*)handle,string,maxchars);
   3.224 +	#endif
   3.225 +}
   3.226 +
   3.227 +/* Should return a pointer, which is used as a "magic cookie" to all I/O
   3.228 + * functions; return NULL for failure.
   3.229 + */
   3.230 +void *pc_openbin(char *filename)
   3.231 +{
   3.232 +	return memfile_creat(filename, 1);
   3.233 +}
   3.234 +
   3.235 +void pc_closebin(void *handle,int deletefile)
   3.236 +{
   3.237 +	if (deletefile)
   3.238 +	{
   3.239 +		memfile_destroy((memfile_t *)handle);
   3.240 +	}
   3.241 +}
   3.242 +
   3.243 +/* pc_resetbin()
   3.244 + * Can seek to any location in the file.
   3.245 + * The offset is always from the start of the file.
   3.246 + */
   3.247 +void pc_resetbin(void *handle,long offset)
   3.248 +{
   3.249 +	memfile_seek((memfile_t *)handle, offset);
   3.250 +}
   3.251 +
   3.252 +int pc_writebin(void *handle,void *buffer,int size)
   3.253 +{
   3.254 +	return memfile_write((memfile_t *)handle, buffer, size);
   3.255 +}
   3.256 +
   3.257 +long pc_lengthbin(void *handle)
   3.258 +{
   3.259 +	return memfile_tell((memfile_t *)handle);
   3.260 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/compiler-init/compiler-init/libpawnc.rc	Fri Jul 14 02:02:18 2006 +0000
     4.3 @@ -0,0 +1,55 @@
     4.4 +#include <windows.h>
     4.5 +#if defined WIN32 || defined _WIN32 || defined __WIN32__
     4.6 +#  include <winver.h>
     4.7 +#else
     4.8 +#  include <ver.h>
     4.9 +#endif
    4.10 +#include "svnrev.h"
    4.11 +
    4.12 +AppIcon ICON "pawn.ico"
    4.13 +
    4.14 +/*  Version information
    4.15 + *
    4.16 + *  All strings MUST have an explicit \0. See the Windows SDK documentation
    4.17 + *  for details on version information and the VERSIONINFO structure.
    4.18 + */
    4.19 +#define VERSION              SMC_VERSION
    4.20 +#define REVISION             SMC_REVISION
    4.21 +#define BUILD                SMC_BUILD
    4.22 +#define VERSIONSTR           SMC_VERSTRING
    4.23 +#define VERSIONNAME          "smcomp.exe\0"
    4.24 +#define VERSIONDESCRIPTION   "SourcePawn Compiler\0"
    4.25 +#define VERSIONPRODUCTNAME   "smcomp\0"
    4.26 +
    4.27 +VS_VERSION_INFO VERSIONINFO
    4.28 +FILEVERSION    VERSION, REVISION, BUILD, 0
    4.29 +PRODUCTVERSION VERSION, REVISION, BUILD, 0
    4.30 +FILEFLAGSMASK  0x0000003FL
    4.31 +FILEFLAGS      0
    4.32 +#if defined(WIN32)
    4.33 +  FILEOS       VOS__WINDOWS32
    4.34 +#else
    4.35 +  FILEOS       VOS__WINDOWS16
    4.36 +#endif
    4.37 +FILETYPE       VFT_DLL
    4.38 +BEGIN
    4.39 +    BLOCK "StringFileInfo"
    4.40 +    BEGIN
    4.41 +        BLOCK "040904E4"
    4.42 +        BEGIN
    4.43 +            VALUE "CompanyName",      "(C)1998-2006 ITB CompuPhase, AlliedModders LLC\0"
    4.44 +            VALUE "FileDescription",  VERSIONDESCRIPTION
    4.45 +            VALUE "FileVersion",      VERSIONSTR
    4.46 +            VALUE "InternalName",     VERSIONNAME
    4.47 +            VALUE "LegalCopyright",   "(C)1998-2006 ITB CompuPhase, AlliedModders LLC\0"
    4.48 +            VALUE "OriginalFilename", VERSIONNAME
    4.49 +            VALUE "ProductName",      VERSIONPRODUCTNAME
    4.50 +            VALUE "ProductVersion",   VERSIONSTR
    4.51 +        END
    4.52 +    END
    4.53 +
    4.54 +    BLOCK "VarFileInfo"
    4.55 +    BEGIN
    4.56 +        VALUE "Translation", 0x409, 1252
    4.57 +    END
    4.58 +END
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/compiler-init/compiler-init/lstring.c	Fri Jul 14 02:02:18 2006 +0000
     5.3 @@ -0,0 +1,124 @@
     5.4 +/* Safe string copying and concatenation
     5.5 + * These routines are originally distributed in two separate files. I have
     5.6 + * copied the files verbatim in this single source file, including all comments.
     5.7 + * The only change is that the second set of include files is commented out
     5.8 + * (there is no need to include the same files twice).
     5.9 + */
    5.10 +
    5.11 +#include "lstring.h"
    5.12 +
    5.13 +#if !defined HAVE_SAFESTR
    5.14 +
    5.15 +/*	$OpenBSD: strlcpy.c,v 1.10 2005/08/08 08:05:37 espie Exp $	*/
    5.16 +
    5.17 +/*
    5.18 + * Copyright (c) 1998 Todd C. Miller <[email protected]>
    5.19 + *
    5.20 + * Permission to use, copy, modify, and distribute this software for any
    5.21 + * purpose with or without fee is hereby granted, provided that the above
    5.22 + * copyright notice and this permission notice appear in all copies.
    5.23 + *
    5.24 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    5.25 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    5.26 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    5.27 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    5.28 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    5.29 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    5.30 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    5.31 + */
    5.32 +
    5.33 +/*
    5.34 +  #include <sys/types.h>  already included through lstring.h
    5.35 + */
    5.36 +#include <string.h>   /* for strlen() */
    5.37 +
    5.38 +/*
    5.39 + * Copy src to string dst of size siz.  At most siz-1 characters
    5.40 + * will be copied.  Always NUL terminates (unless siz == 0).
    5.41 + * Returns strlen(src); if retval >= siz, truncation occurred.
    5.42 + */
    5.43 +size_t
    5.44 +strlcpy(char *dst, const char *src, size_t siz)
    5.45 +{
    5.46 +	char *d = dst;
    5.47 +	const char *s = src;
    5.48 +	size_t n = siz;
    5.49 +
    5.50 +	/* Copy as many bytes as will fit */
    5.51 +	if (n != 0 && --n != 0) {
    5.52 +		do {
    5.53 +			if ((*d++ = *s++) == 0)
    5.54 +				break;
    5.55 +		} while (--n != 0);
    5.56 +	}
    5.57 +
    5.58 +	/* Not enough room in dst, add NUL and traverse rest of src */
    5.59 +	if (n == 0) {
    5.60 +		if (siz != 0)
    5.61 +			*d = '\0';		/* NUL-terminate dst */
    5.62 +		while (*s++)
    5.63 +			;
    5.64 +	}
    5.65 +
    5.66 +	return(s - src - 1);	/* count does not include NUL */
    5.67 +}
    5.68 +
    5.69 +/*	$OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $	*/
    5.70 +
    5.71 +/*
    5.72 + * Copyright (c) 1998 Todd C. Miller <[email protected]>
    5.73 + *
    5.74 + * Permission to use, copy, modify, and distribute this software for any
    5.75 + * purpose with or without fee is hereby granted, provided that the above
    5.76 + * copyright notice and this permission notice appear in all copies.
    5.77 + *
    5.78 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    5.79 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    5.80 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    5.81 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    5.82 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    5.83 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    5.84 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    5.85 + */
    5.86 +
    5.87 +/*
    5.88 +  #include <sys/types.h>    already included
    5.89 +  #include <string.h>       already included
    5.90 +*/
    5.91 +
    5.92 +/*
    5.93 + * Appends src to string dst of size siz (unlike strncat, siz is the
    5.94 + * full size of dst, not space left).  At most siz-1 characters
    5.95 + * will be copied.  Always NUL terminates (unless siz <= strlen(dst)).
    5.96 + * Returns strlen(src) + MIN(siz, strlen(initial dst)).
    5.97 + * If retval >= siz, truncation occurred.
    5.98 + */
    5.99 +size_t
   5.100 +strlcat(char *dst, const char *src, size_t siz)
   5.101 +{
   5.102 +	char *d = dst;
   5.103 +	const char *s = src;
   5.104 +	size_t n = siz;
   5.105 +	size_t dlen;
   5.106 +
   5.107 +	/* Find the end of dst and adjust bytes left but don't go past end */
   5.108 +	while (n-- != 0 && *d != '\0')
   5.109 +		d++;
   5.110 +	dlen = d - dst;
   5.111 +	n = siz - dlen;
   5.112 +
   5.113 +	if (n == 0)
   5.114 +		return(dlen + strlen(s));
   5.115 +	while (*s != '\0') {
   5.116 +		if (n != 1) {
   5.117 +			*d++ = *s;
   5.118 +			n--;
   5.119 +		}
   5.120 +		s++;
   5.121 +	}
   5.122 +	*d = '\0';
   5.123 +
   5.124 +	return(dlen + (s - src));	/* count does not include NUL */
   5.125 +}
   5.126 +
   5.127 +#endif /* #if !defined HAVE_SAFESTR */
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/compiler-init/compiler-init/lstring.h	Fri Jul 14 02:02:18 2006 +0000
     6.3 @@ -0,0 +1,18 @@
     6.4 +/* prototypes for strlcpy() and strlcat() */
     6.5 +
     6.6 +#include <stddef.h>
     6.7 +
     6.8 +#if defined __WATCOMC__ && __WATCOMC__ >= 1240
     6.9 +  /* OpenWatcom introduced BSD "safe string functions" with version 1.4 */
    6.10 +  #define HAVE_SAFESTR
    6.11 +#endif
    6.12 +
    6.13 +#if !defined HAVE_SAFESTR
    6.14 +
    6.15 +size_t
    6.16 +strlcpy(char *dst, const char *src, size_t siz);
    6.17 +
    6.18 +size_t
    6.19 +strlcat(char *dst, const char *src, size_t siz);
    6.20 +
    6.21 +#endif
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/compiler-init/compiler-init/memfile.c	Fri Jul 14 02:02:18 2006 +0000
     7.3 @@ -0,0 +1,105 @@
     7.4 +#include "memfile.h"
     7.5 +#include <string.h>
     7.6 +#include "osdefs.h"
     7.7 +
     7.8 +memfile_t *memfile_creat(const char *name, size_t init)
     7.9 +{
    7.10 +	memfile_t mf;
    7.11 +	memfile_t *pmf;
    7.12 +
    7.13 +	mf.size = init;
    7.14 +	mf.base = (char *)malloc(init);
    7.15 +	mf.usedoffs = 0;
    7.16 +	if (!mf.base)
    7.17 +	{
    7.18 +		return NULL;
    7.19 +	}
    7.20 +
    7.21 +	mf.offs = 0;
    7.22 +	mf._static = 0;
    7.23 +
    7.24 +	pmf = (memfile_t *)malloc(sizeof(memfile_t));
    7.25 +	memcpy(pmf, &mf, sizeof(memfile_t));
    7.26 +
    7.27 +	pmf->name = strdup(name);
    7.28 +
    7.29 +	return pmf;
    7.30 +}
    7.31 +
    7.32 +void memfile_destroy(memfile_t *mf)
    7.33 +{
    7.34 +	if (!mf->_static)
    7.35 +	{
    7.36 +		free(mf->name);
    7.37 +		free(mf->base);
    7.38 +		free(mf);
    7.39 +	}
    7.40 +}
    7.41 +
    7.42 +void memfile_seek(memfile_t *mf, long seek)
    7.43 +{
    7.44 +	mf->offs = seek;
    7.45 +}
    7.46 +
    7.47 +long memfile_tell(memfile_t *mf)
    7.48 +{
    7.49 +	return mf->offs;
    7.50 +}
    7.51 +
    7.52 +size_t memfile_read(memfile_t *mf, void *buffer, size_t maxsize)
    7.53 +{
    7.54 +	if (!maxsize || mf->offs >= mf->usedoffs)
    7.55 +	{
    7.56 +		return 0;
    7.57 +	}
    7.58 +
    7.59 +	if (mf->usedoffs - mf->offs < (long)maxsize)
    7.60 +	{
    7.61 +		maxsize = mf->usedoffs - mf->offs;
    7.62 +		if (!maxsize)
    7.63 +		{
    7.64 +			return 0;
    7.65 +		}
    7.66 +	}
    7.67 +
    7.68 +	memcpy(buffer, mf->base + mf->offs, maxsize);
    7.69 +
    7.70 +	mf->offs += maxsize;
    7.71 +
    7.72 +	return maxsize;
    7.73 +}
    7.74 +
    7.75 +int memfile_write(memfile_t *mf, void *buffer, size_t size)
    7.76 +{
    7.77 +	if (mf->offs + size > mf->size)
    7.78 +	{
    7.79 +		size_t newsize = (mf->size + size) * 2;
    7.80 +		if (mf->_static)
    7.81 +		{
    7.82 +			char *oldbase = mf->base;
    7.83 +			mf->base = (char *)malloc(newsize);
    7.84 +			if (!mf->base)
    7.85 +			{
    7.86 +				return 0;
    7.87 +			}
    7.88 +			memcpy(mf->base, oldbase, mf->size);
    7.89 +		} else {
    7.90 +			mf->base = (char *)realloc(mf->base, newsize);
    7.91 +			if (!mf->base)
    7.92 +			{
    7.93 +				return 0;
    7.94 +			}
    7.95 +		}
    7.96 +		mf->_static = 0;
    7.97 +		mf->size = newsize;
    7.98 +	}
    7.99 +	memcpy(mf->base + mf->offs, buffer, size);
   7.100 +	mf->offs += size;
   7.101 +
   7.102 +	if (mf->offs > mf->usedoffs)
   7.103 +	{
   7.104 +		mf->usedoffs = mf->offs;
   7.105 +	}
   7.106 +
   7.107 +	return 1;
   7.108 +}
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/compiler-init/compiler-init/memfile.h	Fri Jul 14 02:02:18 2006 +0000
     8.3 @@ -0,0 +1,23 @@
     8.4 +#ifndef _INCLUDE_MEMFILE_H
     8.5 +#define _INCLUDE_MEMFILE_H
     8.6 +
     8.7 +#include <malloc.h>
     8.8 +
     8.9 +typedef struct memfile_s
    8.10 +{
    8.11 +	char *name;
    8.12 +	char *base;
    8.13 +	long offs;
    8.14 +	long usedoffs;
    8.15 +	size_t size;
    8.16 +	int _static;
    8.17 +} memfile_t;
    8.18 +
    8.19 +memfile_t *memfile_creat(const char *name, size_t init);
    8.20 +void memfile_destroy(memfile_t *mf);
    8.21 +void memfile_seek(memfile_t *mf, long seek);
    8.22 +int memfile_write(memfile_t *mf, void *buffer, size_t size);
    8.23 +size_t memfile_read(memfile_t *mf, void *buffer, size_t maxsize);
    8.24 +long memfile_tell(memfile_t *mf);
    8.25 +
    8.26 +#endif //_INCLUDE_MEMFILE_H
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/compiler-init/compiler-init/osdefs.h	Fri Jul 14 02:02:18 2006 +0000
     9.3 @@ -0,0 +1,108 @@
     9.4 +/* __MSDOS__    set when compiling for DOS (not Windows)
     9.5 + * _Windows     set when compiling for any version of Microsoft Windows
     9.6 + * __WIN32__    set when compiling for Windows95 or WindowsNT (32 bit mode)
     9.7 + * __32BIT__    set when compiling in 32-bit "flat" mode (DOS or Windows)
     9.8 + *
     9.9 + * Copyright 1998-2005, ITB CompuPhase, The Netherlands.
    9.10 + * [email protected].
    9.11 + */
    9.12 +
    9.13 +#ifndef _OSDEFS_H
    9.14 +#define _OSDEFS_H
    9.15 +
    9.16 +/* Every compiler uses different "default" macros to indicate the mode
    9.17 + * it is in. Throughout the source, we use the Borland C++ macros, so
    9.18 + * the macros of Watcom C/C++ and Microsoft Visual C/C++ are mapped to
    9.19 + * those of Borland C++.
    9.20 + */
    9.21 +#if defined(__WATCOMC__)
    9.22 +#  if defined(__WINDOWS__) || defined(__NT__)
    9.23 +#    define _Windows    1
    9.24 +#  endif
    9.25 +#  ifdef __386__
    9.26 +#    define __32BIT__   1
    9.27 +#  endif
    9.28 +#  if defined(_Windows) && defined(__32BIT__)
    9.29 +#    define __WIN32__   1
    9.30 +#  endif
    9.31 +#elif defined(_MSC_VER)
    9.32 +#  if defined(_WINDOWS) || defined(_WIN32)
    9.33 +#    define _Windows    1
    9.34 +#  endif
    9.35 +#  ifdef _WIN32
    9.36 +#    define __WIN32__   1
    9.37 +#    define __32BIT__   1
    9.38 +#  endif
    9.39 +#  if _MSC_VER >= 1400
    9.40 +#    if !defined _CRT_SECURE_NO_DEPRECATE
    9.41 +#      define _CRT_SECURE_NO_DEPRECATE
    9.42 +#    endif
    9.43 +#    define strdup		_strdup
    9.44 +#    define stricmp		_stricmp
    9.45 +#    define access		_access
    9.46 +#    define chdir		_chdir
    9.47 +#    define strdup		_strdup
    9.48 +#  endif
    9.49 +#endif
    9.50 +
    9.51 +#if defined __FreeBSD__
    9.52 +   #include <sys/endian.h>
    9.53 +#elif defined LINUX
    9.54 +   #include <endian.h>
    9.55 +#endif
    9.56 +
    9.57 +/* Linux NOW has these */
    9.58 +#if !defined BIG_ENDIAN
    9.59 +  #define BIG_ENDIAN    4321
    9.60 +#endif
    9.61 +#if !defined LITTLE_ENDIAN
    9.62 +  #define LITTLE_ENDIAN 1234
    9.63 +#endif
    9.64 +
    9.65 +/* educated guess, BYTE_ORDER is undefined, i386 is common => little endian */
    9.66 +#if !defined BYTE_ORDER
    9.67 +  #if defined UCLINUX
    9.68 +    #define BYTE_ORDER BIG_ENDIAN
    9.69 +  #else
    9.70 +    #define BYTE_ORDER LITTLE_ENDIAN
    9.71 +  #endif
    9.72 +#endif
    9.73 +
    9.74 +#if defined __MSDOS__ || defined __WIN32__ || defined _Windows
    9.75 +  #define DIRSEP_CHAR '\\'
    9.76 +#elif defined macintosh
    9.77 +  #define DIRSEP_CHAR ':'
    9.78 +#else
    9.79 +  #define DIRSEP_CHAR '/'   /* directory separator character */
    9.80 +#endif
    9.81 +
    9.82 +/* _MAX_PATH is sometimes called differently and it may be in limits.h or
    9.83 + * stdlib.h instead of stdio.h.
    9.84 + */
    9.85 +#if !defined _MAX_PATH
    9.86 +  /* not defined, perhaps stdio.h was not included */
    9.87 +  #if !defined PATH_MAX
    9.88 +    #include <stdio.h>
    9.89 +  #endif
    9.90 +  #if !defined _MAX_PATH && !defined PATH_MAX
    9.91 +    /* no _MAX_PATH and no MAX_PATH, perhaps it is in limits.h */
    9.92 +    #include <limits.h>
    9.93 +  #endif
    9.94 +  #if !defined _MAX_PATH && !defined PATH_MAX
    9.95 +    /* no _MAX_PATH and no MAX_PATH, perhaps it is in stdlib.h */
    9.96 +    #include <stdlib.h>
    9.97 +  #endif
    9.98 +  /* if _MAX_PATH is undefined, try common alternative names */
    9.99 +  #if !defined _MAX_PATH
   9.100 +    #if defined MAX_PATH
   9.101 +      #define _MAX_PATH    MAX_PATH
   9.102 +    #elif defined _POSIX_PATH_MAX
   9.103 +      #define _MAX_PATH  _POSIX_PATH_MAX
   9.104 +    #else
   9.105 +      /* everything failed, actually we have a problem here... */
   9.106 +      #define _MAX_PATH  1024
   9.107 +    #endif
   9.108 +  #endif
   9.109 +#endif
   9.110 +
   9.111 +#endif  /* _OSDEFS_H */
    10.1 Binary file compiler-init/compiler-init/pawn.ico has changed
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/compiler-init/compiler-init/pawncc.c	Fri Jul 14 02:02:18 2006 +0000
    11.3 @@ -0,0 +1,30 @@
    11.4 +/*  Pawn compiler driver
    11.5 + *
    11.6 + *  Function and variable definition and declaration, statement parser.
    11.7 + *
    11.8 + *  Copyright (c) ITB CompuPhase, 2006
    11.9 + *
   11.10 + *  This software is provided "as-is", without any express or implied warranty.
   11.11 + *  In no event will the authors be held liable for any damages arising from
   11.12 + *  the use of this software.
   11.13 + *
   11.14 + *  Permission is granted to anyone to use this software for any purpose,
   11.15 + *  including commercial applications, and to alter it and redistribute it
   11.16 + *  freely, subject to the following restrictions:
   11.17 + *
   11.18 + *  1.  The origin of this software must not be misrepresented; you must not
   11.19 + *      claim that you wrote the original software. If you use this software in
   11.20 + *      a product, an acknowledgment in the product documentation would be
   11.21 + *      appreciated but is not required.
   11.22 + *  2.  Altered source versions must be plainly marked as such, and must not be
   11.23 + *      misrepresented as being the original software.
   11.24 + *  3.  This notice may not be removed or altered from any source distribution.
   11.25 + *
   11.26 + *  Version: $Id: Sc1.c 3114 2005-03-17 14:48:29Z thiadmer $
   11.27 + */
   11.28 +#include "sc.h"
   11.29 +
   11.30 +int main(int argc, char *argv[])
   11.31 +{
   11.32 +  return pc_compile(argc,argv);
   11.33 +}
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/compiler-init/compiler-init/sc.h	Fri Jul 14 02:02:18 2006 +0000
    12.3 @@ -0,0 +1,813 @@
    12.4 +/*  Pawn compiler
    12.5 + *
    12.6 + *  Drafted after the Small-C compiler Version 2.01, originally created
    12.7 + *  by Ron Cain, july 1980, and enhanced by James E. Hendrix.
    12.8 + *
    12.9 + *  This version comes close to a complete rewrite.
   12.10 + *
   12.11 + *  Copyright R. Cain, 1980
   12.12 + *  Copyright J.E. Hendrix, 1982, 1983
   12.13 + *  Copyright ITB CompuPhase, 1997-2006
   12.14 + *
   12.15 + *  This software is provided "as-is", without any express or implied warranty.
   12.16 + *  In no event will the authors be held liable for any damages arising from
   12.17 + *  the use of this software.
   12.18 + *
   12.19 + *  Permission is granted to anyone to use this software for any purpose,
   12.20 + *  including commercial applications, and to alter it and redistribute it
   12.21 + *  freely, subject to the following restrictions:
   12.22 + *
   12.23 + *  1.  The origin of this software must not be misrepresented; you must not
   12.24 + *      claim that you wrote the original software. If you use this software in
   12.25 + *      a product, an acknowledgment in the product documentation would be
   12.26 + *      appreciated but is not required.
   12.27 + *  2.  Altered source versions must be plainly marked as such, and must not be
   12.28 + *      misrepresented as being the original software.
   12.29 + *  3.  This notice may not be removed or altered from any source distribution.
   12.30 + *
   12.31 + *  Version: $Id: sc.h 3590 2006-06-24 14:16:39Z thiadmer $
   12.32 + */
   12.33 +#ifndef SC_H_INCLUDED
   12.34 +#define SC_H_INCLUDED
   12.35 +#include <limits.h>
   12.36 +#include <stdarg.h>
   12.37 +#include <stdio.h>
   12.38 +#if defined __BORLANDC__ && defined _Windows && !(defined __32BIT__ || defined __WIN32__)
   12.39 +  /* setjmp() and longjmp() not well supported in 16-bit windows */
   12.40 +  #include <windows.h>
   12.41 +  typedef int jmp_buf[9];
   12.42 +  #define setjmp(b)     Catch(b)
   12.43 +  #define longjmp(b,e)  Throw(b,e)
   12.44 +#else
   12.45 +  #include <setjmp.h>
   12.46 +#endif
   12.47 +#include "osdefs.h"
   12.48 +#include "amx.h"
   12.49 +
   12.50 +/* Note: the "cell" and "ucell" types are defined in AMX.H */
   12.51 +
   12.52 +#define PUBLIC_CHAR '@'     /* character that defines a function "public" */
   12.53 +#define CTRL_CHAR   '\\'    /* default control character */
   12.54 +#define sCHARBITS   8       /* size of a packed character */
   12.55 +
   12.56 +#define sDIMEN_MAX     4    /* maximum number of array dimensions */
   12.57 +#define sLINEMAX     1024   /* input line length (in characters) */
   12.58 +#define sCOMP_STACK   32    /* maximum nesting of #if .. #endif sections */
   12.59 +#define sDEF_LITMAX  500    /* initial size of the literal pool, in "cells" */
   12.60 +#define sDEF_AMXSTACK 4096  /* default stack size for AMX files */
   12.61 +#define PREPROC_TERM  '\x7f'/* termination character for preprocessor expressions (the "DEL" code) */
   12.62 +#define sDEF_PREFIX   "sourcemod.inc" /* default prefix filename */
   12.63 +
   12.64 +typedef union {
   12.65 +  void *pv;                 /* e.g. a name */
   12.66 +  int i;
   12.67 +} stkitem;                  /* type of items stored on the compiler stack */
   12.68 +
   12.69 +typedef struct s_arginfo {  /* function argument info */
   12.70 +  char name[sNAMEMAX+1];
   12.71 +  char ident;           /* iVARIABLE, iREFERENCE, iREFARRAY or iVARARGS */
   12.72 +  char usage;           /* uCONST */
   12.73 +  int *tags;            /* argument tag id. list */
   12.74 +  int numtags;          /* number of tags in the tag list */
   12.75 +  int dim[sDIMEN_MAX];
   12.76 +  int idxtag[sDIMEN_MAX];
   12.77 +  int numdim;           /* number of dimensions */
   12.78 +  unsigned char hasdefault; /* bit0: is there a default value? bit6: "tagof"; bit7: "sizeof" */
   12.79 +  union {
   12.80 +    cell val;           /* default value */
   12.81 +    struct {
   12.82 +      char *symname;    /* name of another symbol */
   12.83 +      short level;      /* indirection level for that symbol */
   12.84 +    } size;             /* used for "sizeof" default value */
   12.85 +    struct {
   12.86 +      cell *data;       /* values of default array */
   12.87 +      int size;         /* complete length of default array */
   12.88 +      int arraysize;    /* size to reserve on the heap */
   12.89 +      cell addr;        /* address of the default array in the data segment */
   12.90 +    } array;
   12.91 +  } defvalue;           /* default value, or pointer to default array */
   12.92 +  int defvalue_tag;     /* tag of the default value */
   12.93 +} arginfo;
   12.94 +
   12.95 +/*  Equate table, tagname table, library table */
   12.96 +typedef struct s_constvalue {
   12.97 +  struct s_constvalue *next;
   12.98 +  char name[sNAMEMAX+1];
   12.99 +  cell value;
  12.100 +  int index;            /* index level, for constants referring to array sizes/tags
  12.101 +                         * automaton id. for states and automatons
  12.102 +                         * tag for enumeration lists */
  12.103 +} constvalue;
  12.104 +
  12.105 +/*  Symbol table format
  12.106 + *
  12.107 + *  The symbol name read from the input file is stored in "name", the
  12.108 + *  value of "addr" is written to the output file. The address in "addr"
  12.109 + *  depends on the class of the symbol:
  12.110 + *      global          offset into the data segment
  12.111 + *      local           offset relative to the stack frame
  12.112 + *      label           generated hexadecimal number
  12.113 + *      function        offset into code segment
  12.114 + */
  12.115 +typedef struct s_symbol {
  12.116 +  struct s_symbol *next;
  12.117 +  struct s_symbol *parent;  /* hierarchical types (multi-dimensional arrays) */
  12.118 +  char name[sNAMEMAX+1];
  12.119 +  uint32_t hash;        /* value derived from name, for quicker searching */
  12.120 +  cell addr;            /* address or offset (or value for constant, index for native function) */
  12.121 +  cell codeaddr;        /* address (in the code segment) where the symbol declaration starts */
  12.122 +  char vclass;          /* sLOCAL if "addr" refers to a local symbol */
  12.123 +  char ident;           /* see below for possible values */
  12.124 +  short usage;          /* see below for possible values */
  12.125 +  char flags;           /* see below for possible values */
  12.126 +  int compound;         /* compound level (braces nesting level) */
  12.127 +  int tag;              /* tagname id */
  12.128 +  union {
  12.129 +    int declared;       /* label: how many local variables are declared */
  12.130 +    struct {
  12.131 +      int index;        /* array & enum: tag of array indices or the enum item */
  12.132 +      int field;        /* enumeration fields, where a size is attached to the field */
  12.133 +    } tags;             /* extra tags */
  12.134 +    constvalue *lib;    /* native function: library it is part of */
  12.135 +    long stacksize;     /* normal/public function: stack requirements */
  12.136 +  } x;                  /* 'x' for 'extra' */
  12.137 +  union {
  12.138 +    arginfo *arglist;   /* types of all parameters for functions */
  12.139 +    constvalue *enumlist;/* list of names for the "root" of an enumeration */
  12.140 +    struct {
  12.141 +      cell length;      /* arrays: length (size) */
  12.142 +      short level;      /* number of dimensions below this level */
  12.143 +    } array;
  12.144 +  } dim;                /* for 'dimension', both functions and arrays */
  12.145 +  constvalue *states;   /* list of state function/state variable ids + addresses */
  12.146 +  int fnumber;          /* static global variables: file number in which the declaration is visible */
  12.147 +  int lnumber;          /* line number (in the current source file) for the declaration */
  12.148 +  struct s_symbol **refer;  /* referrer list, functions that "use" this symbol */
  12.149 +  int numrefers;        /* number of entries in the referrer list */
  12.150 +  char *documentation;  /* optional documentation string */
  12.151 +} symbol;
  12.152 +
  12.153 +
  12.154 +/*  Possible entries for "ident". These are used in the "symbol", "value"
  12.155 + *  and arginfo structures. Not every constant is valid for every use.
  12.156 + *  In an argument list, the list is terminated with a "zero" ident; labels
  12.157 + *  cannot be passed as function arguments, so the value 0 is overloaded.
  12.158 + */
  12.159 +#define iLABEL      0
  12.160 +#define iVARIABLE   1   /* cell that has an address and that can be fetched directly (lvalue) */
  12.161 +#define iREFERENCE  2   /* iVARIABLE, but must be dereferenced */
  12.162 +#define iARRAY      3
  12.163 +#define iREFARRAY   4   /* an array passed by reference (i.e. a pointer) */
  12.164 +#define iARRAYCELL  5   /* array element, cell that must be fetched indirectly */
  12.165 +#define iARRAYCHAR  6   /* array element, character from cell from array */
  12.166 +#define iEXPRESSION 7   /* expression result, has no address (rvalue) */
  12.167 +#define iCONSTEXPR  8   /* constant expression (or constant symbol) */
  12.168 +#define iFUNCTN     9
  12.169 +#define iREFFUNC    10
  12.170 +#define iVARARGS    11  /* function specified ... as argument(s) */
  12.171 +
  12.172 +/*  Possible entries for "usage"
  12.173 + *
  12.174 + *  This byte is used as a serie of bits, the syntax is different for
  12.175 + *  functions and other symbols:
  12.176 + *
  12.177 + *  VARIABLE
  12.178 + *  bits: 0     (uDEFINE) the variable is defined in the source file
  12.179 + *        1     (uREAD) the variable is "read" (accessed) in the source file
  12.180 + *        2     (uWRITTEN) the variable is altered (assigned a value)
  12.181 + *        3     (uCONST) the variable is constant (may not be assigned to)
  12.182 + *        4     (uPUBLIC) the variable is public
  12.183 + *        6     (uSTOCK) the variable is discardable (without warning)
  12.184 + *
  12.185 + *  FUNCTION
  12.186 + *  bits: 0     (uDEFINE) the function is defined ("implemented") in the source file
  12.187 + *        1     (uREAD) the function is invoked in the source file
  12.188 + *        2     (uRETVALUE) the function returns a value (or should return a value)
  12.189 + *        3     (uPROTOTYPED) the function was prototyped (implicitly via a definition or explicitly)
  12.190 + *        4     (uPUBLIC) the function is public
  12.191 + *        5     (uNATIVE) the function is native
  12.192 + *        6     (uSTOCK) the function is discardable (without warning)
  12.193 + *        7     (uMISSING) the function is not implemented in this source file
  12.194 + *        8     (uFORWARD) the function is explicitly forwardly declared
  12.195 + *
  12.196 + *  CONSTANT
  12.197 + *  bits: 0     (uDEFINE) the symbol is defined in the source file
  12.198 + *        1     (uREAD) the constant is "read" (accessed) in the source file
  12.199 + *        2     (uWRITTEN) redundant, but may be set for constants passed by reference
  12.200 + *        3     (uPREDEF) the constant is pre-defined and should be kept between passes
  12.201 + *        5     (uENUMROOT) the constant is the "root" of an enumeration
  12.202 + *        6     (uENUMFIELD) the constant is a field in a named enumeration
  12.203 + */
  12.204 +#define uDEFINE   0x001
  12.205 +#define uREAD     0x002
  12.206 +#define uWRITTEN  0x004
  12.207 +#define uRETVALUE 0x004 /* function returns (or should return) a value */
  12.208 +#define uCONST    0x008
  12.209 +#define uPROTOTYPED 0x008
  12.210 +#define uPREDEF   0x008 /* constant is pre-defined */
  12.211 +#define uPUBLIC   0x010
  12.212 +#define uNATIVE   0x020
  12.213 +#define uENUMROOT 0x020
  12.214 +#define uSTOCK    0x040
  12.215 +#define uENUMFIELD 0x040
  12.216 +#define uMISSING  0x080
  12.217 +#define uFORWARD  0x100
  12.218 +/* uRETNONE is not stored in the "usage" field of a symbol. It is
  12.219 + * used during parsing a function, to detect a mix of "return;" and
  12.220 + * "return value;" in a few special cases.
  12.221 + */
  12.222 +#define uRETNONE  0x10
  12.223 +
  12.224 +#define flgDEPRICATED 0x01  /* symbol is depricated (avoid use) */
  12.225 +
  12.226 +#define uTAGOF    0x40  /* set in the "hasdefault" field of the arginfo struct */
  12.227 +#define uSIZEOF   0x80  /* set in the "hasdefault" field of the arginfo struct */
  12.228 +
  12.229 +#define uMAINFUNC "main"
  12.230 +#define uENTRYFUNC "entry"
  12.231 +
  12.232 +#define sGLOBAL   0     /* global variable/constant class (no states) */
  12.233 +#define sLOCAL    1     /* local variable/constant */
  12.234 +#define sSTATIC   2     /* global life, local scope */
  12.235 +
  12.236 +#define sSTATEVAR  3    /* criterion to find variables (sSTATEVAR implies a global variable) */
  12.237 +
  12.238 +typedef struct s_value {
  12.239 +  symbol *sym;          /* symbol in symbol table, NULL for (constant) expression */
  12.240 +  cell constval;        /* value of the constant expression (if ident==iCONSTEXPR)
  12.241 +                         * also used for the size of a literal array */
  12.242 +  int tag;              /* tag (of the expression) */
  12.243 +  int cmptag;           /* for searching symbols: choose the one with the matching tag */
  12.244 +  char ident;           /* iCONSTEXPR, iVARIABLE, iARRAY, iARRAYCELL,
  12.245 +                         * iEXPRESSION or iREFERENCE */
  12.246 +  char boolresult;      /* boolean result for relational operators */
  12.247 +  cell *arrayidx;       /* last used array indices, for checking self assignment */
  12.248 +} value;
  12.249 +
  12.250 +/*  "while" statement queue (also used for "for" and "do - while" loops) */
  12.251 +enum {
  12.252 +  wqBRK,        /* used to restore stack for "break" */
  12.253 +  wqCONT,       /* used to restore stack for "continue" */
  12.254 +  wqLOOP,       /* loop start label number */
  12.255 +  wqEXIT,       /* loop exit label number (jump if false) */
  12.256 +  /* --- */
  12.257 +  wqSIZE        /* "while queue" size */
  12.258 +};
  12.259 +#define wqTABSZ (24*wqSIZE)    /* 24 nested loop statements */
  12.260 +
  12.261 +enum {
  12.262 +  statIDLE,     /* not compiling yet */
  12.263 +  statFIRST,    /* first pass */
  12.264 +  statWRITE,    /* writing output */
  12.265 +  statSKIP,     /* skipping output */
  12.266 +};
  12.267 +
  12.268 +typedef struct s_stringlist {
  12.269 +  struct s_stringlist *next;
  12.270 +  char *line;
  12.271 +} stringlist;
  12.272 +
  12.273 +typedef struct s_stringpair {
  12.274 +  struct s_stringpair *next;
  12.275 +  char *first;
  12.276 +  char *second;
  12.277 +  int matchlength;
  12.278 +} stringpair;
  12.279 +
  12.280 +/* macros for code generation */
  12.281 +#define opcodes(n)      ((n)*sizeof(cell))      /* opcode size */
  12.282 +#define opargs(n)       ((n)*sizeof(cell))      /* size of typical argument */
  12.283 +
  12.284 +/*  Tokens recognized by lex()
  12.285 + *  Some of these constants are assigned as well to the variable "lastst"
  12.286 + */
  12.287 +#define tFIRST   256    /* value of first multi-character operator */
  12.288 +#define tMIDDLE  280    /* value of last multi-character operator */
  12.289 +#define tLAST    326    /* value of last multi-character match-able token */
  12.290 +/* multi-character operators */
  12.291 +#define taMULT   256    /* *= */
  12.292 +#define taDIV    257    /* /= */
  12.293 +#define taMOD    258    /* %= */
  12.294 +#define taADD    259    /* += */
  12.295 +#define taSUB    260    /* -= */
  12.296 +#define taSHL    261    /* <<= */
  12.297 +#define taSHRU   262    /* >>>= */
  12.298 +#define taSHR    263    /* >>= */
  12.299 +#define taAND    264    /* &= */
  12.300 +#define taXOR    265    /* ^= */
  12.301 +#define taOR     266    /* |= */
  12.302 +#define tlOR     267    /* || */
  12.303 +#define tlAND    268    /* && */
  12.304 +#define tlEQ     269    /* == */
  12.305 +#define tlNE     270    /* != */
  12.306 +#define tlLE     271    /* <= */
  12.307 +#define tlGE     272    /* >= */
  12.308 +#define tSHL     273    /* << */
  12.309 +#define tSHRU    274    /* >>> */
  12.310 +#define tSHR     275    /* >> */
  12.311 +#define tINC     276    /* ++ */
  12.312 +#define tDEC     277    /* -- */
  12.313 +#define tELLIPS  278    /* ... */
  12.314 +#define tDBLDOT  279    /* .. */
  12.315 +#define tDBLCOLON 280   /* :: */
  12.316 +/* reserved words (statements) */
  12.317 +#define tASSERT  281
  12.318 +#define tBREAK   282
  12.319 +#define tCASE    283
  12.320 +#define tCHAR    284
  12.321 +#define tCONST   285
  12.322 +#define tCONTINUE 286
  12.323 +#define tDEFAULT 287
  12.324 +#define tDEFINED 288
  12.325 +#define tDO      289
  12.326 +#define tELSE    290
  12.327 +#define tENUM    291
  12.328 +#define tEXIT    292
  12.329 +#define tFOR     293
  12.330 +#define tFORWARD 294
  12.331 +#define tGOTO    295
  12.332 +#define tIF      296
  12.333 +#define tNATIVE  297
  12.334 +#define tNEW     298
  12.335 +#define tDECL    299
  12.336 +#define tOPERATOR 300
  12.337 +#define tPUBLIC  301
  12.338 +#define tRETURN  303
  12.339 +#define tSIZEOF  303
  12.340 +#define tSLEEP   304
  12.341 +#define tSTATE   305
  12.342 +#define tSTATIC  306
  12.343 +#define tSTOCK   307
  12.344 +#define tSWITCH  308
  12.345 +#define tTAGOF   309
  12.346 +#define tWHILE   310
  12.347 +/* compiler directives */
  12.348 +#define tpASSERT 311    /* #assert */
  12.349 +#define tpDEFINE 312
  12.350 +#define tpELSE   313    /* #else */
  12.351 +#define tpELSEIF 314    /* #elseif */
  12.352 +#define tpEMIT   315
  12.353 +#define tpENDIF  316
  12.354 +#define tpENDINPUT 317
  12.355 +#define tpENDSCRPT 318
  12.356 +#define tpERROR  319
  12.357 +#define tpFILE   320
  12.358 +#define tpIF     321    /* #if */
  12.359 +#define tINCLUDE 322
  12.360 +#define tpLINE   323
  12.361 +#define tpPRAGMA 324
  12.362 +#define tpTRYINCLUDE 325
  12.363 +#define tpUNDEF  326
  12.364 +/* semicolon is a special case, because it can be optional */
  12.365 +#define tTERM    327    /* semicolon or newline */
  12.366 +#define tENDEXPR 328    /* forced end of expression */
  12.367 +/* other recognized tokens */
  12.368 +#define tNUMBER  329    /* integer number */
  12.369 +#define tRATIONAL 330   /* rational number */
  12.370 +#define tSYMBOL  331
  12.371 +#define tLABEL   332
  12.372 +#define tSTRING  333
  12.373 +#define tEXPR    334    /* for assigment to "lastst" only */
  12.374 +
  12.375 +/* (reversed) evaluation of staging buffer */
  12.376 +#define sSTARTREORDER 0x01
  12.377 +#define sENDREORDER   0x02
  12.378 +#define sEXPRSTART    0x80      /* top bit set, rest is free */
  12.379 +#define sMAXARGS      127       /* relates to the bit pattern of sEXPRSTART */
  12.380 +
  12.381 +#define sDOCSEP       0x01      /* to separate documentation comments between functions */
  12.382 +
  12.383 +/* codes for ffabort() */
  12.384 +#define xEXIT           1       /* exit code in PRI */
  12.385 +#define xASSERTION      2       /* abort caused by failing assertion */
  12.386 +#define xSTACKERROR     3       /* stack/heap overflow */
  12.387 +#define xBOUNDSERROR    4       /* array index out of bounds */
  12.388 +#define xMEMACCESS      5       /* data access error */
  12.389 +#define xINVINSTR       6       /* invalid instruction */
  12.390 +#define xSTACKUNDERFLOW 7       /* stack underflow */
  12.391 +#define xHEAPUNDERFLOW  8       /* heap underflow */
  12.392 +#define xCALLBACKERR    9       /* no, or invalid, callback */
  12.393 +#define xSLEEP         12       /* sleep, exit code in PRI, tag in ALT */
  12.394 +
  12.395 +/* Miscellaneous  */
  12.396 +#if !defined TRUE
  12.397 +  #define FALSE         0
  12.398 +  #define TRUE          1
  12.399 +#endif
  12.400 +#define sIN_CSEG        1       /* if parsing CODE */
  12.401 +#define sIN_DSEG        2       /* if parsing DATA */
  12.402 +#define sCHKBOUNDS      1       /* bit position in "debug" variable: check bounds */
  12.403 +#define sSYMBOLIC       2       /* bit position in "debug" variable: symbolic info */
  12.404 +#define sRESET          0       /* reset error flag */
  12.405 +#define sFORCESET       1       /* force error flag on */
  12.406 +#define sEXPRMARK       2       /* mark start of expression */
  12.407 +#define sEXPRRELEASE    3       /* mark end of expression */
  12.408 +#define sSETPOS         4       /* set line number for the error */
  12.409 +
  12.410 +enum {
  12.411 +  sOPTIMIZE_NONE,               /* no optimization */
  12.412 +  sOPTIMIZE_NOMACRO,            /* no macro instructions */
  12.413 +  sOPTIMIZE_DEFAULT,            /* full optimization */
  12.414 +  /* ----- */
  12.415 +  sOPTIMIZE_NUMBER
  12.416 +};
  12.417 +
  12.418 +typedef enum s_regid {
  12.419 +  sPRI,                         /* indicates the primary register */
  12.420 +  sALT,                         /* indicates the secundary register */
  12.421 +} regid;
  12.422 +
  12.423 +typedef enum s_optmark {
  12.424 +  sEXPR,                        /* end of expression (for expressions that form a statement) */
  12.425 +  sPARM,                        /* end of parameter (in a function parameter list) */
  12.426 +  sLDECL,                       /* start of local declaration (variable) */
  12.427 +} optmark;
  12.428 +
  12.429 +#define suSLEEP_INSTR 0x01      /* the "sleep" instruction was used */
  12.430 +
  12.431 +#if INT_MAX<0x8000u
  12.432 +  #define PUBLICTAG   0x8000u
  12.433 +  #define FIXEDTAG    0x4000u
  12.434 +#else
  12.435 +  #define PUBLICTAG   0x80000000Lu
  12.436 +  #define FIXEDTAG    0x40000000Lu
  12.437 +#endif
  12.438 +#define TAGMASK       (~PUBLICTAG)
  12.439 +#define CELL_MAX      (((ucell)1 << (sizeof(cell)*8-1)) - 1)
  12.440 +
  12.441 +
  12.442 +/* interface functions */
  12.443 +#if defined __cplusplus
  12.444 +  extern "C" {
  12.445 +#endif
  12.446 +
  12.447 +/*
  12.448 + * Functions you call from the "driver" program
  12.449 + */
  12.450 +int pc_compile(int argc, char **argv);
  12.451 +int pc_addconstant(char *name,cell value,int tag);
  12.452 +int pc_addtag(char *name);
  12.453 +int pc_enablewarning(int number,int enable);
  12.454 +
  12.455 +/*
  12.456 + * Functions called from the compiler (to be implemented by you)
  12.457 + */
  12.458 +
  12.459 +/* general console output */
  12.460 +int pc_printf(const char *message,...);
  12.461 +
  12.462 +/* error report function */
  12.463 +int pc_error(int number,char *message,char *filename,int firstline,int lastline,va_list argptr);
  12.464 +
  12.465 +/* input from source file */
  12.466 +void *pc_opensrc(char *filename); /* reading only */
  12.467 +void *pc_createsrc(char *filename);
  12.468 +void pc_closesrc(void *handle);   /* never delete */
  12.469 +void pc_resetsrc(void *handle,void *position);  /* reset to a position marked earlier */
  12.470 +char *pc_readsrc(void *handle,unsigned char *target,int maxchars);
  12.471 +int pc_writesrc(void *handle,unsigned char *source);
  12.472 +void *pc_getpossrc(void *handle); /* mark the current position */
  12.473 +int  pc_eofsrc(void *handle);
  12.474 +
  12.475 +/* output to intermediate (.ASM) file */
  12.476 +void *pc_openasm(char *filename); /* read/write */
  12.477 +void pc_closeasm(void *handle,int deletefile);
  12.478 +void pc_resetasm(void *handle);
  12.479 +int  pc_writeasm(void *handle,char *str);
  12.480 +char *pc_readasm(void *handle,char *target,int maxchars);
  12.481 +
  12.482 +/* output to binary (.AMX) file */
  12.483 +void *pc_openbin(char *filename);
  12.484 +void pc_closebin(void *handle,int deletefile);
  12.485 +void pc_resetbin(void *handle,long offset);
  12.486 +int  pc_writebin(void *handle,void *buffer,int size);
  12.487 +long pc_lengthbin(void *handle); /* return the length of the file */
  12.488 +
  12.489 +#if defined __cplusplus
  12.490 +  }
  12.491 +#endif
  12.492 +
  12.493 +
  12.494 +/* by default, functions and variables used in throughout the compiler
  12.495 + * files are "external"
  12.496 + */
  12.497 +#if !defined SC_FUNC
  12.498 +  #define SC_FUNC
  12.499 +#endif
  12.500 +#if !defined SC_VDECL
  12.501 +  #define SC_VDECL  extern
  12.502 +#endif
  12.503 +#if !defined SC_VDEFINE
  12.504 +  #define SC_VDEFINE
  12.505 +#endif
  12.506 +
  12.507 +/* function prototypes in SC1.C */
  12.508 +SC_FUNC void set_extension(char *filename,char *extension,int force);
  12.509 +SC_FUNC symbol *fetchfunc(char *name,int tag);
  12.510 +SC_FUNC char *operator_symname(char *symname,char *opername,int tag1,int tag2,int numtags,int resulttag);
  12.511 +SC_FUNC char *funcdisplayname(char *dest,char *funcname);
  12.512 +SC_FUNC int constexpr(cell *val,int *tag,symbol **symptr);
  12.513 +SC_FUNC constvalue *append_constval(constvalue *table,const char *name,cell val,int index);
  12.514 +SC_FUNC constvalue *find_constval(constvalue *table,char *name,int index);
  12.515 +SC_FUNC void delete_consttable(constvalue *table);
  12.516 +SC_FUNC symbol *add_constant(char *name,cell val,int vclass,int tag);
  12.517 +SC_FUNC void exporttag(int tag);
  12.518 +SC_FUNC void sc_attachdocumentation(symbol *sym);
  12.519 +
  12.520 +/* function prototypes in SC2.C */
  12.521 +#define PUSHSTK_P(v)  { stkitem s_; s_.pv=(v); pushstk(s_); }
  12.522 +#define PUSHSTK_I(v)  { stkitem s_; s_.i=(v); pushstk(s_); }
  12.523 +#define POPSTK_P()    (popstk().pv)
  12.524 +#define POPSTK_I()    (popstk().i)
  12.525 +SC_FUNC void pushstk(stkitem val);
  12.526 +SC_FUNC stkitem popstk(void);
  12.527 +SC_FUNC void clearstk(void);
  12.528 +SC_FUNC int plungequalifiedfile(char *name);  /* explicit path included */
  12.529 +SC_FUNC int plungefile(char *name,int try_currentpath,int try_includepaths);   /* search through "include" paths */
  12.530 +SC_FUNC void preprocess(void);
  12.531 +SC_FUNC void lexinit(void);
  12.532 +SC_FUNC int lex(cell *lexvalue,char **lexsym);
  12.533 +SC_FUNC void lexpush(void);
  12.534 +SC_FUNC void lexclr(int clreol);
  12.535 +SC_FUNC int matchtoken(int token);
  12.536 +SC_FUNC int tokeninfo(cell *val,char **str);
  12.537 +SC_FUNC int needtoken(int token);
  12.538 +SC_FUNC void litadd(cell value);
  12.539 +SC_FUNC void litinsert(cell value,int pos);
  12.540 +SC_FUNC int alphanum(char c);
  12.541 +SC_FUNC int ishex(char c);
  12.542 +SC_FUNC void delete_symbol(symbol *root,symbol *sym);
  12.543 +SC_FUNC void delete_symbols(symbol *root,int level,int del_labels,int delete_functions);
  12.544 +SC_FUNC int refer_symbol(symbol *entry,symbol *bywhom);
  12.545 +SC_FUNC void markusage(symbol *sym,int usage);
  12.546 +SC_FUNC uint32_t namehash(const char *name);
  12.547 +SC_FUNC symbol *findglb(const char *name,int filter);
  12.548 +SC_FUNC symbol *findloc(const char *name);
  12.549 +SC_FUNC symbol *findconst(const char *name,int *matchtag);
  12.550 +SC_FUNC symbol *finddepend(const symbol *parent);
  12.551 +SC_FUNC symbol *addsym(const char *name,cell addr,int ident,int vclass,int tag,
  12.552 +                       int usage);
  12.553 +SC_FUNC symbol *addvariable(const char *name,cell addr,int ident,int vclass,int tag,
  12.554 +                            int dim[],int numdim,int idxtag[]);
  12.555 +SC_FUNC int getlabel(void);
  12.556 +SC_FUNC char *itoh(ucell val);
  12.557 +
  12.558 +/* function prototypes in SC3.C */
  12.559 +SC_FUNC int check_userop(void (*oper)(void),int tag1,int tag2,int numparam,
  12.560 +                         value *lval,int *resulttag);
  12.561 +SC_FUNC int matchtag(int formaltag,int actualtag,int allowcoerce);
  12.562 +SC_FUNC int expression(cell *val,int *tag,symbol **symptr,int chkfuncresult);
  12.563 +SC_FUNC int sc_getstateid(constvalue **automaton,constvalue **state);
  12.564 +SC_FUNC cell array_totalsize(symbol *sym);
  12.565 +
  12.566 +/* function prototypes in SC4.C */
  12.567 +SC_FUNC void writeleader(symbol *root);
  12.568 +SC_FUNC void writetrailer(void);
  12.569 +SC_FUNC void begcseg(void);
  12.570 +SC_FUNC void begdseg(void);
  12.571 +SC_FUNC void setline(int chkbounds);
  12.572 +SC_FUNC void setfiledirect(char *name);
  12.573 +SC_FUNC void setlinedirect(int line);
  12.574 +SC_FUNC void setlabel(int index);
  12.575 +SC_FUNC void markexpr(optmark type,const char *name,cell offset);
  12.576 +SC_FUNC void startfunc(char *fname);
  12.577 +SC_FUNC void endfunc(void);
  12.578 +SC_FUNC void alignframe(int numbytes);
  12.579 +SC_FUNC void rvalue(value *lval);
  12.580 +SC_FUNC void address(symbol *ptr,regid reg);
  12.581 +SC_FUNC void store(value *lval);
  12.582 +SC_FUNC void loadreg(cell address,regid reg);
  12.583 +SC_FUNC void storereg(cell address,regid reg);
  12.584 +SC_FUNC void memcopy(cell size);
  12.585 +SC_FUNC void copyarray(symbol *sym,cell size);
  12.586 +SC_FUNC void fillarray(symbol *sym,cell size,cell value);
  12.587 +SC_FUNC void ldconst(cell val,regid reg);
  12.588 +SC_FUNC void moveto1(void);
  12.589 +SC_FUNC void pushreg(regid reg);
  12.590 +SC_FUNC void pushval(cell val);
  12.591 +SC_FUNC void popreg(regid reg);
  12.592 +SC_FUNC void swap1(void);
  12.593 +SC_FUNC void ffswitch(int label);
  12.594 +SC_FUNC void ffcase(cell value,char *labelname,int newtable);
  12.595 +SC_FUNC void ffcall(symbol *sym,const char *label,int numargs);
  12.596 +SC_FUNC void ffret(int remparams);
  12.597 +SC_FUNC void ffabort(int reason);
  12.598 +SC_FUNC void ffbounds(cell size);
  12.599 +SC_FUNC void jumplabel(int number);
  12.600 +SC_FUNC void defstorage(void);
  12.601 +SC_FUNC void modstk(int delta);
  12.602 +SC_FUNC void setstk(cell value);
  12.603 +SC_FUNC void modheap(int delta);
  12.604 +SC_FUNC void setheap_pri(void);
  12.605 +SC_FUNC void setheap(cell value);
  12.606 +SC_FUNC void cell2addr(void);
  12.607 +SC_FUNC void cell2addr_alt(void);
  12.608 +SC_FUNC void addr2cell(void);
  12.609 +SC_FUNC void char2addr(void);
  12.610 +SC_FUNC void charalign(void);
  12.611 +SC_FUNC void addconst(cell value);
  12.612 +
  12.613 +/*  Code generation functions for arithmetic operators.
  12.614 + *
  12.615 + *  Syntax: o[u|s|b]_name
  12.616 + *          |   |   | +--- name of operator
  12.617 + *          |   |   +----- underscore
  12.618 + *          |   +--------- "u"nsigned operator, "s"igned operator or "b"oth
  12.619 + *          +------------- "o"perator
  12.620 + */
  12.621 +SC_FUNC void os_mult(void); /* multiplication (signed) */
  12.622 +SC_FUNC void os_div(void);  /* division (signed) */
  12.623 +SC_FUNC void os_mod(void);  /* modulus (signed) */
  12.624 +SC_FUNC void ob_add(void);  /* addition */
  12.625 +SC_FUNC void ob_sub(void);  /* subtraction */
  12.626 +SC_FUNC void ob_sal(void);  /* shift left (arithmetic) */
  12.627 +SC_FUNC void os_sar(void);  /* shift right (arithmetic, signed) */
  12.628 +SC_FUNC void ou_sar(void);  /* shift right (logical, unsigned) */
  12.629 +SC_FUNC void ob_or(void);   /* bitwise or */
  12.630 +SC_FUNC void ob_xor(void);  /* bitwise xor */
  12.631 +SC_FUNC void ob_and(void);  /* bitwise and */
  12.632 +SC_FUNC void ob_eq(void);   /* equality */
  12.633 +SC_FUNC void ob_ne(void);   /* inequality */
  12.634 +SC_FUNC void relop_prefix(void);
  12.635 +SC_FUNC void relop_suffix(void);
  12.636 +SC_FUNC void os_le(void);   /* less or equal (signed) */
  12.637 +SC_FUNC void os_ge(void);   /* greater or equal (signed) */
  12.638 +SC_FUNC void os_lt(void);   /* less (signed) */
  12.639 +SC_FUNC void os_gt(void);   /* greater (signed) */
  12.640 +
  12.641 +SC_FUNC void lneg(void);
  12.642 +SC_FUNC void neg(void);
  12.643 +SC_FUNC void invert(void);
  12.644 +SC_FUNC void nooperation(void);
  12.645 +SC_FUNC void inc(value *lval);
  12.646 +SC_FUNC void dec(value *lval);
  12.647 +SC_FUNC void jmp_ne0(int number);
  12.648 +SC_FUNC void jmp_eq0(int number);
  12.649 +SC_FUNC void outval(cell val,int newline);
  12.650 +
  12.651 +/* function prototypes in SC5.C */
  12.652 +SC_FUNC int error(int number,...);
  12.653 +SC_FUNC void errorset(int code,int line);
  12.654 +
  12.655 +/* function prototypes in SC6.C */
  12.656 +SC_FUNC int assemble(FILE *fout,FILE *fin);
  12.657 +
  12.658 +/* function prototypes in SC7.C */
  12.659 +SC_FUNC void stgbuffer_cleanup(void);
  12.660 +SC_FUNC void stgmark(char mark);
  12.661 +SC_FUNC void stgwrite(const char *st);
  12.662 +SC_FUNC void stgout(int index);
  12.663 +SC_FUNC void stgdel(int index,cell code_index);
  12.664 +SC_FUNC int stgget(int *index,cell *code_index);
  12.665 +SC_FUNC void stgset(int onoff);
  12.666 +SC_FUNC int phopt_init(void);
  12.667 +SC_FUNC int phopt_cleanup(void);
  12.668 +
  12.669 +/* function prototypes in SCLIST.C */
  12.670 +SC_FUNC char* duplicatestring(const char* sourcestring);
  12.671 +SC_FUNC stringpair *insert_alias(char *name,char *alias);
  12.672 +SC_FUNC stringpair *find_alias(char *name);
  12.673 +SC_FUNC int lookup_alias(char *target,char *name);
  12.674 +SC_FUNC void delete_aliastable(void);
  12.675 +SC_FUNC stringlist *insert_path(char *path);
  12.676 +SC_FUNC char *get_path(int index);
  12.677 +SC_FUNC void delete_pathtable(void);
  12.678 +SC_FUNC stringpair *insert_subst(char *pattern,char *substitution,int prefixlen);
  12.679 +SC_FUNC int get_subst(int index,char **pattern,char **substitution);
  12.680 +SC_FUNC stringpair *find_subst(char *name,int length);
  12.681 +SC_FUNC int delete_subst(char *name,int length);
  12.682 +SC_FUNC void delete_substtable(void);
  12.683 +SC_FUNC stringlist *insert_sourcefile(char *string);
  12.684 +SC_FUNC char *get_sourcefile(int index);
  12.685 +SC_FUNC void delete_sourcefiletable(void);
  12.686 +SC_FUNC stringlist *insert_docstring(char *string);
  12.687 +SC_FUNC char *get_docstring(int index);
  12.688 +SC_FUNC void delete_docstring(int index);
  12.689 +SC_FUNC void delete_docstringtable(void);
  12.690 +SC_FUNC stringlist *insert_autolist(char *string);
  12.691 +SC_FUNC char *get_autolist(int index);
  12.692 +SC_FUNC void delete_autolisttable(void);
  12.693 +SC_FUNC stringlist *insert_dbgfile(const char *filename);
  12.694 +SC_FUNC stringlist *insert_dbgline(int linenr);
  12.695 +SC_FUNC stringlist *insert_dbgsymbol(symbol *sym);
  12.696 +SC_FUNC char *get_dbgstring(int index);
  12.697 +SC_FUNC void delete_dbgstringtable(void);
  12.698 +
  12.699 +/* function prototypes in SCMEMFILE.C */
  12.700 +#if !defined tMEMFILE
  12.701 +  typedef unsigned char MEMFILE;
  12.702 +  #define tMEMFILE  1
  12.703 +#endif
  12.704 +MEMFILE *mfcreate(char *filename);
  12.705 +void mfclose(MEMFILE *mf);
  12.706 +int mfdump(MEMFILE *mf);
  12.707 +long mflength(MEMFILE *mf);
  12.708 +long mfseek(MEMFILE *mf,long offset,int whence);
  12.709 +unsigned int mfwrite(MEMFILE *mf,unsigned char *buffer,unsigned int size);
  12.710 +unsigned int mfread(MEMFILE *mf,unsigned char *buffer,unsigned int size);
  12.711 +char *mfgets(MEMFILE *mf,char *string,unsigned int size);
  12.712 +int mfputs(MEMFILE *mf,char *string);
  12.713 +
  12.714 +/* function prototypes in SCI18N.C */
  12.715 +#define MAXCODEPAGE 12
  12.716 +SC_FUNC int cp_path(const char *root,const char *directory);
  12.717 +SC_FUNC int cp_set(const char *name);
  12.718 +SC_FUNC cell cp_translate(const unsigned char *string,const unsigned char **endptr);
  12.719 +SC_FUNC cell get_utf8_char(const unsigned char *string,const unsigned char **endptr);
  12.720 +SC_FUNC int scan_utf8(FILE *fp,const char *filename);
  12.721 +
  12.722 +/* function prototypes in SCSTATE.C */
  12.723 +SC_FUNC constvalue *automaton_add(const char *name);
  12.724 +SC_FUNC constvalue *automaton_find(const char *name);
  12.725 +SC_FUNC constvalue *automaton_findid(int id);
  12.726 +SC_FUNC constvalue *state_add(const char *name,int fsa_id);
  12.727 +SC_FUNC constvalue *state_find(const char *name,int fsa_id);
  12.728 +SC_FUNC constvalue *state_findid(int id);
  12.729 +SC_FUNC void state_buildlist(int **list,int *listsize,int *count,int stateid);
  12.730 +SC_FUNC int state_addlist(int *list,int count,int fsa_id);
  12.731 +SC_FUNC void state_deletetable(void);
  12.732 +SC_FUNC int state_getfsa(int listid);
  12.733 +SC_FUNC int state_count(int listid);
  12.734 +SC_FUNC int state_inlist(int listid,int state);
  12.735 +SC_FUNC int state_listitem(int listid,int index);
  12.736 +SC_FUNC void state_conflict(symbol *root);
  12.737 +SC_FUNC int state_conflict_id(int listid1,int listid2);
  12.738 +
  12.739 +/* external variables (defined in scvars.c) */
  12.740 +#if !defined SC_SKIP_VDECL
  12.741 +SC_VDECL symbol loctab;       /* local symbol table */
  12.742 +SC_VDECL symbol glbtab;       /* global symbol table */
  12.743 +SC_VDECL cell *litq;          /* the literal queue */
  12.744 +SC_VDECL unsigned char pline[]; /* the line read from the input file */
  12.745 +SC_VDECL const unsigned char *lptr;/* points to the current position in "pline" */
  12.746 +SC_VDECL constvalue tagname_tab;/* tagname table */
  12.747 +SC_VDECL constvalue libname_tab;/* library table (#pragma library "..." syntax) */
  12.748 +SC_VDECL constvalue *curlibrary;/* current library */
  12.749 +SC_VDECL int pc_addlibtable;  /* is the library table added to the AMX file? */
  12.750 +SC_VDECL symbol *curfunc;     /* pointer to current function */
  12.751 +SC_VDECL char *inpfname;      /* name of the file currently read from */
  12.752 +SC_VDECL char outfname[];     /* intermediate (assembler) file name */
  12.753 +SC_VDECL char binfname[];     /* binary file name */
  12.754 +SC_VDECL char errfname[];     /* error file name */
  12.755 +SC_VDECL char sc_ctrlchar;    /* the control character (or escape character) */
  12.756 +SC_VDECL char sc_ctrlchar_org;/* the default control character */
  12.757 +SC_VDECL int litidx;          /* index to literal table */
  12.758 +SC_VDECL int litmax;          /* current size of the literal table */
  12.759 +SC_VDECL int stgidx;          /* index to the staging buffer */
  12.760 +SC_VDECL int sc_labnum;       /* number of (internal) labels */
  12.761 +SC_VDECL int staging;         /* true if staging output */
  12.762 +SC_VDECL cell declared;       /* number of local cells declared */
  12.763 +SC_VDECL cell glb_declared;   /* number of global cells declared */
  12.764 +SC_VDECL cell code_idx;       /* number of bytes with generated code */
  12.765 +SC_VDECL int ntv_funcid;      /* incremental number of native function */
  12.766 +SC_VDECL int errnum;          /* number of errors */
  12.767 +SC_VDECL int warnnum;         /* number of warnings */
  12.768 +SC_VDECL int sc_debug;        /* debug/optimization options (bit field) */
  12.769 +SC_VDECL int sc_packstr;      /* strings are packed by default? */
  12.770 +SC_VDECL int sc_asmfile;      /* create .ASM file? */
  12.771 +SC_VDECL int sc_listing;      /* create .LST file? */
  12.772 +SC_VDECL int sc_compress;     /* compress bytecode? */
  12.773 +SC_VDECL int sc_needsemicolon;/* semicolon required to terminate expressions? */
  12.774 +SC_VDECL int sc_dataalign;    /* data alignment value */
  12.775 +SC_VDECL int sc_alignnext;    /* must frame of the next function be aligned? */
  12.776 +SC_VDECL int pc_docexpr;      /* must expression be attached to documentation comment? */
  12.777 +SC_VDECL int curseg;          /* 1 if currently parsing CODE, 2 if parsing DATA */
  12.778 +SC_VDECL cell pc_stksize;     /* stack size */
  12.779 +SC_VDECL cell pc_amxlimit;    /* abstract machine size limit (code + data, or only code) */
  12.780 +SC_VDECL cell pc_amxram;      /* abstract machine data size limit */
  12.781 +SC_VDECL int freading;        /* is there an input file ready for reading? */
  12.782 +SC_VDECL int fline;           /* the line number in the current file */
  12.783 +SC_VDECL short fnumber;       /* number of files in the file table (debugging) */
  12.784 +SC_VDECL short fcurrent;      /* current file being processed (debugging) */
  12.785 +SC_VDECL short sc_intest;     /* true if inside a test */
  12.786 +SC_VDECL int sideeffect;      /* true if an expression causes a side-effect */
  12.787 +SC_VDECL int stmtindent;      /* current indent of the statement */
  12.788 +SC_VDECL int indent_nowarn;   /* skip warning "217 loose indentation" */
  12.789 +SC_VDECL int sc_tabsize;      /* number of spaces that a TAB represents */
  12.790 +SC_VDECL short sc_allowtags;  /* allow/detect tagnames in lex() */
  12.791 +SC_VDECL int sc_status;       /* read/write status */
  12.792 +SC_VDECL int sc_rationaltag;  /* tag for rational numbers */
  12.793 +SC_VDECL int rational_digits; /* number of fractional digits */
  12.794 +SC_VDECL int sc_allowproccall;/* allow/detect tagnames in lex() */
  12.795 +SC_VDECL short sc_is_utf8;    /* is this source file in UTF-8 encoding */
  12.796 +SC_VDECL char *pc_depricate;  /* if non-NULL, mark next declaration as depricated */
  12.797 +SC_VDECL int sc_curstates;    /* ID of the current state list */
  12.798 +SC_VDECL int pc_optimize;     /* (peephole) optimization level */
  12.799 +SC_VDECL int pc_memflags;     /* special flags for the stack/heap usage */
  12.800 +
  12.801 +SC_VDECL constvalue sc_automaton_tab; /* automaton table */
  12.802 +SC_VDECL constvalue sc_state_tab;     /* state table */
  12.803 +
  12.804 +SC_VDECL FILE *inpf;          /* file read from (source or include) */
  12.805 +SC_VDECL FILE *inpf_org;      /* main source file */
  12.806 +SC_VDECL FILE *outf;          /* file written to */
  12.807 +
  12.808 +SC_VDECL jmp_buf errbuf;      /* target of longjmp() on a fatal error */
  12.809 +
  12.810 +#if !defined SC_LIGHT
  12.811 +  SC_VDECL int sc_makereport; /* generate a cross-reference report */
  12.812 +#endif
  12.813 +
  12.814 +#endif /* SC_SKIP_VDECL */
  12.815 +
  12.816 +#endif /* SC_H_INCLUDED */
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/compiler-init/compiler-init/sc1.c	Fri Jul 14 02:02:18 2006 +0000
    13.3 @@ -0,0 +1,5605 @@
    13.4 +/*  Pawn compiler
    13.5 + *
    13.6 + *  Function and variable definition and declaration, statement parser.
    13.7 + *
    13.8 + *  Copyright (c) ITB CompuPhase, 1997-2006
    13.9 + *
   13.10 + *  This software is provided "as-is", without any express or implied warranty.
   13.11 + *  In no event will the authors be held liable for any damages arising from
   13.12 + *  the use of this software.
   13.13 + *
   13.14 + *  Permission is granted to anyone to use this software for any purpose,
   13.15 + *  including commercial applications, and to alter it and redistribute it
   13.16 + *  freely, subject to the following restrictions:
   13.17 + *
   13.18 + *  1.  The origin of this software must not be misrepresented; you must not
   13.19 + *      claim that you wrote the original software. If you use this software in
   13.20 + *      a product, an acknowledgment in the product documentation would be
   13.21 + *      appreciated but is not required.
   13.22 + *  2.  Altered source versions must be plainly marked as such, and must not be
   13.23 + *      misrepresented as being the original software.
   13.24 + *  3.  This notice may not be removed or altered from any source distribution.
   13.25 + *
   13.26 + *  Version: $Id: sc1.c 3591 2006-06-25 14:30:07Z thiadmer $
   13.27 + */
   13.28 +#include <assert.h>
   13.29 +#include <ctype.h>
   13.30 +#include <limits.h>
   13.31 +#include <stdarg.h>
   13.32 +#include <stdio.h>
   13.33 +#include <stdlib.h>
   13.34 +#include <string.h>
   13.35 +
   13.36 +#if defined	__WIN32__ || defined _WIN32 || defined __MSDOS__
   13.37 +  #include <conio.h>
   13.38 +  #include <io.h>
   13.39 +#endif
   13.40 +
   13.41 +#if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
   13.42 +  #include <sclinux.h>
   13.43 +  #include <binreloc.h> /* from BinReloc, see www.autopackage.org */
   13.44 +#endif
   13.45 +
   13.46 +#if defined FORTIFY
   13.47 +  #include <alloc/fortify.h>
   13.48 +#endif
   13.49 +
   13.50 +#if defined __BORLANDC__ || defined __WATCOMC__
   13.51 +  #include <dos.h>
   13.52 +  static unsigned total_drives; /* dummy variable */
   13.53 +  #define dos_setdrive(i)       _dos_setdrive(i,&total_drives)
   13.54 +#elif defined _MSC_VER && defined _WIN32
   13.55 +  #include <direct.h>           /* for _chdrive() */
   13.56 +  #define dos_setdrive(i)       _chdrive(i)
   13.57 +#endif
   13.58 +#if defined __BORLANDC__
   13.59 +  #include <dir.h>              /* for chdir() */
   13.60 +#elif defined __WATCOMC__
   13.61 +  #include <direct.h>           /* for chdir() */
   13.62 +#endif
   13.63 +#if defined __WIN32__ || defined _WIN32 || defined _Windows
   13.64 +  #include <windows.h>
   13.65 +#endif
   13.66 +
   13.67 +#include "lstring.h"
   13.68 +#include "sc.h"
   13.69 +#include "svnrev.h"
   13.70 +#define VERSION_STR "3.2." SVN_REVSTR
   13.71 +#define VERSION_INT 0x0302
   13.72 +
   13.73 +static void resetglobals(void);
   13.74 +static void initglobals(void);
   13.75 +static char *get_extension(char *filename);
   13.76 +static void setopt(int argc,char **argv,char *oname,char *ename,char *pname,
   13.77 +                   char *rname,char *codepage);
   13.78 +static void setconfig(char *root);
   13.79 +static void setcaption(void);
   13.80 +static void about(void);
   13.81 +static void setconstants(void);
   13.82 +static void parse(void);
   13.83 +static void dumplits(void);
   13.84 +static void dumpzero(int count);
   13.85 +static void declfuncvar(int fpublic,int fstatic,int fstock,int fconst);
   13.86 +static void declglb(char *firstname,int firsttag,int fpublic,int fstatic,
   13.87 +                    int stock,int fconst);
   13.88 +static int declloc(int fstatic);
   13.89 +static void decl_const(int table);
   13.90 +static void decl_enum(int table);
   13.91 +static cell needsub(int *tag,constvalue **enumroot);
   13.92 +static void initials(int ident,int tag,cell *size,int dim[],int numdim,
   13.93 +                     constvalue *enumroot);
   13.94 +static cell initarray(int ident,int tag,int dim[],int numdim,int cur,
   13.95 +                      int startlit,int counteddim[],constvalue *lastdim,
   13.96 +                      constvalue *enumroot,int *errorfound);
   13.97 +static cell initvector(int ident,int tag,cell size,int fillzero,
   13.98 +                       constvalue *enumroot,int *errorfound);
   13.99 +static cell init(int ident,int *tag,int *errorfound);
  13.100 +static int getstates(const char *funcname);
  13.101 +static void attachstatelist(symbol *sym, int state_id);
  13.102 +static void funcstub(int fnative);
  13.103 +static int newfunc(char *firstname,int firsttag,int fpublic,int fstatic,int stock);
  13.104 +static int declargs(symbol *sym,int chkshadow);
  13.105 +static void doarg(char *name,int ident,int offset,int tags[],int numtags,
  13.106 +                  int fpublic,int fconst,int chkshadow,arginfo *arg);
  13.107 +static void make_report(symbol *root,FILE *log,char *sourcefile);
  13.108 +static void reduce_referrers(symbol *root);
  13.109 +static long max_stacksize(symbol *root,int *recursion);
  13.110 +static int testsymbols(symbol *root,int level,int testlabs,int testconst);
  13.111 +static void destructsymbols(symbol *root,int level);
  13.112 +static constvalue *find_constval_byval(constvalue *table,cell val);
  13.113 +static void statement(int *lastindent,int allow_decl);
  13.114 +static void compound(int stmt_sameline);
  13.115 +static int doexpr(int comma,int chkeffect,int allowarray,int mark_endexpr,
  13.116 +                  int *tag,symbol **symptr,int chkfuncresult);
  13.117 +static void doassert(void);
  13.118 +static void doexit(void);
  13.119 +static void test(int label,int parens,int invert);
  13.120 +static void doif(void);
  13.121 +static void dowhile(void);
  13.122 +static void dodo(void);
  13.123 +static void dofor(void);
  13.124 +static void doswitch(void);
  13.125 +static void dogoto(void);
  13.126 +static void dolabel(void);
  13.127 +static symbol *fetchlab(char *name);
  13.128 +static void doreturn(void);
  13.129 +static void dobreak(void);
  13.130 +static void docont(void);
  13.131 +static void dosleep(void);
  13.132 +static void dostate(void);
  13.133 +static void addwhile(int *ptr);
  13.134 +static void delwhile(void);
  13.135 +static int *readwhile(void);
  13.136 +
  13.137 +static int norun      = 0;      /* the compiler never ran */
  13.138 +static int lastst     = 0;      /* last executed statement type */
  13.139 +static int nestlevel  = 0;      /* number of active (open) compound statements */
  13.140 +static int rettype    = 0;      /* the type that a "return" expression should have */
  13.141 +static int skipinput  = 0;      /* number of lines to skip from the first input file */
  13.142 +static int optproccall = TRUE;  /* support "procedure call" */
  13.143 +static int verbosity  = 1;      /* verbosity level, 0=quiet, 1=normal, 2=verbose */
  13.144 +static int sc_reparse = 0;      /* needs 3th parse because of changed prototypes? */
  13.145 +static int sc_parsenum = 0;     /* number of the extra parses */
  13.146 +static int wq[wqTABSZ];         /* "while queue", internal stack for nested loops */
  13.147 +static int *wqptr;              /* pointer to next entry */
  13.148 +#if !defined SC_LIGHT
  13.149 +  static char sc_rootpath[_MAX_PATH];
  13.150 +  static char *sc_documentation=NULL;/* main documentation */
  13.151 +#endif
  13.152 +#if defined	__WIN32__ || defined _WIN32 || defined _Windows
  13.153 +  static HWND hwndFinish = 0;
  13.154 +#endif
  13.155 +
  13.156 +/*  "main" of the compiler
  13.157 + */
  13.158 +#if defined __cplusplus
  13.159 +  extern "C"
  13.160 +#endif
  13.161 +int pc_compile(int argc, char *argv[])
  13.162 +{
  13.163 +  int entry,i,jmpcode;
  13.164 +  int retcode;
  13.165 +  char incfname[_MAX_PATH];
  13.166 +  char reportname[_MAX_PATH];
  13.167 +  char codepage[MAXCODEPAGE+1];
  13.168 +  FILE *binf;
  13.169 +  void *inpfmark;
  13.170 +  int lcl_packstr,lcl_needsemicolon,lcl_tabsize;
  13.171 +  #if !defined SC_LIGHT
  13.172 +    int hdrsize=0;
  13.173 +  #endif
  13.174 +  char *ptr;
  13.175 +
  13.176 +  /* set global variables to their initial value */
  13.177 +  binf=NULL;
  13.178 +  initglobals();
  13.179 +  errorset(sRESET,0);
  13.180 +  errorset(sEXPRRELEASE,0);
  13.181 +  lexinit();
  13.182 +
  13.183 +  /* make sure that we clean up on a fatal error; do this before the first
  13.184 +   * call to error(). */
  13.185 +  if ((jmpcode=setjmp(errbuf))!=0)
  13.186 +    goto cleanup;
  13.187 +
  13.188 +  /* allocate memory for fixed tables */
  13.189 +  inpfname=(char*)malloc(_MAX_PATH);
  13.190 +  if (inpfname==NULL)
  13.191 +    error(103);         /* insufficient memory */
  13.192 +  litq=(cell*)malloc(litmax*sizeof(cell));
  13.193 +  if (litq==NULL)
  13.194 +    error(103);         /* insufficient memory */
  13.195 +  if (!phopt_init())
  13.196 +    error(103);         /* insufficient memory */
  13.197 +
  13.198 +  setopt(argc,argv,outfname,errfname,incfname,reportname,codepage);
  13.199 +  strcpy(binfname,outfname);
  13.200 +  ptr=get_extension(binfname);
  13.201 +  if (ptr!=NULL && stricmp(ptr,".asm")==0)
  13.202 +    set_extension(binfname,".smx",TRUE);
  13.203 +  else
  13.204 +    set_extension(binfname,".smx",FALSE);
  13.205 +  /* set output names that depend on the input name */
  13.206 +  if (sc_listing)
  13.207 +    set_extension(outfname,".lst",TRUE);
  13.208 +  else
  13.209 +    set_extension(outfname,".asm",TRUE);
  13.210 +  if (strlen(errfname)!=0)
  13.211 +    remove(errfname);   /* delete file on startup */
  13.212 +  else if (verbosity>0)
  13.213 +    setcaption();
  13.214 +  setconfig(argv[0]);   /* the path to the include and codepage files */
  13.215 +  sc_ctrlchar_org=sc_ctrlchar;
  13.216 +  lcl_packstr=sc_packstr;
  13.217 +  lcl_needsemicolon=sc_needsemicolon;
  13.218 +  lcl_tabsize=sc_tabsize;
  13.219 +  #if !defined NO_CODEPAGE
  13.220 +    if (!cp_set(codepage))      /* set codepage */
  13.221 +      error(108);               /* codepage mapping file not found */
  13.222 +  #endif
  13.223 +  /* optionally create a temporary input file that is a collection of all
  13.224 +   * input files
  13.225 +   */
  13.226 +  assert(get_sourcefile(0)!=NULL);  /* there must be at least one source file */
  13.227 +  if (get_sourcefile(1)!=NULL) {
  13.228 +    /* there are at least two or more source files */
  13.229 +    char *tname,*sname;
  13.230 +    FILE *ftmp,*fsrc;
  13.231 +    int fidx;
  13.232 +    #if defined	__WIN32__ || defined _WIN32
  13.233 +      tname=_tempnam(NULL,"pawn");
  13.234 +    #elif defined __MSDOS__ || defined _Windows
  13.235 +      tname=tempnam(NULL,"pawn");
  13.236 +    #elif defined(MACOS) && !defined(__MACH__)
  13.237 +      /* tempnam is not supported for the Macintosh CFM build. */
  13.238 +      error(104,get_sourcefile(1));
  13.239 +      tname=NULL;
  13.240 +      sname=NULL;
  13.241 +    #else
  13.242 +      tname=tempnam(NULL,"pawn");
  13.243 +    #endif
  13.244 +    ftmp=(FILE*)pc_createsrc(tname);
  13.245 +    for (fidx=0; (sname=get_sourcefile(fidx))!=NULL; fidx++) {
  13.246 +      unsigned char tstring[128];
  13.247 +      fsrc=(FILE*)pc_opensrc(sname);
  13.248 +      if (fsrc==NULL) {
  13.249 +        strcpy(inpfname,sname); /* avoid invalid filename */
  13.250 +        error(100,sname);
  13.251 +      } /* if */
  13.252 +      pc_writesrc(ftmp,(unsigned char*)"#file ");
  13.253 +      pc_writesrc(ftmp,(unsigned char*)sname);
  13.254 +      pc_writesrc(ftmp,(unsigned char*)"\n");
  13.255 +      while (!pc_eofsrc(fsrc)) {
  13.256 +        pc_readsrc(fsrc,tstring,sizeof tstring);
  13.257 +        pc_writesrc(ftmp,tstring);
  13.258 +      } /* while */
  13.259 +      pc_closesrc(fsrc);
  13.260 +    } /* for */
  13.261 +    pc_closesrc(ftmp);
  13.262 +    strcpy(inpfname,tname);
  13.263 +    free(tname);
  13.264 +  } else {
  13.265 +    strcpy(inpfname,get_sourcefile(0));
  13.266 +  } /* if */
  13.267 +  inpf_org=(FILE*)pc_opensrc(inpfname);
  13.268 +  if (inpf_org==NULL)
  13.269 +    error(100,inpfname);
  13.270 +  freading=TRUE;
  13.271 +  outf=(FILE*)pc_openasm(outfname); /* first write to assembler file (may be temporary) */
  13.272 +  if (outf==NULL)
  13.273 +    error(101,outfname);
  13.274 +  /* immediately open the binary file, for other programs to check */
  13.275 +  if (sc_asmfile || sc_listing) {
  13.276 +    binf=NULL;
  13.277 +  } else {
  13.278 +    binf=(FILE*)pc_openbin(binfname);
  13.279 +    if (binf==NULL)
  13.280 +      error(101,binfname);
  13.281 +  } /* if */
  13.282 +  setconstants();               /* set predefined constants and tagnames */
  13.283 +  for (i=0; i<skipinput; i++)   /* skip lines in the input file */
  13.284 +    if (pc_readsrc(inpf_org,pline,sLINEMAX)!=NULL)
  13.285 +      fline++;                  /* keep line number up to date */
  13.286 +  skipinput=fline;
  13.287 +  sc_status=statFIRST;
  13.288 +  /* write starting options (from the command line or the configuration file) */
  13.289 +  if (sc_listing) {
  13.290 +    char string[150];
  13.291 +    sprintf(string,"#pragma ctrlchar 0x%02x\n"
  13.292 +                   "#pragma pack %s\n"
  13.293 +                   "#pragma semicolon %s\n"
  13.294 +                   "#pragma tabsize %d\n",
  13.295 +            sc_ctrlchar,
  13.296 +            sc_packstr ? "true" : "false",
  13.297 +            sc_needsemicolon ? "true" : "false",
  13.298 +            sc_tabsize);
  13.299 +    pc_writeasm(outf,string);
  13.300 +    setfiledirect(inpfname);
  13.301 +  } /* if */
  13.302 +  /* do the first pass through the file (or possibly two or more "first passes") */
  13.303 +  sc_parsenum=0;
  13.304 +  inpfmark=pc_getpossrc(inpf_org);
  13.305 +  do {
  13.306 +    /* reset "defined" flag of all functions and global variables */
  13.307 +    reduce_referrers(&glbtab);
  13.308 +    delete_symbols(&glbtab,0,TRUE,FALSE);
  13.309 +    #if !defined NO_DEFINE
  13.310 +      delete_substtable();
  13.311 +    #endif
  13.312 +    resetglobals();
  13.313 +    sc_ctrlchar=sc_ctrlchar_org;
  13.314 +    sc_packstr=lcl_packstr;
  13.315 +    sc_needsemicolon=lcl_needsemicolon;
  13.316 +    sc_tabsize=lcl_tabsize;
  13.317 +    errorset(sRESET,0);
  13.318 +    /* reset the source file */
  13.319 +    inpf=inpf_org;
  13.320 +    freading=TRUE;
  13.321 +    pc_resetsrc(inpf,inpfmark); /* reset file position */
  13.322 +    fline=skipinput;            /* reset line number */
  13.323 +    sc_reparse=FALSE;           /* assume no extra passes */
  13.324 +    sc_status=statFIRST;        /* resetglobals() resets it to IDLE */
  13.325 +
  13.326 +    if (strlen(incfname)>0) {
  13.327 +      if (strcmp(incfname,sDEF_PREFIX)==0) {
  13.328 +        plungefile(incfname,FALSE,TRUE);    /* parse "default.inc" */
  13.329 +      } else {
  13.330 +        if (!plungequalifiedfile(incfname)) /* parse "prefix" include file */
  13.331 +          error(100,incfname);          /* cannot read from ... (fatal error) */
  13.332 +      } /* if */
  13.333 +    } /* if */
  13.334 +    preprocess();                       /* fetch first line */
  13.335 +    parse();                            /* process all input */
  13.336 +    sc_parsenum++;
  13.337 +  } while (sc_reparse);
  13.338 +
  13.339 +  /* second (or third) pass */
  13.340 +  sc_status=statWRITE;                  /* set, to enable warnings */
  13.341 +  state_conflict(&glbtab);
  13.342 +
  13.343 +  /* write a report, if requested */
  13.344 +  #if !defined SC_LIGHT
  13.345 +    if (sc_makereport) {
  13.346 +      FILE *frep=stdout;
  13.347 +      if (strlen(reportname)>0)
  13.348 +        frep=fopen(reportname,"wb");    /* avoid translation of \n to \r\n in DOS/Windows */
  13.349 +      if (frep!=NULL) {
  13.350 +        make_report(&glbtab,frep,get_sourcefile(0));
  13.351 +        if (strlen(reportname)>0)
  13.352 +          fclose(frep);
  13.353 +      } /* if */
  13.354 +      if (sc_documentation!=NULL) {
  13.355 +        free(sc_documentation);
  13.356 +        sc_documentation=NULL;
  13.357 +      } /* if */
  13.358 +    } /* if */
  13.359 +  #endif
  13.360 +  if (sc_listing)
  13.361 +    goto cleanup;
  13.362 +
  13.363 +  /* ??? for re-parsing the listing file instead of the original source
  13.364 +   * file (and doing preprocessing twice):
  13.365 +   * - close input file, close listing file
  13.366 +   * - re-open listing file for reading (inpf)
  13.367 +   * - open assembler file (outf)
  13.368 +   */
  13.369 +
  13.370 +  /* reset "defined" flag of all functions and global variables */
  13.371 +  reduce_referrers(&glbtab);
  13.372 +  delete_symbols(&glbtab,0,TRUE,FALSE);
  13.373 +  #if !defined NO_DEFINE
  13.374 +    delete_substtable();
  13.375 +  #endif
  13.376 +  resetglobals();
  13.377 +  sc_ctrlchar=sc_ctrlchar_org;
  13.378 +  sc_packstr=lcl_packstr;
  13.379 +  sc_needsemicolon=lcl_needsemicolon;
  13.380 +  sc_tabsize=lcl_tabsize;
  13.381 +  errorset(sRESET,0);
  13.382 +  /* reset the source file */
  13.383 +  inpf=inpf_org;
  13.384 +  freading=TRUE;
  13.385 +  pc_resetsrc(inpf,inpfmark);   /* reset file position */
  13.386 +  fline=skipinput;              /* reset line number */
  13.387 +  lexinit();                    /* clear internal flags of lex() */
  13.388 +  sc_status=statWRITE;          /* allow to write --this variable was reset by resetglobals() */
  13.389 +  writeleader(&glbtab);
  13.390 +  insert_dbgfile(inpfname);
  13.391 +  if (strlen(incfname)>0) {
  13.392 +    if (strcmp(incfname,sDEF_PREFIX)==0)
  13.393 +      plungefile(incfname,FALSE,TRUE);  /* parse "default.inc" (again) */
  13.394 +    else
  13.395 +      plungequalifiedfile(incfname);    /* parse implicit include file (again) */
  13.396 +  } /* if */
  13.397 +  preprocess();                         /* fetch first line */
  13.398 +  parse();                              /* process all input */
  13.399 +  /* inpf is already closed when readline() attempts to pop of a file */
  13.400 +  writetrailer();                       /* write remaining stuff */
  13.401 +
  13.402 +  entry=testsymbols(&glbtab,0,TRUE,FALSE);  /* test for unused or undefined
  13.403 +                                             * functions and variables */
  13.404 +  if (!entry)
  13.405 +    error(13);                  /* no entry point (no public functions) */
  13.406 +
  13.407 +cleanup:
  13.408 +  if (inpf!=NULL)               /* main source file is not closed, do it now */
  13.409 +    pc_closesrc(inpf);
  13.410 +  /* write the binary file (the file is already open) */
  13.411 +  if (!(sc_asmfile || sc_listing) && errnum==0 && jmpcode==0) {
  13.412 +    assert(binf!=NULL);
  13.413 +    pc_resetasm(outf);          /* flush and loop back, for reading */
  13.414 +    #if !defined SC_LIGHT
  13.415 +      hdrsize=
  13.416 +    #endif
  13.417 +    assemble(binf,outf);        /* assembler file is now input */
  13.418 +  } /* if */
  13.419 +  if (outf!=NULL) {
  13.420 +    pc_closeasm(outf,!(sc_asmfile || sc_listing));
  13.421 +    outf=NULL;
  13.422 +  } /* if */
  13.423 +  if (binf!=NULL) {
  13.424 +    pc_closebin(binf,errnum!=0);
  13.425 +    binf=NULL;
  13.426 +  } /* if */
  13.427 +
  13.428 +  #if !defined SC_LIGHT
  13.429 +    if (errnum==0 && strlen(errfname)==0) {
  13.430 +      int recursion;
  13.431 +      long stacksize=max_stacksize(&glbtab,&recursion);
  13.432 +      int flag_exceed=0;
  13.433 +      if (pc_amxlimit>0) {
  13.434 +        long totalsize=hdrsize+code_idx;
  13.435 +        if (pc_amxram==0)
  13.436 +          totalsize+=(glb_declared+pc_stksize)*sizeof(cell);
  13.437 +        if (totalsize>=pc_amxlimit)
  13.438 +          flag_exceed=1;
  13.439 +      } /* if */
  13.440 +      if (pc_amxram>0 && (glb_declared+pc_stksize)*sizeof(cell)>=(unsigned long)pc_amxram)
  13.441 +        flag_exceed=1;
  13.442 +      if (!norun && (sc_debug & sSYMBOLIC)!=0 || verbosity>=2 || stacksize+32>=(long)pc_stksize || flag_exceed) {
  13.443 +        pc_printf("Header size:       %8ld bytes\n", (long)hdrsize);
  13.444 +        pc_printf("Code size:         %8ld bytes\n", (long)code_idx);
  13.445 +        pc_printf("Data size:         %8ld bytes\n", (long)glb_declared*sizeof(cell));
  13.446 +        pc_printf("Stack/heap size:   %8ld bytes; ", (long)pc_stksize*sizeof(cell));
  13.447 +        pc_printf("estimated max. usage");
  13.448 +        if (recursion)
  13.449 +          pc_printf(" is unknown, due to recursion\n");
  13.450 +        else if ((pc_memflags & suSLEEP_INSTR)!=0)
  13.451 +          pc_printf(" is unknown, due to the \"sleep\" instruction\n");
  13.452 +        else
  13.453 +          pc_printf("=%ld cells (%ld bytes)\n",stacksize,stacksize*sizeof(cell));
  13.454 +        pc_printf("Total requirements:%8ld bytes\n", (long)hdrsize+(long)code_idx+(long)glb_declared*sizeof(cell)+(long)pc_stksize*sizeof(cell));
  13.455 +      } /* if */
  13.456 +      if (flag_exceed)
  13.457 +        error(106,pc_amxlimit+pc_amxram); /* this causes a jump back to label "cleanup" */
  13.458 +    } /* if */
  13.459 +  #endif
  13.460 +
  13.461 +  if (inpfname!=NULL) {
  13.462 +    if (get_sourcefile(1)!=NULL)
  13.463 +      remove(inpfname);         /* the "input file" was in fact a temporary file */
  13.464 +    free(inpfname);
  13.465 +  } /* if */
  13.466 +  if (litq!=NULL)
  13.467 +    free(litq);
  13.468 +  phopt_cleanup();
  13.469 +  stgbuffer_cleanup();
  13.470 +  clearstk();
  13.471 +  assert(jmpcode!=0 || loctab.next==NULL);/* on normal flow, local symbols
  13.472 +                                           * should already have been deleted */
  13.473 +  delete_symbols(&loctab,0,TRUE,TRUE);    /* delete local variables if not yet
  13.474 +                                           * done (i.e. on a fatal error) */
  13.475 +  delete_symbols(&glbtab,0,TRUE,TRUE);
  13.476 +  delete_consttable(&tagname_tab);
  13.477 +  delete_consttable(&libname_tab);
  13.478 +  delete_consttable(&sc_automaton_tab);
  13.479 +  delete_consttable(&sc_state_tab);
  13.480 +  state_deletetable();
  13.481 +  delete_aliastable();
  13.482 +  delete_pathtable();
  13.483 +  delete_sourcefiletable();
  13.484 +  delete_dbgstringtable();
  13.485 +  #if !defined NO_DEFINE
  13.486 +    delete_substtable();
  13.487 +  #endif
  13.488 +  #if !defined SC_LIGHT
  13.489 +    delete_docstringtable();
  13.490 +    if (sc_documentation!=NULL)
  13.491 +      free(sc_documentation);
  13.492 +  #endif
  13.493 +  delete_autolisttable();
  13.494 +  if (errnum!=0) {
  13.495 +    if (strlen(errfname)==0)
  13.496 +      pc_printf("\n%d Error%s.\n",errnum,(errnum>1) ? "s" : "");
  13.497 +    retcode=1;
  13.498 +  } else if (warnnum!=0){
  13.499 +    if (strlen(errfname)==0)
  13.500 +      pc_printf("\n%d Warning%s.\n",warnnum,(warnnum>1) ? "s" : "");
  13.501 +    retcode=0;          /* use "0", so that MAKE and similar tools continue */
  13.502 +  } else {
  13.503 +    retcode=jmpcode;
  13.504 +    if (retcode==0 && verbosity>=2)
  13.505 +      pc_printf("\nDone.\n");
  13.506 +  } /* if */
  13.507 +  #if defined	__WIN32__ || defined _WIN32 || defined _Windows
  13.508 +    if (IsWindow(hwndFinish))
  13.509 +      PostMessageA(hwndFinish,RegisterWindowMessageA("PawnNotify"),retcode,0L);
  13.510 +  #endif
  13.511 +  #if defined FORTIFY
  13.512 +    Fortify_ListAllMemory();
  13.513 +  #endif
  13.514 +  return retcode;
  13.515 +}
  13.516 +
  13.517 +#if defined __cplusplus
  13.518 +  extern "C"
  13.519 +#endif
  13.520 +int pc_addconstant(char *name,cell value,int tag)
  13.521 +{
  13.522 +  errorset(sFORCESET,0);        /* make sure error engine is silenced */
  13.523 +  sc_status=statIDLE;
  13.524 +  add_constant(name,value,sGLOBAL,tag);
  13.525 +  return 1;
  13.526 +}
  13.527 +
  13.528 +#if defined __cplusplus
  13.529 +  extern "C"
  13.530 +#endif
  13.531 +int pc_addtag(char *name)
  13.532 +{
  13.533 +  cell val;
  13.534 +  constvalue *ptr;
  13.535 +  int last,tag;
  13.536 +
  13.537 +  if (name==NULL) {
  13.538 +    /* no tagname was given, check for one */
  13.539 +    if (lex(&val,&name)!=tLABEL) {
  13.540 +      lexpush();
  13.541 +      return 0;         /* untagged */
  13.542 +    } /* if */
  13.543 +  } /* if */
  13.544 +
  13.545 +  assert(strchr(name,':')==NULL); /* colon should already have been stripped */
  13.546 +  last=0;
  13.547 +  ptr=tagname_tab.next;
  13.548 +  while (ptr!=NULL) {
  13.549 +    tag=(int)(ptr->value & TAGMASK);
  13.550 +    if (strcmp(name,ptr->name)==0)
  13.551 +      return tag;       /* tagname is known, return its sequence number */
  13.552 +    tag &= (int)~FIXEDTAG;
  13.553 +    if (tag>last)
  13.554 +      last=tag;
  13.555 +    ptr=ptr->next;
  13.556 +  } /* while */
  13.557 +
  13.558 +  /* tagname currently unknown, add it */
  13.559 +  tag=last+1;           /* guaranteed not to exist already */
  13.560 +  if (isupper(*name))
  13.561 +    tag |= (int)FIXEDTAG;
  13.562 +  append_constval(&tagname_tab,name,(cell)tag,0);
  13.563 +  return tag;
  13.564 +}
  13.565 +
  13.566 +static void resetglobals(void)
  13.567 +{
  13.568 +  /* reset the subset of global variables that is modified by the first pass */
  13.569 +  curfunc=NULL;         /* pointer to current function */
  13.570 +  lastst=0;             /* last executed statement type */
  13.571 +  nestlevel=0;          /* number of active (open) compound statements */
  13.572 +  rettype=0;            /* the type that a "return" expression should have */
  13.573 +  litidx=0;             /* index to literal table */
  13.574 +  stgidx=0;             /* index to the staging buffer */
  13.575 +  sc_labnum=0;          /* top value of (internal) labels */
  13.576 +  staging=0;            /* true if staging output */
  13.577 +  declared=0;           /* number of local cells declared */
  13.578 +  glb_declared=0;       /* number of global cells declared */
  13.579 +  code_idx=0;           /* number of bytes with generated code */
  13.580 +  ntv_funcid=0;         /* incremental number of native function */
  13.581 +  curseg=0;             /* 1 if currently parsing CODE, 2 if parsing DATA */
  13.582 +  freading=FALSE;       /* no input file ready yet */
  13.583 +  fline=0;              /* the line number in the current file */
  13.584 +  fnumber=0;            /* the file number in the file table (debugging) */
  13.585 +  fcurrent=0;           /* current file being processed (debugging) */
  13.586 +  sc_intest=FALSE;      /* true if inside a test */
  13.587 +  sideeffect=0;         /* true if an expression causes a side-effect */
  13.588 +  stmtindent=0;         /* current indent of the statement */
  13.589 +  indent_nowarn=FALSE;  /* do not skip warning "217 loose indentation" */
  13.590 +  sc_allowtags=TRUE;    /* allow/detect tagnames */
  13.591 +  sc_status=statIDLE;
  13.592 +  sc_allowproccall=FALSE;
  13.593 +  pc_addlibtable=TRUE;  /* by default, add a "library table" to the output file */
  13.594 +  sc_alignnext=FALSE;
  13.595 +  pc_docexpr=FALSE;
  13.596 +  pc_depricate=NULL;
  13.597 +  sc_curstates=0;
  13.598 +  pc_memflags=0;
  13.599 +}
  13.600 +
  13.601 +static void initglobals(void)
  13.602 +{
  13.603 +  resetglobals();
  13.604 +
  13.605 +  sc_asmfile=FALSE;     /* do not create .ASM file */
  13.606 +  sc_listing=FALSE;     /* do not create .LST file */
  13.607 +  skipinput=0;          /* number of lines to skip from the first input file */
  13.608 +  sc_ctrlchar=CTRL_CHAR;/* the escape character */
  13.609 +  litmax=sDEF_LITMAX;   /* current size of the literal table */
  13.610 +  errnum=0;             /* number of errors */
  13.611 +  warnnum=0;            /* number of warnings */
  13.612 +  optproccall=FALSE;    /* sourcemod: do not support "procedure call" */
  13.613 +  verbosity=1;          /* verbosity level, no copyright banner */
  13.614 +  sc_debug=sSYMBOLIC;   /* sourcemod: full debug stuff */
  13.615 +  pc_optimize=sOPTIMIZE_DEFAULT;  /* sourcemod: full optimization */
  13.616 +  sc_packstr=FALSE;     /* strings are unpacked by default */
  13.617 +  #if AMX_COMPACTMARGIN > 2
  13.618 +    sc_compress=TRUE;   /* compress output bytecodes */
  13.619 +  #else
  13.620 +    sc_compress=FALSE;
  13.621 +  #endif
  13.622 +  sc_needsemicolon=FALSE;/* semicolon required to terminate expressions? */
  13.623 +  sc_dataalign=sizeof(cell);
  13.624 +  pc_stksize=sDEF_AMXSTACK;/* default stack size */
  13.625 +  pc_amxlimit=0;        /* no limit on size of the abstract machine */
  13.626 +  pc_amxram=0;          /* no limit on data size of the abstract machine */
  13.627 +  sc_tabsize=8;         /* assume a TAB is 8 spaces */
  13.628 +  sc_rationaltag=0;     /* assume no support for rational numbers */
  13.629 +  rational_digits=0;    /* number of fractional digits */
  13.630 +
  13.631 +  outfname[0]='\0';     /* output file name */
  13.632 +  errfname[0]='\0';     /* error file name */
  13.633 +  inpf=NULL;            /* file read from */
  13.634 +  inpfname=NULL;        /* pointer to name of the file currently read from */
  13.635 +  outf=NULL;            /* file written to */
  13.636 +  litq=NULL;            /* the literal queue */
  13.637 +  glbtab.next=NULL;     /* clear global variables/constants table */
  13.638 +  loctab.next=NULL;     /*   "   local      "    /    "       "   */
  13.639 +  tagname_tab.next=NULL;/* tagname table */
  13.640 +  libname_tab.next=NULL;/* library table (#pragma library "..." syntax) */
  13.641 +
  13.642 +  pline[0]='\0';        /* the line read from the input file */
  13.643 +  lptr=NULL;            /* points to the current position in "pline" */
  13.644 +  curlibrary=NULL;      /* current library */
  13.645 +  inpf_org=NULL;        /* main source file */
  13.646 +
  13.647 +  wqptr=wq;             /* initialize while queue pointer */
  13.648 +
  13.649 +#if !defined SC_LIGHT
  13.650 +  sc_documentation=NULL;
  13.651 +  sc_makereport=FALSE;  /* do not generate a cross-reference report */
  13.652 +#endif
  13.653 +}
  13.654 +
  13.655 +static char *get_extension(char *filename)
  13.656 +{
  13.657 +  char *ptr;
  13.658 +
  13.659 +  assert(filename!=NULL);
  13.660 +  ptr=strrchr(filename,'.');
  13.661 +  if (ptr!=NULL) {
  13.662 +    /* ignore extension on a directory or at the start of the filename */
  13.663 +    if (strchr(ptr,DIRSEP_CHAR)!=NULL || ptr==filename || *(ptr-1)==DIRSEP_CHAR)
  13.664 +      ptr=NULL;
  13.665 +  } /* if */
  13.666 +  return ptr;
  13.667 +}
  13.668 +
  13.669 +/* set_extension
  13.670 + * Set the default extension, or force an extension. To erase the
  13.671 + * extension of a filename, set "extension" to an empty string.
  13.672 + */
  13.673 +SC_FUNC void set_extension(char *filename,char *extension,int force)
  13.674 +{
  13.675 +  char *ptr;
  13.676 +
  13.677 +  assert(extension!=NULL && (*extension=='\0' || *extension=='.'));
  13.678 +  assert(filename!=NULL);
  13.679 +  ptr=get_extension(filename);
  13.680 +  if (force && ptr!=NULL)
  13.681 +    *ptr='\0';          /* set zero terminator at the position of the period */
  13.682 +  if (force || ptr==NULL)
  13.683 +    strcat(filename,extension);
  13.684 +}
  13.685 +
  13.686 +static const char *option_value(const char *optptr)
  13.687 +{
  13.688 +  return (*(optptr+1)=='=' || *(optptr+1)==':') ? optptr+2 : optptr+1;
  13.689 +}
  13.690 +
  13.691 +static int toggle_option(const char *optptr, int option)
  13.692 +{
  13.693 +  switch (*option_value(optptr)) {
  13.694 +  case '\0':
  13.695 +    option=!option;
  13.696 +    break;
  13.697 +  case '-':
  13.698 +    option=FALSE;
  13.699 +    break;
  13.700 +  case '+':
  13.701 +    option=TRUE;
  13.702 +    break;
  13.703 +  default:
  13.704 +    about();
  13.705 +  } /* switch */
  13.706 +  return option;
  13.707 +}
  13.708 +
  13.709 +/* Parsing command line options is indirectly recursive: parseoptions()
  13.710 + * calls parserespf() to handle options in a a response file and
  13.711 + * parserespf() calls parseoptions() at its turn after having created
  13.712 + * an "option list" from the contents of the file.
  13.713 + */
  13.714 +static void parserespf(char *filename,char *oname,char *ename,char *pname,
  13.715 +                       char *rname, char *codepage);
  13.716 +
  13.717 +static void parseoptions(int argc,char **argv,char *oname,char *ename,char *pname,
  13.718 +                         char *rname, char *codepage)
  13.719 +{
  13.720 +  char str[_MAX_PATH],*name;
  13.721 +  const char *ptr;
  13.722 +  int arg,i,isoption;
  13.723 +
  13.724 +  for (arg=1; arg<argc; arg++) {
  13.725 +    #if DIRSEP_CHAR=='/'
  13.726 +      isoption= argv[arg][0]=='-';
  13.727 +    #else
  13.728 +      isoption= argv[arg][0]=='/' || argv[arg][0]=='-';
  13.729 +    #endif
  13.730 +    if (isoption) {
  13.731 +      ptr=&argv[arg][1];
  13.732 +      switch (*ptr) {
  13.733 +      case 'A':
  13.734 +        i=atoi(option_value(ptr));
  13.735 +        if ((i % sizeof(cell))==0)
  13.736 +          sc_dataalign=i;
  13.737 +        else
  13.738 +          about();
  13.739 +        break;
  13.740 +      case 'a':
  13.741 +        if (*(ptr+1)!='\0')
  13.742 +          about();
  13.743 +        sc_asmfile=TRUE;        /* skip last pass of making binary file */
  13.744 +        if (verbosity>1)
  13.745 +          verbosity=1;
  13.746 +        break;
  13.747 +      case 'C':
  13.748 +        #if AMX_COMPACTMARGIN > 2
  13.749 +          sc_compress=toggle_option(ptr,sc_compress);
  13.750 +        #else
  13.751 +          about();
  13.752 +        #endif
  13.753 +        break;
  13.754 +      case 'c':
  13.755 +        strlcpy(codepage,option_value(ptr),MAXCODEPAGE);  /* set name of codepage */
  13.756 +        break;
  13.757 +#if defined dos_setdrive
  13.758 +      case 'D':                 /* set active directory */
  13.759 +        ptr=option_value(ptr);
  13.760 +        if (ptr[1]==':')
  13.761 +          dos_setdrive(toupper(*ptr)-'A'+1);    /* set active drive */
  13.762 +        chdir(ptr);
  13.763 +        break;
  13.764 +#endif
  13.765 +#if 0 /* not allowed to change for SourceMod */
  13.766 +      case 'd':
  13.767 +        switch (*option_value(ptr)) {
  13.768 +        case '0':
  13.769 +          sc_debug=0;
  13.770 +          break;
  13.771 +        case '1':
  13.772 +          sc_debug=sCHKBOUNDS;  /* assertions and bounds checking */
  13.773 +          break;
  13.774 +        case '2':
  13.775 +          sc_debug=sCHKBOUNDS | sSYMBOLIC;  /* also symbolic info */
  13.776 +          break;
  13.777 +        case '3':
  13.778 +          sc_debug=sCHKBOUNDS | sSYMBOLIC;
  13.779 +          pc_optimize=sOPTIMIZE_NONE;
  13.780 +          /* also avoid peephole optimization */
  13.781 +          break;
  13.782 +        default:
  13.783 +          about();
  13.784 +        } /* switch */
  13.785 +        break;
  13.786 +#endif
  13.787 +      case 'e':
  13.788 +        strlcpy(ename,option_value(ptr),_MAX_PATH); /* set name of error file */
  13.789 +        break;
  13.790 +#if defined	__WIN32__ || defined _WIN32 || defined _Windows
  13.791 +      case 'H':
  13.792 +        hwndFinish=(HWND)atoi(option_value(ptr));
  13.793 +        if (!IsWindow(hwndFinish))
  13.794 +          hwndFinish=(HWND)0;
  13.795 +        break;
  13.796 +#endif
  13.797 +      case 'i':
  13.798 +        strlcpy(str,option_value(ptr),sizeof str);  /* set name of include directory */
  13.799 +        i=strlen(str);
  13.800 +        if (i>0) {
  13.801 +          if (str[i-1]!=DIRSEP_CHAR) {
  13.802 +            str[i]=DIRSEP_CHAR;
  13.803 +            str[i+1]='\0';
  13.804 +          } /* if */
  13.805 +          insert_path(str);
  13.806 +        } /* if */
  13.807 +        break;
  13.808 +      case 'l':
  13.809 +        if (*(ptr+1)!='\0')
  13.810 +          about();
  13.811 +        sc_listing=TRUE;        /* skip second pass & code generation */
  13.812 +        break;
  13.813 +      case 'o':
  13.814 +        strlcpy(oname,option_value(ptr),_MAX_PATH); /* set name of (binary) output file */
  13.815 +        break;
  13.816 +      case 'O':
  13.817 +        pc_optimize=*option_value(ptr) - '0';
  13.818 +        if (pc_optimize<sOPTIMIZE_NONE || pc_optimize>=sOPTIMIZE_NUMBER || pc_optimize==sOPTIMIZE_NOMACRO)
  13.819 +          about();
  13.820 +        break;
  13.821 +      case 'p':
  13.822 +        strlcpy(pname,option_value(ptr),_MAX_PATH); /* set name of implicit include file */
  13.823 +        break;
  13.824 +#if !defined SC_LIGHT
  13.825 +      case 'r':
  13.826 +        strlcpy(rname,option_value(ptr),_MAX_PATH); /* set name of report file */
  13.827 +        sc_makereport=TRUE;
  13.828 +        if (strlen(rname)>0) {
  13.829 +          set_extension(rname,".xml",FALSE);
  13.830 +        } else if ((name=get_sourcefile(0))!=NULL) {
  13.831 +          assert(strlen(rname)==0);
  13.832 +          assert(strlen(name)<_MAX_PATH);
  13.833 +          if ((ptr=strrchr(name,DIRSEP_CHAR))!=NULL)
  13.834 +            ptr++;          /* strip path */
  13.835 +          else
  13.836 +            ptr=name;
  13.837 +          assert(strlen(ptr)<_MAX_PATH);
  13.838 +          strcpy(rname,ptr);
  13.839 +          set_extension(rname,".xml",TRUE);
  13.840 +        } /* if */
  13.841 +        break;
  13.842 +#endif
  13.843 +      case 'S':
  13.844 +        i=atoi(option_value(ptr));
  13.845 +        if (i>32)
  13.846 +          pc_stksize=(cell)i;   /* stack size has minimum size */
  13.847 +        else
  13.848 +          about();
  13.849 +        break;
  13.850 +      case 's':
  13.851 +        skipinput=atoi(option_value(ptr));
  13.852 +        break;
  13.853 +      case 't':
  13.854 +        sc_tabsize=atoi(option_value(ptr));
  13.855 +        break;
  13.856 +      case 'v':
  13.857 +        verbosity= isdigit(*option_value(ptr)) ? atoi(option_value(ptr)) : 2;
  13.858 +        if (sc_asmfile && verbosity>1)
  13.859 +          verbosity=1;
  13.860 +        break;
  13.861 +      case 'w':
  13.862 +        i=(int)strtol(option_value(ptr),(char **)&ptr,10);
  13.863 +        if (*ptr=='-')
  13.864 +          pc_enablewarning(i,0);
  13.865 +        else if (*ptr=='+')
  13.866 +          pc_enablewarning(i,1);
  13.867 +        else if (*ptr=='\0')
  13.868 +          pc_enablewarning(i,2);
  13.869 +        break;
  13.870 +      case 'X':
  13.871 +        if (*(ptr+1)=='D') {
  13.872 +          i=atoi(option_value(ptr+1));
  13.873 +          if (i>64)
  13.874 +            pc_amxram=(cell)i;  /* abstract machine data/stack has minimum size */
  13.875 +          else
  13.876 +            about();
  13.877 +        } else {
  13.878 +          i=atoi(option_value(ptr));
  13.879 +          if (i>64)
  13.880 +            pc_amxlimit=(cell)i;/* abstract machine has minimum size */
  13.881 +          else
  13.882 +            about();
  13.883 +        } /* if */
  13.884 +        break;
  13.885 +      case '\\':                /* use \ instead for escape characters */
  13.886 +        sc_ctrlchar='\\';
  13.887 +        break;
  13.888 +      case '^':                 /* use ^ instead for escape characters */
  13.889 +        sc_ctrlchar='^';
  13.890 +        break;
  13.891 +      case ';':
  13.892 +        sc_needsemicolon=toggle_option(ptr,sc_needsemicolon);
  13.893 +        break;
  13.894 +#if 0 /* not allowed to change in SourceMod */
  13.895 +      case '(':
  13.896 +        optproccall=!toggle_option(ptr,!optproccall);
  13.897 +        break;
  13.898 +#endif
  13.899 +      default:                  /* wrong option */
  13.900 +        about();
  13.901 +      } /* switch */
  13.902 +    } else if (argv[arg][0]=='@') {
  13.903 +      #if !defined SC_LIGHT
  13.904 +        parserespf(&argv[arg][1],oname,ename,pname,rname,codepage);
  13.905 +      #endif
  13.906 +    } else if ((ptr=strchr(argv[arg],'='))!=NULL) {
  13.907 +      i=(int)(ptr-argv[arg]);
  13.908 +      if (i>sNAMEMAX) {
  13.909 +        i=sNAMEMAX;
  13.910 +        error(200,argv[arg],sNAMEMAX);  /* symbol too long, truncated to sNAMEMAX chars */
  13.911 +      } /* if */
  13.912 +      strlcpy(str,argv[arg],i+1);       /* str holds symbol name */
  13.913 +      i=atoi(ptr+1);
  13.914 +      add_constant(str,i,sGLOBAL,0);
  13.915 +    } else {
  13.916 +      strlcpy(str,argv[arg],sizeof(str)-5); /* -5 because default extension is ".psrc" */
  13.917 +      set_extension(str,".psrc",FALSE);
  13.918 +      insert_sourcefile(str);
  13.919 +      /* The output name is the first input name with a different extension,
  13.920 +       * but it is stored in a different directory
  13.921 +       */
  13.922 +      if (strlen(oname)==0) {
  13.923 +        if ((ptr=strrchr(str,DIRSEP_CHAR))!=NULL)
  13.924 +          ptr++;          /* strip path */
  13.925 +        else
  13.926 +          ptr=str;
  13.927 +        assert(strlen(ptr)<_MAX_PATH);
  13.928 +        strcpy(oname,ptr);
  13.929 +      } /* if */
  13.930 +      set_extension(oname,".asm",TRUE);
  13.931 +#if !defined SC_LIGHT
  13.932 +      if (sc_makereport && strlen(rname)==0) {
  13.933 +        if ((ptr=strrchr(str,DIRSEP_CHAR))!=NULL)
  13.934 +          ptr++;          /* strip path */
  13.935 +        else
  13.936 +          ptr=str;
  13.937 +        assert(strlen(ptr)<_MAX_PATH);
  13.938 +        strcpy(rname,ptr);
  13.939 +        set_extension(rname,".xml",TRUE);
  13.940 +      } /* if */
  13.941 +#endif
  13.942 +    } /* if */
  13.943 +  } /* for */
  13.944 +}
  13.945 +
  13.946 +#if !defined SC_LIGHT
  13.947 +static void parserespf(char *filename,char *oname,char *ename,char *pname,
  13.948 +                       char *rname,char *codepage)
  13.949 +{
  13.950 +#define MAX_OPTIONS     100
  13.951 +  FILE *fp;
  13.952 +  char *string, *ptr, **argv;
  13.953 +  int argc;
  13.954 +  long size;
  13.955 +
  13.956 +  if ((fp=fopen(filename,"r"))==NULL)
  13.957 +    error(100,filename);        /* error reading input file */
  13.958 +  /* load the complete file into memory */
  13.959 +  fseek(fp,0L,SEEK_END);
  13.960 +  size=ftell(fp);
  13.961 +  fseek(fp,0L,SEEK_SET);
  13.962 +  assert(size<INT_MAX);
  13.963 +  if ((string=(char *)malloc((int)size+1))==NULL)
  13.964 +    error(103);                 /* insufficient memory */
  13.965 +  /* fill with zeros; in MS-DOS, fread() may collapse CR/LF pairs to
  13.966 +   * a single '\n', so the string size may be smaller than the file
  13.967 +   * size. */
  13.968 +  memset(string,0,(int)size+1);
  13.969 +  fread(string,1,(int)size,fp);
  13.970 +  fclose(fp);
  13.971 +  /* allocate table for option pointers */
  13.972 +  if ((argv=(char **)malloc(MAX_OPTIONS*sizeof(char*)))==NULL)
  13.973 +    error(103);                 /* insufficient memory */
  13.974 +  /* fill the options table */
  13.975 +  ptr=strtok(string," \t\r\n");
  13.976 +  for (argc=1; argc<MAX_OPTIONS && ptr!=NULL; argc++) {
  13.977 +    /* note: the routine skips argv[0], for compatibility with main() */
  13.978 +    argv[argc]=ptr;
  13.979 +    ptr=strtok(NULL," \t\r\n");
  13.980 +  } /* for */
  13.981 +  if (ptr!=NULL)
  13.982 +    error(102,"option table");   /* table overflow */
  13.983 +  /* parse the option table */
  13.984 +  parseoptions(argc,argv,oname,ename,pname,rname,codepage);
  13.985 +  /* free allocated memory */
  13.986 +  free(argv);
  13.987 +  free(string);
  13.988 +}
  13.989 +#endif
  13.990 +
  13.991 +static void setopt(int argc,char **argv,char *oname,char *ename,char *pname,
  13.992 +                   char *rname,char *codepage)
  13.993 +{
  13.994 +  delete_sourcefiletable(); /* make sure it is empty */
  13.995 +  *oname='\0';
  13.996 +  *ename='\0';
  13.997 +  *pname='\0';
  13.998 +  *rname='\0';
  13.999 +  *codepage='\0';
 13.1000 +  strcpy(pname,sDEF_PREFIX);
 13.1001 +
 13.1002 +  #if 0 /* needed to test with BoundsChecker for DOS (it does not pass
 13.1003 +         * through arguments) */
 13.1004 +    insert_sourcefile("test.p");
 13.1005 +    strcpy(oname,"test.asm");
 13.1006 +  #endif
 13.1007 +
 13.1008 +  #if !defined SC_LIGHT
 13.1009 +    /* first parse a "config" file with default options */
 13.1010 +    if (argv[0]!=NULL) {
 13.1011 +      char cfgfile[_MAX_PATH];
 13.1012 +      char *ext;
 13.1013 +      strcpy(cfgfile,argv[0]);
 13.1014 +      if ((ext=strrchr(cfgfile,DIRSEP_CHAR))!=NULL) {
 13.1015 +        *(ext+1)='\0';          /* strip the program filename */
 13.1016 +        strcat(cfgfile,"pawn.cfg");
 13.1017 +      } else {
 13.1018 +        strcpy(cfgfile,"pawn.cfg");
 13.1019 +      } /* if */
 13.1020 +      if (access(cfgfile,4)==0)
 13.1021 +        parserespf(cfgfile,oname,ename,pname,rname,codepage);
 13.1022 +    } /* if */
 13.1023 +  #endif
 13.1024 +  parseoptions(argc,argv,oname,ename,pname,rname,codepage);
 13.1025 +  if (get_sourcefile(0)==NULL)
 13.1026 +    about();
 13.1027 +}
 13.1028 +
 13.1029 +#if defined __BORLANDC__ || defined __WATCOMC__
 13.1030 +  #pragma argsused
 13.1031 +#endif
 13.1032 +static void setconfig(char *root)
 13.1033 +{
 13.1034 +  #if defined macintosh
 13.1035 +    insert_path(":include:");
 13.1036 +  #else
 13.1037 +    char path[_MAX_PATH];
 13.1038 +    char *ptr,*base;
 13.1039 +    int len;
 13.1040 +
 13.1041 +    /* add the default "include" directory */
 13.1042 +    #if defined __WIN32__ || defined _WIN32
 13.1043 +      GetModuleFileNameA(NULL,path,_MAX_PATH);
 13.1044 +    #elif defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
 13.1045 +      /* see www.autopackage.org for the BinReloc module */
 13.1046 +      br_init_lib(NULL);
 13.1047 +      ptr=br_find_exe("/opt/pawn/bin/pawncc");
 13.1048 +      strlcpy(path,ptr,sizeof path);
 13.1049 +      free(ptr);
 13.1050 +    #else
 13.1051 +      if (root!=NULL)
 13.1052 +        strlcpy(path,root,sizeof path); /* path + filename (hopefully) */
 13.1053 +    #endif
 13.1054 +    #if defined __MSDOS__
 13.1055 +      /* strip the options (appended to the path + filename) */
 13.1056 +      if ((ptr=strpbrk(path," \t/"))!=NULL)
 13.1057 +        *ptr='\0';
 13.1058 +    #endif
 13.1059 +    /* terminate just behind last \ or : */
 13.1060 +    if ((ptr=strrchr(path,DIRSEP_CHAR))!=NULL || (ptr=strchr(path,':'))!=NULL) {
 13.1061 +      /* If there is no "\" or ":", the string probably does not contain the
 13.1062 +       * path; so we just don't add it to the list in that case
 13.1063 +       */
 13.1064 +      *(ptr+1)='\0';
 13.1065 +      base=ptr;
 13.1066 +      strcat(path,"include");
 13.1067 +      len=strlen(path);
 13.1068 +      path[len]=DIRSEP_CHAR;
 13.1069 +      path[len+1]='\0';
 13.1070 +      /* see if it exists */
 13.1071 +      if (access(path,0)!=0 && *base==DIRSEP_CHAR) {
 13.1072 +        /* There is no "include" directory below the directory where the compiler
 13.1073 +         * is found. This typically means that the compiler is in a "bin" sub-directory
 13.1074 +         * and the "include" is below the *parent*. So find the parent...
 13.1075 +         */
 13.1076 +        *base='\0';
 13.1077 +        if ((ptr=strrchr(path,DIRSEP_CHAR))!=NULL) {
 13.1078 +          *(ptr+1)='\0';
 13.1079 +          strcat(path,"include");
 13.1080 +          len=strlen(path);
 13.1081 +          path[len]=DIRSEP_CHAR;
 13.1082 +          path[len+1]='\0';
 13.1083 +        } else {
 13.1084 +          *base=DIRSEP_CHAR;
 13.1085 +        } /* if */
 13.1086 +      } /* if */
 13.1087 +      insert_path(path);
 13.1088 +      /* same for the codepage root */
 13.1089 +      #if !defined NO_CODEPAGE
 13.1090 +        *ptr='\0';
 13.1091 +        if (!cp_path(path,"codepage"))
 13.1092 +          error(109,path);        /* codepage path */
 13.1093 +      #endif
 13.1094 +      /* also copy the root path (for the XML documentation) */
 13.1095 +      #if !defined SC_LIGHT
 13.1096 +        *ptr='\0';
 13.1097 +        strcpy(sc_rootpath,path);
 13.1098 +      #endif
 13.1099 +    } /* if */
 13.1100 +  #endif /* macintosh */
 13.1101 +}
 13.1102 +
 13.1103 +static void setcaption(void)
 13.1104 +{
 13.1105 +  pc_printf("SourcePawn Compiler " SMC_VERSTRING "\n");
 13.1106 +  pc_printf("Copyright (c) 1997-2006, ITB CompuPhase, (C)2004-2006 AlliedModders, LLC\n\n");
 13.1107 +}
 13.1108 +
 13.1109 +static void about(void)
 13.1110 +{
 13.1111 +  if (strlen(errfname)==0) {
 13.1112 +    setcaption();
 13.1113 +    pc_printf("Usage:   pawncc <filename> [filename...] [options]\n\n");
 13.1114 +    pc_printf("Options:\n");
 13.1115 +    pc_printf("         -A<num>  alignment in bytes of the data segment and the stack\n");
 13.1116 +    pc_printf("         -a       output assembler code\n");
 13.1117 +#if AMX_COMPACTMARGIN > 2
 13.1118 +    pc_printf("         -C[+/-]  compact encoding for output file (default=%c)\n", sc_compress ? '+' : '-');
 13.1119 +#endif
 13.1120 +    pc_printf("         -c<name> codepage name or number; e.g. 1252 for Windows Latin-1\n");
 13.1121 +#if defined dos_setdrive
 13.1122 +    pc_printf("         -Dpath   active directory path\n");
 13.1123 +#endif
 13.1124 +#if 0 /* not used for SourceMod */
 13.1125 +    pc_printf("         -d<num>  debugging level (default=-d%d)\n",sc_debug);
 13.1126 +    pc_printf("             0    no symbolic information, no run-time checks\n");
 13.1127 +    pc_printf("             1    run-time checks, no symbolic information\n");
 13.1128 +    pc_printf("             2    full debug information and dynamic checking\n");
 13.1129 +    pc_printf("             3    same as -d2, but implies -O0\n");
 13.1130 +#endif
 13.1131 +    pc_printf("         -e<name> set name of error file (quiet compile)\n");
 13.1132 +#if defined	__WIN32__ || defined _WIN32 || defined _Windows
 13.1133 +    pc_printf("         -H<hwnd> window handle to send a notification message on finish\n");
 13.1134 +#endif
 13.1135 +    pc_printf("         -i<name> path for include files\n");
 13.1136 +    pc_printf("         -l       create list file (preprocess only)\n");
 13.1137 +    pc_printf("         -o<name> set base name of (P-code) output file\n");
 13.1138 +    pc_printf("         -O<num>  optimization level (default=-O%d)\n",pc_optimize);
 13.1139 +    pc_printf("             0    no optimization\n");
 13.1140 +#if 0 /* not used for SourceMod */
 13.1141 +    pc_printf("             1    JIT-compatible optimizations only\n");
 13.1142 +#endif
 13.1143 +    pc_printf("             2    full optimizations\n");
 13.1144 +    pc_printf("         -p<name> set name of \"prefix\" file\n");
 13.1145 +#if !defined SC_LIGHT
 13.1146 +    pc_printf("         -r[name] write cross reference report to console or to specified file\n");
 13.1147 +#endif
 13.1148 +    pc_printf("         -S<num>  stack/heap size in cells (default=%d)\n",(int)pc_stksize);
 13.1149 +    pc_printf("         -s<num>  skip lines from the input file\n");
 13.1150 +    pc_printf("         -t<num>  TAB indent size (in character positions, default=%d)\n",sc_tabsize);
 13.1151 +    pc_printf("         -v<num>  verbosity level; 0=quiet, 1=normal, 2=verbose (default=%d)\n",verbosity);
 13.1152 +    pc_printf("         -w<num>  disable a specific warning by its number\n");
 13.1153 +    pc_printf("         -X<num>  abstract machine size limit in bytes\n");
 13.1154 +    pc_printf("         -XD<num> abstract machine data/stack size limit in bytes\n");
 13.1155 +    pc_printf("         -\\       use '\\' for escape characters\n");
 13.1156 +    pc_printf("         -^       use '^' for escape characters\n");
 13.1157 +    pc_printf("         -;[+/-]  require a semicolon to end each statement (default=%c)\n", sc_needsemicolon ? '+' : '-');
 13.1158 +#if 0 /* not allowed in SourceMod */
 13.1159 +    pc_printf("         -([+/-]  require parantheses for function invocation (default=%c)\n", optproccall ? '-' : '+');
 13.1160 +#endif
 13.1161 +    pc_printf("         sym=val  define constant \"sym\" with value \"val\"\n");
 13.1162 +    pc_printf("         sym=     define constant \"sym\" with value 0\n");
 13.1163 +#if defined	__WIN32__ || defined _WIN32 || defined _Windows || defined __MSDOS__
 13.1164 +    pc_printf("\nOptions may start with a dash or a slash; the options \"-d0\" and \"/d0\" are\n");
 13.1165 +    pc_printf("equivalent.\n");
 13.1166 +#endif
 13.1167 +    pc_printf("\nOptions with a value may optionally separate the value from the option letter\n");
 13.1168 +    pc_printf("with a colon (\":\") or an equal sign (\"=\"). That is, the options \"-d0\", \"-d=0\"\n");
 13.1169 +    pc_printf("and \"-d:0\" are all equivalent.\n");
 13.1170 +  } /* if */
 13.1171 +  norun = 1;
 13.1172 +  longjmp(errbuf,3);        /* user abort */
 13.1173 +}
 13.1174 +
 13.1175 +static void setconstants(void)
 13.1176 +{
 13.1177 +  int debug;
 13.1178 +
 13.1179 +  assert(sc_status==statIDLE);
 13.1180 +  append_constval(&tagname_tab,"_",0,0);/* "untagged" */
 13.1181 +  append_constval(&tagname_tab,"bool",1,0);
 13.1182 +
 13.1183 +  add_constant("true",1,sGLOBAL,1);     /* boolean flags */
 13.1184 +  add_constant("false",0,sGLOBAL,1);
 13.1185 +  add_constant("EOS",0,sGLOBAL,0);      /* End Of String, or '\0' */
 13.1186 +  #if PAWN_CELL_SIZE==16
 13.1187 +    add_constant("cellbits",16,sGLOBAL,0);
 13.1188 +    #if defined _I16_MAX
 13.1189 +      add_constant("cellmax",_I16_MAX,sGLOBAL,0);
 13.1190 +      add_constant("cellmin",_I16_MIN,sGLOBAL,0);
 13.1191 +    #else
 13.1192 +      add_constant("cellmax",SHRT_MAX,sGLOBAL,0);
 13.1193 +      add_constant("cellmin",SHRT_MIN,sGLOBAL,0);
 13.1194 +    #endif
 13.1195 +  #elif PAWN_CELL_SIZE==32
 13.1196 +    add_constant("cellbits",32,sGLOBAL,0);
 13.1197 +    #if defined _I32_MAX
 13.1198 +      add_constant("cellmax",_I32_MAX,sGLOBAL,0);
 13.1199 +      add_constant("cellmin",_I32_MIN,sGLOBAL,0);
 13.1200 +    #else
 13.1201 +      add_constant("cellmax",LONG_MAX,sGLOBAL,0);
 13.1202 +      add_constant("cellmin",LONG_MIN,sGLOBAL,0);
 13.1203 +    #endif
 13.1204 +  #elif PAWN_CELL_SIZE==64
 13.1205 +    #if !defined _I64_MIN
 13.1206 +      #define _I64_MIN  (-9223372036854775807ULL - 1)
 13.1207 +      #define _I64_MAX    9223372036854775807ULL
 13.1208 +    #endif
 13.1209 +    add_constant("cellbits",64,sGLOBAL,0);
 13.1210 +    add_constant("cellmax",_I64_MAX,sGLOBAL,0);
 13.1211 +    add_constant("cellmin",_I64_MIN,sGLOBAL,0);
 13.1212 +  #else
 13.1213 +    #error Unsupported cell size
 13.1214 +  #endif
 13.1215 +  add_constant("charbits",sCHARBITS,sGLOBAL,0);
 13.1216 +  add_constant("charmin",0,sGLOBAL,0);
 13.1217 +  add_constant("charmax",~(-1 << sCHARBITS) - 1,sGLOBAL,0);
 13.1218 +  add_constant("ucharmax",(1 << (sizeof(cell)-1)*8)-1,sGLOBAL,0);
 13.1219 +
 13.1220 +  add_constant("__Pawn",VERSION_INT,sGLOBAL,0);
 13.1221 +
 13.1222 +  debug=0;
 13.1223 +  if ((sc_debug & (sCHKBOUNDS | sSYMBOLIC))==(sCHKBOUNDS | sSYMBOLIC))
 13.1224 +    debug=2;
 13.1225 +  else if ((sc_debug & sCHKBOUNDS)==sCHKBOUNDS)
 13.1226 +    debug=1;
 13.1227 +  add_constant("debug",debug,sGLOBAL,0);
 13.1228 +
 13.1229 +  append_constval(&sc_automaton_tab,"",0,0);    /* anonymous automaton */
 13.1230 +}
 13.1231 +
 13.1232 +static int getclassspec(int initialtok,int *fpublic,int *fstatic,int *fstock,int *fconst)
 13.1233 +{
 13.1234 +  int tok,err;
 13.1235 +  cell val;
 13.1236 +  char *str;
 13.1237 +
 13.1238 +  assert(fconst!=NULL);
 13.1239 +  assert(fstock!=NULL);
 13.1240 +  assert(fstatic!=NULL);
 13.1241 +  assert(fpublic!=NULL);
 13.1242 +  *fconst=FALSE;
 13.1243 +  *fstock=FALSE;
 13.1244 +  *fstatic=FALSE;
 13.1245 +  *fpublic=FALSE;
 13.1246 +  switch (initialtok) {
 13.1247 +  case tCONST:
 13.1248 +    *fconst=TRUE;
 13.1249 +    break;
 13.1250 +  case tSTOCK:
 13.1251 +    *fstock=TRUE;
 13.1252 +    break;
 13.1253 +  case tSTATIC:
 13.1254 +    *fstatic=TRUE;
 13.1255 +    break;
 13.1256 +  case tPUBLIC:
 13.1257 +    *fpublic=TRUE;
 13.1258 +    break;
 13.1259 +  } /* switch */
 13.1260 +
 13.1261 +  err=0;
 13.1262 +  do {
 13.1263 +    tok=lex(&val,&str);  /* read in (new) token */
 13.1264 +    switch (tok) {
 13.1265 +    case tCONST:
 13.1266 +      if (*fconst)
 13.1267 +        err=42;          /* invalid combination of class specifiers */
 13.1268 +      *fconst=TRUE;
 13.1269 +      break;
 13.1270 +    case tSTOCK:
 13.1271 +      if (*fstock)
 13.1272 +        err=42;          /* invalid combination of class specifiers */
 13.1273 +      *fstock=TRUE;
 13.1274 +      break;
 13.1275 +    case tSTATIC:
 13.1276 +      if (*fstatic)
 13.1277 +        err=42;          /* invalid combination of class specifiers */
 13.1278 +      *fstatic=TRUE;
 13.1279 +      break;
 13.1280 +    case tPUBLIC:
 13.1281 +      if (*fpublic)
 13.1282 +        err=42;          /* invalid combination of class specifiers */
 13.1283 +      *fpublic=TRUE;
 13.1284 +      break;
 13.1285 +    default:
 13.1286 +      lexpush();
 13.1287 +      tok=0;             /* force break out of loop */
 13.1288 +    } /* switch */
 13.1289 +  } while (tok && err==0);
 13.1290 +
 13.1291 +  /* extra checks */
 13.1292 +  if (*fstatic && *fpublic) {
 13.1293 +    err=42;              /* invalid combination of class specifiers */
 13.1294 +    *fstatic=*fpublic=FALSE;
 13.1295 +  } /* if */
 13.1296 +
 13.1297 +  if (err)
 13.1298 +    error(err);
 13.1299 +  return err==0;
 13.1300 +}
 13.1301 +
 13.1302 +/*  parse       - process all input text
 13.1303 + *
 13.1304 + *  At this level, only static declarations and function definitions are legal.
 13.1305 + */
 13.1306 +static void parse(void)
 13.1307 +{
 13.1308 +  int tok,fconst,fstock,fstatic,fpublic;
 13.1309 +  cell val;
 13.1310 +  char *str;
 13.1311 +
 13.1312 +  while (freading){
 13.1313 +    /* first try whether a declaration possibly is native or public */
 13.1314 +    tok=lex(&val,&str);  /* read in (new) token */
 13.1315 +    switch (tok) {
 13.1316 +    case 0:
 13.1317 +      /* ignore zero's */
 13.1318 +      break;
 13.1319 +    case tNEW:
 13.1320 +      if (getclassspec(tok,&fpublic,&fstatic,&fstock,&fconst))
 13.1321 +        declglb(NULL,0,fpublic,fstatic,fstock,fconst);
 13.1322 +      break;
 13.1323 +    case tSTATIC:
 13.1324 +      /* This can be a static function or a static global variable; we know
 13.1325 +       * which of the two as soon as we have parsed up to the point where an
 13.1326 +       * opening paranthesis of a function would be expected. To back out after
 13.1327 +       * deciding it was a declaration of a static variable after all, we have
 13.1328 +       * to store the symbol name and tag.
 13.1329 +       */
 13.1330 +      if (getclassspec(tok,&fpublic,&fstatic,&fstock,&fconst)) {
 13.1331 +        assert(!fpublic);
 13.1332 +        declfuncvar(fpublic,fstatic,fstock,fconst);
 13.1333 +      } /* if */
 13.1334 +      break;
 13.1335 +    case tCONST:
 13.1336 +      decl_const(sGLOBAL);
 13.1337 +      break;
 13.1338 +    case tENUM:
 13.1339 +      decl_enum(sGLOBAL);
 13.1340 +      break;
 13.1341 +    case tPUBLIC:
 13.1342 +      /* This can be a public function or a public variable; see the comment
 13.1343 +       * above (for static functions/variables) for details.
 13.1344 +       */
 13.1345 +      if (getclassspec(tok,&fpublic,&fstatic,&fstock,&fconst)) {
 13.1346 +        assert(!fstatic);
 13.1347 +        declfuncvar(fpublic,fstatic,fstock,fconst);
 13.1348 +      } /* if */
 13.1349 +      break;
 13.1350 +    case tSTOCK:
 13.1351 +      /* This can be a stock function or a stock *global*) variable; see the
 13.1352 +       * comment above (for static functions/variables) for details.
 13.1353 +       */
 13.1354 +      if (getclassspec(tok,&fpublic,&fstatic,&fstock,&fconst)) {
 13.1355 +        assert(fstock);
 13.1356 +        declfuncvar(fpublic,fstatic,fstock,fconst);
 13.1357 +      } /* if */
 13.1358 +      break;
 13.1359 +    case tLABEL:
 13.1360 +    case tSYMBOL:
 13.1361 +    case tOPERATOR:
 13.1362 +      lexpush();
 13.1363 +      if (!newfunc(NULL,-1,FALSE,FALSE,FALSE)) {
 13.1364 +        error(10);              /* illegal function or declaration */
 13.1365 +        lexclr(TRUE);           /* drop the rest of the line */
 13.1366 +        litidx=0;               /* drop the literal queue too */
 13.1367 +      } /* if */
 13.1368 +      break;
 13.1369 +    case tNATIVE:
 13.1370 +      funcstub(TRUE);           /* create a dummy function */
 13.1371 +      break;
 13.1372 +    case tFORWARD:
 13.1373 +      funcstub(FALSE);
 13.1374 +      break;
 13.1375 +    case '}':
 13.1376 +      error(54);                /* unmatched closing brace */
 13.1377 +      break;
 13.1378 +    case '{':
 13.1379 +      error(55);                /* start of function body without function header */
 13.1380 +      break;
 13.1381 +    default:
 13.1382 +      if (freading) {
 13.1383 +        error(10);              /* illegal function or declaration */
 13.1384 +        lexclr(TRUE);           /* drop the rest of the line */
 13.1385 +        litidx=0;               /* drop any literal arrays (strings) */
 13.1386 +      } /* if */
 13.1387 +    } /* switch */
 13.1388 +  } /* while */
 13.1389 +}
 13.1390 +
 13.1391 +/*  dumplits
 13.1392 + *
 13.1393 + *  Dump the literal pool (strings etc.)
 13.1394 + *
 13.1395 + *  Global references: litidx (referred to only)
 13.1396 + */
 13.1397 +static void dumplits(void)
 13.1398 +{
 13.1399 +  int j,k;
 13.1400 +
 13.1401 +  k=0;
 13.1402 +  while (k<litidx){
 13.1403 +    /* should be in the data segment */
 13.1404 +    assert(curseg==2);
 13.1405 +    defstorage();
 13.1406 +    j=16;       /* 16 values per line */
 13.1407 +    while (j && k<litidx){
 13.1408 +      outval(litq[k], FALSE);
 13.1409 +      stgwrite(" ");
 13.1410 +      k++;
 13.1411 +      j--;
 13.1412 +      if (j==0 || k>=litidx)
 13.1413 +        stgwrite("\n");         /* force a newline after 10 dumps */
 13.1414 +      /* Note: stgwrite() buffers a line until it is complete. It recognizes
 13.1415 +       * the end of line as a sequence of "\n\0", so something like "\n\t"
 13.1416 +       * so should not be passed to stgwrite().
 13.1417 +       */
 13.1418 +    } /* while */
 13.1419 +  } /* while */
 13.1420 +}
 13.1421 +
 13.1422 +/*  dumpzero
 13.1423 + *
 13.1424 + *  Dump zero's for default initial values
 13.1425 + */
 13.1426 +static void dumpzero(int count)
 13.1427 +{
 13.1428 +  int i;
 13.1429 +
 13.1430 +  if (count<=0)
 13.1431 +    return;
 13.1432 +  assert(curseg==2);
 13.1433 +  defstorage();
 13.1434 +  i=0;
 13.1435 +  while (count-- > 0) {
 13.1436 +    outval(0, FALSE);
 13.1437 +    i=(i+1) % 16;
 13.1438 +    stgwrite((i==0 || count==0) ? "\n" : " ");
 13.1439 +    if (i==0 && count>0)
 13.1440 +      defstorage();
 13.1441 +  } /* while */
 13.1442 +}
 13.1443 +
 13.1444 +static void aligndata(int numbytes)
 13.1445 +{
 13.1446 +  assert(numbytes % sizeof(cell) == 0);   /* alignment must be a multiple of
 13.1447 +                                           * the cell size */
 13.1448 +  assert(numbytes!=0);
 13.1449 +
 13.1450 +  if ((((glb_declared+litidx)*sizeof(cell)) % numbytes)!=0) {
 13.1451 +    while ((((glb_declared+litidx)*sizeof(cell)) % numbytes)!=0)
 13.1452 +      litadd(0);
 13.1453 +  } /* if */
 13.1454 +
 13.1455 +}
 13.1456 +
 13.1457 +#if !defined SC_LIGHT
 13.1458 +/* sc_attachdocumentation()
 13.1459 + * appends documentation comments to the passed-in symbol, or to a global
 13.1460 + * string if "sym" is NULL.
 13.1461 + */
 13.1462 +void sc_attachdocumentation(symbol *sym)
 13.1463 +{
 13.1464 +  int line;
 13.1465 +  size_t length;
 13.1466 +  char *str,*doc;
 13.1467 +
 13.1468 +  if (!sc_makereport || sc_status!=statFIRST || sc_parsenum>0) {
 13.1469 +    /* just clear the entire table */
 13.1470 +    delete_docstringtable();
 13.1471 +    return;
 13.1472 +  } /* if */
 13.1473 +  /* in the case of state functions, multiple documentation sections may
 13.1474 +   * appear; we should concatenate these
 13.1475 +   * (with forward declarations, this is also already the case, so the assertion
 13.1476 +   * below is invalid)
 13.1477 +   */
 13.1478 +  // assert(sym==NULL || sym->documentation==NULL || sym->states!=NULL);
 13.1479 +
 13.1480 +  /* first check the size */
 13.1481 +  length=0;
 13.1482 +  for (line=0; (str=get_docstring(line))!=NULL && *str!=sDOCSEP; line++) {
 13.1483 +    if (length>0)
 13.1484 +      length++;   /* count 1 extra for a separating space */
 13.1485 +    length+=strlen(str);
 13.1486 +  } /* for */
 13.1487 +  if (sym==NULL && sc_documentation!=NULL) {
 13.1488 +    length += strlen(sc_documentation) + 1 + 4; /* plus 4 for "<p/>" */
 13.1489 +    assert(length>strlen(sc_documentation));
 13.1490 +  } /* if */
 13.1491 +
 13.1492 +  if (length>0) {
 13.1493 +    /* allocate memory for the documentation */
 13.1494 +    if (sym!=NULL && sym->documentation!=NULL)
 13.1495 +      length+=strlen(sym->documentation) + 1 + 4;/* plus 4 for "<p/>" */
 13.1496 +    doc=(char*)malloc((length+1)*sizeof(char));
 13.1497 +    if (doc!=NULL) {
 13.1498 +      /* initialize string or concatenate */
 13.1499 +      if (sym==NULL && sc_documentation!=NULL) {
 13.1500 +        strcpy(doc,sc_documentation);
 13.1501 +        strcat(doc,"<p/>");
 13.1502 +      } else if (sym!=NULL && sym->documentation!=NULL) {
 13.1503 +        strcpy(doc,sym->documentation);
 13.1504 +        strcat(doc,"<p/>");
 13.1505 +        free(sym->documentation);
 13.1506 +        sym->documentation=NULL;
 13.1507 +      } else {
 13.1508 +        doc[0]='\0';
 13.1509 +      } /* if */
 13.1510 +      /* collect all documentation */
 13.1511 +      while ((str=get_docstring(0))!=NULL && *str!=sDOCSEP) {
 13.1512 +        if (doc[0]!='\0')
 13.1513 +          strcat(doc," ");
 13.1514 +        strcat(doc,str);
 13.1515 +        delete_docstring(0);
 13.1516 +      } /* while */
 13.1517 +      if (str!=NULL) {
 13.1518 +        /* also delete the separator */
 13.1519 +        assert(*str==sDOCSEP);
 13.1520 +        delete_docstring(0);
 13.1521 +      } /* if */
 13.1522 +      if (sym!=NULL) {
 13.1523 +        assert(sym->documentation==NULL);
 13.1524 +        sym->documentation=doc;
 13.1525 +      } else {
 13.1526 +        if (sc_documentation!=NULL)
 13.1527 +          free(sc_documentation);
 13.1528 +        sc_documentation=doc;
 13.1529 +      } /* if */
 13.1530 +    } /* if */
 13.1531 +  } else {
 13.1532 +    /* delete an empty separator, if present */
 13.1533 +    if ((str=get_docstring(0))!=NULL && *str==sDOCSEP)
 13.1534 +      delete_docstring(0);
 13.1535 +  } /* if */
 13.1536 +}
 13.1537 +
 13.1538 +static void insert_docstring_separator(void)
 13.1539 +{
 13.1540 +  char sep[2]={sDOCSEP,'\0'};
 13.1541 +  insert_docstring(sep);
 13.1542 +}
 13.1543 +#else
 13.1544 +  #define sc_attachdocumentation(s)      (void)(s)
 13.1545 +  #define insert_docstring_separator()
 13.1546 +#endif
 13.1547 +
 13.1548 +static void declfuncvar(int fpublic,int fstatic,int fstock,int fconst)
 13.1549 +{
 13.1550 +  char name[sNAMEMAX+11];
 13.1551 +  int tok,tag;
 13.1552 +  char *str;
 13.1553 +  cell val;
 13.1554 +  int invalidfunc;
 13.1555 +
 13.1556 +  tag=pc_addtag(NULL);
 13.1557 +  tok=lex(&val,&str);
 13.1558 +  /* if we arrived here, this may not be a declaration of a native function
 13.1559 +   * or variable
 13.1560 +   */
 13.1561 +  if (tok==tNATIVE) {
 13.1562 +    error(42);          /* invalid combination of class specifiers */
 13.1563 +    return;
 13.1564 +  } /* if */
 13.1565 +
 13.1566 +  if (tok!=tSYMBOL && tok!=tOPERATOR) {
 13.1567 +    lexpush();
 13.1568 +    needtoken(tSYMBOL);
 13.1569 +    lexclr(TRUE);       /* drop the rest of the line */
 13.1570 +    litidx=0;           /* drop the literal queue too */
 13.1571 +    return;
 13.1572 +  } /* if */
 13.1573 +  if (tok==tOPERATOR) {
 13.1574 +    lexpush();          /* push "operator" keyword back (for later analysis) */
 13.1575 +    if (!newfunc(NULL,tag,fpublic,fstatic,fstock)) {
 13.1576 +      error(10);        /* illegal function or declaration */
 13.1577 +      lexclr(TRUE);     /* drop the rest of the line */
 13.1578 +      litidx=0;         /* drop the literal queue too */
 13.1579 +    } /* if */
 13.1580 +  } else {
 13.1581 +    /* so tok is tSYMBOL */
 13.1582 +    assert(strlen(str)<=sNAMEMAX);
 13.1583 +    strcpy(name,str);
 13.1584 +    /* only variables can be "const" or both "public" and "stock" */
 13.1585 +    invalidfunc= fconst || (fpublic && fstock);
 13.1586 +    if (invalidfunc || !newfunc(name,tag,fpublic,fstatic,fstock)) {
 13.1587 +      /* if not a function, try a global variable */
 13.1588 +      declglb(name,tag,fpublic,fstatic,fstock,fconst);
 13.1589 +    } /* if */
 13.1590 +  } /* if */
 13.1591 +}
 13.1592 +
 13.1593 +/*  declglb     - declare global symbols
 13.1594 + *
 13.1595 + *  Declare a static (global) variable. Global variables are stored in
 13.1596 + *  the DATA segment.
 13.1597 + *
 13.1598 + *  global references: glb_declared     (altered)
 13.1599 + */
 13.1600 +static void declglb(char *firstname,int firsttag,int fpublic,int fstatic,int fstock,int fconst)
 13.1601 +{
 13.1602 +  int ident,tag,ispublic;
 13.1603 +  int idxtag[sDIMEN_MAX];
 13.1604 +  char name[sNAMEMAX+1];
 13.1605 +  cell val,size,cidx;
 13.1606 +  ucell address;
 13.1607 +  int glb_incr;
 13.1608 +  char *str;
 13.1609 +  int dim[sDIMEN_MAX];
 13.1610 +  int numdim;
 13.1611 +  short filenum;
 13.1612 +  symbol *sym;
 13.1613 +  constvalue *enumroot;
 13.1614 +  #if !defined NDEBUG
 13.1615 +    cell glbdecl=0;
 13.1616 +  #endif
 13.1617 +
 13.1618 +  assert(!fpublic || !fstatic);         /* may not both be set */
 13.1619 +  insert_docstring_separator();         /* see comment in newfunc() */
 13.1620 +  filenum=fcurrent;                     /* save file number at the start of the declaration */
 13.1621 +  do {
 13.1622 +    size=1;                             /* single size (no array) */
 13.1623 +    numdim=0;                           /* no dimensions */
 13.1624 +    ident=iVARIABLE;
 13.1625 +    if (firstname!=NULL) {
 13.1626 +      assert(strlen(firstname)<=sNAMEMAX);
 13.1627 +      strcpy(name,firstname);           /* save symbol name */
 13.1628 +      tag=firsttag;
 13.1629 +      firstname=NULL;
 13.1630 +    } else {
 13.1631 +      tag=pc_addtag(NULL);
 13.1632 +      if (lex(&val,&str)!=tSYMBOL)      /* read in (new) token */
 13.1633 +        error(20,str);                  /* invalid symbol name */
 13.1634 +      assert(strlen(str)<=sNAMEMAX);
 13.1635 +      strcpy(name,str);                 /* save symbol name */
 13.1636 +    } /* if */
 13.1637 +    ispublic=fpublic;
 13.1638 +    if (name[0]==PUBLIC_CHAR) {
 13.1639 +      ispublic=TRUE;                    /* implicitly public variable */
 13.1640 +      assert(!fstatic);
 13.1641 +    } /* if */
 13.1642 +    while (matchtoken('[')) {
 13.1643 +      ident=iARRAY;
 13.1644 +      if (numdim == sDIMEN_MAX) {
 13.1645 +        error(53);                      /* exceeding maximum number of dimensions */
 13.1646 +        return;
 13.1647 +      } /* if */
 13.1648 +      size=needsub(&idxtag[numdim],&enumroot);  /* get size; size==0 for "var[]" */
 13.1649 +      #if INT_MAX < LONG_MAX
 13.1650 +        if (size > INT_MAX)
 13.1651 +          error(105);                   /* overflow, exceeding capacity */
 13.1652 +      #endif
 13.1653 +      if (ispublic)
 13.1654 +        error(56,name);                 /* arrays cannot be public */
 13.1655 +      dim[numdim++]=(int)size;
 13.1656 +    } /* while */
 13.1657 +    assert(sc_curstates==0);
 13.1658 +    sc_curstates=getstates(name);
 13.1659 +    if (sc_curstates<0) {
 13.1660 +      error(85,name);           /* empty state list on declaration */
 13.1661 +      sc_curstates=0;
 13.1662 +    } else if (sc_curstates>0 && ispublic) {
 13.1663 +      error(88,name);           /* public variables may not have states */
 13.1664 +      sc_curstates=0;
 13.1665 +    } /* if */
 13.1666 +    sym=findconst(name,NULL);
 13.1667 +    if (sym==NULL) {
 13.1668 +      sym=findglb(name,sSTATEVAR);
 13.1669 +      /* if a global variable without states is found and this declaration has
 13.1670 +       * states, the declaration is okay
 13.1671 +       */
 13.1672 +      if (sym!=NULL && sym->states==NULL && sc_curstates>0)
 13.1673 +        sym=NULL;               /* set to NULL, we found the global variable */
 13.1674 +      if (sc_curstates>0 && findglb(name,sGLOBAL)!=NULL)
 13.1675 +        error(233,name);        /* state variable shadows a global variable */
 13.1676 +    } /* if */
 13.1677 +    /* we have either:
 13.1678 +     * a) not found a matching variable (or rejected it, because it was a shadow)
 13.1679 +     * b) found a global variable and we were looking for that global variable
 13.1680 +     * c) found a state variable in the automaton that we were looking for
 13.1681 +     */
 13.1682 +    assert(sym==NULL
 13.1683 +           || sym->states==NULL && sc_curstates==0
 13.1684 +           || sym->states!=NULL && sym->next!=NULL && sym->states->next->index==sc_curstates);
 13.1685 +    /* a state variable may only have a single id in its list (so either this
 13.1686 +     * variable has no states, or it has a single list)
 13.1687 +     */
 13.1688 +    assert(sym==NULL || sym->states==NULL || sym->states->next->next==NULL);
 13.1689 +    /* it is okay for the (global) variable to exist, as long as it belongs to
 13.1690 +     * a different automaton
 13.1691 +     */
 13.1692 +    if (sym!=NULL && (sym->usage & uDEFINE)!=0)
 13.1693 +      error(21,name);                   /* symbol already defined */
 13.1694 +    /* if this variable is never used (which can be detected only in the
 13.1695 +     * second stage), shut off code generation
 13.1696 +     */
 13.1697 +    cidx=0;             /* only to avoid a compiler warning */
 13.1698 +    if (sc_status==statWRITE && sym!=NULL && (sym->usage & (uREAD | uWRITTEN))==0) {
 13.1699 +      sc_status=statSKIP;
 13.1700 +      cidx=code_idx;
 13.1701 +      #if !defined NDEBUG
 13.1702 +        glbdecl=glb_declared;
 13.1703 +      #endif
 13.1704 +    } /* if */
 13.1705 +    begdseg();          /* real (initialized) data in data segment */
 13.1706 +    assert(litidx==0);  /* literal queue should be empty */
 13.1707 +    if (sc_alignnext) {
 13.1708 +      litidx=0;
 13.1709 +      aligndata(sc_dataalign);
 13.1710 +      dumplits();       /* dump the literal queue */
 13.1711 +      sc_alignnext=FALSE;
 13.1712 +      litidx=0;         /* global initial data is dumped, so restart at zero */
 13.1713 +    } /* if */
 13.1714 +    assert(litidx==0);  /* literal queue should be empty (again) */
 13.1715 +    initials(ident,tag,&size,dim,numdim,enumroot);/* stores values in the literal queue */
 13.1716 +    assert(size>=litidx);
 13.1717 +    if (numdim==1)
 13.1718 +      dim[0]=(int)size;
 13.1719 +    /* before dumping the initial values (or zeros) check whether this variable
 13.1720 +     * overlaps another
 13.1721 +     */
 13.1722 +    if (sc_curstates>0) {
 13.1723 +      unsigned char *map;
 13.1724 +
 13.1725 +      if (litidx!=0)
 13.1726 +        error(89,name); /* state variables may not be initialized */
 13.1727 +      /* find an appropriate address for the state variable */
 13.1728 +      /* assume that it cannot be found */
 13.1729 +      address=sizeof(cell)*glb_declared;
 13.1730 +      glb_incr=(int)size;
 13.1731 +      /* use a memory map in which every cell occupies one bit */
 13.1732 +      if (glb_declared>0 && (map=(unsigned char*)malloc((glb_declared+7)/8))!=NULL) {
 13.1733 +        int fsa=state_getfsa(sc_curstates);
 13.1734 +        symbol *sweep;
 13.1735 +        cell sweepsize,addr;
 13.1736 +        memset(map,0,(glb_declared+7)/8);
 13.1737 +        assert(fsa>=0);
 13.1738 +        /* fill in all variables belonging to this automaton */
 13.1739 +        for (sweep=glbtab.next; sweep!=NULL; sweep=sweep->next) {
 13.1740 +          if (sweep->parent!=NULL || sweep->states==NULL || sweep==sym)
 13.1741 +            continue;   /* hierarchical type, or no states, or same as this variable */
 13.1742 +          if (sweep->ident!=iVARIABLE && sweep->ident!=iARRAY)
 13.1743 +            continue;   /* a function or a constant */
 13.1744 +          if ((sweep->usage & uDEFINE)==0)
 13.1745 +            continue;   /* undefined variable, ignore */
 13.1746 +          if (fsa!=state_getfsa(sweep->states->next->index))
 13.1747 +            continue;   /* wrong automaton */
 13.1748 +          /* when arrived here, this is a global variable, with states and
 13.1749 +           * belonging to the same automaton as the variable we are declaring
 13.1750 +           */
 13.1751 +          sweepsize=(sweep->ident==iVARIABLE) ? 1 : array_totalsize(sweep);
 13.1752 +          assert(sweep->addr % sizeof(cell) == 0);
 13.1753 +          addr=sweep->addr/sizeof(cell);
 13.1754 +          /* mark this address range */
 13.1755 +          while (sweepsize-->0) {
 13.1756 +            map[addr/8] |= (unsigned char)(1 << (addr % 8));
 13.1757 +            addr++;
 13.1758 +          } /* while */
 13.1759 +        } /* for */
 13.1760 +        /* go over it again, clearing any ranges that have conflicts */
 13.1761 +        for (sweep=glbtab.next; sweep!=NULL; sweep=sweep->next) {
 13.1762 +          if (sweep->parent!=NULL || sweep->states==NULL || sweep==sym)
 13.1763 +            continue;   /* hierarchical type, or no states, or same as this variable */
 13.1764 +          if (sweep->ident!=iVARIABLE && sweep->ident!=iARRAY)
 13.1765 +            continue;   /* a function or a constant */
 13.1766 +          if ((sweep->usage & uDEFINE)==0)
 13.1767 +            continue;   /* undefined variable, ignore */
 13.1768 +          if (fsa!=state_getfsa(sweep->states->next->index))
 13.1769 +            continue;   /* wrong automaton */
 13.1770 +          /* when arrived here, this is a global variable, with states and
 13.1771 +           * belonging to the same automaton as the variable we are declaring
 13.1772 +           */
 13.1773 +          /* if the lists of states of the existing variable and the new
 13.1774 +           * variable have a non-empty intersection, this is not a suitable
 13.1775 +           * overlap point -> wipe the address range
 13.1776 +           */
 13.1777 +          if (state_conflict_id(sc_curstates,sweep->states->next->index)) {
 13.1778 +            sweepsize=(sweep->ident==iVARIABLE) ? 1 : array_totalsize(sweep);
 13.1779 +            assert(sweep->addr % sizeof(cell) == 0);
 13.1780 +            addr=sweep->addr/sizeof(cell);
 13.1781 +            /* mark this address range */
 13.1782 +            while (sweepsize-->0) {
 13.1783 +              map[addr/8] &= (unsigned char)(~(1 << (addr % 8)));
 13.1784 +              addr++;
 13.1785 +            } /* while */
 13.1786 +          } /* if */
 13.1787 +        } /* for */
 13.1788 +        /* now walk through the map and find a starting point that is big enough */
 13.1789 +        sweepsize=0;
 13.1790 +        for (addr=0; addr<glb_declared; addr++) {
 13.1791 +          if ((map[addr/8] & (1 << (addr % 8)))==0)
 13.1792 +            continue;
 13.1793 +          for (sweepsize=addr+1; sweepsize<glb_declared; sweepsize++) {
 13.1794 +            if ((map[sweepsize/8] & (1 << (sweepsize % 8)))==0)
 13.1795 +              break;    /* zero bit found, skip this range */
 13.1796 +            if (sweepsize-addr>=size)
 13.1797 +              break;    /* fitting range found, no need to search further */
 13.1798 +          } /* for */
 13.1799 +          if (sweepsize-addr>=size)
 13.1800 +            break;      /* fitting range found, no need to search further */
 13.1801 +          addr=sweepsize;
 13.1802 +        } /* for */
 13.1803 +        free(map);
 13.1804 +        if (sweepsize-addr>=size) {
 13.1805 +          address=sizeof(cell)*addr;    /* fitting range found, set it */
 13.1806 +          glb_incr=0;
 13.1807 +        } /* if */
 13.1808 +      } /* if */
 13.1809 +    } else {
 13.1810 +      address=sizeof(cell)*glb_declared;
 13.1811 +      glb_incr=(int)size;
 13.1812 +    } /* if */
 13.1813 +    if (address==sizeof(cell)*glb_declared) {
 13.1814 +      dumplits();       /* dump the literal queue */
 13.1815 +      dumpzero((int)size-litidx);
 13.1816 +    } /* if */
 13.1817 +    litidx=0;
 13.1818 +    if (sym==NULL) {    /* define only if not yet defined */
 13.1819 +      sym=addvariable(name,address,ident,sGLOBAL,tag,dim,numdim,idxtag);
 13.1820 +      if (sc_curstates>0)
 13.1821 +        attachstatelist(sym,sc_curstates);
 13.1822 +    } else {            /* if declared but not yet defined, adjust the variable's address */
 13.1823 +      assert(sym->states==NULL && sc_curstates==0
 13.1824 +             || sym->states->next!=NULL && sym->states->next->index==sc_curstates && sym->states->next->next==NULL);
 13.1825 +      sym->addr=address;
 13.1826 +      sym->codeaddr=code_idx;
 13.1827 +      sym->usage|=uDEFINE;
 13.1828 +    } /* if */
 13.1829 +    assert(sym!=NULL);
 13.1830 +    sc_curstates=0;
 13.1831 +    if (ispublic)
 13.1832 +      sym->usage|=uPUBLIC;
 13.1833 +    if (fconst)
 13.1834 +      sym->usage|=uCONST;
 13.1835 +    if (fstock)
 13.1836 +      sym->usage|=uSTOCK;
 13.1837 +    if (fstatic)
 13.1838 +      sym->fnumber=filenum;
 13.1839 +    sc_attachdocumentation(sym);/* attach any documenation to the variable */
 13.1840 +    if (sc_status==statSKIP) {
 13.1841 +      sc_status=statWRITE;
 13.1842 +      code_idx=cidx;
 13.1843 +      assert(glb_declared==glbdecl);
 13.1844 +    } else {
 13.1845 +      glb_declared+=glb_incr;   /* add total number of cells (if added to the end) */
 13.1846 +    } /* if */
 13.1847 +  } while (matchtoken(',')); /* enddo */   /* more? */
 13.1848 +  needtoken(tTERM);    /* if not comma, must be semicolumn */
 13.1849 +}
 13.1850 +
 13.1851 +/*  declloc     - declare local symbols
 13.1852 + *
 13.1853 + *  Declare local (automatic) variables. Since these variables are relative
 13.1854 + *  to the STACK, there is no switch to the DATA segment. These variables
 13.1855 + *  cannot be initialized either.
 13.1856 + *
 13.1857 + *  global references: declared   (altered)
 13.1858 + *                     funcstatus (referred to only)
 13.1859 + */
 13.1860 +static int declloc(int fstatic)
 13.1861 +{
 13.1862 +  int ident,tag;
 13.1863 +  int idxtag[sDIMEN_MAX];
 13.1864 +  char name[sNAMEMAX+1];
 13.1865 +  symbol *sym;
 13.1866 +  constvalue *enumroot;
 13.1867 +  cell val,size;
 13.1868 +  char *str;
 13.1869 +  value lval = {0};
 13.1870 +  int cur_lit=0;
 13.1871 +  int dim[sDIMEN_MAX];
 13.1872 +  int numdim;
 13.1873 +  int fconst;
 13.1874 +  int staging_start;
 13.1875 +
 13.1876 +  fconst=matchtoken(tCONST);
 13.1877 +  do {
 13.1878 +    ident=iVARIABLE;
 13.1879 +    size=1;
 13.1880 +    numdim=0;                           /* no dimensions */
 13.1881 +    tag=pc_addtag(NULL);
 13.1882 +    if (lex(&val,&str)!=tSYMBOL)        /* read in (new) token */
 13.1883 +      error(20,str);                    /* invalid symbol name */
 13.1884 +    assert(strlen(str)<=sNAMEMAX);
 13.1885 +    strcpy(name,str);                   /* save symbol name */
 13.1886 +    if (name[0]==PUBLIC_CHAR)
 13.1887 +      error(56,name);                   /* local variables cannot be public */
 13.1888 +    /* Note: block locals may be named identical to locals at higher
 13.1889 +     * compound blocks (as with standard C); so we must check (and add)
 13.1890 +     * the "nesting level" of local variables to verify the
 13.1891 +     * multi-definition of symbols.
 13.1892 +     */
 13.1893 +    if ((sym=findloc(name))!=NULL && sym->compound==nestlevel)
 13.1894 +      error(21,name);                   /* symbol already defined */
 13.1895 +    /* Although valid, a local variable whose name is equal to that
 13.1896 +     * of a global variable or to that of a local variable at a lower
 13.1897 +     * level might indicate a bug.
 13.1898 +     */
 13.1899 +    if ((sym=findloc(name))!=NULL && sym->compound!=nestlevel || findglb(name,sGLOBAL)!=NULL)
 13.1900 +      error(219,name);                  /* variable shadows another symbol */
 13.1901 +    while (matchtoken('[')){
 13.1902 +      ident=iARRAY;
 13.1903 +      if (numdim == sDIMEN_MAX) {
 13.1904 +        error(53);                      /* exceeding maximum number of dimensions */
 13.1905 +        return ident;
 13.1906 +      } /* if */
 13.1907 +      size=needsub(&idxtag[numdim],&enumroot); /* get size; size==0 for "var[]" */
 13.1908 +      #if INT_MAX < LONG_MAX
 13.1909 +        if (size > INT_MAX)
 13.1910 +          error(105);                   /* overflow, exceeding capacity */
 13.1911 +      #endif
 13.1912 +      dim[numdim++]=(int)size;
 13.1913 +    } /* while */
 13.1914 +    if (getstates(name))
 13.1915 +      error(88,name);           /* local variables may not have states */
 13.1916 +    if (ident==iARRAY || fstatic) {
 13.1917 +      if (sc_alignnext) {
 13.1918 +        aligndata(sc_dataalign);
 13.1919 +        sc_alignnext=FALSE;
 13.1920 +      } /* if */
 13.1921 +      cur_lit=litidx;           /* save current index in the literal table */
 13.1922 +      initials(ident,tag,&size,dim,numdim,enumroot);
 13.1923 +      if (size==0)
 13.1924 +        return ident;           /* error message already given */
 13.1925 +      if (numdim==1)
 13.1926 +        dim[0]=(int)size;
 13.1927 +    } /* if */
 13.1928 +    /* reserve memory (on the stack) for the variable */
 13.1929 +    if (fstatic) {
 13.1930 +      /* write zeros for uninitialized fields */
 13.1931 +      while (litidx<cur_lit+size)
 13.1932 +        litadd(0);
 13.1933 +      sym=addvariable(name,(cur_lit+glb_declared)*sizeof(cell),ident,sSTATIC,
 13.1934 +                      tag,dim,numdim,idxtag);
 13.1935 +    } else {
 13.1936 +      declared+=(int)size;      /* variables are put on stack, adjust "declared" */
 13.1937 +      sym=addvariable(name,-declared*sizeof(cell),ident,sLOCAL,tag,
 13.1938 +                      dim,numdim,idxtag);
 13.1939 +      if (ident==iVARIABLE) {
 13.1940 +        assert(!staging);
 13.1941 +        stgset(TRUE);           /* start stage-buffering */
 13.1942 +        assert(stgidx==0);
 13.1943 +        staging_start=stgidx;
 13.1944 +      } /* if */
 13.1945 +      markexpr(sLDECL,name,-declared*sizeof(cell)); /* mark for better optimization */
 13.1946 +      modstk(-(int)size*sizeof(cell));
 13.1947 +      assert(curfunc!=NULL);
 13.1948 +      assert((curfunc->usage & uNATIVE)==0);
 13.1949 +      if (curfunc->x.stacksize<declared+1)
 13.1950 +        curfunc->x.stacksize=declared+1;  /* +1 for PROC opcode */
 13.1951 +    } /* if */
 13.1952 +    /* now that we have reserved memory for the variable, we can proceed
 13.1953 +     * to initialize it */
 13.1954 +    assert(sym!=NULL);          /* we declared it, it must be there */
 13.1955 +    sym->compound=nestlevel;    /* for multiple declaration/shadowing check */
 13.1956 +    if (fconst)
 13.1957 +      sym->usage|=uCONST;
 13.1958 +    if (!fstatic) {             /* static variables already initialized */
 13.1959 +      if (ident==iVARIABLE) {
 13.1960 +        /* simple variable, also supports initialization */
 13.1961 +        int ctag = tag;         /* set to "tag" by default */
 13.1962 +        int explicit_init=FALSE;/* is the variable explicitly initialized? */
 13.1963 +        if (matchtoken('=')) {
 13.1964 +          doexpr(FALSE,FALSE,FALSE,FALSE,&ctag,NULL,TRUE);
 13.1965 +          explicit_init=TRUE;
 13.1966 +        } else {
 13.1967 +          ldconst(0,sPRI);      /* uninitialized variable, set to zero */
 13.1968 +        } /* if */
 13.1969 +        /* now try to save the value (still in PRI) in the variable */
 13.1970 +        lval.sym=sym;
 13.1971 +        lval.ident=iVARIABLE;
 13.1972 +        lval.constval=0;
 13.1973 +        lval.tag=tag;
 13.1974 +        check_userop(NULL,ctag,lval.tag,2,NULL,&ctag);
 13.1975 +        store(&lval);
 13.1976 +        markexpr(sEXPR,NULL,0); /* full expression ends after the store */
 13.1977 +        assert(staging);        /* end staging phase (optimize expression) */
 13.1978 +        stgout(staging_start);
 13.1979 +        stgset(FALSE);
 13.1980 +        if (!matchtag(tag,ctag,TRUE))
 13.1981 +          error(213);           /* tag mismatch */
 13.1982 +        /* if the variable was not explicitly initialized, reset the
 13.1983 +         * "uWRITTEN" flag that store() set */
 13.1984 +        if (!explicit_init)
 13.1985 +          sym->usage &= ~uWRITTEN;
 13.1986 +      } else {
 13.1987 +        /* an array */
 13.1988 +        assert(cur_lit>=0 && cur_lit<=litidx && litidx<=litmax);
 13.1989 +        assert(size>0 && size>=sym->dim.array.length);
 13.1990 +        assert(numdim>1 || size==sym->dim.array.length);
 13.1991 +        /* final literal values that are zero make no sense to put in the literal
 13.1992 +         * pool, because values get zero-initialized anyway; we check for this,
 13.1993 +         * because users often explicitly initialize strings to ""
 13.1994 +         */
 13.1995 +        while (litidx>cur_lit && litq[litidx-1]==0)
 13.1996 +          litidx--;
 13.1997 +        /* if the array is not completely filled, set all values to zero first */
 13.1998 +        if (litidx-cur_lit<size && (ucell)size<CELL_MAX)
 13.1999 +          fillarray(sym,size*sizeof(cell),0);
 13.2000 +        if (cur_lit<litidx) {
 13.2001 +          /* check whether the complete array is set to a single value; if
 13.2002 +           * it is, more compact code can be generated */
 13.2003 +          cell first=litq[cur_lit];
 13.2004 +          int i;
 13.2005 +          for (i=cur_lit; i<litidx && litq[i]==first; i++)
 13.2006 +            /* nothing */;
 13.2007 +          if (i==litidx) {
 13.2008 +            /* all values are the same */
 13.2009 +            fillarray(sym,(litidx-cur_lit)*sizeof(cell),first);
 13.2010 +            litidx=cur_lit;     /* reset literal table */
 13.2011 +          } else {
 13.2012 +            /* copy the literals to the array */
 13.2013 +            ldconst((cur_lit+glb_declared)*sizeof(cell),sPRI);
 13.2014 +            copyarray(sym,(litidx-cur_lit)*sizeof(cell));
 13.2015 +          } /* if */
 13.2016 +        } /* if */
 13.2017 +      } /* if */
 13.2018 +    } /* if */
 13.2019 +  } while (matchtoken(',')); /* enddo */   /* more? */
 13.2020 +  needtoken(tTERM);    /* if not comma, must be semicolumn */
 13.2021 +  return ident;
 13.2022 +}
 13.2023 +
 13.2024 +/* this function returns the maximum value for a cell in case of an error
 13.2025 + * (invalid dimension).
 13.2026 + */
 13.2027 +static cell calc_arraysize(int dim[],int numdim,int cur)
 13.2028 +{
 13.2029 +  cell subsize;
 13.2030 +  ucell newsize;
 13.2031 +
 13.2032 +  /* the return value is in cells, not bytes */
 13.2033 +  assert(cur>=0 && cur<=numdim);
 13.2034 +  if (cur==numdim)
 13.2035 +    return 0;
 13.2036 +  subsize=calc_arraysize(dim,numdim,cur+1);
 13.2037 +  newsize=dim[cur]+dim[cur]*subsize;
 13.2038 +  if ((ucell)subsize>=CELL_MAX || newsize>=CELL_MAX || newsize<(ucell)subsize
 13.2039 +      || newsize*sizeof(cell)>=CELL_MAX)
 13.2040 +    return CELL_MAX;
 13.2041 +  return newsize;
 13.2042 +}
 13.2043 +
 13.2044 +static cell adjust_indirectiontables(int dim[],int numdim,int cur,cell increment,
 13.2045 +                                     int startlit,constvalue *lastdim,int *skipdim)
 13.2046 +{
 13.2047 +static int base;
 13.2048 +  int d;
 13.2049 +  cell accum;
 13.2050 +
 13.2051 +  assert(cur>=0 && cur<numdim);
 13.2052 +  assert(increment>=0);
 13.2053 +  assert(cur>0 && startlit==-1 || startlit>=0 && startlit<=litidx);
 13.2054 +  if (cur==0)
 13.2055 +    base=startlit;
 13.2056 +  if (cur==numdim-1)
 13.2057 +    return 0;
 13.2058 +  /* 2 or more dimensions left, fill in an indirection vector */
 13.2059 +  assert(dim[cur]>0);
 13.2060 +  if (dim[cur+1]>0) {
 13.2061 +    for (d=0; d<dim[cur]; d++)
 13.2062 +      litq[base++]=(dim[cur]+d*(dim[cur+1]-1)+increment) * sizeof(cell);
 13.2063 +    accum=dim[cur]*(dim[cur+1]-1);
 13.2064 +  } else {
 13.2065 +    /* final dimension is variable length */
 13.2066 +    constvalue *ld;
 13.2067 +    assert(dim[cur+1]==0);
 13.2068 +    assert(lastdim!=NULL);
 13.2069 +    assert(skipdim!=NULL);
 13.2070 +    accum=0;
 13.2071 +    /* skip the final dimension sizes for all earlier major dimensions */
 13.2072 +    for (d=0,ld=lastdim->next; d<*skipdim; d++,ld=ld->next) {
 13.2073 +      assert(ld!=NULL);
 13.2074 +    } /* for */
 13.2075 +    for (d=0; d<dim[cur]; d++) {
 13.2076 +      assert(ld!=NULL);
 13.2077 +      assert(strtol(ld->name,NULL,16)==d);
 13.2078 +      litq[base++]=(dim[cur]+accum+increment) * sizeof(cell);
 13.2079 +      accum+=ld->value-1;
 13.2080 +      *skipdim+=1;
 13.2081 +      ld=ld->next;
 13.2082 +    } /* for */
 13.2083 +  } /* if */
 13.2084 +  /* create the indirection tables for the lower level */
 13.2085 +  if (cur+2<numdim) {   /* are there at least 2 dimensions below this one? */
 13.2086 +    increment+=(dim[cur]-1)*dim[cur+1]; /* this many indirection tables follow */
 13.2087 +    for (d=0; d<dim[cur]; d++)
 13.2088 +      increment+=adjust_indirectiontables(dim,numdim,cur+1,increment,-1,lastdim,skipdim);
 13.2089 +  } /* if */
 13.2090 +  return accum;
 13.2091 +}
 13.2092 +
 13.2093 +/*  initials
 13.2094 + *
 13.2095 + *  Initialize global objects and local arrays.
 13.2096 + *    size==array cells (count), if 0 on input, the routine counts the number of elements
 13.2097 + *    tag==required tagname id (not the returned tag)
 13.2098 + *
 13.2099 + *  Global references: litidx (altered)
 13.2100 + */
 13.2101 +static void initials(int ident,int tag,cell *size,int dim[],int numdim,
 13.2102 +                     constvalue *enumroot)
 13.2103 +{
 13.2104 +  int ctag;
 13.2105 +  cell tablesize;
 13.2106 +  int curlit=litidx;
 13.2107 +  int err=0;
 13.2108 +
 13.2109 +  if (!matchtoken('=')) {
 13.2110 +    assert(ident!=iARRAY || numdim>0);
 13.2111 +    if (ident==iARRAY && dim[numdim-1]==0) {
 13.2112 +      /* declared as "myvar[];" which is senseless (note: this *does* make
 13.2113 +       * sense in the case of a iREFARRAY, which is a function parameter)
 13.2114 +       */
 13.2115 +      error(9);         /* array has zero length -> invalid size */
 13.2116 +    } /* if */
 13.2117 +    if (ident==iARRAY) {
 13.2118 +      assert(numdim>0 && numdim<=sDIMEN_MAX);
 13.2119 +      *size=calc_arraysize(dim,numdim,0);
 13.2120 +      if (*size==(cell)CELL_MAX) {
 13.2121 +        error(9);       /* array is too big -> invalid size */
 13.2122 +        return;
 13.2123 +      } /* if */
 13.2124 +      /* first reserve space for the indirection vectors of the array, then
 13.2125 +       * adjust it to contain the proper values
 13.2126 +       * (do not use dumpzero(), as it bypasses the literal queue)
 13.2127 +       */
 13.2128 +      for (tablesize=calc_arraysize(dim,numdim-1,0); tablesize>0; tablesize--)
 13.2129 +        litadd(0);
 13.2130 +      if (dim[numdim-1]!=0)     /* error 9 has already been given */
 13.2131 +        adjust_indirectiontables(dim,numdim,0,0,curlit,NULL,NULL);
 13.2132 +    } /* if */
 13.2133 +    return;
 13.2134 +  } /* if */
 13.2135 +
 13.2136 +  if (ident==iVARIABLE) {
 13.2137 +    assert(*size==1);
 13.2138 +    init(ident,&ctag,NULL);
 13.2139 +    if (!matchtag(tag,ctag,TRUE))
 13.2140 +      error(213);       /* tag mismatch */
 13.2141 +  } else {
 13.2142 +    assert(numdim>0);
 13.2143 +    if (numdim==1) {
 13.2144 +      *size=initvector(ident,tag,dim[0],FALSE,enumroot,NULL);
 13.2145 +    } else {
 13.2146 +      int errorfound=FALSE;
 13.2147 +      int counteddim[sDIMEN_MAX];
 13.2148 +      int idx;
 13.2149 +      constvalue lastdim={NULL,"",0,0};     /* sizes of the final dimension */
 13.2150 +      int skipdim=0;
 13.2151 +
 13.2152 +      if (dim[numdim-1]!=0)
 13.2153 +        *size=calc_arraysize(dim,numdim,0); /* calc. full size, if known */
 13.2154 +      /* already reserve space for the indirection tables (for an array with
 13.2155 +       * known dimensions)
 13.2156 +       * (do not use dumpzero(), as it bypasses the literal queue)
 13.2157 +       */
 13.2158 +      for (tablesize=calc_arraysize(dim,numdim-1,0); tablesize>0; tablesize--)
 13.2159 +        litadd(0);
 13.2160 +      /* now initialize the sub-arrays */
 13.2161 +      memset(counteddim,0,sizeof counteddim);
 13.2162 +      initarray(ident,tag,dim,numdim,0,curlit,counteddim,&lastdim,enumroot,&errorfound);
 13.2163 +      /* check the specified array dimensions with the initialler counts */
 13.2164 +      for (idx=0; idx<numdim-1; idx++) {
 13.2165 +        if (dim[idx]==0) {
 13.2166 +          dim[idx]=counteddim[idx];
 13.2167 +        } else if (counteddim[idx]<dim[idx]) {
 13.2168 +          error(52);            /* array is not fully initialized */
 13.2169 +          err++;
 13.2170 +        } else if (counteddim[idx]>dim[idx]) {
 13.2171 +          error(18);            /* initialization data exceeds declared size */
 13.2172 +          err++;
 13.2173 +        } /* if */
 13.2174 +      } /* for */
 13.2175 +      /* after all arrays have been initalized, we know the (major) dimensions
 13.2176 +       * of the array and we can properly adjust the indirection vectors
 13.2177 +       */
 13.2178 +      if (err==0)
 13.2179 +        adjust_indirectiontables(dim,numdim,0,0,curlit,&lastdim,&skipdim);
 13.2180 +      delete_consttable(&lastdim);  /* clear list of minor dimension sizes */
 13.2181 +    } /* if */
 13.2182 +  } /* if */
 13.2183 +
 13.2184 +  if (*size==0)
 13.2185 +    *size=litidx-curlit;        /* number of elements defined */
 13.2186 +}
 13.2187 +
 13.2188 +static cell initarray(int ident,int tag,int dim[],int numdim,int cur,
 13.2189 +                      int startlit,int counteddim[],constvalue *lastdim,
 13.2190 +                      constvalue *enumroot,int *errorfound)
 13.2191 +{
 13.2192 +  cell dsize,totalsize;
 13.2193 +  int idx,abortparse;
 13.2194 +
 13.2195 +  assert(cur>=0 && cur<numdim);
 13.2196 +  assert(startlit>=0);
 13.2197 +  assert(cur+2<=numdim);/* there must be 2 dimensions or more to do */
 13.2198 +  assert(errorfound!=NULL && *errorfound==FALSE);
 13.2199 +  totalsize=0;
 13.2200 +  needtoken('{');
 13.2201 +  for (idx=0,abortparse=FALSE; !abortparse; idx++) {
 13.2202 +    /* In case the major dimension is zero, we need to store the offset
 13.2203 +     * to the newly detected sub-array into the indirection table; i.e.
 13.2204 +     * this table needs to be expanded and updated.
 13.2205 +     * In the current design, the indirection vectors for a multi-dimensional
 13.2206 +     * array are adjusted after parsing all initiallers. Hence, it is only
 13.2207 +     * necessary at this point to reserve space for an extra cell in the
 13.2208 +     * indirection vector.
 13.2209 +     */
 13.2210 +    if (dim[cur]==0) {
 13.2211 +      litinsert(0,startlit);
 13.2212 +    } else if (idx>=dim[cur]) {
 13.2213 +      error(18);            /* initialization data exceeds array size */
 13.2214 +      break;
 13.2215 +    } /* if */
 13.2216 +    if (cur+2<numdim) {
 13.2217 +      dsize=initarray(ident,tag,dim,numdim,cur+1,startlit,counteddim,
 13.2218 +                      lastdim,enumroot,errorfound);
 13.2219 +    } else {
 13.2220 +      dsize=initvector(ident,tag,dim[cur+1],TRUE,enumroot,errorfound);
 13.2221 +      /* The final dimension may be variable length. We need to keep the
 13.2222 +       * lengths of the final dimensions in order to set the indirection
 13.2223 +       * vectors for the next-to-last dimension.
 13.2224 +       */
 13.2225 +      append_constval(lastdim,itoh(idx),dsize,0);
 13.2226 +    } /* if */
 13.2227 +    totalsize+=dsize;
 13.2228 +    if (*errorfound || !matchtoken(','))
 13.2229 +      abortparse=TRUE;
 13.2230 +  } /* for */
 13.2231 +  needtoken('}');
 13.2232 +  assert(counteddim!=NULL);
 13.2233 +  if (counteddim[cur]>0) {
 13.2234 +    if (idx<counteddim[cur])
 13.2235 +      error(52);                /* array is not fully initialized */
 13.2236 +    else if (idx>counteddim[cur])
 13.2237 +      error(18);                /* initialization data exceeds declared size */
 13.2238 +  } /* if */
 13.2239 +  counteddim[cur]=idx;
 13.2240 +
 13.2241 +  return totalsize+dim[cur];    /* size of sub-arrays + indirection vector */
 13.2242 +}
 13.2243 +
 13.2244 +/*  initvector
 13.2245 + *  Initialize a single dimensional array
 13.2246 + */
 13.2247 +static cell initvector(int ident,int tag,cell size,int fillzero,
 13.2248 +                       constvalue *enumroot,int *errorfound)
 13.2249 +{
 13.2250 +  cell prev1=0,prev2=0;
 13.2251 +  int ellips=FALSE;
 13.2252 +  int curlit=litidx;
 13.2253 +  int rtag,ctag;
 13.2254 +
 13.2255 +  assert(ident==iARRAY || ident==iREFARRAY);
 13.2256 +  if (matchtoken('{')) {
 13.2257 +    constvalue *enumfield=(enumroot!=NULL) ? enumroot->next : NULL;
 13.2258 +    do {
 13.2259 +      int fieldlit=litidx;
 13.2260 +      int matchbrace,i;
 13.2261 +      if (matchtoken('}')) {    /* to allow for trailing ',' after the initialization */
 13.2262 +        lexpush();
 13.2263 +        break;
 13.2264 +      } /* if */
 13.2265 +      if ((ellips=matchtoken(tELLIPS))!=0)
 13.2266 +        break;
 13.2267 +      /* for enumeration fields, allow another level of braces ("{...}") */
 13.2268 +      matchbrace=0;             /* preset */
 13.2269 +      ellips=0;
 13.2270 +      if (enumfield!=NULL)
 13.2271 +        matchbrace=matchtoken('{');
 13.2272 +      for ( ;; ) {
 13.2273 +        prev2=prev1;
 13.2274 +        prev1=init(ident,&ctag,errorfound);
 13.2275 +        if (!matchbrace)
 13.2276 +          break;
 13.2277 +        if ((ellips=matchtoken(tELLIPS))!=0)
 13.2278 +          break;
 13.2279 +        if (!matchtoken(',')) {
 13.2280 +          needtoken('}');
 13.2281 +          break;
 13.2282 +        } /* for */
 13.2283 +      } /* for */
 13.2284 +      /* if this array is based on an enumeration, fill the "field" up with
 13.2285 +       * zeros, and toggle the tag
 13.2286 +       */
 13.2287 +      if (enumroot!=NULL && enumfield==NULL)
 13.2288 +        error(227);             /* more initiallers than enum fields */
 13.2289 +      rtag=tag;                 /* preset, may be overridden by enum field tag */
 13.2290 +      if (enumfield!=NULL) {
 13.2291 +        cell step;
 13.2292 +        int cmptag=enumfield->index;
 13.2293 +        symbol *symfield=findconst(enumfield->name,&cmptag);
 13.2294 +        if (cmptag>1)
 13.2295 +          error(91,enumfield->name); /* ambiguous constant, needs tag override */
 13.2296 +        assert(symfield!=NULL);
 13.2297 +        assert(fieldlit<litidx);
 13.2298 +        if (litidx-fieldlit>symfield->dim.array.length)
 13.2299 +          error(228);           /* length of initialler exceeds size of the enum field */
 13.2300 +        if (ellips) {
 13.2301 +          step=prev1-prev2;
 13.2302 +        } else {
 13.2303 +          step=0;
 13.2304 +          prev1=0;
 13.2305 +        } /* if */
 13.2306 +        for (i=litidx-fieldlit; i<symfield->dim.array.length; i++) {
 13.2307 +          prev1+=step;
 13.2308 +          litadd(prev1);
 13.2309 +        } /* for */
 13.2310 +        rtag=symfield->x.tags.index;  /* set the expected tag to the index tag */
 13.2311 +        enumfield=enumfield->next;
 13.2312 +      } /* if */
 13.2313 +      if (!matchtag(rtag,ctag,TRUE))
 13.2314 +        error(213);             /* tag mismatch */
 13.2315 +    } while (matchtoken(',')); /* do */
 13.2316 +    needtoken('}');
 13.2317 +  } else {
 13.2318 +    init(ident,&ctag,errorfound);
 13.2319 +    if (!matchtag(tag,ctag,TRUE))
 13.2320 +      error(213);               /* tagname mismatch */
 13.2321 +  } /* if */
 13.2322 +  /* fill up the literal queue with a series */
 13.2323 +  if (ellips) {
 13.2324 +    cell step=((litidx-curlit)==1) ? (cell)0 : prev1-prev2;
 13.2325 +    if (size==0 || (litidx-curlit)==0)
 13.2326 +      error(41);                /* invalid ellipsis, array size unknown */
 13.2327 +    else if ((litidx-curlit)==(int)size)
 13.2328 +      error(18);                /* initialisation data exceeds declared size */
 13.2329 +    while ((litidx-curlit)<(int)size) {
 13.2330 +      prev1+=step;
 13.2331 +      litadd(prev1);
 13.2332 +    } /* while */
 13.2333 +  } /* if */
 13.2334 +  if (fillzero && size>0) {
 13.2335 +    while ((litidx-curlit)<(int)size)
 13.2336 +      litadd(0);
 13.2337 +  } /* if */
 13.2338 +  if (size==0) {
 13.2339 +    size=litidx-curlit;                 /* number of elements defined */
 13.2340 +  } else if (litidx-curlit>(int)size) { /* e.g. "myvar[3]={1,2,3,4};" */
 13.2341 +    error(18);                  /* initialisation data exceeds declared size */
 13.2342 +    litidx=(int)size+curlit;    /* avoid overflow in memory moves */
 13.2343 +  } /* if */
 13.2344 +  return size;
 13.2345 +}
 13.2346 +
 13.2347 +/*  init
 13.2348 + *
 13.2349 + *  Evaluate one initializer.
 13.2350 + */
 13.2351 +static cell init(int ident,int *tag,int *errorfound)
 13.2352 +{
 13.2353 +  cell i = 0;
 13.2354 +
 13.2355 +  if (matchtoken(tSTRING)){
 13.2356 +    /* lex() automatically stores strings in the literal table (and
 13.2357 +     * increases "litidx") */
 13.2358 +    if (ident==iVARIABLE) {
 13.2359 +      error(6);         /* must be assigned to an array */
 13.2360 +      litidx=1;         /* reset literal queue */
 13.2361 +    } /* if */
 13.2362 +    *tag=0;
 13.2363 +  } else if (constexpr(&i,tag,NULL)){
 13.2364 +    litadd(i);          /* store expression result in literal table */
 13.2365 +  } else {
 13.2366 +    if (errorfound!=NULL)
 13.2367 +      *errorfound=TRUE;
 13.2368 +  } /* if */
 13.2369 +  return i;
 13.2370 +}
 13.2371 +
 13.2372 +/*  needsub
 13.2373 + *
 13.2374 + *  Get required array size
 13.2375 + */
 13.2376 +static cell needsub(int *tag,constvalue **enumroot)
 13.2377 +{
 13.2378 +  cell val;
 13.2379 +  symbol *sym;
 13.2380 +
 13.2381 +  assert(tag!=NULL);
 13.2382 +  *tag=0;
 13.2383 +  if (enumroot!=NULL)
 13.2384 +    *enumroot=NULL;         /* preset */
 13.2385 +  if (matchtoken(']'))      /* we have already seen "[" */
 13.2386 +    return 0;               /* zero size (like "char msg[]") */
 13.2387 +
 13.2388 +  constexpr(&val,tag,&sym); /* get value (must be constant expression) */
 13.2389 +  if (val<0) {
 13.2390 +    error(9);               /* negative array size is invalid; assumed zero */
 13.2391 +    val=0;
 13.2392 +  } /* if */
 13.2393 +  needtoken(']');
 13.2394 +
 13.2395 +  if (enumroot!=NULL) {
 13.2396 +    /* get the field list for an enumeration */
 13.2397 +    assert(*enumroot==NULL);/* should have been preset */
 13.2398 +    assert(sym==NULL || sym->ident==iCONSTEXPR);
 13.2399 +    if (sym!=NULL && (sym->usage & uENUMROOT)==uENUMROOT) {
 13.2400 +      assert(sym->dim.enumlist!=NULL);
 13.2401 +      *enumroot=sym->dim.enumlist;
 13.2402 +    } /* if */
 13.2403 +  } /* if */
 13.2404 +
 13.2405 +  return val;               /* return array size */
 13.2406 +}
 13.2407 +
 13.2408 +/*  decl_const  - declare a single constant
 13.2409 + *
 13.2410 + */
 13.2411 +static void decl_const(int vclass)
 13.2412 +{
 13.2413 +  char constname[sNAMEMAX+1];
 13.2414 +  cell val;
 13.2415 +  char *str;
 13.2416 +  int tag,exprtag;
 13.2417 +  int symbolline;
 13.2418 +  symbol *sym;
 13.2419 +
 13.2420 +  insert_docstring_separator(); /* see comment in newfunc() */
 13.2421 +  tag=pc_addtag(NULL);
 13.2422 +  if (lex(&val,&str)!=tSYMBOL)  /* read in (new) token */
 13.2423 +    error(20,str);              /* invalid symbol name */
 13.2424 +  symbolline=fline;             /* save line where symbol was found */
 13.2425 +  strcpy(constname,str);        /* save symbol name */
 13.2426 +  needtoken('=');
 13.2427 +  constexpr(&val,&exprtag,NULL);/* get value */
 13.2428 +  needtoken(tTERM);
 13.2429 +  /* add_constant() checks for duplicate definitions */
 13.2430 +  if (!matchtag(tag,exprtag,FALSE)) {
 13.2431 +    /* temporarily reset the line number to where the symbol was defined */
 13.2432 +    int orgfline=fline;
 13.2433 +    fline=symbolline;
 13.2434 +    error(213);                 /* tagname mismatch */
 13.2435 +    fline=orgfline;
 13.2436 +  } /* if */
 13.2437 +  sym=add_constant(constname,val,vclass,tag);
 13.2438 +  if (sym!=NULL)
 13.2439 +    sc_attachdocumentation(sym);/* attach any documenation to the function */
 13.2440 +}
 13.2441 +
 13.2442 +/*  decl_enum   - declare enumerated constants
 13.2443 + *
 13.2444 + */
 13.2445 +static void decl_enum(int vclass)
 13.2446 +{
 13.2447 +  char enumname[sNAMEMAX+1],constname[sNAMEMAX+1];
 13.2448 +  cell val,value,size;
 13.2449 +  char *str;
 13.2450 +  int tag,explicittag;
 13.2451 +  cell increment,multiplier;
 13.2452 +  constvalue *enumroot;
 13.2453 +  symbol *enumsym;
 13.2454 +
 13.2455 +  /* get an explicit tag, if any (we need to remember whether an explicit
 13.2456 +   * tag was passed, even if that explicit tag was "_:", so we cannot call
 13.2457 +   * pc_addtag() here
 13.2458 +   */
 13.2459 +  if (lex(&val,&str)==tLABEL) {
 13.2460 +    tag=pc_addtag(str);
 13.2461 +    explicittag=TRUE;
 13.2462 +  } else {
 13.2463 +    lexpush();
 13.2464 +    tag=0;
 13.2465 +    explicittag=FALSE;
 13.2466 +  } /* if */
 13.2467 +
 13.2468 +  /* get optional enum name (also serves as a tag if no explicit tag was set) */
 13.2469 +  if (lex(&val,&str)==tSYMBOL) {        /* read in (new) token */
 13.2470 +    strcpy(enumname,str);               /* save enum name (last constant) */
 13.2471 +    if (!explicittag)
 13.2472 +      tag=pc_addtag(enumname);
 13.2473 +  } else {
 13.2474 +    lexpush();                          /* analyze again */
 13.2475 +    enumname[0]='\0';
 13.2476 +  } /* if */
 13.2477 +
 13.2478 +  /* get increment and multiplier */
 13.2479 +  increment=1;
 13.2480 +  multiplier=1;
 13.2481 +  if (matchtoken('(')) {
 13.2482 +    if (matchtoken(taADD)) {
 13.2483 +      constexpr(&increment,NULL,NULL);
 13.2484 +    } else if (matchtoken(taMULT)) {
 13.2485 +      constexpr(&multiplier,NULL,NULL);
 13.2486 +    } else if (matchtoken(taSHL)) {
 13.2487 +      constexpr(&val,NULL,NULL);
 13.2488 +      while (val-->0)
 13.2489 +        multiplier*=2;
 13.2490 +    } /* if */
 13.2491 +    needtoken(')');
 13.2492 +  } /* if */
 13.2493 +
 13.2494 +  if (strlen(enumname)>0) {
 13.2495 +    /* already create the root symbol, so the fields can have it as their "parent" */
 13.2496 +    enumsym=add_constant(enumname,0,vclass,tag);
 13.2497 +    if (enumsym!=NULL)
 13.2498 +      enumsym->usage |= uENUMROOT;
 13.2499 +    /* start a new list for the element names */
 13.2500 +    if ((enumroot=(constvalue*)malloc(sizeof(constvalue)))==NULL)
 13.2501 +      error(103);                       /* insufficient memory (fatal error) */
 13.2502 +    memset(enumroot,0,sizeof(constvalue));
 13.2503 +  } else {
 13.2504 +    enumsym=NULL;
 13.2505 +    enumroot=NULL;
 13.2506 +  } /* if */
 13.2507 +
 13.2508 +  needtoken('{');
 13.2509 +  /* go through all constants */
 13.2510 +  value=0;                              /* default starting value */
 13.2511 +  do {
 13.2512 +    int idxtag,fieldtag;
 13.2513 +    symbol *sym;
 13.2514 +    if (matchtoken('}')) {              /* quick exit if '}' follows ',' */
 13.2515 +      lexpush();
 13.2516 +      break;
 13.2517 +    } /* if */
 13.2518 +    idxtag=pc_addtag(NULL);             /* optional explicit item tag */
 13.2519 +    if (needtoken(tSYMBOL)) {           /* read in (new) token */
 13.2520 +      tokeninfo(&val,&str);             /* get the information */
 13.2521 +      strcpy(constname,str);            /* save symbol name */
 13.2522 +    } else {
 13.2523 +      constname[0]='\0';
 13.2524 +    } /* if */
 13.2525 +    size=increment;                     /* default increment of 'val' */
 13.2526 +    fieldtag=0;                         /* default field tag */
 13.2527 +    if (matchtoken('[')) {
 13.2528 +      constexpr(&size,&fieldtag,NULL);  /* get size */
 13.2529 +      needtoken(']');
 13.2530 +    } /* if */
 13.2531 +    if (matchtoken('='))
 13.2532 +      constexpr(&value,NULL,NULL);      /* get value */
 13.2533 +    /* add_constant() checks whether a variable (global or local) or
 13.2534 +     * a constant with the same name already exists
 13.2535 +     */
 13.2536 +    sym=add_constant(constname,value,vclass,tag);
 13.2537 +    if (sym==NULL)
 13.2538 +      continue;                         /* error message already given */
 13.2539 +    /* set the item tag and the item size, for use in indexing arrays */
 13.2540 +    sym->x.tags.index=idxtag;
 13.2541 +    sym->x.tags.field=fieldtag;
 13.2542 +    sym->dim.array.length=size;
 13.2543 +    sym->dim.array.level=0;
 13.2544 +    sym->parent=enumsym;
 13.2545 +    /* add the constant to a separate list as well */
 13.2546 +    if (enumroot!=NULL) {
 13.2547 +      sym->usage |= uENUMFIELD;
 13.2548 +      append_constval(enumroot,constname,value,tag);
 13.2549 +    } /* if */
 13.2550 +    if (multiplier==1)
 13.2551 +      value+=size;
 13.2552 +    else
 13.2553 +      value*=size*multiplier;
 13.2554 +  } while (matchtoken(','));
 13.2555 +  needtoken('}');       /* terminates the constant list */
 13.2556 +  matchtoken(';');      /* eat an optional ; */
 13.2557 +
 13.2558 +  /* set the enum name to the "next" value (typically the last value plus one) */
 13.2559 +  if (enumsym!=NULL) {
 13.2560 +    assert((enumsym->usage & uENUMROOT)!=0);
 13.2561 +    enumsym->addr=value;
 13.2562 +    /* assign the constant list */
 13.2563 +    assert(enumroot!=NULL);
 13.2564 +    enumsym->dim.enumlist=enumroot;
 13.2565 +    sc_attachdocumentation(enumsym);  /* attach any documenation to the enumeration */
 13.2566 +  } /* if */
 13.2567 +}
 13.2568 +
 13.2569 +static int getstates(const char *funcname)
 13.2570 +{
 13.2571 +  char fsaname[sNAMEMAX+1],statename[sNAMEMAX+1];
 13.2572 +  cell val;
 13.2573 +  char *str;
 13.2574 +  constvalue *automaton;
 13.2575 +  constvalue *state;
 13.2576 +  int fsa,islabel;
 13.2577 +  int *list;
 13.2578 +  int count,listsize,state_id;
 13.2579 +
 13.2580 +  if (!matchtoken('<'))
 13.2581 +    return 0;
 13.2582 +  if (matchtoken('>'))
 13.2583 +    return -1;          /* special construct: all other states (fall-back) */
 13.2584 +
 13.2585 +  count=0;
 13.2586 +  listsize=0;
 13.2587 +  list=NULL;
 13.2588 +  fsa=-1;
 13.2589 +
 13.2590 +  do {
 13.2591 +    if (!(islabel=matchtoken(tLABEL)) && !needtoken(tSYMBOL))
 13.2592 +      break;
 13.2593 +    tokeninfo(&val,&str);
 13.2594 +    assert(strlen(str)<sizeof fsaname);
 13.2595 +    strcpy(fsaname,str);  /* assume this is the name of the automaton */
 13.2596 +    if (islabel || matchtoken(':')) {
 13.2597 +      /* token is an automaton name, add the name and get a new token */
 13.2598 +      if (!needtoken(tSYMBOL))
 13.2599 +        break;
 13.2600 +      tokeninfo(&val,&str);
 13.2601 +      assert(strlen(str)<sizeof statename);
 13.2602 +      strcpy(statename,str);
 13.2603 +    } else {
 13.2604 +      /* the token was the state name (part of an anynymous automaton) */
 13.2605 +      assert(strlen(fsaname)<sizeof statename);
 13.2606 +      strcpy(statename,fsaname);
 13.2607 +      fsaname[0]='\0';
 13.2608 +    } /* if */
 13.2609 +    if (fsa<0 || fsaname[0]!='\0') {
 13.2610 +      automaton=automaton_add(fsaname);
 13.2611 +      assert(automaton!=NULL);
 13.2612 +      if (fsa>=0 && automaton->index!=fsa)
 13.2613 +        error(83,funcname); /* multiple automatons for a single function/variable */
 13.2614 +      fsa=automaton->index;
 13.2615 +    } /* if */
 13.2616 +    state=state_add(statename,fsa);
 13.2617 +    /* add this state to the state combination list (it will be attached to the
 13.2618 +     * automaton later) */
 13.2619 +    state_buildlist(&list,&listsize,&count,(int)state->value);
 13.2620 +  } while (matchtoken(','));
 13.2621 +  needtoken('>');
 13.2622 +
 13.2623 +  if (count>0) {
 13.2624 +    assert(automaton!=NULL);
 13.2625 +    assert(fsa>=0);
 13.2626 +    state_id=state_addlist(list,count,fsa);
 13.2627 +    assert(state_id>0);
 13.2628 +  } else {
 13.2629 +    /* error is already given */
 13.2630 +    state_id=0;
 13.2631 +  } /* if */
 13.2632 +  if (list!=NULL)
 13.2633 +    free(list);
 13.2634 +
 13.2635 +  return state_id;
 13.2636 +}
 13.2637 +
 13.2638 +static void attachstatelist(symbol *sym, int state_id)
 13.2639 +{
 13.2640 +  assert(sym!=NULL);
 13.2641 +  if ((sym->usage & uDEFINE)!=0 && (sym->states==NULL || state_id==0))
 13.2642 +    error(21,sym->name); /* function already defined, either without states or the current definition has no states */
 13.2643 +
 13.2644 +  if (state_id!=0) {
 13.2645 +    /* add the state list id */
 13.2646 +    constvalue *stateptr;
 13.2647 +    if (sym->states==NULL) {
 13.2648 +      if ((sym->states=(constvalue*)malloc(sizeof(constvalue)))==NULL)
 13.2649 +        error(103);             /* insufficient memory (fatal error) */
 13.2650 +      memset(sym->states,0,sizeof(constvalue));
 13.2651 +    } /* if */
 13.2652 +    /* see whether the id already exists (add new state only if it does not
 13.2653 +     * yet exist
 13.2654 +     */
 13.2655 +    assert(sym->states!=NULL);
 13.2656 +    for (stateptr=sym->states->next; stateptr!=NULL && stateptr->index!=state_id; stateptr=stateptr->next)
 13.2657 +      /* nothing */;
 13.2658 +    assert(state_id<=SHRT_MAX);
 13.2659 +    if (stateptr==NULL)
 13.2660 +      append_constval(sym->states,"",code_idx,(short)state_id);
 13.2661 +    else if (stateptr->value==0)
 13.2662 +      stateptr->value=code_idx;
 13.2663 +    else
 13.2664 +      error(84,sym->name);
 13.2665 +    /* also check for another conflicting situation: a fallback function
 13.2666 +     * without any states
 13.2667 +     */
 13.2668 +    if (state_id==-1 && sc_status!=statFIRST) {
 13.2669 +      /* in the second round, all states should have been accumulated */
 13.2670 +      assert(sym->states!=NULL);
 13.2671 +      for (stateptr=sym->states->next; stateptr!=NULL && stateptr->index==-1; stateptr=stateptr->next)
 13.2672 +        /* nothing */;
 13.2673 +      if (stateptr==NULL)
 13.2674 +        error(85,sym->name);      /* no states are defined for this function */
 13.2675 +    } /* if */
 13.2676 +  } /* if */
 13.2677 +}
 13.2678 +
 13.2679 +/*
 13.2680 + *  Finds a function in the global symbol table or creates a new entry.
 13.2681 + *  It does some basic processing and error checking.
 13.2682 + */
 13.2683 +SC_FUNC symbol *fetchfunc(char *name,int tag)
 13.2684 +{
 13.2685 +  symbol *sym;
 13.2686 +
 13.2687 +  if ((sym=findglb(name,sGLOBAL))!=0) {   /* already in symbol table? */
 13.2688 +    if (sym->ident!=iFUNCTN) {
 13.2689 +      error(21,name);                     /* yes, but not as a function */
 13.2690 +      return NULL;                        /* make sure the old symbol is not damaged */
 13.2691 +    } else if ((sym->usage & uNATIVE)!=0) {
 13.2692 +      error(21,name);                     /* yes, and it is a native */
 13.2693 +    } /* if */
 13.2694 +    assert(sym->vclass==sGLOBAL);
 13.2695 +    if ((sym->usage & uPROTOTYPED)!=0 && sym->tag!=tag)
 13.2696 +      error(25);                          /* mismatch from earlier prototype */
 13.2697 +    if ((sym->usage & uDEFINE)==0) {
 13.2698 +      /* as long as the function stays undefined, update the address and the tag */
 13.2699 +      if (sym->states==NULL)
 13.2700 +        sym->addr=code_idx;
 13.2701 +      sym->tag=tag;
 13.2702 +    } /* if */
 13.2703 +  } else {
 13.2704 +    /* don't set the "uDEFINE" flag; it may be a prototype */
 13.2705 +    sym=addsym(name,code_idx,iFUNCTN,sGLOBAL,tag,0);
 13.2706 +    assert(sym!=NULL);          /* fatal error 103 must be given on error */
 13.2707 +    /* assume no arguments */
 13.2708 +    sym->dim.arglist=(arginfo*)malloc(1*sizeof(arginfo));
 13.2709 +    sym->dim.arglist[0].ident=0;
 13.2710 +    /* set library ID to NULL (only for native functions) */
 13.2711 +    sym->x.lib=NULL;
 13.2712 +    /* set the required stack size to zero (only for non-native functions) */
 13.2713 +    sym->x.stacksize=1;         /* 1 for PROC opcode */
 13.2714 +  } /* if */
 13.2715 +  if (pc_depricate!=NULL) {
 13.2716 +    assert(sym!=NULL);
 13.2717 +    sym->flags|=flgDEPRICATED;
 13.2718 +    if (sc_status==statWRITE) {
 13.2719 +      if (sym->documentation!=NULL) {
 13.2720 +        free(sym->documentation);
 13.2721 +        sym->documentation=NULL;
 13.2722 +      } /* if */
 13.2723 +      sym->documentation=pc_depricate;
 13.2724 +    } else {
 13.2725 +      free(pc_depricate);
 13.2726 +    } /* if */
 13.2727 +    pc_depricate=NULL;
 13.2728 +  } /* if */
 13.2729 +
 13.2730 +  return sym;
 13.2731 +}
 13.2732 +
 13.2733 +/* This routine adds symbolic information for each argument.
 13.2734 + */
 13.2735 +static void define_args(void)
 13.2736 +{
 13.2737 +  symbol *sym;
 13.2738 +
 13.2739 +  /* At this point, no local variables have been declared. All
 13.2740 +   * local symbols are function arguments.
 13.2741 +   */
 13.2742 +  sym=loctab.next;
 13.2743 +  while (sym!=NULL) {
 13.2744 +    assert(sym->ident!=iLABEL);
 13.2745 +    assert(sym->vclass==sLOCAL);
 13.2746 +    markexpr(sLDECL,sym->name,sym->addr); /* mark for better optimization */
 13.2747 +    sym=sym->next;
 13.2748 +  } /* while */
 13.2749 +}
 13.2750 +
 13.2751 +static int operatorname(char *name)
 13.2752 +{
 13.2753 +  int opertok;
 13.2754 +  char *str;
 13.2755 +  cell val;
 13.2756 +
 13.2757 +  assert(name!=NULL);
 13.2758 +
 13.2759 +  /* check the operator */
 13.2760 +  opertok=lex(&val,&str);
 13.2761 +  switch (opertok) {
 13.2762 +  case '+':
 13.2763 +  case '-':
 13.2764 +  case '*':
 13.2765 +  case '/':
 13.2766 +  case '%':
 13.2767 +  case '>':
 13.2768 +  case '<':
 13.2769 +  case '!':
 13.2770 +  case '~':
 13.2771 +  case '=':
 13.2772 +    name[0]=(char)opertok;
 13.2773 +    name[1]='\0';
 13.2774 +    break;
 13.2775 +  case tINC:
 13.2776 +    strcpy(name,"++");
 13.2777 +    break;
 13.2778 +  case tDEC:
 13.2779 +    strcpy(name,"--");
 13.2780 +    break;
 13.2781 +  case tlEQ:
 13.2782 +    strcpy(name,"==");
 13.2783 +    break;
 13.2784 +  case tlNE:
 13.2785 +    strcpy(name,"!=");
 13.2786 +    break;
 13.2787 +  case tlLE:
 13.2788 +    strcpy(name,"<=");
 13.2789 +    break;
 13.2790 +  case tlGE:
 13.2791 +    strcpy(name,">=");
 13.2792 +    break;
 13.2793 +  default:
 13.2794 +    name[0]='\0';
 13.2795 +    error(7);           /* operator cannot be redefined (or bad operator name) */
 13.2796 +    return 0;
 13.2797 +  } /* switch */
 13.2798 +
 13.2799 +  return opertok;
 13.2800 +}
 13.2801 +
 13.2802 +static int operatoradjust(int opertok,symbol *sym,char *opername,int resulttag)
 13.2803 +{
 13.2804 +  int tags[2]={0,0};
 13.2805 +  int count=0;
 13.2806 +  arginfo *arg;
 13.2807 +  char tmpname[sNAMEMAX+1];
 13.2808 +  symbol *oldsym;
 13.2809 +
 13.2810 +  if (opertok==0)
 13.2811 +    return TRUE;
 13.2812 +
 13.2813 +  assert(sym!=NULL && sym->ident==iFUNCTN && sym->dim.arglist!=NULL);
 13.2814 +  /* count arguments and save (first two) tags */
 13.2815 +  while (arg=&sym->dim.arglist[count], arg->ident!=0) {
 13.2816 +    if (count<2) {
 13.2817 +      if (arg->numtags>1)
 13.2818 +        error(65,count+1);  /* function argument may only have a single tag */
 13.2819 +      else if (arg->numtags==1)
 13.2820 +        tags[count]=arg->tags[0];
 13.2821 +    } /* if */
 13.2822 +    if (opertok=='~' && count==0) {
 13.2823 +      if (arg->ident!=iREFARRAY)
 13.2824 +        error(73,arg->name);/* must be an array argument */
 13.2825 +    } else {
 13.2826 +      if (arg->ident!=iVARIABLE)
 13.2827 +        error(66,arg->name);/* must be non-reference argument */
 13.2828 +    } /* if */
 13.2829 +    if (arg->hasdefault)
 13.2830 +      error(59,arg->name);  /* arguments of an operator may not have a default value */
 13.2831 +    count++;
 13.2832 +  } /* while */
 13.2833 +
 13.2834 +  /* for '!', '++' and '--', count must be 1
 13.2835 +   * for '-', count may be 1 or 2
 13.2836 +   * for '=', count must be 1, and the resulttag is also important
 13.2837 +   * for all other (binary) operators and the special '~' operator, count must be 2
 13.2838 +   */
 13.2839 +  switch (opertok) {
 13.2840 +  case '!':
 13.2841 +  case '=':
 13.2842 +  case tINC:
 13.2843 +  case tDEC:
 13.2844 +    if (count!=1)
 13.2845 +      error(62);      /* number or placement of the operands does not fit the operator */
 13.2846 +    break;
 13.2847 +  case '-':
 13.2848 +    if (count!=1 && count!=2)
 13.2849 +      error(62);      /* number or placement of the operands does not fit the operator */
 13.2850 +    break;
 13.2851 +  default:
 13.2852 +    if (count!=2)
 13.2853 +      error(62);      /* number or placement of the operands does not fit the operator */
 13.2854 +  } /* switch */
 13.2855 +
 13.2856 +  if (tags[0]==0 && (opertok!='=' && tags[1]==0 || opertok=='=' && resulttag==0))
 13.2857 +    error(64);        /* cannot change predefined operators */
 13.2858 +
 13.2859 +  /* change the operator name */
 13.2860 +  assert(strlen(opername)>0);
 13.2861 +  operator_symname(tmpname,opername,tags[0],tags[1],count,resulttag);
 13.2862 +  if ((oldsym=findglb(tmpname,sGLOBAL))!=NULL) {
 13.2863 +    int i;
 13.2864 +    if ((oldsym->usage & uDEFINE)!=0) {
 13.2865 +      char errname[2*sNAMEMAX+16];
 13.2866 +      funcdisplayname(errname,tmpname);
 13.2867 +      error(21,errname);        /* symbol already defined */
 13.2868 +    } /* if */
 13.2869 +    sym->usage|=oldsym->usage;  /* copy flags from the previous definition */
 13.2870 +    for (i=0; i<oldsym->numrefers; i++)
 13.2871 +      if (oldsym->refer[i]!=NULL)
 13.2872 +        refer_symbol(sym,oldsym->refer[i]);
 13.2873 +    delete_symbol(&glbtab,oldsym);
 13.2874 +  } /* if */
 13.2875 +  strcpy(sym->name,tmpname);
 13.2876 +  sym->hash=namehash(sym->name);/* calculate new hash */
 13.2877 +
 13.2878 +  /* operators should return a value, except the '~' operator */
 13.2879 +  if (opertok!='~')
 13.2880 +    sym->usage |= uRETVALUE;
 13.2881 +
 13.2882 +  return TRUE;
 13.2883 +}
 13.2884 +
 13.2885 +static int check_operatortag(int opertok,int resulttag,char *opername)
 13.2886 +{
 13.2887 +  assert(opername!=NULL && strlen(opername)>0);
 13.2888 +  switch (opertok) {
 13.2889 +  case '!':
 13.2890 +  case '<':
 13.2891 +  case '>':
 13.2892 +  case tlEQ:
 13.2893 +  case tlNE:
 13.2894 +  case tlLE:
 13.2895 +  case tlGE:
 13.2896 +    if (resulttag!=pc_addtag("bool")) {
 13.2897 +      error(63,opername,"bool:"); /* operator X requires a "bool:" result tag */
 13.2898 +      return FALSE;
 13.2899 +    } /* if */
 13.2900 +    break;
 13.2901 +  case '~':
 13.2902 +    if (resulttag!=0) {
 13.2903 +      error(63,opername,"_:");    /* operator "~" requires a "_:" result tag */
 13.2904 +      return FALSE;
 13.2905 +    } /* if */
 13.2906 +    break;
 13.2907 +  } /* switch */
 13.2908 +  return TRUE;
 13.2909 +}
 13.2910 +
 13.2911 +static char *tag2str(char *dest,int tag)
 13.2912 +{
 13.2913 +  tag &= TAGMASK;
 13.2914 +  assert(tag>=0);
 13.2915 +  sprintf(dest,"0%x",tag);
 13.2916 +  return isdigit(dest[1]) ? &dest[1] : dest;
 13.2917 +}
 13.2918 +
 13.2919 +SC_FUNC char *operator_symname(char *symname,char *opername,int tag1,int tag2,int numtags,int resulttag)
 13.2920 +{
 13.2921 +  char tagstr1[10], tagstr2[10];
 13.2922 +  int opertok;
 13.2923 +
 13.2924 +  assert(numtags>=1 && numtags<=2);
 13.2925 +  opertok= (opername[1]=='\0') ? opername[0] : 0;
 13.2926 +  if (opertok=='=')
 13.2927 +    sprintf(symname,"%s%s%s",tag2str(tagstr1,resulttag),opername,tag2str(tagstr2,tag1));
 13.2928 +  else if (numtags==1 || opertok=='~')
 13.2929 +    sprintf(symname,"%s%s",opername,tag2str(tagstr1,tag1));
 13.2930 +  else
 13.2931 +    sprintf(symname,"%s%s%s",tag2str(tagstr1,tag1),opername,tag2str(tagstr2,tag2));
 13.2932 +  return symname;
 13.2933 +}
 13.2934 +
 13.2935 +static int parse_funcname(char *fname,int *tag1,int *tag2,char *opname)
 13.2936 +{
 13.2937 +  char *ptr,*name;
 13.2938 +  int unary;
 13.2939 +
 13.2940 +  /* tags are only positive, so if the function name starts with a '-',
 13.2941 +   * the operator is an unary '-' or '--' operator.
 13.2942 +   */
 13.2943 +  if (*fname=='-') {
 13.2944 +    *tag1=0;
 13.2945 +    unary=TRUE;
 13.2946 +    ptr=fname;
 13.2947 +  } else {
 13.2948 +    *tag1=(int)strtol(fname,&ptr,16);
 13.2949 +    unary= ptr==fname;  /* unary operator if it doesn't start with a tag name */
 13.2950 +  } /* if */
 13.2951 +  assert(!unary || *tag1==0);
 13.2952 +  assert(*ptr!='\0');
 13.2953 +  for (name=opname; !isdigit(*ptr); )
 13.2954 +    *name++ = *ptr++;
 13.2955 +  *name='\0';
 13.2956 +  *tag2=(int)strtol(ptr,NULL,16);
 13.2957 +  return unary;
 13.2958 +}
 13.2959 +
 13.2960 +static constvalue *find_tag_byval(int tag)
 13.2961 +{
 13.2962 +  constvalue *tagsym;
 13.2963 +  tagsym=find_constval_byval(&tagname_tab,tag & ~PUBLICTAG);
 13.2964 +  if (tagsym==NULL)
 13.2965 +    tagsym=find_constval_byval(&tagname_tab,tag | PUBLICTAG);
 13.2966 +  return tagsym;
 13.2967 +}
 13.2968 +
 13.2969 +SC_FUNC char *funcdisplayname(char *dest,char *funcname)
 13.2970 +{
 13.2971 +  int tags[2];
 13.2972 +  char opname[10];
 13.2973 +  constvalue *tagsym[2];
 13.2974 +  int unary;
 13.2975 +
 13.2976 +  if (isalpha(*funcname) || *funcname=='_' || *funcname==PUBLIC_CHAR || *funcname=='\0') {
 13.2977 +    if (dest!=funcname)
 13.2978 +      strcpy(dest,funcname);
 13.2979 +    return dest;
 13.2980 +  } /* if */
 13.2981 +
 13.2982 +  unary=parse_funcname(funcname,&tags[0],&tags[1],opname);
 13.2983 +  tagsym[1]=find_tag_byval(tags[1]);
 13.2984 +  assert(tagsym[1]!=NULL);
 13.2985 +  if (unary) {
 13.2986 +    sprintf(dest,"operator%s(%s:)",opname,tagsym[1]->name);
 13.2987 +  } else {
 13.2988 +    tagsym[0]=find_tag_byval(tags[0]);
 13.2989 +    assert(tagsym[0]!=NULL);
 13.2990 +    /* special case: the assignment operator has the return value as the 2nd tag */
 13.2991 +    if (opname[0]=='=' && opname[1]=='\0')
 13.2992 +      sprintf(dest,"%s:operator%s(%s:)",tagsym[0]->name,opname,tagsym[1]->name);
 13.2993 +    else
 13.2994 +      sprintf(dest,"operator%s(%s:,%s:)",opname,tagsym[0]->name,tagsym[1]->name);
 13.2995 +  } /* if */
 13.2996 +  return dest;
 13.2997 +}
 13.2998 +
 13.2999 +static void funcstub(int fnative)
 13.3000 +{
 13.3001 +  int tok,tag,fpublic;
 13.3002 +  char *str;
 13.3003 +  cell val,size;
 13.3004 +  char symbolname[sNAMEMAX+1];
 13.3005 +  int idxtag[sDIMEN_MAX];
 13.3006 +  int dim[sDIMEN_MAX];
 13.3007 +  int numdim;
 13.3008 +  symbol *sym,*sub;
 13.3009 +  int opertok;
 13.3010 +
 13.3011 +  opertok=0;
 13.3012 +  lastst=0;
 13.3013 +  litidx=0;                     /* clear the literal pool */
 13.3014 +  assert(loctab.next==NULL);    /* local symbol table should be empty */
 13.3015 +
 13.3016 +  tag=pc_addtag(NULL);			/* get the tag of the return value */
 13.3017 +  numdim=0;
 13.3018 +  while (matchtoken('[')) {
 13.3019 +    /* the function returns an array, get this tag for the index and the array
 13.3020 +     * dimensions
 13.3021 +     */
 13.3022 +    if (numdim == sDIMEN_MAX) {
 13.3023 +      error(53);                /* exceeding maximum number of dimensions */
 13.3024 +      return;
 13.3025 +    } /* if */
 13.3026 +    size=needsub(&idxtag[numdim],NULL); /* get size; size==0 for "var[]" */
 13.3027 +    if (size==0)
 13.3028 +      error(9);                 /* invalid array size */
 13.3029 +    #if INT_MAX < LONG_MAX
 13.3030 +      if (size > INT_MAX)
 13.3031 +        error(105);             /* overflow, exceeding capacity */
 13.3032 +    #endif
 13.3033 +    dim[numdim++]=(int)size;
 13.3034 +  } /* while */
 13.3035 +
 13.3036 +  tok=lex(&val,&str);
 13.3037 +  fpublic=(tok==tPUBLIC) || (tok==tSYMBOL && str[0]==PUBLIC_CHAR);
 13.3038 +  if (fnative) {
 13.3039 +    if (fpublic || tok==tSTOCK || tok==tSTATIC || tok==tSYMBOL && *str==PUBLIC_CHAR)
 13.3040 +      error(42);                /* invalid combination of class specifiers */
 13.3041 +  } else {
 13.3042 +    if (tok==tPUBLIC || tok==tSTOCK || tok==tSTATIC)
 13.3043 +      tok=lex(&val,&str);
 13.3044 +  } /* if */
 13.3045 +
 13.3046 +  if (tok==tOPERATOR) {
 13.3047 +    opertok=operatorname(symbolname);
 13.3048 +    if (opertok==0)
 13.3049 +      return;                   /* error message already given */
 13.3050 +    check_operatortag(opertok,tag,symbolname);
 13.3051 +  } else {
 13.3052 +    if (tok!=tSYMBOL && freading) {
 13.3053 +      error(10);                /* illegal function or declaration */
 13.3054 +      return;
 13.3055 +    } /* if */
 13.3056 +    strcpy(symbolname,str);
 13.3057 +  } /* if */
 13.3058 +  needtoken('(');               /* only functions may be native/forward */
 13.3059 +
 13.3060 +  sym=fetchfunc(symbolname,tag);/* get a pointer to the function entry */
 13.3061 +  if (sym==NULL)
 13.3062 +    return;
 13.3063 +  if (fnative) {
 13.3064 +    sym->usage=(char)(uNATIVE | uRETVALUE | uDEFINE | (sym->usage & uPROTOTYPED));
 13.3065 +    sym->x.lib=curlibrary;
 13.3066 +  } else if (fpublic) {
 13.3067 +    sym->usage|=uPUBLIC;
 13.3068 +  } /* if */
 13.3069 +  sym->usage|=uFORWARD;
 13.3070 +
 13.3071 +  declargs(sym,FALSE);
 13.3072 +  /* "declargs()" found the ")" */
 13.3073 +  sc_attachdocumentation(sym);  /* attach any documenation to the function */
 13.3074 +  if (!operatoradjust(opertok,sym,symbolname,tag))
 13.3075 +    sym->usage &= ~uDEFINE;
 13.3076 +
 13.3077 +  if (getstates(symbolname)!=0) {
 13.3078 +    if (fnative || opertok!=0)
 13.3079 +      error(82);                /* native functions and operators may not have states */
 13.3080 +    else
 13.3081 +      error(231);               /* ignoring state specifications on forward declarations */
 13.3082 +  } /* if */
 13.3083 +
 13.3084 +  /* for a native operator, also need to specify an "exported" function name;
 13.3085 +   * for a native function, this is optional
 13.3086 +   */
 13.3087 +  if (fnative) {
 13.3088 +    if (opertok!=0) {
 13.3089 +      needtoken('=');
 13.3090 +      lexpush();        /* push back, for matchtoken() to retrieve again */
 13.3091 +    } /* if */
 13.3092 +    if (matchtoken('=')) {
 13.3093 +      /* allow number or symbol */
 13.3094 +      if (matchtoken(tSYMBOL)) {
 13.3095 +        tokeninfo(&val,&str);
 13.3096 +        insert_alias(sym->name,str);
 13.3097 +      } else {
 13.3098 +        constexpr(&val,NULL,NULL);
 13.3099 +        sym->addr=val;
 13.3100 +        /* At the moment, I have assumed that this syntax is only valid if
 13.3101 +         * val < 0. To properly mix "normal" native functions and indexed
 13.3102 +         * native functions, one should use negative indices anyway.
 13.3103 +         * Special code for a negative index in sym->addr exists in SC4.C
 13.3104 +         * (ffcall()) and in SC6.C (the loops for counting the number of native
 13.3105 +         * variables and for writing them).
 13.3106 +         */
 13.3107 +      } /* if */
 13.3108 +    } /* if */
 13.3109 +  } /* if */
 13.3110 +  needtoken(tTERM);
 13.3111 +
 13.3112 +  /* attach the array to the function symbol */
 13.3113 +  if (numdim>0) {
 13.3114 +    assert(sym!=NULL);
 13.3115 +    sub=addvariable(symbolname,0,iARRAY,sGLOBAL,tag,dim,numdim,idxtag);
 13.3116 +    sub->parent=sym;
 13.3117 +  } /* if */
 13.3118 +
 13.3119 +  litidx=0;                     /* clear the literal pool */
 13.3120 +  delete_symbols(&loctab,0,TRUE,TRUE);/* clear local variables queue */
 13.3121 +}
 13.3122 +
 13.3123 +/*  newfunc    - begin a function
 13.3124 + *
 13.3125 + *  This routine is called from "parse" and tries to make a function
 13.3126 + *  out of the following text
 13.3127 + *
 13.3128 + *  Global references: funcstatus,lastst,litidx
 13.3129 + *                     rettype  (altered)
 13.3130 + *                     curfunc  (altered)
 13.3131 + *                     declared (altered)
 13.3132 + *                     glb_declared (altered)
 13.3133 + *                     sc_alignnext (altered)
 13.3134 + */
 13.3135 +static int newfunc(char *firstname,int firsttag,int fpublic,int fstatic,int stock)
 13.3136 +{
 13.3137 +  symbol *sym;
 13.3138 +  int argcnt,tok,tag,funcline;
 13.3139 +  int opertok,opererror;
 13.3140 +  char symbolname[sNAMEMAX+1];
 13.3141 +  char *str;
 13.3142 +  cell val,cidx,glbdecl;
 13.3143 +  short filenum;
 13.3144 +  int state_id;
 13.3145 +
 13.3146 +  assert(litidx==0);    /* literal queue should be empty */
 13.3147 +  litidx=0;             /* clear the literal pool (should already be empty) */
 13.3148 +  opertok=0;
 13.3149 +  lastst=0;             /* no statement yet */
 13.3150 +  cidx=0;               /* just to avoid compiler warnings */
 13.3151 +  glbdecl=0;
 13.3152 +  assert(loctab.next==NULL);    /* local symbol table should be empty */
 13.3153 +  filenum=fcurrent;     /* save file number at the start of the declaration */
 13.3154 +
 13.3155 +  if (firstname!=NULL) {
 13.3156 +    assert(strlen(firstname)<=sNAMEMAX);
 13.3157 +    strcpy(symbolname,firstname);       /* save symbol name */
 13.3158 +    tag=firsttag;
 13.3159 +  } else {
 13.3160 +    tag= (firsttag>=0) ? firsttag : pc_addtag(NULL);
 13.3161 +    tok=lex(&val,&str);
 13.3162 +    assert(!fpublic);
 13.3163 +    if (tok==tNATIVE || tok==tPUBLIC && stock)
 13.3164 +      error(42);                /* invalid combination of class specifiers */
 13.3165 +    if (tok==tOPERATOR) {
 13.3166 +      opertok=operatorname(symbolname);
 13.3167 +      if (opertok==0)
 13.3168 +        return TRUE;            /* error message already given */
 13.3169 +      check_operatortag(opertok,tag,symbolname);
 13.3170 +    } else {
 13.3171 +      if (tok!=tSYMBOL && freading) {
 13.3172 +        error(20,str);          /* invalid symbol name */
 13.3173 +        return FALSE;
 13.3174 +      } /* if */
 13.3175 +      assert(strlen(str)<=sNAMEMAX);
 13.3176 +      strcpy(symbolname,str);
 13.3177 +    } /* if */
 13.3178 +  } /* if */
 13.3179 +  /* check whether this is a function or a variable declaration */
 13.3180 +  if (!matchtoken('('))
 13.3181 +    return FALSE;
 13.3182 +  /* so it is a function, proceed */
 13.3183 +  funcline=fline;               /* save line at which the function is defined */
 13.3184 +  if (symbolname[0]==PUBLIC_CHAR) {
 13.3185 +    fpublic=TRUE;               /* implicitly public function */
 13.3186 +    if (stock)
 13.3187 +      error(42);                /* invalid combination of class specifiers */
 13.3188 +  } /* if */
 13.3189 +  sym=fetchfunc(symbolname,tag);/* get a pointer to the function entry */
 13.3190 +  if (sym==NULL || (sym->usage & uNATIVE)!=0)
 13.3191 +    return TRUE;                /* it was recognized as a function declaration, but not as a valid one */
 13.3192 +  if (fpublic)
 13.3193 +    sym->usage|=uPUBLIC;
 13.3194 +  if (fstatic)
 13.3195 +    sym->fnumber=filenum;
 13.3196 +  /* if the function was used before being declared, and it has a tag for the
 13.3197 +   * result, add a third pass (as second "skimming" parse) because the function
 13.3198 +   * result may have been used with user-defined operators, which have now
 13.3199 +   * been incorrectly flagged (as the return tag was unknown at the time of
 13.3200 +   * the call)
 13.3201 +   */
 13.3202 +  if ((sym->usage & (uPROTOTYPED | uREAD))==uREAD && sym->tag!=0) {
 13.3203 +    int curstatus=sc_status;
 13.3204 +    sc_status=statWRITE;  /* temporarily set status to WRITE, so the warning isn't blocked */
 13.3205 +    error(208);
 13.3206 +    sc_status=curstatus;
 13.3207 +    sc_reparse=TRUE;      /* must add another pass to "initial scan" phase */
 13.3208 +  } /* if */
 13.3209 +  /* we want public functions to be explicitly prototyped, as they are called
 13.3210 +   * from the outside
 13.3211 +   */
 13.3212 +  if (fpublic && (sym->usage & uFORWARD)==0)
 13.3213 +    error(235,symbolname);
 13.3214 +  /* declare all arguments */
 13.3215 +  argcnt=declargs(sym,TRUE);
 13.3216 +  opererror=!operatoradjust(opertok,sym,symbolname,tag);
 13.3217 +  if (strcmp(symbolname,uMAINFUNC)==0 || strcmp(symbolname,uENTRYFUNC)==0) {
 13.3218 +    if (argcnt>0)
 13.3219 +      error(5);         /* "main()" and "entry()" functions may not have any arguments */
 13.3220 +    sym->usage|=uREAD;  /* "main()" is the program's entry point: always used */
 13.3221 +  } /* if */
 13.3222 +  state_id=getstates(symbolname);
 13.3223 +  if (state_id>0 && (opertok!=0 || strcmp(symbolname,uMAINFUNC)==0))
 13.3224 +    error(82);          /* operators may not have states, main() may neither */
 13.3225 +  attachstatelist(sym,state_id);
 13.3226 +  /* "declargs()" found the ")"; if a ";" appears after this, it was a
 13.3227 +   * prototype */
 13.3228 +  if (matchtoken(';')) {
 13.3229 +    sym->usage|=uFORWARD;
 13.3230 +    if (!sc_needsemicolon)
 13.3231 +      error(218);       /* old style prototypes used with optional semicolumns */
 13.3232 +    delete_symbols(&loctab,0,TRUE,TRUE);  /* prototype is done; forget everything */
 13.3233 +    return TRUE;
 13.3234 +  } /* if */
 13.3235 +  /* so it is not a prototype, proceed */
 13.3236 +  /* if this is a function that is not referred to (this can only be detected
 13.3237 +   * in the second stage), shut code generation off */
 13.3238 +  if (sc_status==statWRITE && (sym->usage & uREAD)==0 && !fpublic) {
 13.3239 +    sc_status=statSKIP;
 13.3240 +    cidx=code_idx;
 13.3241 +    glbdecl=glb_declared;
 13.3242 +  } /* if */
 13.3243 +  if ((sym->flags & flgDEPRICATED)!=0) {
 13.3244 +    char *ptr= (sym->documentation!=NULL) ? sym->documentation : "";
 13.3245 +    error(234,symbolname,ptr);  /* depricated (probably a public function) */
 13.3246 +  } /* if */
 13.3247 +  begcseg();
 13.3248 +  sym->usage|=uDEFINE;  /* set the definition flag */
 13.3249 +  if (stock)
 13.3250 +    sym->usage|=uSTOCK;
 13.3251 +  if (opertok!=0 && opererror)
 13.3252 +    sym->usage &= ~uDEFINE;
 13.3253 +  /* if the function has states, dump the label to the start of the function */
 13.3254 +  if (state_id!=0) {
 13.3255 +    constvalue *ptr=sym->states->next;
 13.3256 +    while (ptr!=NULL) {
 13.3257 +      assert(sc_status!=statWRITE || strlen(ptr->name)>0);
 13.3258 +      if (ptr->index==state_id) {
 13.3259 +        setlabel((int)strtol(ptr->name,NULL,16));
 13.3260 +        break;
 13.3261 +      } /* if */
 13.3262 +      ptr=ptr->next;
 13.3263 +    } /* while */
 13.3264 +  } /* if */
 13.3265 +  startfunc(sym->name); /* creates stack frame */
 13.3266 +  insert_dbgline(funcline);
 13.3267 +  setline(FALSE);
 13.3268 +  if (sc_alignnext) {
 13.3269 +    alignframe(sc_dataalign);
 13.3270 +    sc_alignnext=FALSE;
 13.3271 +  } /* if */
 13.3272 +  declared=0;           /* number of local cells */
 13.3273 +  rettype=(sym->usage & uRETVALUE);      /* set "return type" variable */
 13.3274 +  curfunc=sym;
 13.3275 +  define_args();        /* add the symbolic info for the function arguments */
 13.3276 +  #if !defined SC_LIGHT
 13.3277 +    if (matchtoken('{')) {
 13.3278 +      lexpush();
 13.3279 +    } else {
 13.3280 +      /* Insert a separator so that comments following the statement will not
 13.3281 +       * be attached to this function; they should be attached to the next
 13.3282 +       * function. This is not a problem for functions having a compound block,
 13.3283 +       * because the closing brace is an explicit "end token" for the function.
 13.3284 +       * With single statement functions, the preprocessor may overread the
 13.3285 +       * source code before the parser determines an "end of statement".
 13.3286 +       */
 13.3287 +      insert_docstring_separator();
 13.3288 +    } /* if */
 13.3289 +  #endif
 13.3290 +  sc_curstates=state_id;/* set state id, for accessing global state variables */
 13.3291 +  statement(NULL,FALSE);
 13.3292 +  sc_curstates=0;
 13.3293 +  if ((rettype & uRETVALUE)!=0)
 13.3294 +    sym->usage|=uRETVALUE;
 13.3295 +  if (declared!=0) {
 13.3296 +    /* This happens only in a very special (and useless) case, where a function
 13.3297 +     * has only a single statement in its body (no compound block) and that
 13.3298 +     * statement declares a new variable
 13.3299 +     */
 13.3300 +    modstk((int)declared*sizeof(cell)); /* remove all local variables */
 13.3301 +    declared=0;
 13.3302 +  } /* if */
 13.3303 +  if ((lastst!=tRETURN) && (lastst!=tGOTO)){
 13.3304 +    ldconst(0,sPRI);
 13.3305 +    ffret(strcmp(sym->name,uENTRYFUNC)!=0);
 13.3306 +    if ((sym->usage & uRETVALUE)!=0) {
 13.3307 +      char symname[2*sNAMEMAX+16];  /* allow space for user defined operators */
 13.3308 +      funcdisplayname(symname,sym->name);
 13.3309 +      error(209,symname);       /* function should return a value */
 13.3310 +    } /* if */
 13.3311 +  } /* if */
 13.3312 +  endfunc();
 13.3313 +  sym->codeaddr=code_idx;
 13.3314 +  sc_attachdocumentation(sym);  /* attach collected documenation to the function */
 13.3315 +  if (litidx) {                 /* if there are literals defined */
 13.3316 +    glb_declared+=litidx;
 13.3317 +    begdseg();                  /* flip to DATA segment */
 13.3318 +    dumplits();                 /* dump literal strings */
 13.3319 +    litidx=0;
 13.3320 +  } /* if */
 13.3321 +  testsymbols(&loctab,0,TRUE,TRUE);     /* test for unused arguments and labels */
 13.3322 +  delete_symbols(&loctab,0,TRUE,TRUE);  /* clear local variables queue */
 13.3323 +  assert(loctab.next==NULL);
 13.3324 +  curfunc=NULL;
 13.3325 +  if (sc_status==statSKIP) {
 13.3326 +    sc_status=statWRITE;
 13.3327 +    code_idx=cidx;
 13.3328 +    glb_declared=glbdecl;
 13.3329 +  } /* if */
 13.3330 +  return TRUE;
 13.3331 +}
 13.3332 +
 13.3333 +static int argcompare(arginfo *a1,arginfo *a2)
 13.3334 +{
 13.3335 +  int result,level,i;
 13.3336 +
 13.3337 +  result= strcmp(a1->name,a2->name)==0;     /* name */
 13.3338 +  if (result)
 13.3339 +    result= a1->ident==a2->ident;           /* type/class */
 13.3340 +  if (result)
 13.3341 +    result= a1->usage==a2->usage;           /* "const" flag */
 13.3342 +  if (result)
 13.3343 +    result= a1->numtags==a2->numtags;       /* tags (number and names) */
 13.3344 +  for (i=0; result && i<a1->numtags; i++)
 13.3345 +    result= a1->tags[i]==a2->tags[i];
 13.3346 +  if (result)
 13.3347 +    result= a1->numdim==a2->numdim;         /* array dimensions & index tags */
 13.3348 +  for (level=0; result && level<a1->numdim; level++)
 13.3349 +    result= a1->dim[level]==a2->dim[level];
 13.3350 +  for (level=0; result && level<a1->numdim; level++)
 13.3351 +    result= a1->idxtag[level]==a2->idxtag[level];
 13.3352 +  if (result)
 13.3353 +    result= a1->hasdefault==a2->hasdefault; /* availability of default value */
 13.3354 +  if (a1->hasdefault) {
 13.3355 +    if (a1->ident==iREFARRAY) {
 13.3356 +      if (result)
 13.3357 +        result= a1->defvalue.array.size==a2->defvalue.array.size;
 13.3358 +      if (result)
 13.3359 +        result= a1->defvalue.array.arraysize==a2->defvalue.array.arraysize;
 13.3360 +      /* ??? should also check contents of the default array (these troubles
 13.3361 +       * go away in a 2-pass compiler that forbids double declarations, but
 13.3362 +       * Pawn currently does not forbid them) */
 13.3363 +    } else {
 13.3364 +      if (result) {
 13.3365 +        if ((a1->hasdefault & uSIZEOF)!=0 || (a1->hasdefault & uTAGOF)!=0)
 13.3366 +          result= a1->hasdefault==a2->hasdefault
 13.3367 +                  && strcmp(a1->defvalue.size.symname,a2->defvalue.size.symname)==0
 13.3368 +                  && a1->defvalue.size.level==a2->defvalue.size.level;
 13.3369 +        else
 13.3370 +          result= a1->defvalue.val==a2->defvalue.val;
 13.3371 +      } /* if */
 13.3372 +    } /* if */
 13.3373 +    if (result)
 13.3374 +      result= a1->defvalue_tag==a2->defvalue_tag;
 13.3375 +  } /* if */
 13.3376 +  return result;
 13.3377 +}
 13.3378 +
 13.3379 +/*  declargs()
 13.3380 + *
 13.3381 + *  This routine adds an entry in the local symbol table for each argument
 13.3382 + *  found in the argument list. It returns the number of arguments.
 13.3383 + */
 13.3384 +static int declargs(symbol *sym,int chkshadow)
 13.3385 +{
 13.3386 +  #define MAXTAGS 16
 13.3387 +  char *ptr;
 13.3388 +  int argcnt,oldargcnt,tok,tags[MAXTAGS],numtags;
 13.3389 +  cell val;
 13.3390 +  arginfo arg, *arglist;
 13.3391 +  char name[sNAMEMAX+1];
 13.3392 +  int ident,fpublic,fconst;
 13.3393 +  int idx;
 13.3394 +
 13.3395 +  /* if the function is already defined earlier, get the number of arguments
 13.3396 +   * of the existing definition
 13.3397 +   */
 13.3398 +  oldargcnt=0;
 13.3399 +  if ((sym->usage & uPROTOTYPED)!=0)
 13.3400 +    while (sym->dim.arglist[oldargcnt].ident!=0)
 13.3401 +      oldargcnt++;
 13.3402 +  argcnt=0;                             /* zero aruments up to now */
 13.3403 +  ident=iVARIABLE;
 13.3404 +  numtags=0;
 13.3405 +  fconst=FALSE;
 13.3406 +  fpublic= (sym->usage & uPUBLIC)!=0;
 13.3407 +  /* the '(' parantheses has already been parsed */
 13.3408 +  if (!matchtoken(')')){
 13.3409 +    do {                                /* there are arguments; process them */
 13.3410 +      /* any legal name increases argument count (and stack offset) */
 13.3411 +      tok=lex(&val,&ptr);
 13.3412 +      switch (tok) {
 13.3413 +      case 0:
 13.3414 +        /* nothing */
 13.3415 +        break;
 13.3416 +      case '&':
 13.3417 +        if (ident!=iVARIABLE || numtags>0)
 13.3418 +          error(1,"-identifier-","&");
 13.3419 +        ident=iREFERENCE;
 13.3420 +        break;
 13.3421 +      case tCONST:
 13.3422 +        if (ident!=iVARIABLE || numtags>0)
 13.3423 +          error(1,"-identifier-","const");
 13.3424 +        fconst=TRUE;
 13.3425 +        break;
 13.3426 +      case tLABEL:
 13.3427 +        if (numtags>0)
 13.3428 +          error(1,"-identifier-","-tagname-");
 13.3429 +        tags[0]=pc_addtag(ptr);
 13.3430 +        numtags=1;
 13.3431 +        break;
 13.3432 +      case '{':
 13.3433 +        if (numtags>0)
 13.3434 +          error(1,"-identifier-","-tagname-");
 13.3435 +        numtags=0;
 13.3436 +        while (numtags<MAXTAGS) {
 13.3437 +          if (!matchtoken('_') && !needtoken(tSYMBOL))
 13.3438 +            break;
 13.3439 +          tokeninfo(&val,&ptr);
 13.3440 +          tags[numtags++]=pc_addtag(ptr);
 13.3441 +          if (matchtoken('}'))
 13.3442 +            break;
 13.3443 +          needtoken(',');
 13.3444 +        } /* for */
 13.3445 +        needtoken(':');
 13.3446 +        tok=tLABEL;     /* for outer loop: flag that we have seen a tagname */
 13.3447 +        break;
 13.3448 +      case tSYMBOL:
 13.3449 +        if (argcnt>=sMAXARGS)
 13.3450 +          error(45);                    /* too many function arguments */
 13.3451 +        strcpy(name,ptr);               /* save symbol name */
 13.3452 +        if (name[0]==PUBLIC_CHAR)
 13.3453 +          error(56,name);               /* function arguments cannot be public */
 13.3454 +        if (numtags==0)
 13.3455 +          tags[numtags++]=0;            /* default tag */
 13.3456 +        /* Stack layout:
 13.3457 +         *   base + 0*sizeof(cell)  == previous "base"
 13.3458 +         *   base + 1*sizeof(cell)  == function return address
 13.3459 +         *   base + 2*sizeof(cell)  == number of arguments
 13.3460 +         *   base + 3*sizeof(cell)  == first argument of the function
 13.3461 +         * So the offset of each argument is "(argcnt+3) * sizeof(cell)".
 13.3462 +         */
 13.3463 +        doarg(name,ident,(argcnt+3)*sizeof(cell),tags,numtags,fpublic,fconst,chkshadow,&arg);
 13.3464 +        if (fpublic && arg.hasdefault)
 13.3465 +          error(59,name);       /* arguments of a public function may not have a default value */
 13.3466 +        if ((sym->usage & uPROTOTYPED)==0) {
 13.3467 +          /* redimension the argument list, add the entry */
 13.3468 +          sym->dim.arglist=(arginfo*)realloc(sym->dim.arglist,(argcnt+2)*sizeof(arginfo));
 13.3469 +          if (sym->dim.arglist==0)
 13.3470 +            error(103);                 /* insufficient memory */
 13.3471 +          memset(&sym->dim.arglist[argcnt+1],0,sizeof(arginfo));  /* keep the list terminated */
 13.3472 +          sym->dim.arglist[argcnt]=arg;
 13.3473 +        } else {
 13.3474 +          /* check the argument with the earlier definition */
 13.3475 +          if (argcnt>oldargcnt || !argcompare(&sym->dim.arglist[argcnt],&arg))
 13.3476 +            error(25);          /* function definition does not match prototype */
 13.3477 +          /* may need to free default array argument and the tag list */
 13.3478 +          if (arg.ident==iREFARRAY && arg.hasdefault)
 13.3479 +            free(arg.defvalue.array.data);
 13.3480 +          else if (arg.ident==iVARIABLE
 13.3481 +                   && ((arg.hasdefault & uSIZEOF)!=0 || (arg.hasdefault & uTAGOF)!=0))
 13.3482 +            free(arg.defvalue.size.symname);
 13.3483 +          free(arg.tags);
 13.3484 +        } /* if */
 13.3485 +        argcnt++;
 13.3486 +        ident=iVARIABLE;
 13.3487 +        numtags=0;
 13.3488 +        fconst=FALSE;
 13.3489 +        break;
 13.3490 +      case tELLIPS:
 13.3491 +        if (ident!=iVARIABLE)
 13.3492 +          error(10);                    /* illegal function or declaration */
 13.3493 +        if (numtags==0)
 13.3494 +          tags[numtags++]=0;            /* default tag */
 13.3495 +        if ((sym->usage & uPROTOTYPED)==0) {
 13.3496 +          /* redimension the argument list, add the entry iVARARGS */
 13.3497 +          sym->dim.arglist=(arginfo*)realloc(sym->dim.arglist,(argcnt+2)*sizeof(arginfo));
 13.3498 +          if (sym->dim.arglist==0)
 13.3499 +            error(103);                 /* insufficient memory */
 13.3500 +          memset(&sym->dim.arglist[argcnt+1],0,sizeof(arginfo));  /* keep the list terminated */
 13.3501 +          sym->dim.arglist[argcnt].ident=iVARARGS;
 13.3502 +          sym->dim.arglist[argcnt].hasdefault=FALSE;
 13.3503 +          sym->dim.arglist[argcnt].defvalue.val=0;
 13.3504 +          sym->dim.arglist[argcnt].defvalue_tag=0;
 13.3505 +          sym->dim.arglist[argcnt].numtags=numtags;
 13.3506 +          sym->dim.arglist[argcnt].tags=(int*)malloc(numtags*sizeof tags[0]);
 13.3507 +          if (sym->dim.arglist[argcnt].tags==NULL)
 13.3508 +            error(103);                 /* insufficient memory */
 13.3509 +          memcpy(sym->dim.arglist[argcnt].tags,tags,numtags*sizeof tags[0]);
 13.3510 +        } else {
 13.3511 +          if (argcnt>oldargcnt || sym->dim.arglist[argcnt].ident!=iVARARGS)
 13.3512 +            error(25);          /* function definition does not match prototype */
 13.3513 +        } /* if */
 13.3514 +        argcnt++;
 13.3515 +        break;
 13.3516 +      default:
 13.3517 +        error(10);                      /* illegal function or declaration */
 13.3518 +      } /* switch */
 13.3519 +    } while (tok=='&' || tok==tLABEL || tok==tCONST
 13.3520 +             || tok!=tELLIPS && matchtoken(',')); /* more? */
 13.3521 +    /* if the next token is not ",", it should be ")" */
 13.3522 +    needtoken(')');
 13.3523 +  } /* if */
 13.3524 +  /* resolve any "sizeof" arguments (now that all arguments are known) */
 13.3525 +  assert(sym->dim.arglist!=NULL);
 13.3526 +  arglist=sym->dim.arglist;
 13.3527 +  for (idx=0; idx<argcnt && arglist[idx].ident!=0; idx++) {
 13.3528 +    if ((arglist[idx].hasdefault & uSIZEOF)!=0 || (arglist[idx].hasdefault & uTAGOF)!=0) {
 13.3529 +      int altidx;
 13.3530 +      /* Find the argument with the name mentioned after the "sizeof". Note
 13.3531 +       * that we cannot use findloc here because we need the arginfo struct,
 13.3532 +       * not the symbol.
 13.3533 +       */
 13.3534 +      ptr=arglist[idx].defvalue.size.symname;
 13.3535 +      assert(ptr!=NULL);
 13.3536 +      for (altidx=0; altidx<argcnt && strcmp(ptr,arglist[altidx].name)!=0; altidx++)
 13.3537 +        /* nothing */;
 13.3538 +      if (altidx>=argcnt) {
 13.3539 +        error(17,ptr);                  /* undefined symbol */
 13.3540 +      } else {
 13.3541 +        assert(arglist[idx].defvalue.size.symname!=NULL);
 13.3542 +        /* check the level against the number of dimensions */
 13.3543 +        if (arglist[idx].defvalue.size.level>0
 13.3544 +            && arglist[idx].defvalue.size.level>=arglist[altidx].numdim)
 13.3545 +          error(28,arglist[idx].name);  /* invalid subscript */
 13.3546 +        /* check the type of the argument whose size to take; for a iVARIABLE
 13.3547 +         * or a iREFERENCE, this is always 1 (so the code is redundant)
 13.3548 +         */
 13.3549 +        assert(arglist[altidx].ident!=iVARARGS);
 13.3550 +        if (arglist[altidx].ident!=iREFARRAY && (arglist[idx].hasdefault & uSIZEOF)!=0) {
 13.3551 +          if ((arglist[idx].hasdefault & uTAGOF)!=0) {
 13.3552 +            error(81,arglist[idx].name);  /* cannot take "tagof" an indexed array */
 13.3553 +          } else {
 13.3554 +            assert(arglist[altidx].ident==iVARIABLE || arglist[altidx].ident==iREFERENCE);
 13.3555 +            error(223,ptr);             /* redundant sizeof */
 13.3556 +          } /* if */
 13.3557 +        } /* if */
 13.3558 +      } /* if */
 13.3559 +    } /* if */
 13.3560 +  } /* for */
 13.3561 +
 13.3562 +  sym->usage|=uPROTOTYPED;
 13.3563 +  errorset(sRESET,0);           /* reset error flag (clear the "panic mode")*/
 13.3564 +  return argcnt;
 13.3565 +}
 13.3566 +
 13.3567 +/*  doarg       - declare one argument type
 13.3568 + *
 13.3569 + *  this routine is called from "declargs()" and adds an entry in the local
 13.3570 + *  symbol table for one argument.
 13.3571 + *
 13.3572 + *  "fpublic" indicates whether the function for this argument list is public.
 13.3573 + *  The arguments themselves are never public.
 13.3574 + */
 13.3575 +static void doarg(char *name,int ident,int offset,int tags[],int numtags,
 13.3576 +                  int fpublic,int fconst,int chkshadow,arginfo *arg)
 13.3577 +{
 13.3578 +  symbol *argsym;
 13.3579 +  constvalue *enumroot;
 13.3580 +  cell size;
 13.3581 +
 13.3582 +  strcpy(arg->name,name);
 13.3583 +  arg->hasdefault=FALSE;        /* preset (most common case) */
 13.3584 +  arg->defvalue.val=0;          /* clear */
 13.3585 +  arg->defvalue_tag=0;
 13.3586 +  arg->numdim=0;
 13.3587 +  if (matchtoken('[')) {
 13.3588 +    if (ident==iREFERENCE)
 13.3589 +      error(67,name);           /* illegal declaration ("&name[]" is unsupported) */
 13.3590 +    do {
 13.3591 +      if (arg->numdim == sDIMEN_MAX) {
 13.3592 +        error(53);              /* exceeding maximum number of dimensions */
 13.3593 +        return;
 13.3594 +      } /* if */
 13.3595 +      size=needsub(&arg->idxtag[arg->numdim],&enumroot);/* may be zero here, it is a pointer anyway */
 13.3596 +      #if INT_MAX < LONG_MAX
 13.3597 +        if (size > INT_MAX)
 13.3598 +          error(105);           /* overflow, exceeding capacity */
 13.3599 +      #endif
 13.3600 +      arg->dim[arg->numdim]=(int)size;
 13.3601 +      arg->numdim+=1;
 13.3602 +    } while (matchtoken('['));
 13.3603 +    ident=iREFARRAY;            /* "reference to array" (is a pointer) */
 13.3604 +    if (matchtoken('=')) {
 13.3605 +      lexpush();                /* initials() needs the "=" token again */
 13.3606 +      assert(litidx==0);        /* at the start of a function, this is reset */
 13.3607 +      assert(numtags>0);
 13.3608 +      initials(ident,tags[0],&size,arg->dim,arg->numdim,enumroot);
 13.3609 +      assert(size>=litidx);
 13.3610 +      /* allocate memory to hold the initial values */
 13.3611 +      arg->defvalue.array.data=(cell *)malloc(litidx*sizeof(cell));
 13.3612 +      if (arg->defvalue.array.data!=NULL) {
 13.3613 +        int i;
 13.3614 +        memcpy(arg->defvalue.array.data,litq,litidx*sizeof(cell));
 13.3615 +        arg->hasdefault=TRUE;   /* argument has default value */
 13.3616 +        arg->defvalue.array.size=litidx;
 13.3617 +        arg->defvalue.array.addr=-1;
 13.3618 +        /* calulate size to reserve on the heap */
 13.3619 +        arg->defvalue.array.arraysize=1;
 13.3620 +        for (i=0; i<arg->numdim; i++)
 13.3621 +          arg->defvalue.array.arraysize*=arg->dim[i];
 13.3622 +        if (arg->defvalue.array.arraysize < arg->defvalue.array.size)
 13.3623 +          arg->defvalue.array.arraysize = arg->defvalue.array.size;
 13.3624 +      } /* if */
 13.3625 +      litidx=0;                 /* reset */
 13.3626 +    } /* if */
 13.3627 +  } else {
 13.3628 +    if (matchtoken('=')) {
 13.3629 +      unsigned char size_tag_token;
 13.3630 +      assert(ident==iVARIABLE || ident==iREFERENCE);
 13.3631 +      arg->hasdefault=TRUE;     /* argument has a default value */
 13.3632 +      size_tag_token=(unsigned char)(matchtoken(tSIZEOF) ? uSIZEOF : 0);
 13.3633 +      if (size_tag_token==0)
 13.3634 +        size_tag_token=(unsigned char)(matchtoken(tTAGOF) ? uTAGOF : 0);
 13.3635 +      if (size_tag_token!=0) {
 13.3636 +        int paranthese;
 13.3637 +        if (ident==iREFERENCE)
 13.3638 +          error(66,name);       /* argument may not be a reference */
 13.3639 +        paranthese=0;
 13.3640 +        while (matchtoken('('))
 13.3641 +          paranthese++;
 13.3642 +        if (needtoken(tSYMBOL)) {
 13.3643 +          /* save the name of the argument whose size id to take */
 13.3644 +          char *name;
 13.3645 +          cell val;
 13.3646 +          tokeninfo(&val,&name);
 13.3647 +          if ((arg->defvalue.size.symname=duplicatestring(name)) == NULL)
 13.3648 +            error(103);         /* insufficient memory */
 13.3649 +          arg->defvalue.size.level=0;
 13.3650 +          if (size_tag_token==uSIZEOF) {
 13.3651 +            while (matchtoken('[')) {
 13.3652 +              arg->defvalue.size.level+=(short)1;
 13.3653 +              needtoken(']');
 13.3654 +            } /* while */
 13.3655 +          } /* if */
 13.3656 +          if (ident==iVARIABLE) /* make sure we set this only if not a reference */
 13.3657 +            arg->hasdefault |= size_tag_token;  /* uSIZEOF or uTAGOF */
 13.3658 +        } /* if */
 13.3659 +        while (paranthese--)
 13.3660 +          needtoken(')');
 13.3661 +      } else {
 13.3662 +        constexpr(&arg->defvalue.val,&arg->defvalue_tag,NULL);
 13.3663 +        assert(numtags>0);
 13.3664 +        if (!matchtag(tags[0],arg->defvalue_tag,TRUE))
 13.3665 +          error(213);           /* tagname mismatch */
 13.3666 +      } /* if */
 13.3667 +    } /* if */
 13.3668 +  } /* if */
 13.3669 +  arg->ident=(char)ident;
 13.3670 +  arg->usage=(char)(fconst ? uCONST : 0);
 13.3671 +  arg->numtags=numtags;
 13.3672 +  arg->tags=(int*)malloc(numtags*sizeof tags[0]);
 13.3673 +  if (arg->tags==NULL)
 13.3674 +    error(103);                 /* insufficient memory */
 13.3675 +  memcpy(arg->tags,tags,numtags*sizeof tags[0]);
 13.3676 +  argsym=findloc(name);
 13.3677 +  if (argsym!=NULL) {
 13.3678 +    error(21,name);             /* symbol already defined */
 13.3679 +  } else {
 13.3680 +    if (chkshadow && (argsym=findglb(name,sSTATEVAR))!=NULL && argsym->ident!=iFUNCTN)
 13.3681 +      error(219,name);          /* variable shadows another symbol */
 13.3682 +    /* add details of type and address */
 13.3683 +    assert(numtags>0);
 13.3684 +    argsym=addvariable(name,offset,ident,sLOCAL,tags[0],
 13.3685 +                       arg->dim,arg->numdim,arg->idxtag);
 13.3686 +    argsym->compound=0;
 13.3687 +    if (ident==iREFERENCE)
 13.3688 +      argsym->usage|=uREAD;     /* because references are passed back */
 13.3689 +    if (fpublic)
 13.3690 +      argsym->usage|=uREAD;     /* arguments of public functions are always "used" */
 13.3691 +    if (fconst)
 13.3692 +      argsym->usage|=uCONST;
 13.3693 +  } /* if */
 13.3694 +}
 13.3695 +
 13.3696 +static int count_referrers(symbol *entry)
 13.3697 +{
 13.3698 +  int i,count;
 13.3699 +
 13.3700 +  count=0;
 13.3701 +  for (i=0; i<entry->numrefers; i++)
 13.3702 +    if (entry->refer[i]!=NULL)
 13.3703 +      count++;
 13.3704 +  return count;
 13.3705 +}
 13.3706 +
 13.3707 +#if !defined SC_LIGHT
 13.3708 +static int find_xmltag(char *source,char *xmltag,char *xmlparam,char *xmlvalue,
 13.3709 +                       char **outer_start,int *outer_length,
 13.3710 +                       char **inner_start,int *inner_length)
 13.3711 +{
 13.3712 +  char *ptr,*inner_end;
 13.3713 +  int xmltag_len,xmlparam_len,xmlvalue_len;
 13.3714 +  int match;
 13.3715 +
 13.3716 +  assert(source!=NULL);
 13.3717 +  assert(xmltag!=NULL);
 13.3718 +  assert(outer_start!=NULL);
 13.3719 +  assert(outer_length!=NULL);
 13.3720 +  assert(inner_start!=NULL);
 13.3721 +  assert(inner_length!=NULL);
 13.3722 +
 13.3723 +  /* both NULL or both non-NULL */
 13.3724 +  assert(xmlvalue!=NULL && xmlparam!=NULL || xmlvalue==NULL && xmlparam==NULL);
 13.3725 +
 13.3726 +  xmltag_len=strlen(xmltag);
 13.3727 +  xmlparam_len= (xmlparam!=NULL) ? strlen(xmlparam) : 0;
 13.3728 +  xmlvalue_len= (xmlvalue!=NULL) ? strlen(xmlvalue) : 0;
 13.3729 +  ptr=source;
 13.3730 +  /* find an opening '<' */
 13.3731 +  while ((ptr=strchr(ptr,'<'))!=NULL) {
 13.3732 +    *outer_start=ptr;           /* be optimistic... */
 13.3733 +    match=FALSE;                /* ...and pessimistic at the same time */
 13.3734 +    ptr++;                      /* skip '<' */
 13.3735 +    while (*ptr!='\0' && *ptr<=' ')
 13.3736 +      ptr++;                    /* skip white space */
 13.3737 +    if (strncmp(ptr,xmltag,xmltag_len)==0 && (*(ptr+xmltag_len)<=' ' || *(ptr+xmltag_len)=='>')) {
 13.3738 +      /* xml tag found, optionally check the parameter */
 13.3739 +      ptr+=xmltag_len;
 13.3740 +      while (*ptr!='\0' && *ptr<=' ')
 13.3741 +        ptr++;                  /* skip white space */
 13.3742 +      if (xmlparam!=NULL) {
 13.3743 +        if (strncmp(ptr,xmlparam,xmlparam_len)==0 && (*(ptr+xmlparam_len)<=' ' || *(ptr+xmlparam_len)=='=')) {
 13.3744 +          ptr+=xmlparam_len;
 13.3745 +          while (*ptr!='\0' && *ptr<=' ')
 13.3746 +            ptr++;              /* skip white space */
 13.3747 +          if (*ptr=='=') {
 13.3748 +            ptr++;              /* skip '=' */
 13.3749 +            while (*ptr!='\0' && *ptr<=' ')
 13.3750 +              ptr++;            /* skip white space */
 13.3751 +            if (*ptr=='"' || *ptr=='\'')
 13.3752 +              ptr++;            /* skip " or ' */
 13.3753 +            assert(xmlvalue!=NULL);
 13.3754 +            if (strncmp(ptr,xmlvalue,xmlvalue_len)==0
 13.3755 +                && (*(ptr+xmlvalue_len)<=' '
 13.3756 +                    || *(ptr+xmlvalue_len)=='>'
 13.3757 +                    || *(ptr+xmlvalue_len)=='"'
 13.3758 +                    || *(ptr+xmlvalue_len)=='\''))
 13.3759 +              match=TRUE;       /* found it */
 13.3760 +          } /* if */
 13.3761 +        } /* if */
 13.3762 +      } else {
 13.3763 +        match=TRUE;             /* don't check the parameter */
 13.3764 +      } /* if */
 13.3765 +    } /* if */
 13.3766 +    if (match) {
 13.3767 +      /* now find the end of the opening tag */
 13.3768 +      while (*ptr!='\0' && *ptr!='>')
 13.3769 +        ptr++;
 13.3770 +      if (*ptr=='>')
 13.3771 +        ptr++;
 13.3772 +      while (*ptr!='\0' && *ptr<=' ')
 13.3773 +        ptr++;                  /* skip white space */
 13.3774 +      *inner_start=ptr;
 13.3775 +      /* find the start of the closing tag (assume no nesting) */
 13.3776 +      while ((ptr=strchr(ptr,'<'))!=NULL) {
 13.3777 +        inner_end=ptr;
 13.3778 +        ptr++;                  /* skip '<' */
 13.3779 +        while (*ptr!='\0' && *ptr<=' ')
 13.3780 +          ptr++;                /* skip white space */
 13.3781 +        if (*ptr=='/') {
 13.3782 +          ptr++;                /* skip / */
 13.3783 +          while (*ptr!='\0' && *ptr<=' ')
 13.3784 +            ptr++;              /* skip white space */
 13.3785 +          if (strncmp(ptr,xmltag,xmltag_len)==0 && (*(ptr+xmltag_len)<=' ' || *(ptr+xmltag_len)=='>')) {
 13.3786 +            /* find the end of the closing tag */
 13.3787 +            while (*ptr!='\0' && *ptr!='>')
 13.3788 +              ptr++;
 13.3789 +            if (*ptr=='>')
 13.3790 +              ptr++;
 13.3791 +            /* set the lengths of the inner and outer segment */
 13.3792 +            assert(*inner_start!=NULL);
 13.3793 +            *inner_length=(int)(inner_end-*inner_start);
 13.3794 +            assert(*outer_start!=NULL);
 13.3795 +            *outer_length=(int)(ptr-*outer_start);
 13.3796 +            break;              /* break out of the loop */
 13.3797 +          } /* if */
 13.3798 +        } /* if */
 13.3799 +      } /* while */
 13.3800 +      return TRUE;
 13.3801 +    } /* if */
 13.3802 +  } /* while */
 13.3803 +  return FALSE; /* not found */
 13.3804 +}
 13.3805 +
 13.3806 +static char *xmlencode(char *dest,char *source)
 13.3807 +{
 13.3808 +  char temp[2*sNAMEMAX+20],*ptr;
 13.3809 +
 13.3810 +  /* replace < by &lt; and such; normally, such a symbol occurs at most once in
 13.3811 +   * a symbol name (e.g. "operator<")
 13.3812 +   */
 13.3813 +  ptr=temp;
 13.3814 +  while (*source!='\0') {
 13.3815 +    switch (*source) {
 13.3816 +    case '<':
 13.3817 +      strcpy(ptr,"&lt;");
 13.3818 +      ptr+=4;
 13.3819 +      break;
 13.3820 +    case '>':
 13.3821 +      strcpy(ptr,"&gt;");
 13.3822 +      ptr+=4;
 13.3823 +      break;
 13.3824 +    case '&':
 13.3825 +      strcpy(ptr,"&amp;");
 13.3826 +      ptr+=5;
 13.3827 +      break;
 13.3828 +    default:
 13.3829 +      *ptr++=*source;
 13.3830 +    } /* switch */
 13.3831 +    source++;
 13.3832 +  } /* while */
 13.3833 +  *ptr='\0';
 13.3834 +  strcpy(dest,temp);
 13.3835 +  return dest;
 13.3836 +}
 13.3837 +
 13.3838 +static void make_report(symbol *root,FILE *log,char *sourcefile)
 13.3839 +{
 13.3840 +  char symname[_MAX_PATH];
 13.3841 +  int i,arg;
 13.3842 +  symbol *sym,*ref;
 13.3843 +  constvalue *tagsym;
 13.3844 +  constvalue *enumroot;
 13.3845 +  char *ptr;
 13.3846 +
 13.3847 +  /* adapt the installation directory */
 13.3848 +  strcpy(symname,sc_rootpath);
 13.3849 +  #if DIRSEP_CHAR=='\\'
 13.3850 +    while ((ptr=strchr(symname,':'))!=NULL)
 13.3851 +      *ptr='|';
 13.3852 +    while ((ptr=strchr(symname,DIRSEP_CHAR))!=NULL)
 13.3853 +      *ptr='/';
 13.3854 +  #endif
 13.3855 +
 13.3856 +  /* the XML header */
 13.3857 +  fprintf(log,"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n");
 13.3858 +  fprintf(log,"<?xml-stylesheet href=\"file:///%s/xml/pawndoc.xsl\" type=\"text/xsl\"?>\n",symname);
 13.3859 +  fprintf(log,"<doc source=\"%s\">\n",sourcefile);
 13.3860 +  ptr=strrchr(sourcefile,DIRSEP_CHAR);
 13.3861 +  if (ptr!=NULL)
 13.3862 +    ptr++;
 13.3863 +  else
 13.3864 +    ptr=sourcefile;
 13.3865 +  fprintf(log,"\t<assembly>\n\t\t<name>%s</name>\n\t</assembly>\n",ptr);
 13.3866 +
 13.3867 +  /* attach the global documentation, if any */
 13.3868 +  if (sc_documentation!=NULL) {
 13.3869 +    fprintf(log,"\n\t<!-- general -->\n");
 13.3870 +    fprintf(log,"\t<general>\n\t\t");
 13.3871 +    fputs(sc_documentation,log);
 13.3872 +    fprintf(log,"\n\t</general>\n\n");
 13.3873 +  } /* if */
 13.3874 +
 13.3875 +  /* use multiple passes to print constants variables and functions in
 13.3876 +   * separate sections
 13.3877 +   */
 13.3878 +  fprintf(log,"\t<members>\n");
 13.3879 +
 13.3880 +  fprintf(log,"\n\t\t<!-- enumerations -->\n");
 13.3881 +  for (sym=root->next; sym!=NULL; sym=sym->next) {
 13.3882 +    if (sym->parent!=NULL)
 13.3883 +      continue;                 /* hierarchical data type */
 13.3884 +    assert(sym->ident==iCONSTEXPR || sym->ident==iVARIABLE
 13.3885 +           || sym->ident==iARRAY || sym->ident==iFUNCTN);
 13.3886 +    if (sym->ident!=iCONSTEXPR || (sym->usage & uENUMROOT)==0)
 13.3887 +      continue;
 13.3888 +    if ((sym->usage & uREAD)==0)
 13.3889 +      continue;
 13.3890 +    fprintf(log,"\t\t<member name=\"T:%s\" value=\"%ld\">\n",funcdisplayname(symname,sym->name),sym->addr);
 13.3891 +    if (sym->tag!=0) {
 13.3892 +      tagsym=find_tag_byval(sym->tag);
 13.3893 +      assert(tagsym!=NULL);
 13.3894 +      fprintf(log,"\t\t\t<tagname value=\"%s\"/>\n",tagsym->name);
 13.3895 +    } /* if */
 13.3896 +    /* browse through all fields */
 13.3897 +    if ((enumroot=sym->dim.enumlist)!=NULL) {
 13.3898 +      enumroot=enumroot->next;  /* skip root */
 13.3899 +      while (enumroot!=NULL) {
 13.3900 +        fprintf(log,"\t\t\t<member name=\"C:%s\" value=\"%ld\">\n",funcdisplayname(symname,enumroot->name),enumroot->value);
 13.3901 +        /* find the constant with this name and get the tag */
 13.3902 +        ref=findglb(enumroot->name,sGLOBAL);
 13.3903 +        if (ref!=NULL) {
 13.3904 +          if (ref->x.tags.index!=0) {
 13.3905 +            tagsym=find_tag_byval(ref->x.tags.index);
 13.3906 +            assert(tagsym!=NULL);
 13.3907 +            fprintf(log,"\t\t\t\t<tagname value=\"%s\"/>\n",tagsym->name);
 13.3908 +          } /* if */
 13.3909 +          if (ref->dim.array.length!=1)
 13.3910 +            fprintf(log,"\t\t\t\t<size value=\"%ld\"/>\n",(long)ref->dim.array.length);
 13.3911 +        } /* if */
 13.3912 +        fprintf(log,"\t\t\t</member>\n");
 13.3913 +        enumroot=enumroot->next;
 13.3914 +      } /* while */
 13.3915 +    } /* if */
 13.3916 +    assert(sym->refer!=NULL);
 13.3917 +    for (i=0; i<sym->numrefers; i++) {
 13.3918 +      if ((ref=sym->refer[i])!=NULL)
 13.3919 +        fprintf(log,"\t\t\t<referrer name=\"%s\"/>\n",xmlencode(symname,funcdisplayname(symname,ref->name)));
 13.3920 +    } /* for */
 13.3921 +    if (sym->documentation!=NULL)
 13.3922 +      fprintf(log,"\t\t\t%s\n",sym->documentation);
 13.3923 +    fprintf(log,"\t\t</member>\n");
 13.3924 +  } /* for */
 13.3925 +
 13.3926 +  fprintf(log,"\n\t\t<!-- constants -->\n");
 13.3927 +  for (sym=root->next; sym!=NULL; sym=sym->next) {
 13.3928 +    if (sym->parent!=NULL)
 13.3929 +      continue;                 /* hierarchical data type */
 13.3930 +    assert(sym->ident==iCONSTEXPR || sym->ident==iVARIABLE
 13.3931 +           || sym->ident==iARRAY || sym->ident==iFUNCTN);
 13.3932 +    if (sym->ident!=iCONSTEXPR)
 13.3933 +      continue;
 13.3934 +    if ((sym->usage & uREAD)==0 || (sym->usage & (uENUMFIELD | uENUMROOT))!=0)
 13.3935 +      continue;
 13.3936 +    fprintf(log,"\t\t<member name=\"C:%s\" value=\"%ld\">\n",funcdisplayname(symname,sym->name),sym->addr);
 13.3937 +    if (sym->tag!=0) {
 13.3938 +      tagsym=find_tag_byval(sym->tag);
 13.3939 +      assert(tagsym!=NULL);
 13.3940 +      fprintf(log,"\t\t\t<tagname value=\"%s\"/>\n",tagsym->name);
 13.3941 +    } /* if */
 13.3942 +    assert(sym->refer!=NULL);
 13.3943 +    for (i=0; i<sym->numrefers; i++) {
 13.3944 +      if ((ref=sym->refer[i])!=NULL)
 13.3945 +        fprintf(log,"\t\t\t<referrer name=\"%s\"/>\n",xmlencode(symname,funcdisplayname(symname,ref->name)));
 13.3946 +    } /* for */
 13.3947 +    if (sym->documentation!=NULL)
 13.3948 +      fprintf(log,"\t\t\t%s\n",sym->documentation);
 13.3949 +    fprintf(log,"\t\t</member>\n");
 13.3950 +  } /* for */
 13.3951 +
 13.3952 +  fprintf(log,"\n\t\t<!-- variables -->\n");
 13.3953 +  for (sym=root->next; sym!=NULL; sym=sym->next) {
 13.3954 +    if (sym->parent!=NULL)
 13.3955 +      continue;                 /* hierarchical data type */
 13.3956 +    if (sym->ident!=iVARIABLE && sym->ident!=iARRAY)
 13.3957 +      continue;
 13.3958 +    fprintf(log,"\t\t<member name=\"F:%s\">\n",funcdisplayname(symname,sym->name));
 13.3959 +    if (sym->tag!=0) {
 13.3960 +      tagsym=find_tag_byval(sym->tag);
 13.3961 +      assert(tagsym!=NULL);
 13.3962 +      fprintf(log,"\t\t\t<tagname value=\"%s\"/>\n",tagsym->name);
 13.3963 +    } /* if */
 13.3964 +    assert(sym->refer!=NULL);
 13.3965 +    if ((sym->usage & uPUBLIC)!=0)
 13.3966 +      fprintf(log,"\t\t\t<attribute name=\"public\"/>\n");
 13.3967 +    for (i=0; i<sym->numrefers; i++) {
 13.3968 +      if ((ref=sym->refer[i])!=NULL)
 13.3969 +        fprintf(log,"\t\t\t<referrer name=\"%s\"/>\n",xmlencode(symname,funcdisplayname(symname,ref->name)));
 13.3970 +    } /* for */
 13.3971 +    if (sym->documentation!=NULL)
 13.3972 +      fprintf(log,"\t\t\t%s\n",sym->documentation);
 13.3973 +    fprintf(log,"\t\t</member>\n");
 13.3974 +  } /* for */
 13.3975 +
 13.3976 +  fprintf(log,"\n\t\t<!-- functions -->\n");
 13.3977 +  for (sym=root->next; sym!=NULL; sym=sym->next) {
 13.3978 +    if (sym->parent!=NULL)
 13.3979 +      continue;                 /* hierarchical data type */
 13.3980 +    if (sym->ident!=iFUNCTN)
 13.3981 +      continue;
 13.3982 +    if ((sym->usage & (uREAD | uNATIVE))==uNATIVE)
 13.3983 +      continue;                 /* unused native function */
 13.3984 +    funcdisplayname(symname,sym->name);
 13.3985 +    xmlencode(symname,symname);
 13.3986 +    fprintf(log,"\t\t<member name=\"M:%s\" syntax=\"%s(",symname,symname);
 13.3987 +    /* print only the names of the parameters between the parentheses */
 13.3988 +    assert(sym->dim.arglist!=NULL);
 13.3989 +    for (arg=0; sym->dim.arglist[arg].ident!=0; arg++) {
 13.3990 +      int dim;
 13.3991 +      if (arg>0)
 13.3992 +        fprintf(log,", ");
 13.3993 +      switch (sym->dim.arglist[arg].ident) {
 13.3994 +      case iVARIABLE:
 13.3995 +        fprintf(log,"%s",sym->dim.arglist[arg].name);
 13.3996 +        break;
 13.3997 +      case iREFERENCE:
 13.3998 +        fprintf(log,"&amp;%s",sym->dim.arglist[arg].name);
 13.3999 +        break;
 13.4000 +      case iREFARRAY:
 13.4001 +        fprintf(log,"%s",sym->dim.arglist[arg].name);
 13.4002 +        for (dim=0; dim<sym->dim.arglist[arg].numdim;dim++)
 13.4003 +          fprintf(log,"[]");
 13.4004 +        break;
 13.4005 +      case iVARARGS:
 13.4006 +        fprintf(log,"...");
 13.4007 +        break;
 13.4008 +      } /* switch */
 13.4009 +    } /* for */
 13.4010 +    /* ??? should also print an "array return" size */
 13.4011 +    fprintf(log,")\">\n");
 13.4012 +    if (sym->tag!=0) {
 13.4013 +      tagsym=find_tag_byval(sym->tag);
 13.4014 +      assert(tagsym!=NULL);
 13.4015 +      fprintf(log,"\t\t\t<tagname value=\"%s\"/>\n",tagsym->name);
 13.4016 +    } /* if */
 13.4017 +    /* check whether this function is called from the outside */
 13.4018 +    if ((sym->usage & uNATIVE)!=0)
 13.4019 +      fprintf(log,"\t\t\t<attribute name=\"native\"/>\n");
 13.4020 +    if ((sym->usage & uPUBLIC)!=0)
 13.4021 +      fprintf(log,"\t\t\t<attribute name=\"public\"/>\n");
 13.4022 +    if (strcmp(sym->name,uMAINFUNC)==0 || strcmp(sym->name,uENTRYFUNC)==0)
 13.4023 +      fprintf(log,"\t\t\t<attribute name=\"entry\"/>\n");
 13.4024 +    if ((sym->usage & uNATIVE)==0)
 13.4025 +      fprintf(log,"\t\t\t<stacksize value=\"%ld\"/>\n",(long)sym->x.stacksize);
 13.4026 +    if (sym->states!=NULL) {
 13.4027 +      constvalue *stlist=sym->states->next;
 13.4028 +      assert(stlist!=NULL);     /* there should be at least one state item */
 13.4029 +      while (stlist!=NULL && stlist->index==-1)
 13.4030 +        stlist=stlist->next;
 13.4031 +      assert(stlist!=NULL);     /* state id should be found */
 13.4032 +      i=state_getfsa(stlist->index);
 13.4033 +      assert(i>=0);             /* automaton 0 exists */
 13.4034 +      stlist=automaton_findid(i);
 13.4035 +      assert(stlist!=NULL);     /* automaton should be found */
 13.4036 +      fprintf(log,"\t\t\t<automaton name=\"%s\"/>\n", strlen(stlist->name)>0 ? stlist->name : "(anonymous)");
 13.4037 +      //??? dump state decision table
 13.4038 +    } /* if */
 13.4039 +    assert(sym->refer!=NULL);
 13.4040 +    for (i=0; i<sym->numrefers; i++)
 13.4041 +      if ((ref=sym->refer[i])!=NULL)
 13.4042 +        fprintf(log,"\t\t\t<referrer name=\"%s\"/>\n",xmlencode(symname,funcdisplayname(symname,ref->name)));
 13.4043 +    /* print all symbols that are required for this function to compile */
 13.4044 +    for (ref=root->next; ref!=NULL; ref=ref->next) {
 13.4045 +      if (ref==sym)
 13.4046 +        continue;
 13.4047 +      for (i=0; i<ref->numrefers; i++)
 13.4048 +        if (ref->refer[i]==sym)
 13.4049 +          fprintf(log,"\t\t\t<dependency name=\"%s\"/>\n",xmlencode(symname,funcdisplayname(symname,ref->name)));
 13.4050 +    } /* for */
 13.4051 +    /* print parameter list, with tag & const information, plus descriptions */
 13.4052 +    assert(sym->dim.arglist!=NULL);
 13.4053 +    for (arg=0; sym->dim.arglist[arg].ident!=0; arg++) {
 13.4054 +      int dim,paraminfo;
 13.4055 +      char *outer_start,*inner_start;
 13.4056 +      int outer_length,inner_length;
 13.4057 +      if (sym->dim.arglist[arg].ident==iVARARGS)
 13.4058 +        fprintf(log,"\t\t\t<param name=\"...\">\n");
 13.4059 +      else
 13.4060 +        fprintf(log,"\t\t\t<param name=\"%s\">\n",sym->dim.arglist[arg].name);
 13.4061 +      /* print the tag name(s) for each parameter */
 13.4062 +      assert(sym->dim.arglist[arg].numtags>0);
 13.4063 +      assert(sym->dim.arglist[arg].tags!=NULL);
 13.4064 +      paraminfo=(sym->dim.arglist[arg].numtags>1 || sym->dim.arglist[arg].tags[0]!=0)
 13.4065 +                || sym->dim.arglist[arg].ident==iREFERENCE
 13.4066 +                || sym->dim.arglist[arg].ident==iREFARRAY;
 13.4067 +      if (paraminfo)
 13.4068 +        fprintf(log,"\t\t\t\t<paraminfo>");
 13.4069 +      if (sym->dim.arglist[arg].numtags>1 || sym->dim.arglist[arg].tags[0]!=0) {
 13.4070 +        assert(paraminfo);
 13.4071 +        if (sym->dim.arglist[arg].numtags>1)
 13.4072 +          fprintf(log," {");
 13.4073 +        for (i=0; i<sym->dim.arglist[arg].numtags; i++) {
 13.4074 +          if (i>0)
 13.4075 +            fprintf(log,",");
 13.4076 +          tagsym=find_tag_byval(sym->dim.arglist[arg].tags[i]);
 13.4077 +          assert(tagsym!=NULL);
 13.4078 +          fprintf(log,"%s",tagsym->name);
 13.4079 +        } /* for */
 13.4080 +        if (sym->dim.arglist[arg].numtags>1)
 13.4081 +          fprintf(log,"}");
 13.4082 +      } /* if */
 13.4083 +      switch (sym->dim.arglist[arg].ident) {
 13.4084 +      case iREFERENCE:
 13.4085 +        fprintf(log," &amp;");
 13.4086 +        break;
 13.4087 +      case iREFARRAY:
 13.4088 +        fprintf(log," ");
 13.4089 +        for (dim=0; dim<sym->dim.arglist[arg].numdim; dim++) {
 13.4090 +          if (sym->dim.arglist[arg].dim[dim]==0) {
 13.4091 +            fprintf(log,"[]");
 13.4092 +          } else {
 13.4093 +            //??? find index tag
 13.4094 +            fprintf(log,"[%d]",sym->dim.arglist[arg].dim[dim]);
 13.4095 +          } /* if */
 13.4096 +        } /* for */
 13.4097 +        break;
 13.4098 +      } /* switch */
 13.4099 +      if (paraminfo)
 13.4100 +        fprintf(log," </paraminfo>\n");
 13.4101 +      /* print the user description of the parameter (parse through
 13.4102 +       * sym->documentation)
 13.4103 +       */
 13.4104 +      if (sym->documentation!=NULL
 13.4105 +          && find_xmltag(sym->documentation, "param", "name", sym->dim.arglist[arg].name,
 13.4106 +                         &outer_start, &outer_length, &inner_start, &inner_length))
 13.4107 +      {
 13.4108 +        char *tail;
 13.4109 +        fprintf(log,"\t\t\t\t%.*s\n",inner_length,inner_start);
 13.4110 +        /* delete from documentation string */
 13.4111 +        tail=outer_start+outer_length;
 13.4112 +        memmove(outer_start,tail,strlen(tail)+1);
 13.4113 +      } /* if */
 13.4114 +      fprintf(log,"\t\t\t</param>\n");
 13.4115 +    } /* for */
 13.4116 +    if (sym->documentation!=NULL)
 13.4117 +      fprintf(log,"\t\t\t%s\n",sym->documentation);
 13.4118 +    fprintf(log,"\t\t</member>\n");
 13.4119 +  } /* for */
 13.4120 +
 13.4121 +  fprintf(log,"\n\t</members>\n");
 13.4122 +  fprintf(log,"</doc>\n");
 13.4123 +}
 13.4124 +#endif
 13.4125 +
 13.4126 +/* Every symbol has a referrer list, that contains the functions that use
 13.4127 + * the symbol. Now, if function "apple" is accessed by functions "banana" and
 13.4128 + * "citron", but neither function "banana" nor "citron" are used by anyone
 13.4129 + * else, then, by inference, function "apple" is not used either.
 13.4130 + */
 13.4131 +static void reduce_referrers(symbol *root)
 13.4132 +{
 13.4133 +  int i,restart;
 13.4134 +  symbol *sym,*ref;
 13.4135 +
 13.4136 +  do {
 13.4137 +    restart=0;
 13.4138 +    for (sym=root->next; sym!=NULL; sym=sym->next) {
 13.4139 +      if (sym->parent!=NULL)
 13.4140 +        continue;                 /* hierarchical data type */
 13.4141 +      if (sym->ident==iFUNCTN
 13.4142 +          && (sym->usage & uNATIVE)==0
 13.4143 +          && (sym->usage & uPUBLIC)==0 && strcmp(sym->name,uMAINFUNC)!=0 && strcmp(sym->name,uENTRYFUNC)!=0
 13.4144 +          && count_referrers(sym)==0)
 13.4145 +      {
 13.4146 +        sym->usage&=~(uREAD | uWRITTEN);  /* erase usage bits if there is no referrer */
 13.4147 +        /* find all symbols that are referred by this symbol */
 13.4148 +        for (ref=root->next; ref!=NULL; ref=ref->next) {
 13.4149 +          if (ref->parent!=NULL)
 13.4150 +            continue;             /* hierarchical data type */
 13.4151 +          assert(ref->refer!=NULL);
 13.4152 +          for (i=0; i<ref->numrefers && ref->refer[i]!=sym; i++)
 13.4153 +            /* nothing */;
 13.4154 +          if (i<ref->numrefers) {
 13.4155 +            assert(ref->refer[i]==sym);
 13.4156 +            ref->refer[i]=NULL;
 13.4157 +            restart++;
 13.4158 +          } /* if */
 13.4159 +        } /* for */
 13.4160 +      } else if ((sym->ident==iVARIABLE || sym->ident==iARRAY)
 13.4161 +                 && (sym->usage & uPUBLIC)==0
 13.4162 +                 && sym->parent==NULL
 13.4163 +                 && count_referrers(sym)==0)
 13.4164 +      {
 13.4165 +        sym->usage&=~(uREAD | uWRITTEN);  /* erase usage bits if there is no referrer */
 13.4166 +      } /* if */
 13.4167 +    } /* for */
 13.4168 +    /* after removing a symbol, check whether more can be removed */
 13.4169 +  } while (restart>0);
 13.4170 +}
 13.4171 +
 13.4172 +#if !defined SC_LIGHT
 13.4173 +static long max_stacksize_recurse(symbol *sourcesym,symbol *sym,long basesize,int *pubfuncparams,int *recursion)
 13.4174 +{
 13.4175 +  long size,maxsize;
 13.4176 +  int i;
 13.4177 +
 13.4178 +  assert(sym!=NULL);
 13.4179 +  assert(sym->ident==iFUNCTN);
 13.4180 +  assert((sym->usage & uNATIVE)==0);
 13.4181 +  assert(recursion!=NULL);
 13.4182 +
 13.4183 +  maxsize=sym->x.stacksize;
 13.4184 +  for (i=0; i<sym->numrefers; i++) {
 13.4185 +    if (sym->refer[i]!=NULL) {
 13.4186 +      assert(sym->refer[i]->ident==iFUNCTN);
 13.4187 +      assert((sym->refer[i]->usage & uNATIVE)==0); /* a native function cannot refer to a user-function */
 13.4188 +      if (sym->refer[i]==sourcesym) {   /* recursion detection */
 13.4189 +        *recursion=1;
 13.4190 +        break;                          /* recursion was detected, quit loop */
 13.4191 +      } /* if */
 13.4192 +      size=max_stacksize_recurse(sourcesym,sym->refer[i],sym->x.stacksize,pubfuncparams,recursion);
 13.4193 +      if (maxsize<size)
 13.4194 +        maxsize=size;
 13.4195 +    } /* if */
 13.4196 +  } /* for */
 13.4197 +
 13.4198 +  if ((sym->usage & uPUBLIC)!=0) {
 13.4199 +    /* Find out how many parameters a public function has, then see if this
 13.4200 +     * is bigger than some maximum
 13.4201 +     */
 13.4202 +    arginfo *arg=sym->dim.arglist;
 13.4203 +    int count=0;
 13.4204 +    assert(arg!=0);
 13.4205 +    while (arg->ident!=0) {
 13.4206 +      count++;
 13.4207 +      arg++;
 13.4208 +    } /* while */
 13.4209 +    assert(pubfuncparams!=0);
 13.4210 +    if (count>*pubfuncparams)
 13.4211 +      *pubfuncparams=count;
 13.4212 +  } /* if */
 13.4213 +
 13.4214 +  return maxsize+basesize;
 13.4215 +}
 13.4216 +
 13.4217 +static long max_stacksize(symbol *root,int *recursion)
 13.4218 +{
 13.4219 +  /* Loop over all non-native functions. For each function, loop
 13.4220 +   * over all of its referrers, accumulating the stack requirements.
 13.4221 +   * Detect (indirect) recursion with a "mark-and-sweep" algorithm.
 13.4222 +   * I (mis-)use the "compound" field of the symbol structure for
 13.4223 +   * the marker, as this field is unused for functions.
 13.4224 +   *
 13.4225 +   * Note that the stack is shared with the heap. A host application
 13.4226 +   * may "eat" cells from the heap as well, through amx_Allot(). The
 13.4227 +   * stack requirements are thus only an estimate.
 13.4228 +   */
 13.4229 +  long size,maxsize;
 13.4230 +  int maxparams;
 13.4231 +  symbol *sym;
 13.4232 +
 13.4233 +  assert(root!=NULL);
 13.4234 +  assert(recursion!=NULL);
 13.4235 +  #if !defined NDEBUG
 13.4236 +    for (sym=root->next; sym!=NULL; sym=sym->next)
 13.4237 +      if (sym->ident==iFUNCTN)
 13.4238 +        assert(sym->compound==0);
 13.4239 +  #endif
 13.4240 +
 13.4241 +  maxsize=0;
 13.4242 +  maxparams=0;
 13.4243 +  *recursion=0;         /* assume no recursion */
 13.4244 +  for (sym=root->next; sym!=NULL; sym=sym->next) {
 13.4245 +    /* drop out if this is not a user-implemented function */
 13.4246 +    if (sym->ident!=iFUNCTN || (sym->usage & uNATIVE)!=0)
 13.4247 +      continue;
 13.4248 +    /* accumulate stack size for this symbol */
 13.4249 +    size=max_stacksize_recurse(sym,sym,0L,&maxparams,recursion);
 13.4250 +    assert(size>=0);
 13.4251 +    if (maxsize<size)
 13.4252 +      maxsize=size;
 13.4253 +  } /* for */
 13.4254 +
 13.4255 +  maxsize++;                  /* +1 because a zero cell is always pushed on top
 13.4256 +                               * of the stack to catch stack overwrites */
 13.4257 +  return maxsize+(maxparams+1);/* +1 because # of parameters is always pushed on entry */
 13.4258 +}
 13.4259 +#endif
 13.4260 +
 13.4261 +/*  testsymbols - test for unused local or global variables
 13.4262 + *
 13.4263 + *  "Public" functions are excluded from the check, since these
 13.4264 + *  may be exported to other object modules.
 13.4265 + *  Labels are excluded from the check if the argument 'testlabs'
 13.4266 + *  is 0. Thus, labels are not tested until the end of the function.
 13.4267 + *  Constants may also be excluded (convenient for global constants).
 13.4268 + *
 13.4269 + *  When the nesting level drops below "level", the check stops.
 13.4270 + *
 13.4271 + *  The function returns whether there is an "entry" point for the file.
 13.4272 + *  This flag will only be 1 when browsing the global symbol table.
 13.4273 + */
 13.4274 +static int testsymbols(symbol *root,int level,int testlabs,int testconst)
 13.4275 +{
 13.4276 +  char symname[2*sNAMEMAX+16];
 13.4277 +  int entry=FALSE;
 13.4278 +
 13.4279 +  symbol *sym=root->next;
 13.4280 +  while (sym!=NULL && sym->compound>=level) {
 13.4281 +    switch (sym->ident) {
 13.4282 +    case iLABEL:
 13.4283 +      if (testlabs) {
 13.4284 +        if ((sym->usage & uDEFINE)==0) {
 13.4285 +          error(19,sym->name);      /* not a label: ... */
 13.4286 +        } else if ((sym->usage & uREAD)==0) {
 13.4287 +          errorset(sSETPOS,sym->lnumber);
 13.4288 +          error(203,sym->name);     /* symbol isn't used: ... */
 13.4289 +        } /* if */
 13.4290 +      } /* if */
 13.4291 +      break;
 13.4292 +    case iFUNCTN:
 13.4293 +      if ((sym->usage & (uDEFINE | uREAD | uNATIVE | uSTOCK | uPUBLIC))==uDEFINE) {
 13.4294 +        funcdisplayname(symname,sym->name);
 13.4295 +        if (strlen(symname)>0)
 13.4296 +          error(203,symname);       /* symbol isn't used ... (and not public/native/stock) */
 13.4297 +      } /* if */
 13.4298 +      if ((sym->usage & uPUBLIC)!=0 || strcmp(sym->name,uMAINFUNC)==0)
 13.4299 +        entry=TRUE;                 /* there is an entry point */
 13.4300 +      /* also mark the function to the debug information */
 13.4301 +      if (((sym->usage & uREAD)!=0 || (sym->usage & uPUBLIC)!=0) && (sym->usage & uNATIVE)==0)
 13.4302 +        insert_dbgsymbol(sym);
 13.4303 +      break;
 13.4304 +    case iCONSTEXPR:
 13.4305 +      if (testconst && (sym->usage & uREAD)==0) {
 13.4306 +        errorset(sSETPOS,sym->lnumber);
 13.4307 +        error(203,sym->name);       /* symbol isn't used: ... */
 13.4308 +      } /* if */
 13.4309 +      break;
 13.4310 +    default:
 13.4311 +      /* a variable */
 13.4312 +      if (sym->parent!=NULL)
 13.4313 +        break;                      /* hierarchical data type */
 13.4314 +      if ((sym->usage & (uWRITTEN | uREAD | uSTOCK))==0) {
 13.4315 +        if (testconst)
 13.4316 +          errorset(sSETPOS,sym->lnumber);
 13.4317 +        error(203,sym->name,sym->lnumber);  /* symbol isn't used (and not stock) */
 13.4318 +      } else if ((sym->usage & (uREAD | uSTOCK | uPUBLIC))==0) {
 13.4319 +        errorset(sSETPOS,sym->lnumber);
 13.4320 +        error(204,sym->name);       /* value assigned to symbol is never used */
 13.4321 +#if 0 // ??? not sure whether it is a good idea to force people use "const"
 13.4322 +      } else if ((sym->usage & (uWRITTEN | uPUBLIC | uCONST))==0 && sym->ident==iREFARRAY) {
 13.4323 +        errorset(sSETPOS,sym->lnumber);
 13.4324 +        error(214,sym->name);       /* make array argument "const" */
 13.4325 +#endif
 13.4326 +      } /* if */
 13.4327 +      /* also mark the variable (local or global) to the debug information */
 13.4328 +      if ((sym->usage & (uWRITTEN | uREAD))!=0 && (sym->usage & uNATIVE)==0)
 13.4329 +        insert_dbgsymbol(sym);
 13.4330 +    } /* if */
 13.4331 +    sym=sym->next;
 13.4332 +  } /* while */
 13.4333 +
 13.4334 +  return entry;
 13.4335 +}
 13.4336 +
 13.4337 +static cell calc_array_datasize(symbol *sym, cell *offset)
 13.4338 +{
 13.4339 +  cell length;
 13.4340 +
 13.4341 +  assert(sym!=NULL);
 13.4342 +  assert(sym->ident==iARRAY || sym->ident==iREFARRAY);
 13.4343 +  length=sym->dim.array.length;
 13.4344 +  if (sym->dim.array.level > 0) {
 13.4345 +    cell sublength=calc_array_datasize(finddepend(sym),offset);
 13.4346 +    if (offset!=NULL)
 13.4347 +      *offset=length*(*offset+sizeof(cell));
 13.4348 +    if (sublength>0)
 13.4349 +      length*=length*sublength;
 13.4350 +    else
 13.4351 +      length=0;
 13.4352 +  } else {
 13.4353 +    if (offset!=NULL)
 13.4354 +      *offset=0;
 13.4355 +  } /* if */
 13.4356 +  return length;
 13.4357 +}
 13.4358 +
 13.4359 +static void destructsymbols(symbol *root,int level)
 13.4360 +{
 13.4361 +  cell offset=0;
 13.4362 +  int savepri=FALSE;
 13.4363 +  symbol *sym=root->next;
 13.4364 +  while (sym!=NULL && sym->compound>=level) {
 13.4365 +    if (sym->ident==iVARIABLE || sym->ident==iARRAY) {
 13.4366 +      char symbolname[16];
 13.4367 +      symbol *opsym;
 13.4368 +      cell elements;
 13.4369 +      /* check that the '~' operator is defined for this tag */
 13.4370 +      operator_symname(symbolname,"~",sym->tag,0,1,0);
 13.4371 +      if ((opsym=findglb(symbolname,sGLOBAL))!=NULL) {
 13.4372 +        /* save PRI, in case of a return statment */
 13.4373 +        if (!savepri) {
 13.4374 +          pushreg(sPRI);        /* right-hand operand is in PRI */
 13.4375 +          savepri=TRUE;
 13.4376 +        } /* if */
 13.4377 +        /* if the variable is an array, get the number of elements */
 13.4378 +        if (sym->ident==iARRAY) {
 13.4379 +          elements=calc_array_datasize(sym,&offset);
 13.4380 +          /* "elements" can be zero when the variable is declared like
 13.4381 +           *    new mytag: myvar[2][] = { {1, 2}, {3, 4} }
 13.4382 +           * one should declare all dimensions!
 13.4383 +           */
 13.4384 +          if (elements==0)
 13.4385 +            error(46,sym->name);        /* array size is unknown */
 13.4386 +        } else {
 13.4387 +          elements=1;
 13.4388 +          offset=0;
 13.4389 +        } /* if */
 13.4390 +        pushval(elements);
 13.4391 +        /* call the '~' operator */
 13.4392 +        address(sym,sPRI);
 13.4393 +        addconst(offset);       /* add offset to array data to the address */
 13.4394 +        pushreg(sPRI);
 13.4395 +        pushval(2*sizeof(cell));/* 2 parameters */
 13.4396 +        assert(opsym->ident==iFUNCTN);
 13.4397 +        ffcall(opsym,NULL,1);
 13.4398 +        if (sc_status!=statSKIP)
 13.4399 +          markusage(opsym,uREAD);   /* do not mark as "used" when this call itself is skipped */
 13.4400 +        if ((opsym->usage & uNATIVE)!=0 && opsym->x.lib!=NULL)
 13.4401 +          opsym->x.lib->value += 1; /* increment "usage count" of the library */
 13.4402 +      } /* if */
 13.4403 +    } /* if */
 13.4404 +    sym=sym->next;
 13.4405 +  } /* while */
 13.4406 +  /* restore PRI, if it was saved */
 13.4407 +  if (savepri)
 13.4408 +    popreg(sPRI);
 13.4409 +}
 13.4410 +
 13.4411 +static constvalue *insert_constval(constvalue *prev,constvalue *next,const char *name,cell val,
 13.4412 +                                   int index)
 13.4413 +{
 13.4414 +  constvalue *cur;
 13.4415 +
 13.4416 +  if ((cur=(constvalue*)malloc(sizeof(constvalue)))==NULL)
 13.4417 +    error(103);       /* insufficient memory (fatal error) */
 13.4418 +  memset(cur,0,sizeof(constvalue));
 13.4419 +  if (name!=NULL) {
 13.4420 +    assert(strlen(name)<sNAMEMAX);
 13.4421 +    strcpy(cur->name,name);
 13.4422 +  } /* if */
 13.4423 +  cur->value=val;
 13.4424 +  cur->index=index;
 13.4425 +  cur->next=next;
 13.4426 +  prev->next=cur;
 13.4427 +  return cur;
 13.4428 +}
 13.4429 +
 13.4430 +SC_FUNC constvalue *append_constval(constvalue *table,const char *name,cell val,int index)
 13.4431 +{
 13.4432 +  constvalue *cur,*prev;
 13.4433 +
 13.4434 +  /* find the end of the constant table */
 13.4435 +  for (prev=table, cur=table->next; cur!=NULL; prev=cur, cur=cur->next)
 13.4436 +    /* nothing */;
 13.4437 +  return insert_constval(prev,NULL,name,val,index);
 13.4438 +}
 13.4439 +
 13.4440 +SC_FUNC constvalue *find_constval(constvalue *table,char *name,int index)
 13.4441 +{
 13.4442 +  constvalue *ptr = table->next;
 13.4443 +
 13.4444 +  while (ptr!=NULL) {
 13.4445 +    if (strcmp(name,ptr->name)==0 && ptr->index==index)
 13.4446 +      return ptr;
 13.4447 +    ptr=ptr->next;
 13.4448 +  } /* while */
 13.4449 +  return NULL;
 13.4450 +}
 13.4451 +
 13.4452 +static constvalue *find_constval_byval(constvalue *table,cell val)
 13.4453 +{
 13.4454 +  constvalue *ptr = table->next;
 13.4455 +
 13.4456 +  while (ptr!=NULL) {
 13.4457 +    if (ptr->value==val)
 13.4458 +      return ptr;
 13.4459 +    ptr=ptr->next;
 13.4460 +  } /* while */
 13.4461 +  return NULL;
 13.4462 +}
 13.4463 +
 13.4464 +#if 0   /* never used */
 13.4465 +static int delete_constval(constvalue *table,char *name)
 13.4466 +{
 13.4467 +  constvalue *prev = table;
 13.4468 +  constvalue *cur = prev->next;
 13.4469 +
 13.4470 +  while (cur!=NULL) {
 13.4471 +    if (strcmp(name,cur->name)==0) {
 13.4472 +      prev->next=cur->next;
 13.4473 +      free(cur);
 13.4474 +      return TRUE;
 13.4475 +    } /* if */
 13.4476 +    prev=cur;
 13.4477 +    cur=cur->next;
 13.4478 +  } /* while */
 13.4479 +  return FALSE;
 13.4480 +}
 13.4481 +#endif
 13.4482 +
 13.4483 +SC_FUNC void delete_consttable(constvalue *table)
 13.4484 +{
 13.4485 +  constvalue *cur=table->next, *next;
 13.4486 +
 13.4487 +  while (cur!=NULL) {
 13.4488 +    next=cur->next;
 13.4489 +    free(cur);
 13.4490 +    cur=next;
 13.4491 +  } /* while */
 13.4492 +  memset(table,0,sizeof(constvalue));
 13.4493 +}
 13.4494 +
 13.4495 +/*  add_constant
 13.4496 + *
 13.4497 + *  Adds a symbol to the symbol table. Returns NULL on failure.
 13.4498 + */
 13.4499 +SC_FUNC symbol *add_constant(char *name,cell val,int vclass,int tag)
 13.4500 +{
 13.4501 +  symbol *sym;
 13.4502 +
 13.4503 +  /* Test whether a global or local symbol with the same name exists. Since
 13.4504 +   * constants are stored in the symbols table, this also finds previously
 13.4505 +   * defind constants. */
 13.4506 +  sym=findglb(name,sSTATEVAR);
 13.4507 +  if (!sym)
 13.4508 +    sym=findloc(name);
 13.4509 +  if (sym) {
 13.4510 +    int redef=0;
 13.4511 +    if (sym->ident!=iCONSTEXPR)
 13.4512 +      redef=1;                  /* redefinition a function/variable to a constant is not allowed */
 13.4513 +    if ((sym->usage & uENUMFIELD)!=0) {
 13.4514 +      /* enum field, special case if it has a different tag and the new symbol is also an enum field */
 13.4515 +      constvalue *tagid;
 13.4516 +      symbol *tagsym;
 13.4517 +      if (sym->tag==tag)
 13.4518 +        redef=1;                /* enumeration field is redefined (same tag) */
 13.4519 +      tagid=find_tag_byval(tag);
 13.4520 +      if (tagid==NULL) {
 13.4521 +        redef=1;                /* new constant does not have a tag */
 13.4522 +      } else {
 13.4523 +        tagsym=findconst(tagid->name,NULL);
 13.4524 +        if (tagsym==NULL || (tagsym->usage & uENUMROOT)==0)
 13.4525 +          redef=1;              /* new constant is not an enumeration field */
 13.4526 +      } /* if */
 13.4527 +      /* in this particular case (enumeration field that is part of a different
 13.4528 +       * enum, and non-conflicting with plain constants) we want to be able to
 13.4529 +       * redefine it
 13.4530 +       */
 13.4531 +      if (!redef)
 13.4532 +        goto redef_enumfield;
 13.4533 +    } else if (sym->tag!=tag) {
 13.4534 +      redef=1;                  /* redefinition of a constant (non-enum) to a different tag is not allowed */
 13.4535 +    } /* if */
 13.4536 +    if (redef) {
 13.4537 +      error(21,name);           /* symbol already defined */
 13.4538 +      return NULL;
 13.4539 +    } else if (sym->addr!=val) {
 13.4540 +      error(201,name);          /* redefinition of constant (different value) */
 13.4541 +      sym->addr=val;            /* set new value */
 13.4542 +    } /* if */
 13.4543 +    /* silently ignore redefinitions of constants with the same value & tag */
 13.4544 +    return sym;
 13.4545 +  } /* if */
 13.4546 +
 13.4547 +  /* constant doesn't exist yet (or is allowed to be redefined) */
 13.4548 +redef_enumfield:
 13.4549 +  sym=addsym(name,val,iCONSTEXPR,vclass,tag,uDEFINE);
 13.4550 +  assert(sym!=NULL);            /* fatal error 103 must be given on error */
 13.4551 +  if (sc_status == statIDLE)
 13.4552 +    sym->usage |= uPREDEF;
 13.4553 +  return sym;
 13.4554 +}
 13.4555 +
 13.4556 +/*  statement           - The Statement Parser
 13.4557 + *
 13.4558 + *  This routine is called whenever the parser needs to know what statement
 13.4559 + *  it encounters (i.e. whenever program syntax requires a statement).
 13.4560 + */
 13.4561 +static void statement(int *lastindent,int allow_decl)
 13.4562 +{
 13.4563 +  int tok;
 13.4564 +  cell val;
 13.4565 +  char *st;
 13.4566 +
 13.4567 +  if (!freading) {
 13.4568 +    error(36);                  /* empty statement */
 13.4569 +    return;
 13.4570 +  } /* if */
 13.4571 +  errorset(sRESET,0);
 13.4572 +
 13.4573 +  tok=lex(&val,&st);
 13.4574 +  if (tok!='{') {
 13.4575 +    insert_dbgline(fline);
 13.4576 +    setline(TRUE);
 13.4577 +  } /* if */
 13.4578 +  /* lex() has set stmtindent */
 13.4579 +  if (lastindent!=NULL && tok!=tLABEL) {
 13.4580 +    if (*lastindent>=0 && *lastindent!=stmtindent && !indent_nowarn && sc_tabsize>0)
 13.4581 +      error(217);               /* loose indentation */
 13.4582 +    *lastindent=stmtindent;
 13.4583 +    indent_nowarn=FALSE;        /* if warning was blocked, re-enable it */
 13.4584 +  } /* if */
 13.4585 +  switch (tok) {
 13.4586 +  case 0:
 13.4587 +    /* nothing */
 13.4588 +    break;
 13.4589 +  case tNEW:
 13.4590 +    if (allow_decl) {
 13.4591 +      declloc(FALSE);
 13.4592 +      lastst=tNEW;
 13.4593 +    } else {
 13.4594 +      error(3);                 /* declaration only valid in a block */
 13.4595 +    } /* if */
 13.4596 +    break;
 13.4597 +  case tSTATIC:
 13.4598 +    if (allow_decl) {
 13.4599 +      declloc(TRUE);
 13.4600 +      lastst=tNEW;
 13.4601 +    } else {
 13.4602 +      error(3);                 /* declaration only valid in a block */
 13.4603 +    } /* if */
 13.4604 +    break;
 13.4605 +  case '{':
 13.4606 +    tok=fline;
 13.4607 +    if (!matchtoken('}'))       /* {} is the empty statement */
 13.4608 +      compound(tok==fline);
 13.4609 +    /* lastst (for "last statement") does not change */
 13.4610 +    break;
 13.4611 +  case ';':
 13.4612 +    error(36);                  /* empty statement */
 13.4613 +    break;
 13.4614 +  case tIF:
 13.4615 +    doif();
 13.4616 +    lastst=tIF;
 13.4617 +    break;
 13.4618 +  case tWHILE:
 13.4619 +    dowhile();
 13.4620 +    lastst=tWHILE;
 13.4621 +    break;
 13.4622 +  case tDO:
 13.4623 +    dodo();
 13.4624 +    lastst=tDO;
 13.4625 +    break;
 13.4626 +  case tFOR:
 13.4627 +    dofor();
 13.4628 +    lastst=tFOR;
 13.4629 +    break;
 13.4630 +  case tSWITCH:
 13.4631 +    doswitch();
 13.4632 +    lastst=tSWITCH;
 13.4633 +    break;
 13.4634 +  case tCASE:
 13.4635 +  case tDEFAULT:
 13.4636 +    error(14);     /* not in switch */
 13.4637 +    break;
 13.4638 +  case tGOTO:
 13.4639 +    dogoto();
 13.4640 +    lastst=tGOTO;
 13.4641 +    break;
 13.4642 +  case tLABEL:
 13.4643 +    dolabel();
 13.4644 +    lastst=tLABEL;
 13.4645 +    break;
 13.4646 +  case tRETURN:
 13.4647 +    doreturn();
 13.4648 +    lastst=tRETURN;
 13.4649 +    break;
 13.4650 +  case tBREAK:
 13.4651 +    dobreak();
 13.4652 +    lastst=tBREAK;
 13.4653 +    break;
 13.4654 +  case tCONTINUE:
 13.4655 +    docont();
 13.4656 +    lastst=tCONTINUE;
 13.4657 +    break;
 13.4658 +  case tEXIT:
 13.4659 +    doexit();
 13.4660 +    lastst=tEXIT;
 13.4661 +    break;
 13.4662 +  case tASSERT:
 13.4663 +    doassert();
 13.4664 +    lastst=tASSERT;
 13.4665 +    break;
 13.4666 +  case tSLEEP:
 13.4667 +    dosleep();
 13.4668 +    lastst=tSLEEP;
 13.4669 +    break;
 13.4670 +  case tSTATE:
 13.4671 +    dostate();
 13.4672 +    lastst=tSTATE;
 13.4673 +    break;
 13.4674 +  case tCONST:
 13.4675 +    decl_const(sLOCAL);
 13.4676 +    break;
 13.4677 +  case tENUM:
 13.4678 +    decl_enum(sLOCAL);
 13.4679 +    break;
 13.4680 +  default:          /* non-empty expression */
 13.4681 +    sc_allowproccall=optproccall;
 13.4682 +    lexpush();      /* analyze token later */
 13.4683 +    doexpr(TRUE,TRUE,TRUE,TRUE,NULL,NULL,FALSE);
 13.4684 +    needtoken(tTERM);
 13.4685 +    lastst=tEXPR;
 13.4686 +    sc_allowproccall=FALSE;
 13.4687 +  } /* switch */
 13.4688 +}
 13.4689 +
 13.4690 +static void compound(int stmt_sameline)
 13.4691 +{
 13.4692 +  int indent=-1;
 13.4693 +  cell save_decl=declared;
 13.4694 +  int count_stmt=0;
 13.4695 +  int block_start=fline;  /* save line where the compound block started */
 13.4696 +
 13.4697 +  /* if there is more text on this line, we should adjust the statement indent */
 13.4698 +  if (stmt_sameline) {
 13.4699 +    int i;
 13.4700 +    const unsigned char *p=lptr;
 13.4701 +    /* go back to the opening brace */
 13.4702 +    while (*p!='{') {
 13.4703 +      assert(p>pline);
 13.4704 +      p--;
 13.4705 +    } /* while */
 13.4706 +    assert(*p=='{');  /* it should be found */
 13.4707 +    /* go forward, skipping white-space */
 13.4708 +    p++;
 13.4709 +    while (*p<=' ' && *p!='\0')
 13.4710 +      p++;
 13.4711 +    assert(*p!='\0'); /* a token should be found */
 13.4712 +    stmtindent=0;
 13.4713 +    for (i=0; i<(int)(p-pline); i++)
 13.4714 +      if (pline[i]=='\t' && sc_tabsize>0)
 13.4715 +        stmtindent += (int)(sc_tabsize - (stmtindent+sc_tabsize) % sc_tabsize);
 13.4716 +      else
 13.4717 +        stmtindent++;
 13.4718 +  } /* if */
 13.4719 +
 13.4720 +  nestlevel+=1;                 /* increase compound statement level */
 13.4721 +  while (matchtoken('}')==0){   /* repeat until compound statement is closed */
 13.4722 +    if (!freading){
 13.4723 +      error(30,block_start);    /* compound block not closed at end of file */
 13.4724 +      break;
 13.4725 +    } else {
 13.4726 +      if (count_stmt>0 && (lastst==tRETURN || lastst==tBREAK || lastst==tCONTINUE))
 13.4727 +        error(225);             /* unreachable code */
 13.4728 +      statement(&indent,TRUE);  /* do a statement */
 13.4729 +      count_stmt++;
 13.4730 +    } /* if */
 13.4731 +  } /* while */
 13.4732 +  if (lastst!=tRETURN)
 13.4733 +    destructsymbols(&loctab,nestlevel);
 13.4734 +  if (lastst!=tRETURN && lastst!=tGOTO)
 13.4735 +    modstk((int)(declared-save_decl)*sizeof(cell)); /* delete local variable space */
 13.4736 +  testsymbols(&loctab,nestlevel,FALSE,TRUE);        /* look for unused block locals */
 13.4737 +  declared=save_decl;
 13.4738 +  delete_symbols(&loctab,nestlevel,FALSE,TRUE);     /* erase local symbols, but
 13.4739 +                                                     * retain block local labels
 13.4740 +                                                     * (within the function) */
 13.4741 +  nestlevel-=1;                 /* decrease compound statement level */
 13.4742 +}
 13.4743 +
 13.4744 +/*  doexpr
 13.4745 + *
 13.4746 + *  Global references: stgidx   (referred to only)
 13.4747 + */
 13.4748 +static int doexpr(int comma,int chkeffect,int allowarray,int mark_endexpr,
 13.4749 +                  int *tag,symbol **symptr,int chkfuncresult)
 13.4750 +{
 13.4751 +  int index,ident;
 13.4752 +  int localstaging=FALSE;
 13.4753 +  cell val;
 13.4754 +
 13.4755 +  if (!staging) {
 13.4756 +    stgset(TRUE);               /* start stage-buffering */
 13.4757 +    localstaging=TRUE;
 13.4758 +    assert(stgidx==0);
 13.4759 +  } /* if */
 13.4760 +  index=stgidx;
 13.4761 +  errorset(sEXPRMARK,0);
 13.4762 +  do {
 13.4763 +    /* on second round through, mark the end of the previous expression */
 13.4764 +    if (index!=stgidx)
 13.4765 +      markexpr(sEXPR,NULL,0);
 13.4766 +    sideeffect=FALSE;
 13.4767 +    ident=expression(&val,tag,symptr,chkfuncresult);
 13.4768 +    if (!allowarray && (ident==iARRAY || ident==iREFARRAY))
 13.4769 +      error(33,"-unknown-");    /* array must be indexed */
 13.4770 +    if (chkeffect && !sideeffect)
 13.4771 +      error(215);               /* expression has no effect */
 13.4772 +    sc_allowproccall=FALSE;     /* cannot use "procedure call" syntax anymore */
 13.4773 +  } while (comma && matchtoken(',')); /* more? */
 13.4774 +  if (mark_endexpr)
 13.4775 +    markexpr(sEXPR,NULL,0);     /* optionally, mark the end of the expression */
 13.4776 +  errorset(sEXPRRELEASE,0);
 13.4777 +  if (localstaging) {
 13.4778 +    stgout(index);
 13.4779 +    stgset(FALSE);              /* stop staging */
 13.4780 +  } /* if */
 13.4781 +  return ident;
 13.4782 +}
 13.4783 +
 13.4784 +/*  constexpr
 13.4785 + */
 13.4786 +SC_FUNC int constexpr(cell *val,int *tag,symbol **symptr)
 13.4787 +{
 13.4788 +  int ident,index;
 13.4789 +  cell cidx;
 13.4790 +
 13.4791 +  stgset(TRUE);         /* start stage-buffering */
 13.4792 +  stgget(&index,&cidx); /* mark position in code generator */
 13.4793 +  errorset(sEXPRMARK,0);
 13.4794 +  ident=expression(val,tag,symptr,FALSE);
 13.4795 +  stgdel(index,cidx);   /* scratch generated code */
 13.4796 +  stgset(FALSE);        /* stop stage-buffering */
 13.4797 +  if (ident!=iCONSTEXPR) {
 13.4798 +    error(8);           /* must be constant expression */
 13.4799 +    if (val!=NULL)
 13.4800 +      *val=0;
 13.4801 +    if (tag!=NULL)
 13.4802 +      *tag=0;
 13.4803 +    if (symptr!=NULL)
 13.4804 +      *symptr=NULL;
 13.4805 +  } /* if */
 13.4806 +  errorset(sEXPRRELEASE,0);
 13.4807 +  return (ident==iCONSTEXPR);
 13.4808 +}
 13.4809 +
 13.4810 +/*  test
 13.4811 + *
 13.4812 + *  In the case a "simple assignment" operator ("=") is used within a test,
 13.4813 + *  the warning "possibly unintended assignment" is displayed. This routine
 13.4814 + *  sets the global variable "sc_intest" to true, it is restored upon termination.
 13.4815 + *  In the case the assignment was intended, use parantheses around the
 13.4816 + *  expression to avoid the warning; primary() sets "sc_intest" to 0.
 13.4817 + *
 13.4818 + *  Global references: sc_intest (altered, but restored upon termination)
 13.4819 + */
 13.4820 +static void test(int label,int parens,int invert)
 13.4821 +{
 13.4822 +  int index,tok;
 13.4823 +  cell cidx;
 13.4824 +  int ident,tag;
 13.4825 +  cell constval;
 13.4826 +  symbol *sym;
 13.4827 +  int localstaging=FALSE;
 13.4828 +
 13.4829 +  if (!staging) {
 13.4830 +    stgset(TRUE);               /* start staging */
 13.4831 +    localstaging=TRUE;
 13.4832 +    #if !defined NDEBUG
 13.4833 +      stgget(&index,&cidx);     /* should start at zero if started locally */
 13.4834 +      assert(index==0);
 13.4835 +    #endif
 13.4836 +  } /* if */
 13.4837 +
 13.4838 +  PUSHSTK_I(sc_intest);
 13.4839 +  sc_intest=TRUE;
 13.4840 +  if (parens)
 13.4841 +    needtoken('(');
 13.4842 +  do {
 13.4843 +    stgget(&index,&cidx);       /* mark position (of last expression) in
 13.4844 +                                 * code generator */
 13.4845 +    ident=expression(&constval,&tag,&sym,TRUE);
 13.4846 +    tok=matchtoken(',');
 13.4847 +    if (tok)
 13.4848 +      markexpr(sEXPR,NULL,0);
 13.4849 +  } while (tok); /* do */
 13.4850 +  if (parens)
 13.4851 +    needtoken(')');
 13.4852 +  if (ident==iARRAY || ident==iREFARRAY) {
 13.4853 +    char *ptr=(sym->name!=NULL) ? sym->name : "-unknown-";
 13.4854 +    error(33,ptr);              /* array must be indexed */
 13.4855 +  } /* if */
 13.4856 +  if (ident==iCONSTEXPR) {      /* constant expression */
 13.4857 +    sc_intest=(short)POPSTK_I();/* restore stack */
 13.4858 +    stgdel(index,cidx);
 13.4859 +    if (constval) {             /* code always executed */
 13.4860 +      error(206);               /* redundant test: always non-zero */
 13.4861 +    } else {
 13.4862 +      error(205);               /* redundant code: never executed */
 13.4863 +      jumplabel(label);
 13.4864 +    } /* if */
 13.4865 +    if (localstaging) {
 13.4866 +      stgout(0);                /* write "jumplabel" code */
 13.4867 +      stgset(FALSE);            /* stop staging */
 13.4868 +    } /* if */
 13.4869 +    return;
 13.4870 +  } /* if */
 13.4871 +  if (tag!=0 && tag!=pc_addtag("bool"))
 13.4872 +    if (check_userop(lneg,tag,0,1,NULL,&tag))
 13.4873 +      invert= !invert;          /* user-defined ! operator inverted result */
 13.4874 +  if (invert)
 13.4875 +    jmp_ne0(label);             /* jump to label if true (different from 0) */
 13.4876 +  else
 13.4877 +    jmp_eq0(label);             /* jump to label if false (equal to 0) */
 13.4878 +  markexpr(sEXPR,NULL,0);       /* end expression (give optimizer a chance) */
 13.4879 +  sc_intest=(short)POPSTK_I();  /* double typecast to avoid warning with Microsoft C */
 13.4880 +  if (localstaging) {
 13.4881 +    stgout(0);                  /* output queue from the very beginning (see
 13.4882 +                                 * assert() when localstaging is set to TRUE) */
 13.4883 +    stgset(FALSE);              /* stop staging */
 13.4884 +  } /* if */
 13.4885 +}
 13.4886 +
 13.4887 +static void doif(void)
 13.4888 +{
 13.4889 +  int flab1,flab2;
 13.4890 +  int ifindent;
 13.4891 +
 13.4892 +  ifindent=stmtindent;          /* save the indent of the "if" instruction */
 13.4893 +  flab1=getlabel();             /* get label number for false branch */
 13.4894 +  test(flab1,TRUE,FALSE);       /* get expression, branch to flab1 if false */
 13.4895 +  statement(NULL,FALSE);        /* if true, do a statement */
 13.4896 +  if (matchtoken(tELSE)==0){    /* if...else ? */
 13.4897 +    setlabel(flab1);            /* no, simple if..., print false label */
 13.4898 +  } else {
 13.4899 +    /* to avoid the "dangling else" error, we want a warning if the "else"
 13.4900 +     * has a lower indent than the matching "if" */
 13.4901 +    if (stmtindent<ifindent && sc_tabsize>0)
 13.4902 +      error(217);               /* loose indentation */
 13.4903 +    flab2=getlabel();
 13.4904 +    if ((lastst!=tRETURN) && (lastst!=tGOTO))
 13.4905 +      jumplabel(flab2);
 13.4906 +    setlabel(flab1);            /* print false label */
 13.4907 +    statement(NULL,FALSE);      /* do "else" clause */
 13.4908 +    setlabel(flab2);            /* print true label */
 13.4909 +  } /* endif */
 13.4910 +}
 13.4911 +
 13.4912 +static void dowhile(void)
 13.4913 +{
 13.4914 +  int wq[wqSIZE];               /* allocate local queue */
 13.4915 +
 13.4916 +  addwhile(wq);                 /* add entry to queue for "break" */
 13.4917 +  setlabel(wq[wqLOOP]);         /* loop label */
 13.4918 +  /* The debugger uses the "break" opcode to be able to "break" out of
 13.4919 +   * a loop. To make sure that each loop has a break opcode, even for the
 13.4920 +   * tiniest loop, set it below the top of the loop
 13.4921 +   */
 13.4922 +  setline(TRUE);
 13.4923 +  test(wq[wqEXIT],TRUE,FALSE);  /* branch to wq[wqEXIT] if false */
 13.4924 +  statement(NULL,FALSE);        /* if so, do a statement */
 13.4925 +  jumplabel(wq[wqLOOP]);        /* and loop to "while" start */
 13.4926 +  setlabel(wq[wqEXIT]);         /* exit label */
 13.4927 +  delwhile();                   /* delete queue entry */
 13.4928 +}
 13.4929 +
 13.4930 +/*
 13.4931 + *  Note that "continue" will in this case not jump to the top of the loop, but
 13.4932 + *  to the end: just before the TRUE-or-FALSE testing code.
 13.4933 + */
 13.4934 +static void dodo(void)
 13.4935 +{
 13.4936 +  int wq[wqSIZE],top;
 13.4937 +
 13.4938 +  addwhile(wq);           /* see "dowhile" for more info */
 13.4939 +  top=getlabel();         /* make a label first */
 13.4940 +  setlabel(top);          /* loop label */
 13.4941 +  statement(NULL,FALSE);
 13.4942 +  needtoken(tWHILE);
 13.4943 +  setlabel(wq[wqLOOP]);   /* "continue" always jumps to WQLOOP. */
 13.4944 +  setline(TRUE);
 13.4945 +  test(wq[wqEXIT],TRUE,FALSE);
 13.4946 +  jumplabel(top);
 13.4947 +  setlabel(wq[wqEXIT]);
 13.4948 +  delwhile();
 13.4949 +  needtoken(tTERM);
 13.4950 +}
 13.4951 +
 13.4952 +static void dofor(void)
 13.4953 +{
 13.4954 +  int wq[wqSIZE],skiplab;
 13.4955 +  cell save_decl;
 13.4956 +  int save_nestlevel,index;
 13.4957 +  int *ptr;
 13.4958 +
 13.4959 +  save_decl=declared;
 13.4960 +  save_nestlevel=nestlevel;
 13.4961 +
 13.4962 +  addwhile(wq);
 13.4963 +  skiplab=getlabel();
 13.4964 +  needtoken('(');
 13.4965 +  if (matchtoken(';')==0) {
 13.4966 +    /* new variable declarations are allowed here */
 13.4967 +    if (matchtoken(tNEW)) {
 13.4968 +      /* The variable in expr1 of the for loop is at a
 13.4969 +       * 'compound statement' level of it own.
 13.4970 +       */
 13.4971 +      nestlevel++;
 13.4972 +      declloc(FALSE); /* declare local variable */
 13.4973 +    } else {
 13.4974 +      doexpr(TRUE,TRUE,TRUE,TRUE,NULL,NULL,FALSE);  /* expression 1 */
 13.4975 +      needtoken(';');
 13.4976 +    } /* if */
 13.4977 +  } /* if */
 13.4978 +  /* Adjust the "declared" field in the "while queue", in case that
 13.4979 +   * local variables were declared in the first expression of the
 13.4980 +   * "for" loop. These are deleted in separately, so a "break" or a "continue"
 13.4981 +   * must ignore these fields.
 13.4982 +   */
 13.4983 +  ptr=readwhile();
 13.4984 +  assert(ptr!=NULL);
 13.4985 +  ptr[wqBRK]=(int)declared;
 13.4986 +  ptr[wqCONT]=(int)declared;
 13.4987 +  jumplabel(skiplab);               /* skip expression 3 1st time */
 13.4988 +  setlabel(wq[wqLOOP]);             /* "continue" goes to this label: expr3 */
 13.4989 +  setline(TRUE);
 13.4990 +  /* Expressions 2 and 3 are reversed in the generated code: expression 3
 13.4991 +   * precedes expression 2. When parsing, the code is buffered and marks for
 13.4992 +   * the start of each expression are insterted in the buffer.
 13.4993 +   */
 13.4994 +  assert(!staging);
 13.4995 +  stgset(TRUE);                     /* start staging */
 13.4996 +  assert(stgidx==0);
 13.4997 +  index=stgidx;
 13.4998 +  stgmark(sSTARTREORDER);
 13.4999 +  stgmark((char)(sEXPRSTART+0));    /* mark start of 2nd expression in stage */
 13.5000 +  setlabel(skiplab);                /* jump to this point after 1st expression */
 13.5001 +  if (matchtoken(';')==0) {
 13.5002 +    test(wq[wqEXIT],FALSE,FALSE);   /* expression 2 (jump to wq[wqEXIT] if false) */
 13.5003 +    needtoken(';');
 13.5004 +  } /* if */
 13.5005 +  stgmark((char)(sEXPRSTART+1));    /* mark start of 3th expression in stage */
 13.5006 +  if (matchtoken(')')==0) {
 13.5007 +    doexpr(TRUE,TRUE,TRUE,TRUE,NULL,NULL,FALSE);    /* expression 3 */
 13.5008 +    needtoken(')');
 13.5009 +  } /* if */
 13.5010 +  stgmark(sENDREORDER);             /* mark end of reversed evaluation */
 13.5011 +  stgout(index);
 13.5012 +  stgset(FALSE);                    /* stop staging */
 13.5013 +  statement(NULL,FALSE);
 13.5014 +  jumplabel(wq[wqLOOP]);
 13.5015 +  setlabel(wq[wqEXIT]);
 13.5016 +  delwhile();
 13.5017 +
 13.5018 +  assert(nestlevel>=save_nestlevel);
 13.5019 +  if (nestlevel>save_nestlevel) {
 13.5020 +    /* Clean up the space and the symbol table for the local
 13.5021 +     * variable in "expr1".
 13.5022 +     */
 13.5023 +    destructsymbols(&loctab,nestlevel);
 13.5024 +    modstk((int)(declared-save_decl)*sizeof(cell));
 13.5025 +    testsymbols(&loctab,nestlevel,FALSE,TRUE);  /* look for unused block locals */
 13.5026 +    declared=save_decl;
 13.5027 +    delete_symbols(&loctab,nestlevel,FALSE,TRUE);
 13.5028 +    nestlevel=save_nestlevel;     /* reset 'compound statement' nesting level */
 13.5029 +  } /* if */
 13.5030 +}
 13.5031 +
 13.5032 +/* The switch statement is incompatible with its C sibling:
 13.5033 + * 1. the cases are not drop through
 13.5034 + * 2. only one instruction may appear below each case, use a compound
 13.5035 + *    instruction to execute multiple instructions
 13.5036 + * 3. the "case" keyword accepts a comma separated list of values to
 13.5037 + *    match, it also accepts a range using the syntax "1 .. 4"
 13.5038 + *
 13.5039 + * SWITCH param
 13.5040 + *   PRI = expression result
 13.5041 + *   param = table offset (code segment)
 13.5042 + *
 13.5043 + */
 13.5044 +static void doswitch(void)
 13.5045 +{
 13.5046 +  int lbl_table,lbl_exit,lbl_case;
 13.5047 +  int tok,swdefault,casecount;
 13.5048 +  cell val;
 13.5049 +  char *str;
 13.5050 +  constvalue caselist = { NULL, "", 0, 0};   /* case list starts empty */
 13.5051 +  constvalue *cse,*csp;
 13.5052 +  char labelname[sNAMEMAX+1];
 13.5053 +
 13.5054 +  needtoken('(');
 13.5055 +  doexpr(TRUE,FALSE,FALSE,FALSE,NULL,NULL,TRUE);/* evaluate switch expression */
 13.5056 +  needtoken(')');
 13.5057 +  /* generate the code for the switch statement, the label is the address
 13.5058 +   * of the case table (to be generated later).
 13.5059 +   */
 13.5060 +  lbl_table=getlabel();
 13.5061 +  lbl_case=0;                   /* just to avoid a compiler warning */
 13.5062 +  ffswitch(lbl_table);
 13.5063 +
 13.5064 +  needtoken('{');
 13.5065 +  lbl_exit=getlabel();          /* get label number for jumping out of switch */
 13.5066 +  swdefault=FALSE;
 13.5067 +  casecount=0;
 13.5068 +  do {
 13.5069 +    tok=lex(&val,&str);         /* read in (new) token */
 13.5070 +    switch (tok) {
 13.5071 +    case tCASE:
 13.5072 +      if (swdefault!=FALSE)
 13.5073 +        error(15);        /* "default" case must be last in switch statement */
 13.5074 +      lbl_case=getlabel();
 13.5075 +      PUSHSTK_I(sc_allowtags);
 13.5076 +      sc_allowtags=FALSE; /* do not allow tagnames here */
 13.5077 +      do {
 13.5078 +        casecount++;
 13.5079 +
 13.5080 +        /* ??? enforce/document that, in a switch, a statement cannot start
 13.5081 +         *     with a label. Then, you can search for:
 13.5082 +         *     * the first semicolon (marks the end of a statement)
 13.5083 +         *     * an opening brace (marks the start of a compound statement)
 13.5084 +         *     and search for the right-most colon before that statement
 13.5085 +         *     Now, by replacing the ':' by a special COLON token, you can
 13.5086 +         *     parse all expressions until that special token.
 13.5087 +         */
 13.5088 +
 13.5089 +        constexpr(&val,NULL,NULL);
 13.5090 +        /* Search the insertion point (the table is kept in sorted order, so
 13.5091 +         * that advanced abstract machines can sift the case table with a
 13.5092 +         * binary search). Check for duplicate case values at the same time.
 13.5093 +         */
 13.5094 +        for (csp=&caselist, cse=caselist.next;
 13.5095 +             cse!=NULL && cse->value<val;
 13.5096 +             csp=cse, cse=cse->next)
 13.5097 +          /* nothing */;
 13.5098 +        if (cse!=NULL && cse->value==val)
 13.5099 +          error(40,val);                /* duplicate "case" label */
 13.5100 +        /* Since the label is stored as a string in the "constvalue", the
 13.5101 +         * size of an identifier must be at least 8, as there are 8
 13.5102 +         * hexadecimal digits in a 32-bit number.
 13.5103 +         */
 13.5104 +        #if sNAMEMAX < 8
 13.5105 +          #error Length of identifier (sNAMEMAX) too small.
 13.5106 +        #endif
 13.5107 +        assert(csp!=NULL);
 13.5108 +        assert(csp->next==cse);
 13.5109 +        insert_constval(csp,cse,itoh(lbl_case),val,0);
 13.5110 +        if (matchtoken(tDBLDOT)) {
 13.5111 +          cell end;
 13.5112 +          constexpr(&end,NULL,NULL);
 13.5113 +          if (end<=val)
 13.5114 +            error(50);                  /* invalid range */
 13.5115 +          while (++val<=end) {
 13.5116 +            casecount++;
 13.5117 +            /* find the new insertion point */
 13.5118 +            for (csp=&caselist, cse=caselist.next;
 13.5119 +                 cse!=NULL && cse->value<val;
 13.5120 +                 csp=cse, cse=cse->next)
 13.5121 +              /* nothing */;
 13.5122 +            if (cse!=NULL && cse->value==val)
 13.5123 +              error(40,val);            /* duplicate "case" label */
 13.5124 +            assert(csp!=NULL);
 13.5125 +            assert(csp->next==cse);
 13.5126 +            insert_constval(csp,cse,itoh(lbl_case),val,0);
 13.5127 +          } /* if */
 13.5128 +        } /* if */
 13.5129 +      } while (matchtoken(','));
 13.5130 +      needtoken(':');                   /* ':' ends the case */
 13.5131 +      sc_allowtags=(short)POPSTK_I();   /* reset */
 13.5132 +      setlabel(lbl_case);
 13.5133 +      statement(NULL,FALSE);
 13.5134 +      jumplabel(lbl_exit);
 13.5135 +      break;
 13.5136 +    case tDEFAULT:
 13.5137 +      if (swdefault!=FALSE)
 13.5138 +        error(16);         /* multiple defaults in switch */
 13.5139 +      lbl_case=getlabel();
 13.5140 +      setlabel(lbl_case);
 13.5141 +      needtoken(':');
 13.5142 +      swdefault=TRUE;
 13.5143 +      statement(NULL,FALSE);
 13.5144 +      /* Jump to lbl_exit, even thouh this is the last clause in the
 13.5145 +       * switch, because the jump table is generated between the last
 13.5146 +       * clause of the switch and the exit label.
 13.5147 +       */
 13.5148 +      jumplabel(lbl_exit);
 13.5149 +      break;
 13.5150 +    case '}':
 13.5151 +      /* nothing, but avoid dropping into "default" */
 13.5152 +      break;
 13.5153 +    default:
 13.5154 +      error(2);
 13.5155 +      indent_nowarn=TRUE; /* disable this check */
 13.5156 +      tok='}';          /* break out of the loop after an error */
 13.5157 +    } /* switch */
 13.5158 +  } while (tok!='}');
 13.5159 +
 13.5160 +  #if !defined NDEBUG
 13.5161 +    /* verify that the case table is sorted (unfortunatly, duplicates can
 13.5162 +     * occur; there really shouldn't be duplicate cases, but the compiler
 13.5163 +     * may not crash or drop into an assertion for a user error). */
 13.5164 +    for (cse=caselist.next; cse!=NULL && cse->next!=NULL; cse=cse->next)
 13.5165 +      assert(cse->value <= cse->next->value);
 13.5166 +  #endif
 13.5167 +  /* generate the table here, before lbl_exit (general jump target) */
 13.5168 +  setlabel(lbl_table);
 13.5169 +  assert(swdefault==FALSE || swdefault==TRUE);
 13.5170 +  if (swdefault==FALSE) {
 13.5171 +    /* store lbl_exit as the "none-matched" label in the switch table */
 13.5172 +    strcpy(labelname,itoh(lbl_exit));
 13.5173 +  } else {
 13.5174 +    /* lbl_case holds the label of the "default" clause */
 13.5175 +    strcpy(labelname,itoh(lbl_case));
 13.5176 +  } /* if */
 13.5177 +  ffcase(casecount,labelname,TRUE);
 13.5178 +  /* generate the rest of the table */
 13.5179 +  for (cse=caselist.next; cse!=NULL; cse=cse->next)
 13.5180 +    ffcase(cse->value,cse->name,FALSE);
 13.5181 +
 13.5182 +  setlabel(lbl_exit);
 13.5183 +  delete_consttable(&caselist); /* clear list of case labels */
 13.5184 +}
 13.5185 +
 13.5186 +static void doassert(void)
 13.5187 +{
 13.5188 +  int flab1,index;
 13.5189 +  cell cidx;
 13.5190 +
 13.5191 +  if ((sc_debug & sCHKBOUNDS)!=0) {
 13.5192 +    flab1=getlabel();           /* get label number for "OK" branch */
 13.5193 +    test(flab1,FALSE,TRUE);     /* get expression and branch to flab1 if true */
 13.5194 +    insert_dbgline(fline);      /* make sure we can find the correct line number */
 13.5195 +    ffabort(xASSERTION);
 13.5196 +    setlabel(flab1);
 13.5197 +  } else {
 13.5198 +    stgset(TRUE);               /* start staging */
 13.5199 +    stgget(&index,&cidx);       /* mark position in code generator */
 13.5200 +    do {
 13.5201 +      expression(NULL,NULL,NULL,FALSE);
 13.5202 +      stgdel(index,cidx);       /* just scrap the code */
 13.5203 +    } while (matchtoken(','));
 13.5204 +    stgset(FALSE);              /* stop staging */
 13.5205 +  } /* if */
 13.5206 +  needtoken(tTERM);
 13.5207 +}
 13.5208 +
 13.5209 +static void dogoto(void)
 13.5210 +{
 13.5211 +  char *st;
 13.5212 +  cell val;
 13.5213 +  symbol *sym;
 13.5214 +
 13.5215 +  if (lex(&val,&st)==tSYMBOL) {
 13.5216 +    sym=fetchlab(st);
 13.5217 +    jumplabel((int)sym->addr);
 13.5218 +    sym->usage|=uREAD;  /* set "uREAD" bit */
 13.5219 +    // ??? if the label is defined (check sym->usage & uDEFINE), check
 13.5220 +    //     sym->compound (nesting level of the label) against nestlevel;
 13.5221 +    //     if sym->compound < nestlevel, call the destructor operator
 13.5222 +  } else {
 13.5223 +    error(20,st);       /* illegal symbol name */
 13.5224 +  } /* if */
 13.5225 +  needtoken(tTERM);
 13.5226 +}
 13.5227 +
 13.5228 +static void dolabel(void)
 13.5229 +{
 13.5230 +  char *st;
 13.5231 +  cell val;
 13.5232 +  symbol *sym;
 13.5233 +
 13.5234 +  tokeninfo(&val,&st);  /* retrieve label name again */
 13.5235 +  if (find_constval(&tagname_tab,st,0)!=NULL)
 13.5236 +    error(221,st);      /* label name shadows tagname */
 13.5237 +  sym=fetchlab(st);
 13.5238 +  setlabel((int)sym->addr);
 13.5239 +  /* since one can jump around variable declarations or out of compound
 13.5240 +   * blocks, the stack must be manually adjusted
 13.5241 +   */
 13.5242 +  setstk(-declared*sizeof(cell));
 13.5243 +  sym->usage|=uDEFINE;  /* label is now defined */
 13.5244 +}
 13.5245 +
 13.5246 +/*  fetchlab
 13.5247 + *
 13.5248 + *  Finds a label from the (local) symbol table or adds one to it.
 13.5249 + *  Labels are local in scope.
 13.5250 + *
 13.5251 + *  Note: The "_usage" bit is set to zero. The routines that call "fetchlab()"
 13.5252 + *        must set this bit accordingly.
 13.5253 + */
 13.5254 +static symbol *fetchlab(char *name)
 13.5255 +{
 13.5256 +  symbol *sym;
 13.5257 +
 13.5258 +  sym=findloc(name);            /* labels are local in scope */
 13.5259 +  if (sym){
 13.5260 +    if (sym->ident!=iLABEL)
 13.5261 +      error(19,sym->name);      /* not a label: ... */
 13.5262 +  } else {
 13.5263 +    sym=addsym(name,getlabel(),iLABEL,sLOCAL,0,0);
 13.5264 +    assert(sym!=NULL);          /* fatal error 103 must be given on error */
 13.5265 +    sym->x.declared=(int)declared;
 13.5266 +    sym->compound=nestlevel;
 13.5267 +  } /* if */
 13.5268 +  return sym;
 13.5269 +}
 13.5270 +
 13.5271 +/*  doreturn
 13.5272 + *
 13.5273 + *  Global references: rettype  (altered)
 13.5274 + */
 13.5275 +static void doreturn(void)
 13.5276 +{
 13.5277 +  int tag,ident;
 13.5278 +  int level;
 13.5279 +  symbol *sym,*sub;
 13.5280 +
 13.5281 +  if (!matchtoken(tTERM)) {
 13.5282 +    /* "return <value>" */
 13.5283 +    if ((rettype & uRETNONE)!=0)
 13.5284 +      error(78);                        /* mix "return;" and "return value;" */
 13.5285 +    ident=doexpr(TRUE,FALSE,TRUE,TRUE,&tag,&sym,TRUE);
 13.5286 +    needtoken(tTERM);
 13.5287 +    /* see if this function already has a sub type (an array attached) */
 13.5288 +    sub=finddepend(curfunc);
 13.5289 +    assert(sub==NULL || sub->ident==iREFARRAY);
 13.5290 +    if ((rettype & uRETVALUE)!=0) {
 13.5291 +      int retarray=(ident==iARRAY || ident==iREFARRAY);
 13.5292 +      /* there was an earlier "return" statement in this function */
 13.5293 +      if (sub==NULL && retarray || sub!=NULL && !retarray)
 13.5294 +        error(79);                      /* mixing "return array;" and "return value;" */
 13.5295 +      if (retarray && (curfunc->usage & uPUBLIC)!=0)
 13.5296 +        error(90,curfunc->name);        /* public function may not return array */
 13.5297 +    } /* if */
 13.5298 +    rettype|=uRETVALUE;                 /* function returns a value */
 13.5299 +    /* check tagname with function tagname */
 13.5300 +    assert(curfunc!=NULL);
 13.5301 +    if (!matchtag(curfunc->tag,tag,TRUE))
 13.5302 +      error(213);                       /* tagname mismatch */
 13.5303 +    if (ident==iARRAY || ident==iREFARRAY) {
 13.5304 +      int dim[sDIMEN_MAX],numdim;
 13.5305 +      cell arraysize;
 13.5306 +      assert(sym!=NULL);
 13.5307 +      if (sub!=NULL) {
 13.5308 +        assert(sub->ident==iREFARRAY);
 13.5309 +        /* this function has an array attached already; check that the current
 13.5310 +         * "return" statement returns exactly the same array
 13.5311 +         */
 13.5312 +        level=sym->dim.array.level;
 13.5313 +        if (sub->dim.array.level!=level) {
 13.5314 +          error(48);                    /* array dimensions must match */
 13.5315 +        } else {
 13.5316 +          for (numdim=0; numdim<=level; numdim++) {
 13.5317 +            dim[numdim]=(int)sub->dim.array.length;
 13.5318 +            if (sym->dim.array.length!=dim[numdim])
 13.5319 +              error(47);    /* array sizes must match */
 13.5320 +            if (numdim<level) {
 13.5321 +              sym=finddepend(sym);
 13.5322 +              sub=finddepend(sub);
 13.5323 +              assert(sym!=NULL && sub!=NULL);
 13.5324 +              /* ^^^ both arrays have the same dimensions (this was checked
 13.5325 +               *     earlier) so the dependend should always be found
 13.5326 +               */
 13.5327 +            } /* if */
 13.5328 +          } /* for */
 13.5329 +        } /* if */
 13.5330 +      } else {
 13.5331 +        int idxtag[sDIMEN_MAX];
 13.5332 +        int argcount;
 13.5333 +        /* this function does not yet have an array attached; clone the
 13.5334 +         * returned symbol beneath the current function
 13.5335 +         */
 13.5336 +        sub=sym;
 13.5337 +        assert(sub!=NULL);
 13.5338 +        level=sub->dim.array.level;
 13.5339 +        for (numdim=0; numdim<=level; numdim++) {
 13.5340 +          dim[numdim]=(int)sub->dim.array.length;
 13.5341 +          idxtag[numdim]=sub->x.tags.index;
 13.5342 +          if (numdim<level) {
 13.5343 +            sub=finddepend(sub);
 13.5344 +            assert(sub!=NULL);
 13.5345 +          } /* if */
 13.5346 +          /* check that all dimensions are known */
 13.5347 +          if (dim[numdim]<=0)
 13.5348 +            error(46,sym->name);
 13.5349 +        } /* for */
 13.5350 +        /* the address of the array is stored in a hidden parameter; the address
 13.5351 +         * of this parameter is 1 + the number of parameters (times the size of
 13.5352 +         * a cell) + the size of the stack frame and the return address
 13.5353 +         *   base + 0*sizeof(cell)         == previous "base"
 13.5354 +         *   base + 1*sizeof(cell)         == function return address
 13.5355 +         *   base + 2*sizeof(cell)         == number of arguments
 13.5356 +         *   base + 3*sizeof(cell)         == first argument of the function
 13.5357 +         *   ...
 13.5358 +         *   base + ((n-1)+3)*sizeof(cell) == last argument of the function
 13.5359 +         *   base + (n+3)*sizeof(cell)     == hidden parameter with array address
 13.5360 +         */
 13.5361 +        assert(curfunc!=NULL);
 13.5362 +        assert(curfunc->dim.arglist!=NULL);
 13.5363 +        for (argcount=0; curfunc->dim.arglist[argcount].ident!=0; argcount++)
 13.5364 +          /* nothing */;
 13.5365 +        sub=addvariable(curfunc->name,(argcount+3)*sizeof(cell),iREFARRAY,sGLOBAL,curfunc->tag,dim,numdim,idxtag);
 13.5366 +        sub->parent=curfunc;
 13.5367 +      } /* if */
 13.5368 +      /* get the hidden parameter, copy the array (the array is on the heap;
 13.5369 +       * it stays on the heap for the moment, and it is removed -usually- at
 13.5370 +       * the end of the expression/statement, see expression() in SC3.C)
 13.5371 +       */
 13.5372 +      address(sub,sALT);                /* ALT = destination */
 13.5373 +      arraysize=calc_arraysize(dim,numdim,0);
 13.5374 +      memcopy(arraysize*sizeof(cell));  /* source already in PRI */
 13.5375 +      /* moveto1(); is not necessary, callfunction() does a popreg() */
 13.5376 +    } /* if */
 13.5377 +  } else {
 13.5378 +    /* this return statement contains no expression */
 13.5379 +    ldconst(0,sPRI);
 13.5380 +    if ((rettype & uRETVALUE)!=0) {
 13.5381 +      char symname[2*sNAMEMAX+16];      /* allow space for user defined operators */
 13.5382 +      assert(curfunc!=NULL);
 13.5383 +      funcdisplayname(symname,curfunc->name);
 13.5384 +      error(209,symname);               /* function should return a value */
 13.5385 +    } /* if */
 13.5386 +    rettype|=uRETNONE;                  /* function does not return anything */
 13.5387 +  } /* if */
 13.5388 +  destructsymbols(&loctab,0);           /* call destructor for *all* locals */
 13.5389 +  modstk((int)declared*sizeof(cell));   /* end of function, remove *all*
 13.5390 +                                         * local variables */
 13.5391 +  ffret(strcmp(curfunc->name,uENTRYFUNC)!=0);
 13.5392 +}
 13.5393 +
 13.5394 +static void dobreak(void)
 13.5395 +{
 13.5396 +  int *ptr;
 13.5397 +
 13.5398 +  ptr=readwhile();      /* readwhile() gives an error if not in loop */
 13.5399 +  needtoken(tTERM);
 13.5400 +  if (ptr==NULL)
 13.5401 +    return;
 13.5402 +  destructsymbols(&loctab,nestlevel);
 13.5403 +  modstk(((int)declared-ptr[wqBRK])*sizeof(cell));
 13.5404 +  jumplabel(ptr[wqEXIT]);
 13.5405 +}
 13.5406 +
 13.5407 +static void docont(void)
 13.5408 +{
 13.5409 +  int *ptr;
 13.5410 +
 13.5411 +  ptr=readwhile();      /* readwhile() gives an error if not in loop */
 13.5412 +  needtoken(tTERM);
 13.5413 +  if (ptr==NULL)
 13.5414 +    return;
 13.5415 +  destructsymbols(&loctab,nestlevel);
 13.5416 +  modstk(((int)declared-ptr[wqCONT])*sizeof(cell));
 13.5417 +  jumplabel(ptr[wqLOOP]);
 13.5418 +}
 13.5419 +
 13.5420 +SC_FUNC void exporttag(int tag)
 13.5421 +{
 13.5422 +  /* find the tag by value in the table, then set the top bit to mark it
 13.5423 +   * "public"
 13.5424 +   */
 13.5425 +  if (tag!=0 && (tag & PUBLICTAG)==0) {
 13.5426 +    constvalue *ptr;
 13.5427 +    for (ptr=tagname_tab.next; ptr!=NULL && tag!=(int)(ptr->value & TAGMASK); ptr=ptr->next)
 13.5428 +      /* nothing */;
 13.5429 +    if (ptr!=NULL)
 13.5430 +      ptr->value |= PUBLICTAG;
 13.5431 +  } /* if */
 13.5432 +}
 13.5433 +
 13.5434 +static void doexit(void)
 13.5435 +{
 13.5436 +  int tag=0;
 13.5437 +
 13.5438 +  if (matchtoken(tTERM)==0){
 13.5439 +    doexpr(TRUE,FALSE,FALSE,TRUE,&tag,NULL,TRUE);
 13.5440 +    needtoken(tTERM);
 13.5441 +  } else {
 13.5442 +    ldconst(0,sPRI);
 13.5443 +  } /* if */
 13.5444 +  ldconst(tag,sALT);
 13.5445 +  exporttag(tag);
 13.5446 +  destructsymbols(&loctab,0);           /* call destructor for *all* locals */
 13.5447 +  ffabort(xEXIT);
 13.5448 +}
 13.5449 +
 13.5450 +static void dosleep(void)
 13.5451 +{
 13.5452 +  int tag=0;
 13.5453 +
 13.5454 +  if (matchtoken(tTERM)==0){
 13.5455 +    doexpr(TRUE,FALSE,FALSE,TRUE,&tag,NULL,TRUE);
 13.5456 +    needtoken(tTERM);
 13.5457 +  } else {
 13.5458 +    ldconst(0,sPRI);
 13.5459 +  } /* if */
 13.5460 +  ldconst(tag,sALT);
 13.5461 +  exporttag(tag);
 13.5462 +  ffabort(xSLEEP);
 13.5463 +
 13.5464 +  /* for stack usage checking, mark the use of the sleep instruction */
 13.5465 +  pc_memflags |= suSLEEP_INSTR;
 13.5466 +}
 13.5467 +
 13.5468 +static void dostate(void)
 13.5469 +{
 13.5470 +  char name[sNAMEMAX+1];
 13.5471 +  constvalue *automaton;
 13.5472 +  constvalue *state;
 13.5473 +  constvalue *stlist;
 13.5474 +  int flabel;
 13.5475 +  symbol *sym;
 13.5476 +  #if !defined SC_LIGHT
 13.5477 +    int length,index,listid,listindex,stateindex;
 13.5478 +    char *doc;
 13.5479 +  #endif
 13.5480 +
 13.5481 +  /* check for an optional condition */
 13.5482 +  if (matchtoken('(')) {
 13.5483 +    flabel=getlabel();          /* get label number for "false" branch */
 13.5484 +    pc_docexpr=TRUE;            /* attach expression as a documentation string */
 13.5485 +    test(flabel,FALSE,FALSE);   /* get expression, branch to flabel if false */
 13.5486 +    pc_docexpr=FALSE;
 13.5487 +    needtoken(')');
 13.5488 +  } else {
 13.5489 +    flabel=-1;
 13.5490 +  } /* if */
 13.5491 +
 13.5492 +  if (!sc_getstateid(&automaton,&state)) {
 13.5493 +    delete_autolisttable();
 13.5494 +    return;
 13.5495 +  } /* if */
 13.5496 +  needtoken(tTERM);
 13.5497 +
 13.5498 +  /* store the new state id */
 13.5499 +  assert(state!=NULL);
 13.5500 +  ldconst(state->value,sPRI);
 13.5501 +  assert(automaton!=NULL);
 13.5502 +  assert(automaton->index==0 && automaton->name[0]=='\0' || automaton->index>0);
 13.5503 +  storereg(automaton->value,sPRI);
 13.5504 +
 13.5505 +  /* find the optional entry() function for the state */
 13.5506 +  sym=findglb(uENTRYFUNC,sGLOBAL);
 13.5507 +  if (sc_status==statWRITE && sym!=NULL && sym->ident==iFUNCTN && sym->states!=NULL) {
 13.5508 +    for (stlist=sym->states->next; stlist!=NULL; stlist=stlist->next) {
 13.5509 +      assert(strlen(stlist->name)!=0);
 13.5510 +      if (state_getfsa(stlist->index)==automaton->index && state_inlist(stlist->index,(int)state->value))
 13.5511 +        break;      /* found! */
 13.5512 +    } /* for */
 13.5513 +    assert(stlist==NULL || state_inlist(stlist->index,state->value));
 13.5514 +    if (stlist!=NULL) {
 13.5515 +      /* the label to jump to is in stlist->name */
 13.5516 +      ffcall(sym,stlist->name,0);
 13.5517 +    } /* if */
 13.5518 +  } /* if */
 13.5519 +
 13.5520 +  if (flabel>=0)
 13.5521 +    setlabel(flabel);           /* condition was false, jump around the state switch */
 13.5522 +
 13.5523 +  #if !defined SC_LIGHT
 13.5524 +    /* mark for documentation */
 13.5525 +    if (sc_status==statFIRST) {
 13.5526 +      char *str;
 13.5527 +      /* get the last list id attached to the function, this contains the source states */
 13.5528 +      assert(curfunc!=NULL);
 13.5529 +      if (curfunc->states!=NULL) {
 13.5530 +        stlist=curfunc->states->next;
 13.5531 +        assert(stlist!=NULL);
 13.5532 +        while (stlist->next!=NULL)
 13.5533 +          stlist=stlist->next;
 13.5534 +        listid=stlist->index;
 13.5535 +      } else {
 13.5536 +        listid=-1;
 13.5537 +      } /* if */
 13.5538 +      listindex=0;
 13.5539 +      length=strlen(name)+70; /* +70 for the fixed part "<transition ... />\n" */
 13.5540 +      /* see if there are any condition strings to attach */
 13.5541 +      for (index=0; (str=get_autolist(index))!=NULL; index++)
 13.5542 +        length+=strlen(str);
 13.5543 +      if ((doc=(char*)malloc(length*sizeof(char)))!=NULL) {
 13.5544 +        do {
 13.5545 +          sprintf(doc,"<transition target=\"%s\"",name);
 13.5546 +          if (listid>=0) {
 13.5547 +            /* get the source state */
 13.5548 +            stateindex=state_listitem(listid,listindex);
 13.5549 +            state=state_findid(stateindex);
 13.5550 +            assert(state!=NULL);
 13.5551 +            sprintf(doc+strlen(doc)," source=\"%s\"",state->name);
 13.5552 +          } /* if */
 13.5553 +          if (get_autolist(0)!=NULL) {
 13.5554 +            /* add the condition */
 13.5555 +            strcat(doc," condition=\"");
 13.5556 +            for (index=0; (str=get_autolist(index))!=NULL; index++) {
 13.5557 +              /* remove the ')' token that may be appended before detecting that the expression has ended */
 13.5558 +              if (*str!=')' || *(str+1)!='\0' || get_autolist(index+1)!=NULL)
 13.5559 +                strcat(doc,str);
 13.5560 +            } /* for */
 13.5561 +            strcat(doc,"\"");
 13.5562 +          } /* if */
 13.5563 +          strcat(doc,"/>\n");
 13.5564 +          insert_docstring(doc);
 13.5565 +        } while (listid>=0 && ++listindex<state_count(listid));
 13.5566 +        free(doc);
 13.5567 +      } /* if */
 13.5568 +    } /* if */
 13.5569 +  #endif
 13.5570 +  delete_autolisttable();
 13.5571 +}
 13.5572 +
 13.5573 +
 13.5574 +static void addwhile(int *ptr)
 13.5575 +{
 13.5576 +  int k;
 13.5577 +
 13.5578 +  ptr[wqBRK]=(int)declared;     /* stack pointer (for "break") */
 13.5579 +  ptr[wqCONT]=(int)declared;    /* for "continue", possibly adjusted later */
 13.5580 +  ptr[wqLOOP]=getlabel();
 13.5581 +  ptr[wqEXIT]=getlabel();
 13.5582 +  if (wqptr>=(wq+wqTABSZ-wqSIZE))
 13.5583 +    error(102,"loop table");    /* loop table overflow (too many active loops)*/
 13.5584 +  k=0;
 13.5585 +  while (k<wqSIZE){     /* copy "ptr" to while queue table */
 13.5586 +    *wqptr=*ptr;
 13.5587 +    wqptr+=1;
 13.5588 +    ptr+=1;
 13.5589 +    k+=1;
 13.5590 +  } /* while */
 13.5591 +}
 13.5592 +
 13.5593 +static void delwhile(void)
 13.5594 +{
 13.5595 +  if (wqptr>wq)
 13.5596 +    wqptr-=wqSIZE;
 13.5597 +}
 13.5598 +
 13.5599 +static int *readwhile(void)
 13.5600 +{
 13.5601 +  if (wqptr<=wq){
 13.5602 +    error(24);          /* out of context */
 13.5603 +    return NULL;
 13.5604 +  } else {
 13.5605 +    return (wqptr-wqSIZE);
 13.5606 +  } /* if */
 13.5607 +}
 13.5608 +
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/compiler-init/compiler-init/sc2.c	Fri Jul 14 02:02:18 2006 +0000
    14.3 @@ -0,0 +1,2801 @@
    14.4 +/*  Pawn compiler - File input, preprocessing and lexical analysis functions
    14.5 + *
    14.6 + *  Copyright (c) ITB CompuPhase, 1997-2006
    14.7 + *
    14.8 + *  This software is provided "as-is", without any express or implied warranty.
    14.9 + *  In no event will the authors be held liable for any damages arising from
   14.10 + *  the use of this software.
   14.11 + *
   14.12 + *  Permission is granted to anyone to use this software for any purpose,
   14.13 + *  including commercial applications, and to alter it and redistribute it
   14.14 + *  freely, subject to the following restrictions:
   14.15 + *
   14.16 + *  1.  The origin of this software must not be misrepresented; you must not
   14.17 + *      claim that you wrote the original software. If you use this software in
   14.18 + *      a product, an acknowledgment in the product documentation would be
   14.19 + *      appreciated but is not required.
   14.20 + *  2.  Altered source versions must be plainly marked as such, and must not be
   14.21 + *      misrepresented as being the original software.
   14.22 + *  3.  This notice may not be removed or altered from any source distribution.
   14.23 + *
   14.24 + *  Version: $Id: sc2.c 3590 2006-06-24 14:16:39Z thiadmer $
   14.25 + */
   14.26 +#include <assert.h>
   14.27 +#include <stdio.h>
   14.28 +#include <stdlib.h>
   14.29 +#include <string.h>
   14.30 +#include <ctype.h>
   14.31 +#include <math.h>
   14.32 +#include "lstring.h"
   14.33 +#include "sc.h"
   14.34 +#if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
   14.35 +  #include <sclinux.h>
   14.36 +#endif
   14.37 +
   14.38 +#if defined FORTIFY
   14.39 +  #include <alloc/fortify.h>
   14.40 +#endif
   14.41 +
   14.42 +/* flags for litchar() */
   14.43 +#define RAWMODE         1
   14.44 +#define UTF8MODE        2
   14.45 +static cell litchar(const unsigned char **lptr,int flags);
   14.46 +static symbol *find_symbol(const symbol *root,const char *name,int fnumber,int automaton,int *cmptag);
   14.47 +
   14.48 +static void substallpatterns(unsigned char *line,int buffersize);
   14.49 +static int match(char *st,int end);
   14.50 +static int alpha(char c);
   14.51 +
   14.52 +#define SKIPMODE      1 /* bit field in "#if" stack */
   14.53 +#define PARSEMODE     2 /* bit field in "#if" stack */
   14.54 +#define HANDLED_ELSE  4 /* bit field in "#if" stack */
   14.55 +#define SKIPPING      (skiplevel>0 && (ifstack[skiplevel-1] & SKIPMODE)==SKIPMODE)
   14.56 +
   14.57 +static short icomment;  /* currently in multiline comment? */
   14.58 +static char ifstack[sCOMP_STACK]; /* "#if" stack */
   14.59 +static short iflevel;   /* nesting level if #if/#else/#endif */
   14.60 +static short skiplevel; /* level at which we started skipping (including nested #if .. #endif) */
   14.61 +static unsigned char term_expr[] = "";
   14.62 +static int listline=-1; /* "current line" for the list file */
   14.63 +
   14.64 +
   14.65 +/*  pushstk & popstk
   14.66 + *
   14.67 + *  Uses a LIFO stack to store information. The stack is used by doinclude(),
   14.68 + *  doswitch() (to hold the state of "swactive") and some other routines.
   14.69 + *
   14.70 + *  Porting note: I made the bold assumption that an integer will not be
   14.71 + *  larger than a pointer (it may be smaller). That is, the stack element
   14.72 + *  is typedef'ed as a pointer type, but I also store integers on it. See
   14.73 + *  SC.H for "stkitem"
   14.74 + *
   14.75 + *  Global references: stack,stkidx,stktop (private to pushstk(), popstk()
   14.76 + *                     and clearstk())
   14.77 + */
   14.78 +static stkitem *stack=NULL;
   14.79 +static int stkidx=0,stktop=0;
   14.80 +
   14.81 +SC_FUNC void pushstk(stkitem val)
   14.82 +{
   14.83 +  assert(stkidx<=stktop);
   14.84 +  if (stkidx==stktop) {
   14.85 +    stkitem *newstack;
   14.86 +    int newsize= (stktop==0) ? 16 : 2*stktop;
   14.87 +    /* try to resize the stack */
   14.88 +    assert(newsize>stktop);
   14.89 +    newstack=(stkitem*)malloc(newsize*sizeof(stkitem));
   14.90 +    if (newstack==NULL)
   14.91 +      error(102,"parser stack");  /* stack overflow (recursive include?) */
   14.92 +    /* swap the stacks */
   14.93 +    memcpy(newstack,stack,stkidx*sizeof(stkitem));
   14.94 +    if (stack!=NULL)
   14.95 +      free(stack);
   14.96 +    stack=newstack;
   14.97 +    stktop=newsize;
   14.98 +  } /* if */
   14.99 +  assert(stkidx<stktop);
  14.100 +  stack[stkidx]=val;
  14.101 +  stkidx+=1;
  14.102 +}
  14.103 +
  14.104 +SC_FUNC stkitem popstk(void)
  14.105 +{
  14.106 +  if (stkidx==0) {
  14.107 +    stkitem s;
  14.108 +    s.i=-1;             /* stack is empty */
  14.109 +    return s;
  14.110 +  } /* if */
  14.111 +  stkidx--;
  14.112 +  assert(stack!=NULL);
  14.113 +  return stack[stkidx];
  14.114 +}
  14.115 +
  14.116 +SC_FUNC void clearstk(void)
  14.117 +{
  14.118 +  assert(stack!=NULL || stktop==0);
  14.119 +  if (stack!=NULL) {
  14.120 +    free(stack);
  14.121 +    stack=NULL;
  14.122 +    stktop=0;
  14.123 +  } /* if */
  14.124 +  assert(stktop==0);
  14.125 +}
  14.126 +
  14.127 +SC_FUNC int plungequalifiedfile(char *name)
  14.128 +{
  14.129 +static char *extensions[] = { ".inc", ".p", ".pawn" };
  14.130 +  FILE *fp;
  14.131 +  char *ext;
  14.132 +  int ext_idx;
  14.133 +
  14.134 +  ext_idx=0;
  14.135 +  do {
  14.136 +    fp=(FILE*)pc_opensrc(name);
  14.137 +    ext=strchr(name,'\0');      /* save position */
  14.138 +    if (fp==NULL) {
  14.139 +      /* try to append an extension */
  14.140 +      strcpy(ext,extensions[ext_idx]);
  14.141 +      fp=(FILE*)pc_opensrc(name);
  14.142 +      if (fp==NULL)
  14.143 +        *ext='\0';              /* on failure, restore filename */
  14.144 +    } /* if */
  14.145 +    ext_idx++;
  14.146 +  } while (fp==NULL && ext_idx<(sizeof extensions / sizeof extensions[0]));
  14.147 +  if (fp==NULL) {
  14.148 +    *ext='\0';                  /* restore filename */
  14.149 +    return FALSE;
  14.150 +  } /* if */
  14.151 +  PUSHSTK_P(inpf);
  14.152 +  PUSHSTK_P(inpfname);          /* pointer to current file name */
  14.153 +  PUSHSTK_P(curlibrary);
  14.154 +  PUSHSTK_I(iflevel);
  14.155 +  assert(!SKIPPING);
  14.156 +  assert(skiplevel==iflevel);   /* these two are always the same when "parsing" */
  14.157 +  PUSHSTK_I(sc_is_utf8);
  14.158 +  PUSHSTK_I(icomment);
  14.159 +  PUSHSTK_I(fcurrent);
  14.160 +  PUSHSTK_I(fline);
  14.161 +  inpfname=duplicatestring(name);/* set name of include file */
  14.162 +  if (inpfname==NULL)
  14.163 +    error(103);             /* insufficient memory */
  14.164 +  inpf=fp;                  /* set input file pointer to include file */
  14.165 +  fnumber++;
  14.166 +  fline=0;                  /* set current line number to 0 */
  14.167 +  fcurrent=fnumber;
  14.168 +  icomment=0;               /* not in a comment */
  14.169 +  insert_dbgfile(inpfname);
  14.170 +  setfiledirect(inpfname);
  14.171 +  listline=-1;              /* force a #line directive when changing the file */
  14.172 +  sc_is_utf8=(short)scan_utf8(inpf,name);
  14.173 +  return TRUE;
  14.174 +}
  14.175 +
  14.176 +SC_FUNC int plungefile(char *name,int try_currentpath,int try_includepaths)
  14.177 +{
  14.178 +  int result=FALSE;
  14.179 +
  14.180 +  if (try_currentpath) {
  14.181 +    result=plungequalifiedfile(name);
  14.182 +    if (!result) {
  14.183 +      /* failed to open the file in the active directory, try to open the file
  14.184 +       * in the same directory as the current file --but first check whether
  14.185 +       * there is a (relative) path for the current file
  14.186 +       */
  14.187 +      char *ptr;
  14.188 +      if ((ptr=strrchr(inpfname,DIRSEP_CHAR))!=0) {
  14.189 +        int len=(int)(ptr-inpfname)+1;
  14.190 +        if (len+strlen(name)<_MAX_PATH) {
  14.191 +          char path[_MAX_PATH];
  14.192 +          strlcpy(path,inpfname,len+1);
  14.193 +          strlcat(path,name,sizeof path);
  14.194 +          result=plungequalifiedfile(path);
  14.195 +        } /* if */
  14.196 +      } /* if */
  14.197 +    } /* if */
  14.198 +  } /* if */
  14.199 +
  14.200 +  if (try_includepaths && name[0]!=DIRSEP_CHAR) {
  14.201 +    int i;
  14.202 +    char *ptr;
  14.203 +    for (i=0; !result && (ptr=get_path(i))!=NULL; i++) {
  14.204 +      char path[_MAX_PATH];
  14.205 +      strlcpy(path,ptr,sizeof path);
  14.206 +      strlcat(path,name,sizeof path);
  14.207 +      result=plungequalifiedfile(path);
  14.208 +    } /* while */
  14.209 +  } /* if */
  14.210 +  return result;
  14.211 +}
  14.212 +
  14.213 +static void check_empty(const unsigned char *lptr)
  14.214 +{
  14.215 +  /* verifies that the string contains only whitespace */
  14.216 +  while (*lptr<=' ' && *lptr!='\0')
  14.217 +    lptr++;
  14.218 +  if (*lptr!='\0')
  14.219 +    error(38);          /* extra characters on line */
  14.220 +}
  14.221 +
  14.222 +/*  doinclude
  14.223 + *
  14.224 + *  Gets the name of an include file, pushes the old file on the stack and
  14.225 + *  sets some options. This routine doesn't use lex(), since lex() doesn't
  14.226 + *  recognize file names (and directories).
  14.227 + *
  14.228 + *  Global references: inpf     (altered)
  14.229 + *                     inpfname (altered)
  14.230 + *                     fline    (altered)
  14.231 + *                     lptr     (altered)
  14.232 + */
  14.233 +static void doinclude(int silent)
  14.234 +{
  14.235 +  char name[_MAX_PATH];
  14.236 +  char symname[sNAMEMAX];
  14.237 +  char *ptr;
  14.238 +  char c;
  14.239 +  int i, result;
  14.240 +
  14.241 +  while (*lptr<=' ' && *lptr!='\0')         /* skip leading whitespace */
  14.242 +    lptr++;
  14.243 +  if (*lptr=='<' || *lptr=='\"'){
  14.244 +    c=(char)((*lptr=='\"') ? '\"' : '>');   /* termination character */
  14.245 +    lptr++;
  14.246 +    while (*lptr<=' ' && *lptr!='\0')       /* skip whitespace after quote */
  14.247 +      lptr++;
  14.248 +  } else {
  14.249 +    c='\0';
  14.250 +  } /* if */
  14.251 +
  14.252 +  i=0;
  14.253 +  while (*lptr!=c && *lptr!='\0' && i<sizeof name - 1)  /* find the end of the string */
  14.254 +    name[i++]=*lptr++;
  14.255 +  while (i>0 && name[i-1]<=' ')
  14.256 +    i--;                        /* strip trailing whitespace */
  14.257 +  assert(i>=0 && i<sizeof name);
  14.258 +  name[i]='\0';                 /* zero-terminate the string */
  14.259 +
  14.260 +  if (*lptr!=c) {               /* verify correct string termination */
  14.261 +    error(37);                  /* invalid string */
  14.262 +    return;
  14.263 +  } /* if */
  14.264 +  if (c!='\0')
  14.265 +    check_empty(lptr+1);        /* verify that the rest of the line is whitespace */
  14.266 +
  14.267 +  /* create a symbol from the name of the include file; this allows the system
  14.268 +   * to test for multiple inclusions
  14.269 +   */
  14.270 +  strcpy(symname,"_inc_");
  14.271 +  if ((ptr=strrchr(name,DIRSEP_CHAR))!=NULL)
  14.272 +    strlcat(symname,ptr+1,sizeof symname);
  14.273 +  else
  14.274 +    strlcat(symname,name,sizeof symname);
  14.275 +  if (find_symbol(&glbtab,symname,fcurrent,-1,NULL)==NULL) {
  14.276 +    /* constant is not present, so this file has not been included yet */
  14.277 +
  14.278 +    /* Include files between "..." or without quotes are read from the current
  14.279 +     * directory, or from a list of "include directories". Include files
  14.280 +     * between <...> are only read from the list of include directories.
  14.281 +     */
  14.282 +    result=plungefile(name,(c!='>'),TRUE);
  14.283 +    if (result)
  14.284 +      add_constant(symname,1,sGLOBAL,0);
  14.285 +    else if (!silent)
  14.286 +      error(100,name);            /* cannot read from ... (fatal error) */
  14.287 +  } /* if */
  14.288 +}
  14.289 +
  14.290 +/*  readline
  14.291 + *
  14.292 + *  Reads in a new line from the input file pointed to by "inpf". readline()
  14.293 + *  concatenates lines that end with a \ with the next line. If no more data
  14.294 + *  can be read from the file, readline() attempts to pop off the previous file
  14.295 + *  from the stack. If that fails too, it sets "freading" to 0.
  14.296 + *
  14.297 + *  Global references: inpf,fline,inpfname,freading,icomment (altered)
  14.298 + */
  14.299 +static void readline(unsigned char *line)
  14.300 +{
  14.301 +  int i,num,cont;
  14.302 +  unsigned char *ptr;
  14.303 +
  14.304 +  if (lptr==term_expr)
  14.305 +    return;
  14.306 +  num=sLINEMAX;
  14.307 +  cont=FALSE;
  14.308 +  do {
  14.309 +    if (inpf==NULL || pc_eofsrc(inpf)) {
  14.310 +      if (cont)
  14.311 +        error(49);        /* invalid line continuation */
  14.312 +      if (inpf!=NULL && inpf!=inpf_org)
  14.313 +        pc_closesrc(inpf);
  14.314 +      i=POPSTK_I();
  14.315 +      if (i==-1) {        /* All's done; popstk() returns "stack is empty" */
  14.316 +        freading=FALSE;
  14.317 +        *line='\0';
  14.318 +        /* when there is nothing more to read, the #if/#else stack should
  14.319 +         * be empty and we should not be in a comment
  14.320 +         */
  14.321 +        assert(iflevel>=0);
  14.322 +        if (iflevel>0)
  14.323 +          error(1,"#endif","-end of file-");
  14.324 +        else if (icomment!=0)
  14.325 +          error(1,"*/","-end of file-");
  14.326 +        return;
  14.327 +      } /* if */
  14.328 +      fline=i;
  14.329 +      fcurrent=(short)POPSTK_I();
  14.330 +      icomment=(short)POPSTK_I();
  14.331 +      sc_is_utf8=(short)POPSTK_I();
  14.332 +      iflevel=(short)POPSTK_I();
  14.333 +      skiplevel=iflevel;        /* this condition held before including the file */
  14.334 +      assert(!SKIPPING);        /* idem ditto */
  14.335 +      curlibrary=(constvalue *)POPSTK_P();
  14.336 +      free(inpfname);           /* return memory allocated for the include file name */
  14.337 +      inpfname=(char *)POPSTK_P();
  14.338 +      inpf=(FILE *)POPSTK_P();
  14.339 +      insert_dbgfile(inpfname);
  14.340 +      setfiledirect(inpfname);
  14.341 +      listline=-1;              /* force a #line directive when changing the file */
  14.342 +    } /* if */
  14.343 +
  14.344 +    if (pc_readsrc(inpf,line,num)==NULL) {
  14.345 +      *line='\0';     /* delete line */
  14.346 +      cont=FALSE;
  14.347 +    } else {
  14.348 +      /* check whether to erase leading spaces */
  14.349 +      if (cont) {
  14.350 +        unsigned char *ptr=line;
  14.351 +        while (*ptr<=' ' && *ptr!='\0')
  14.352 +          ptr++;
  14.353 +        if (ptr!=line)
  14.354 +          memmove(line,ptr,strlen((char*)ptr)+1);
  14.355 +      } /* if */
  14.356 +      cont=FALSE;
  14.357 +      /* check whether a full line was read */
  14.358 +      if (strchr((char*)line,'\n')==NULL && !pc_eofsrc(inpf))
  14.359 +        error(75);      /* line too long */
  14.360 +      /* check if the next line must be concatenated to this line */
  14.361 +      if ((ptr=(unsigned char*)strchr((char*)line,'\n'))==NULL)
  14.362 +        ptr=(unsigned char*)strchr((char*)line,'\r');
  14.363 +      if (ptr!=NULL && ptr>line) {
  14.364 +        assert(*(ptr+1)=='\0'); /* '\n' or '\r' should be last in the string */
  14.365 +        while (ptr>line && *ptr<=' ')
  14.366 +          ptr--;        /* skip trailing whitespace */
  14.367 +        if (*ptr=='\\') {
  14.368 +          cont=TRUE;
  14.369 +          /* set '\a' at the position of '\\' to make it possible to check
  14.370 +           * for a line continuation in a single line comment (error 49)
  14.371 +           */
  14.372 +          *ptr++='\a';
  14.373 +          *ptr='\0';    /* erase '\n' (and any trailing whitespace) */
  14.374 +        } /* if */
  14.375 +      } /* if */
  14.376 +      num-=strlen((char*)line);
  14.377 +      line+=strlen((char*)line);
  14.378 +    } /* if */
  14.379 +    fline+=1;
  14.380 +  } while (num>=0 && cont);
  14.381 +}
  14.382 +
  14.383 +/*  stripcom
  14.384 + *
  14.385 + *  Replaces all comments from the line by space characters. It updates
  14.386 + *  a global variable ("icomment") for multiline comments.
  14.387 + *
  14.388 + *  This routine also supports the C++ extension for single line comments.
  14.389 + *  These comments are started with "//" and end at the end of the line.
  14.390 + *
  14.391 + *  The function also detects (and manages) "documentation comments". The
  14.392 + *  global variable "icomment" is set to 2 for documentation comments.
  14.393 + *
  14.394 + *  Global references: icomment  (private to "stripcom")
  14.395 + */
  14.396 +static void stripcom(unsigned char *line)
  14.397 +{
  14.398 +  char c;
  14.399 +  #if !defined SC_LIGHT
  14.400 +    #define COMMENT_LIMIT 100
  14.401 +    #define COMMENT_MARGIN 40   /* length of the longest word */
  14.402 +    char comment[COMMENT_LIMIT+COMMENT_MARGIN];
  14.403 +    int commentidx=0;
  14.404 +    int skipstar=TRUE;
  14.405 +    static int prev_singleline=FALSE;
  14.406 +    int singleline=prev_singleline;
  14.407 +
  14.408 +    prev_singleline=FALSE;  /* preset */
  14.409 +  #endif
  14.410 +
  14.411 +  while (*line){
  14.412 +    if (icomment!=0) {
  14.413 +      if (*line=='*' && *(line+1)=='/') {
  14.414 +        #if !defined SC_LIGHT
  14.415 +          if (icomment==2) {
  14.416 +            assert(commentidx<COMMENT_LIMIT+COMMENT_MARGIN);
  14.417 +            comment[commentidx]='\0';
  14.418 +            if (strlen(comment)>0)
  14.419 +              insert_docstring(comment);
  14.420 +          } /* if */
  14.421 +        #endif
  14.422 +        icomment=0;     /* comment has ended */
  14.423 +        *line=' ';      /* replace '*' and '/' characters by spaces */
  14.424 +        *(line+1)=' ';
  14.425 +        line+=2;
  14.426 +      } else {
  14.427 +        if (*line=='/' && *(line+1)=='*')
  14.428 +          error(216);   /* nested comment */
  14.429 +        #if !defined SC_LIGHT
  14.430 +          /* collect the comment characters in a string */
  14.431 +          if (icomment==2) {
  14.432 +            if (skipstar && (*line!='\0' && *line<=' ' || *line=='*')) {
  14.433 +              /* ignore leading whitespace and '*' characters */
  14.434 +            } else if (commentidx<COMMENT_LIMIT+COMMENT_MARGIN-1) {
  14.435 +              comment[commentidx++]=(char)((*line!='\n') ? *line : ' ');
  14.436 +              if (commentidx>COMMENT_LIMIT && *line!='\0' && *line<=' ') {
  14.437 +                comment[commentidx]='\0';
  14.438 +                insert_docstring(comment);
  14.439 +                commentidx=0;
  14.440 +              } /* if */
  14.441 +              skipstar=FALSE;
  14.442 +            } /* if */
  14.443 +          } /* if */
  14.444 +        #endif
  14.445 +        *line=' ';      /* replace comments by spaces */
  14.446 +        line+=1;
  14.447 +      } /* if */
  14.448 +    } else {
  14.449 +      if (*line=='/' && *(line+1)=='*'){
  14.450 +        icomment=1;     /* start comment */
  14.451 +        #if !defined SC_LIGHT
  14.452 +          /* there must be two "*" behind the slash and then white space */
  14.453 +          if (*(line+2)=='*' && *(line+3)<=' ') {
  14.454 +            /* if we are not in a function, we must attach the previous block
  14.455 +             * to the global documentation
  14.456 +             */
  14.457 +            if (curfunc==NULL && get_docstring(0)!=NULL)
  14.458 +              sc_attachdocumentation(NULL);
  14.459 +            icomment=2; /* documentation comment */
  14.460 +          } /* if */
  14.461 +          commentidx=0;
  14.462 +          skipstar=TRUE;
  14.463 +        #endif
  14.464 +        *line=' ';      /* replace '/' and '*' characters by spaces */
  14.465 +        *(line+1)=' ';
  14.466 +        line+=2;
  14.467 +        if (icomment==2)
  14.468 +          *line++=' ';
  14.469 +      } else if (*line=='/' && *(line+1)=='/'){  /* comment to end of line */
  14.470 +        if (strchr((char*)line,'\a')!=NULL)
  14.471 +          error(49);    /* invalid line continuation */
  14.472 +        #if !defined SC_LIGHT
  14.473 +          if (*(line+2)=='/' && *(line+3)<=' ') {
  14.474 +            /* documentation comment */
  14.475 +            char *str=(char*)line+3;
  14.476 +            char *end;
  14.477 +            while (*str<=' ' && *str!='\0')
  14.478 +              str++;    /* skip leading whitespace */
  14.479 +            if ((end=strrchr(str,'\n'))!=NULL)
  14.480 +              *end='\0';/* erase trailing '\n' */
  14.481 +            /* if there is a disjunct block, we may need to attach the previous
  14.482 +             * block to the global documentation
  14.483 +             */
  14.484 +            if (!singleline && curfunc==NULL && get_docstring(0)!=NULL)
  14.485 +              sc_attachdocumentation(NULL);
  14.486 +            insert_docstring(str);
  14.487 +            prev_singleline=TRUE;
  14.488 +          } /* if */
  14.489 +        #endif
  14.490 +        *line++='\n';   /* put "newline" at first slash */
  14.491 +        *line='\0';     /* put "zero-terminator" at second slash */
  14.492 +      } else {
  14.493 +        if (*line=='\"' || *line=='\''){        /* leave literals unaltered */
  14.494 +          c=*line;      /* ending quote, single or double */
  14.495 +          line+=1;
  14.496 +          while ((*line!=c || *(line-1)==sc_ctrlchar) && *line!='\0')
  14.497 +            line+=1;
  14.498 +          line+=1;      /* skip final quote */
  14.499 +        } else {
  14.500 +          line+=1;
  14.501 +        } /* if */
  14.502 +      } /* if */
  14.503 +    } /* if */
  14.504 +  } /* while */
  14.505 +  #if !defined SC_LIGHT
  14.506 +    if (icomment==2) {
  14.507 +      assert(commentidx<COMMENT_LIMIT+COMMENT_MARGIN);
  14.508 +      comment[commentidx]='\0';
  14.509 +      if (strlen(comment)>0)
  14.510 +        insert_docstring(comment);
  14.511 +    } /* if */
  14.512 +  #endif
  14.513 +}
  14.514 +
  14.515 +/*  btoi
  14.516 + *
  14.517 + *  Attempts to interpret a numeric symbol as a boolean value. On success
  14.518 + *  it returns the number of characters processed (so the line pointer can be
  14.519 + *  adjusted) and the value is stored in "val". Otherwise it returns 0 and
  14.520 + *  "val" is garbage.
  14.521 + *
  14.522 + *  A boolean value must start with "0b"
  14.523 + */
  14.524 +static int btoi(cell *val,const unsigned char *curptr)
  14.525 +{
  14.526 +  const unsigned char *ptr;
  14.527 +
  14.528 +  *val=0;
  14.529 +  ptr=curptr;
  14.530 +  if (*ptr=='0' && *(ptr+1)=='b') {
  14.531 +    ptr+=2;
  14.532 +    while (*ptr=='0' || *ptr=='1' || *ptr=='_') {
  14.533 +      if (*ptr!='_')
  14.534 +        *val=(*val<<1) | (*ptr-'0');
  14.535 +      ptr++;
  14.536 +    } /* while */
  14.537 +  } else {
  14.538 +    return 0;
  14.539 +  } /* if */
  14.540 +  if (alphanum(*ptr))   /* number must be delimited by non-alphanumeric char */
  14.541 +    return 0;
  14.542 +  else
  14.543 +    return (int)(ptr-curptr);
  14.544 +}
  14.545 +
  14.546 +/*  dtoi
  14.547 + *
  14.548 + *  Attempts to interpret a numeric symbol as a decimal value. On success
  14.549 + *  it returns the number of characters processed and the value is stored in
  14.550 + *  "val". Otherwise it returns 0 and "val" is garbage.
  14.551 + */
  14.552 +static int dtoi(cell *val,const unsigned char *curptr)
  14.553 +{
  14.554 +  const unsigned char *ptr;
  14.555 +
  14.556 +  *val=0;
  14.557 +  ptr=curptr;
  14.558 +  if (!isdigit(*ptr))   /* should start with digit */
  14.559 +    return 0;
  14.560 +  while (isdigit(*ptr) || *ptr=='_') {
  14.561 +    if (*ptr!='_')
  14.562 +      *val=(*val*10)+(*ptr-'0');
  14.563 +    ptr++;
  14.564 +  } /* while */
  14.565 +  if (alphanum(*ptr))   /* number must be delimited by non-alphanumerical */
  14.566 +    return 0;
  14.567 +  if (*ptr=='.' && isdigit(*(ptr+1)))
  14.568 +    return 0;           /* but a fractional part must not be present */
  14.569 +  return (int)(ptr-curptr);
  14.570 +}
  14.571 +
  14.572 +/*  htoi
  14.573 + *
  14.574 + *  Attempts to interpret a numeric symbol as a hexadecimal value. On
  14.575 + *  success it returns the number of characters processed and the value is
  14.576 + *  stored in "val". Otherwise it return 0 and "val" is garbage.
  14.577 + */
  14.578 +static int htoi(cell *val,const unsigned char *curptr)
  14.579 +{
  14.580 +  const unsigned char *ptr;
  14.581 +
  14.582 +  *val=0;
  14.583 +  ptr=curptr;
  14.584 +  if (!isdigit(*ptr))   /* should start with digit */
  14.585 +    return 0;
  14.586 +  if (*ptr=='0' && *(ptr+1)=='x') {     /* C style hexadecimal notation */
  14.587 +    ptr+=2;
  14.588 +    while (ishex(*ptr) || *ptr=='_') {
  14.589 +      if (*ptr!='_') {
  14.590 +        assert(ishex(*ptr));
  14.591 +        *val= *val<<4;
  14.592 +        if (isdigit(*ptr))
  14.593 +          *val+= (*ptr-'0');
  14.594 +        else
  14.595 +          *val+= (tolower(*ptr)-'a'+10);
  14.596 +      } /* if */
  14.597 +      ptr++;
  14.598 +    } /* while */
  14.599 +  } else {
  14.600 +    return 0;
  14.601 +  } /* if */
  14.602 +  if (alphanum(*ptr))
  14.603 +    return 0;
  14.604 +  else
  14.605 +    return (int)(ptr-curptr);
  14.606 +}
  14.607 +
  14.608 +#if defined __GNUC__
  14.609 +static double pow10(int value)
  14.610 +{
  14.611 +  double res=1.0;
  14.612 +  while (value>=4) {
  14.613 +    res*=10000.0;
  14.614 +    value-=5;
  14.615 +  } /* while */
  14.616 +  while (value>=2) {
  14.617 +    res*=100.0;
  14.618 +    value-=2;
  14.619 +  } /* while */
  14.620 +  while (value>=1) {
  14.621 +    res*=10.0;
  14.622 +    value-=1;
  14.623 +  } /* while */
  14.624 +  return res;
  14.625 +}
  14.626 +#endif
  14.627 +
  14.628 +/*  ftoi
  14.629 + *
  14.630 + *  Attempts to interpret a numeric symbol as a rational number, either as
  14.631 + *  IEEE 754 single/double precision floating point or as a fixed point integer.
  14.632 + *  On success it returns the number of characters processed and the value is
  14.633 + *  stored in "val". Otherwise it returns 0 and "val" is unchanged.
  14.634 + *
  14.635 + *  Pawn has stricter definition for rational numbers than most:
  14.636 + *  o  the value must start with a digit; ".5" is not a valid number, you
  14.637 + *     should write "0.5"
  14.638 + *  o  a period must appear in the value, even if an exponent is given; "2e3"
  14.639 + *     is not a valid number, you should write "2.0e3"
  14.640 + *  o  at least one digit must follow the period; "6." is not a valid number,
  14.641 + *     you should write "6.0"
  14.642 + */
  14.643 +static int ftoi(cell *val,const unsigned char *curptr)
  14.644 +{
  14.645 +  const unsigned char *ptr;
  14.646 +  double fnum,ffrac,fmult;
  14.647 +  unsigned long dnum,dbase;
  14.648 +  int i, ignore;
  14.649 +
  14.650 +  assert(rational_digits>=0 && rational_digits<9);
  14.651 +  for (i=0,dbase=1; i<rational_digits; i++)
  14.652 +    dbase*=10;
  14.653 +  fnum=0.0;
  14.654 +  dnum=0L;
  14.655 +  ptr=curptr;
  14.656 +  if (!isdigit(*ptr))   /* should start with digit */
  14.657 +    return 0;
  14.658 +  while (isdigit(*ptr) || *ptr=='_') {
  14.659 +    if (*ptr!='_') {
  14.660 +      fnum=(fnum*10.0)+(*ptr-'0');
  14.661 +      dnum=(dnum*10L)+(*ptr-'0')*dbase;
  14.662 +    } /* if */
  14.663 +    ptr++;
  14.664 +  } /* while */
  14.665 +  if (*ptr!='.')
  14.666 +    return 0;           /* there must be a period */
  14.667 +  ptr++;
  14.668 +  if (!isdigit(*ptr))   /* there must be at least one digit after the dot */
  14.669 +    return 0;
  14.670 +  ffrac=0.0;
  14.671 +  fmult=1.0;
  14.672 +  ignore=FALSE;
  14.673 +  while (isdigit(*ptr) || *ptr=='_') {
  14.674 +    if (*ptr!='_') {
  14.675 +      ffrac=(ffrac*10.0)+(*ptr-'0');
  14.676 +      fmult=fmult/10.0;
  14.677 +      dbase /= 10L;
  14.678 +      dnum += (*ptr-'0')*dbase;
  14.679 +      if (dbase==0L && sc_rationaltag && rational_digits>0 && !ignore) {
  14.680 +        error(222);     /* number of digits exceeds rational number precision */
  14.681 +        ignore=TRUE;
  14.682 +      } /* if */
  14.683 +    } /* if */
  14.684 +    ptr++;
  14.685 +  } /* while */
  14.686 +  fnum += ffrac*fmult;  /* form the number so far */
  14.687 +  if (*ptr=='e') {      /* optional fractional part */
  14.688 +    int exp,sign;
  14.689 +    ptr++;
  14.690 +    if (*ptr=='-') {
  14.691 +      sign=-1;
  14.692 +      ptr++;
  14.693 +    } else {
  14.694 +      sign=1;
  14.695 +    } /* if */
  14.696 +    if (!isdigit(*ptr)) /* 'e' should be followed by a digit */
  14.697 +      return 0;
  14.698 +    exp=0;
  14.699 +    while (isdigit(*ptr)) {
  14.700 +      exp=(exp*10)+(*ptr-'0');
  14.701 +      ptr++;
  14.702 +    } /* while */
  14.703 +    #if defined __GNUC__
  14.704 +      fmult=pow10(exp*sign);
  14.705 +    #else
  14.706 +      fmult=pow(10,exp*sign);
  14.707 +    #endif
  14.708 +    fnum *= fmult;
  14.709 +    dnum *= (unsigned long)(fmult+0.5);
  14.710 +  } /* if */
  14.711 +
  14.712 +  /* decide how to store the number */
  14.713 +  if (sc_rationaltag==0) {
  14.714 +    error(70);          /* rational number support was not enabled */
  14.715 +    *val=0;
  14.716 +  } else if (rational_digits==0) {
  14.717 +    /* floating point */
  14.718 +    #if PAWN_CELL_SIZE==32
  14.719 +      float value=(float)fnum;
  14.720 +      *val=*((cell *)&value);
  14.721 +      #if !defined NDEBUG
  14.722 +        /* I assume that the C/C++ compiler stores "float" values in IEEE 754
  14.723 +         * format (as mandated in the ANSI standard). Test this assumption
  14.724 +         * anyway.
  14.725 +         * Note: problems have been reported with GCC 3.2.x, version 3.3.x works.
  14.726 +         */
  14.727 +        { float test1 = 0.0, test2 = 50.0, test3 = -50.0;
  14.728 +          uint32_t bit = 1;
  14.729 +          /* test 0.0 == all bits 0 */
  14.730 +          assert(*(uint32_t*)&test1==0x00000000L);
  14.731 +          /* test sign & magnitude format */
  14.732 +          assert(((*(uint32_t*)&test2) ^ (*(uint32_t*)&test3)) == (bit << (PAWN_CELL_SIZE-1)));
  14.733 +          /* test a known value */
  14.734 +          assert(*(uint32_t*)&test2==0x42480000L);
  14.735 +        }
  14.736 +      #endif
  14.737 +    #elif PAWN_CELL_SIZE==64
  14.738 +      *val=*((cell *)&fnum);
  14.739 +      #if !defined NDEBUG
  14.740 +        /* I assume that the C/C++ compiler stores "double" values in IEEE 754
  14.741 +         * format (as mandated in the ANSI standard).
  14.742 +         */
  14.743 +        { float test1 = 0.0, test2 = 50.0, test3 = -50.0;
  14.744 +          uint64_t bit = 1;
  14.745 +          /* test 0.0 == all bits 0 */
  14.746 +          assert(*(uint64_t*)&test1==0x00000000L);
  14.747 +          /* test sign & magnitude format */
  14.748 +          assert(((*(uint64_t*)&test2) ^ (*(uint64_t*)&test3)) == (bit << (PAWN_CELL_SIZE-1)));
  14.749 +        }
  14.750 +      #endif
  14.751 +    #else
  14.752 +      #error Unsupported cell size
  14.753 +    #endif
  14.754 +  } else {
  14.755 +    /* fixed point */
  14.756 +    *val=(cell)dnum;
  14.757 +  } /* if */
  14.758 +
  14.759 +  return (int)(ptr-curptr);
  14.760 +}
  14.761 +
  14.762 +/*  number
  14.763 + *
  14.764 + *  Reads in a number (binary, decimal or hexadecimal). It returns the number
  14.765 + *  of characters processed or 0 if the symbol couldn't be interpreted as a
  14.766 + *  number (in this case the argument "val" remains unchanged). This routine
  14.767 + *  relies on the 'early dropout' implementation of the logical or (||)
  14.768 + *  operator.
  14.769 + *
  14.770 + *  Note: the routine doesn't check for a sign (+ or -). The - is checked
  14.771 + *        for at "hier2()" (in fact, it is viewed as an operator, not as a
  14.772 + *        sign) and the + is invalid (as in K&R C, and unlike ANSI C).
  14.773 + */
  14.774 +static int number(cell *val,const unsigned char *curptr)
  14.775 +{
  14.776 +  int i;
  14.777 +  cell value;
  14.778 +
  14.779 +  if ((i=btoi(&value,curptr))!=0      /* binary? */
  14.780 +      || (i=htoi(&value,curptr))!=0   /* hexadecimal? */
  14.781 +      || (i=dtoi(&value,curptr))!=0)  /* decimal? */
  14.782 +  {
  14.783 +    *val=value;
  14.784 +    return i;
  14.785 +  } else {
  14.786 +    return 0;                      /* else not a number */
  14.787 +  } /* if */
  14.788 +}
  14.789 +
  14.790 +static void chrcat(char *str,char chr)
  14.791 +{
  14.792 +  str=strchr(str,'\0');
  14.793 +  *str++=chr;
  14.794 +  *str='\0';
  14.795 +}
  14.796 +
  14.797 +static int preproc_expr(cell *val,int *tag)
  14.798 +{
  14.799 +  int result;
  14.800 +  int index;
  14.801 +  cell code_index;
  14.802 +  char *term;
  14.803 +
  14.804 +  /* Disable staging; it should be disabled already because
  14.805 +   * expressions may not be cut off half-way between conditional
  14.806 +   * compilations. Reset the staging index, but keep the code
  14.807 +   * index.
  14.808 +   */
  14.809 +  if (stgget(&index,&code_index)) {
  14.810 +    error(57);                          /* unfinished expression */
  14.811 +    stgdel(0,code_index);
  14.812 +    stgset(FALSE);
  14.813 +  } /* if */
  14.814 +  assert((lptr-pline)<(int)strlen((char*)pline));   /* lptr must point inside the string */
  14.815 +  #if !defined NO_DEFINE
  14.816 +    /* preprocess the string */
  14.817 +    substallpatterns(pline,sLINEMAX);
  14.818 +    assert((lptr-pline)<(int)strlen((char*)pline)); /* lptr must STILL point inside the string */
  14.819 +  #endif
  14.820 +  /* append a special symbol to the string, so the expression
  14.821 +   * analyzer won't try to read a next line when it encounters
  14.822 +   * an end-of-line
  14.823 +   */
  14.824 +  assert(strlen((char*)pline)<sLINEMAX);
  14.825 +  term=strchr((char*)pline,'\0');
  14.826 +  assert(term!=NULL);
  14.827 +  chrcat((char*)pline,PREPROC_TERM);    /* the "DEL" code (see SC.H) */
  14.828 +  result=constexpr(val,tag,NULL);       /* get value (or 0 on error) */
  14.829 +  *term='\0';                           /* erase the token (if still present) */
  14.830 +  lexclr(FALSE);                        /* clear any "pushed" tokens */
  14.831 +  return result;
  14.832 +}
  14.833 +
  14.834 +/* getstring
  14.835 + * Returns returns a pointer behind the closing quote or to the other
  14.836 + * character that caused the input to be ended.
  14.837 + */
  14.838 +static const unsigned char *getstring(unsigned char *dest,int max,const unsigned char *line)
  14.839 +{
  14.840 +  assert(dest!=NULL && line!=NULL);
  14.841 +  *dest='\0';
  14.842 +  while (*line<=' ' && *line!='\0')
  14.843 +    line++;             /* skip whitespace */
  14.844 +  if (*line=='"') {
  14.845 +    int len=0;
  14.846 +    line++;             /* skip " */
  14.847 +    while (*line!='"' && *line!='\0') {
  14.848 +      if (len<max-1)
  14.849 +        dest[len++]=*line;
  14.850 +      line++;
  14.851 +    } /* if */
  14.852 +    dest[len]='\0';
  14.853 +    if (*line=='"')
  14.854 +      line++;           /* skip closing " */
  14.855 +    else
  14.856 +      error(37);        /* invalid string */
  14.857 +  } else {
  14.858 +    error(37);          /* invalid string */
  14.859 +  } /* if */
  14.860 +  return line;
  14.861 +}
  14.862 +
  14.863 +enum {
  14.864 +  CMD_NONE,
  14.865 +  CMD_TERM,
  14.866 +  CMD_EMPTYLINE,
  14.867 +  CMD_CONDFALSE,
  14.868 +  CMD_INCLUDE,
  14.869 +  CMD_DEFINE,
  14.870 +  CMD_IF,
  14.871 +  CMD_DIRECTIVE,
  14.872 +};
  14.873 +
  14.874 +/*  command
  14.875 + *
  14.876 + *  Recognizes the compiler directives. The function returns:
  14.877 + *     CMD_NONE         the line must be processed
  14.878 + *     CMD_TERM         a pending expression must be completed before processing further lines
  14.879 + *     Other value: the line must be skipped, because:
  14.880 + *     CMD_CONDFALSE    false "#if.." code
  14.881 + *     CMD_EMPTYLINE    line is empty
  14.882 + *     CMD_INCLUDE      the line contains a #include directive
  14.883 + *     CMD_DEFINE       the line contains a #subst directive
  14.884 + *     CMD_IF           the line contains a #if/#else/#endif directive
  14.885 + *     CMD_DIRECTIVE    the line contains some other compiler directive
  14.886 + *
  14.887 + *  Global variables: iflevel, ifstack (altered)
  14.888 + *                    lptr      (altered)
  14.889 + */
  14.890 +static int command(void)
  14.891 +{
  14.892 +  int tok,ret;
  14.893 +  cell val;
  14.894 +  char *str;
  14.895 +  int index;
  14.896 +  cell code_index;
  14.897 +
  14.898 +  while (*lptr<=' ' && *lptr!='\0')
  14.899 +    lptr+=1;
  14.900 +  if (*lptr=='\0')
  14.901 +    return CMD_EMPTYLINE;       /* empty line */
  14.902 +  if (*lptr!='#')
  14.903 +    return SKIPPING ? CMD_CONDFALSE : CMD_NONE; /* it is not a compiler directive */
  14.904 +  /* compiler directive found */
  14.905 +  indent_nowarn=TRUE;           /* allow loose indentation" */
  14.906 +  lexclr(FALSE);                /* clear any "pushed" tokens */
  14.907 +  /* on a pending expression, force to return a silent ';' token and force to
  14.908 +   * re-read the line
  14.909 +   */
  14.910 +  if (!sc_needsemicolon && stgget(&index,&code_index)) {
  14.911 +    lptr=term_expr;
  14.912 +    return CMD_TERM;
  14.913 +  } /* if */
  14.914 +  tok=lex(&val,&str);
  14.915 +  ret=SKIPPING ? CMD_CONDFALSE : CMD_DIRECTIVE;  /* preset 'ret' to CMD_DIRECTIVE (most common case) */
  14.916 +  switch (tok) {
  14.917 +  case tpIF:                    /* conditional compilation */
  14.918 +    ret=CMD_IF;
  14.919 +    assert(iflevel>=0);
  14.920 +    if (iflevel>=sCOMP_STACK)
  14.921 +      error(102,"Conditional compilation stack"); /* table overflow */
  14.922 +    iflevel++;
  14.923 +    if (SKIPPING)
  14.924 +      break;                    /* break out of switch */
  14.925 +    skiplevel=iflevel;
  14.926 +    preproc_expr(&val,NULL);    /* get value (or 0 on error) */
  14.927 +    ifstack[iflevel-1]=(char)(val ? PARSEMODE : SKIPMODE);
  14.928 +    check_empty(lptr);
  14.929 +    break;
  14.930 +  case tpELSE:
  14.931 +  case tpELSEIF:
  14.932 +    ret=CMD_IF;
  14.933 +    assert(iflevel>=0);
  14.934 +    if (iflevel==0) {
  14.935 +      error(26);                /* no matching #if */
  14.936 +      errorset(sRESET,0);
  14.937 +    } else {
  14.938 +      /* check for earlier #else */
  14.939 +      if ((ifstack[iflevel-1] & HANDLED_ELSE)==HANDLED_ELSE) {
  14.940 +        if (tok==tpELSEIF)
  14.941 +          error(61);            /* #elseif directive may not follow an #else */
  14.942 +        else
  14.943 +          error(60);            /* multiple #else directives between #if ... #endif */
  14.944 +        errorset(sRESET,0);
  14.945 +      } else {
  14.946 +        assert(iflevel>0);
  14.947 +        /* if there has been a "parse mode" on this level, set "skip mode",
  14.948 +         * otherwise, clear "skip mode"
  14.949 +         */
  14.950 +        if ((ifstack[iflevel-1] & PARSEMODE)==PARSEMODE) {
  14.951 +          /* there has been a parse mode already on this level, so skip the rest */
  14.952 +          ifstack[iflevel-1] |= (char)SKIPMODE;
  14.953 +        } else {
  14.954 +          /* previous conditions were all FALSE */
  14.955 +          if (tok==tpELSEIF) {
  14.956 +            /* get new expression */
  14.957 +            preproc_expr(&val,NULL);  /* get value (or 0 on error) */
  14.958 +            ifstack[iflevel-1]=(char)(val ? PARSEMODE : SKIPMODE);
  14.959 +          } else {
  14.960 +            /* a simple #else, clear skip mode */
  14.961 +            ifstack[iflevel-1] &= (char)~SKIPMODE;
  14.962 +          } /* if */
  14.963 +        } /* if */
  14.964 +      } /* if */
  14.965 +    } /* if */
  14.966 +    check_empty(lptr);
  14.967 +    break;
  14.968 +  case tpENDIF:
  14.969 +    ret=CMD_IF;
  14.970 +    if (iflevel==0){
  14.971 +      error(26);        /* no matching "#if" */
  14.972 +      errorset(sRESET,0);
  14.973 +    } else {
  14.974 +      iflevel--;
  14.975 +      if (iflevel<skiplevel)
  14.976 +        skiplevel=iflevel;
  14.977 +    } /* if */
  14.978 +    check_empty(lptr);
  14.979 +    break;
  14.980 +  case tINCLUDE:                /* #include directive */
  14.981 +  case tpTRYINCLUDE:
  14.982 +    ret=CMD_INCLUDE;
  14.983 +    if (!SKIPPING)
  14.984 +      doinclude(tok==tpTRYINCLUDE);
  14.985 +    break;
  14.986 +  case tpFILE:
  14.987 +    if (!SKIPPING) {
  14.988 +      char pathname[_MAX_PATH];
  14.989 +      lptr=getstring((unsigned char*)pathname,sizeof pathname,lptr);
  14.990 +      if (strlen(pathname)>0) {
  14.991 +        free(inpfname);
  14.992 +        inpfname=duplicatestring(pathname);
  14.993 +        if (inpfname==NULL)
  14.994 +          error(103);           /* insufficient memory */
  14.995 +      } /* if */
  14.996 +    } /* if */
  14.997 +    check_empty(lptr);
  14.998 +    break;
  14.999 +  case tpLINE:
 14.1000 +    if (!SKIPPING) {
 14.1001 +      if (lex(&val,&str)!=tNUMBER)
 14.1002 +        error(8);               /* invalid/non-constant expression */
 14.1003 +      fline=(int)val;
 14.1004 +    } /* if */
 14.1005 +    check_empty(lptr);
 14.1006 +    break;
 14.1007 +  case tpASSERT:
 14.1008 +    if (!SKIPPING && (sc_debug & sCHKBOUNDS)!=0) {
 14.1009 +      for (str=(char*)lptr; *str<=' ' && *str!='\0'; str++)
 14.1010 +        /* nothing */;          /* save start of expression */
 14.1011 +      preproc_expr(&val,NULL);  /* get constant expression (or 0 on error) */
 14.1012 +      if (!val)
 14.1013 +        error(110,str);         /* assertion failed */
 14.1014 +      check_empty(lptr);
 14.1015 +    } /* if */
 14.1016 +    break;
 14.1017 +  case tpPRAGMA:
 14.1018 +    if (!SKIPPING) {
 14.1019 +      if (lex(&val,&str)==tSYMBOL) {
 14.1020 +        if (strcmp(str,"amxlimit")==0) {
 14.1021 +          preproc_expr(&pc_amxlimit,NULL);
 14.1022 +        } else if (strcmp(str,"amxram")==0) {
 14.1023 +          preproc_expr(&pc_amxram,NULL);
 14.1024 +        } else if (strcmp(str,"codepage")==0) {
 14.1025 +          char name[sNAMEMAX+1];
 14.1026 +          while (*lptr<=' ' && *lptr!='\0')
 14.1027 +            lptr++;
 14.1028 +          if (*lptr=='"') {
 14.1029 +            lptr=getstring((unsigned char*)name,sizeof name,lptr);
 14.1030 +          } else {
 14.1031 +            int i;
 14.1032 +            for (i=0; i<sizeof name && alphanum(*lptr); i++,lptr++)
 14.1033 +              name[i]=*lptr;
 14.1034 +            name[i]='\0';
 14.1035 +          } /* if */
 14.1036 +          if (!cp_set(name))
 14.1037 +            error(108);         /* codepage mapping file not found */
 14.1038 +        } else if (strcmp(str,"compress")==0) {
 14.1039 +          cell val;
 14.1040 +          preproc_expr(&val,NULL);
 14.1041 +          sc_compress=(int)val; /* switch code packing on/off */
 14.1042 +        } else if (strcmp(str,"ctrlchar")==0) {
 14.1043 +          while (*lptr<=' ' && *lptr!='\0')
 14.1044 +            lptr++;
 14.1045 +          if (*lptr=='\0') {
 14.1046 +            sc_ctrlchar=sc_ctrlchar_org;
 14.1047 +          } else {
 14.1048 +            if (lex(&val,&str)!=tNUMBER)
 14.1049 +              error(27);          /* invalid character constant */
 14.1050 +            sc_ctrlchar=(char)val;
 14.1051 +          } /* if */
 14.1052 +        } else if (strcmp(str,"depricated")==0) {
 14.1053 +          while (*lptr<=' ' && *lptr!='\0')
 14.1054 +            lptr++;
 14.1055 +          pc_depricate=(char*)malloc(strlen((char*)lptr)+1);
 14.1056 +          if (pc_depricate!=NULL)
 14.1057 +            strcpy(pc_depricate,(char*)lptr);
 14.1058 +          lptr=(unsigned char*)strchr((char*)lptr,'\0'); /* skip to end (ignore "extra characters on line") */
 14.1059 +        } else if (strcmp(str,"dynamic")==0) {
 14.1060 +          preproc_expr(&pc_stksize,NULL);
 14.1061 +        } else if (strcmp(str,"library")==0) {
 14.1062 +          char name[sNAMEMAX+1];
 14.1063 +          while (*lptr<=' ' && *lptr!='\0')
 14.1064 +            lptr++;
 14.1065 +          if (*lptr=='"') {
 14.1066 +            lptr=getstring((unsigned char*)name,sizeof name,lptr);
 14.1067 +          } else {
 14.1068 +            int i;
 14.1069 +            for (i=0; i<sizeof name && (alphanum(*lptr) || *lptr=='-'); i++,lptr++)
 14.1070 +              name[i]=*lptr;
 14.1071 +            name[i]='\0';
 14.1072 +          } /* if */
 14.1073 +          if (strlen(name)==0) {
 14.1074 +            curlibrary=NULL;
 14.1075 +          } else if (strcmp(name,"-")==0) {
 14.1076 +            pc_addlibtable=FALSE;
 14.1077 +          } else {
 14.1078 +            /* add the name if it does not yet exist in the table */
 14.1079 +            if (find_constval(&libname_tab,name,0)==NULL)
 14.1080 +              curlibrary=append_constval(&libname_tab,name,0,0);
 14.1081 +          } /* if */
 14.1082 +        } else if (strcmp(str,"pack")==0) {
 14.1083 +          cell val;
 14.1084 +          preproc_expr(&val,NULL);      /* default = packed/unpacked */
 14.1085 +          sc_packstr=(int)val;
 14.1086 +        } else if (strcmp(str,"rational")==0) {
 14.1087 +          char name[sNAMEMAX+1];
 14.1088 +          cell digits=0;
 14.1089 +          int i;
 14.1090 +          /* first gather all information, start with the tag name */
 14.1091 +          while (*lptr<=' ' && *lptr!='\0')
 14.1092 +            lptr++;
 14.1093 +          for (i=0; i<sizeof name && alphanum(*lptr); i++,lptr++)
 14.1094 +            name[i]=*lptr;
 14.1095 +          name[i]='\0';
 14.1096 +          /* then the precision (for fixed point arithmetic) */
 14.1097 +          while (*lptr<=' ' && *lptr!='\0')
 14.1098 +            lptr++;
 14.1099 +          if (*lptr=='(') {
 14.1100 +            preproc_expr(&digits,NULL);
 14.1101 +            if (digits<=0 || digits>9) {
 14.1102 +              error(68);        /* invalid rational number precision */
 14.1103 +              digits=0;
 14.1104 +            } /* if */
 14.1105 +            if (*lptr==')')
 14.1106 +              lptr++;
 14.1107 +          } /* if */
 14.1108 +          /* add the tag (make it public) and check the values */
 14.1109 +          i=pc_addtag(name);
 14.1110 +          exporttag(i);
 14.1111 +          if (sc_rationaltag==0 || (sc_rationaltag==i && rational_digits==(int)digits)) {
 14.1112 +            sc_rationaltag=i;
 14.1113 +            rational_digits=(int)digits;
 14.1114 +          } else {
 14.1115 +            error(69);          /* rational number format already set, can only be set once */
 14.1116 +          } /* if */
 14.1117 +        } else if (strcmp(str,"semicolon")==0) {
 14.1118 +          cell val;
 14.1119 +          preproc_expr(&val,NULL);
 14.1120 +          sc_needsemicolon=(int)val;
 14.1121 +        } else if (strcmp(str,"tabsize")==0) {
 14.1122 +          cell val;
 14.1123 +          preproc_expr(&val,NULL);
 14.1124 +          sc_tabsize=(int)val;
 14.1125 +        } else if (strcmp(str,"align")==0) {
 14.1126 +          sc_alignnext=TRUE;
 14.1127 +        } else if (strcmp(str,"unused")==0) {
 14.1128 +          char name[sNAMEMAX+1];
 14.1129 +          int i,comma;
 14.1130 +          symbol *sym;
 14.1131 +          do {
 14.1132 +            /* get the name */
 14.1133 +            while (*lptr<=' ' && *lptr!='\0')
 14.1134 +              lptr++;
 14.1135 +            for (i=0; i<sizeof name && alphanum(*lptr); i++,lptr++)
 14.1136 +              name[i]=*lptr;
 14.1137 +            name[i]='\0';
 14.1138 +            /* get the symbol */
 14.1139 +            sym=findloc(name);
 14.1140 +            if (sym==NULL)
 14.1141 +              sym=findglb(name,sSTATEVAR);
 14.1142 +            if (sym!=NULL) {
 14.1143 +              sym->usage |= uREAD;
 14.1144 +              if (sym->ident==iVARIABLE || sym->ident==iREFERENCE
 14.1145 +                  || sym->ident==iARRAY || sym->ident==iREFARRAY)
 14.1146 +                sym->usage |= uWRITTEN;
 14.1147 +            } else {
 14.1148 +              error(17,name);     /* undefined symbol */
 14.1149 +            } /* if */
 14.1150 +            /* see if a comma follows the name */
 14.1151 +            while (*lptr<=' ' && *lptr!='\0')
 14.1152 +              lptr++;
 14.1153 +            comma= (*lptr==',');
 14.1154 +            if (comma)
 14.1155 +              lptr++;
 14.1156 +          } while (comma);
 14.1157 +        } else {
 14.1158 +          error(207);           /* unknown #pragma */
 14.1159 +        } /* if */
 14.1160 +      } else {
 14.1161 +        error(207);             /* unknown #pragma */
 14.1162 +      } /* if */
 14.1163 +      check_empty(lptr);
 14.1164 +    } /* if */
 14.1165 +    break;
 14.1166 +  case tpENDINPUT:
 14.1167 +  case tpENDSCRPT:
 14.1168 +    if (!SKIPPING) {
 14.1169 +      check_empty(lptr);
 14.1170 +      assert(inpf!=NULL);
 14.1171 +      if (inpf!=inpf_org)
 14.1172 +        pc_closesrc(inpf);
 14.1173 +      inpf=NULL;
 14.1174 +    } /* if */
 14.1175 +    break;
 14.1176 +#if !defined NOEMIT
 14.1177 +  case tpEMIT: {
 14.1178 +    /* write opcode to output file */
 14.1179 +    char name[40];
 14.1180 +    int i;
 14.1181 +    while (*lptr<=' ' && *lptr!='\0')
 14.1182 +      lptr++;
 14.1183 +    for (i=0; i<40 && (isalpha(*lptr) || *lptr=='.'); i++,lptr++)
 14.1184 +      name[i]=(char)tolower(*lptr);
 14.1185 +    name[i]='\0';
 14.1186 +    stgwrite("\t");
 14.1187 +    stgwrite(name);
 14.1188 +    stgwrite(" ");
 14.1189 +    code_idx+=opcodes(1);
 14.1190 +    /* write parameter (if any) */
 14.1191 +    while (*lptr<=' ' && *lptr!='\0')
 14.1192 +      lptr++;
 14.1193 +    if (*lptr!='\0') {
 14.1194 +      symbol *sym;
 14.1195 +      tok=lex(&val,&str);
 14.1196 +      switch (tok) {
 14.1197 +      case tNUMBER:
 14.1198 +      case tRATIONAL:
 14.1199 +        outval(val,FALSE);
 14.1200 +        code_idx+=opargs(1);
 14.1201 +        break;
 14.1202 +      case tSYMBOL:
 14.1203 +        sym=findloc(str);
 14.1204 +        if (sym==NULL)
 14.1205 +          sym=findglb(str,sSTATEVAR);
 14.1206 +        if (sym==NULL || sym->ident!=iFUNCTN && sym->ident!=iREFFUNC && (sym->usage & uDEFINE)==0) {
 14.1207 +          error(17,str);        /* undefined symbol */
 14.1208 +        } else {
 14.1209 +          outval(sym->addr,FALSE);
 14.1210 +          /* mark symbol as "used", unknown whether for read or write */
 14.1211 +          markusage(sym,uREAD | uWRITTEN);
 14.1212 +          code_idx+=opargs(1);
 14.1213 +        } /* if */
 14.1214 +        break;
 14.1215 +      default: {
 14.1216 +        char s2[20];
 14.1217 +        extern char *sc_tokens[];/* forward declaration */
 14.1218 +        if (tok<256)
 14.1219 +          sprintf(s2,"%c",(char)tok);
 14.1220 +        else
 14.1221 +          strcpy(s2,sc_tokens[tok-tFIRST]);
 14.1222 +        error(1,sc_tokens[tSYMBOL-tFIRST],s2);
 14.1223 +        break;
 14.1224 +      } /* case */
 14.1225 +      } /* switch */
 14.1226 +    } /* if */
 14.1227 +    stgwrite("\n");
 14.1228 +    check_empty(lptr);
 14.1229 +    break;
 14.1230 +  } /* case */
 14.1231 +#endif
 14.1232 +#if !defined NO_DEFINE
 14.1233 +  case tpDEFINE: {
 14.1234 +    ret=CMD_DEFINE;
 14.1235 +    if (!SKIPPING) {
 14.1236 +      char *pattern,*substitution;
 14.1237 +      const unsigned char *start,*end;
 14.1238 +      int count,prefixlen;
 14.1239 +      stringpair *def;
 14.1240 +      /* find the pattern to match */
 14.1241 +      while (*lptr<=' ' && *lptr!='\0')
 14.1242 +        lptr++;
 14.1243 +      start=lptr;       /* save starting point of the match pattern */
 14.1244 +      count=0;
 14.1245 +      while (*lptr>' ' && *lptr!='\0') {
 14.1246 +        litchar(&lptr,0); /* litchar() advances "lptr" and handles escape characters */
 14.1247 +        count++;
 14.1248 +      } /* while */
 14.1249 +      end=lptr;
 14.1250 +      /* check pattern to match */
 14.1251 +      if (!alpha(*start)) {
 14.1252 +        error(74);      /* pattern must start with an alphabetic character */
 14.1253 +        break;
 14.1254 +      } /* if */
 14.1255 +      /* store matched pattern */
 14.1256 +      pattern=(char*)malloc(count+1);
 14.1257 +      if (pattern==NULL)
 14.1258 +        error(103);     /* insufficient memory */
 14.1259 +      lptr=start;
 14.1260 +      count=0;
 14.1261 +      while (lptr!=end) {
 14.1262 +        assert(lptr<end);
 14.1263 +        assert(*lptr!='\0');
 14.1264 +        pattern[count++]=(char)litchar(&lptr,0);
 14.1265 +      } /* while */
 14.1266 +      pattern[count]='\0';
 14.1267 +      /* special case, erase trailing variable, because it could match anything */
 14.1268 +      if (count>=2 && isdigit(pattern[count-1]) && pattern[count-2]=='%')
 14.1269 +        pattern[count-2]='\0';
 14.1270 +      /* find substitution string */
 14.1271 +      while (*lptr<=' ' && *lptr!='\0')
 14.1272 +        lptr++;
 14.1273 +      start=lptr;       /* save starting point of the match pattern */
 14.1274 +      count=0;
 14.1275 +      end=NULL;
 14.1276 +      while (*lptr!='\0') {
 14.1277 +        /* keep position of the start of trailing whitespace */
 14.1278 +        if (*lptr<=' ') {
 14.1279 +          if (end==NULL)
 14.1280 +            end=lptr;
 14.1281 +        } else {
 14.1282 +          end=NULL;
 14.1283 +        } /* if */
 14.1284 +        count++;
 14.1285 +        lptr++;
 14.1286 +      } /* while */
 14.1287 +      if (end==NULL)
 14.1288 +        end=lptr;
 14.1289 +      /* store matched substitution */
 14.1290 +      substitution=(char*)malloc(count+1);  /* +1 for '\0' */
 14.1291 +      if (substitution==NULL)
 14.1292 +        error(103);     /* insufficient memory */
 14.1293 +      lptr=start;
 14.1294 +      count=0;
 14.1295 +      while (lptr!=end) {
 14.1296 +        assert(lptr<end);
 14.1297 +        assert(*lptr!='\0');
 14.1298 +        substitution[count++]=*lptr++;
 14.1299 +      } /* while */
 14.1300 +      substitution[count]='\0';
 14.1301 +      /* check whether the definition already exists */
 14.1302 +      for (prefixlen=0,start=(unsigned char*)pattern; alphanum(*start); prefixlen++,start++)
 14.1303 +        /* nothing */;
 14.1304 +      assert(prefixlen>0);
 14.1305 +      if ((def=find_subst(pattern,prefixlen))!=NULL) {
 14.1306 +        if (strcmp(def->first,pattern)!=0 || strcmp(def->second,substitution)!=0)
 14.1307 +          error(201,pattern);   /* redefinition of macro (non-identical) */
 14.1308 +        delete_subst(pattern,prefixlen);
 14.1309 +      } /* if */
 14.1310 +      /* add the pattern/substitution pair to the list */
 14.1311 +      assert(strlen(pattern)>0);
 14.1312 +      insert_subst(pattern,substitution,prefixlen);
 14.1313 +      free(pattern);
 14.1314 +      free(substitution);
 14.1315 +    } /* if */
 14.1316 +    break;
 14.1317 +  } /* case */
 14.1318 +  case tpUNDEF:
 14.1319 +    if (!SKIPPING) {
 14.1320 +      if (lex(&val,&str)==tSYMBOL) {
 14.1321 +        ret=delete_subst(str,strlen(str));
 14.1322 +        if (!ret) {
 14.1323 +          /* also undefine normal constants */
 14.1324 +          symbol *sym=findconst(str,NULL);
 14.1325 +          if (sym!=NULL && (sym->usage & (uENUMROOT | uENUMFIELD))==0) {
 14.1326 +            delete_symbol(&glbtab,sym);
 14.1327 +            ret=TRUE;
 14.1328 +          } /* if */
 14.1329 +        } /* if */
 14.1330 +        if (!ret)
 14.1331 +          error(17,str);        /* undefined symbol */
 14.1332 +      } else {
 14.1333 +        error(20,str);          /* invalid symbol name */
 14.1334 +      } /* if */
 14.1335 +      check_empty(lptr);
 14.1336 +    } /* if */
 14.1337 +    break;
 14.1338 +#endif
 14.1339 +  case tpERROR:
 14.1340 +    while (*lptr<=' ' && *lptr!='\0')
 14.1341 +      lptr++;
 14.1342 +    if (!SKIPPING)
 14.1343 +      error(111,lptr);  /* user error */
 14.1344 +    break;
 14.1345 +  default:
 14.1346 +    error(31);          /* unknown compiler directive */
 14.1347 +    ret=SKIPPING ? CMD_CONDFALSE : CMD_NONE;  /* process as normal line */
 14.1348 +  } /* switch */
 14.1349 +  return ret;
 14.1350 +}
 14.1351 +
 14.1352 +#if !defined NO_DEFINE
 14.1353 +static int is_startstring(const unsigned char *string)
 14.1354 +{
 14.1355 +  if (*string=='\"' || *string=='\'')
 14.1356 +    return TRUE;                        /* "..." */
 14.1357 +
 14.1358 +  if (*string=='!') {
 14.1359 +    string++;
 14.1360 +    if (*string=='\"' || *string=='\'')
 14.1361 +      return TRUE;                      /* !"..." */
 14.1362 +    if (*string==sc_ctrlchar) {
 14.1363 +      string++;
 14.1364 +      if (*string=='\"' || *string=='\'')
 14.1365 +        return TRUE;                    /* !\"..." */
 14.1366 +    } /* if */
 14.1367 +  } else if (*string==sc_ctrlchar) {
 14.1368 +    string++;
 14.1369 +    if (*string=='\"' || *string=='\'')
 14.1370 +      return TRUE;                      /* \"..." */
 14.1371 +    if (*string=='!') {
 14.1372 +      string++;
 14.1373 +      if (*string=='\"' || *string=='\'')
 14.1374 +        return TRUE;                    /* \!"..." */
 14.1375 +    } /* if */
 14.1376 +  } /* if */
 14.1377 +
 14.1378 +  return FALSE;
 14.1379 +}
 14.1380 +
 14.1381 +static const unsigned char *skipstring(const unsigned char *string)
 14.1382 +{
 14.1383 +  char endquote;
 14.1384 +  int flags=0;
 14.1385 +
 14.1386 +  while (*string=='!' || *string==sc_ctrlchar) {
 14.1387 +    if (*string==sc_ctrlchar)
 14.1388 +      flags=RAWMODE;
 14.1389 +    string++;
 14.1390 +  } /* while */
 14.1391 +
 14.1392 +  endquote=*string;
 14.1393 +  assert(endquote=='"' || endquote=='\'');
 14.1394 +  string++;             /* skip open quote */
 14.1395 +  while (*string!=endquote && *string!='\0')
 14.1396 +    litchar(&string,flags);
 14.1397 +  return string;
 14.1398 +}
 14.1399 +
 14.1400 +static const unsigned char *skippgroup(const unsigned char *string)
 14.1401 +{
 14.1402 +  int nest=0;
 14.1403 +  char open=*string;
 14.1404 +  char close;
 14.1405 +
 14.1406 +  switch (open) {
 14.1407 +  case '(':
 14.1408 +    close=')';
 14.1409 +    break;
 14.1410 +  case '{':
 14.1411 +    close='}';
 14.1412 +    break;
 14.1413 +  case '[':
 14.1414 +    close=']';
 14.1415 +    break;
 14.1416 +  case '<':
 14.1417 +    close='>';
 14.1418 +    break;
 14.1419 +  default:
 14.1420 +    assert(0);
 14.1421 +	close='\0';         /* only to avoid a compiler warning */
 14.1422 +  }/* switch */
 14.1423 +
 14.1424 +  string++;
 14.1425 +  while (*string!=close || nest>0) {
 14.1426 +    if (*string==open)
 14.1427 +      nest++;
 14.1428 +    else if (*string==close)
 14.1429 +      nest--;
 14.1430 +    else if (is_startstring(string))
 14.1431 +      string=skipstring(string);
 14.1432 +    if (*string=='\0')
 14.1433 +      break;
 14.1434 +    string++;
 14.1435 +  } /* while */
 14.1436 +  return string;
 14.1437 +}
 14.1438 +
 14.1439 +static char *strdel(char *str,size_t len)
 14.1440 +{
 14.1441 +  size_t length=strlen(str);
 14.1442 +  if (len>length)
 14.1443 +    len=length;
 14.1444 +  memmove(str, str+len, length-len+1);  /* include EOS byte */
 14.1445 +  return str;
 14.1446 +}
 14.1447 +
 14.1448 +static char *strins(char *dest,char *src,size_t srclen)
 14.1449 +{
 14.1450 +  size_t destlen=strlen(dest);
 14.1451 +  assert(srclen<=strlen(src));
 14.1452 +  memmove(dest+srclen, dest, destlen+1);/* include EOS byte */
 14.1453 +  memcpy(dest, src, srclen);
 14.1454 +  return dest;
 14.1455 +}
 14.1456 +
 14.1457 +static int substpattern(unsigned char *line,size_t buffersize,char *pattern,char *substitution)
 14.1458 +{
 14.1459 +  int prefixlen;
 14.1460 +  const unsigned char *p,*s,*e;
 14.1461 +  unsigned char *args[10];
 14.1462 +  int match,arg,len;
 14.1463 +
 14.1464 +  memset(args,0,sizeof args);
 14.1465 +
 14.1466 +  /* check the length of the prefix */
 14.1467 +  for (prefixlen=0,s=(unsigned char*)pattern; alphanum(*s); prefixlen++,s++)
 14.1468 +    /* nothing */;
 14.1469 +  assert(prefixlen>0);
 14.1470 +  assert(strncmp((char*)line,pattern,prefixlen)==0);
 14.1471 +
 14.1472 +  /* pattern prefix matches; match the rest of the pattern, gather
 14.1473 +   * the parameters
 14.1474 +   */
 14.1475 +  s=line+prefixlen;
 14.1476 +  p=(unsigned char*)pattern+prefixlen;
 14.1477 +  match=TRUE;         /* so far, pattern matches */
 14.1478 +  while (match && *s!='\0' && *p!='\0') {
 14.1479 +    if (*p=='%') {
 14.1480 +      p++;            /* skip '%' */
 14.1481 +      if (isdigit(*p)) {
 14.1482 +        arg=*p-'0';
 14.1483 +        assert(arg>=0 && arg<=9);
 14.1484 +        p++;          /* skip parameter id */
 14.1485 +        assert(*p!='\0');
 14.1486 +        /* match the source string up to the character after the digit
 14.1487 +         * (skipping strings in the process
 14.1488 +         */
 14.1489 +        e=s;
 14.1490 +        while (*e!=*p && *e!='\0' && *e!='\n') {
 14.1491 +          if (is_startstring(e))              /* skip strings */
 14.1492 +            e=skipstring(e);
 14.1493 +          else if (strchr("({[",*e)!=NULL)    /* skip parenthized groups */
 14.1494 +            e=skippgroup(e);
 14.1495 +          if (*e!='\0')
 14.1496 +            e++;      /* skip non-alphapetic character (or closing quote of
 14.1497 +                       * a string, or the closing paranthese of a group) */
 14.1498 +        } /* while */
 14.1499 +        /* store the parameter (overrule any earlier) */
 14.1500 +        if (args[arg]!=NULL)
 14.1501 +          free(args[arg]);
 14.1502 +        len=(int)(e-s);
 14.1503 +        args[arg]=(unsigned char*)malloc(len+1);
 14.1504 +        if (args[arg]==NULL)
 14.1505 +          error(103); /* insufficient memory */
 14.1506 +        strlcpy((char*)args[arg],(char*)s,len+1);
 14.1507 +        /* character behind the pattern was matched too */
 14.1508 +        if (*e==*p) {
 14.1509 +          s=e+1;
 14.1510 +        } else if (*e=='\n' && *p==';' && *(p+1)=='\0' && !sc_needsemicolon) {
 14.1511 +          s=e;    /* allow a trailing ; in the pattern match to end of line */
 14.1512 +        } else {
 14.1513 +          assert(*e=='\0' || *e=='\n');
 14.1514 +          match=FALSE;
 14.1515 +          s=e;
 14.1516 +        } /* if */
 14.1517 +        p++;
 14.1518 +      } else {
 14.1519 +        match=FALSE;
 14.1520 +      } /* if */
 14.1521 +    } else if (*p==';' && *(p+1)=='\0' && !sc_needsemicolon) {
 14.1522 +      /* source may be ';' or end of the line */
 14.1523 +      while (*s<=' ' && *s!='\0')
 14.1524 +        s++;          /* skip white space */
 14.1525 +      if (*s!=';' && *s!='\0')
 14.1526 +        match=FALSE;
 14.1527 +      p++;            /* skip the semicolon in the pattern */
 14.1528 +    } else {
 14.1529 +      cell ch;
 14.1530 +      /* skip whitespace between two non-alphanumeric characters, except
 14.1531 +       * for two identical symbols
 14.1532 +       */
 14.1533 +      assert((char*)p>pattern);
 14.1534 +      if (!alphanum(*p) && *(p-1)!=*p)
 14.1535 +        while (*s<=' ' && *s!='\0')
 14.1536 +          s++;                  /* skip white space */
 14.1537 +      ch=litchar(&p,0);         /* this increments "p" */
 14.1538 +      if (*s!=ch)
 14.1539 +        match=FALSE;
 14.1540 +      else
 14.1541 +        s++;                    /* this character matches */
 14.1542 +    } /* if */
 14.1543 +  } /* while */
 14.1544 +
 14.1545 +  if (match && *p=='\0') {
 14.1546 +    /* if the last character to match is an alphanumeric character, the
 14.1547 +     * current character in the source may not be alphanumeric
 14.1548 +     */
 14.1549 +    assert(p>(unsigned char*)pattern);
 14.1550 +    if (alphanum(*(p-1)) && alphanum(*s))
 14.1551 +      match=FALSE;
 14.1552 +  } /* if */
 14.1553 +
 14.1554 +  if (match) {
 14.1555 +    /* calculate the length of the substituted string */
 14.1556 +    for (e=(unsigned char*)substitution,len=0; *e!='\0'; e++) {
 14.1557 +      if (*e=='%' && isdigit(*(e+1))) {
 14.1558 +        arg=*(e+1)-'0';
 14.1559 +        assert(arg>=0 && arg<=9);
 14.1560 +        if (args[arg]!=NULL)
 14.1561 +          len+=strlen((char*)args[arg]);
 14.1562 +        else
 14.1563 +          len+=2;     /* copy '%' plus digit */
 14.1564 +        e++;          /* skip %, digit is skipped later */
 14.1565 +      } else {
 14.1566 +        len++;
 14.1567 +      } /* if */
 14.1568 +    } /* for */
 14.1569 +    /* check length of the string after substitution */
 14.1570 +    if (strlen((char*)line) + len - (int)(s-line) > buffersize) {
 14.1571 +      error(75);      /* line too long */
 14.1572 +    } else {
 14.1573 +      /* substitute pattern */
 14.1574 +      strdel((char*)line,(int)(s-line));
 14.1575 +      for (e=(unsigned char*)substitution,s=line; *e!='\0'; e++) {
 14.1576 +        if (*e=='%' && isdigit(*(e+1))) {
 14.1577 +          arg=*(e+1)-'0';
 14.1578 +          assert(arg>=0 && arg<=9);
 14.1579 +          if (args[arg]!=NULL) {
 14.1580 +            strins((char*)s,(char*)args[arg],strlen((char*)args[arg]));
 14.1581 +            s+=strlen((char*)args[arg]);
 14.1582 +          } else {
 14.1583 +            error(236); /* parameter does not exist, incorrect #define pattern */
 14.1584 +            strins((char*)s,(char*)e,2);
 14.1585 +            s+=2;
 14.1586 +          } /* if */
 14.1587 +          e++;          /* skip %, digit is skipped later */
 14.1588 +        } else {
 14.1589 +          strins((char*)s,(char*)e,1);
 14.1590 +          s++;
 14.1591 +        } /* if */
 14.1592 +      } /* for */
 14.1593 +    } /* if */
 14.1594 +  } /* if */
 14.1595 +
 14.1596 +  for (arg=0; arg<10; arg++)
 14.1597 +    if (args[arg]!=NULL)
 14.1598 +      free(args[arg]);
 14.1599 +
 14.1600 +  return match;
 14.1601 +}
 14.1602 +
 14.1603 +static void substallpatterns(unsigned char *line,int buffersize)
 14.1604 +{
 14.1605 +  unsigned char *start, *end;
 14.1606 +  int prefixlen;
 14.1607 +  stringpair *subst;
 14.1608 +
 14.1609 +  start=line;
 14.1610 +  while (*start!='\0') {
 14.1611 +    /* find the start of a prefix (skip all non-alphabetic characters),
 14.1612 +     * also skip strings
 14.1613 +     */
 14.1614 +    while (!alpha(*start) && *start!='\0') {
 14.1615 +      /* skip strings */
 14.1616 +      if (is_startstring(start)) {
 14.1617 +        start=(unsigned char *)skipstring(start);
 14.1618 +        if (*start=='\0')
 14.1619 +          break;        /* abort loop on error */
 14.1620 +      } /* if */
 14.1621 +      start++;          /* skip non-alphapetic character (or closing quote of a string) */
 14.1622 +    } /* while */
 14.1623 +    if (*start=='\0')
 14.1624 +      break;            /* abort loop on error */
 14.1625 +    /* if matching the operator "defined", skip it plus the symbol behind it */
 14.1626 +    if (strncmp((char*)start,"defined",7)==0 && *(start+7)<=' ') {
 14.1627 +      start+=7;         /* skip "defined" */
 14.1628 +      /* skip white space & parantheses */
 14.1629 +      while (*start<=' ' && *start!='\0' || *start=='(')
 14.1630 +        start++;
 14.1631 +      /* skip the symbol behind it */
 14.1632 +      while (alphanum(*start))
 14.1633 +        start++;
 14.1634 +      /* drop back into the main loop */
 14.1635 +      continue;
 14.1636 +    } /* if */
 14.1637 +    /* get the prefix (length), look for a matching definition */
 14.1638 +    prefixlen=0;
 14.1639 +    end=start;
 14.1640 +    while (alphanum(*end)) {
 14.1641 +      prefixlen++;
 14.1642 +      end++;
 14.1643 +    } /* while */
 14.1644 +    assert(prefixlen>0);
 14.1645 +    subst=find_subst((char*)start,prefixlen);
 14.1646 +    if (subst!=NULL) {
 14.1647 +      /* properly match the pattern and substitute */
 14.1648 +      if (!substpattern(start,buffersize-(int)(start-line),subst->first,subst->second))
 14.1649 +        start=end;      /* match failed, skip this prefix */
 14.1650 +      /* match succeeded: do not update "start", because the substitution text
 14.1651 +       * may be matched by other macros
 14.1652 +       */
 14.1653 +    } else {
 14.1654 +      start=end;        /* no macro with this prefix, skip this prefix */
 14.1655 +    } /* if */
 14.1656 +  } /* while */
 14.1657 +}
 14.1658 +#endif
 14.1659 +
 14.1660 +/*  preprocess
 14.1661 + *
 14.1662 + *  Reads a line by readline() into "pline" and performs basic preprocessing:
 14.1663 + *  deleting comments, skipping lines with false "#if.." code and recognizing
 14.1664 + *  other compiler directives. There is an indirect recursion: lex() calls
 14.1665 + *  preprocess() if a new line must be read, preprocess() calls command(),
 14.1666 + *  which at his turn calls lex() to identify the token.
 14.1667 + *
 14.1668 + *  Global references: lptr     (altered)
 14.1669 + *                     pline    (altered)
 14.1670 + *                     freading (referred to only)
 14.1671 + */
 14.1672 +SC_FUNC void preprocess(void)
 14.1673 +{
 14.1674 +  int iscommand;
 14.1675 +
 14.1676 +  if (!freading)
 14.1677 +    return;
 14.1678 +  do {
 14.1679 +    readline(pline);
 14.1680 +    stripcom(pline);    /* ??? no need for this when reading back from list file (in the second pass) */
 14.1681 +    lptr=pline;         /* set "line pointer" to start of the parsing buffer */
 14.1682 +    iscommand=command();
 14.1683 +    if (iscommand!=CMD_NONE)
 14.1684 +      errorset(sRESET,0); /* reset error flag ("panic mode") on empty line or directive */
 14.1685 +    #if !defined NO_DEFINE
 14.1686 +      if (iscommand==CMD_NONE) {
 14.1687 +        assert(lptr!=term_expr);
 14.1688 +        substallpatterns(pline,sLINEMAX);
 14.1689 +        lptr=pline;       /* reset "line pointer" to start of the parsing buffer */
 14.1690 +      } /* if */
 14.1691 +    #endif
 14.1692 +    if (sc_status==statFIRST && sc_listing && freading
 14.1693 +        && (iscommand==CMD_NONE || iscommand==CMD_EMPTYLINE || iscommand==CMD_DIRECTIVE))
 14.1694 +    {
 14.1695 +      listline++;
 14.1696 +      if (fline!=listline) {
 14.1697 +        listline=fline;
 14.1698 +        setlinedirect(fline);
 14.1699 +      } /* if */
 14.1700 +      if (iscommand==CMD_EMPTYLINE)
 14.1701 +        pc_writeasm(outf,"\n");
 14.1702 +      else
 14.1703 +        pc_writeasm(outf,(char*)pline);
 14.1704 +    } /* if */
 14.1705 +  } while (iscommand!=CMD_NONE && iscommand!=CMD_TERM && freading); /* enddo */
 14.1706 +}
 14.1707 +
 14.1708 +static const unsigned char *unpackedstring(const unsigned char *lptr,int flags)
 14.1709 +{
 14.1710 +  while (*lptr!='\"' && *lptr!='\0') {
 14.1711 +    if (*lptr=='\a') {          /* ignore '\a' (which was inserted at a line concatenation) */
 14.1712 +      lptr++;
 14.1713 +      continue;
 14.1714 +    } /* if */
 14.1715 +    litadd(litchar(&lptr,flags | UTF8MODE));  /* litchar() alters "lptr" */
 14.1716 +  } /* while */
 14.1717 +  litadd(0);                    /* terminate string */
 14.1718 +  return lptr;
 14.1719 +}
 14.1720 +
 14.1721 +static const unsigned char *packedstring(const unsigned char *lptr,int flags)
 14.1722 +{
 14.1723 +  int i;
 14.1724 +  ucell val,c;
 14.1725 +
 14.1726 +  i=sizeof(ucell)-(sCHARBITS/8); /* start at most significant byte */
 14.1727 +  val=0;
 14.1728 +  while (*lptr!='\"' && *lptr!='\0') {
 14.1729 +    if (*lptr=='\a') {          /* ignore '\a' (which was inserted at a line concatenation) */
 14.1730 +      lptr++;
 14.1731 +      continue;
 14.1732 +    } /* if */
 14.1733 +    c=litchar(&lptr,flags);     /* litchar() alters "lptr" */
 14.1734 +    if (c>=(ucell)(1 << sCHARBITS))
 14.1735 +      error(43);                /* character constant exceeds range */
 14.1736 +    val |= (c << 8*i);
 14.1737 +    if (i==0) {
 14.1738 +      litadd(val);
 14.1739 +      val=0;
 14.1740 +    } /* if */
 14.1741 +    i=(i+sizeof(ucell)-(sCHARBITS/8)) % sizeof(ucell);
 14.1742 +  } /* if */
 14.1743 +  /* save last code; make sure there is at least one terminating zero character */
 14.1744 +  if (i!=(int)(sizeof(ucell)-(sCHARBITS/8)))
 14.1745 +    litadd(val);        /* at least one zero character in "val" */
 14.1746 +  else
 14.1747 +    litadd(0);          /* add full cell of zeros */
 14.1748 +  return lptr;
 14.1749 +}
 14.1750 +
 14.1751 +/*  lex(lexvalue,lexsym)        Lexical Analysis
 14.1752 + *
 14.1753 + *  lex() first deletes leading white space, then checks for multi-character
 14.1754 + *  operators, keywords (including most compiler directives), numbers,
 14.1755 + *  labels, symbols and literals (literal characters are converted to a number
 14.1756 + *  and are returned as such). If every check fails, the line must contain
 14.1757 + *  a single-character operator. So, lex() returns this character. In the other
 14.1758 + *  case (something did match), lex() returns the number of the token. All
 14.1759 + *  these tokens have been assigned numbers above 255.
 14.1760 + *
 14.1761 + *  Some tokens have "attributes":
 14.1762 + *     tNUMBER        the value of the number is return in "lexvalue".
 14.1763 + *     tRATIONAL      the value is in IEEE 754 encoding or in fixed point
 14.1764 + *                    encoding in "lexvalue".
 14.1765 + *     tSYMBOL        the first sNAMEMAX characters of the symbol are
 14.1766 + *                    stored in a buffer, a pointer to this buffer is
 14.1767 + *                    returned in "lexsym".
 14.1768 + *     tLABEL         the first sNAMEMAX characters of the label are
 14.1769 + *                    stored in a buffer, a pointer to this buffer is
 14.1770 + *                    returned in "lexsym".
 14.1771 + *     tSTRING        the string is stored in the literal pool, the index
 14.1772 + *                    in the literal pool to this string is stored in
 14.1773 + *                    "lexvalue".
 14.1774 + *
 14.1775 + *  lex() stores all information (the token found and possibly its attribute)
 14.1776 + *  in global variables. This allows a token to be examined twice. If "_pushed"
 14.1777 + *  is true, this information is returned.
 14.1778 + *
 14.1779 + *  Global references: lptr          (altered)
 14.1780 + *                     fline         (referred to only)
 14.1781 + *                     litidx        (referred to only)
 14.1782 + *                     _lextok, _lexval, _lexstr
 14.1783 + *                     _pushed
 14.1784 + */
 14.1785 +
 14.1786 +static int _pushed;
 14.1787 +static int _lextok;
 14.1788 +static cell _lexval;
 14.1789 +static char _lexstr[sLINEMAX+1];
 14.1790 +static int _lexnewline;
 14.1791 +
 14.1792 +SC_FUNC void lexinit(void)
 14.1793 +{
 14.1794 +  stkidx=0;             /* index for pushstk() and popstk() */
 14.1795 +  iflevel=0;            /* preprocessor: nesting of "#if" is currently 0 */
 14.1796 +  skiplevel=0;          /* preprocessor: not currently skipping */
 14.1797 +  icomment=0;           /* currently not in a multiline comment */
 14.1798 +  _pushed=FALSE;        /* no token pushed back into lex */
 14.1799 +  _lexnewline=FALSE;
 14.1800 +}
 14.1801 +
 14.1802 +char *sc_tokens[] = {
 14.1803 +         "*=", "/=", "%=", "+=", "-=", "<<=", ">>>=", ">>=", "&=", "^=", "|=",
 14.1804 +         "||", "&&", "==", "!=", "<=", ">=", "<<", ">>>", ">>", "++", "--",
 14.1805 +         "...", "..", "::",
 14.1806 +         "assert", "break", "case", "char", "const", "continue", "default",
 14.1807 +         "defined", "do", "else", "enum", "exit", "for", "forward", "goto",
 14.1808 +         "if", "native", "new", "decl", "operator", "public", "return", "sizeof",
 14.1809 +         "sleep", "state", "static", "stock", "switch", "tagof", "while",
 14.1810 +         "#assert", "#define", "#else", "#elseif", "#emit", "#endif", "#endinput",
 14.1811 +         "#endscript", "#error", "#file", "#if", "#include", "#line", "#pragma",
 14.1812 +         "#tryinclude", "#undef",
 14.1813 +         ";", ";", "-integer value-", "-rational value-", "-identifier-",
 14.1814 +         "-label-", "-string-"
 14.1815 +       };
 14.1816 +
 14.1817 +SC_FUNC int lex(cell *lexvalue,char **lexsym)
 14.1818 +{
 14.1819 +  int i,toolong,newline,stringflags;
 14.1820 +  char **tokptr;
 14.1821 +  const unsigned char *starttoken;
 14.1822 +
 14.1823 +  if (_pushed) {
 14.1824 +    _pushed=FALSE;      /* reset "_pushed" flag */
 14.1825 +    *lexvalue=_lexval;
 14.1826 +    *lexsym=_lexstr;
 14.1827 +    return _lextok;
 14.1828 +  } /* if */
 14.1829 +
 14.1830 +  _lextok=0;            /* preset all values */
 14.1831 +  _lexval=0;
 14.1832 +  _lexstr[0]='\0';
 14.1833 +  *lexvalue=_lexval;
 14.1834 +  *lexsym=_lexstr;
 14.1835 +  _lexnewline=FALSE;
 14.1836 +  if (!freading)
 14.1837 +    return 0;
 14.1838 +
 14.1839 +  newline= (lptr==pline);       /* does lptr point to start of line buffer */
 14.1840 +  while (*lptr<=' ') {          /* delete leading white space */
 14.1841 +    if (*lptr=='\0') {
 14.1842 +      preprocess();             /* preprocess resets "lptr" */
 14.1843 +      if (!freading)
 14.1844 +        return 0;
 14.1845 +      if (lptr==term_expr)      /* special sequence to terminate a pending expression */
 14.1846 +        return (_lextok=tENDEXPR);
 14.1847 +      _lexnewline=TRUE;         /* set this after preprocess(), because
 14.1848 +                                 * preprocess() calls lex() recursively */
 14.1849 +      newline=TRUE;
 14.1850 +    } else {
 14.1851 +      lptr+=1;
 14.1852 +    } /* if */
 14.1853 +  } /* while */
 14.1854 +  if (newline) {
 14.1855 +    stmtindent=0;
 14.1856 +    for (i=0; i<(int)(lptr-pline); i++)
 14.1857 +      if (pline[i]=='\t' && sc_tabsize>0)
 14.1858 +        stmtindent += (int)(sc_tabsize - (stmtindent+sc_tabsize) % sc_tabsize);
 14.1859 +      else
 14.1860 +        stmtindent++;
 14.1861 +  } /* if */
 14.1862 +
 14.1863 +  i=tFIRST;
 14.1864 +  tokptr=sc_tokens;
 14.1865 +  while (i<=tMIDDLE) {  /* match multi-character operators */
 14.1866 +    if (*lptr==**tokptr && match(*tokptr,FALSE)) {
 14.1867 +      _lextok=i;
 14.1868 +      if (pc_docexpr)   /* optionally concatenate to documentation string */
 14.1869 +        insert_autolist(*tokptr);
 14.1870 +      return _lextok;
 14.1871 +    } /* if */
 14.1872 +    i+=1;
 14.1873 +    tokptr+=1;
 14.1874 +  } /* while */
 14.1875 +  while (i<=tLAST) {    /* match reserved words and compiler directives */
 14.1876 +    if (*lptr==**tokptr && match(*tokptr,TRUE)) {
 14.1877 +      _lextok=i;
 14.1878 +      errorset(sRESET,0); /* reset error flag (clear the "panic mode")*/
 14.1879 +      if (pc_docexpr)   /* optionally concatenate to documentation string */
 14.1880 +        insert_autolist(*tokptr);
 14.1881 +      return _lextok;
 14.1882 +    } /* if */
 14.1883 +    i+=1;
 14.1884 +    tokptr+=1;
 14.1885 +  } /* while */
 14.1886 +
 14.1887 +  starttoken=lptr;      /* save start pointer (for concatenating to documentation string) */
 14.1888 +  if ((i=number(&_lexval,lptr))!=0) {   /* number */
 14.1889 +    _lextok=tNUMBER;
 14.1890 +    *lexvalue=_lexval;
 14.1891 +    lptr+=i;
 14.1892 +  } else if ((i=ftoi(&_lexval,lptr))!=0) {
 14.1893 +    _lextok=tRATIONAL;
 14.1894 +    *lexvalue=_lexval;
 14.1895 +    lptr+=i;
 14.1896 +  } else if (alpha(*lptr)) {            /* symbol or label */
 14.1897 +    /*  Note: only sNAMEMAX characters are significant. The compiler
 14.1898 +     *        generates a warning if a symbol exceeds this length.
 14.1899 +     */
 14.1900 +    _lextok=tSYMBOL;
 14.1901 +    i=0;
 14.1902 +    toolong=0;
 14.1903 +    while (alphanum(*lptr)){
 14.1904 +      _lexstr[i]=*lptr;
 14.1905 +      lptr+=1;
 14.1906 +      if (i<sNAMEMAX)
 14.1907 +        i+=1;
 14.1908 +      else
 14.1909 +        toolong=1;
 14.1910 +    } /* while */
 14.1911 +    _lexstr[i]='\0';
 14.1912 +    if (toolong)
 14.1913 +      error(200,_lexstr,sNAMEMAX);  /* symbol too long, truncated to sNAMEMAX chars */
 14.1914 +    if (_lexstr[0]==PUBLIC_CHAR && _lexstr[1]=='\0') {
 14.1915 +      _lextok=PUBLIC_CHAR;  /* '@' all alone is not a symbol, it is an operator */
 14.1916 +    } else if (_lexstr[0]=='_' && _lexstr[1]=='\0') {
 14.1917 +      _lextok='_';      /* '_' by itself is not a symbol, it is a placeholder */
 14.1918 +    } /* if */
 14.1919 +    if (*lptr==':' && *(lptr+1)!=':' && _lextok!=PUBLIC_CHAR) {
 14.1920 +      if (sc_allowtags) {
 14.1921 +        _lextok=tLABEL; /* it wasn't a normal symbol, it was a label/tagname */
 14.1922 +        lptr+=1;        /* skip colon */
 14.1923 +      } else if (find_constval(&tagname_tab,_lexstr,0)!=NULL) {
 14.1924 +        /* this looks like a tag override (because a tag with this name
 14.1925 +         * exists), but tags are not allowed right now, so it is probably an
 14.1926 +         * error
 14.1927 +         */
 14.1928 +        error(220);
 14.1929 +      } /* if */
 14.1930 +    } /* if */
 14.1931 +  } else if (*lptr=='\"' || *lptr==sc_ctrlchar && *(lptr+1)=='\"')
 14.1932 +  {                                     /* unpacked string literal */
 14.1933 +    _lextok=tSTRING;
 14.1934 +    stringflags= (*lptr==sc_ctrlchar) ? RAWMODE : 0;
 14.1935 +    *lexvalue=_lexval=litidx;
 14.1936 +    lptr+=1;            /* skip double quote */
 14.1937 +    if ((stringflags & RAWMODE)!=0)
 14.1938 +      lptr+=1;          /* skip "escape" character too */
 14.1939 +    lptr=sc_packstr ? packedstring(lptr,stringflags) : unpackedstring(lptr,stringflags);
 14.1940 +    if (*lptr=='\"')
 14.1941 +      lptr+=1;          /* skip final quote */
 14.1942 +    else
 14.1943 +      error(37);        /* invalid (non-terminated) string */
 14.1944 +  } else if (*lptr=='!' && *(lptr+1)=='\"'
 14.1945 +             || *lptr=='!' && *(lptr+1)==sc_ctrlchar && *(lptr+2)=='\"'
 14.1946 +             || *lptr==sc_ctrlchar && *(lptr+1)=='!' && *(lptr+2)=='\"')
 14.1947 +  {                                     /* packed string literal */
 14.1948 +    _lextok=tSTRING;
 14.1949 +    stringflags= (*lptr==sc_ctrlchar || *(lptr+1)==sc_ctrlchar) ? RAWMODE : 0;
 14.1950 +    *lexvalue=_lexval=litidx;
 14.1951 +    lptr+=2;            /* skip exclamation point and double quote */
 14.1952 +    if ((stringflags & RAWMODE)!=0)
 14.1953 +      lptr+=1;          /* skip "escape" character too */
 14.1954 +    lptr=sc_packstr ? unpackedstring(lptr,stringflags) : packedstring(lptr,stringflags);
 14.1955 +    if (*lptr=='\"')
 14.1956 +      lptr+=1;          /* skip final quote */
 14.1957 +    else
 14.1958 +      error(37);        /* invalid (non-terminated) string */
 14.1959 +  } else if (*lptr=='\'') {             /* character literal */
 14.1960 +    lptr+=1;            /* skip quote */
 14.1961 +    _lextok=tNUMBER;
 14.1962 +    *lexvalue=_lexval=litchar(&lptr,UTF8MODE);
 14.1963 +    if (*lptr=='\'')
 14.1964 +      lptr+=1;          /* skip final quote */
 14.1965 +    else
 14.1966 +      error(27);        /* invalid character constant (must be one character) */
 14.1967 +  } else if (*lptr==';') {      /* semicolumn resets "error" flag */
 14.1968 +    _lextok=';';
 14.1969 +    lptr+=1;
 14.1970 +    errorset(sRESET,0); /* reset error flag (clear the "panic mode")*/
 14.1971 +  } else {
 14.1972 +    _lextok=*lptr;      /* if every match fails, return the character */
 14.1973 +    lptr+=1;            /* increase the "lptr" pointer */
 14.1974 +  } /* if */
 14.1975 +
 14.1976 +  if (pc_docexpr) {     /* optionally concatenate to documentation string */
 14.1977 +    char *docstr=(char*)malloc(((int)(lptr-starttoken)+1)*sizeof(char));
 14.1978 +    if (docstr!=NULL) {
 14.1979 +      strlcpy(docstr,(char*)starttoken,(int)(lptr-starttoken)+1);
 14.1980 +      insert_autolist(docstr);
 14.1981 +      free(docstr);
 14.1982 +    } /* if */
 14.1983 +  } /* if */
 14.1984 +  return _lextok;
 14.1985 +}
 14.1986 +
 14.1987 +/*  lexpush
 14.1988 + *
 14.1989 + *  Pushes a token back, so the next call to lex() will return the token
 14.1990 + *  last examined, instead of a new token.
 14.1991 + *
 14.1992 + *  Only one token can be pushed back.
 14.1993 + *
 14.1994 + *  In fact, lex() already stores the information it finds into global
 14.1995 + *  variables, so all that is to be done is set a flag that informs lex()
 14.1996 + *  to read and return the information from these variables, rather than
 14.1997 + *  to read in a new token from the input file.
 14.1998 + */
 14.1999 +SC_FUNC void lexpush(void)
 14.2000 +{
 14.2001 +  assert(_pushed==FALSE);
 14.2002 +  _pushed=TRUE;
 14.2003 +}
 14.2004 +
 14.2005 +/*  lexclr
 14.2006 + *
 14.2007 + *  Sets the variable "_pushed" to 0 to make sure lex() will read in a new
 14.2008 + *  symbol (a not continue with some old one). This is required upon return
 14.2009 + *  from Assembler mode, and in a few cases after detecting an syntax error.
 14.2010 + */
 14.2011 +SC_FUNC void lexclr(int clreol)
 14.2012 +{
 14.2013 +  _pushed=FALSE;
 14.2014 +  if (clreol) {
 14.2015 +    lptr=(unsigned char*)strchr((char*)pline,'\0');
 14.2016 +    assert(lptr!=NULL);
 14.2017 +  } /* if */
 14.2018 +}
 14.2019 +
 14.2020 +/*  matchtoken
 14.2021 + *
 14.2022 + *  This routine is useful if only a simple check is needed. If the token
 14.2023 + *  differs from the one expected, it is pushed back.
 14.2024 + *  This function returns 1 for "token found" and 2 for "implied statement
 14.2025 + *  termination token" found --the statement termination is an end of line in
 14.2026 + *  an expression where there is no pending operation. Such an implied token
 14.2027 + *  (i.e. not present in the source code) should not be pushed back, which is
 14.2028 + *  why it is sometimes important to distinguish the two.
 14.2029 + */
 14.2030 +SC_FUNC int matchtoken(int token)
 14.2031 +{
 14.2032 +  cell val;
 14.2033 +  char *str;
 14.2034 +  int tok;
 14.2035 +
 14.2036 +  tok=lex(&val,&str);
 14.2037 +  if (tok==token || token==tTERM && (tok==';' || tok==tENDEXPR)) {
 14.2038 +    return 1;
 14.2039 +  } else if (!sc_needsemicolon && token==tTERM && (_lexnewline || !freading)) {
 14.2040 +    /* Push "tok" back, because it is the token following the implicit statement
 14.2041 +     * termination (newline) token.
 14.2042 +     */
 14.2043 +    lexpush();
 14.2044 +    return 2;
 14.2045 +  } else {
 14.2046 +    lexpush();
 14.2047 +    return 0;
 14.2048 +  } /* if */
 14.2049 +}
 14.2050 +
 14.2051 +/*  tokeninfo
 14.2052 + *
 14.2053 + *  Returns additional information of a token after using "matchtoken()"
 14.2054 + *  or needtoken(). It does no harm using this routine after a call to
 14.2055 + *  "lex()", but lex() already returns the same information.
 14.2056 + *
 14.2057 + *  The token itself is the return value. Normally, this one is already known.
 14.2058 + */
 14.2059 +SC_FUNC int tokeninfo(cell *val,char **str)
 14.2060 +{
 14.2061 +  /* if the token was pushed back, tokeninfo() returns the token and
 14.2062 +   * parameters of the *next* token, not of the *current* token.
 14.2063 +   */
 14.2064 +  assert(!_pushed);
 14.2065 +  *val=_lexval;
 14.2066 +  *str=_lexstr;
 14.2067 +  return _lextok;
 14.2068 +}
 14.2069 +
 14.2070 +/*  needtoken
 14.2071 + *
 14.2072 + *  This routine checks for a required token and gives an error message if
 14.2073 + *  it isn't there (and returns 0/FALSE in that case). Like function matchtoken(),
 14.2074 + *  this function returns 1 for "token found" and 2 for "statement termination
 14.2075 + *  token" found; see function matchtoken() for details.
 14.2076 + *
 14.2077 + *  Global references: _lextok;
 14.2078 + */
 14.2079 +SC_FUNC int needtoken(int token)
 14.2080 +{
 14.2081 +  char s1[20],s2[20];
 14.2082 +  int t;
 14.2083 +
 14.2084 +  if ((t=matchtoken(token))!=0) {
 14.2085 +    return t;
 14.2086 +  } else {
 14.2087 +    /* token already pushed back */
 14.2088 +    assert(_pushed);
 14.2089 +    if (token<256)
 14.2090 +      sprintf(s1,"%c",(char)token);        /* single character token */
 14.2091 +    else
 14.2092 +      strcpy(s1,sc_tokens[token-tFIRST]);  /* multi-character symbol */
 14.2093 +    if (!freading)
 14.2094 +      strcpy(s2,"-end of file-");
 14.2095 +    else if (_lextok<256)
 14.2096 +      sprintf(s2,"%c",(char)_lextok);
 14.2097 +    else
 14.2098 +      strcpy(s2,sc_tokens[_lextok-tFIRST]);
 14.2099 +    error(1,s1,s2);     /* expected ..., but found ... */
 14.2100 +    return FALSE;
 14.2101 +  } /* if */
 14.2102 +}
 14.2103 +
 14.2104 +/*  match
 14.2105 + *
 14.2106 + *  Compares a series of characters from the input file with the characters
 14.2107 + *  in "st" (that contains a token). If the token on the input file matches
 14.2108 + *  "st", the input file pointer "lptr" is adjusted to point to the next
 14.2109 + *  token, otherwise "lptr" remains unaltered.
 14.2110 + *
 14.2111 + *  If the parameter "end: is true, match() requires that the first character
 14.2112 + *  behind the recognized token is non-alphanumeric.
 14.2113 + *
 14.2114 + *  Global references: lptr   (altered)
 14.2115 + */
 14.2116 +static int match(char *st,int end)
 14.2117 +{
 14.2118 +  int k;
 14.2119 +  const unsigned char *ptr;
 14.2120 +
 14.2121 +  k=0;
 14.2122 +  ptr=lptr;
 14.2123 +  while (st[k]) {
 14.2124 +    if ((unsigned char)st[k]!=*ptr)
 14.2125 +      return 0;
 14.2126 +    k+=1;
 14.2127 +    ptr+=1;
 14.2128 +  } /* while */
 14.2129 +  if (end) {            /* symbol must terminate with non-alphanumeric char */
 14.2130 +    if (alphanum(*ptr))
 14.2131 +      return 0;
 14.2132 +  } /* if */
 14.2133 +  lptr=ptr;     /* match found, skip symbol */
 14.2134 +  return 1;
 14.2135 +}
 14.2136 +
 14.2137 +static void chk_grow_litq(void)
 14.2138 +{
 14.2139 +  if (litidx>=litmax) {
 14.2140 +    cell *p;
 14.2141 +
 14.2142 +    litmax+=sDEF_LITMAX;
 14.2143 +    p=(cell *)realloc(litq,litmax*sizeof(cell));
 14.2144 +    if (p==NULL)
 14.2145 +      error(102,"literal table");   /* literal table overflow (fatal error) */
 14.2146 +    litq=p;
 14.2147 +  } /* if */
 14.2148 +}
 14.2149 +
 14.2150 +/*  litadd
 14.2151 + *
 14.2152 + *  Adds a value at the end of the literal queue. The literal queue is used
 14.2153 + *  for literal strings used in functions and for initializing array variables.
 14.2154 + *
 14.2155 + *  Global references: litidx  (altered)
 14.2156 + *                     litq    (altered)
 14.2157 + */
 14.2158 +SC_FUNC void litadd(cell value)
 14.2159 +{
 14.2160 +  chk_grow_litq();
 14.2161 +  assert(litidx<litmax);
 14.2162 +  litq[litidx++]=value;
 14.2163 +}
 14.2164 +
 14.2165 +/*  litinsert
 14.2166 + *
 14.2167 + *  Inserts a value into the literal queue. This is sometimes necessary for
 14.2168 + *  initializing multi-dimensional arrays.
 14.2169 + *
 14.2170 + *  Global references: litidx  (altered)
 14.2171 + *                     litq    (altered)
 14.2172 + */
 14.2173 +SC_FUNC void litinsert(cell value,int pos)
 14.2174 +{
 14.2175 +  chk_grow_litq();
 14.2176 +  assert(litidx<litmax);
 14.2177 +  assert(pos>=0 && pos<=litidx);
 14.2178 +  memmove(litq+(pos+1),litq+pos,(litidx-pos)*sizeof(cell));
 14.2179 +  litidx++;
 14.2180 +  litq[pos]=value;
 14.2181 +}
 14.2182 +
 14.2183 +/*  litchar
 14.2184 + *
 14.2185 + *  Return current literal character and increase the pointer to point
 14.2186 + *  just behind this literal character.
 14.2187 + *
 14.2188 + *  Note: standard "escape sequences" are suported, but the backslash may be
 14.2189 + *        replaced by another character; the syntax '\ddd' is supported,
 14.2190 + *        but ddd must be decimal!
 14.2191 + */
 14.2192 +static cell litchar(const unsigned char **lptr,int flags)
 14.2193 +{
 14.2194 +  cell c=0;
 14.2195 +  const unsigned char *cptr;
 14.2196 +
 14.2197 +  cptr=*lptr;
 14.2198 +  if ((flags & RAWMODE)!=0 || *cptr!=sc_ctrlchar) {  /* no escape character */
 14.2199 +    #if !defined NO_UTF8
 14.2200 +      if (sc_is_utf8 && (flags & UTF8MODE)!=0) {
 14.2201 +        c=get_utf8_char(cptr,&cptr);
 14.2202 +        assert(c>=0);   /* file was already scanned for conformance to UTF-8 */
 14.2203 +      } else {
 14.2204 +    #endif
 14.2205 +      #if !defined NO_CODEPAGE
 14.2206 +        c=cp_translate(cptr,&cptr);
 14.2207 +      #else
 14.2208 +        c=*cptr;
 14.2209 +        cptr+=1;
 14.2210 +      #endif
 14.2211 +    #if !defined NO_UTF8
 14.2212 +      } /* if */
 14.2213 +    #endif
 14.2214 +  } else {
 14.2215 +    cptr+=1;
 14.2216 +    if (*cptr==sc_ctrlchar) {
 14.2217 +      c=*cptr;          /* \\ == \ (the escape character itself) */
 14.2218 +      cptr+=1;
 14.2219 +    } else {
 14.2220 +      switch (*cptr) {
 14.2221 +      case 'a':         /* \a == audible alarm */
 14.2222 +        c=7;
 14.2223 +        cptr+=1;
 14.2224 +        break;
 14.2225 +      case 'b':         /* \b == backspace */
 14.2226 +        c=8;
 14.2227 +        cptr+=1;
 14.2228 +        break;
 14.2229 +      case 'e':         /* \e == escape */
 14.2230 +        c=27;
 14.2231 +        cptr+=1;
 14.2232 +        break;
 14.2233 +      case 'f':         /* \f == form feed */
 14.2234 +        c=12;
 14.2235 +        cptr+=1;
 14.2236 +        break;
 14.2237 +      case 'n':         /* \n == NewLine character */
 14.2238 +        c=10;
 14.2239 +        cptr+=1;
 14.2240 +        break;
 14.2241 +      case 'r':         /* \r == carriage return */
 14.2242 +        c=13;
 14.2243 +        cptr+=1;
 14.2244 +        break;
 14.2245 +      case 't':         /* \t == horizontal TAB */
 14.2246 +        c=9;
 14.2247 +        cptr+=1;
 14.2248 +        break;
 14.2249 +      case 'v':         /* \v == vertical TAB */
 14.2250 +        c=11;
 14.2251 +        cptr+=1;
 14.2252 +        break;
 14.2253 +      case 'x':
 14.2254 +        cptr+=1;
 14.2255 +        c=0;
 14.2256 +        while (ishex(*cptr)) {
 14.2257 +          if (isdigit(*cptr))
 14.2258 +            c=(c<<4)+(*cptr-'0');
 14.2259 +          else
 14.2260 +            c=(c<<4)+(tolower(*cptr)-'a'+10);
 14.2261 +          cptr++;
 14.2262 +        } /* while */
 14.2263 +        if (*cptr==';')
 14.2264 +          cptr++;       /* swallow a trailing ';' */
 14.2265 +        break;
 14.2266 +      case '\'':        /* \' == ' (single quote) */
 14.2267 +      case '"':         /* \" == " (single quote) */
 14.2268 +      case '%':         /* \% == % (percent) */
 14.2269 +        c=*cptr;
 14.2270 +        cptr+=1;
 14.2271 +        break;
 14.2272 +      default:
 14.2273 +        if (isdigit(*cptr)) {   /* \ddd */
 14.2274 +          c=0;
 14.2275 +          while (*cptr>='0' && *cptr<='9')  /* decimal! */
 14.2276 +            c=c*10 + *cptr++ - '0';
 14.2277 +          if (*cptr==';')
 14.2278 +            cptr++;     /* swallow a trailing ';' */
 14.2279 +        } else {
 14.2280 +          error(27);    /* invalid character constant */
 14.2281 +        } /* if */
 14.2282 +      } /* switch */
 14.2283 +    } /* if */
 14.2284 +  } /* if */
 14.2285 +  *lptr=cptr;
 14.2286 +  assert(c>=0);
 14.2287 +  return c;
 14.2288 +}
 14.2289 +
 14.2290 +/*  alpha
 14.2291 + *
 14.2292 + *  Test if character "c" is alphabetic ("a".."z"), an underscore ("_")
 14.2293 + *  or an "at" sign ("@"). The "@" is an extension to standard C.
 14.2294 + */
 14.2295 +static int alpha(char c)
 14.2296 +{
 14.2297 +  return (isalpha(c) || c=='_' || c==PUBLIC_CHAR);
 14.2298 +}
 14.2299 +
 14.2300 +/*  alphanum
 14.2301 + *
 14.2302 + *  Test if character "c" is alphanumeric ("a".."z", "0".."9", "_" or "@")
 14.2303 + */
 14.2304 +SC_FUNC int alphanum(char c)
 14.2305 +{
 14.2306 +  return (alpha(c) || isdigit(c));
 14.2307 +}
 14.2308 +
 14.2309 +/*  ishex
 14.2310 + *
 14.2311 + *  Test if character "c" is a hexadecimal digit ("0".."9" or "a".."f").
 14.2312 + */
 14.2313 +SC_FUNC int ishex(char c)
 14.2314 +{
 14.2315 +  return (c>='0' && c<='9') || (c>='a' && c<='f') || (c>='A' && c<='F');
 14.2316 +}
 14.2317 +
 14.2318 +/* The local variable table must be searched backwards, so that the deepest
 14.2319 + * nesting of local variables is searched first. The simplest way to do
 14.2320 + * this is to insert all new items at the head of the list.
 14.2321 + * In the global list, the symbols are kept in sorted order, so that the
 14.2322 + * public functions are written in sorted order.
 14.2323 + */
 14.2324 +static symbol *add_symbol(symbol *root,symbol *entry,int sort)
 14.2325 +{
 14.2326 +  symbol *newsym;
 14.2327 +
 14.2328 +  if (sort)
 14.2329 +    while (root->next!=NULL && strcmp(entry->name,root->next->name)>0)
 14.2330 +      root=root->next;
 14.2331 +
 14.2332 +  if ((newsym=(symbol *)malloc(sizeof(symbol)))==NULL) {
 14.2333 +    error(103);
 14.2334 +    return NULL;
 14.2335 +  } /* if */
 14.2336 +  memcpy(newsym,entry,sizeof(symbol));
 14.2337 +  newsym->next=root->next;
 14.2338 +  root->next=newsym;
 14.2339 +  return newsym;
 14.2340 +}
 14.2341 +
 14.2342 +static void free_symbol(symbol *sym)
 14.2343 +{
 14.2344 +  arginfo *arg;
 14.2345 +
 14.2346 +  /* free all sub-symbol allocated memory blocks, depending on the
 14.2347 +   * kind of the symbol
 14.2348 +   */
 14.2349 +  assert(sym!=NULL);
 14.2350 +  if (sym->ident==iFUNCTN) {
 14.2351 +    /* run through the argument list; "default array" arguments
 14.2352 +     * must be freed explicitly; the tag list must also be freed */
 14.2353 +    assert(sym->dim.arglist!=NULL);
 14.2354 +    for (arg=sym->dim.arglist; arg->ident!=0; arg++) {
 14.2355 +      if (arg->ident==iREFARRAY && arg->hasdefault)
 14.2356 +        free(arg->defvalue.array.data);
 14.2357 +      else if (arg->ident==iVARIABLE
 14.2358 +               && ((arg->hasdefault & uSIZEOF)!=0 || (arg->hasdefault & uTAGOF)!=0))
 14.2359 +        free(arg->defvalue.size.symname);
 14.2360 +      assert(arg->tags!=NULL);
 14.2361 +      free(arg->tags);
 14.2362 +    } /* for */
 14.2363 +    free(sym->dim.arglist);
 14.2364 +    if (sym->states!=NULL) {
 14.2365 +      delete_consttable(sym->states);
 14.2366 +      free(sym->states);
 14.2367 +    } /* if */
 14.2368 +  } else if (sym->ident==iVARIABLE || sym->ident==iARRAY) {
 14.2369 +    if (sym->states!=NULL) {
 14.2370 +      delete_consttable(sym->states);
 14.2371 +      free(sym->states);
 14.2372 +    } /* if */
 14.2373 +  } else if (sym->ident==iCONSTEXPR && (sym->usage & uENUMROOT)==uENUMROOT) {
 14.2374 +    /* free the constant list of an enum root */
 14.2375 +    assert(sym->dim.enumlist!=NULL);
 14.2376 +    delete_consttable(sym->dim.enumlist);
 14.2377 +    free(sym->dim.enumlist);
 14.2378 +  } /* if */
 14.2379 +  assert(sym->refer!=NULL);
 14.2380 +  free(sym->refer);
 14.2381 +  if (sym->documentation!=NULL)
 14.2382 +    free(sym->documentation);
 14.2383 +  free(sym);
 14.2384 +}
 14.2385 +
 14.2386 +SC_FUNC void delete_symbol(symbol *root,symbol *sym)
 14.2387 +{
 14.2388 +  /* find the symbol and its predecessor
 14.2389 +   * (this function assumes that you will never delete a symbol that is not
 14.2390 +   * in the table pointed at by "root")
 14.2391 +   */
 14.2392 +  assert(root!=sym);
 14.2393 +  while (root->next!=sym) {
 14.2394 +    root=root->next;
 14.2395 +    assert(root!=NULL);
 14.2396 +  } /* while */
 14.2397 +
 14.2398 +  /* unlink it, then free it */
 14.2399 +  root->next=sym->next;
 14.2400 +  free_symbol(sym);
 14.2401 +}
 14.2402 +
 14.2403 +SC_FUNC void delete_symbols(symbol *root,int level,int delete_labels,int delete_functions)
 14.2404 +{
 14.2405 +  symbol *sym,*parent_sym;
 14.2406 +  constvalue *stateptr;
 14.2407 +  int mustdelete;
 14.2408 +
 14.2409 +  /* erase only the symbols with a deeper nesting level than the
 14.2410 +   * specified nesting level */
 14.2411 +  while (root->next!=NULL) {
 14.2412 +    sym=root->next;
 14.2413 +    if (sym->compound<level)
 14.2414 +      break;
 14.2415 +    switch (sym->ident) {
 14.2416 +    case iLABEL:
 14.2417 +      mustdelete=delete_labels;
 14.2418 +      break;
 14.2419 +    case iVARIABLE:
 14.2420 +    case iARRAY:
 14.2421 +      /* do not delete global variables if functions are preserved */
 14.2422 +      mustdelete=delete_functions;
 14.2423 +      break;
 14.2424 +    case iREFERENCE:
 14.2425 +      /* always delete references (only exist as function parameters) */
 14.2426 +      mustdelete=TRUE;
 14.2427 +      break;
 14.2428 +    case iREFARRAY:
 14.2429 +      /* a global iREFARRAY symbol is the return value of a function: delete
 14.2430 +       * this only if "globals" must be deleted; other iREFARRAY instances
 14.2431 +       * (locals) are also deleted
 14.2432 +       */
 14.2433 +      mustdelete=delete_functions;
 14.2434 +      for (parent_sym=sym->parent; parent_sym!=NULL && parent_sym->ident!=iFUNCTN; parent_sym=parent_sym->parent)
 14.2435 +        assert(parent_sym->ident==iREFARRAY);
 14.2436 +      assert(parent_sym==NULL || (parent_sym->ident==iFUNCTN && parent_sym->parent==NULL));
 14.2437 +      if (parent_sym==NULL || parent_sym->ident!=iFUNCTN)
 14.2438 +        mustdelete=TRUE;
 14.2439 +      break;
 14.2440 +    case iCONSTEXPR:
 14.2441 +      /* delete constants, except predefined constants */
 14.2442 +      mustdelete=delete_functions || (sym->usage & uPREDEF)==0;
 14.2443 +      break;
 14.2444 +    case iFUNCTN:
 14.2445 +      /* optionally preserve globals (variables & functions), but
 14.2446 +       * NOT native functions
 14.2447 +       */
 14.2448 +      mustdelete=delete_functions || (sym->usage & uNATIVE)!=0;
 14.2449 +      assert(sym->parent==NULL);
 14.2450 +      break;
 14.2451 +    case iARRAYCELL:
 14.2452 +    case iARRAYCHAR:
 14.2453 +    case iEXPRESSION:
 14.2454 +    case iVARARGS:
 14.2455 +    default:
 14.2456 +      assert(0);
 14.2457 +      break;
 14.2458 +    } /* switch */
 14.2459 +    if (mustdelete) {
 14.2460 +      root->next=sym->next;
 14.2461 +      free_symbol(sym);
 14.2462 +    } else {
 14.2463 +      /* if the function was prototyped, but not implemented in this source,
 14.2464 +       * mark it as such, so that its use can be flagged
 14.2465 +       */
 14.2466 +      if (sym->ident==iFUNCTN && (sym->usage & uDEFINE)==0)
 14.2467 +        sym->usage |= uMISSING;
 14.2468 +      if (sym->ident==iFUNCTN || sym->ident==iVARIABLE || sym->ident==iARRAY)
 14.2469 +        sym->usage &= ~uDEFINE; /* clear "defined" flag */
 14.2470 +      /* set all states as "undefined" too */
 14.2471 +      if (sym->states!=NULL)
 14.2472 +        for (stateptr=sym->states->next; stateptr!=NULL; stateptr=stateptr->next)
 14.2473 +          stateptr->value=0;
 14.2474 +      /* for user defined operators, also remove the "prototyped" flag, as
 14.2475 +       * user-defined operators *must* be declared before use
 14.2476 +       */
 14.2477 +      if (sym->ident==iFUNCTN && !alpha(*sym->name))
 14.2478 +        sym->usage &= ~uPROTOTYPED;
 14.2479 +      root=sym;                 /* skip the symbol */
 14.2480 +    } /* if */
 14.2481 +  } /* if */
 14.2482 +}
 14.2483 +
 14.2484 +/* The purpose of the hash is to reduce the frequency of a "name"
 14.2485 + * comparison (which is costly). There is little interest in avoiding
 14.2486 + * clusters in similar names, which is why this function is plain simple.
 14.2487 + */
 14.2488 +SC_FUNC uint32_t namehash(const char *name)
 14.2489 +{
 14.2490 +  const unsigned char *ptr=(const unsigned char *)name;
 14.2491 +  int len=strlen(name);
 14.2492 +  if (len==0)
 14.2493 +    return 0L;
 14.2494 +  assert(len<256);
 14.2495 +  return (len<<24Lu) + (ptr[0]<<16Lu) + (ptr[len-1]<<8Lu) + (ptr[len>>1Lu]);
 14.2496 +}
 14.2497 +
 14.2498 +static symbol *find_symbol(const symbol *root,const char *name,int fnumber,int automaton,int *cmptag)
 14.2499 +{
 14.2500 +  symbol *firstmatch=NULL;
 14.2501 +  symbol *sym=root->next;
 14.2502 +  int count=0;
 14.2503 +  unsigned long hash=namehash(name);
 14.2504 +  while (sym!=NULL) {
 14.2505 +    if (hash==sym->hash && strcmp(name,sym->name)==0        /* check name */
 14.2506 +        && (sym->parent==NULL || sym->ident==iCONSTEXPR)    /* sub-types (hierarchical types) are skipped, except for enum fields */
 14.2507 +        && (sym->fnumber<0 || sym->fnumber==fnumber))       /* check file number for scope */
 14.2508 +    {
 14.2509 +      assert(sym->states==NULL || sym->states->next!=NULL); /* first element of the state list is the "root" */
 14.2510 +      if (sym->ident==iFUNCTN
 14.2511 +          || automaton<0 && sym->states==NULL
 14.2512 +          || automaton>=0 && sym->states!=NULL && state_getfsa(sym->states->next->index)==automaton)
 14.2513 +      {
 14.2514 +        if (cmptag==NULL)
 14.2515 +          return sym;   /* return first match */
 14.2516 +        /* return closest match or first match; count number of matches */
 14.2517 +        if (firstmatch==NULL)
 14.2518 +          firstmatch=sym;
 14.2519 +        assert(cmptag!=NULL);
 14.2520 +        if (*cmptag==0)
 14.2521 +          count++;
 14.2522 +        if (*cmptag==sym->tag) {
 14.2523 +          *cmptag=1;    /* good match found, set number of matches to 1 */
 14.2524 +          return sym;
 14.2525 +        } /* if */
 14.2526 +      } /* if */
 14.2527 +    } /*  */
 14.2528 +    sym=sym->next;
 14.2529 +  } /* while */
 14.2530 +  if (cmptag!=NULL && firstmatch!=NULL)
 14.2531 +    *cmptag=count;
 14.2532 +  return firstmatch;
 14.2533 +}
 14.2534 +
 14.2535 +static symbol *find_symbol_child(const symbol *root,const symbol *sym)
 14.2536 +{
 14.2537 +  symbol *ptr=root->next;
 14.2538 +  while (ptr!=NULL) {
 14.2539 +    if (ptr->parent==sym)
 14.2540 +      return ptr;
 14.2541 +    ptr=ptr->next;
 14.2542 +  } /* while */
 14.2543 +  return NULL;
 14.2544 +}
 14.2545 +
 14.2546 +/* Adds "bywhom" to the list of referrers of "entry". Typically,
 14.2547 + * bywhom will be the function that uses a variable or that calls
 14.2548 + * the function.
 14.2549 + */
 14.2550 +SC_FUNC int refer_symbol(symbol *entry,symbol *bywhom)
 14.2551 +{
 14.2552 +  int count;
 14.2553 +
 14.2554 +  assert(bywhom!=NULL);         /* it makes no sense to add a "void" referrer */
 14.2555 +  assert(entry!=NULL);
 14.2556 +  assert(entry->refer!=NULL);
 14.2557 +
 14.2558 +  /* see if it is already there */
 14.2559 +  for (count=0; count<entry->numrefers && entry->refer[count]!=bywhom; count++)
 14.2560 +    /* nothing */;
 14.2561 +  if (count<entry->numrefers) {
 14.2562 +    assert(entry->refer[count]==bywhom);
 14.2563 +    return TRUE;
 14.2564 +  } /* if */
 14.2565 +
 14.2566 +  /* see if there is an empty spot in the referrer list */
 14.2567 +  for (count=0; count<entry->numrefers && entry->refer[count]!=NULL; count++)
 14.2568 +    /* nothing */;
 14.2569 +  assert(count <= entry->numrefers);
 14.2570 +  if (count==entry->numrefers) {
 14.2571 +    symbol **refer;
 14.2572 +    int newsize=2*entry->numrefers;
 14.2573 +    assert(newsize>0);
 14.2574 +    /* grow the referrer list */
 14.2575 +    refer=(symbol**)realloc(entry->refer,newsize*sizeof(symbol*));
 14.2576 +    if (refer==NULL)
 14.2577 +      return FALSE;             /* insufficient memory */
 14.2578 +    /* initialize the new entries */
 14.2579 +    entry->refer=refer;
 14.2580 +    for (count=entry->numrefers; count<newsize; count++)
 14.2581 +      entry->refer[count]=NULL;
 14.2582 +    count=entry->numrefers;     /* first empty spot */
 14.2583 +    entry->numrefers=newsize;
 14.2584 +  } /* if */
 14.2585 +
 14.2586 +  /* add the referrer */
 14.2587 +  assert(entry->refer[count]==NULL);
 14.2588 +  entry->refer[count]=bywhom;
 14.2589 +  return TRUE;
 14.2590 +}
 14.2591 +
 14.2592 +SC_FUNC void markusage(symbol *sym,int usage)
 14.2593 +{
 14.2594 +  assert(sym!=NULL);
 14.2595 +  sym->usage |= (char)usage;
 14.2596 +  if ((usage & uWRITTEN)!=0)
 14.2597 +    sym->lnumber=fline;
 14.2598 +  /* check if (global) reference must be added to the symbol */
 14.2599 +  if ((usage & (uREAD | uWRITTEN))!=0) {
 14.2600 +    /* only do this for global symbols */
 14.2601 +    if (sym->vclass==sGLOBAL) {
 14.2602 +      /* "curfunc" should always be valid, since statements may not occurs
 14.2603 +       * outside functions; in the case of syntax errors, however, the
 14.2604 +       * compiler may arrive through this function
 14.2605 +       */
 14.2606 +      if (curfunc!=NULL)
 14.2607 +        refer_symbol(sym,curfunc);
 14.2608 +    } /* if */
 14.2609 +  } /* if */
 14.2610 +}
 14.2611 +
 14.2612 +
 14.2613 +/*  findglb
 14.2614 + *
 14.2615 + *  Returns a pointer to the global symbol (if found) or NULL (if not found)
 14.2616 + */
 14.2617 +SC_FUNC symbol *findglb(const char *name,int filter)
 14.2618 +{
 14.2619 +  /* find a symbol with a matching automaton first */
 14.2620 +  symbol *sym=NULL;
 14.2621 +
 14.2622 +  if (filter>sGLOBAL && sc_curstates>0) {
 14.2623 +    /* find a symbol whose state list matches the current fsa */
 14.2624 +    sym=find_symbol(&glbtab,name,fcurrent,state_getfsa(sc_curstates),NULL);
 14.2625 +    if (sym!=NULL && sym->ident!=iFUNCTN) {
 14.2626 +      /* if sym!=NULL, we found a variable in the automaton; now we should
 14.2627 +       * also verify whether there is an intersection between the symbol's
 14.2628 +       * state list and the current state list
 14.2629 +       */
 14.2630 +      assert(sym->states!=NULL && sym->states->next!=NULL);
 14.2631 +      if (!state_conflict_id(sc_curstates,sym->states->next->index))
 14.2632 +        sym=NULL;
 14.2633 +    } /* if */
 14.2634 +  } /* if */
 14.2635 +
 14.2636 +  /* if no symbol with a matching automaton exists, find a variable/function
 14.2637 +   * that has no state(s) attached to it
 14.2638 +   */
 14.2639 +  if (sym==NULL)
 14.2640 +    sym=find_symbol(&glbtab,name,fcurrent,-1,NULL);
 14.2641 +  return sym;
 14.2642 +}
 14.2643 +
 14.2644 +/*  findloc
 14.2645 + *
 14.2646 + *  Returns a pointer to the local symbol (if found) or NULL (if not found).
 14.2647 + *  See add_symbol() how the deepest nesting level is searched first.
 14.2648 + */
 14.2649 +SC_FUNC symbol *findloc(const char *name)
 14.2650 +{
 14.2651 +  return find_symbol(&loctab,name,-1,-1,NULL);
 14.2652 +}
 14.2653 +
 14.2654 +SC_FUNC symbol *findconst(const char *name,int *cmptag)
 14.2655 +{
 14.2656 +  symbol *sym;
 14.2657 +
 14.2658 +  sym=find_symbol(&loctab,name,-1,-1,cmptag);  /* try local symbols first */
 14.2659 +  if (sym==NULL || sym->ident!=iCONSTEXPR)     /* not found, or not a constant */
 14.2660 +    sym=find_symbol(&glbtab,name,fcurrent,-1,cmptag);
 14.2661 +  if (sym==NULL || sym->ident!=iCONSTEXPR)
 14.2662 +    return NULL;
 14.2663 +  assert(sym->parent==NULL || (sym->usage & uENUMFIELD)!=0);
 14.2664 +  /* ^^^ constants have no hierarchy, but enumeration fields may have a parent */
 14.2665 +  return sym;
 14.2666 +}
 14.2667 +
 14.2668 +SC_FUNC symbol *finddepend(const symbol *parent)
 14.2669 +{
 14.2670 +  symbol *sym;
 14.2671 +
 14.2672 +  sym=find_symbol_child(&loctab,parent);    /* try local symbols first */
 14.2673 +  if (sym==NULL)                            /* not found */
 14.2674 +    sym=find_symbol_child(&glbtab,parent);
 14.2675 +  return sym;
 14.2676 +}
 14.2677 +
 14.2678 +/*  addsym
 14.2679 + *
 14.2680 + *  Adds a symbol to the symbol table (either global or local variables,
 14.2681 + *  or global and local constants).
 14.2682 + */
 14.2683 +SC_FUNC symbol *addsym(const char *name,cell addr,int ident,int vclass,int tag,int usage)
 14.2684 +{
 14.2685 +  symbol entry, **refer;
 14.2686 +
 14.2687 +  /* labels may only be defined once */
 14.2688 +  assert(ident!=iLABEL || findloc(name)==NULL);
 14.2689 +
 14.2690 +  /* create an empty referrer list */
 14.2691 +  if ((refer=(symbol**)malloc(sizeof(symbol*)))==NULL) {
 14.2692 +    error(103);         /* insufficient memory */
 14.2693 +    return NULL;
 14.2694 +  } /* if */
 14.2695 +  *refer=NULL;
 14.2696 +
 14.2697 +  /* first fill in the entry */
 14.2698 +  memset(&entry,0,sizeof entry);
 14.2699 +  strcpy(entry.name,name);
 14.2700 +  entry.hash=namehash(name);
 14.2701 +  entry.addr=addr;
 14.2702 +  entry.codeaddr=code_idx;
 14.2703 +  entry.vclass=(char)vclass;
 14.2704 +  entry.ident=(char)ident;
 14.2705 +  entry.tag=tag;
 14.2706 +  entry.usage=(char)usage;
 14.2707 +  entry.fnumber=-1;     /* assume global visibility (ignored for local symbols) */
 14.2708 +  entry.lnumber=fline;
 14.2709 +  entry.numrefers=1;
 14.2710 +  entry.refer=refer;
 14.2711 +
 14.2712 +  /* then insert it in the list */
 14.2713 +  if (vclass==sGLOBAL)
 14.2714 +    return add_symbol(&glbtab,&entry,TRUE);
 14.2715 +  else
 14.2716 +    return add_symbol(&loctab,&entry,FALSE);
 14.2717 +}
 14.2718 +
 14.2719 +SC_FUNC symbol *addvariable(const char *name,cell addr,int ident,int vclass,int tag,
 14.2720 +                            int dim[],int numdim,int idxtag[])
 14.2721 +{
 14.2722 +  symbol *sym;
 14.2723 +
 14.2724 +  /* global variables may only be defined once
 14.2725 +   * One complication is that functions returning arrays declare an array
 14.2726 +   * with the same name as the function, so the assertion must allow for
 14.2727 +   * this special case. Another complication is that variables may be
 14.2728 +   * "redeclared" if they are local to an automaton (and findglb() will find
 14.2729 +   * the symbol without states if no symbol with states exists).
 14.2730 +   */
 14.2731 +  assert(vclass!=sGLOBAL || (sym=findglb(name,sGLOBAL))==NULL || (sym->usage & uDEFINE)==0
 14.2732 +         || sym->ident==iFUNCTN && sym==curfunc
 14.2733 +         || sym->states==NULL && sc_curstates>0);
 14.2734 +
 14.2735 +  if (ident==iARRAY || ident==iREFARRAY) {
 14.2736 +    symbol *parent=NULL,*top;
 14.2737 +    int level;
 14.2738 +    sym=NULL;                   /* to avoid a compiler warning */
 14.2739 +    for (level=0; level<numdim; level++) {
 14.2740 +      top=addsym(name,addr,ident,vclass,tag,uDEFINE);
 14.2741 +      top->dim.array.length=dim[level];
 14.2742 +      top->dim.array.level=(short)(numdim-level-1);
 14.2743 +      top->x.tags.index=idxtag[level];
 14.2744 +      top->parent=parent;
 14.2745 +      parent=top;
 14.2746 +      if (level==0)
 14.2747 +        sym=top;
 14.2748 +    } /* for */
 14.2749 +  } else {
 14.2750 +    sym=addsym(name,addr,ident,vclass,tag,uDEFINE);
 14.2751 +  } /* if */
 14.2752 +  return sym;
 14.2753 +}
 14.2754 +
 14.2755 +/*  getlabel
 14.2756 + *
 14.2757 + *  Returns te next internal label number. The global variable sc_labnum is
 14.2758 + *  initialized to zero.
 14.2759 + */
 14.2760 +SC_FUNC int getlabel(void)
 14.2761 +{
 14.2762 +  return sc_labnum++;
 14.2763 +}
 14.2764 +
 14.2765 +/*  itoh
 14.2766 + *
 14.2767 + *  Converts a number to a hexadecimal string and returns a pointer to that
 14.2768 + *  string. This function is NOT re-entrant.
 14.2769 + */
 14.2770 +SC_FUNC char *itoh(ucell val)
 14.2771 +{
 14.2772 +static char itohstr[30];
 14.2773 +  char *ptr;
 14.2774 +  int i,nibble[16];             /* a 64-bit hexadecimal cell has 16 nibbles */
 14.2775 +  int max;
 14.2776 +
 14.2777 +  #if PAWN_CELL_SIZE==16
 14.2778 +    max=4;
 14.2779 +  #elif PAWN_CELL_SIZE==32
 14.2780 +    max=8;
 14.2781 +  #elif PAWN_CELL_SIZE==64
 14.2782 +    max=16;
 14.2783 +  #else
 14.2784 +    #error Unsupported cell size
 14.2785 +  #endif
 14.2786 +  ptr=itohstr;
 14.2787 +  for (i=0; i<max; i+=1){
 14.2788 +    nibble[i]=(int)(val & 0x0f);        /* nibble 0 is lowest nibble */
 14.2789 +    val>>=4;
 14.2790 +  } /* endfor */
 14.2791 +  i=max-1;
 14.2792 +  while (nibble[i]==0 && i>0)   /* search for highest non-zero nibble */
 14.2793 +    i-=1;
 14.2794 +  while (i>=0){
 14.2795 +    if (nibble[i]>=10)
 14.2796 +      *ptr++=(char)('a'+(nibble[i]-10));
 14.2797 +    else
 14.2798 +      *ptr++=(char)('0'+nibble[i]);
 14.2799 +    i-=1;
 14.2800 +  } /* while */
 14.2801 +  *ptr='\0';            /* and a zero-terminator */
 14.2802 +  return itohstr;
 14.2803 +}
 14.2804 +
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/compiler-init/compiler-init/sc3.c	Fri Jul 14 02:02:18 2006 +0000
    15.3 @@ -0,0 +1,2453 @@
    15.4 +/*  Pawn compiler - Recursive descend expresion parser
    15.5 + *
    15.6 + *  Copyright (c) ITB CompuPhase, 1997-2005
    15.7 + *
    15.8 + *  This software is provided "as-is", without any express or implied warranty.
    15.9 + *  In no event will the authors be held liable for any damages arising from
   15.10 + *  the use of this software.
   15.11 + *
   15.12 + *  Permission is granted to anyone to use this software for any purpose,
   15.13 + *  including commercial applications, and to alter it and redistribute it
   15.14 + *  freely, subject to the following restrictions:
   15.15 + *
   15.16 + *  1.  The origin of this software must not be misrepresented; you must not
   15.17 + *      claim that you wrote the original software. If you use this software in
   15.18 + *      a product, an acknowledgment in the product documentation would be
   15.19 + *      appreciated but is not required.
   15.20 + *  2.  Altered source versions must be plainly marked as such, and must not be
   15.21 + *      misrepresented as being the original software.
   15.22 + *  3.  This notice may not be removed or altered from any source distribution.
   15.23 + *
   15.24 + *  Version: $Id: sc3.c 3598 2006-07-04 13:44:04Z thiadmer $
   15.25 + */
   15.26 +#include <assert.h>
   15.27 +#include <stdio.h>
   15.28 +#include <stdlib.h>     /* for _MAX_PATH */
   15.29 +#include <string.h>
   15.30 +#if defined FORTIFY
   15.31 +  #include <alloc/fortify.h>
   15.32 +#endif
   15.33 +#include "sc.h"
   15.34 +
   15.35 +static int skim(int *opstr,void (*testfunc)(int),int dropval,int endval,
   15.36 +                int (*hier)(value*),value *lval);
   15.37 +static void dropout(int lvalue,void (*testfunc)(int val),int exit1,value *lval);
   15.38 +static int plnge(int *opstr,int opoff,int (*hier)(value *lval),value *lval,
   15.39 +                 char *forcetag,int chkbitwise);
   15.40 +static int plnge1(int (*hier)(value *lval),value *lval);
   15.41 +static void plnge2(void (*oper)(void),
   15.42 +                   int (*hier)(value *lval),
   15.43 +                   value *lval1,value *lval2);
   15.44 +static cell calc(cell left,void (*oper)(),cell right,char *boolresult);
   15.45 +static int hier14(value *lval);
   15.46 +static int hier13(value *lval);
   15.47 +static int hier12(value *lval);
   15.48 +static int hier11(value *lval);
   15.49 +static int hier10(value *lval);
   15.50 +static int hier9(value *lval);
   15.51 +static int hier8(value *lval);
   15.52 +static int hier7(value *lval);
   15.53 +static int hier6(value *lval);
   15.54 +static int hier5(value *lval);
   15.55 +static int hier4(value *lval);
   15.56 +static int hier3(value *lval);
   15.57 +static int hier2(value *lval);
   15.58 +static int hier1(value *lval1);
   15.59 +static int primary(value *lval);
   15.60 +static void clear_value(value *lval);
   15.61 +static void callfunction(symbol *sym,value *lval_result,int matchparanthesis);
   15.62 +static int dbltest(void (*oper)(),value *lval1,value *lval2);
   15.63 +static int commutative(void (*oper)());
   15.64 +static int constant(value *lval);
   15.65 +
   15.66 +static char lastsymbol[sNAMEMAX+1]; /* name of last function/variable */
   15.67 +static int bitwise_opercount;   /* count of bitwise operators in an expression */
   15.68 +static int decl_heap=0;
   15.69 +
   15.70 +/* Function addresses of binary operators for signed operations */
   15.71 +static void (*op1[17])(void) = {
   15.72 +  os_mult,os_div,os_mod,        /* hier3, index 0 */
   15.73 +  ob_add,ob_sub,                /* hier4, index 3 */
   15.74 +  ob_sal,os_sar,ou_sar,         /* hier5, index 5 */
   15.75 +  ob_and,                       /* hier6, index 8 */
   15.76 +  ob_xor,                       /* hier7, index 9 */
   15.77 +  ob_or,                        /* hier8, index 10 */
   15.78 +  os_le,os_ge,os_lt,os_gt,      /* hier9, index 11 */
   15.79 +  ob_eq,ob_ne,                  /* hier10, index 15 */
   15.80 +};
   15.81 +/* These two functions are defined because the functions inc() and dec() in
   15.82 + * SC4.C have a different prototype than the other code generation functions.
   15.83 + * The arrays for user-defined functions use the function pointers for
   15.84 + * identifying what kind of operation is requested; these functions must all
   15.85 + * have the same prototype. As inc() and dec() are special cases already, it
   15.86 + * is simplest to add two "do-nothing" functions.
   15.87 + */
   15.88 +static void user_inc(void) {}
   15.89 +static void user_dec(void) {}
   15.90 +
   15.91 +/*
   15.92 + *  Searches for a binary operator a list of operators. The list is stored in
   15.93 + *  the array "list". The last entry in the list should be set to 0.
   15.94 + *
   15.95 + *  The index of an operator in "list" (if found) is returned in "opidx". If
   15.96 + *  no operator is found, nextop() returns 0.
   15.97 + *
   15.98 + *  If an operator is found in the expression, it cannot be used in a function
   15.99 + *  call with omitted parantheses. Mark this...
  15.100 + *
  15.101 + *  Global references: sc_allowproccall   (modified)
  15.102 + */
  15.103 +static int nextop(int *opidx,int *list)
  15.104 +{
  15.105 +  *opidx=0;
  15.106 +  while (*list){
  15.107 +    if (matchtoken(*list)){
  15.108 +      sc_allowproccall=FALSE;
  15.109 +      return TRUE;      /* found! */
  15.110 +    } else {
  15.111 +      list+=1;
  15.112 +      *opidx+=1;
  15.113 +    } /* if */
  15.114 +  } /* while */
  15.115 +  return FALSE;         /* entire list scanned, nothing found */
  15.116 +}
  15.117 +
  15.118 +SC_FUNC int check_userop(void (*oper)(void),int tag1,int tag2,int numparam,
  15.119 +                         value *lval,int *resulttag)
  15.120 +{
  15.121 +static char *binoperstr[] = { "*", "/", "%", "+", "-", "", "", "",
  15.122 +                              "", "", "", "<=", ">=", "<", ">", "==", "!=" };
  15.123 +static int binoper_savepri[] = { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  15.124 +                                 FALSE, FALSE, FALSE, FALSE, FALSE,
  15.125 +                                 TRUE, TRUE, TRUE, TRUE, FALSE, FALSE };
  15.126 +static char *unoperstr[] = { "!", "-", "++", "--" };
  15.127 +static void (*unopers[])(void) = { lneg, neg, user_inc, user_dec };
  15.128 +  char opername[4] = "", symbolname[sNAMEMAX+1];
  15.129 +  int i,swapparams,savepri,savealt;
  15.130 +  int paramspassed;
  15.131 +  symbol *sym;
  15.132 +
  15.133 +  /* since user-defined operators on untagged operands are forbidden, we have
  15.134 +   * a quick exit.
  15.135 +   */
  15.136 +  assert(numparam==1 || numparam==2);
  15.137 +  if (tag1==0 && (numparam==1 || tag2==0))
  15.138 +    return FALSE;
  15.139 +
  15.140 +  savepri=savealt=FALSE;
  15.141 +  /* find the name with the operator */
  15.142 +  if (numparam==2) {
  15.143 +    if (oper==NULL) {
  15.144 +      /* assignment operator: a special case */
  15.145 +      strcpy(opername,"=");
  15.146 +      if (lval!=NULL && (lval->ident==iARRAYCELL || lval->ident==iARRAYCHAR))
  15.147 +        savealt=TRUE;
  15.148 +    } else {
  15.149 +      assert( (sizeof binoperstr / sizeof binoperstr[0]) == (sizeof op1 / sizeof op1[0]) );
  15.150 +      for (i=0; i<sizeof op1 / sizeof op1[0]; i++) {
  15.151 +        if (oper==op1[i]) {
  15.152 +          strcpy(opername,binoperstr[i]);
  15.153 +          savepri=binoper_savepri[i];
  15.154 +          break;
  15.155 +        } /* if */
  15.156 +      } /* for */
  15.157 +    } /* if */
  15.158 +  } else {
  15.159 +    assert(oper!=NULL);
  15.160 +    assert(numparam==1);
  15.161 +    /* try a select group of unary operators */
  15.162 +    assert( (sizeof unoperstr / sizeof unoperstr[0]) == (sizeof unopers / sizeof unopers[0]) );
  15.163 +    if (opername[0]=='\0') {
  15.164 +      for (i=0; i<sizeof unopers / sizeof unopers[0]; i++) {
  15.165 +        if (oper==unopers[i]) {
  15.166 +          strcpy(opername,unoperstr[i]);
  15.167 +          break;
  15.168 +        } /* if */
  15.169 +      } /* for */
  15.170 +    } /* if */
  15.171 +  } /* if */
  15.172 +  /* if not found, quit */
  15.173 +  if (opername[0]=='\0')
  15.174 +    return FALSE;
  15.175 +
  15.176 +  /* create a symbol name from the tags and the operator name */
  15.177 +  assert(numparam==1 || numparam==2);
  15.178 +  operator_symname(symbolname,opername,tag1,tag2,numparam,tag2);
  15.179 +  swapparams=FALSE;
  15.180 +  sym=findglb(symbolname,sGLOBAL);
  15.181 +  if (sym==NULL /*|| (sym->usage & uDEFINE)==0*/) {  /* ??? should not check uDEFINE; first pass clears these bits */
  15.182 +    /* check for commutative operators */
  15.183 +    if (tag1==tag2 || oper==NULL || !commutative(oper))
  15.184 +      return FALSE;             /* not commutative, cannot swap operands */
  15.185 +    /* if arrived here, the operator is commutative and the tags are different,
  15.186 +     * swap tags and try again
  15.187 +     */
  15.188 +    assert(numparam==2);        /* commutative operator must be a binary operator */
  15.189 +    operator_symname(symbolname,opername,tag2,tag1,numparam,tag1);
  15.190 +    swapparams=TRUE;
  15.191 +    sym=findglb(symbolname,sGLOBAL);
  15.192 +    if (sym==NULL /*|| (sym->usage & uDEFINE)==0*/)
  15.193 +      return FALSE;
  15.194 +  } /* if */
  15.195 +
  15.196 +  /* check existance and the proper declaration of this function */
  15.197 +  if ((sym->usage & uMISSING)!=0 || (sym->usage & uPROTOTYPED)==0) {
  15.198 +    char symname[2*sNAMEMAX+16];  /* allow space for user defined operators */
  15.199 +    funcdisplayname(symname,sym->name);
  15.200 +    if ((sym->usage & uMISSING)!=0)
  15.201 +      error(4,symname);           /* function not defined */
  15.202 +    if ((sym->usage & uPROTOTYPED)==0)
  15.203 +      error(71,symname);          /* operator must be declared before use */
  15.204 +  } /* if */
  15.205 +
  15.206 +  /* we don't want to use the redefined operator in the function that
  15.207 +   * redefines the operator itself, otherwise the snippet below gives
  15.208 +   * an unexpected recursion:
  15.209 +   *    fixed:operator+(fixed:a, fixed:b)
  15.210 +   *        return a + b
  15.211 +   */
  15.212 +  if (sym==curfunc)
  15.213 +    return FALSE;
  15.214 +
  15.215 +  /* for increment and decrement operators, the symbol must first be loaded
  15.216 +   * (and stored back afterwards)
  15.217 +   */
  15.218 +  if (oper==user_inc || oper==user_dec) {
  15.219 +    assert(!savepri);
  15.220 +    assert(lval!=NULL);
  15.221 +    if (lval->ident==iARRAYCELL || lval->ident==iARRAYCHAR)
  15.222 +      pushreg(sPRI);            /* save current address in PRI */
  15.223 +    rvalue(lval);               /* get the symbol's value in PRI */
  15.224 +  } /* if */
  15.225 +
  15.226 +  assert(!savepri || !savealt); /* either one MAY be set, but not both */
  15.227 +  if (savepri) {
  15.228 +    /* the chained comparison operators require that the ALT register is
  15.229 +     * unmodified, so we save it here; actually, we save PRI because the normal
  15.230 +     * instruction sequence (without user operator) swaps PRI and ALT
  15.231 +     */
  15.232 +    pushreg(sPRI);              /* right-hand operand is in PRI */
  15.233 +  } else if (savealt) {
  15.234 +    /* for the assignment operator, ALT may contain an address at which the
  15.235 +     * result must be stored; this address must be preserved accross the
  15.236 +     * call
  15.237 +     */
  15.238 +    assert(lval!=NULL);         /* this was checked earlier */
  15.239 +    assert(lval->ident==iARRAYCELL || lval->ident==iARRAYCHAR); /* checked earlier */
  15.240 +    pushreg(sALT);
  15.241 +  } /* if */
  15.242 +
  15.243 +  /* push parameters, call the function */
  15.244 +  paramspassed= (oper==NULL) ? 1 : numparam;
  15.245 +  switch (paramspassed) {
  15.246 +  case 1:
  15.247 +    pushreg(sPRI);
  15.248 +    break;
  15.249 +  case 2:
  15.250 +    /* note that 1) a function expects that the parameters are pushed
  15.251 +     * in reversed order, and 2) the left operand is in the secondary register
  15.252 +     * and the right operand is in the primary register */
  15.253 +    if (swapparams) {
  15.254 +      pushreg(sALT);
  15.255 +      pushreg(sPRI);
  15.256 +    } else {
  15.257 +      pushreg(sPRI);
  15.258 +      pushreg(sALT);
  15.259 +    } /* if */
  15.260 +    break;
  15.261 +  default:
  15.262 +    assert(0);
  15.263 +  } /* switch */
  15.264 +  markexpr(sPARM,NULL,0);       /* mark the end of a sub-expression */
  15.265 +  pushval((cell)paramspassed*sizeof(cell));
  15.266 +  assert(sym->ident==iFUNCTN);
  15.267 +  ffcall(sym,NULL,paramspassed);
  15.268 +  if (sc_status!=statSKIP)
  15.269 +    markusage(sym,uREAD);       /* do not mark as "used" when this call itself is skipped */
  15.270 +  if ((sym->usage & uNATIVE)!=0 && sym->x.lib!=NULL)
  15.271 +    sym->x.lib->value += 1;     /* increment "usage count" of the library */
  15.272 +  sideeffect=TRUE;              /* assume functions carry out a side-effect */
  15.273 +  assert(resulttag!=NULL);
  15.274 +  *resulttag=sym->tag;          /* save tag of the called function */
  15.275 +
  15.276 +  if (savepri || savealt)
  15.277 +    popreg(sALT);               /* restore the saved PRI/ALT that into ALT */
  15.278 +  if (oper==user_inc || oper==user_dec) {
  15.279 +    assert(lval!=NULL);
  15.280 +    if (lval->ident==iARRAYCELL || lval->ident==iARRAYCHAR)
  15.281 +      popreg(sALT);             /* restore address (in ALT) */
  15.282 +    store(lval);                /* store PRI in the symbol */
  15.283 +    moveto1();                  /* make sure PRI is restored on exit */
  15.284 +  } /* if */
  15.285 +  return TRUE;
  15.286 +}
  15.287 +
  15.288 +SC_FUNC int matchtag(int formaltag,int actualtag,int allowcoerce)
  15.289 +{
  15.290 +  if (formaltag!=actualtag) {
  15.291 +    /* if the formal tag is zero and the actual tag is not "fixed", the actual
  15.292 +     * tag is "coerced" to zero
  15.293 +     */
  15.294 +    if (!allowcoerce || formaltag!=0 || (actualtag & FIXEDTAG)!=0)
  15.295 +      return FALSE;
  15.296 +  } /* if */
  15.297 +  return TRUE;
  15.298 +}
  15.299 +
  15.300 +/*
  15.301 + *  The AMX pseudo-processor has no direct support for logical (boolean)
  15.302 + *  operations. These have to be done via comparing and jumping. Since we are
  15.303 + *  already jumping through the code, we might as well implement an "early
  15.304 + *  drop-out" evaluation (also called "short-circuit"). This conforms to
  15.305 + *  standard C:
  15.306 + *
  15.307 + *  expr1 || expr2           expr2 will only be evaluated if expr1 is false.
  15.308 + *  expr1 && expr2           expr2 will only be evaluated if expr1 is true.
  15.309 + *
  15.310 + *  expr1 || expr2 && expr3  expr2 will only be evaluated if expr1 is false
  15.311 + *                           and expr3 will only be evaluated if expr1 is
  15.312 + *                           false and expr2 is true.
  15.313 + *
  15.314 + *  Code generation for the last example proceeds thus:
  15.315 + *
  15.316 + *      evaluate expr1
  15.317 + *      operator || found
  15.318 + *      jump to "l1" if result of expr1 not equal to 0
  15.319 + *      evaluate expr2
  15.320 + *      ->  operator && found; skip to higher level in hierarchy diagram
  15.321 + *          jump to "l2" if result of expr2 equal to 0
  15.322 + *          evaluate expr3
  15.323 + *          jump to "l2" if result of expr3 equal to 0
  15.324 + *          set expression result to 1 (true)
  15.325 + *          jump to "l3"
  15.326 + *      l2: set expression result to 0 (false)
  15.327 + *      l3:
  15.328 + *      <-  drop back to previous hierarchy level
  15.329 + *      jump to "l1" if result of expr2 && expr3 not equal to 0
  15.330 + *      set expression result to 0 (false)
  15.331 + *      jump to "l4"
  15.332 + *  l1: set expression result to 1 (true)
  15.333 + *  l4:
  15.334 + *
  15.335 + */
  15.336 +
  15.337 +/*  Skim over terms adjoining || and && operators
  15.338 + *  dropval   The value of the expression after "dropping out". An "or" drops
  15.339 + *            out when the left hand is TRUE, so dropval must be 1 on "or"
  15.340 + *            expressions.
  15.341 + *  endval    The value of the expression when no expression drops out. In an
  15.342 + *            "or" expression, this happens when both the left hand and the
  15.343 + *            right hand are FALSE, so endval must be 0 for "or" expressions.
  15.344 + */
  15.345 +static int skim(int *opstr,void (*testfunc)(int),int dropval,int endval,
  15.346 +                int (*hier)(value*),value *lval)
  15.347 +{
  15.348 +  int lvalue,hits,droplab,endlab,opidx;
  15.349 +  int allconst,foundop;
  15.350 +  cell constval;
  15.351 +  int index;
  15.352 +  cell cidx;
  15.353 +
  15.354 +  stgget(&index,&cidx);         /* mark position in code generator */
  15.355 +  hits=FALSE;                   /* no logical operators "hit" yet */
  15.356 +  allconst=TRUE;                /* assume all values "const" */
  15.357 +  constval=0;
  15.358 +  droplab=0;                    /* to avoid a compiler warning */
  15.359 +  for ( ;; ) {
  15.360 +    lvalue=plnge1(hier,lval);   /* evaluate left expression */
  15.361 +
  15.362 +    allconst= allconst && (lval->ident==iCONSTEXPR);
  15.363 +    if (allconst) {
  15.364 +      if (hits) {
  15.365 +        /* one operator was already found */
  15.366 +        if (testfunc==jmp_ne0)
  15.367 +          lval->constval= lval->constval || constval;
  15.368 +        else
  15.369 +          lval->constval= lval->constval && constval;
  15.370 +      } /* if */
  15.371 +      constval=lval->constval;  /* save result accumulated so far */
  15.372 +    } /* if */
  15.373 +
  15.374 +    foundop=nextop(&opidx,opstr);
  15.375 +    if ((foundop || hits) && (lval->ident==iARRAY || lval->ident==iREFARRAY))
  15.376 +      error(33, lval->sym ? (lval->sym->name ? lval->sym->name : "-unknown") : "-unknown-");  /* array was not indexed in an expression */
  15.377 +    if (foundop) {
  15.378 +      if (!hits) {
  15.379 +        /* this is the first operator in the list */
  15.380 +        hits=TRUE;
  15.381 +        droplab=getlabel();
  15.382 +      } /* if */
  15.383 +      dropout(lvalue,testfunc,droplab,lval);
  15.384 +    } else if (hits) {                       /* no (more) identical operators */
  15.385 +      dropout(lvalue,testfunc,droplab,lval); /* found at least one operator! */
  15.386 +      ldconst(endval,sPRI);
  15.387 +      jumplabel(endlab=getlabel());
  15.388 +      setlabel(droplab);
  15.389 +      ldconst(dropval,sPRI);
  15.390 +      setlabel(endlab);
  15.391 +      lval->sym=NULL;
  15.392 +      lval->tag=pc_addtag("bool");  /* force tag to be "bool" */
  15.393 +      if (allconst) {
  15.394 +        lval->ident=iCONSTEXPR;
  15.395 +        lval->constval=constval;
  15.396 +        stgdel(index,cidx);         /* scratch generated code and calculate */
  15.397 +      } else {
  15.398 +        lval->ident=iEXPRESSION;
  15.399 +        lval->constval=0;
  15.400 +      } /* if */
  15.401 +      return FALSE;
  15.402 +    } else {
  15.403 +      return lvalue;            /* none of the operators in "opstr" were found */
  15.404 +    } /* if */
  15.405 +
  15.406 +  } /* while */
  15.407 +}
  15.408 +
  15.409 +/*
  15.410 + *  Reads into the primary register the variable pointed to by lval if
  15.411 + *  plunging through the hierarchy levels detected an lvalue. Otherwise
  15.412 + *  if a constant was detected, it is loaded. If there is no constant and
  15.413 + *  no lvalue, the primary register must already contain the expression
  15.414 + *  result.
  15.415 + *
  15.416 + *  After that, the compare routines "jmp_ne0" or "jmp_eq0" are called, which
  15.417 + *  compare the primary register against 0, and jump to the "early drop-out"
  15.418 + *  label "exit1" if the condition is true.
  15.419 + */
  15.420 +static void dropout(int lvalue,void (*testfunc)(int val),int exit1,value *lval)
  15.421 +{
  15.422 +  if (lvalue)
  15.423 +    rvalue(lval);
  15.424 +  else if (lval->ident==iCONSTEXPR)
  15.425 +    ldconst(lval->constval,sPRI);
  15.426 +  (*testfunc)(exit1);
  15.427 +}
  15.428 +
  15.429 +static void checkfunction(value *lval)
  15.430 +{
  15.431 +  symbol *sym=lval->sym;
  15.432 +
  15.433 +  if (sym==NULL || (sym->ident!=iFUNCTN && sym->ident!=iREFFUNC))
  15.434 +    return;             /* no known symbol, or not a function result */
  15.435 +
  15.436 +  if ((sym->usage & uDEFINE)!=0) {
  15.437 +    /* function is defined, can now check the return value (but make an
  15.438 +     * exception for directly recursive functions)
  15.439 +     */
  15.440 +    if (sym!=curfunc && (sym->usage & uRETVALUE)==0) {
  15.441 +      char symname[2*sNAMEMAX+16];  /* allow space for user defined operators */
  15.442 +      funcdisplayname(symname,sym->name);
  15.443 +      error(209,symname);       /* function should return a value */
  15.444 +    } /* if */
  15.445 +  } else {
  15.446 +    /* function not yet defined, set */
  15.447 +    sym->usage|=uRETVALUE;      /* make sure that a future implementation of
  15.448 +                                 * the function uses "return <value>" */
  15.449 +  } /* if */
  15.450 +}
  15.451 +
  15.452 +/*
  15.453 + *  Plunge to a lower level
  15.454 + */
  15.455 +static int plnge(int *opstr,int opoff,int (*hier)(value *lval),value *lval,
  15.456 +                 char *forcetag,int chkbitwise)
  15.457 +{
  15.458 +  int lvalue,opidx;
  15.459 +  int count;
  15.460 +  value lval2 = {0};
  15.461 +
  15.462 +  lvalue=plnge1(hier,lval);
  15.463 +  if (nextop(&opidx,opstr)==0)
  15.464 +    return lvalue;              /* no operator in "opstr" found */
  15.465 +  if (lvalue)
  15.466 +    rvalue(lval);
  15.467 +  count=0;
  15.468 +  do {
  15.469 +    if (chkbitwise && count++>0 && bitwise_opercount!=0)
  15.470 +      error(212);
  15.471 +    opidx+=opoff;               /* add offset to index returned by nextop() */
  15.472 +    plnge2(op1[opidx],hier,lval,&lval2);
  15.473 +    if (op1[opidx]==ob_and || op1[opidx]==ob_or)
  15.474 +      bitwise_opercount++;
  15.475 +    if (forcetag!=NULL)
  15.476 +      lval->tag=pc_addtag(forcetag);
  15.477 +  } while (nextop(&opidx,opstr)); /* do */
  15.478 +  return FALSE;         /* result of expression is not an lvalue */
  15.479 +}
  15.480 +
  15.481 +/*  plnge_rel
  15.482 + *
  15.483 + *  Binary plunge to lower level; this is very simular to plnge, but
  15.484 + *  it has special code generation sequences for chained operations.
  15.485 + */
  15.486 +static int plnge_rel(int *opstr,int opoff,int (*hier)(value *lval),value *lval)
  15.487 +{
  15.488 +  int lvalue,opidx;
  15.489 +  value lval2={0};
  15.490 +  int count;
  15.491 +
  15.492 +  /* this function should only be called for relational operators */
  15.493 +  assert(op1[opoff]==os_le);
  15.494 +  lvalue=plnge1(hier,lval);
  15.495 +  if (nextop(&opidx,opstr)==0)
  15.496 +    return lvalue;              /* no operator in "opstr" found */
  15.497 +  if (lvalue)
  15.498 +    rvalue(lval);
  15.499 +  count=0;
  15.500 +  lval->boolresult=TRUE;
  15.501 +  do {
  15.502 +    /* same check as in plnge(), but "chkbitwise" is always TRUE */
  15.503 +    if (count>0 && bitwise_opercount!=0)
  15.504 +      error(212);
  15.505 +    if (count>0) {
  15.506 +      relop_prefix();
  15.507 +      *lval=lval2;      /* copy right hand expression of the previous iteration */
  15.508 +    } /* if */
  15.509 +    opidx+=opoff;
  15.510 +    plnge2(op1[opidx],hier,lval,&lval2);
  15.511 +    if (count++>0)
  15.512 +      relop_suffix();
  15.513 +  } while (nextop(&opidx,opstr)); /* enddo */
  15.514 +  lval->constval=lval->boolresult;
  15.515 +  lval->tag=pc_addtag("bool");    /* force tag to be "bool" */
  15.516 +  return FALSE;         /* result of expression is not an lvalue */
  15.517 +}
  15.518 +
  15.519 +/*  plnge1
  15.520 + *
  15.521 + *  Unary plunge to lower level
  15.522 + *  Called by: skim(), plnge(), plnge2(), plnge_rel(), hier14() and hier13()
  15.523 + */
  15.524 +static int plnge1(int (*hier)(value *lval),value *lval)
  15.525 +{
  15.526 +  int lvalue,index;
  15.527 +  cell cidx;
  15.528 +
  15.529 +  stgget(&index,&cidx); /* mark position in code generator */
  15.530 +  lvalue=(*hier)(lval);
  15.531 +  if (lval->ident==iCONSTEXPR)
  15.532 +    stgdel(index,cidx); /* load constant later */
  15.533 +  return lvalue;
  15.534 +}
  15.535 +
  15.536 +/*  plnge2
  15.537 + *
  15.538 + *  Binary plunge to lower level
  15.539 + *  Called by: plnge(), plnge_rel(), hier14() and hier1()
  15.540 + */
  15.541 +static void plnge2(void (*oper)(void),
  15.542 +                   int (*hier)(value *lval),
  15.543 +                   value *lval1,value *lval2)
  15.544 +{
  15.545 +  int index;
  15.546 +  cell cidx;
  15.547 +
  15.548 +  stgget(&index,&cidx);             /* mark position in code generator */
  15.549 +  if (lval1->ident==iCONSTEXPR) {   /* constant on left side; it is not yet loaded */
  15.550 +    if (plnge1(hier,lval2))
  15.551 +      rvalue(lval2);                /* load lvalue now */
  15.552 +    else if (lval2->ident==iCONSTEXPR)
  15.553 +      ldconst(lval2->constval<<dbltest(oper,lval2,lval1),sPRI);
  15.554 +    ldconst(lval1->constval<<dbltest(oper,lval2,lval1),sALT);
  15.555 +                   /* ^ doubling of constants operating on integer addresses */
  15.556 +                   /*   is restricted to "add" and "subtract" operators */
  15.557 +  } else {                          /* non-constant on left side */
  15.558 +    pushreg(sPRI);
  15.559 +    if (plnge1(hier,lval2))
  15.560 +      rvalue(lval2);
  15.561 +    if (lval2->ident==iCONSTEXPR) { /* constant on right side */
  15.562 +      if (commutative(oper)) {      /* test for commutative operators */
  15.563 +        value lvaltmp = {0};
  15.564 +        stgdel(index,cidx);         /* scratch pushreg() and constant fetch (then
  15.565 +                                     * fetch the constant again */
  15.566 +        ldconst(lval2->constval<<dbltest(oper,lval1,lval2),sALT);
  15.567 +        /* now, the primary register has the left operand and the secondary
  15.568 +         * register the right operand; swap the "lval" variables so that lval1
  15.569 +         * is associated with the secondary register and lval2 with the
  15.570 +         * primary register, as is the "normal" case.
  15.571 +         */
  15.572 +        lvaltmp=*lval1;
  15.573 +        *lval1=*lval2;
  15.574 +        *lval2=lvaltmp;
  15.575 +      } else {
  15.576 +        ldconst(lval2->constval<<dbltest(oper,lval1,lval2),sPRI);
  15.577 +        popreg(sALT);   /* pop result of left operand into secondary register */
  15.578 +      } /* if */
  15.579 +    } else {            /* non-constants on both sides */
  15.580 +      popreg(sALT);
  15.581 +      if (dbltest(oper,lval1,lval2))
  15.582 +        cell2addr();                    /* double primary register */
  15.583 +      if (dbltest(oper,lval2,lval1))
  15.584 +        cell2addr_alt();                /* double secondary register */
  15.585 +    } /* if */
  15.586 +  } /* if */
  15.587 +  if (oper) {
  15.588 +    /* If used in an expression, a function should return a value.
  15.589 +     * If the function has been defined, we can check this. If the
  15.590 +     * function was not defined, we can set this requirement (so that
  15.591 +     * a future function definition can check this bit.
  15.592 +     */
  15.593 +    checkfunction(lval1);
  15.594 +    checkfunction(lval2);
  15.595 +    if (lval1->ident==iARRAY || lval1->ident==iREFARRAY) {
  15.596 +      char *ptr=(lval1->sym!=NULL) ? lval1->sym->name : "-unknown-";
  15.597 +      error(33,ptr);                    /* array must be indexed */
  15.598 +    } else if (lval2->ident==iARRAY || lval2->ident==iREFARRAY) {
  15.599 +      char *ptr=(lval2->sym!=NULL) ? lval2->sym->name : "-unknown-";
  15.600 +      error(33,ptr);                    /* array must be indexed */
  15.601 +    } /* if */
  15.602 +    /* ??? ^^^ should do same kind of error checking with functions */
  15.603 +
  15.604 +    /* check whether an "operator" function is defined for the tag names
  15.605 +     * (a constant expression cannot be optimized in that case)
  15.606 +     */
  15.607 +    if (check_userop(oper,lval1->tag,lval2->tag,2,NULL,&lval1->tag)) {
  15.608 +      lval1->ident=iEXPRESSION;
  15.609 +      lval1->constval=0;
  15.610 +    } else if (lval1->ident==iCONSTEXPR && lval2->ident==iCONSTEXPR) {
  15.611 +      /* only constant expression if both constant */
  15.612 +      stgdel(index,cidx);       /* scratch generated code and calculate */
  15.613 +      if (!matchtag(lval1->tag,lval2->tag,FALSE))
  15.614 +        error(213);             /* tagname mismatch */
  15.615 +      lval1->constval=calc(lval1->constval,oper,lval2->constval,&lval1->boolresult);
  15.616 +    } else {
  15.617 +      if (!matchtag(lval1->tag,lval2->tag,FALSE))
  15.618 +        error(213);             /* tagname mismatch */
  15.619 +      (*oper)();                /* do the (signed) operation */
  15.620 +      lval1->ident=iEXPRESSION;
  15.621 +    } /* if */
  15.622 +  } /* if */
  15.623 +}
  15.624 +
  15.625 +static cell truemodulus(cell a,cell b)
  15.626 +{
  15.627 +  return (a % b + b) % b;
  15.628 +}
  15.629 +
  15.630 +static cell calc(cell left,void (*oper)(),cell right,char *boolresult)
  15.631 +{
  15.632 +  if (oper==ob_or)
  15.633 +    return (left | right);
  15.634 +  else if (oper==ob_xor)
  15.635 +    return (left ^ right);
  15.636 +  else if (oper==ob_and)
  15.637 +    return (left & right);
  15.638 +  else if (oper==ob_eq)
  15.639 +    return (left == right);
  15.640 +  else if (oper==ob_ne)
  15.641 +    return (left != right);
  15.642 +  else if (oper==os_le)
  15.643 +    return *boolresult &= (char)(left <= right), right;
  15.644 +  else if (oper==os_ge)
  15.645 +    return *boolresult &= (char)(left >= right), right;
  15.646 +  else if (oper==os_lt)
  15.647 +    return *boolresult &= (char)(left < right), right;
  15.648 +  else if (oper==os_gt)
  15.649 +    return *boolresult &= (char)(left > right), right;
  15.650 +  else if (oper==os_sar)
  15.651 +    return (left >> (int)right);
  15.652 +  else if (oper==ou_sar)
  15.653 +    return ((ucell)left >> (ucell)right);
  15.654 +  else if (oper==ob_sal)
  15.655 +    return ((ucell)left << (int)right);
  15.656 +  else if (oper==ob_add)
  15.657 +    return (left + right);
  15.658 +  else if (oper==ob_sub)
  15.659 +    return (left - right);
  15.660 +  else if (oper==os_mult)
  15.661 +    return (left * right);
  15.662 +  else if (oper==os_div)
  15.663 +    return (left - truemodulus(left,right)) / right;
  15.664 +  else if (oper==os_mod)
  15.665 +    return truemodulus(left,right);
  15.666 +  else
  15.667 +    error(29);  /* invalid expression, assumed 0 (this should never occur) */
  15.668 +  return 0;
  15.669 +}
  15.670 +
  15.671 +SC_FUNC int expression(cell *val,int *tag,symbol **symptr,int chkfuncresult)
  15.672 +{
  15.673 +  int locheap=decl_heap;
  15.674 +  value lval={0};
  15.675 +
  15.676 +  if (hier14(&lval))
  15.677 +    rvalue(&lval);
  15.678 +  /* scrap any arrays left on the heap */
  15.679 +  assert(decl_heap>=locheap);
  15.680 +  modheap((locheap-decl_heap)*sizeof(cell));  /* remove heap space, so negative delta */
  15.681 +  decl_heap=locheap;
  15.682 +
  15.683 +  if (lval.ident==iCONSTEXPR && val!=NULL)    /* constant expression */
  15.684 +    *val=lval.constval;
  15.685 +  if (tag!=NULL)
  15.686 +    *tag=lval.tag;
  15.687 +  if (symptr!=NULL)
  15.688 +    *symptr=lval.sym;
  15.689 +  if (chkfuncresult)
  15.690 +    checkfunction(&lval);
  15.691 +  return lval.ident;
  15.692 +}
  15.693 +
  15.694 +SC_FUNC int sc_getstateid(constvalue **automaton,constvalue **state)
  15.695 +{
  15.696 +  char name[sNAMEMAX+1];
  15.697 +  cell val;
  15.698 +  char *str;
  15.699 +  int fsa,islabel;
  15.700 +
  15.701 +  assert(automaton!=NULL);
  15.702 +  assert(state!=NULL);
  15.703 +  if (!(islabel=matchtoken(tLABEL)) && !needtoken(tSYMBOL))
  15.704 +    return 0;
  15.705 +
  15.706 +  tokeninfo(&val,&str);
  15.707 +  assert(strlen(str)<sizeof name);
  15.708 +  strcpy(name,str);
  15.709 +  if (islabel || matchtoken(':')) {
  15.710 +    /* token is an automaton name, add the name and get a new token */
  15.711 +    *automaton=automaton_find(name);
  15.712 +    /* read in the state name before checking the automaton, to keep the parser
  15.713 +     * going (an "unknown automaton" error may occur when the "state" instruction
  15.714 +     * precedes any state definition)
  15.715 +     */
  15.716 +    if (!needtoken(tSYMBOL))
  15.717 +      return 0;
  15.718 +    tokeninfo(&val,&str);        /* do not copy the name yet, must check automaton first */
  15.719 +    if (*automaton==NULL) {
  15.720 +      error(86,name);            /* unknown automaton */
  15.721 +      return 0;
  15.722 +    } /* if */
  15.723 +    assert((*automaton)->index>0);
  15.724 +    assert(strlen(str)<sizeof name);
  15.725 +    strcpy(name,str);
  15.726 +  } else {
  15.727 +    *automaton=automaton_find("");
  15.728 +    assert(*automaton!=NULL);
  15.729 +    assert((*automaton)->index==0);
  15.730 +  } /* if */
  15.731 +  assert(*automaton!=NULL);
  15.732 +  fsa=(*automaton)->index;
  15.733 +
  15.734 +  assert(*automaton!=NULL);
  15.735 +  *state=state_find(name,fsa);
  15.736 +  if (*state==NULL) {
  15.737 +    char *fsaname=(*automaton)->name;
  15.738 +    if (*fsaname=='\0')
  15.739 +      fsaname="<main>";
  15.740 +    error(87,name,fsaname);   /* unknown state for automaton */
  15.741 +    return 0;
  15.742 +  } /* if */
  15.743 +
  15.744 +  return 1;
  15.745 +}
  15.746 +
  15.747 +SC_FUNC cell array_totalsize(symbol *sym)
  15.748 +{
  15.749 +  cell length;
  15.750 +
  15.751 +  assert(sym!=NULL);
  15.752 +  assert(sym->ident==iARRAY || sym->ident==iREFARRAY);
  15.753 +  length=sym->dim.array.length;
  15.754 +  if (sym->dim.array.level > 0) {
  15.755 +    cell sublength=array_totalsize(finddepend(sym));
  15.756 +    if (sublength>0)
  15.757 +      length=length+length*sublength;
  15.758 +    else
  15.759 +      length=0;
  15.760 +  } /* if */
  15.761 +  return length;
  15.762 +}
  15.763 +
  15.764 +static cell array_levelsize(symbol *sym,int level)
  15.765 +{
  15.766 +  assert(sym!=NULL);
  15.767 +  assert(sym->ident==iARRAY || sym->ident==iREFARRAY);
  15.768 +  assert(level <= sym->dim.array.level);
  15.769 +  while (level-- > 0) {
  15.770 +    sym=finddepend(sym);
  15.771 +    assert(sym!=NULL);
  15.772 +  } /* if */
  15.773 +  return sym->dim.array.length;
  15.774 +}
  15.775 +
  15.776 +/*  hier14
  15.777 + *
  15.778 + *  Lowest hierarchy level (except for the , operator).
  15.779 + *
  15.780 + *  Global references: sc_intest        (reffered to only)
  15.781 + *                     sc_allowproccall (modified)
  15.782 + */
  15.783 +static int hier14(value *lval1)
  15.784 +{
  15.785 +  int lvalue;
  15.786 +  value lval2={0},lval3={0};
  15.787 +  void (*oper)(void);
  15.788 +  int tok,level,i;
  15.789 +  cell val;
  15.790 +  char *st;
  15.791 +  int bwcount,leftarray;
  15.792 +  cell arrayidx1[sDIMEN_MAX],arrayidx2[sDIMEN_MAX];  /* last used array indices */
  15.793 +  cell *org_arrayidx;
  15.794 +
  15.795 +  bwcount=bitwise_opercount;
  15.796 +  bitwise_opercount=0;
  15.797 +  /* initialize the index arrays with unlikely constant indices; note that
  15.798 +   * these indices will only be changed when the array is indexed with a
  15.799 +   * constant, and that negative array indices are invalid (so actually, any
  15.800 +   * negative value would do).
  15.801 +   */
  15.802 +  for (i=0; i<sDIMEN_MAX; i++)
  15.803 +    arrayidx1[i]=arrayidx2[i]=(cell)(-1L << (sizeof(cell)*8-1));
  15.804 +  org_arrayidx=lval1->arrayidx; /* save current pointer, to reset later */
  15.805 +  if (lval1->arrayidx==NULL)
  15.806 +    lval1->arrayidx=arrayidx1;
  15.807 +  lvalue=plnge1(hier13,lval1);
  15.808 +  if (lval1->ident!=iARRAYCELL && lval1->ident!=iARRAYCHAR)
  15.809 +    lval1->arrayidx=NULL;
  15.810 +  if (lval1->ident==iCONSTEXPR) /* load constant here */
  15.811 +    ldconst(lval1->constval,sPRI);
  15.812 +  tok=lex(&val,&st);
  15.813 +  switch (tok) {
  15.814 +    case taOR:
  15.815 +      oper=ob_or;
  15.816 +      break;
  15.817 +    case taXOR:
  15.818 +      oper=ob_xor;
  15.819 +      break;
  15.820 +    case taAND:
  15.821 +      oper=ob_and;
  15.822 +      break;
  15.823 +    case taADD:
  15.824 +      oper=ob_add;
  15.825 +      break;
  15.826 +    case taSUB:
  15.827 +      oper=ob_sub;
  15.828 +      break;
  15.829 +    case taMULT:
  15.830 +      oper=os_mult;
  15.831 +      break;
  15.832 +    case taDIV:
  15.833 +      oper=os_div;
  15.834 +      break;
  15.835 +    case taMOD:
  15.836 +      oper=os_mod;
  15.837 +      break;
  15.838 +    case taSHRU:
  15.839 +      oper=ou_sar;
  15.840 +      break;
  15.841 +    case taSHR:
  15.842 +      oper=os_sar;
  15.843 +      break;
  15.844 +    case taSHL:
  15.845 +      oper=ob_sal;
  15.846 +      break;
  15.847 +    case '=':           /* simple assignment */
  15.848 +      oper=NULL;
  15.849 +      if (sc_intest)
  15.850 +        error(211);     /* possibly unintended assignment */
  15.851 +      break;
  15.852 +    default:
  15.853 +      lexpush();
  15.854 +      bitwise_opercount=bwcount;
  15.855 +      lval1->arrayidx=org_arrayidx; /* restore array index pointer */
  15.856 +      return lvalue;
  15.857 +  } /* switch */
  15.858 +
  15.859 +  /* if we get here, it was an assignment; first check a few special cases
  15.860 +   * and then the general */
  15.861 +  if (lval1->ident==iARRAYCHAR) {
  15.862 +    /* special case, assignment to packed character in a cell is permitted */
  15.863 +    lvalue=TRUE;
  15.864 +  } else if (lval1->ident==iARRAY || lval1->ident==iREFARRAY) {
  15.865 +    /* array assignment is permitted too (with restrictions) */
  15.866 +    if (oper)
  15.867 +      return error(23); /* array assignment must be simple assigment */
  15.868 +    assert(lval1->sym!=NULL);
  15.869 +    if (array_totalsize(lval1->sym)==0)
  15.870 +      return error(46,lval1->sym->name);        /* unknown array size */
  15.871 +    lvalue=TRUE;
  15.872 +  } /* if */
  15.873 +
  15.874 +  /* operand on left side of assignment must be lvalue */
  15.875 +  if (!lvalue)
  15.876 +    return error(22);                   /* must be lvalue */
  15.877 +  /* may not change "constant" parameters */
  15.878 +  assert(lval1->sym!=NULL);
  15.879 +  if ((lval1->sym->usage & uCONST)!=0)
  15.880 +    return error(22);           /* assignment to const argument */
  15.881 +  sc_allowproccall=FALSE;       /* may no longer use "procedure call" syntax */
  15.882 +
  15.883 +  lval3=*lval1;         /* save symbol to enable storage of expresion result */
  15.884 +  lval1->arrayidx=org_arrayidx; /* restore array index pointer */
  15.885 +  if (lval1->ident==iARRAYCELL || lval1->ident==iARRAYCHAR
  15.886 +      || lval1->ident==iARRAY || lval1->ident==iREFARRAY)
  15.887 +  {
  15.888 +    /* if indirect fetch: save PRI (cell address) */
  15.889 +    if (oper) {
  15.890 +      pushreg(sPRI);
  15.891 +      rvalue(lval1);
  15.892 +    } /* if */
  15.893 +    lval2.arrayidx=arrayidx2;
  15.894 +    plnge2(oper,hier14,lval1,&lval2);
  15.895 +    if (lval2.ident!=iARRAYCELL && lval2.ident!=iARRAYCHAR)
  15.896 +      lval2.arrayidx=NULL;
  15.897 +    if (oper)
  15.898 +      popreg(sALT);
  15.899 +    if (!oper && lval3.arrayidx!=NULL && lval2.arrayidx!=NULL
  15.900 +        && lval3.ident==lval2.ident && lval3.sym==lval2.sym)
  15.901 +    {
  15.902 +      int same=TRUE;
  15.903 +      assert(lval2.arrayidx==arrayidx2);
  15.904 +      for (i=0; i<sDIMEN_MAX; i++)
  15.905 +        same=same && (lval3.arrayidx[i]==lval2.arrayidx[i]);
  15.906 +        if (same)
  15.907 +          error(226,lval3.sym->name);   /* self-assignment */
  15.908 +    } /* if */
  15.909 +  } else {
  15.910 +    if (oper){
  15.911 +      rvalue(lval1);
  15.912 +      plnge2(oper,hier14,lval1,&lval2);
  15.913 +    } else {
  15.914 +      /* if direct fetch and simple assignment: no "push"
  15.915 +       * and "pop" needed -> call hier14() directly, */
  15.916 +      if (hier14(&lval2))
  15.917 +        rvalue(&lval2);         /* instead of plnge2(). */
  15.918 +      else if (lval2.ident==iVARIABLE)
  15.919 +        lval2.ident=iEXPRESSION;/* mark as "rvalue" if it is not an "lvalue" */
  15.920 +      checkfunction(&lval2);
  15.921 +      /* check whether lval2 and lval3 (old lval1) refer to the same variable */
  15.922 +      if (lval2.ident==iVARIABLE && lval3.ident==lval2.ident && lval3.sym==lval2.sym) {
  15.923 +        assert(lval3.sym!=NULL);
  15.924 +        error(226,lval3.sym->name);     /* self-assignment */
  15.925 +      } /* if */
  15.926 +    } /* if */
  15.927 +  } /* if */
  15.928 +  /* Array elements are sometimes considered as sub-arrays --when the
  15.929 +   * array index is an enumeration field and the enumeration size is greater
  15.930 +   * than 1. If the expression on the right side of the assignment is a cell,
  15.931 +   * or if an operation is in effect, this does not apply.
  15.932 +   */
  15.933 +  leftarray= lval3.ident==iARRAY || lval3.ident==iREFARRAY
  15.934 +             || ((lval3.ident==iARRAYCELL || lval3.ident==iARRAYCHAR)
  15.935 +                 && lval3.constval>1 && lval3.sym->dim.array.level==0
  15.936 +                 && !oper && (lval2.ident==iARRAY || lval2.ident==iREFARRAY));
  15.937 +  if (leftarray) {
  15.938 +    /* Left operand is an array, right operand should be an array variable
  15.939 +     * of the same size and the same dimension, an array literal (of the
  15.940 +     * same size) or a literal string. For single-dimensional arrays without
  15.941 +     * tag for the index, it is permitted to assign a smaller array into a
  15.942 +     * larger one (without warning). This is to make it easier to work with
  15.943 +     * strings.
  15.944 +     */
  15.945 +    int exactmatch=TRUE;
  15.946 +    int idxtag=0;
  15.947 +    int ltlength=(int)lval3.sym->dim.array.length;
  15.948 +    if ((lval3.ident==iARRAYCELL || lval3.ident==iARRAYCHAR)
  15.949 +        && lval3.constval>0 && lval3.sym->dim.array.level==0)
  15.950 +    {
  15.951 +      ltlength=(int)lval3.constval;
  15.952 +    } /* if */
  15.953 +    if (lval2.ident!=iARRAY && lval2.ident!=iREFARRAY
  15.954 +        && (lval2.sym==NULL || lval2.constval<=0))
  15.955 +      error(33,lval3.sym->name);        /* array must be indexed */
  15.956 +    if (lval2.sym!=NULL) {
  15.957 +      if (lval2.constval==0) {
  15.958 +        val=lval2.sym->dim.array.length;/* array variable */
  15.959 +      } else {
  15.960 +        val=lval2.constval;
  15.961 +        if (lval2.sym->dim.array.level!=0)
  15.962 +          error(28,lval2.sym->name);
  15.963 +      } /* if */
  15.964 +      level=lval2.sym->dim.array.level;
  15.965 +      idxtag=lval2.sym->x.tags.index;
  15.966 +      if (level==0 && idxtag==0 && lval3.sym->x.tags.index==0)
  15.967 +        exactmatch=FALSE;
  15.968 +    } else {
  15.969 +      val=lval2.constval;               /* literal array */
  15.970 +      level=0;
  15.971 +      /* If val is negative, it means that lval2 is a literal string.
  15.972 +       * The string array size may be smaller than the destination
  15.973 +       * array, provided that the destination array does not have an
  15.974 +       * index tag.
  15.975 +       */
  15.976 +      if (val<0) {
  15.977 +        val=-val;
  15.978 +        if (lval3.sym->x.tags.index==0)
  15.979 +          exactmatch=FALSE;
  15.980 +      } /* if */
  15.981 +    } /* if */
  15.982 +    if (lval3.sym->dim.array.level!=level)
  15.983 +      return error(48); /* array dimensions must match */
  15.984 +    else if (ltlength<val || exactmatch && ltlength>val || val==0)
  15.985 +      return error(47); /* array sizes must match */
  15.986 +    else if (lval3.ident!=iARRAYCELL && !matchtag(lval3.sym->x.tags.index,idxtag,TRUE))
  15.987 +      error(229,(lval2.sym!=NULL) ? lval2.sym->name : lval3.sym->name); /* index tag mismatch */
  15.988 +    if (level>0) {
  15.989 +      /* check the sizes of all sublevels too */
  15.990 +      symbol *sym1 = lval3.sym;
  15.991 +      symbol *sym2 = lval2.sym;
  15.992 +      int i;
  15.993 +      assert(sym1!=NULL && sym2!=NULL);
  15.994 +      /* ^^^ sym2 must be valid, because only variables can be
  15.995 +       *     multi-dimensional (there are no multi-dimensional literals),
  15.996 +       *     sym1 must be valid because it must be an lvalue
  15.997 +       */
  15.998 +      assert(exactmatch);
  15.999 +      for (i=0; i<level; i++) {
 15.1000 +        sym1=finddepend(sym1);
 15.1001 +        sym2=finddepend(sym2);
 15.1002 +        assert(sym1!=NULL && sym2!=NULL);
 15.1003 +        /* ^^^ both arrays have the same dimensions (this was checked
 15.1004 +         *     earlier) so the dependend should always be found
 15.1005 +         */
 15.1006 +        if (sym1->dim.array.length!=sym2->dim.array.length)
 15.1007 +          error(47);    /* array sizes must match */
 15.1008 +        else if (!matchtag(sym1->x.tags.index,sym2->x.tags.index,TRUE))
 15.1009 +          error(229,sym2->name);  /* index tag mismatch */
 15.1010 +      } /* for */
 15.1011 +      /* get the total size in cells of the multi-dimensional array */
 15.1012 +      val=array_totalsize(lval3.sym);
 15.1013 +      assert(val>0);    /* already checked */
 15.1014 +    } /* if */
 15.1015 +  } else {
 15.1016 +    /* left operand is not an array, right operand should then not be either */
 15.1017 +    if (lval2.ident==iARRAY || lval2.ident==iREFARRAY)
 15.1018 +      error(6);         /* must be assigned to an array */
 15.1019 +  } /* if */
 15.1020 +  if (leftarray) {
 15.1021 +    memcopy(val*sizeof(cell));
 15.1022 +  } else {
 15.1023 +    check_userop(NULL,lval2.tag,lval3.tag,2,&lval3,&lval2.tag);
 15.1024 +    store(&lval3);      /* now, store the expression result */
 15.1025 +  } /* if */
 15.1026 +  if (!oper && !matchtag(lval3.tag,lval2.tag,TRUE))
 15.1027 +    error(213);         /* tagname mismatch (if "oper", warning already given in plunge2()) */
 15.1028 +  if (lval3.sym)
 15.1029 +    markusage(lval3.sym,uWRITTEN);
 15.1030 +  sideeffect=TRUE;
 15.1031 +  bitwise_opercount=bwcount;
 15.1032 +  lval1->ident=iEXPRESSION;
 15.1033 +  return FALSE;         /* expression result is never an lvalue */
 15.1034 +}
 15.1035 +
 15.1036 +static int hier13(value *lval)
 15.1037 +{
 15.1038 +  int lvalue=plnge1(hier12,lval);
 15.1039 +  if (matchtoken('?')) {
 15.1040 +    int flab1=getlabel();
 15.1041 +    int flab2=getlabel();
 15.1042 +    value lval2={0};
 15.1043 +    int array1,array2;
 15.1044 +
 15.1045 +    if (lvalue) {
 15.1046 +      rvalue(lval);
 15.1047 +    } else if (lval->ident==iCONSTEXPR) {
 15.1048 +      ldconst(lval->constval,sPRI);
 15.1049 +      error(lval->constval ? 206 : 205);        /* redundant test */
 15.1050 +    } /* if */
 15.1051 +    jmp_eq0(flab1);             /* go to second expression if primary register==0 */
 15.1052 +    PUSHSTK_I(sc_allowtags);
 15.1053 +    sc_allowtags=FALSE;         /* do not allow tagnames here (colon is a special token) */
 15.1054 +    if (hier13(lval))
 15.1055 +      rvalue(lval);
 15.1056 +    if (lval->ident==iCONSTEXPR)        /* load constant here */
 15.1057 +      ldconst(lval->constval,sPRI);
 15.1058 +    sc_allowtags=(short)POPSTK_I();     /* restore */
 15.1059 +    jumplabel(flab2);
 15.1060 +    setlabel(flab1);
 15.1061 +    needtoken(':');
 15.1062 +    if (hier13(&lval2))
 15.1063 +      rvalue(&lval2);
 15.1064 +    if (lval2.ident==iCONSTEXPR)        /* load constant here */
 15.1065 +      ldconst(lval2.constval,sPRI);
 15.1066 +    array1= (lval->ident==iARRAY || lval->ident==iREFARRAY);
 15.1067 +    array2= (lval2.ident==iARRAY || lval2.ident==iREFARRAY);
 15.1068 +    if (array1 && !array2) {
 15.1069 +      char *ptr=(lval->sym->name!=NULL) ? lval->sym->name : "-unknown-";
 15.1070 +      error(33,ptr);            /* array must be indexed */
 15.1071 +    } else if (!array1 && array2) {
 15.1072 +      char *ptr=(lval2.sym->name!=NULL) ? lval2.sym->name : "-unknown-";
 15.1073 +      error(33,ptr);            /* array must be indexed */
 15.1074 +    } /* if */
 15.1075 +    /* ??? if both are arrays, should check dimensions */
 15.1076 +    if (!matchtag(lval->tag,lval2.tag,FALSE))
 15.1077 +      error(213);               /* tagname mismatch ('true' and 'false' expressions) */
 15.1078 +    setlabel(flab2);
 15.1079 +    if (lval->ident==iARRAY)
 15.1080 +      lval->ident=iREFARRAY;    /* iARRAY becomes iREFARRAY */
 15.1081 +    else if (lval->ident!=iREFARRAY)
 15.1082 +      lval->ident=iEXPRESSION;  /* iREFARRAY stays iREFARRAY, rest becomes iEXPRESSION */
 15.1083 +    return FALSE;               /* conditional expression is no lvalue */
 15.1084 +  } else {
 15.1085 +    return lvalue;
 15.1086 +  } /* if */
 15.1087 +}
 15.1088 +
 15.1089 +/* the order of the operators in these lists is important and must be
 15.1090 + * the same as the order of the operators in the array "op1"
 15.1091 + */
 15.1092 +static int list3[]  = {'*','/','%',0};
 15.1093 +static int list4[]  = {'+','-',0};
 15.1094 +static int list5[]  = {tSHL,tSHR,tSHRU,0};
 15.1095 +static int list6[]  = {'&',0};
 15.1096 +static int list7[]  = {'^',0};
 15.1097 +static int list8[]  = {'|',0};
 15.1098 +static int list9[]  = {tlLE,tlGE,'<','>',0};
 15.1099 +static int list10[] = {tlEQ,tlNE,0};
 15.1100 +static int list11[] = {tlAND,0};
 15.1101 +static int list12[] = {tlOR,0};
 15.1102 +
 15.1103 +static int hier12(value *lval)
 15.1104 +{
 15.1105 +  return skim(list12,jmp_ne0,1,0,hier11,lval);
 15.1106 +}
 15.1107 +
 15.1108 +static int hier11(value *lval)
 15.1109 +{
 15.1110 +  return skim(list11,jmp_eq0,0,1,hier10,lval);
 15.1111 +}
 15.1112 +
 15.1113 +static int hier10(value *lval)
 15.1114 +{ /* ==, != */
 15.1115 +  return plnge(list10,15,hier9,lval,"bool",TRUE);
 15.1116 +}                  /* ^ this variable is the starting index in the op1[]
 15.1117 +                    *   array of the operators of this hierarchy level */
 15.1118 +
 15.1119 +static int hier9(value *lval)
 15.1120 +{ /* <=, >=, <, > */
 15.1121 +  return plnge_rel(list9,11,hier8,lval);
 15.1122 +}
 15.1123 +
 15.1124 +static int hier8(value *lval)
 15.1125 +{ /* | */
 15.1126 +  return plnge(list8,10,hier7,lval,NULL,FALSE);
 15.1127 +}
 15.1128 +
 15.1129 +static int hier7(value *lval)
 15.1130 +{ /* ^ */
 15.1131 +  return plnge(list7,9,hier6,lval,NULL,FALSE);
 15.1132 +}
 15.1133 +
 15.1134 +static int hier6(value *lval)
 15.1135 +{ /* & */
 15.1136 +  return plnge(list6,8,hier5,lval,NULL,FALSE);
 15.1137 +}
 15.1138 +
 15.1139 +static int hier5(value *lval)
 15.1140 +{ /* <<, >>, >>> */
 15.1141 +  return plnge(list5,5,hier4,lval,NULL,FALSE);
 15.1142 +}
 15.1143 +
 15.1144 +static int hier4(value *lval)
 15.1145 +{ /* +, - */
 15.1146 +  return plnge(list4,3,hier3,lval,NULL,FALSE);
 15.1147 +}
 15.1148 +
 15.1149 +static int hier3(value *lval)
 15.1150 +{ /* *, /, % */
 15.1151 +  return plnge(list3,0,hier2,lval,NULL,FALSE);
 15.1152 +}
 15.1153 +
 15.1154 +static int hier2(value *lval)
 15.1155 +{
 15.1156 +  int lvalue,tok;
 15.1157 +  int tag,paranthese;
 15.1158 +  cell val;
 15.1159 +  char *st;
 15.1160 +  symbol *sym;
 15.1161 +  int saveresult;
 15.1162 +
 15.1163 +  tok=lex(&val,&st);
 15.1164 +  switch (tok) {
 15.1165 +  case tINC:                    /* ++lval */
 15.1166 +    if (!hier2(lval))
 15.1167 +      return error(22);         /* must be lvalue */
 15.1168 +    assert(lval->sym!=NULL);
 15.1169 +    if ((lval->sym->usage & uCONST)!=0)
 15.1170 +      return error(22);         /* assignment to const argument */
 15.1171 +    if (!check_userop(user_inc,lval->tag,0,1,lval,&lval->tag))
 15.1172 +      inc(lval);                /* increase variable first */
 15.1173 +    rvalue(lval);               /* and read the result into PRI */
 15.1174 +    sideeffect=TRUE;
 15.1175 +    return FALSE;               /* result is no longer lvalue */
 15.1176 +  case tDEC:                    /* --lval */
 15.1177 +    if (!hier2(lval))
 15.1178 +      return error(22);         /* must be lvalue */
 15.1179 +    assert(lval->sym!=NULL);
 15.1180 +    if ((lval->sym->usage & uCONST)!=0)
 15.1181 +      return error(22);         /* assignment to const argument */
 15.1182 +    if (!check_userop(user_dec,lval->tag,0,1,lval,&lval->tag))
 15.1183 +      dec(lval);                /* decrease variable first */
 15.1184 +    rvalue(lval);               /* and read the result into PRI */
 15.1185 +    sideeffect=TRUE;
 15.1186 +    return FALSE;               /* result is no longer lvalue */
 15.1187 +  case '~':                     /* ~ (one's complement) */
 15.1188 +    if (hier2(lval))
 15.1189 +      rvalue(lval);
 15.1190 +    invert();                   /* bitwise NOT */
 15.1191 +    lval->constval=~lval->constval;
 15.1192 +    return FALSE;
 15.1193 +  case '!':                     /* ! (logical negate) */
 15.1194 +    if (hier2(lval))
 15.1195 +      rvalue(lval);
 15.1196 +    if (check_userop(lneg,lval->tag,0,1,NULL,&lval->tag)) {
 15.1197 +      lval->ident=iEXPRESSION;
 15.1198 +      lval->constval=0;
 15.1199 +    } else {
 15.1200 +      lneg();                   /* 0 -> 1,  !0 -> 0 */
 15.1201 +      lval->constval=!lval->constval;
 15.1202 +      lval->tag=pc_addtag("bool");
 15.1203 +    } /* if */
 15.1204 +    return FALSE;
 15.1205 +  case '-':                     /* unary - (two's complement) */
 15.1206 +    if (hier2(lval))
 15.1207 +      rvalue(lval);
 15.1208 +    /* make a special check for a constant expression with the tag of a
 15.1209 +     * rational number, so that we can simple swap the sign of that constant.
 15.1210 +     */
 15.1211 +    if (lval->ident==iCONSTEXPR && lval->tag==sc_rationaltag && sc_rationaltag!=0) {
 15.1212 +      if (rational_digits==0) {
 15.1213 +        #if PAWN_CELL_SIZE==32
 15.1214 +          float *f = (float *)&lval->constval;
 15.1215 +        #elif PAWN_CELL_SIZE==64
 15.1216 +          double *f = (double *)&lval->constval;
 15.1217 +        #else
 15.1218 +          #error Unsupported cell size
 15.1219 +        #endif
 15.1220 +        *f= - *f; /* this modifies lval->constval */
 15.1221 +      } else {
 15.1222 +        /* the negation of a fixed point number is just an integer negation */
 15.1223 +        lval->constval=-lval->constval;
 15.1224 +      } /* if */
 15.1225 +    } else if (check_userop(neg,lval->tag,0,1,NULL,&lval->tag)) {
 15.1226 +      lval->ident=iEXPRESSION;
 15.1227 +      lval->constval=0;
 15.1228 +    } else {
 15.1229 +      neg();                    /* arithmic negation */
 15.1230 +      lval->constval=-lval->constval;
 15.1231 +    } /* if */
 15.1232 +    return FALSE;
 15.1233 +  case tLABEL:                  /* tagname override */
 15.1234 +    tag=pc_addtag(st);
 15.1235 +    lval->cmptag=tag;
 15.1236 +    lvalue=hier2(lval);
 15.1237 +    lval->tag=tag;
 15.1238 +    return lvalue;
 15.1239 +  case tDEFINED:
 15.1240 +    paranthese=0;
 15.1241 +    while (matchtoken('('))
 15.1242 +      paranthese++;
 15.1243 +    tok=lex(&val,&st);
 15.1244 +    if (tok!=tSYMBOL)
 15.1245 +      return error(20,st);      /* illegal symbol name */
 15.1246 +    sym=findloc(st);
 15.1247 +    if (sym==NULL)
 15.1248 +      sym=findglb(st,sSTATEVAR);
 15.1249 +    if (sym!=NULL && sym->ident!=iFUNCTN && sym->ident!=iREFFUNC && (sym->usage & uDEFINE)==0)
 15.1250 +      sym=NULL;                 /* symbol is not a function, it is in the table, but not "defined" */
 15.1251 +    val= (sym!=NULL);
 15.1252 +    if (!val && find_subst(st,strlen(st))!=NULL)
 15.1253 +      val=1;
 15.1254 +    clear_value(lval);
 15.1255 +    lval->ident=iCONSTEXPR;
 15.1256 +    lval->constval= val;
 15.1257 +    lval->tag=pc_addtag("bool");
 15.1258 +    ldconst(lval->constval,sPRI);
 15.1259 +    while (paranthese--)
 15.1260 +      needtoken(')');
 15.1261 +    return FALSE;
 15.1262 +  case tSIZEOF:
 15.1263 +    paranthese=0;
 15.1264 +    while (matchtoken('('))
 15.1265 +      paranthese++;
 15.1266 +    tok=lex(&val,&st);
 15.1267 +    if (tok!=tSYMBOL)
 15.1268 +      return error(20,st);      /* illegal symbol name */
 15.1269 +    sym=findloc(st);
 15.1270 +    if (sym==NULL)
 15.1271 +      sym=findglb(st,sSTATEVAR);
 15.1272 +    if (sym==NULL)
 15.1273 +      return error(17,st);      /* undefined symbol */
 15.1274 +    if (sym->ident==iCONSTEXPR)
 15.1275 +      error(39);                /* constant symbol has no size */
 15.1276 +    else if (sym->ident==iFUNCTN || sym->ident==iREFFUNC)
 15.1277 +      error(72);                /* "function" symbol has no size */
 15.1278 +    else if ((sym->usage & uDEFINE)==0)
 15.1279 +      return error(17,st);      /* undefined symbol (symbol is in the table, but it is "used" only) */
 15.1280 +    clear_value(lval);
 15.1281 +    lval->ident=iCONSTEXPR;
 15.1282 +    lval->constval=1;           /* preset */
 15.1283 +    if (sym->ident==iARRAY || sym->ident==iREFARRAY) {
 15.1284 +      int level;
 15.1285 +      symbol *idxsym=NULL;
 15.1286 +      symbol *subsym=sym;
 15.1287 +      for (level=0; matchtoken('['); level++) {
 15.1288 +        idxsym=NULL;
 15.1289 +        if (subsym!=NULL && level==subsym->dim.array.level && matchtoken(tSYMBOL)) {
 15.1290 +          char *idxname;
 15.1291 +          int cmptag=subsym->x.tags.index;
 15.1292 +          tokeninfo(&val,&idxname);
 15.1293 +          if ((idxsym=findconst(idxname,&cmptag))==NULL)
 15.1294 +            error(80,idxname);  /* unknown symbol, or non-constant */
 15.1295 +          else if (cmptag>1)
 15.1296 +            error(91,idxname);  /* ambiguous constant */
 15.1297 +        } /* if */
 15.1298 +        needtoken(']');
 15.1299 +        if (subsym!=NULL)
 15.1300 +          subsym=finddepend(subsym);
 15.1301 +      } /* for */
 15.1302 +      if (level>sym->dim.array.level+1)
 15.1303 +        error(28,sym->name);  /* invalid subscript */
 15.1304 +      else if (level==sym->dim.array.level+1)
 15.1305 +        lval->constval= (idxsym!=NULL && idxsym->dim.array.length>0) ? idxsym->dim.array.length : 1;
 15.1306 +      else
 15.1307 +        lval->constval=array_levelsize(sym,level);
 15.1308 +      if (lval->constval==0 && strchr((char *)lptr,PREPROC_TERM)==NULL)
 15.1309 +        error(224,st);          /* indeterminate array size in "sizeof" expression */
 15.1310 +    } /* if */
 15.1311 +    ldconst(lval->constval,sPRI);
 15.1312 +    while (paranthese--)
 15.1313 +      needtoken(')');
 15.1314 +    return FALSE;
 15.1315 +  case tTAGOF:
 15.1316 +    paranthese=0;
 15.1317 +    while (matchtoken('('))
 15.1318 +      paranthese++;
 15.1319 +    tok=lex(&val,&st);
 15.1320 +    if (tok!=tSYMBOL && tok!=tLABEL)
 15.1321 +      return error(20,st);      /* illegal symbol name */
 15.1322 +    if (tok==tLABEL) {
 15.1323 +      constvalue *tagsym=find_constval(&tagname_tab,st,0);
 15.1324 +      tag=(int)((tagsym!=NULL) ? tagsym->value : 0);
 15.1325 +    } else {
 15.1326 +      sym=findloc(st);
 15.1327 +      if (sym==NULL)
 15.1328 +        sym=findglb(st,sSTATEVAR);
 15.1329 +      if (sym==NULL)
 15.1330 +        return error(17,st);      /* undefined symbol */
 15.1331 +      if ((sym->usage & uDEFINE)==0)
 15.1332 +        return error(17,st);      /* undefined symbol (symbol is in the table, but it is "used" only) */
 15.1333 +      tag=sym->tag;
 15.1334 +    } /* if */
 15.1335 +    if (sym->ident==iARRAY || sym->ident==iREFARRAY) {
 15.1336 +      int level;
 15.1337 +      symbol *idxsym=NULL;
 15.1338 +      symbol *subsym=sym;
 15.1339 +      for (level=0; matchtoken('['); level++) {
 15.1340 +        idxsym=NULL;
 15.1341 +        if (subsym!=NULL && level==subsym->dim.array.level && matchtoken(tSYMBOL)) {
 15.1342 +          char *idxname;
 15.1343 +          int cmptag=subsym->x.tags.index;
 15.1344 +          tokeninfo(&val,&idxname);
 15.1345 +          if ((idxsym=findconst(idxname,&cmptag))==NULL)
 15.1346 +            error(80,idxname);  /* unknown symbol, or non-constant */
 15.1347 +          else if (cmptag>1)
 15.1348 +            error(91,idxname);  /* ambiguous constant */
 15.1349 +        } /* if */
 15.1350 +        needtoken(']');
 15.1351 +        if (subsym!=NULL)
 15.1352 +          subsym=finddepend(subsym);
 15.1353 +      } /* for */
 15.1354 +      if (level>sym->dim.array.level+1)
 15.1355 +        error(28,sym->name);  /* invalid subscript */
 15.1356 +      else if (level==sym->dim.array.level+1 && idxsym!=NULL)
 15.1357 +        tag= idxsym->x.tags.index;
 15.1358 +    } /* if */
 15.1359 +    exporttag(tag);
 15.1360 +    clear_value(lval);
 15.1361 +    lval->ident=iCONSTEXPR;
 15.1362 +    lval->constval=tag | PUBLICTAG;
 15.1363 +    ldconst(lval->constval,sPRI);
 15.1364 +    while (paranthese--)
 15.1365 +      needtoken(')');
 15.1366 +    return FALSE;
 15.1367 +  case tSTATE: {
 15.1368 +    constvalue *automaton;
 15.1369 +    constvalue *state;
 15.1370 +    if (sc_getstateid(&automaton,&state)) {
 15.1371 +      assert(automaton!=NULL);
 15.1372 +      assert(automaton->index==0 && automaton->name[0]=='\0' || automaton->index>0);
 15.1373 +      loadreg(automaton->value,sALT);
 15.1374 +      assert(state!=NULL);
 15.1375 +      ldconst(state->value,sPRI);
 15.1376 +      ob_eq();
 15.1377 +      clear_value(lval);
 15.1378 +      lval->ident=iEXPRESSION;
 15.1379 +      lval->tag=pc_addtag("bool");
 15.1380 +    } /* if */
 15.1381 +    return FALSE;
 15.1382 +  } /* case */
 15.1383 +  default:
 15.1384 +    lexpush();
 15.1385 +    lvalue=hier1(lval);
 15.1386 +    /* check for postfix operators */
 15.1387 +    if (matchtoken(';')) {
 15.1388 +      /* Found a ';', do not look further for postfix operators */
 15.1389 +      lexpush();                /* push ';' back after successful match */
 15.1390 +      return lvalue;
 15.1391 +    } else if (matchtoken(tTERM)) {
 15.1392 +      /* Found a newline that ends a statement (this is the case when
 15.1393 +       * semicolons are optional). Note that an explicit semicolon was
 15.1394 +       * handled above. This case is similar, except that the token must
 15.1395 +       * not be pushed back.
 15.1396 +       */
 15.1397 +      return lvalue;
 15.1398 +    } else {
 15.1399 +      tok=lex(&val,&st);
 15.1400 +      switch (tok) {
 15.1401 +      case tINC:                /* lval++ */
 15.1402 +        if (!lvalue)
 15.1403 +          return error(22);     /* must be lvalue */
 15.1404 +        assert(lval->sym!=NULL);
 15.1405 +        if ((lval->sym->usage & uCONST)!=0)
 15.1406 +          return error(22);     /* assignment to const argument */
 15.1407 +        /* on incrementing array cells, the address in PRI must be saved for
 15.1408 +         * incremening the value, whereas the current value must be in PRI
 15.1409 +         * on exit.
 15.1410 +         */
 15.1411 +        saveresult= (lval->ident==iARRAYCELL || lval->ident==iARRAYCHAR);
 15.1412 +        if (saveresult)
 15.1413 +          pushreg(sPRI);        /* save address in PRI */
 15.1414 +        rvalue(lval);           /* read current value into PRI */
 15.1415 +        if (saveresult)
 15.1416 +          swap1();              /* save PRI on the stack, restore address in PRI */
 15.1417 +        if (!check_userop(user_inc,lval->tag,0,1,lval,&lval->tag))
 15.1418 +          inc(lval);            /* increase variable afterwards */
 15.1419 +        if (saveresult)
 15.1420 +          popreg(sPRI);         /* restore PRI (result of rvalue()) */
 15.1421 +        sideeffect=TRUE;
 15.1422 +        return FALSE;           /* result is no longer lvalue */
 15.1423 +      case tDEC:                /* lval-- */
 15.1424 +        if (!lvalue)
 15.1425 +          return error(22);     /* must be lvalue */
 15.1426 +        assert(lval->sym!=NULL);
 15.1427 +        if ((lval->sym->usage & uCONST)!=0)
 15.1428 +          return error(22);     /* assignment to const argument */
 15.1429 +        saveresult= (lval->ident==iARRAYCELL || lval->ident==iARRAYCHAR);
 15.1430 +        if (saveresult)
 15.1431 +          pushreg(sPRI);        /* save address in PRI */
 15.1432 +        rvalue(lval);           /* read current value into PRI */
 15.1433 +        if (saveresult)
 15.1434 +          swap1();              /* save PRI on the stack, restore address in PRI */
 15.1435 +        if (!check_userop(user_dec,lval->tag,0,1,lval,&lval->tag))
 15.1436 +          dec(lval);            /* decrease variable afterwards */
 15.1437 +        if (saveresult)
 15.1438 +          popreg(sPRI);         /* restore PRI (result of rvalue()) */
 15.1439 +        sideeffect=TRUE;
 15.1440 +        return FALSE;
 15.1441 +      case tCHAR:               /* char (compute required # of cells */
 15.1442 +        if (lval->ident==iCONSTEXPR) {
 15.1443 +          lval->constval *= sCHARBITS/8;  /* from char to bytes */
 15.1444 +          lval->constval = (lval->constval + sizeof(cell)-1) / sizeof(cell);
 15.1445 +        } else {
 15.1446 +          if (lvalue)
 15.1447 +            rvalue(lval);       /* fetch value if not already in PRI */
 15.1448 +          char2addr();          /* from characters to bytes */
 15.1449 +          addconst(sizeof(cell)-1);     /* make sure the value is rounded up */
 15.1450 +          addr2cell();          /* truncate to number of cells */
 15.1451 +        } /* if */
 15.1452 +        return FALSE;
 15.1453 +      default:
 15.1454 +        lexpush();
 15.1455 +        return lvalue;
 15.1456 +      } /* switch */
 15.1457 +    } /* if */
 15.1458 +  } /* switch */
 15.1459 +}
 15.1460 +
 15.1461 +/*  hier1
 15.1462 + *
 15.1463 + *  The highest hierarchy level: it looks for pointer and array indices
 15.1464 + *  and function calls.
 15.1465 + *  Generates code to fetch a pointer value if it is indexed and code to
 15.1466 + *  add to the pointer value or the array address (the address is already
 15.1467 + *  read at primary()). It also generates code to fetch a function address
 15.1468 + *  if that hasn't already been done at primary() (check lval[4]) and calls
 15.1469 + *  callfunction() to call the function.
 15.1470 + */
 15.1471 +static int hier1(value *lval1)
 15.1472 +{
 15.1473 +  int lvalue,index,tok,symtok;
 15.1474 +  cell val,cidx;
 15.1475 +  value lval2={0};
 15.1476 +  char *st;
 15.1477 +  char close;
 15.1478 +  symbol *sym;
 15.1479 +  symbol dummysymbol,*cursym;   /* for changing the index tags in case of enumerated pseudo-arrays */
 15.1480 +
 15.1481 +  lvalue=primary(lval1);
 15.1482 +  symtok=tokeninfo(&val,&st);   /* get token read by primary() */
 15.1483 +  cursym=lval1->sym;
 15.1484 +restart:
 15.1485 +  sym=cursym;
 15.1486 +  if (matchtoken('[') || matchtoken('{') || matchtoken('(')) {
 15.1487 +    tok=tokeninfo(&val,&st);    /* get token read by matchtoken() */
 15.1488 +    if (sym==NULL && symtok!=tSYMBOL) {
 15.1489 +      /* we do not have a valid symbol and we appear not to have read a valid
 15.1490 +       * symbol name (so it is unlikely that we would have read a name of an
 15.1491 +       * undefined symbol) */
 15.1492 +      error(29);                /* expression error, assumed 0 */
 15.1493 +      lexpush();                /* analyse '(', '{' or '[' again later */
 15.1494 +      return FALSE;
 15.1495 +    } /* if */
 15.1496 +    if (tok=='[' || tok=='{') { /* subscript */
 15.1497 +      close = (char)((tok=='[') ? ']' : '}');
 15.1498 +      if (sym==NULL) {  /* sym==NULL if lval is a constant or a literal */
 15.1499 +        error(28,"<no variable>");  /* cannot subscript */
 15.1500 +        needtoken(close);
 15.1501 +        return FALSE;
 15.1502 +      } else if (sym->ident!=iARRAY && sym->ident!=iREFARRAY){
 15.1503 +        error(28,sym->name);    /* cannot subscript, variable is not an array */
 15.1504 +        needtoken(close);
 15.1505 +        return FALSE;
 15.1506 +      } else if (sym->dim.array.level>0 && close!=']') {
 15.1507 +        error(51);      /* invalid subscript, must use [ ] */
 15.1508 +        needtoken(close);
 15.1509 +        return FALSE;
 15.1510 +      } /* if */
 15.1511 +      /* set the tag to match (enumeration fields as indices) */
 15.1512 +      lval2.cmptag=sym->x.tags.index;
 15.1513 +      stgget(&index,&cidx);     /* mark position in code generator */
 15.1514 +      pushreg(sPRI);            /* save base address of the array */
 15.1515 +      if (hier14(&lval2))       /* create expression for the array index */
 15.1516 +        rvalue(&lval2);
 15.1517 +      if (lval2.ident==iARRAY || lval2.ident==iREFARRAY)
 15.1518 +        error(33,lval2.sym->name);      /* array must be indexed */
 15.1519 +      needtoken(close);
 15.1520 +      if (!matchtag(sym->x.tags.index,lval2.tag,TRUE))
 15.1521 +        error(213);
 15.1522 +      if (lval2.ident==iCONSTEXPR) {    /* constant expression */
 15.1523 +        stgdel(index,cidx);             /* scratch generated code */
 15.1524 +        if (lval1->arrayidx!=NULL) {    /* keep constant index, for checking */
 15.1525 +          assert(sym->dim.array.level>=0 && sym->dim.array.level<sDIMEN_MAX);
 15.1526 +          lval1->arrayidx[sym->dim.array.level]=lval2.constval;
 15.1527 +        } /* if */
 15.1528 +        if (close==']') {
 15.1529 +          /* normal array index */
 15.1530 +          if (lval2.constval<0 || sym->dim.array.length!=0 && sym->dim.array.length<=lval2.constval)
 15.1531 +            error(32,sym->name);        /* array index out of bounds */
 15.1532 +          if (lval2.constval!=0) {
 15.1533 +            /* don't add offsets for zero subscripts */
 15.1534 +            #if PAWN_CELL_SIZE==16
 15.1535 +              ldconst(lval2.constval<<1,sALT);
 15.1536 +            #elif PAWN_CELL_SIZE==32
 15.1537 +              ldconst(lval2.constval<<2,sALT);
 15.1538 +            #elif PAWN_CELL_SIZE==64
 15.1539 +              ldconst(lval2.constval<<3,sALT);
 15.1540 +            #else
 15.1541 +              #error Unsupported cell size
 15.1542 +            #endif
 15.1543 +            ob_add();
 15.1544 +          } /* if */
 15.1545 +        } else {
 15.1546 +          /* character index */
 15.1547 +          if (lval2.constval<0 || sym->dim.array.length!=0
 15.1548 +              && sym->dim.array.length*((8*sizeof(cell))/sCHARBITS)<=(ucell)lval2.constval)
 15.1549 +            error(32,sym->name);        /* array index out of bounds */
 15.1550 +          if (lval2.constval!=0) {
 15.1551 +            /* don't add offsets for zero subscripts */
 15.1552 +            #if sCHARBITS==16
 15.1553 +              ldconst(lval2.constval<<1,sALT);/* 16-bit character */
 15.1554 +            #else
 15.1555 +              ldconst(lval2.constval,sALT);   /* 8-bit character */
 15.1556 +            #endif
 15.1557 +            ob_add();
 15.1558 +          } /* if */
 15.1559 +          charalign();                  /* align character index into array */
 15.1560 +        } /* if */
 15.1561 +        /* if the array index is a field from an enumeration, get the tag name
 15.1562 +         * from the field and save the size of the field too.
 15.1563 +         */
 15.1564 +        assert(lval2.sym==NULL || lval2.sym->dim.array.level==0);
 15.1565 +        if (lval2.sym!=NULL && lval2.sym->dim.array.length>0 && sym->dim.array.level==0) {
 15.1566 +          lval1->tag=lval2.sym->x.tags.index;
 15.1567 +          lval1->constval=lval2.sym->dim.array.length;
 15.1568 +        } /* if */
 15.1569 +      } else {
 15.1570 +        /* array index is not constant */
 15.1571 +        lval1->arrayidx=NULL;           /* reset, so won't be checked */
 15.1572 +        if (close==']') {
 15.1573 +          if (sym->dim.array.length!=0)
 15.1574 +            ffbounds(sym->dim.array.length-1);  /* run time check for array bounds */
 15.1575 +          cell2addr();  /* normal array index */
 15.1576 +        } else {
 15.1577 +          if (sym->dim.array.length!=0)
 15.1578 +            ffbounds(sym->dim.array.length*(32/sCHARBITS)-1);
 15.1579 +          char2addr();  /* character array index */
 15.1580 +        } /* if */
 15.1581 +        popreg(sALT);
 15.1582 +        ob_add();       /* base address was popped into secondary register */
 15.1583 +        if (close!=']')
 15.1584 +          charalign();  /* align character index into array */
 15.1585 +      } /* if */
 15.1586 +      /* the indexed item may be another array (multi-dimensional arrays) */
 15.1587 +      assert(cursym==sym && sym!=NULL); /* should still be set */
 15.1588 +      if (sym->dim.array.level>0) {
 15.1589 +        assert(close==']');     /* checked earlier */
 15.1590 +        assert(cursym==lval1->sym);
 15.1591 +        /* read the offset to the subarray and add it to the current address */
 15.1592 +        lval1->ident=iARRAYCELL;
 15.1593 +        pushreg(sPRI);          /* the optimizer makes this to a MOVE.alt */
 15.1594 +        rvalue(lval1);
 15.1595 +        popreg(sALT);
 15.1596 +        ob_add();
 15.1597 +        /* adjust the "value" structure and find the referenced array */
 15.1598 +        lval1->ident=iREFARRAY;
 15.1599 +        lval1->sym=finddepend(sym);
 15.1600 +        assert(lval1->sym!=NULL);
 15.1601 +        assert(lval1->sym->dim.array.level==sym->dim.array.level-1);
 15.1602 +        cursym=lval1->sym;
 15.1603 +        /* try to parse subsequent array indices */
 15.1604 +        lvalue=FALSE;   /* for now, a iREFARRAY is no lvalue */
 15.1605 +        goto restart;
 15.1606 +      } /* if */
 15.1607 +      assert(sym->dim.array.level==0);
 15.1608 +      /* set type to fetch... INDIRECTLY */
 15.1609 +      lval1->ident= (char)((close==']') ? iARRAYCELL : iARRAYCHAR);
 15.1610 +      /* if the array index is a field from an enumeration, get the tag name
 15.1611 +       * from the field and save the size of the field too. Otherwise, the
 15.1612 +       * tag is the one from the array symbol.
 15.1613 +       */
 15.1614 +      if (lval2.ident==iCONSTEXPR && lval2.sym!=NULL
 15.1615 +          && lval2.sym->dim.array.length>0 && sym->dim.array.level==0)
 15.1616 +      {
 15.1617 +        lval1->tag=lval2.sym->x.tags.index;
 15.1618 +        lval1->constval=lval2.sym->dim.array.length;
 15.1619 +        if (lval2.tag==sym->x.tags.index && lval1->constval>1 && matchtoken('[')) {
 15.1620 +          /* an array indexed with an enumeration field may be considered a sub-array */
 15.1621 +          lexpush();
 15.1622 +          lvalue=FALSE;   /* for now, a iREFARRAY is no lvalue */
 15.1623 +          lval1->ident=iREFARRAY;
 15.1624 +          /* initialize a dummy symbol, which is a copy of the current symbol,
 15.1625 +           * but with an adjusted index tag
 15.1626 +           */
 15.1627 +          assert(sym!=NULL);
 15.1628 +          dummysymbol=*sym;
 15.1629 +          /* get the tag of the root of the enumeration */
 15.1630 +          assert(lval2.sym!=NULL);
 15.1631 +          dummysymbol.x.tags.index=lval2.sym->x.tags.field;
 15.1632 +          dummysymbol.dim.array.length=lval2.sym->dim.array.length;
 15.1633 +          cursym=&dummysymbol;
 15.1634 +          /* recurse */
 15.1635 +          goto restart;
 15.1636 +        } /* if */
 15.1637 +      } else {
 15.1638 +        assert(sym!=NULL);
 15.1639 +        if (cursym!=&dummysymbol)
 15.1640 +          lval1->tag=sym->tag;
 15.1641 +        lval1->constval=0;
 15.1642 +      } /* if */
 15.1643 +      /* a cell in an array is an lvalue, a character in an array is not
 15.1644 +       * always a *valid* lvalue */
 15.1645 +      return TRUE;
 15.1646 +    } else {            /* tok=='(' -> function(...) */
 15.1647 +      assert(tok=='(');
 15.1648 +      if (sym==NULL
 15.1649 +          || (sym->ident!=iFUNCTN && sym->ident!=iREFFUNC))
 15.1650 +      {
 15.1651 +        if (sym==NULL && sc_status==statFIRST) {
 15.1652 +          /* could be a "use before declaration"; in that case, create a stub
 15.1653 +           * function so that the usage can be marked.
 15.1654 +           */
 15.1655 +          sym=fetchfunc(lastsymbol,0);
 15.1656 +          if (sym==NULL)
 15.1657 +            error(103); /* insufficient memory */
 15.1658 +          markusage(sym,uREAD);
 15.1659 +        } else {
 15.1660 +          return error(12);           /* invalid function call */
 15.1661 +        } /* if */
 15.1662 +      } else if ((sym->usage & uMISSING)!=0) {
 15.1663 +        char symname[2*sNAMEMAX+16];  /* allow space for user defined operators */
 15.1664 +        funcdisplayname(symname,sym->name);
 15.1665 +        error(4,symname);             /* function not defined */
 15.1666 +      } /* if */
 15.1667 +      callfunction(sym,lval1,TRUE);
 15.1668 +      return FALSE;             /* result of function call is no lvalue */
 15.1669 +    } /* if */
 15.1670 +  } /* if */
 15.1671 +  if (sym!=NULL && lval1->ident==iFUNCTN) {
 15.1672 +    assert(sym->ident==iFUNCTN);
 15.1673 +    if (sc_allowproccall) {
 15.1674 +      callfunction(sym,lval1,FALSE);
 15.1675 +    } else {
 15.1676 +      lval1->sym=NULL;
 15.1677 +      lval1->ident=iEXPRESSION;
 15.1678 +      lval1->constval=0;
 15.1679 +      lval1->tag=0;
 15.1680 +      error(76);                /* invalid function call, or syntax error */
 15.1681 +    } /* if */
 15.1682 +    return FALSE;
 15.1683 +  } /* if */
 15.1684 +  return lvalue;
 15.1685 +}
 15.1686 +
 15.1687 +/*  primary
 15.1688 + *
 15.1689 + *  Returns 1 if the operand is an lvalue (everything except arrays, functions
 15.1690 + *  constants and -of course- errors).
 15.1691 + *  Generates code to fetch the address of arrays. Code for constants is
 15.1692 + *  already generated by constant().
 15.1693 + *  This routine first clears the entire lval array (all fields are set to 0).
 15.1694 + *
 15.1695 + *  Global references: sc_intest  (may be altered, but restored upon termination)
 15.1696 + */
 15.1697 +static int primary(value *lval)
 15.1698 +{
 15.1699 +  char *st;
 15.1700 +  int lvalue,tok;
 15.1701 +  cell val;
 15.1702 +  symbol *sym;
 15.1703 +
 15.1704 +  if (matchtoken('(')){         /* sub-expression - (expression,...) */
 15.1705 +    PUSHSTK_I(sc_intest);
 15.1706 +    PUSHSTK_I(sc_allowtags);
 15.1707 +
 15.1708 +    sc_intest=FALSE;            /* no longer in "test" expression */
 15.1709 +    sc_allowtags=TRUE;          /* allow tagnames to be used in parenthesized expressions */
 15.1710 +    sc_allowproccall=FALSE;
 15.1711 +    do
 15.1712 +      lvalue=hier14(lval);
 15.1713 +    while (matchtoken(','));
 15.1714 +    needtoken(')');
 15.1715 +    lexclr(FALSE);              /* clear lex() push-back, it should have been
 15.1716 +                                 * cleared already by needtoken() */
 15.1717 +    sc_allowtags=(short)POPSTK_I();
 15.1718 +    sc_intest=(short)POPSTK_I();
 15.1719 +    return lvalue;
 15.1720 +  } /* if */
 15.1721 +
 15.1722 +  clear_value(lval);    /* clear lval */
 15.1723 +  tok=lex(&val,&st);
 15.1724 +  if (tok==tSYMBOL) {
 15.1725 +    /* lastsymbol is char[sNAMEMAX+1], lex() should have truncated any symbol
 15.1726 +     * to sNAMEMAX significant characters */
 15.1727 +    assert(strlen(st)<sizeof lastsymbol);
 15.1728 +    strcpy(lastsymbol,st);
 15.1729 +  } /* if */
 15.1730 +  if (tok==tSYMBOL && !findconst(st,NULL)) {
 15.1731 +    /* first look for a local variable */
 15.1732 +    if ((sym=findloc(st))!=0) {
 15.1733 +      if (sym->ident==iLABEL) {
 15.1734 +        error(29);          /* expression error, assumed 0 */
 15.1735 +        ldconst(0,sPRI);    /* load 0 */
 15.1736 +        return FALSE;       /* return 0 for labels (expression error) */
 15.1737 +      } /* if */
 15.1738 +      lval->sym=sym;
 15.1739 +      lval->ident=sym->ident;
 15.1740 +      lval->tag=sym->tag;
 15.1741 +      if (sym->ident==iARRAY || sym->ident==iREFARRAY) {
 15.1742 +        address(sym,sPRI);  /* get starting address in primary register */
 15.1743 +        return FALSE;       /* return 0 for array (not lvalue) */
 15.1744 +      } else {
 15.1745 +        return TRUE;        /* return 1 if lvalue (not label or array) */
 15.1746 +      } /* if */
 15.1747 +    } /* if */
 15.1748 +    /* now try a global variable */
 15.1749 +    if ((sym=findglb(st,sSTATEVAR))!=0) {
 15.1750 +      if (sym->ident==iFUNCTN || sym->ident==iREFFUNC) {
 15.1751 +        /* if the function is only in the table because it was inserted as a
 15.1752 +         * stub in the first pass (i.e. it was "used" but never declared or
 15.1753 +         * implemented, issue an error
 15.1754 +         */
 15.1755 +        if ((sym->usage & uPROTOTYPED)==0)
 15.1756 +          error(17,st);
 15.1757 +      } else {
 15.1758 +        if ((sym->usage & uDEFINE)==0)
 15.1759 +          error(17,st);
 15.1760 +        lval->sym=sym;
 15.1761 +        lval->ident=sym->ident;
 15.1762 +        lval->tag=sym->tag;
 15.1763 +        if (sym->ident==iARRAY || sym->ident==iREFARRAY) {
 15.1764 +          address(sym,sPRI);    /* get starting address in primary register */
 15.1765 +          return FALSE;         /* return 0 for array (not lvalue) */
 15.1766 +        } else {
 15.1767 +          return TRUE;          /* return 1 if lvalue (not function or array) */
 15.1768 +        } /* if */
 15.1769 +      } /* if */
 15.1770 +    } else {
 15.1771 +      if (!sc_allowproccall)
 15.1772 +        return error(17,st);    /* undefined symbol */
 15.1773 +      /* an unknown symbol, but used in a way compatible with the "procedure
 15.1774 +       * call" syntax. So assume that the symbol refers to a function.
 15.1775 +       */
 15.1776 +      assert(sc_status==statFIRST);
 15.1777 +      sym=fetchfunc(st,0);
 15.1778 +      if (sym==NULL)
 15.1779 +        error(103);     /* insufficient memory */
 15.1780 +    } /* if */
 15.1781 +    assert(sym!=NULL);
 15.1782 +    assert(sym->ident==iFUNCTN || sym->ident==iREFFUNC);
 15.1783 +    lval->sym=sym;
 15.1784 +    lval->ident=sym->ident;
 15.1785 +    lval->tag=sym->tag;
 15.1786 +    return FALSE;       /* return 0 for function (not an lvalue) */
 15.1787 +  } /* if */
 15.1788 +  lexpush();            /* push the token, it is analyzed by constant() */
 15.1789 +  if (constant(lval)==0) {
 15.1790 +    error(29);          /* expression error, assumed 0 */
 15.1791 +    ldconst(0,sPRI);    /* load 0 */
 15.1792 +  } /* if */
 15.1793 +  return FALSE;         /* return 0 for constants (or errors) */
 15.1794 +}
 15.1795 +
 15.1796 +static void clear_value(value *lval)
 15.1797 +{
 15.1798 +  lval->sym=NULL;
 15.1799 +  lval->constval=0L;
 15.1800 +  lval->tag=0;
 15.1801 +  lval->ident=0;
 15.1802 +  lval->boolresult=FALSE;
 15.1803 +  /* do not clear lval->arrayidx, it is preset in hier14() */
 15.1804 +  /* do not clear lval->cmptag */
 15.1805 +}
 15.1806 +
 15.1807 +static void setdefarray(cell *string,cell size,cell array_sz,cell *dataaddr,int fconst)
 15.1808 +{
 15.1809 +  /* The routine must copy the default array data onto the heap, as to avoid
 15.1810 +   * that a function can change the default value. An optimization is that
 15.1811 +   * the default array data is "dumped" into the data segment only once (on the
 15.1812 +   * first use).
 15.1813 +   */
 15.1814 +  assert(string!=NULL);
 15.1815 +  assert(size>0);
 15.1816 +  /* check whether to dump the default array */
 15.1817 +  assert(dataaddr!=NULL);
 15.1818 +  if (sc_status==statWRITE && *dataaddr<0) {
 15.1819 +    int i;
 15.1820 +    *dataaddr=(litidx+glb_declared)*sizeof(cell);
 15.1821 +    for (i=0; i<size; i++)
 15.1822 +      litadd(*string++);
 15.1823 +  } /* if */
 15.1824 +
 15.1825 +  /* if the function is known not to modify the array (meaning that it also
 15.1826 +   * does not modify the default value), directly pass the address of the
 15.1827 +   * array in the data segment.
 15.1828 +   */
 15.1829 +  if (fconst) {
 15.1830 +    ldconst(*dataaddr,sPRI);
 15.1831 +  } else {
 15.1832 +    /* Generate the code:
 15.1833 +     *  CONST.pri dataaddr                ;address of the default array data
 15.1834 +     *  HEAP      array_sz*sizeof(cell)   ;heap address in ALT
 15.1835 +     *  MOVS      size*sizeof(cell)       ;copy data from PRI to ALT
 15.1836 +     *  MOVE.PRI                          ;PRI = address on the heap
 15.1837 +     */
 15.1838 +    ldconst(*dataaddr,sPRI);
 15.1839 +    /* "array_sz" is the size of the argument (the value between the brackets
 15.1840 +     * in the declaration), "size" is the size of the default array data.
 15.1841 +     */
 15.1842 +    assert(array_sz>=size);
 15.1843 +    modheap((int)array_sz*sizeof(cell));
 15.1844 +    /* ??? should perhaps fill with zeros first */
 15.1845 +    memcopy(size*sizeof(cell));
 15.1846 +    moveto1();
 15.1847 +  } /* if */
 15.1848 +}
 15.1849 +
 15.1850 +static int findnamedarg(arginfo *arg,char *name)
 15.1851 +{
 15.1852 +  int i;
 15.1853 +
 15.1854 +  for (i=0; arg[i].ident!=0 && arg[i].ident!=iVARARGS; i++)
 15.1855 +    if (strcmp(arg[i].name,name)==0)
 15.1856 +      return i;
 15.1857 +  return -1;
 15.1858 +}
 15.1859 +
 15.1860 +static int checktag(int tags[],int numtags,int exprtag)
 15.1861 +{
 15.1862 +  int i;
 15.1863 +
 15.1864 +  assert(tags!=0);
 15.1865 +  assert(numtags>0);
 15.1866 +  for (i=0; i<numtags; i++)
 15.1867 +    if (matchtag(tags[i],exprtag,TRUE))
 15.1868 +      return TRUE;    /* matching tag */
 15.1869 +  return FALSE;       /* no tag matched */
 15.1870 +}
 15.1871 +
 15.1872 +enum {
 15.1873 +  ARG_UNHANDLED,
 15.1874 +  ARG_IGNORED,
 15.1875 +  ARG_DONE,
 15.1876 +};
 15.1877 +
 15.1878 +/*  callfunction
 15.1879 + *
 15.1880 + *  Generates code to call a function. This routine handles default arguments
 15.1881 + *  and positional as well as named parameters.
 15.1882 + */
 15.1883 +static void callfunction(symbol *sym,value *lval_result,int matchparanthesis)
 15.1884 +{
 15.1885 +static long nest_stkusage=0L;
 15.1886 +static int nesting=0;
 15.1887 +  int locheap;
 15.1888 +  int close,lvalue;
 15.1889 +  int argpos;       /* index in the output stream (argpos==nargs if positional parameters) */
 15.1890 +  int argidx=0;     /* index in "arginfo" list */
 15.1891 +  int nargs=0;      /* number of arguments */
 15.1892 +  int heapalloc=0;
 15.1893 +  int namedparams=FALSE;
 15.1894 +  value lval = {0};
 15.1895 +  arginfo *arg;
 15.1896 +  char arglist[sMAXARGS];
 15.1897 +  constvalue arrayszlst = { NULL, "", 0, 0};/* array size list starts empty */
 15.1898 +  constvalue taglst = { NULL, "", 0, 0};    /* tag list starts empty */
 15.1899 +  symbol *symret;
 15.1900 +  cell lexval;
 15.1901 +  char *lexstr;
 15.1902 +
 15.1903 +  assert(sym!=NULL);
 15.1904 +  lval_result->ident=iEXPRESSION; /* preset, may be changed later */
 15.1905 +  lval_result->constval=0;
 15.1906 +  lval_result->tag=sym->tag;
 15.1907 +  /* check whether this is a function that returns an array */
 15.1908 +  symret=finddepend(sym);
 15.1909 +  assert(symret==NULL || symret->ident==iREFARRAY);
 15.1910 +  if (symret!=NULL) {
 15.1911 +    int retsize;
 15.1912 +    /* allocate space on the heap for the array, and pass the pointer to the
 15.1913 +     * reserved memory block as a hidden parameter
 15.1914 +     */
 15.1915 +    retsize=(int)array_totalsize(symret);
 15.1916 +    assert(retsize>0);
 15.1917 +    modheap(retsize*sizeof(cell));/* address is in ALT */
 15.1918 +    pushreg(sALT);                /* pass ALT as the last (hidden) parameter */
 15.1919 +    decl_heap+=retsize;
 15.1920 +    /* also mark the ident of the result as "array" */
 15.1921 +    lval_result->ident=iREFARRAY;
 15.1922 +    lval_result->sym=symret;
 15.1923 +  } /* if */
 15.1924 +  locheap=decl_heap;
 15.1925 +
 15.1926 +  nesting++;
 15.1927 +  assert(nest_stkusage>=0);
 15.1928 +  #if !defined NDEBUG
 15.1929 +    if (nesting==1)
 15.1930 +      assert(nest_stkusage==0);
 15.1931 +  #endif
 15.1932 +  sc_allowproccall=FALSE;       /* parameters may not use procedure call syntax */
 15.1933 +
 15.1934 +  if ((sym->flags & flgDEPRICATED)!=0) {
 15.1935 +    char *ptr= (sym->documentation!=NULL) ? sym->documentation : "";
 15.1936 +    error(234,sym->name,ptr);   /* depricated (probably a native function) */
 15.1937 +  } /* if */
 15.1938 +
 15.1939 +  /* run through the arguments */
 15.1940 +  arg=sym->dim.arglist;
 15.1941 +  assert(arg!=NULL);
 15.1942 +  stgmark(sSTARTREORDER);
 15.1943 +  memset(arglist,ARG_UNHANDLED,sizeof arglist);
 15.1944 +  if (matchparanthesis) {
 15.1945 +    /* Opening brace was already parsed, if closing brace follows, this
 15.1946 +     * call passes no parameters.
 15.1947 +     */
 15.1948 +    close=matchtoken(')');
 15.1949 +  } else {
 15.1950 +    /* When we find an end of line here, it may be a function call passing
 15.1951 +     * no parameters, or it may be that the first parameter is on a line
 15.1952 +     * below. But as a parameter can be anything, this is difficult to check.
 15.1953 +     * The only simple check that we have is the use of "named parameters".
 15.1954 +     */
 15.1955 +    close=matchtoken(tTERM);
 15.1956 +    if (close) {
 15.1957 +      close=!matchtoken('.');
 15.1958 +      if (!close)
 15.1959 +        lexpush();                /* reset the '.' */
 15.1960 +    } /* if */
 15.1961 +  } /* if */
 15.1962 +  if (!close) {
 15.1963 +    do {
 15.1964 +      if (matchtoken('.')) {
 15.1965 +        namedparams=TRUE;
 15.1966 +        if (needtoken(tSYMBOL))
 15.1967 +          tokeninfo(&lexval,&lexstr);
 15.1968 +        else
 15.1969 +          lexstr="";
 15.1970 +        argpos=findnamedarg(arg,lexstr);
 15.1971 +        if (argpos<0) {
 15.1972 +          error(17,lexstr);       /* undefined symbol */
 15.1973 +          break;                  /* exit loop, argpos is invalid */
 15.1974 +        } /* if */
 15.1975 +        needtoken('=');
 15.1976 +        argidx=argpos;
 15.1977 +      } else {
 15.1978 +        if (namedparams)
 15.1979 +          error(44);   /* positional parameters must precede named parameters */
 15.1980 +        argpos=nargs;
 15.1981 +      } /* if */
 15.1982 +      /* the number of arguments this was already checked at the declaration
 15.1983 +       * of the function; check it again for functions with a variable
 15.1984 +       * argument list
 15.1985 +       */
 15.1986 +      if (argpos>=sMAXARGS)
 15.1987 +        error(45);                /* too many function arguments */
 15.1988 +      stgmark((char)(sEXPRSTART+argpos));/* mark beginning of new expression in stage */
 15.1989 +      if (arglist[argpos]!=ARG_UNHANDLED)
 15.1990 +        error(58);                /* argument already set */
 15.1991 +      if (matchtoken('_')) {
 15.1992 +        arglist[argpos]=ARG_IGNORED;  /* flag argument as "present, but ignored" */
 15.1993 +        if (arg[argidx].ident==0 || arg[argidx].ident==iVARARGS) {
 15.1994 +          error(202);             /* argument count mismatch */
 15.1995 +        } else if (!arg[argidx].hasdefault) {
 15.1996 +          error(34,nargs+1);      /* argument has no default value */
 15.1997 +        } /* if */
 15.1998 +        if (arg[argidx].ident!=0 && arg[argidx].ident!=iVARARGS)
 15.1999 +          argidx++;
 15.2000 +        /* The rest of the code to handle default values is at the bottom
 15.2001 +         * of this routine where default values for unspecified parameters
 15.2002 +         * are (also) handled. Note that above, the argument is flagged as
 15.2003 +         * ARG_IGNORED.
 15.2004 +         */
 15.2005 +      } else {
 15.2006 +        arglist[argpos]=ARG_DONE; /* flag argument as "present" */
 15.2007 +        if (arg[argidx].numtags==1)     /* set the expected tag, if any */
 15.2008 +          lval.cmptag=arg[argidx].tags[0];
 15.2009 +        lvalue=hier14(&lval);
 15.2010 +        assert(sc_status==statFIRST || arg[argidx].tags!=NULL);
 15.2011 +        switch (arg[argidx].ident) {
 15.2012 +        case 0:
 15.2013 +          error(202);             /* argument count mismatch */
 15.2014 +          break;
 15.2015 +        case iVARARGS:
 15.2016 +          /* always pass by reference */
 15.2017 +          if (lval.ident==iVARIABLE || lval.ident==iREFERENCE) {
 15.2018 +            assert(lval.sym!=NULL);
 15.2019 +            if ((lval.sym->usage & uCONST)!=0 && (arg[argidx].usage & uCONST)==0) {
 15.2020 +              /* treat a "const" variable passed to a function with a non-const
 15.2021 +               * "variable argument list" as a constant here */
 15.2022 +              if (!lvalue) {
 15.2023 +                error(22);        /* need lvalue */
 15.2024 +              } else {
 15.2025 +                rvalue(&lval);    /* get value in PRI */
 15.2026 +                setheap_pri();    /* address of the value on the heap in PRI */
 15.2027 +                heapalloc++;
 15.2028 +                nest_stkusage++;
 15.2029 +              } /* if */
 15.2030 +            } else if (lvalue) {
 15.2031 +              address(lval.sym,sPRI);
 15.2032 +            } else {
 15.2033 +              setheap_pri();      /* address of the value on the heap in PRI */
 15.2034 +              heapalloc++;
 15.2035 +              nest_stkusage++;
 15.2036 +            } /* if */
 15.2037 +          } else if (lval.ident==iCONSTEXPR || lval.ident==iEXPRESSION
 15.2038 +                     || lval.ident==iARRAYCHAR)
 15.2039 +          {
 15.2040 +            /* fetch value if needed */
 15.2041 +            if (lval.ident==iARRAYCHAR)
 15.2042 +              rvalue(&lval);
 15.2043 +            /* allocate a cell on the heap and store the
 15.2044 +             * value (already in PRI) there */
 15.2045 +            setheap_pri();        /* address of the value on the heap in PRI */
 15.2046 +            heapalloc++;
 15.2047 +            nest_stkusage++;
 15.2048 +          } /* if */
 15.2049 +          /* ??? handle const array passed by reference */
 15.2050 +          /* otherwise, the address is already in PRI */
 15.2051 +          if (lval.sym!=NULL)
 15.2052 +            markusage(lval.sym,uWRITTEN);
 15.2053 +          if (!checktag(arg[argidx].tags,arg[argidx].numtags,lval.tag))
 15.2054 +            error(213);
 15.2055 +          if (lval.tag!=0)
 15.2056 +            append_constval(&taglst,arg[argidx].name,lval.tag,0);
 15.2057 +          break;
 15.2058 +        case iVARIABLE:
 15.2059 +          if (lval.ident==iLABEL || lval.ident==iFUNCTN || lval.ident==iREFFUNC
 15.2060 +              || lval.ident==iARRAY || lval.ident==iREFARRAY)
 15.2061 +            error(35,argidx+1);   /* argument type mismatch */
 15.2062 +          if (lvalue)
 15.2063 +            rvalue(&lval);        /* get value (direct or indirect) */
 15.2064 +          /* otherwise, the expression result is already in PRI */
 15.2065 +          assert(arg[argidx].numtags>0);
 15.2066 +          check_userop(NULL,lval.tag,arg[argidx].tags[0],2,NULL,&lval.tag);
 15.2067 +          if (!checktag(arg[argidx].tags,arg[argidx].numtags,lval.tag))
 15.2068 +            error(213);
 15.2069 +          if (lval.tag!=0)
 15.2070 +            append_constval(&taglst,arg[argidx].name,lval.tag,0);
 15.2071 +          argidx++;               /* argument done */
 15.2072 +          break;
 15.2073 +        case iREFERENCE:
 15.2074 +          if (!lvalue || lval.ident==iARRAYCHAR)
 15.2075 +            error(35,argidx+1);   /* argument type mismatch */
 15.2076 +          if (lval.sym!=NULL && (lval.sym->usage & uCONST)!=0 && (arg[argidx].usage & uCONST)==0)
 15.2077 +            error(35,argidx+1);   /* argument type mismatch */
 15.2078 +          if (lval.ident==iVARIABLE || lval.ident==iREFERENCE) {
 15.2079 +            if (lvalue) {
 15.2080 +              assert(lval.sym!=NULL);
 15.2081 +              address(lval.sym,sPRI);
 15.2082 +            } else {
 15.2083 +              setheap_pri();      /* address of the value on the heap in PRI */
 15.2084 +              heapalloc++;
 15.2085 +              nest_stkusage++;
 15.2086 +            } /* if */
 15.2087 +          } /* if */
 15.2088 +          /* otherwise, the address is already in PRI */
 15.2089 +          if (!checktag(arg[argidx].tags,arg[argidx].numtags,lval.tag))
 15.2090 +            error(213);
 15.2091 +          if (lval.tag!=0)
 15.2092 +            append_constval(&taglst,arg[argidx].name,lval.tag,0);
 15.2093 +          argidx++;               /* argument done */
 15.2094 +          if (lval.sym!=NULL)
 15.2095 +            markusage(lval.sym,uWRITTEN);
 15.2096 +          break;
 15.2097 +        case iREFARRAY:
 15.2098 +          if (lval.ident!=iARRAY && lval.ident!=iREFARRAY
 15.2099 +              && lval.ident!=iARRAYCELL)
 15.2100 +          {
 15.2101 +            error(35,argidx+1);   /* argument type mismatch */
 15.2102 +            break;
 15.2103 +          } /* if */
 15.2104 +          if (lval.sym!=NULL && (lval.sym->usage & uCONST)!=0 && (arg[argidx].usage & uCONST)==0)
 15.2105 +            error(35,argidx+1); /* argument type mismatch */
 15.2106 +          /* Verify that the dimensions match with those in arg[argidx].
 15.2107 +           * A literal array always has a single dimension.
 15.2108 +           * An iARRAYCELL parameter is also assumed to have a single dimension.
 15.2109 +           */
 15.2110 +          if (lval.sym==NULL || lval.ident==iARRAYCELL) {
 15.2111 +            if (arg[argidx].numdim!=1) {
 15.2112 +              error(48);        /* array dimensions must match */
 15.2113 +            } else if (arg[argidx].dim[0]!=0) {
 15.2114 +              assert(arg[argidx].dim[0]>0);
 15.2115 +              if (lval.ident==iARRAYCELL) {
 15.2116 +                error(47);        /* array sizes must match */
 15.2117 +              } else {
 15.2118 +                assert(lval.constval!=0); /* literal array must have a size */
 15.2119 +                /* A literal array must have exactly the same size as the
 15.2120 +                 * function argument; a literal string may be smaller than
 15.2121 +                 * the function argument.
 15.2122 +                 */
 15.2123 +                if (lval.constval>0 && arg[argidx].dim[0]!=lval.constval
 15.2124 +                    || lval.constval<0 && arg[argidx].dim[0] < -lval.constval)
 15.2125 +                  error(47);      /* array sizes must match */
 15.2126 +              } /* if */
 15.2127 +            } /* if */
 15.2128 +            if (lval.ident!=iARRAYCELL) {
 15.2129 +              /* save array size, for default values with uSIZEOF flag */
 15.2130 +              cell array_sz=lval.constval;
 15.2131 +              assert(array_sz!=0);/* literal array must have a size */
 15.2132 +              if (array_sz<0)
 15.2133 +                array_sz= -array_sz;
 15.2134 +              append_constval(&arrayszlst,arg[argidx].name,array_sz,0);
 15.2135 +            } /* if */
 15.2136 +          } else {
 15.2137 +            symbol *sym=lval.sym;
 15.2138 +            short level=0;
 15.2139 +            assert(sym!=NULL);
 15.2140 +            if (sym->dim.array.level+1!=arg[argidx].numdim)
 15.2141 +              error(48);          /* array dimensions must match */
 15.2142 +            /* the lengths for all dimensions must match, unless the dimension
 15.2143 +             * length was defined at zero (which means "undefined")
 15.2144 +             */
 15.2145 +            while (sym->dim.array.level>0) {
 15.2146 +              assert(level<sDIMEN_MAX);
 15.2147 +              if (arg[argidx].dim[level]!=0 && sym->dim.array.length!=arg[argidx].dim[level])
 15.2148 +                error(47);        /* array sizes must match */
 15.2149 +              else if (!matchtag(arg[argidx].idxtag[level],sym->x.tags.index,TRUE))
 15.2150 +                error(229,sym->name);   /* index tag mismatch */
 15.2151 +              append_constval(&arrayszlst,arg[argidx].name,sym->dim.array.length,level);
 15.2152 +              sym=finddepend(sym);
 15.2153 +              assert(sym!=NULL);
 15.2154 +              level++;
 15.2155 +            } /* if */
 15.2156 +            /* the last dimension is checked too, again, unless it is zero */
 15.2157 +            assert(level<sDIMEN_MAX);
 15.2158 +            assert(sym!=NULL);
 15.2159 +            if (arg[argidx].dim[level]!=0 && sym->dim.array.length!=arg[argidx].dim[level])
 15.2160 +              error(47);          /* array sizes must match */
 15.2161 +            else if (!matchtag(arg[argidx].idxtag[level],sym->x.tags.index,TRUE))
 15.2162 +              error(229,sym->name);   /* index tag mismatch */
 15.2163 +            append_constval(&arrayszlst,arg[argidx].name,sym->dim.array.length,level);
 15.2164 +          } /* if */
 15.2165 +          /* address already in PRI */
 15.2166 +          if (!checktag(arg[argidx].tags,arg[argidx].numtags,lval.tag))
 15.2167 +            error(213);
 15.2168 +          if (lval.tag!=0)
 15.2169 +            append_constval(&taglst,arg[argidx].name,lval.tag,0);
 15.2170 +          // ??? set uWRITTEN?
 15.2171 +          argidx++;               /* argument done */
 15.2172 +          break;
 15.2173 +        } /* switch */
 15.2174 +        pushreg(sPRI);            /* store the function argument on the stack */
 15.2175 +        markexpr(sPARM,NULL,0);   /* mark the end of a sub-expression */
 15.2176 +        nest_stkusage++;
 15.2177 +      } /* if */
 15.2178 +      assert(arglist[argpos]!=ARG_UNHANDLED);
 15.2179 +      nargs++;
 15.2180 +      if (matchparanthesis) {
 15.2181 +        close=matchtoken(')');
 15.2182 +        if (!close)               /* if not paranthese... */
 15.2183 +          if (!needtoken(','))    /* ...should be comma... */
 15.2184 +            break;                /* ...but abort loop if neither */
 15.2185 +      } else {
 15.2186 +        close=!matchtoken(',');
 15.2187 +        if (close) {              /* if not comma... */
 15.2188 +          if (needtoken(tTERM)==1)/* ...must be end of statement */
 15.2189 +            lexpush();            /* push again, because end of statement is analised later */
 15.2190 +        } /* if */
 15.2191 +      } /* if */
 15.2192 +    } while (!close && freading && !matchtoken(tENDEXPR)); /* do */
 15.2193 +  } /* if */
 15.2194 +  /* check remaining function arguments (they may have default values) */
 15.2195 +  for (argidx=0; arg[argidx].ident!=0 && arg[argidx].ident!=iVARARGS; argidx++) {
 15.2196 +    if (arglist[argidx]==ARG_DONE)
 15.2197 +      continue;                 /* already seen and handled this argument */
 15.2198 +    /* in this first stage, we also skip the arguments with uSIZEOF and uTAGOF;
 15.2199 +     * these are handled last
 15.2200 +     */
 15.2201 +    if ((arg[argidx].hasdefault & uSIZEOF)!=0 || (arg[argidx].hasdefault & uTAGOF)!=0) {
 15.2202 +      assert(arg[argidx].ident==iVARIABLE);
 15.2203 +      continue;
 15.2204 +    } /* if */
 15.2205 +    stgmark((char)(sEXPRSTART+argidx));/* mark beginning of new expression in stage */
 15.2206 +    if (arg[argidx].hasdefault) {
 15.2207 +      if (arg[argidx].ident==iREFARRAY) {
 15.2208 +        short level;
 15.2209 +        setdefarray(arg[argidx].defvalue.array.data,
 15.2210 +                    arg[argidx].defvalue.array.size,
 15.2211 +                    arg[argidx].defvalue.array.arraysize,
 15.2212 +                    &arg[argidx].defvalue.array.addr,
 15.2213 +                    (arg[argidx].usage & uCONST)!=0);
 15.2214 +        if ((arg[argidx].usage & uCONST)==0) {
 15.2215 +          heapalloc+=arg[argidx].defvalue.array.arraysize;
 15.2216 +          nest_stkusage+=arg[argidx].defvalue.array.arraysize;
 15.2217 +        } /* if */
 15.2218 +        /* keep the lengths of all dimensions of a multi-dimensional default array */
 15.2219 +        assert(arg[argidx].numdim>0);
 15.2220 +        if (arg[argidx].numdim==1) {
 15.2221 +          append_constval(&arrayszlst,arg[argidx].name,arg[argidx].defvalue.array.arraysize,0);
 15.2222 +        } else {
 15.2223 +          for (level=0; level<arg[argidx].numdim; level++) {
 15.2224 +            assert(level<sDIMEN_MAX);
 15.2225 +            append_constval(&arrayszlst,arg[argidx].name,arg[argidx].dim[level],level);
 15.2226 +          } /* for */
 15.2227 +        } /* if */
 15.2228 +      } else if (arg[argidx].ident==iREFERENCE) {
 15.2229 +        setheap(arg[argidx].defvalue.val);
 15.2230 +        /* address of the value on the heap in PRI */
 15.2231 +        heapalloc++;
 15.2232 +        nest_stkusage++;
 15.2233 +      } else {
 15.2234 +        int dummytag=arg[argidx].tags[0];
 15.2235 +        ldconst(arg[argidx].defvalue.val,sPRI);
 15.2236 +        assert(arg[argidx].numtags>0);
 15.2237 +        check_userop(NULL,arg[argidx].defvalue_tag,arg[argidx].tags[0],2,NULL,&dummytag);
 15.2238 +        assert(dummytag==arg[argidx].tags[0]);
 15.2239 +      } /* if */
 15.2240 +      pushreg(sPRI);            /* store the function argument on the stack */
 15.2241 +      markexpr(sPARM,NULL,0);   /* mark the end of a sub-expression */
 15.2242 +      nest_stkusage++;
 15.2243 +    } else {
 15.2244 +      error(202,argidx);        /* argument count mismatch */
 15.2245 +    } /* if */
 15.2246 +    if (arglist[argidx]==ARG_UNHANDLED)
 15.2247 +      nargs++;
 15.2248 +    arglist[argidx]=ARG_DONE;
 15.2249 +  } /* for */
 15.2250 +  /* now a second loop to catch the arguments with default values that are
 15.2251 +   * the "sizeof" or "tagof" of other arguments
 15.2252 +   */
 15.2253 +  for (argidx=0; arg[argidx].ident!=0 && arg[argidx].ident!=iVARARGS; argidx++) {
 15.2254 +    constvalue *asz;
 15.2255 +    cell array_sz;
 15.2256 +    if (arglist[argidx]==ARG_DONE)
 15.2257 +      continue;                 /* already seen and handled this argument */
 15.2258 +    stgmark((char)(sEXPRSTART+argidx));/* mark beginning of new expression in stage */
 15.2259 +    assert(arg[argidx].ident==iVARIABLE);           /* if "sizeof", must be single cell */
 15.2260 +    /* if unseen, must be "sizeof" or "tagof" */
 15.2261 +    assert((arg[argidx].hasdefault & uSIZEOF)!=0 || (arg[argidx].hasdefault & uTAGOF)!=0);
 15.2262 +    if ((arg[argidx].hasdefault & uSIZEOF)!=0) {
 15.2263 +      /* find the argument; if it isn't found, the argument's default value
 15.2264 +       * was a "sizeof" of a non-array (a warning for this was already given
 15.2265 +       * when declaring the function)
 15.2266 +       */
 15.2267 +      asz=find_constval(&arrayszlst,arg[argidx].defvalue.size.symname,
 15.2268 +                        arg[argidx].defvalue.size.level);
 15.2269 +      if (asz!=NULL) {
 15.2270 +        array_sz=asz->value;
 15.2271 +        if (array_sz==0)
 15.2272 +          error(224,arg[argidx].name);    /* indeterminate array size in "sizeof" expression */
 15.2273 +      } else {
 15.2274 +        array_sz=1;
 15.2275 +      } /* if */
 15.2276 +    } else {
 15.2277 +      asz=find_constval(&taglst,arg[argidx].defvalue.size.symname,
 15.2278 +                        arg[argidx].defvalue.size.level);
 15.2279 +      if (asz != NULL) {
 15.2280 +        exporttag(asz->value);
 15.2281 +        array_sz=asz->value | PUBLICTAG;  /* must be set, because it just was exported */
 15.2282 +      } else {
 15.2283 +        array_sz=0;
 15.2284 +      } /* if */
 15.2285 +    } /* if */
 15.2286 +    ldconst(array_sz,sPRI);
 15.2287 +    pushreg(sPRI);              /* store the function argument on the stack */
 15.2288 +    markexpr(sPARM,NULL,0);
 15.2289 +    nest_stkusage++;
 15.2290 +    if (arglist[argidx]==ARG_UNHANDLED)
 15.2291 +      nargs++;
 15.2292 +    arglist[argidx]=ARG_DONE;
 15.2293 +  } /* for */
 15.2294 +  stgmark(sENDREORDER);         /* mark end of reversed evaluation */
 15.2295 +  pushval((cell)nargs*sizeof(cell));
 15.2296 +  nest_stkusage++;
 15.2297 +  ffcall(sym,NULL,nargs);
 15.2298 +  if (sc_status!=statSKIP)
 15.2299 +    markusage(sym,uREAD);       /* do not mark as "used" when this call itself is skipped */
 15.2300 +  if ((sym->usage & uNATIVE)!=0 &&sym->x.lib!=NULL)
 15.2301 +    sym->x.lib->value += 1;     /* increment "usage count" of the library */
 15.2302 +  modheap(-heapalloc*sizeof(cell));
 15.2303 +  if (symret!=NULL)
 15.2304 +    popreg(sPRI);               /* pop hidden parameter as function result */
 15.2305 +  sideeffect=TRUE;              /* assume functions carry out a side-effect */
 15.2306 +  delete_consttable(&arrayszlst);     /* clear list of array sizes */
 15.2307 +  delete_consttable(&taglst);   /* clear list of parameter tags */
 15.2308 +
 15.2309 +  /* maintain max. amount of memory used */
 15.2310 +  {
 15.2311 +    long totalsize;
 15.2312 +    totalsize=declared+decl_heap+1;   /* local variables & return value size,
 15.2313 +                                       * +1 for PROC opcode */
 15.2314 +    if (lval_result->ident==iREFARRAY)
 15.2315 +      totalsize++;                    /* add hidden parameter (on the stack) */
 15.2316 +    if ((sym->usage & uNATIVE)==0)
 15.2317 +      totalsize++;                    /* add "call" opcode */
 15.2318 +    totalsize+=nest_stkusage;
 15.2319 +    assert(curfunc!=NULL);
 15.2320 +    if (curfunc->x.stacksize<totalsize)
 15.2321 +      curfunc->x.stacksize=totalsize;
 15.2322 +    nest_stkusage-=nargs+heapalloc+1; /* stack/heap space, +1 for argcount param */
 15.2323 +    /* if there is a syntax error in the script, the stack calculation is
 15.2324 +     * probably incorrect; but we may not allow it to drop below zero
 15.2325 +     */
 15.2326 +    if (nest_stkusage<0)
 15.2327 +      nest_stkusage=0;
 15.2328 +  }
 15.2329 +
 15.2330 +  /* scrap any arrays left on the heap, with the exception of the array that
 15.2331 +   * this function has as a result (in other words, scrap all arrays on the
 15.2332 +   * heap that caused by expressions in the function arguments)
 15.2333 +   */
 15.2334 +  assert(decl_heap>=locheap);
 15.2335 +  modheap((locheap-decl_heap)*sizeof(cell));  /* remove heap space, so negative delta */
 15.2336 +  decl_heap=locheap;
 15.2337 +  nesting--;
 15.2338 +}
 15.2339 +
 15.2340 +/*  dbltest
 15.2341 + *
 15.2342 + *  Returns a non-zero value if lval1 an array and lval2 is not an array and
 15.2343 + *  the operation is addition or subtraction.
 15.2344 + *
 15.2345 + *  Returns the "shift" count (1 for 16-bit, 2 for 32-bit) to align a cell
 15.2346 + *  to an array offset.
 15.2347 + */
 15.2348 +static int dbltest(void (*oper)(),value *lval1,value *lval2)
 15.2349 +{
 15.2350 +  if ((oper!=ob_add) && (oper!=ob_sub))
 15.2351 +    return 0;
 15.2352 +  if (lval1->ident!=iARRAY)
 15.2353 +    return 0;
 15.2354 +  if (lval2->ident==iARRAY)
 15.2355 +    return 0;
 15.2356 +  return sizeof(cell)/2;        /* 1 for 16-bit, 2 for 32-bit */
 15.2357 +}
 15.2358 +
 15.2359 +/*  commutative
 15.2360 + *
 15.2361 + *  Test whether an operator is commutative, i.e. x oper y == y oper x.
 15.2362 + *  Commutative operators are: +  (addition)
 15.2363 + *                             *  (multiplication)
 15.2364 + *                             == (equality)
 15.2365 + *                             != (inequality)
 15.2366 + *                             &  (bitwise and)
 15.2367 + *                             ^  (bitwise xor)
 15.2368 + *                             |  (bitwise or)
 15.2369 + *
 15.2370 + *  If in an expression, code for the left operand has been generated and
 15.2371 + *  the right operand is a constant and the operator is commutative, the
 15.2372 + *  precautionary "push" of the primary register is scrapped and the constant
 15.2373 + *  is read into the secondary register immediately.
 15.2374 + */
 15.2375 +static int commutative(void (*oper)())
 15.2376 +{
 15.2377 +  return oper==ob_add || oper==os_mult
 15.2378 +         || oper==ob_eq || oper==ob_ne
 15.2379 +         || oper==ob_and || oper==ob_xor || oper==ob_or;
 15.2380 +}
 15.2381 +
 15.2382 +/*  constant
 15.2383 + *
 15.2384 + *  Generates code to fetch a number, a literal character (which is returned
 15.2385 + *  by lex() as a number as well) or a literal string (lex() stores the
 15.2386 + *  strings in the literal queue). If the operand was a number, it is stored
 15.2387 + *  in lval->constval.
 15.2388 + *
 15.2389 + *  The function returns 1 if the token was a constant or a string, 0
 15.2390 + *  otherwise.
 15.2391 + */
 15.2392 +static int constant(value *lval)
 15.2393 +{
 15.2394 +  int tok,index,ident;
 15.2395 +  cell val,item,cidx;
 15.2396 +  char *st;
 15.2397 +  symbol *sym;
 15.2398 +  int cmptag=lval->cmptag;
 15.2399 +
 15.2400 +  tok=lex(&val,&st);
 15.2401 +  if (tok==tSYMBOL && (sym=findconst(st,&cmptag))!=0) {
 15.2402 +    if (cmptag>1)
 15.2403 +      error(91,sym->name);  /* ambiguity: multiple matching constants (different tags) */
 15.2404 +    lval->constval=sym->addr;
 15.2405 +    ldconst(lval->constval,sPRI);
 15.2406 +    lval->ident=iCONSTEXPR;
 15.2407 +    lval->tag=sym->tag;
 15.2408 +    lval->sym=sym;
 15.2409 +    markusage(sym,uREAD);
 15.2410 +  } else if (tok==tNUMBER) {
 15.2411 +    lval->constval=val;
 15.2412 +    ldconst(lval->constval,sPRI);
 15.2413 +    lval->ident=iCONSTEXPR;
 15.2414 +  } else if (tok==tRATIONAL) {
 15.2415 +    lval->constval=val;
 15.2416 +    ldconst(lval->constval,sPRI);
 15.2417 +    lval->ident=iCONSTEXPR;
 15.2418 +    lval->tag=sc_rationaltag;
 15.2419 +  } else if (tok==tSTRING) {
 15.2420 +    /* lex() stores starting index of string in the literal table in 'val' */
 15.2421 +    ldconst((val+glb_declared)*sizeof(cell),sPRI);
 15.2422 +    lval->ident=iARRAY;         /* pretend this is a global array */
 15.2423 +    lval->constval=val-litidx;  /* constval == the negative value of the
 15.2424 +                                 * size of the literal array; using a negative
 15.2425 +                                 * value distinguishes between literal arrays
 15.2426 +                                 * and literal strings (this was done for
 15.2427 +                                 * array assignment). */
 15.2428 +  } else if (tok=='{') {
 15.2429 +    int tag,lasttag=-1;
 15.2430 +    val=litidx;
 15.2431 +    do {
 15.2432 +      /* cannot call constexpr() here, because "staging" is already turned
 15.2433 +       * on at this point */
 15.2434 +      assert(staging);
 15.2435 +      stgget(&index,&cidx);     /* mark position in code generator */
 15.2436 +      ident=expression(&item,&tag,NULL,FALSE);
 15.2437 +      stgdel(index,cidx);       /* scratch generated code */
 15.2438 +      if (ident!=iCONSTEXPR)
 15.2439 +        error(8);               /* must be constant expression */
 15.2440 +      if (lasttag<0)
 15.2441 +        lasttag=tag;
 15.2442 +      else if (!matchtag(lasttag,tag,FALSE))
 15.2443 +        error(213);             /* tagname mismatch */
 15.2444 +      litadd(item);             /* store expression result in literal table */
 15.2445 +    } while (matchtoken(','));
 15.2446 +    if (!needtoken('}'))
 15.2447 +      lexclr(FALSE);
 15.2448 +    ldconst((val+glb_declared)*sizeof(cell),sPRI);
 15.2449 +    lval->ident=iARRAY;         /* pretend this is a global array */
 15.2450 +    lval->constval=litidx-val;  /* constval == the size of the literal array */
 15.2451 +  } else {
 15.2452 +    return FALSE;               /* no, it cannot be interpreted as a constant */
 15.2453 +  } /* if */
 15.2454 +  return TRUE;                  /* yes, it was a constant value */
 15.2455 +}
 15.2456 +
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/compiler-init/compiler-init/sc4.c	Fri Jul 14 02:02:18 2006 +0000
    16.3 @@ -0,0 +1,1331 @@
    16.4 +/*  Pawn compiler - code generation (unoptimized "assembler" code)
    16.5 + *
    16.6 + *  Copyright (c) ITB CompuPhase, 1997-2006
    16.7 + *
    16.8 + *  This software is provided "as-is", without any express or implied warranty.
    16.9 + *  In no event will the authors be held liable for any damages arising from
   16.10 + *  the use of this software.
   16.11 + *
   16.12 + *  Permission is granted to anyone to use this software for any purpose,
   16.13 + *  including commercial applications, and to alter it and redistribute it
   16.14 + *  freely, subject to the following restrictions:
   16.15 + *
   16.16 + *  1.  The origin of this software must not be misrepresented; you must not
   16.17 + *      claim that you wrote the original software. If you use this software in
   16.18 + *      a product, an acknowledgment in the product documentation would be
   16.19 + *      appreciated but is not required.
   16.20 + *  2.  Altered source versions must be plainly marked as such, and must not be
   16.21 + *      misrepresented as being the original software.
   16.22 + *  3.  This notice may not be removed or altered from any source distribution.
   16.23 + *
   16.24 + *  Version: $Id: sc4.c 3579 2006-06-06 13:35:29Z thiadmer $
   16.25 + */
   16.26 +#include <assert.h>
   16.27 +#include <ctype.h>
   16.28 +#include <stdio.h>
   16.29 +#include <stdlib.h>     /* for _MAX_PATH */
   16.30 +#include <string.h>
   16.31 +#if defined FORTIFY
   16.32 +  #include <alloc/fortify.h>
   16.33 +#endif
   16.34 +#include "sc.h"
   16.35 +
   16.36 +static int fcurseg;     /* the file number (fcurrent) for the active segment */
   16.37 +
   16.38 +
   16.39 +/* When a subroutine returns to address 0, the AMX must halt. In earlier
   16.40 + * releases, the RET and RETN opcodes checked for the special case 0 address.
   16.41 + * Today, the compiler simply generates a HALT instruction at address 0. So
   16.42 + * a subroutine can savely return to 0, and then encounter a HALT.
   16.43 + */
   16.44 +SC_FUNC void writeleader(symbol *root)
   16.45 +{
   16.46 +  int lbl_nostate,lbl_table;
   16.47 +  int statecount;
   16.48 +  symbol *sym;
   16.49 +  constvalue *fsa, *state, *stlist;
   16.50 +  int fsa_id,listid;
   16.51 +  char lbl_default[sNAMEMAX+1];
   16.52 +
   16.53 +  assert(code_idx==0);
   16.54 +
   16.55 +  begcseg();
   16.56 +  stgwrite(";program exit point\n");
   16.57 +  stgwrite("\thalt 0\n\n");
   16.58 +  code_idx+=opcodes(1)+opargs(1);       /* calculate code length */
   16.59 +
   16.60 +  /* check whether there are any functions that have states */
   16.61 +  for (sym=root->next; sym!=NULL; sym=sym->next)
   16.62 +    if (sym->ident==iFUNCTN && (sym->usage & (uPUBLIC | uREAD))!=0 && sym->states!=NULL)
   16.63 +      break;
   16.64 +  if (sym==NULL)
   16.65 +    return;             /* no function has states, nothing to do next */
   16.66 +
   16.67 +  /* generate an error function that is called for an undefined state */
   16.68 +  stgwrite("\n;exit point for functions called from the wrong state\n");
   16.69 +  lbl_nostate=getlabel();
   16.70 +  setlabel(lbl_nostate);
   16.71 +  stgwrite("\thalt ");
   16.72 +  outval(AMX_ERR_INVSTATE,TRUE);
   16.73 +  code_idx+=opcodes(1)+opargs(1);       /* calculate code length */
   16.74 +
   16.75 +  /* write the "state-selectors" table with all automatons (update the
   16.76 +   * automatons structure too, as we are now assigning the address to
   16.77 +   * each automaton state-selector variable)
   16.78 +   */
   16.79 +  assert(glb_declared==0);
   16.80 +  begdseg();
   16.81 +  for (fsa=sc_automaton_tab.next; fsa!=NULL; fsa=fsa->next) {
   16.82 +    defstorage();
   16.83 +    stgwrite("0\t; automaton ");
   16.84 +    if (strlen(fsa->name)==0)
   16.85 +      stgwrite("(anonymous)");
   16.86 +    else
   16.87 +      stgwrite(fsa->name);
   16.88 +    stgwrite("\n");
   16.89 +    fsa->value=glb_declared*sizeof(cell);
   16.90 +    glb_declared++;
   16.91 +  } /* for */
   16.92 +
   16.93 +  /* write stubs and jump tables for all state functions */
   16.94 +  begcseg();
   16.95 +  for (sym=root->next; sym!=NULL; sym=sym->next) {
   16.96 +    if (sym->ident==iFUNCTN && (sym->usage & (uPUBLIC | uREAD))!=0 && sym->states!=NULL) {
   16.97 +      stlist=sym->states->next;
   16.98 +      assert(stlist!=NULL);     /* there should be at least one state item */
   16.99 +      listid=stlist->index;
  16.100 +      assert(listid==-1 || listid>0);
  16.101 +      if (listid==-1 && stlist->next!=NULL) {
  16.102 +        /* first index is the "fallback", take the next one (if available) */
  16.103 +        stlist=stlist->next;
  16.104 +        listid=stlist->index;
  16.105 +      } /* if */
  16.106 +      if (listid==-1) {
  16.107 +        /* first index is the fallback, there is no second... */
  16.108 +        strcpy(stlist->name,"0"); /* insert dummy label number */
  16.109 +        /* this is an error, but we postpone adding the error message until the
  16.110 +         * function definition
  16.111 +         */
  16.112 +        continue;
  16.113 +      } /* if */
  16.114 +      /* generate label numbers for all statelist ids */
  16.115 +      for (stlist=sym->states->next; stlist!=NULL; stlist=stlist->next) {
  16.116 +        assert(strlen(stlist->name)==0);
  16.117 +        strcpy(stlist->name,itoh(getlabel()));
  16.118 +      } /* for */
  16.119 +      if (strcmp(sym->name,uENTRYFUNC)==0)
  16.120 +        continue;               /* do not generate stubs for this special function */
  16.121 +      sym->addr=code_idx;       /* fix the function address now */
  16.122 +      /* get automaton id for this function */
  16.123 +      assert(listid>0);
  16.124 +      fsa_id=state_getfsa(listid);
  16.125 +      assert(fsa_id>=0);        /* automaton 0 exists */
  16.126 +      fsa=automaton_findid(fsa_id);
  16.127 +      /* count the number of states actually used; at the sane time, check
  16.128 +       * whether there is a default state function
  16.129 +       */
  16.130 +      statecount=0;
  16.131 +      strcpy(lbl_default,itoh(lbl_nostate));
  16.132 +      for (stlist=sym->states->next; stlist!=NULL; stlist=stlist->next) {
  16.133 +        if (stlist->index==-1) {
  16.134 +          assert(strlen(stlist->name)<sizeof lbl_default);
  16.135 +          strcpy(lbl_default,stlist->name);
  16.136 +        } else {
  16.137 +          statecount+=state_count(stlist->index);
  16.138 +        } /* if */
  16.139 +      } /* for */
  16.140 +      /* generate a stub entry for the functions */
  16.141 +      stgwrite("\tload.pri ");
  16.142 +      outval(fsa->value,FALSE);
  16.143 +      stgwrite("\t; ");
  16.144 +      stgwrite(sym->name);
  16.145 +      stgwrite("\n");
  16.146 +      code_idx+=opcodes(1)+opargs(1);   /* calculate code length */
  16.147 +      lbl_table=getlabel();
  16.148 +      ffswitch(lbl_table);
  16.149 +      /* generate the jump table */
  16.150 +      setlabel(lbl_table);
  16.151 +      ffcase(statecount,lbl_default,TRUE);
  16.152 +      for (state=sc_state_tab.next; state!=NULL; state=state->next) {
  16.153 +        if (state->index==fsa_id) {
  16.154 +          /* find the label for this list id */
  16.155 +          for (stlist=sym->states->next; stlist!=NULL; stlist=stlist->next) {
  16.156 +            if (stlist->index!=-1 && state_inlist(stlist->index,(int)state->value)) {
  16.157 +              ffcase(state->value,stlist->name,FALSE);
  16.158 +              break;
  16.159 +            } /* if */
  16.160 +          } /* for */
  16.161 +          if (stlist==NULL && strtol(lbl_default,NULL,16)==lbl_nostate)
  16.162 +            error(230,state->name,sym->name);  /* unimplemented state, no fallback */
  16.163 +        } /* if (state belongs to automaton of function) */
  16.164 +      } /* for (state) */
  16.165 +      stgwrite("\n");
  16.166 +    } /* if (is function, used & having states) */
  16.167 +  } /* for (sym) */
  16.168 +}
  16.169 +
  16.170 +/*  writetrailer
  16.171 + *  Not much left of this once important function.
  16.172 + *
  16.173 + *  Global references: pc_stksize       (referred to only)
  16.174 + *                     sc_dataalign     (referred to only)
  16.175 + *                     code_idx         (altered)
  16.176 + *                     glb_declared     (altered)
  16.177 + */
  16.178 +SC_FUNC void writetrailer(void)
  16.179 +{
  16.180 +  assert(sc_dataalign % opcodes(1) == 0);   /* alignment must be a multiple of
  16.181 +                                             * the opcode size */
  16.182 +  assert(sc_dataalign!=0);
  16.183 +
  16.184 +  /* pad code to align data segment */
  16.185 +  if ((code_idx % sc_dataalign)!=0) {
  16.186 +    begcseg();
  16.187 +    while ((code_idx % sc_dataalign)!=0)
  16.188 +      nooperation();
  16.189 +  } /* if */
  16.190 +
  16.191 +  /* pad data segment to align the stack and the heap */
  16.192 +  assert(litidx==0);            /* literal queue should have been emptied */
  16.193 +  assert(sc_dataalign % sizeof(cell) == 0);
  16.194 +  if (((glb_declared*sizeof(cell)) % sc_dataalign)!=0) {
  16.195 +    begdseg();
  16.196 +    defstorage();
  16.197 +    while (((glb_declared*sizeof(cell)) % sc_dataalign)!=0) {
  16.198 +      stgwrite("0 ");
  16.199 +      glb_declared++;
  16.200 +    } /* while */
  16.201 +  } /* if */
  16.202 +
  16.203 +  stgwrite("\nSTKSIZE ");       /* write stack size (align stack top) */
  16.204 +  outval(pc_stksize - (pc_stksize % sc_dataalign), TRUE);
  16.205 +}
  16.206 +
  16.207 +/*
  16.208 + *  Start (or restart) the CODE segment.
  16.209 + *
  16.210 + *  In fact, the code and data segment specifiers are purely informational;
  16.211 + *  the "DUMP" instruction itself already specifies that the following values
  16.212 + *  should go to the data segment. All other instructions go to the code
  16.213 + *  segment.
  16.214 + *
  16.215 + *  Global references: curseg
  16.216 + *                     fcurrent
  16.217 + */
  16.218 +SC_FUNC void begcseg(void)
  16.219 +{
  16.220 +  if (curseg!=sIN_CSEG || fcurrent!=fcurseg) {
  16.221 +    stgwrite("\n");
  16.222 +    stgwrite("CODE ");
  16.223 +    outval(fcurrent,FALSE);
  16.224 +    stgwrite("\t; ");
  16.225 +    outval(code_idx,TRUE);
  16.226 +    curseg=sIN_CSEG;
  16.227 +    fcurseg=fcurrent;
  16.228 +  } /* endif */
  16.229 +}
  16.230 +
  16.231 +/*
  16.232 + *  Start (or restart) the DATA segment.
  16.233 + *
  16.234 + *  Global references: curseg
  16.235 + */
  16.236 +SC_FUNC void begdseg(void)
  16.237 +{
  16.238 +  if (curseg!=sIN_DSEG || fcurrent!=fcurseg) {
  16.239 +    stgwrite("\n");
  16.240 +    stgwrite("DATA ");
  16.241 +    outval(fcurrent,FALSE);
  16.242 +    stgwrite("\t; ");
  16.243 +    outval((glb_declared-litidx)*sizeof(cell),TRUE);
  16.244 +    curseg=sIN_DSEG;
  16.245 +    fcurseg=fcurrent;
  16.246 +  } /* if */
  16.247 +}
  16.248 +
  16.249 +SC_FUNC void setline(int chkbounds)
  16.250 +{
  16.251 +  if ((sc_debug & sSYMBOLIC)!=0 || chkbounds && (sc_debug & sCHKBOUNDS)!=0) {
  16.252 +    /* generate a "break" (start statement) opcode rather than a "line" opcode
  16.253 +     * because earlier versions of Small/Pawn have an incompatible version of the
  16.254 +     * line opcode
  16.255 +     */
  16.256 +    stgwrite("\tbreak\t; ");
  16.257 +    outval(code_idx,TRUE);
  16.258 +    code_idx+=opcodes(1);
  16.259 +  } /* if */
  16.260 +}
  16.261 +
  16.262 +SC_FUNC void setfiledirect(char *name)
  16.263 +{
  16.264 +  if (sc_status==statFIRST && sc_listing) {
  16.265 +    assert(name!=NULL);
  16.266 +    pc_writeasm(outf,"#file ");
  16.267 +    pc_writeasm(outf,name);
  16.268 +    pc_writeasm(outf,"\n");
  16.269 +  } /* if */
  16.270 +}
  16.271 +
  16.272 +SC_FUNC void setlinedirect(int line)
  16.273 +{
  16.274 +  if (sc_status==statFIRST && sc_listing) {
  16.275 +    char string[40];
  16.276 +    sprintf(string,"#line %d\n",line);
  16.277 +    pc_writeasm(outf,string);
  16.278 +  } /* if */
  16.279 +}
  16.280 +
  16.281 +/*  setlabel
  16.282 + *
  16.283 + *  Post a code label (specified as a number), on a new line.
  16.284 + */
  16.285 +SC_FUNC void setlabel(int number)
  16.286 +{
  16.287 +  assert(number>=0);
  16.288 +  stgwrite("l.");
  16.289 +  stgwrite((char *)itoh(number));
  16.290 +  /* To assist verification of the assembled code, put the address of the
  16.291 +   * label as a comment. However, labels that occur inside an expression
  16.292 +   * may move (through optimization or through re-ordering). So write the
  16.293 +   * address only if it is known to accurate.
  16.294 +   */
  16.295 +  if (!staging) {
  16.296 +    stgwrite("\t\t; ");
  16.297 +    outval(code_idx,FALSE);
  16.298 +  } /* if */
  16.299 +  stgwrite("\n");
  16.300 +}
  16.301 +
  16.302 +/* Write a token that signifies the start or end of an expression or special
  16.303 + * statement. This allows several simple optimizations by the peephole
  16.304 + * optimizer.
  16.305 + */
  16.306 +SC_FUNC void markexpr(optmark type,const char *name,cell offset)
  16.307 +{
  16.308 +  switch (type) {
  16.309 +  case sEXPR:
  16.310 +    stgwrite("\t;$exp\n");
  16.311 +    break;
  16.312 +  case sPARM:
  16.313 +    stgwrite("\t;$par\n");
  16.314 +    break;
  16.315 +  case sLDECL:
  16.316 +    assert(name!=NULL);
  16.317 +    stgwrite("\t;$lcl ");
  16.318 +    stgwrite(name);
  16.319 +    stgwrite(" ");
  16.320 +    outval(offset,TRUE);
  16.321 +    break;
  16.322 +  default:
  16.323 +    assert(0);
  16.324 +  } /* switch */
  16.325 +}
  16.326 +
  16.327 +/*  startfunc   - declare a CODE entry point (function start)
  16.328 + *
  16.329 + *  Global references: funcstatus  (referred to only)
  16.330 + */
  16.331 +SC_FUNC void startfunc(char *fname)
  16.332 +{
  16.333 +  stgwrite("\tproc");
  16.334 +  if (sc_asmfile) {
  16.335 +    char symname[2*sNAMEMAX+16];
  16.336 +    funcdisplayname(symname,fname);
  16.337 +    stgwrite("\t; ");
  16.338 +    stgwrite(symname);
  16.339 +  } /* if */
  16.340 +  stgwrite("\n");
  16.341 +  code_idx+=opcodes(1);
  16.342 +}
  16.343 +
  16.344 +/*  endfunc
  16.345 + *
  16.346 + *  Declare a CODE ending point (function end)
  16.347 + */
  16.348 +SC_FUNC void endfunc(void)
  16.349 +{
  16.350 +  stgwrite("\n");       /* skip a line */
  16.351 +}
  16.352 +
  16.353 +/*  alignframe
  16.354 + *
  16.355 + *  Aligns the frame (and the stack) of the current function to a multiple
  16.356 + *  of the specified byte count. Two caveats: the alignment ("numbytes") should
  16.357 + *  be a power of 2, and this alignment must be done right after the frame
  16.358 + *  is set up (before the first variable is declared)
  16.359 + */
  16.360 +SC_FUNC void alignframe(int numbytes)
  16.361 +{
  16.362 +  #if !defined NDEBUG
  16.363 +    /* "numbytes" should be a power of 2 for this code to work */
  16.364 +    int i,count=0;
  16.365 +    for (i=0; i<sizeof numbytes*8; i++)
  16.366 +      if (numbytes & (1 << i))
  16.367 +        count++;
  16.368 +    assert(count==1);
  16.369 +  #endif
  16.370 +
  16.371 +  stgwrite("\tlctrl 4\n");      /* get STK in PRI */
  16.372 +  stgwrite("\tconst.alt ");     /* get ~(numbytes-1) in ALT */
  16.373 +  outval(~(numbytes-1),TRUE);
  16.374 +  stgwrite("\tand\n");          /* PRI = STK "and" ~(numbytes-1) */
  16.375 +  stgwrite("\tsctrl 4\n");      /* set the new value of STK ... */
  16.376 +  stgwrite("\tsctrl 5\n");      /* ... and FRM */
  16.377 +  code_idx+=opcodes(5)+opargs(4);
  16.378 +}
  16.379 +
  16.380 +/*  rvalue
  16.381 + *
  16.382 + *  Generate code to get the value of a symbol into "primary".
  16.383 + */
  16.384 +SC_FUNC void rvalue(value *lval)
  16.385 +{
  16.386 +  symbol *sym;
  16.387 +
  16.388 +  sym=lval->sym;
  16.389 +  if (lval->ident==iARRAYCELL) {
  16.390 +    /* indirect fetch, address already in PRI */
  16.391 +    stgwrite("\tload.i\n");
  16.392 +    code_idx+=opcodes(1);
  16.393 +  } else if (lval->ident==iARRAYCHAR) {
  16.394 +    /* indirect fetch of a character from a pack, address already in PRI */
  16.395 +    stgwrite("\tlodb.i ");
  16.396 +    outval(sCHARBITS/8,TRUE);   /* read one or two bytes */
  16.397 +    code_idx+=opcodes(1)+opargs(1);
  16.398 +  } else if (lval->ident==iREFERENCE) {
  16.399 +    /* indirect fetch, but address not yet in PRI */
  16.400 +    assert(sym!=NULL);
  16.401 +    assert(sym->vclass==sLOCAL);/* global references don't exist in Pawn */
  16.402 +    if (sym->vclass==sLOCAL)
  16.403 +      stgwrite("\tlref.s.pri ");
  16.404 +    else
  16.405 +      stgwrite("\tlref.pri ");
  16.406 +    outval(sym->addr,TRUE);
  16.407 +    markusage(sym,uREAD);
  16.408 +    code_idx+=opcodes(1)+opargs(1);
  16.409 +  } else {
  16.410 +    /* direct or stack relative fetch */
  16.411 +    assert(sym!=NULL);
  16.412 +    if (sym->vclass==sLOCAL)
  16.413 +      stgwrite("\tload.s.pri ");
  16.414 +    else
  16.415 +      stgwrite("\tload.pri ");
  16.416 +    outval(sym->addr,TRUE);
  16.417 +    markusage(sym,uREAD);
  16.418 +    code_idx+=opcodes(1)+opargs(1);
  16.419 +  } /* if */
  16.420 +}
  16.421 +
  16.422 +/* Get the address of a symbol into the primary or alternate register (used
  16.423 + * for arrays, and for passing arguments by reference).
  16.424 + */
  16.425 +SC_FUNC void address(symbol *sym,regid reg)
  16.426 +{
  16.427 +  assert(sym!=NULL);
  16.428 +  assert(reg==sPRI || reg==sALT);
  16.429 +  /* the symbol can be a local array, a global array, or an array
  16.430 +   * that is passed by reference.
  16.431 +   */
  16.432 +  if (sym->ident==iREFARRAY || sym->ident==iREFERENCE) {
  16.433 +    /* reference to a variable or to an array; currently this is
  16.434 +     * always a local variable */
  16.435 +    switch (reg) {
  16.436 +    case sPRI:
  16.437 +      stgwrite("\tload.s.pri ");
  16.438 +      break;
  16.439 +    case sALT:
  16.440 +      stgwrite("\tload.s.alt ");
  16.441 +      break;
  16.442 +    } /* switch */
  16.443 +  } else {
  16.444 +    /* a local array or local variable */
  16.445 +    switch (reg) {
  16.446 +    case sPRI:
  16.447 +      if (sym->vclass==sLOCAL)
  16.448 +        stgwrite("\taddr.pri ");
  16.449 +      else
  16.450 +        stgwrite("\tconst.pri ");
  16.451 +      break;
  16.452 +    case sALT:
  16.453 +      if (sym->vclass==sLOCAL)
  16.454 +        stgwrite("\taddr.alt ");
  16.455 +      else
  16.456 +        stgwrite("\tconst.alt ");
  16.457 +      break;
  16.458 +    } /* switch */
  16.459 +  } /* if */
  16.460 +  outval(sym->addr,TRUE);
  16.461 +  markusage(sym,uREAD);
  16.462 +  code_idx+=opcodes(1)+opargs(1);
  16.463 +}
  16.464 +
  16.465 +/*  store
  16.466 + *
  16.467 + *  Saves the contents of "primary" into a memory cell, either directly
  16.468 + *  or indirectly (at the address given in the alternate register).
  16.469 + */
  16.470 +SC_FUNC void store(value *lval)
  16.471 +{
  16.472 +  symbol *sym;
  16.473 +
  16.474 +  sym=lval->sym;
  16.475 +  if (lval->ident==iARRAYCELL) {
  16.476 +    /* store at address in ALT */
  16.477 +    stgwrite("\tstor.i\n");
  16.478 +    code_idx+=opcodes(1);
  16.479 +  } else if (lval->ident==iARRAYCHAR) {
  16.480 +    /* store at address in ALT */
  16.481 +    stgwrite("\tstrb.i ");
  16.482 +    outval(sCHARBITS/8,TRUE);   /* write one or two bytes */
  16.483 +    code_idx+=opcodes(1)+opargs(1);
  16.484 +  } else if (lval->ident==iREFERENCE) {
  16.485 +    assert(sym!=NULL);
  16.486 +    if (sym->vclass==sLOCAL)
  16.487 +      stgwrite("\tsref.s.pri ");
  16.488 +    else
  16.489 +      stgwrite("\tsref.pri ");
  16.490 +    outval(sym->addr,TRUE);
  16.491 +    code_idx+=opcodes(1)+opargs(1);
  16.492 +  } else {
  16.493 +    assert(sym!=NULL);
  16.494 +    markusage(sym,uWRITTEN);
  16.495 +    if (sym->vclass==sLOCAL)
  16.496 +      stgwrite("\tstor.s.pri ");
  16.497 +    else
  16.498 +      stgwrite("\tstor.pri ");
  16.499 +    outval(sym->addr,TRUE);
  16.500 +    code_idx+=opcodes(1)+opargs(1);
  16.501 +  } /* if */
  16.502 +}
  16.503 +
  16.504 +/* Get a cell from a fixed address in memory */
  16.505 +SC_FUNC void loadreg(cell address,regid reg)
  16.506 +{
  16.507 +  assert(reg==sPRI || reg==sALT);
  16.508 +  if (reg==sPRI)
  16.509 +    stgwrite("\tload.pri ");
  16.510 +  else
  16.511 +    stgwrite("\tload.alt ");
  16.512 +  outval(address,TRUE);
  16.513 +  code_idx+=opcodes(1)+opargs(1);
  16.514 +}
  16.515 +
  16.516 +/* Store a cell into a fixed address in memory */
  16.517 +SC_FUNC void storereg(cell address,regid reg)
  16.518 +{
  16.519 +  assert(reg==sPRI || reg==sALT);
  16.520 +  if (reg==sPRI)
  16.521 +    stgwrite("\tstor.pri ");
  16.522 +  else
  16.523 +    stgwrite("\tstor.alt ");
  16.524 +  outval(address,TRUE);
  16.525 +  code_idx+=opcodes(1)+opargs(1);
  16.526 +}
  16.527 +
  16.528 +/* source must in PRI, destination address in ALT. The "size"
  16.529 + * parameter is in bytes, not cells.
  16.530 + */
  16.531 +SC_FUNC void memcopy(cell size)
  16.532 +{
  16.533 +  stgwrite("\tmovs ");
  16.534 +  outval(size,TRUE);
  16.535 +
  16.536 +  code_idx+=opcodes(1)+opargs(1);
  16.537 +}
  16.538 +
  16.539 +/* Address of the source must already have been loaded in PRI
  16.540 + * "size" is the size in bytes (not cells).
  16.541 + */
  16.542 +SC_FUNC void copyarray(symbol *sym,cell size)
  16.543 +{
  16.544 +  assert(sym!=NULL);
  16.545 +  /* the symbol can be a local array, a global array, or an array
  16.546 +   * that is passed by reference.
  16.547 +   */
  16.548 +  if (sym->ident==iREFARRAY) {
  16.549 +    /* reference to an array; currently this is always a local variable */
  16.550 +    assert(sym->vclass==sLOCAL);        /* symbol must be stack relative */
  16.551 +    stgwrite("\tload.s.alt ");
  16.552 +  } else {
  16.553 +    /* a local or global array */
  16.554 +    if (sym->vclass==sLOCAL)
  16.555 +      stgwrite("\taddr.alt ");
  16.556 +    else
  16.557 +      stgwrite("\tconst.alt ");
  16.558 +  } /* if */
  16.559 +  outval(sym->addr,TRUE);
  16.560 +  markusage(sym,uWRITTEN);
  16.561 +
  16.562 +  code_idx+=opcodes(1)+opargs(1);
  16.563 +  memcopy(size);
  16.564 +}
  16.565 +
  16.566 +SC_FUNC void fillarray(symbol *sym,cell size,cell value)
  16.567 +{
  16.568 +  ldconst(value,sPRI);  /* load value in PRI */
  16.569 +
  16.570 +  assert(sym!=NULL);
  16.571 +  /* the symbol can be a local array, a global array, or an array
  16.572 +   * that is passed by reference.
  16.573 +   */
  16.574 +  if (sym->ident==iREFARRAY) {
  16.575 +    /* reference to an array; currently this is always a local variable */
  16.576 +    assert(sym->vclass==sLOCAL);        /* symbol must be stack relative */
  16.577 +    stgwrite("\tload.s.alt ");
  16.578 +  } else {
  16.579 +    /* a local or global array */
  16.580 +    if (sym->vclass==sLOCAL)
  16.581 +      stgwrite("\taddr.alt ");
  16.582 +    else
  16.583 +      stgwrite("\tconst.alt ");
  16.584 +  } /* if */
  16.585 +  outval(sym->addr,TRUE);
  16.586 +  markusage(sym,uWRITTEN);
  16.587 +
  16.588 +  assert(size>0);
  16.589 +  stgwrite("\tfill ");
  16.590 +  outval(size,TRUE);
  16.591 +
  16.592 +  code_idx+=opcodes(2)+opargs(2);
  16.593 +}
  16.594 +
  16.595 +/* Instruction to get an immediate value into the primary or the alternate
  16.596 + * register
  16.597 + */
  16.598 +SC_FUNC void ldconst(cell val,regid reg)
  16.599 +{
  16.600 +  assert(reg==sPRI || reg==sALT);
  16.601 +  switch (reg) {
  16.602 +  case sPRI:
  16.603 +    if (val==0) {
  16.604 +      stgwrite("\tzero.pri\n");
  16.605 +      code_idx+=opcodes(1);
  16.606 +    } else {
  16.607 +      stgwrite("\tconst.pri ");
  16.608 +      outval(val, TRUE);
  16.609 +      code_idx+=opcodes(1)+opargs(1);
  16.610 +    } /* if */
  16.611 +    break;
  16.612 +  case sALT:
  16.613 +    if (val==0) {
  16.614 +      stgwrite("\tzero.alt\n");
  16.615 +      code_idx+=opcodes(1);
  16.616 +    } else {
  16.617 +      stgwrite("\tconst.alt ");
  16.618 +      outval(val, TRUE);
  16.619 +      code_idx+=opcodes(1)+opargs(1);
  16.620 +    } /* if */
  16.621 +    break;
  16.622 +  } /* switch */
  16.623 +}
  16.624 +
  16.625 +/* Copy value in alternate register to the primary register */
  16.626 +SC_FUNC void moveto1(void)
  16.627 +{
  16.628 +  stgwrite("\tmove.pri\n");
  16.629 +  code_idx+=opcodes(1)+opargs(0);
  16.630 +}
  16.631 +
  16.632 +/* Push primary or the alternate register onto the stack
  16.633 + */
  16.634 +SC_FUNC void pushreg(regid reg)
  16.635 +{
  16.636 +  assert(reg==sPRI || reg==sALT);
  16.637 +  switch (reg) {
  16.638 +  case sPRI:
  16.639 +    stgwrite("\tpush.pri\n");
  16.640 +    break;
  16.641 +  case sALT:
  16.642 +    stgwrite("\tpush.alt\n");
  16.643 +    break;
  16.644 +  } /* switch */
  16.645 +  code_idx+=opcodes(1);
  16.646 +}
  16.647 +
  16.648 +/*
  16.649 + *  Push a constant value onto the stack
  16.650 + */
  16.651 +SC_FUNC void pushval(cell val)
  16.652 +{
  16.653 +  stgwrite("\tpush.c ");
  16.654 +  outval(val, TRUE);
  16.655 +  code_idx+=opcodes(1)+opargs(1);
  16.656 +}
  16.657 +
  16.658 +/* Pop stack into the primary or the alternate register
  16.659 + */
  16.660 +SC_FUNC void popreg(regid reg)
  16.661 +{
  16.662 +  assert(reg==sPRI || reg==sALT);
  16.663 +  switch (reg) {
  16.664 +  case sPRI:
  16.665 +    stgwrite("\tpop.pri\n");
  16.666 +    break;
  16.667 +  case sALT:
  16.668 +    stgwrite("\tpop.alt\n");
  16.669 +    break;
  16.670 +  } /* switch */
  16.671 +  code_idx+=opcodes(1);
  16.672 +}
  16.673 +
  16.674 +/*
  16.675 + *  swap the top-of-stack with the value in primary register
  16.676 + */
  16.677 +SC_FUNC void swap1(void)
  16.678 +{
  16.679 +  stgwrite("\tswap.pri\n");
  16.680 +  code_idx+=opcodes(1);
  16.681 +}
  16.682 +
  16.683 +/* Switch statements
  16.684 + * The "switch" statement generates a "case" table using the "CASE" opcode.
  16.685 + * The case table contains a list of records, each record holds a comparison
  16.686 + * value and a label to branch to on a match. The very first record is an
  16.687 + * exception: it holds the size of the table (excluding the first record) and
  16.688 + * the label to branch to when none of the values in the case table match.
  16.689 + * The case table is sorted on the comparison value. This allows more advanced
  16.690 + * abstract machines to sift the case table with a binary search.
  16.691 + */
  16.692 +SC_FUNC void ffswitch(int label)
  16.693 +{
  16.694 +  stgwrite("\tswitch ");
  16.695 +  outval(label,TRUE);           /* the label is the address of the case table */
  16.696 +  code_idx+=opcodes(1)+opargs(1);
  16.697 +}
  16.698 +
  16.699 +SC_FUNC void ffcase(cell value,char *labelname,int newtable)
  16.700 +{
  16.701 +  if (newtable) {
  16.702 +    stgwrite("\tcasetbl\n");
  16.703 +    code_idx+=opcodes(1);
  16.704 +  } /* if */
  16.705 +  stgwrite("\tcase ");
  16.706 +  outval(value,FALSE);
  16.707 +  stgwrite(" ");
  16.708 +  stgwrite(labelname);
  16.709 +  stgwrite("\n");
  16.710 +  code_idx+=opcodes(0)+opargs(2);
  16.711 +}
  16.712 +
  16.713 +/*
  16.714 + *  Call specified function
  16.715 + */
  16.716 +SC_FUNC void ffcall(symbol *sym,const char *label,int numargs)
  16.717 +{
  16.718 +  char symname[2*sNAMEMAX+16];
  16.719 +
  16.720 +  assert(sym!=NULL);
  16.721 +  assert(sym->ident==iFUNCTN);
  16.722 +  if (sc_asmfile)
  16.723 +    funcdisplayname(symname,sym->name);
  16.724 +  if ((sym->usage & uNATIVE)!=0) {
  16.725 +    /* reserve a SYSREQ id if called for the first time */
  16.726 +    assert(label==NULL);
  16.727 +    if (sc_status==statWRITE && (sym->usage & uREAD)==0 && sym->addr>=0)
  16.728 +      sym->addr=ntv_funcid++;
  16.729 +    stgwrite("\tsysreq.c ");
  16.730 +    outval(sym->addr,FALSE);
  16.731 +    if (sc_asmfile) {
  16.732 +      stgwrite("\t; ");
  16.733 +      stgwrite(symname);
  16.734 +    } /* if */
  16.735 +    stgwrite("\n"); /* write on a separate line, to mark a sequence point for the peephole optimizer */
  16.736 +    stgwrite("\tstack ");
  16.737 +    outval((numargs+1)*sizeof(cell), TRUE);
  16.738 +    code_idx+=opcodes(2)+opargs(2);
  16.739 +  } else {
  16.740 +    /* normal function */
  16.741 +    stgwrite("\tcall ");
  16.742 +    if (label!=NULL) {
  16.743 +      stgwrite("l.");
  16.744 +      stgwrite(label);
  16.745 +    } else {
  16.746 +      stgwrite(sym->name);
  16.747 +    } /* if */
  16.748 +    if (sc_asmfile
  16.749 +        && (label!=NULL || !isalpha(sym->name[0]) && sym->name[0]!='_'  && sym->name[0]!=sc_ctrlchar))
  16.750 +    {
  16.751 +      stgwrite("\t; ");
  16.752 +      stgwrite(symname);
  16.753 +    } /* if */
  16.754 +    stgwrite("\n");
  16.755 +    code_idx+=opcodes(1)+opargs(1);
  16.756 +  } /* if */
  16.757 +}
  16.758 +
  16.759 +/*  Return from function
  16.760 + *
  16.761 + *  Global references: funcstatus  (referred to only)
  16.762 + */
  16.763 +SC_FUNC void ffret(int remparams)
  16.764 +{
  16.765 +  if (remparams)
  16.766 +    stgwrite("\tretn\n");
  16.767 +  else
  16.768 +    stgwrite("\tret\n");
  16.769 +  code_idx+=opcodes(1);
  16.770 +}
  16.771 +
  16.772 +SC_FUNC void ffabort(int reason)
  16.773 +{
  16.774 +  stgwrite("\thalt ");
  16.775 +  outval(reason,TRUE);
  16.776 +  code_idx+=opcodes(1)+opargs(1);
  16.777 +}
  16.778 +
  16.779 +SC_FUNC void ffbounds(cell size)
  16.780 +{
  16.781 +  if ((sc_debug & sCHKBOUNDS)!=0) {
  16.782 +    stgwrite("\tbounds ");
  16.783 +    outval(size,TRUE);
  16.784 +    code_idx+=opcodes(1)+opargs(1);
  16.785 +  } /* if */
  16.786 +}
  16.787 +
  16.788 +/*
  16.789 + *  Jump to local label number (the number is converted to a name)
  16.790 + */
  16.791 +SC_FUNC void jumplabel(int number)
  16.792 +{
  16.793 +  stgwrite("\tjump ");
  16.794 +  outval(number,TRUE);
  16.795 +  code_idx+=opcodes(1)+opargs(1);
  16.796 +}
  16.797 +
  16.798 +/*
  16.799 + *   Define storage (global and static variables)
  16.800 + */
  16.801 +SC_FUNC void defstorage(void)
  16.802 +{
  16.803 +  stgwrite("dump ");
  16.804 +}
  16.805 +
  16.806 +/*
  16.807 + *  Inclrement/decrement stack pointer. Note that this routine does
  16.808 + *  nothing if the delta is zero.
  16.809 + */
  16.810 +SC_FUNC void modstk(int delta)
  16.811 +{
  16.812 +  if (delta) {
  16.813 +    stgwrite("\tstack ");
  16.814 +    outval(delta, TRUE);
  16.815 +    code_idx+=opcodes(1)+opargs(1);
  16.816 +  } /* if */
  16.817 +}
  16.818 +
  16.819 +/* set the stack to a hard offset from the frame */
  16.820 +SC_FUNC void setstk(cell value)
  16.821 +{
  16.822 +  stgwrite("\tlctrl 5\n");      /* get FRM in PRI */
  16.823 +  assert(value<=0);             /* STK should always become <= FRM */
  16.824 +  if (value<0) {
  16.825 +    stgwrite("\tadd.c ");
  16.826 +    outval(value, TRUE);        /* add (negative) offset */
  16.827 +    code_idx+=opcodes(1)+opargs(1);
  16.828 +    // ??? write zeros in the space between STK and the value in PRI (the new stk)
  16.829 +    //     get value of STK in ALT
  16.830 +    //     zero PRI
  16.831 +    //     need new FILL opcode that takes a variable size
  16.832 +  } /* if */
  16.833 +  stgwrite("\tsctrl 4\n");      /* store in STK */
  16.834 +  code_idx+=opcodes(2)+opargs(2);
  16.835 +}
  16.836 +
  16.837 +SC_FUNC void modheap(int delta)
  16.838 +{
  16.839 +  if (delta) {
  16.840 +    stgwrite("\theap ");
  16.841 +    outval(delta, TRUE);
  16.842 +    code_idx+=opcodes(1)+opargs(1);
  16.843 +  } /* if */
  16.844 +}
  16.845 +
  16.846 +SC_FUNC void setheap_pri(void)
  16.847 +{
  16.848 +  stgwrite("\theap ");          /* ALT = HEA++ */
  16.849 +  outval(sizeof(cell), TRUE);
  16.850 +  stgwrite("\tstor.i\n");       /* store PRI (default value) at address ALT */
  16.851 +  stgwrite("\tmove.pri\n");     /* move ALT to PRI: PRI contains the address */
  16.852 +  code_idx+=opcodes(3)+opargs(1);
  16.853 +}
  16.854 +
  16.855 +SC_FUNC void setheap(cell value)
  16.856 +{
  16.857 +  stgwrite("\tconst.pri ");     /* load default value in PRI */
  16.858 +  outval(value, TRUE);
  16.859 +  code_idx+=opcodes(1)+opargs(1);
  16.860 +  setheap_pri();
  16.861 +}
  16.862 +
  16.863 +/*
  16.864 + *  Convert a cell number to a "byte" address; i.e. double or quadruple
  16.865 + *  the primary register.
  16.866 + */
  16.867 +SC_FUNC void cell2addr(void)
  16.868 +{
  16.869 +  #if PAWN_CELL_SIZE==16
  16.870 +    stgwrite("\tshl.c.pri 1\n");
  16.871 +  #elif PAWN_CELL_SIZE==32
  16.872 +    stgwrite("\tshl.c.pri 2\n");
  16.873 +  #elif PAWN_CELL_SIZE==64
  16.874 +    stgwrite("\tshl.c.pri 3\n");
  16.875 +  #else
  16.876 +    #error Unsupported cell size
  16.877 +  #endif
  16.878 +  code_idx+=opcodes(1)+opargs(1);
  16.879 +}
  16.880 +
  16.881 +/*
  16.882 + *  Double or quadruple the alternate register.
  16.883 + */
  16.884 +SC_FUNC void cell2addr_alt(void)
  16.885 +{
  16.886 +  #if PAWN_CELL_SIZE==16
  16.887 +    stgwrite("\tshl.c.alt 1\n");
  16.888 +  #elif PAWN_CELL_SIZE==32
  16.889 +    stgwrite("\tshl.c.alt 2\n");
  16.890 +  #elif PAWN_CELL_SIZE==64
  16.891 +    stgwrite("\tshl.c.alt 3\n");
  16.892 +  #else
  16.893 +    #error Unsupported cell size
  16.894 +  #endif
  16.895 +  code_idx+=opcodes(1)+opargs(1);
  16.896 +}
  16.897 +
  16.898 +/*
  16.899 + *  Convert "distance of addresses" to "number of cells" in between.
  16.900 + *  Or convert a number of packed characters to the number of cells (with
  16.901 + *  truncation).
  16.902 + */
  16.903 +SC_FUNC void addr2cell(void)
  16.904 +{
  16.905 +  #if PAWN_CELL_SIZE==16
  16.906 +    stgwrite("\tshr.c.pri 1\n");
  16.907 +  #elif PAWN_CELL_SIZE==32
  16.908 +    stgwrite("\tshr.c.pri 2\n");
  16.909 +  #elif PAWN_CELL_SIZE==64
  16.910 +    stgwrite("\tshr.c.pri 3\n");
  16.911 +  #else
  16.912 +    #error Unsupported cell size
  16.913 +  #endif
  16.914 +  code_idx+=opcodes(1)+opargs(1);
  16.915 +}
  16.916 +
  16.917 +/* Convert from character index to byte address. This routine does
  16.918 + * nothing if a character has the size of a byte.
  16.919 + */
  16.920 +SC_FUNC void char2addr(void)
  16.921 +{
  16.922 +  #if sCHARBITS==16
  16.923 +    stgwrite("\tshl.c.pri 1\n");
  16.924 +    code_idx+=opcodes(1)+opargs(1);
  16.925 +  #endif
  16.926 +}
  16.927 +
  16.928 +/* Align PRI (which should hold a character index) to an address.
  16.929 + * The first character in a "pack" occupies the highest bits of
  16.930 + * the cell. This is at the lower memory address on Big Endian
  16.931 + * computers and on the higher address on Little Endian computers.
  16.932 + * The ALIGN.pri/alt instructions must solve this machine dependence;
  16.933 + * that is, on Big Endian computers, ALIGN.pri/alt shuold do nothing
  16.934 + * and on Little Endian computers they should toggle the address.
  16.935 + */
  16.936 +SC_FUNC void charalign(void)
  16.937 +{
  16.938 +  stgwrite("\talign.pri ");
  16.939 +  outval(sCHARBITS/8,TRUE);
  16.940 +  code_idx+=opcodes(1)+opargs(1);
  16.941 +}
  16.942 +
  16.943 +/*
  16.944 + *  Add a constant to the primary register.
  16.945 + */
  16.946 +SC_FUNC void addconst(cell value)
  16.947 +{
  16.948 +  if (value!=0) {
  16.949 +    stgwrite("\tadd.c ");
  16.950 +    outval(value,TRUE);
  16.951 +    code_idx+=opcodes(1)+opargs(1);
  16.952 +  } /* if */
  16.953 +}
  16.954 +
  16.955 +/*
  16.956 + *  signed multiply of primary and secundairy registers (result in primary)
  16.957 + */
  16.958 +SC_FUNC void os_mult(void)
  16.959 +{
  16.960 +  stgwrite("\tsmul\n");
  16.961 +  code_idx+=opcodes(1);
  16.962 +}
  16.963 +
  16.964 +/*
  16.965 + *  signed divide of alternate register by primary register (quotient in
  16.966 + *  primary; remainder in alternate)
  16.967 + */
  16.968 +SC_FUNC void os_div(void)
  16.969 +{
  16.970 +  stgwrite("\tsdiv.alt\n");
  16.971 +  code_idx+=opcodes(1);
  16.972 +}
  16.973 +
  16.974 +/*
  16.975 + *  modulus of (alternate % primary), result in primary (signed)
  16.976 + */
  16.977 +SC_FUNC void os_mod(void)
  16.978 +{
  16.979 +  stgwrite("\tsdiv.alt\n");
  16.980 +  stgwrite("\tmove.pri\n");     /* move ALT to PRI */
  16.981 +  code_idx+=opcodes(2);
  16.982 +}
  16.983 +
  16.984 +/*
  16.985 + *  Add primary and alternate registers (result in primary).
  16.986 + */
  16.987 +SC_FUNC void ob_add(void)
  16.988 +{
  16.989 +  stgwrite("\tadd\n");
  16.990 +  code_idx+=opcodes(1);
  16.991 +}
  16.992 +
  16.993 +/*
  16.994 + *  subtract primary register from alternate register (result in primary)
  16.995 + */
  16.996 +SC_FUNC void ob_sub(void)
  16.997 +{
  16.998 +  stgwrite("\tsub.alt\n");
  16.999 +  code_idx+=opcodes(1);
 16.1000 +}
 16.1001 +
 16.1002 +/*
 16.1003 + *  arithmic shift left alternate register the number of bits
 16.1004 + *  given in the primary register (result in primary).
 16.1005 + *  There is no need for a "logical shift left" routine, since
 16.1006 + *  logical shift left is identical to arithmic shift left.
 16.1007 + */
 16.1008 +SC_FUNC void ob_sal(void)
 16.1009 +{
 16.1010 +  stgwrite("\txchg\n");
 16.1011 +  stgwrite("\tshl\n");
 16.1012 +  code_idx+=opcodes(2);
 16.1013 +}
 16.1014 +
 16.1015 +/*
 16.1016 + *  arithmic shift right alternate register the number of bits
 16.1017 + *  given in the primary register (result in primary).
 16.1018 + */
 16.1019 +SC_FUNC void os_sar(void)
 16.1020 +{
 16.1021 +  stgwrite("\txchg\n");
 16.1022 +  stgwrite("\tsshr\n");
 16.1023 +  code_idx+=opcodes(2);
 16.1024 +}
 16.1025 +
 16.1026 +/*
 16.1027 + *  logical (unsigned) shift right of the alternate register by the
 16.1028 + *  number of bits given in the primary register (result in primary).
 16.1029 + */
 16.1030 +SC_FUNC void ou_sar(void)
 16.1031 +{
 16.1032 +  stgwrite("\txchg\n");
 16.1033 +  stgwrite("\tshr\n");
 16.1034 +  code_idx+=opcodes(2);
 16.1035 +}
 16.1036 +
 16.1037 +/*
 16.1038 + *  inclusive "or" of primary and alternate registers (result in primary)
 16.1039 + */
 16.1040 +SC_FUNC void ob_or(void)
 16.1041 +{
 16.1042 +  stgwrite("\tor\n");
 16.1043 +  code_idx+=opcodes(1);
 16.1044 +}
 16.1045 +
 16.1046 +/*
 16.1047 + *  "exclusive or" of primary and alternate registers (result in primary)
 16.1048 + */
 16.1049 +SC_FUNC void ob_xor(void)
 16.1050 +{
 16.1051 +  stgwrite("\txor\n");
 16.1052 +  code_idx+=opcodes(1);
 16.1053 +}
 16.1054 +
 16.1055 +/*
 16.1056 + *  "and" of primary and secundairy registers (result in primary)
 16.1057 + */
 16.1058 +SC_FUNC void ob_and(void)
 16.1059 +{
 16.1060 +  stgwrite("\tand\n");
 16.1061 +  code_idx+=opcodes(1);
 16.1062 +}
 16.1063 +
 16.1064 +/*
 16.1065 + *  test ALT==PRI; result in primary register (1 or 0).
 16.1066 + */
 16.1067 +SC_FUNC void ob_eq(void)
 16.1068 +{
 16.1069 +  stgwrite("\teq\n");
 16.1070 +  code_idx+=opcodes(1);
 16.1071 +}
 16.1072 +
 16.1073 +/*
 16.1074 + *  test ALT!=PRI
 16.1075 + */
 16.1076 +SC_FUNC void ob_ne(void)
 16.1077 +{
 16.1078 +  stgwrite("\tneq\n");
 16.1079 +  code_idx+=opcodes(1);
 16.1080 +}
 16.1081 +
 16.1082 +/* The abstract machine defines the relational instructions so that PRI is
 16.1083 + * on the left side and ALT on the right side of the operator. For example,
 16.1084 + * SLESS sets PRI to either 1 or 0 depending on whether the expression
 16.1085 + * "PRI < ALT" is true.
 16.1086 + *
 16.1087 + * The compiler generates comparisons with ALT on the left side of the
 16.1088 + * relational operator and PRI on the right side. The XCHG instruction
 16.1089 + * prefixing the relational operators resets this. We leave it to the
 16.1090 + * peephole optimizer to choose more compact instructions where possible.
 16.1091 + */
 16.1092 +
 16.1093 +/* Relational operator prefix for chained relational expressions. The
 16.1094 + * "suffix" code restores the stack.
 16.1095 + * For chained relational operators, the goal is to keep the comparison
 16.1096 + * result "so far" in PRI and the value of the most recent operand in
 16.1097 + * ALT, ready for a next comparison.
 16.1098 + * The "prefix" instruction pushed the comparison result (PRI) onto the
 16.1099 + * stack and moves the value of ALT into PRI. If there is a next comparison,
 16.1100 + * PRI can now serve as the "left" operand of the relational operator.
 16.1101 + */
 16.1102 +SC_FUNC void relop_prefix(void)
 16.1103 +{
 16.1104 +  stgwrite("\tpush.pri\n");
 16.1105 +  stgwrite("\tmove.pri\n");
 16.1106 +  code_idx+=opcodes(2);
 16.1107 +}
 16.1108 +
 16.1109 +SC_FUNC void relop_suffix(void)
 16.1110 +{
 16.1111 +  stgwrite("\tswap.alt\n");
 16.1112 +  stgwrite("\tand\n");
 16.1113 +  stgwrite("\tpop.alt\n");
 16.1114 +  code_idx+=opcodes(3);
 16.1115 +}
 16.1116 +
 16.1117 +/*
 16.1118 + *  test ALT<PRI (signed)
 16.1119 + */
 16.1120 +SC_FUNC void os_lt(void)
 16.1121 +{
 16.1122 +  stgwrite("\txchg\n");
 16.1123 +  stgwrite("\tsless\n");
 16.1124 +  code_idx+=opcodes(2);
 16.1125 +}
 16.1126 +
 16.1127 +/*
 16.1128 + *  test ALT<=PRI (signed)
 16.1129 + */
 16.1130 +SC_FUNC void os_le(void)
 16.1131 +{
 16.1132 +  stgwrite("\txchg\n");
 16.1133 +  stgwrite("\tsleq\n");
 16.1134 +  code_idx+=opcodes(2);
 16.1135 +}
 16.1136 +
 16.1137 +/*
 16.1138 + *  test ALT>PRI (signed)
 16.1139 + */
 16.1140 +SC_FUNC void os_gt(void)
 16.1141 +{
 16.1142 +  stgwrite("\txchg\n");
 16.1143 +  stgwrite("\tsgrtr\n");
 16.1144 +  code_idx+=opcodes(2);
 16.1145 +}
 16.1146 +
 16.1147 +/*
 16.1148 + *  test ALT>=PRI (signed)
 16.1149 + */
 16.1150 +SC_FUNC void os_ge(void)
 16.1151 +{
 16.1152 +  stgwrite("\txchg\n");
 16.1153 +  stgwrite("\tsgeq\n");
 16.1154 +  code_idx+=opcodes(2);
 16.1155 +}
 16.1156 +
 16.1157 +/*
 16.1158 + *  logical negation of primary register
 16.1159 + */
 16.1160 +SC_FUNC void lneg(void)
 16.1161 +{
 16.1162 +  stgwrite("\tnot\n");
 16.1163 +  code_idx+=opcodes(1);
 16.1164 +}
 16.1165 +
 16.1166 +/*
 16.1167 + *  two's complement primary register
 16.1168 + */
 16.1169 +SC_FUNC void neg(void)
 16.1170 +{
 16.1171 +  stgwrite("\tneg\n");
 16.1172 +  code_idx+=opcodes(1);
 16.1173 +}
 16.1174 +
 16.1175 +/*
 16.1176 + *  one's complement of primary register
 16.1177 + */
 16.1178 +SC_FUNC void invert(void)
 16.1179 +{
 16.1180 +  stgwrite("\tinvert\n");
 16.1181 +  code_idx+=opcodes(1);
 16.1182 +}
 16.1183 +
 16.1184 +/*
 16.1185 + *  nop
 16.1186 + */
 16.1187 +SC_FUNC void nooperation(void)
 16.1188 +{
 16.1189 +  stgwrite("\tnop\n");
 16.1190 +  code_idx+=opcodes(1);
 16.1191 +}
 16.1192 +
 16.1193 +
 16.1194 +/*  increment symbol
 16.1195 + */
 16.1196 +SC_FUNC void inc(value *lval)
 16.1197 +{
 16.1198 +  symbol *sym;
 16.1199 +
 16.1200 +  sym=lval->sym;
 16.1201 +  if (lval->ident==iARRAYCELL) {
 16.1202 +    /* indirect increment, address already in PRI */
 16.1203 +    stgwrite("\tinc.i\n");
 16.1204 +    code_idx+=opcodes(1);
 16.1205 +  } else if (lval->ident==iARRAYCHAR) {
 16.1206 +    /* indirect increment of single character, address already in PRI */
 16.1207 +    stgwrite("\tpush.pri\n");
 16.1208 +    stgwrite("\tpush.alt\n");
 16.1209 +    stgwrite("\tmove.alt\n");   /* copy address */
 16.1210 +    stgwrite("\tlodb.i ");      /* read from PRI into PRI */
 16.1211 +    outval(sCHARBITS/8,TRUE);   /* read one or two bytes */
 16.1212 +    stgwrite("\tinc.pri\n");
 16.1213 +    stgwrite("\tstrb.i ");      /* write PRI to ALT */
 16.1214 +    outval(sCHARBITS/8,TRUE);   /* write one or two bytes */
 16.1215 +    stgwrite("\tpop.alt\n");
 16.1216 +    stgwrite("\tpop.pri\n");
 16.1217 +    code_idx+=opcodes(8)+opargs(2);
 16.1218 +  } else if (lval->ident==iREFERENCE) {
 16.1219 +    assert(sym!=NULL);
 16.1220 +    stgwrite("\tpush.pri\n");
 16.1221 +    /* load dereferenced value */
 16.1222 +    assert(sym->vclass==sLOCAL);    /* global references don't exist in Pawn */
 16.1223 +    if (sym->vclass==sLOCAL)
 16.1224 +      stgwrite("\tlref.s.pri ");
 16.1225 +    else
 16.1226 +      stgwrite("\tlref.pri ");
 16.1227 +    outval(sym->addr,TRUE);
 16.1228 +    /* increment */
 16.1229 +    stgwrite("\tinc.pri\n");
 16.1230 +    /* store dereferenced value */
 16.1231 +    if (sym->vclass==sLOCAL)
 16.1232 +      stgwrite("\tsref.s.pri ");
 16.1233 +    else
 16.1234 +      stgwrite("\tsref.pri ");
 16.1235 +    outval(sym->addr,TRUE);
 16.1236 +    stgwrite("\tpop.pri\n");
 16.1237 +    code_idx+=opcodes(5)+opargs(2);
 16.1238 +  } else {
 16.1239 +    /* local or global variable */
 16.1240 +    assert(sym!=NULL);
 16.1241 +    if (sym->vclass==sLOCAL)
 16.1242 +      stgwrite("\tinc.s ");
 16.1243 +    else
 16.1244 +      stgwrite("\tinc ");
 16.1245 +    outval(sym->addr,TRUE);
 16.1246 +    code_idx+=opcodes(1)+opargs(1);
 16.1247 +  } /* if */
 16.1248 +}
 16.1249 +
 16.1250 +/*  decrement symbol
 16.1251 + *
 16.1252 + *  in case of an integer pointer, the symbol must be incremented by 2.
 16.1253 + */
 16.1254 +SC_FUNC void dec(value *lval)
 16.1255 +{
 16.1256 +  symbol *sym;
 16.1257 +
 16.1258 +  sym=lval->sym;
 16.1259 +  if (lval->ident==iARRAYCELL) {
 16.1260 +    /* indirect decrement, address already in PRI */
 16.1261 +    stgwrite("\tdec.i\n");
 16.1262 +    code_idx+=opcodes(1);
 16.1263 +  } else if (lval->ident==iARRAYCHAR) {
 16.1264 +    /* indirect decrement of single character, address already in PRI */
 16.1265 +    stgwrite("\tpush.pri\n");
 16.1266 +    stgwrite("\tpush.alt\n");
 16.1267 +    stgwrite("\tmove.alt\n");   /* copy address */
 16.1268 +    stgwrite("\tlodb.i ");      /* read from PRI into PRI */
 16.1269 +    outval(sCHARBITS/8,TRUE);   /* read one or two bytes */
 16.1270 +    stgwrite("\tdec.pri\n");
 16.1271 +    stgwrite("\tstrb.i ");      /* write PRI to ALT */
 16.1272 +    outval(sCHARBITS/8,TRUE);   /* write one or two bytes */
 16.1273 +    stgwrite("\tpop.alt\n");
 16.1274 +    stgwrite("\tpop.pri\n");
 16.1275 +    code_idx+=opcodes(8)+opargs(2);
 16.1276 +  } else if (lval->ident==iREFERENCE) {
 16.1277 +    assert(sym!=NULL);
 16.1278 +    stgwrite("\tpush.pri\n");
 16.1279 +    /* load dereferenced value */
 16.1280 +    assert(sym->vclass==sLOCAL);    /* global references don't exist in Pawn */
 16.1281 +    if (sym->vclass==sLOCAL)
 16.1282 +      stgwrite("\tlref.s.pri ");
 16.1283 +    else
 16.1284 +      stgwrite("\tlref.pri ");
 16.1285 +    outval(sym->addr,TRUE);
 16.1286 +    /* decrement */
 16.1287 +    stgwrite("\tdec.pri\n");
 16.1288 +    /* store dereferenced value */
 16.1289 +    if (sym->vclass==sLOCAL)
 16.1290 +      stgwrite("\tsref.s.pri ");
 16.1291 +    else
 16.1292 +      stgwrite("\tsref.pri ");
 16.1293 +    outval(sym->addr,TRUE);
 16.1294 +    stgwrite("\tpop.pri\n");
 16.1295 +    code_idx+=opcodes(5)+opargs(2);
 16.1296 +  } else {
 16.1297 +    /* local or global variable */
 16.1298 +    assert(sym!=NULL);
 16.1299 +    if (sym->vclass==sLOCAL)
 16.1300 +      stgwrite("\tdec.s ");
 16.1301 +    else
 16.1302 +      stgwrite("\tdec ");
 16.1303 +    outval(sym->addr,TRUE);
 16.1304 +    code_idx+=opcodes(1)+opargs(1);
 16.1305 +  } /* if */
 16.1306 +}
 16.1307 +
 16.1308 +/*
 16.1309 + *  Jumps to "label" if PRI != 0
 16.1310 + */
 16.1311 +SC_FUNC void jmp_ne0(int number)
 16.1312 +{
 16.1313 +  stgwrite("\tjnz ");
 16.1314 +  outval(number,TRUE);
 16.1315 +  code_idx+=opcodes(1)+opargs(1);
 16.1316 +}
 16.1317 +
 16.1318 +/*
 16.1319 + *  Jumps to "label" if PRI == 0
 16.1320 + */
 16.1321 +SC_FUNC void jmp_eq0(int number)
 16.1322 +{
 16.1323 +  stgwrite("\tjzer ");
 16.1324 +  outval(number,TRUE);
 16.1325 +  code_idx+=opcodes(1)+opargs(1);
 16.1326 +}
 16.1327 +
 16.1328 +/* write a value in hexadecimal; optionally adds a newline */
 16.1329 +SC_FUNC void outval(cell val,int newline)
 16.1330 +{
 16.1331 +  stgwrite(itoh(val));
 16.1332 +  if (newline)
 16.1333 +    stgwrite("\n");
 16.1334 +}
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/compiler-init/compiler-init/sc5.c	Fri Jul 14 02:02:18 2006 +0000
    17.3 @@ -0,0 +1,228 @@
    17.4 +/*  Pawn compiler - Error message system
    17.5 + *  In fact a very simple system, using only 'panic mode'.
    17.6 + *
    17.7 + *  Copyright (c) ITB CompuPhase, 1997-2006
    17.8 + *
    17.9 + *  This software is provided "as-is", without any express or implied warranty.
   17.10 + *  In no event will the authors be held liable for any damages arising from
   17.11 + *  the use of this software.
   17.12 + *
   17.13 + *  Permission is granted to anyone to use this software for any purpose,
   17.14 + *  including commercial applications, and to alter it and redistribute it
   17.15 + *  freely, subject to the following restrictions:
   17.16 + *
   17.17 + *  1.  The origin of this software must not be misrepresented; you must not
   17.18 + *      claim that you wrote the original software. If you use this software in
   17.19 + *      a product, an acknowledgment in the product documentation would be
   17.20 + *      appreciated but is not required.
   17.21 + *  2.  Altered source versions must be plainly marked as such, and must not be
   17.22 + *      misrepresented as being the original software.
   17.23 + *  3.  This notice may not be removed or altered from any source distribution.
   17.24 + *
   17.25 + *  Version: $Id: sc5.c 3579 2006-06-06 13:35:29Z thiadmer $
   17.26 + */
   17.27 +#include <assert.h>
   17.28 +#if defined	__WIN32__ || defined _WIN32 || defined __MSDOS__
   17.29 +  #include <io.h>
   17.30 +#endif
   17.31 +#if defined LINUX || defined __GNUC__
   17.32 +  #include <unistd.h>
   17.33 +#endif
   17.34 +#include <stdio.h>
   17.35 +#include <stdlib.h>
   17.36 +#include <stdarg.h>     /* ANSI standardized variable argument list functions */
   17.37 +#include <string.h>
   17.38 +#if defined FORTIFY
   17.39 +  #include <alloc/fortify.h>
   17.40 +#endif
   17.41 +#include "sc.h"
   17.42 +
   17.43 +#if defined _MSC_VER
   17.44 +  #pragma warning(push)
   17.45 +  #pragma warning(disable:4125)  /* decimal digit terminates octal escape sequence */
   17.46 +#endif
   17.47 +
   17.48 +#include "sc5.scp"
   17.49 +
   17.50 +#if defined _MSC_VER
   17.51 +  #pragma warning(pop)
   17.52 +#endif
   17.53 +
   17.54 +#define NUM_WARNINGS    (sizeof warnmsg / sizeof warnmsg[0])
   17.55 +static unsigned char warndisable[(NUM_WARNINGS + 7) / 8]; /* 8 flags in a char */
   17.56 +
   17.57 +static int errflag;
   17.58 +static int errstart;    /* line number at which the instruction started */
   17.59 +static int errline;     /* forced line number for the error message */
   17.60 +
   17.61 +/*  error
   17.62 + *
   17.63 + *  Outputs an error message (note: msg is passed optionally).
   17.64 + *  If an error is found, the variable "errflag" is set and subsequent
   17.65 + *  errors are ignored until lex() finds a semicolumn or a keyword
   17.66 + *  (lex() resets "errflag" in that case).
   17.67 + *
   17.68 + *  Global references: inpfname   (reffered to only)
   17.69 + *                     fline      (reffered to only)
   17.70 + *                     fcurrent   (reffered to only)
   17.71 + *                     errflag    (altered)
   17.72 + */
   17.73 +SC_FUNC int error(int number,...)
   17.74 +{
   17.75 +static char *prefix[3]={ "error", "fatal error", "warning" };
   17.76 +static int lastline,errorcount;
   17.77 +static short lastfile;
   17.78 +  char *msg,*pre;
   17.79 +  va_list argptr;
   17.80 +  char string[128];
   17.81 +
   17.82 +  /* errflag is reset on each semicolon.
   17.83 +   * In a two-pass compiler, an error should not be reported twice. Therefore
   17.84 +   * the error reporting is enabled only in the second pass (and only when
   17.85 +   * actually producing output). Fatal errors may never be ignored.
   17.86 +   */
   17.87 +  if ((errflag || sc_status!=statWRITE) && (number<100 || number>=200))
   17.88 +    return 0;
   17.89 +
   17.90 +  /* also check for disabled warnings */
   17.91 +  if (number>=200) {
   17.92 +    int index=(number-200)/8;
   17.93 +    int mask=1 << ((number-200)%8);
   17.94 +    if ((warndisable[index] & mask)!=0)
   17.95 +      return 0;
   17.96 +  } /* if */
   17.97 +
   17.98 +  if (number<100){
   17.99 +    msg=errmsg[number-1];
  17.100 +    pre=prefix[0];
  17.101 +    errflag=TRUE;       /* set errflag (skip rest of erroneous expression) */
  17.102 +    errnum++;
  17.103 +  } else if (number<200){
  17.104 +    msg=fatalmsg[number-100];
  17.105 +    pre=prefix[1];
  17.106 +    errnum++;           /* a fatal error also counts as an error */
  17.107 +  } else {
  17.108 +    msg=warnmsg[number-200];
  17.109 +    pre=prefix[2];
  17.110 +    warnnum++;
  17.111 +  } /* if */
  17.112 +
  17.113 +  strexpand(string,(unsigned char *)msg,sizeof string,SCPACK_TABLE);
  17.114 +
  17.115 +  assert(errstart<=fline);
  17.116 +  if (errline>0)
  17.117 +    errstart=errline;
  17.118 +  else
  17.119 +    errline=fline;
  17.120 +  assert(errstart<=errline);
  17.121 +  va_start(argptr,number);
  17.122 +  if (strlen(errfname)==0) {
  17.123 +    int start= (errstart==errline) ? -1 : errstart;
  17.124 +    if (pc_error(number,string,inpfname,start,errline,argptr)) {
  17.125 +      if (outf!=NULL) {
  17.126 +        pc_closeasm(outf,TRUE);
  17.127 +        outf=NULL;
  17.128 +      } /* if */
  17.129 +      longjmp(errbuf,3);        /* user abort */
  17.130 +    } /* if */
  17.131 +  } else {
  17.132 +    FILE *fp=fopen(errfname,"a");
  17.133 +    if (fp!=NULL) {
  17.134 +      if (errstart>=0 && errstart!=errline)
  17.135 +        fprintf(fp,"%s(%d -- %d) : %s %03d: ",inpfname,errstart,errline,pre,number);
  17.136 +      else
  17.137 +        fprintf(fp,"%s(%d) : %s %03d: ",inpfname,errline,pre,number);
  17.138 +      vfprintf(fp,string,argptr);
  17.139 +      fclose(fp);
  17.140 +    } /* if */
  17.141 +  } /* if */
  17.142 +  va_end(argptr);
  17.143 +
  17.144 +  if (number>=100 && number<200 || errnum>25){
  17.145 +    if (strlen(errfname)==0) {
  17.146 +      va_start(argptr,number);
  17.147 +      pc_error(0,"\nCompilation aborted.",NULL,0,0,argptr);
  17.148 +      va_end(argptr);
  17.149 +    } /* if */
  17.150 +    if (outf!=NULL) {
  17.151 +      pc_closeasm(outf,TRUE);
  17.152 +      outf=NULL;
  17.153 +    } /* if */
  17.154 +    longjmp(errbuf,2);          /* fatal error, quit */
  17.155 +  } /* if */
  17.156 +
  17.157 +  errline=-1;
  17.158 +  /* check whether we are seeing many errors on the same line */
  17.159 +  if ((errstart<0 && lastline!=fline) || lastline<errstart || lastline>fline || fcurrent!=lastfile)
  17.160 +    errorcount=0;
  17.161 +  lastline=fline;
  17.162 +  lastfile=fcurrent;
  17.163 +  if (number<200)
  17.164 +    errorcount++;
  17.165 +  if (errorcount>=3)
  17.166 +    error(107);         /* too many error/warning messages on one line */
  17.167 +
  17.168 +  return 0;
  17.169 +}
  17.170 +
  17.171 +SC_FUNC void errorset(int code,int line)
  17.172 +{
  17.173 +  switch (code) {
  17.174 +  case sRESET:
  17.175 +    errflag=FALSE;      /* start reporting errors */
  17.176 +    break;
  17.177 +  case sFORCESET:
  17.178 +    errflag=TRUE;       /* stop reporting errors */
  17.179 +    break;
  17.180 +  case sEXPRMARK:
  17.181 +    errstart=fline;     /* save start line number */
  17.182 +    break;
  17.183 +  case sEXPRRELEASE:
  17.184 +    errstart=-1;        /* forget start line number */
  17.185 +    errline=-1;
  17.186 +    break;
  17.187 +  case sSETPOS:
  17.188 +    errline=line;
  17.189 +    break;
  17.190 +  } /* switch */
  17.191 +}
  17.192 +
  17.193 +/* sc_enablewarning()
  17.194 + * Enables or disables a warning (errors cannot be disabled).
  17.195 + * Initially all warnings are enabled. The compiler does this by setting bits
  17.196 + * for the *disabled* warnings and relying on the array to be zero-initialized.
  17.197 + *
  17.198 + * Parameter enable can be:
  17.199 + *  o  0 for disable
  17.200 + *  o  1 for enable
  17.201 + *  o  2 for toggle
  17.202 + */
  17.203 +int pc_enablewarning(int number,int enable)
  17.204 +{
  17.205 +  int index;
  17.206 +  unsigned char mask;
  17.207 +
  17.208 +  if (number<200)
  17.209 +    return FALSE;       /* errors and fatal errors cannot be disabled */
  17.210 +  number -= 200;
  17.211 +  if (number>=NUM_WARNINGS)
  17.212 +    return FALSE;
  17.213 +
  17.214 +  index=number/8;
  17.215 +  mask=(unsigned char)(1 << (number%8));
  17.216 +  switch (enable) {
  17.217 +  case 0:
  17.218 +    warndisable[index] |= mask;
  17.219 +    break;
  17.220 +  case 1:
  17.221 +    warndisable[index] &= (unsigned char)~mask;
  17.222 +    break;
  17.223 +  case 2:
  17.224 +    warndisable[index] ^= mask;
  17.225 +    break;
  17.226 +  } /* switch */
  17.227 +
  17.228 +  return TRUE;
  17.229 +}
  17.230 +
  17.231 +#undef SCPACK_TABLE
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/compiler-init/compiler-init/sc5.scp	Fri Jul 14 02:02:18 2006 +0000
    18.3 @@ -0,0 +1,342 @@
    18.4 +/*  Pawn compiler - Error message strings (plain and compressed formats)
    18.5 + *
    18.6 + *  Copyright (c) ITB CompuPhase, 2000-2006
    18.7 + *
    18.8 + *  This software is provided "as-is", without any express or implied warranty.
    18.9 + *  In no event will the authors be held liable for any damages arising from
   18.10 + *  the use of this software.
   18.11 + *
   18.12 + *  Permission is granted to anyone to use this software for any purpose,
   18.13 + *  including commercial applications, and to alter it and redistribute it
   18.14 + *  freely, subject to the following restrictions:
   18.15 + *
   18.16 + *  1.  The origin of this software must not be misrepresented; you must not
   18.17 + *      claim that you wrote the original software. If you use this software in
   18.18 + *      a product, an acknowledgment in the product documentation would be
   18.19 + *      appreciated but is not required.
   18.20 + *  2.  Altered source versions must be plainly marked as such, and must not be
   18.21 + *      misrepresented as being the original software.
   18.22 + *  3.  This notice may not be removed or altered from any source distribution.
   18.23 + *
   18.24 + *  Version: $Id: sc5.sch 3590 2006-06-24 14:16:39Z thiadmer $
   18.25 + */
   18.26 +
   18.27 +SC_FUNC int strexpand(char *dest, unsigned char *source, int maxlen, unsigned char pairtable[128][2]);
   18.28 +
   18.29 +#define SCPACK_TABLE errstr_table
   18.30 +/*-*SCPACK start of pair table, do not change or remove this line */
   18.31 +unsigned char errstr_table[][2] = {
   18.32 +  {101,32}, {111,110}, {116,32}, {105,110}, {97,114}, {116,105}, {100,32}, {115,32}, {101,114}, {97,108}, {101,110}, {37,115}, {133,129}, {34,139}, {141,34}, {117,110},
   18.33 +  {110,111}, {114,101}, {115,105}, {121,32}, {97,116}, {111,114}, {97,110}, {32,142}, {109,98}, {115,116}, {41,10}, {100,101}, {109,138}, {101,134}, {98,108}, {140,32},
   18.34 +  {111,108}, {114,97}, {144,130}, {118,137}, {143,99}, {102,164}, {115,121}, {166,152}, {167,160}, {117,115}, {97,32}, {115,146}, {97,158}, {149,32}, {132,161}, {105,134},
   18.35 +  {103,32}, {163,175}, {103,117}, {178,156}, {136,32}, {132,179}, {131,177}, {111,102}, {116,104}, {101,120}, {105,135}, {165,159}, {101,100}, {99,104}, {118,132}, {168,151},
   18.36 +  {105,172}, {190,192}, {155,102}, {174,147}, {183,32}, {109,97}, {116,111}, {99,129}, {101,135}, {181,130}, {98,128}, {115,10}, {112,145}, {153,148}, {44,32}, {40,191},
   18.37 +  {169,130}, {151,10}, {101,10}, {207,154}, {109,208}, {116,97}, {105,99}, {194,131}, {193,128}, {34,32}, {129,32}, {132,97}, {100,105}, {146,122}, {110,32}, {137,32},
   18.38 +  {104,97}, {101,108}, {117,108}, {99,111}, {108,111}, {109,148}, {199,153}, {58,209}, {111,112}, {97,115}, {108,128}, {232,136}, {230,150}, {150,32}, {204,171}, {131,176},
   18.39 +  {212,202}, {102,105}, {119,105}, {185,238}, {109,112}, {116,136}, {165,140}, {197,147}, {102,149}, {111,32}, {131,32}, {213,176}, {110,117}, {115,117}, {118,128}
   18.40 +};
   18.41 +/*-*SCPACK end of pair table, do not change or remove this line */
   18.42 +
   18.43 +static char *errmsg[] = {
   18.44 +#ifdef SCPACK
   18.45 +/*001*/  "expected token: \"%s\", but found \"%s\"\n",
   18.46 +/*002*/  "only a single statement (or expression) can follow each \"case\"\n",
   18.47 +/*003*/  "declaration of a local variable must appear in a compound block\n",
   18.48 +/*004*/  "function \"%s\" is not implemented\n",
   18.49 +/*005*/  "function may not have arguments\n",
   18.50 +/*006*/  "must be assigned to an array\n",
   18.51 +/*007*/  "operator cannot be redefined\n",
   18.52 +/*008*/  "must be a constant expression; assumed zero\n",
   18.53 +/*009*/  "invalid array size (negative, zero or out of bounds)\n",
   18.54 +/*010*/  "invalid function or declaration\n",
   18.55 +/*011*/  "invalid outside functions\n",
   18.56 +/*012*/  "invalid function call, not a valid address\n",
   18.57 +/*013*/  "no entry point (no public functions)\n",
   18.58 +/*014*/  "invalid statement; not in switch\n",
   18.59 +/*015*/  "\"default\" case must be the last case in switch statement\n",
   18.60 +/*016*/  "multiple defaults in \"switch\"\n",
   18.61 +/*017*/  "undefined symbol \"%s\"\n",
   18.62 +/*018*/  "initialization data exceeds declared size\n",
   18.63 +/*019*/  "not a label: \"%s\"\n",
   18.64 +/*020*/  "invalid symbol name \"%s\"\n",
   18.65 +/*021*/  "symbol already defined: \"%s\"\n",
   18.66 +/*022*/  "must be lvalue (non-constant)\n",
   18.67 +/*023*/  "array assignment must be simple assignment\n",
   18.68 +/*024*/  "\"break\" or \"continue\" is out of context\n",
   18.69 +/*025*/  "function heading differs from prototype\n",
   18.70 +/*026*/  "no matching \"#if...\"\n",
   18.71 +/*027*/  "invalid character constant\n",
   18.72 +/*028*/  "invalid subscript (not an array or too many subscripts): \"%s\"\n",
   18.73 +/*029*/  "invalid expression, assumed zero\n",
   18.74 +/*030*/  "compound statement not closed at the end of file (started at line %d)\n",
   18.75 +/*031*/  "unknown directive\n",
   18.76 +/*032*/  "array index out of bounds (variable \"%s\")\n",
   18.77 +/*033*/  "array must be indexed (variable \"%s\")\n",
   18.78 +/*034*/  "argument does not have a default value (argument %d)\n",
   18.79 +/*035*/  "argument type mismatch (argument %d)\n",
   18.80 +/*036*/  "empty statement\n",
   18.81 +/*037*/  "invalid string (possibly non-terminated string)\n",
   18.82 +/*038*/  "extra characters on line\n",
   18.83 +/*039*/  "constant symbol has no size\n",
   18.84 +/*040*/  "duplicate \"case\" label (value %d)\n",
   18.85 +/*041*/  "invalid ellipsis, array size is not known\n",
   18.86 +/*042*/  "invalid combination of class specifiers\n",
   18.87 +/*043*/  "character constant exceeds range for packed string\n",
   18.88 +/*044*/  "positional parameters must precede all named parameters\n",
   18.89 +/*045*/  "too many function arguments\n",
   18.90 +/*046*/  "unknown array size (variable \"%s\")\n",
   18.91 +/*047*/  "array sizes do not match, or destination array is too small\n",
   18.92 +/*048*/  "array dimensions do not match\n",
   18.93 +/*049*/  "invalid line continuation\n",
   18.94 +/*050*/  "invalid range\n",
   18.95 +/*051*/  "invalid subscript, use \"[ ]\" operators on major dimensions\n",
   18.96 +/*052*/  "multi-dimensional arrays must be fully initialized\n",
   18.97 +/*053*/  "exceeding maximum number of dimensions\n",
   18.98 +/*054*/  "unmatched closing brace (\"}\")\n",
   18.99 +/*055*/  "start of function body without function header\n",
  18.100 +/*056*/  "arrays, local variables and function arguments cannot be public (variable \"%s\")\n",
  18.101 +/*057*/  "unfinished expression before compiler directive\n",
  18.102 +/*058*/  "duplicate argument; same argument is passed twice\n",
  18.103 +/*059*/  "function argument may not have a default value (variable \"%s\")\n",
  18.104 +/*060*/  "multiple \"#else\" directives between \"#if ... #endif\"\n",
  18.105 +/*061*/  "\"#elseif\" directive follows an \"#else\" directive\n",
  18.106 +/*062*/  "number of operands does not fit the operator\n",
  18.107 +/*063*/  "function result tag of operator \"%s\" must be \"%s\"\n",
  18.108 +/*064*/  "cannot change predefined operators\n",
  18.109 +/*065*/  "function argument may only have a single tag (argument %d)\n",
  18.110 +/*066*/  "function argument may not be a reference argument or an array (argument \"%s\")\n",
  18.111 +/*067*/  "variable cannot be both a reference and an array (variable \"%s\")\n",
  18.112 +/*068*/  "invalid rational number precision in #pragma\n",
  18.113 +/*069*/  "rational number format already defined\n",
  18.114 +/*070*/  "rational number support was not enabled\n",
  18.115 +/*071*/  "user-defined operator must be declared before use (function \"%s\")\n",
  18.116 +/*072*/  "\"sizeof\" operator is invalid on \"function\" symbols\n",
  18.117 +/*073*/  "function argument must be an array (argument \"%s\")\n",
  18.118 +/*074*/  "#define pattern must start with an alphabetic character\n",
  18.119 +/*075*/  "input line too long (after substitutions)\n",
  18.120 +/*076*/  "syntax error in the expression, or invalid function call\n",
  18.121 +/*077*/  "malformed UTF-8 encoding, or corrupted file: %s\n",
  18.122 +/*078*/  "function uses both \"return\" and \"return <value>\"\n",
  18.123 +/*079*/  "inconsistent return types (array & non-array)\n",
  18.124 +/*080*/  "unknown symbol, or not a constant symbol (symbol \"%s\")\n",
  18.125 +/*081*/  "cannot take a tag as a default value for an indexed array parameter (symbol \"%s\")\n",
  18.126 +/*082*/  "user-defined operators and native functions may not have states\n",
  18.127 +/*083*/  "a function or variable may only belong to a single automaton (symbol \"%s\")\n",
  18.128 +/*084*/  "state conflict: one of the states is already assigned to another implementation (symbol \"%s\")\n",
  18.129 +/*085*/  "no states are defined for symbol \"%s\"\n",
  18.130 +/*086*/  "unknown automaton \"%s\"\n",
  18.131 +/*087*/  "unknown state \"%s\" for automaton \"%s\"\n",
  18.132 +/*088*/  "public variables and local variables may not have states (symbol \"%s\")\n",
  18.133 +/*089*/  "state variables may not be initialized (symbol \"%s\")\n",
  18.134 +/*090*/  "public functions may not return arrays (symbol \"%s\")\n",
  18.135 +/*091*/  "ambiguous constant; tag override is required (symbol \"%s\")\n"
  18.136 +#else
  18.137 +  "\271pect\235\306k\212:\227\316bu\202fo\217\206\216\012",
  18.138 +  "\201l\223\252s\203g\352\315e\234\202(\255\363\201) c\355f\240\344w ea\275 \042c\351e\042\012",
  18.139 +  "\233cl\333\237\304\252\344c\337\330\324appe\204 \372\252\343\364o\217\206\236ock\012",
  18.140 +  "\366\227 \272\242i\364le\234t\274\012",
  18.141 +  "\273\367\242\340\376\265t\313",
  18.142 +  "\360a\253gn\235\306 \355\256y\012",
  18.143 +  "\353\224\255c\226\242\312\221\327\274\012",
  18.144 +  "\360\252\354\202\363\201; \351\375m\235z\210o\012",
  18.145 +  "\266\303\335\200(nega\205ve\316z\210\371\255ou\202\304bo\217ds\232",
  18.146 +  "\266\273\255\233cl\333\214\012",
  18.147 +  "\266out\222d\200\366\313",
  18.148 +  "\266\273c\211l\316\242\252\261add\221s\313",
  18.149 +  "\220 \212tr\223po\203\202(\220 pu\236\326 \366s\232",
  18.150 +  "\266\315e\234t; \242\372s\362t\275\012",
  18.151 +  "\042\302a\342t\331c\351\200\360\270\200l\351\202c\351\200\372s\362t\275 \315e\234t\012",
  18.152 +  "m\342\205p\352\302a\342t\207\372\042s\362t\275\042\012",
  18.153 +  "\217\327\235\277\012",
  18.154 +  "\203i\205\211iza\237d\224\252\271ce\274\207\233cl\204\235\335\322",
  18.155 +  "\242\252lab\341\347",
  18.156 +  "\266\250 nam\200\216\012",
  18.157 +  "\250 \211\221ad\223\327\274\347",
  18.158 +  "\360l\243u\200(n\201-\354t\232",
  18.159 +  "\303a\253gn\234\202\360\222\364\352a\253gn\234t\012",
  18.160 +  "\042b\221ak\331\255\042\307t\203ue\331\272ou\202\304\307t\271t\012",
  18.161 +  "\273head\357\334ff\210\207from pro\306typ\322",
  18.162 +  "\220 \345\275\357\042#if...\042\012",
  18.163 +  "\266\275\333ct\264\354t\012",
  18.164 +  "\266\375bscrip\202(\242\355\303\255\306\371m\226\223\375bscripts)\347",
  18.165 +  "\266\363\201\316\351\375m\235z\210o\012",
  18.166 +  "\343\364o\217\206\315e\234\202\242c\344s\235a\202\270\200\212\206\304\361\352(\231\204t\235a\202l\203\200%d\232",
  18.167 +  "\217k\220w\336\334\221c\205v\322",
  18.168 +  "\303\203\233x ou\202\304bo\217d\207(\330\216\232",
  18.169 +  "\303\360\203\233x\235(\330\216\232",
  18.170 +  "\311do\310\242\340\376\252\302a\342\202\243u\200(\311%d\232",
  18.171 +  "\311typ\200mis\345\275 (\311%d\232",
  18.172 +  "e\364t\223\315e\234t\012",
  18.173 +  "\266\231r\357(po\253\236\223n\201-\365m\203\224\235\231r\203g\232",
  18.174 +  "\271t\241 \275\333c\365\207\332l\203\322",
  18.175 +  "\354\202\250 \340\207\220 \335\322",
  18.176 +  "dupl\326\224\200\042c\351e\331lab\341 (\243u\200%d\232",
  18.177 +  "\266\341lip\222s\316\303\335\200\272\242k\220wn\012",
  18.178 +  "\266\343\230\203a\237\304cl\351\207speci\361\210\313",
  18.179 +  "\275\333ct\264\354\202\271ce\274\207r\226g\200f\255pack\235\231r\203g\012",
  18.180 +  "po\222\214\337p\333me\365\207\324\314c\274\200\211l nam\235p\333me\365\313",
  18.181 +  "\306\371m\226\223\273\265t\313",
  18.182 +  "\217k\220w\336\303\335\200(\330\216\232",
  18.183 +  "\303\335\310d\371\242\345\275\316\255\233\231\203a\237\303\272\306\371sm\211l\012",
  18.184 +  "\303\334\234\222\201\207d\371\242\345\275\012",
  18.185 +  "\266l\203\200\307t\203ua\214\012",
  18.186 +  "\266r\226g\322",
  18.187 +  "\266\375bscript\316\251\200\042[ ]\331\353\224\225\207\332\305j\255\334\234\222\201\313",
  18.188 +  "m\342\205-\334\234\222\201\337\256y\207\360f\342l\223\203i\205\211iz\274\012",
  18.189 +  "\271ce\274\357\305ximum \374\230\264\304\334\234\222\201\313",
  18.190 +  "\217\345\275\235c\344s\357b\241c\200(\042}\042\232",
  18.191 +  "\231\204\202\304\273bod\223\362\270ou\202\273head\210\012",
  18.192 +  "\256ys\316\344c\337\301\310\226\206\273\265t\207c\226\242\312pu\236\326 (\330\216\232",
  18.193 +  "\217f\203ish\235\363\332be\370\200\343\364il\264\334\221c\205v\322",
  18.194 +  "dupl\326\224\200\265t; sam\200\311\272p\351s\235tw\326\322",
  18.195 +  "\273\311\367\242\340\376\252\302a\342\202\243u\200(\330\216\232",
  18.196 +  "m\342\205p\352\042#\341se\331\334\221c\205v\310betwe\212 \042#if ... #\212\334f\042\012",
  18.197 +  "\042#\341seif\331\334\221c\205\376f\240\344w\207\355\042#\341se\331\334\221c\205v\322",
  18.198 +  "\374\230\264\304\353\226d\207do\310\242\361\202\270\200\353\224\225\012",
  18.199 +  "\273\221s\342\202\373\304\353\224\225\227 \360\216\012",
  18.200 +  "c\226\242\275\226g\200\314\327\235\353\224\225\313",
  18.201 +  "\273\311\367\201l\223\340\376\252s\203g\352\373(\311%d\232",
  18.202 +  "\273\311\367\242\312\252\221f\210\212c\200\311\255\355\303(\311\216\232",
  18.203 +  "\330c\226\242\312bo\270 \252\221f\210\212c\200\226\206\355\303(\330\216\232",
  18.204 +  "\266\241\214\337\374\230\264\314ci\222\332\372#p\241g\305\012",
  18.205 +  "\241\214\337\374\230\264\370\305\202\211\221ad\223\327\274\012",
  18.206 +  "\241\214\337\374\230\264\375pp\225\202wa\207\242\212\254\274\012",
  18.207 +  "\251\210-\327\235\353\224\255\360\233cl\204\235be\370\200\251\200(\366\227\232",
  18.208 +  "\042\335e\267\331\353\224\255\272\266\332\042\366\331\250\313",
  18.209 +  "\273\311\360\355\303(\311\216\232",
  18.210 +  "#\327\200p\224\365\336\324\231\204\202\362\270 \355\211p\340be\205c \275\333c\365\012",
  18.211 +  "\203pu\202l\203\200\306\371l\201\260(aft\264\375bs\205tu\214s\232",
  18.212 +  "\246n\325x \210r\255\372\270\200\363\201\316\255\266\273c\211l\012",
  18.213 +  "m\211\370m\235UTF-8 \212\343d\203g\316\255c\225rupt\235\361le: \213\012",
  18.214 +  "\273\251\310bo\270 \042\221turn\331\226\206\042\221tur\336<\243ue>\042\012",
  18.215 +  "\203\307\222\231\212\202\221tur\336typ\310(\303& n\201-\256y\232",
  18.216 +  "\217k\220w\336\250\316\255\242\252\354\202\250 \323",
  18.217 +  "c\226\242\325k\200\252\373a\207\252\302a\342\202\243u\200f\255\355\203\233x\235\303p\333met\264\323",
  18.218 +  "\251\210-\327\235\353\224\225\207\226\206na\205\376\366\207\367\242\340\376\315e\313",
  18.219 +  "\252\273\255\330\367\201l\223b\341\201\260\306 \252s\203g\352au\306\345\332\323",
  18.220 +  "\315\200\307fl\326t: \201\200\304\270\200\315\310\272\211\221ad\223a\253gn\235\306 a\220\270\264i\364le\234\325\237\323",
  18.221 +  "\220 \315\310\204\200\327\235f\255\277\012",
  18.222 +  "\217k\220w\336au\306\345\201\321",
  18.223 +  "\217k\220w\336\315\200\216 f\255au\306\345\201\321",
  18.224 +  "pu\236\326 \301\310\226\206\344c\337\301\310\367\242\340\376\315\310\323",
  18.225 +  "\315\200\301\310\367\242\312\203i\205\211iz\235\323",
  18.226 +  "pu\236\326 \366\207\367\242\221tur\336\256y\207\323",
  18.227 +  "a\230i\262ou\207\354t; \373ov\210rid\200\272\221qui\221\206\323"
  18.228 +#endif
  18.229 +       };
  18.230 +
  18.231 +static char *fatalmsg[] = {
  18.232 +#ifdef SCPACK
  18.233 +/*100*/  "cannot read from file: \"%s\"\n",
  18.234 +/*101*/  "cannot write to file: \"%s\"\n",
  18.235 +/*102*/  "table overflow: \"%s\"\n",
  18.236 +          /* table can be: loop table
  18.237 +           *               literal table
  18.238 +           *               staging buffer
  18.239 +           *               option table (response file)
  18.240 +           *               peephole optimizer table
  18.241 +           */
  18.242 +/*103*/  "insufficient memory\n",
  18.243 +/*104*/  "invalid assembler instruction \"%s\"\n",
  18.244 +/*105*/  "numeric overflow, exceeding capacity\n",
  18.245 +/*106*/  "compiled script exceeds the maximum memory size (%ld bytes)\n",
  18.246 +/*107*/  "too many error messages on one line\n",
  18.247 +/*108*/  "codepage mapping file not found\n",
  18.248 +/*109*/  "invalid path: \"%s\"\n",
  18.249 +/*110*/  "assertion failed: %s\n",
  18.250 +/*111*/  "user error: %s\n",
  18.251 +#else
  18.252 +  "c\226\242\221a\206from \361le\347",
  18.253 +  "c\226\242writ\200\306 \361le\347",
  18.254 +  "t\254\200ov\210f\344w\347",
  18.255 +  "\203\375ff\326i\212\202mem\225y\012",
  18.256 +  "\266\351se\230l\264\203\231ruc\214\321",
  18.257 +  "\374m\210\326 ov\210f\344w\316\271ce\274\357capacity\012",
  18.258 +  "\343\364il\235scrip\202\271ce\274\207\270\200\305ximum mem\225\223\335\200(%l\206bytes\232",
  18.259 +  "\306\371m\226\223\210r\255messag\310\332\201\200l\203\322",
  18.260 +  "\343\233pag\200\305pp\357\361\352\242fo\217d\012",
  18.261 +  "\266p\224h\347",
  18.262 +  "\351s\210\237fail\274: \213\012",
  18.263 +  "\251\264\210r\225: \213\012"
  18.264 +#endif
  18.265 +       };
  18.266 +
  18.267 +static char *warnmsg[] = {
  18.268 +#ifdef SCPACK
  18.269 +/*200*/  "symbol \"%s\" is truncated to %d characters\n",
  18.270 +/*201*/  "redefinition of constant/macro (symbol \"%s\")\n",
  18.271 +/*202*/  "number of arguments does not match definition\n",
  18.272 +/*203*/  "symbol is never used: \"%s\"\n",
  18.273 +/*204*/  "symbol is assigned a value that is never used: \"%s\"\n",
  18.274 +/*205*/  "redundant code: constant expression is zero\n",
  18.275 +/*206*/  "redundant test: constant expression is non-zero\n",
  18.276 +/*207*/  "unknown #pragma\n",
  18.277 +/*208*/  "function with tag result used before definition, forcing reparse\n",
  18.278 +/*209*/  "function \"%s\" should return a value\n",
  18.279 +/*210*/  "possible use of symbol before initialization: \"%s\"\n",
  18.280 +/*211*/  "possibly unintended assignment\n",
  18.281 +/*212*/  "possibly unintended bitwise operation\n",
  18.282 +/*213*/  "tag mismatch\n",
  18.283 +/*214*/  "possibly a \"const\" array argument was intended: \"%s\"\n",
  18.284 +/*215*/  "expression has no effect\n",
  18.285 +/*216*/  "nested comment\n",
  18.286 +/*217*/  "loose indentation\n",
  18.287 +/*218*/  "old style prototypes used with optional semicolumns\n",
  18.288 +/*219*/  "local variable \"%s\" shadows a variable at a preceding level\n",
  18.289 +/*220*/  "expression with tag override must appear between parentheses\n",
  18.290 +/*221*/  "label name \"%s\" shadows tag name\n",
  18.291 +/*222*/  "number of digits exceeds rational number precision\n",
  18.292 +/*223*/  "redundant \"sizeof\": argument size is always 1 (symbol \"%s\")\n",
  18.293 +/*224*/  "indeterminate array size in \"sizeof\" expression (symbol \"%s\")\n",
  18.294 +/*225*/  "unreachable code\n",
  18.295 +/*226*/  "a variable is assigned to itself (symbol \"%s\")\n",
  18.296 +/*227*/  "more initiallers than enum fields\n",
  18.297 +/*228*/  "length of initialler exceeds size of the enum field\n",
  18.298 +/*229*/  "index tag mismatch (symbol \"%s\")\n",
  18.299 +/*230*/  "no implementation for state \"%s\" in function \"%s\", no fall-back\n",
  18.300 +/*231*/  "state specification on forward declaration is ignored\n",
  18.301 +/*232*/  "output file is written, but with compact encoding disabled\n",
  18.302 +/*233*/  "state variable \"%s\" shadows a global variable\n",
  18.303 +/*234*/  "function is depricated (symbol \"%s\") %s\n",
  18.304 +/*235*/  "public function lacks forward declaration (symbol \"%s\")\n",
  18.305 +/*236*/  "unknown parameter in substitution (incorrect #define pattern)\n"
  18.306 +#else
  18.307 +  "\277 \272tr\244\224\235\306 %\206\275\333c\365\313",
  18.308 +  "\221\327i\237\304\354t/\305cr\371\323",
  18.309 +  "\374\230\264\304\265t\207do\310\242\345\275 \327i\214\012",
  18.310 +  "\250 \272nev\264\251\274\347",
  18.311 +  "\250 \272a\253gn\235\252\243u\200\270a\202\272nev\264\251\274\347",
  18.312 +  "\221d\217d\226\202\343\233: \354\202\363\332\272z\210o\012",
  18.313 +  "\221d\217d\226\202te\231: \354\202\363\332\272n\201-z\210o\012",
  18.314 +  "\217k\220w\336#p\241g\305\012",
  18.315 +  "\273\362\270 \373\221s\342\202\251\235be\370\200\327i\214\316\370c\357\221p\204s\322",
  18.316 +  "\366\227 sho\342\206\221tur\336\252\243u\322",
  18.317 +  "po\253\236\200\251\200\304\250 be\370\200\203i\205\211iza\214\347",
  18.318 +  "po\253\236\223\217\203t\212\233\206a\253gn\234t\012",
  18.319 +  "po\253\236\223\217\203t\212\233\206bit\362s\200\353a\214\012",
  18.320 +  "\373mis\345\275\012",
  18.321 +  "po\253\236\223\252\042\346\331\303\311wa\207\203t\212\233d\347",
  18.322 +  "\363\332\340\207\220 effect\012",
  18.323 +  "ne\231\235\343m\234t\012",
  18.324 +  "\344os\200\203d\212\325\214\012",
  18.325 +  "\240\206\231y\352pro\306typ\310\251\235\362\270 \350\214\337sem\326\240umn\313",
  18.326 +  "\344c\337\330\216 s\340dow\207\252\330a\202\252\314c\274\357lev\341\012",
  18.327 +  "\363\332\362\270 \373ov\210rid\200\324appe\204 betwe\212 p\204\212\270ese\313",
  18.328 +  "lab\341 nam\200\216 s\340dow\207\373nam\322",
  18.329 +  "\374\230\264\304\334git\207\271ce\274\207\241\214\337\374\230\264\314ci\222\201\012",
  18.330 +  "\221d\217d\226\202\042\335e\267\042: \311\335\200\272\211way\2071 \323",
  18.331 +  "\203\233\365m\203\224\200\303\335\200\372\042\335e\267\331\363\332\323",
  18.332 +  "\217\221a\275\254\200\343\233\012",
  18.333 +  "\252\330\272a\253gn\235\306 its\341f \323",
  18.334 +  "m\225\200\203i\205\211l\210\207\270\355\212um \361\341d\313",
  18.335 +  "l\212g\270 \304\203i\205\211l\264\271ce\274\207\335\200\304\270\200\212um \361\341d\012",
  18.336 +  "\203\233x \373mis\345\275 \323",
  18.337 +  "\220 i\364le\234\325\237f\255\315\200\216 \372\366\227\316\220 f\211l-back\012",
  18.338 +  "\315\200specif\326a\237\332\370w\204\206\233cl\333\237\272ig\220\221d\012",
  18.339 +  "outpu\202\361\352\272writt\212\316bu\202\362\270 \343\364ac\202\212\343d\357\334s\254\274\012",
  18.340 +  "\315\200\330\216 s\340dow\207\252g\344b\337\301\322",
  18.341 +  "\273\272\233pr\326\224\235\317) \213\012",
  18.342 +  "pu\236\326 \273lack\207\370w\204\206\233cl\333\237\323",
  18.343 +  "\217k\220w\336p\333met\264\372\375bs\205tu\237(\203c\225\221c\202#\327\200p\224\365n\232"
  18.344 +#endif
  18.345 +       };
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/compiler-init/compiler-init/sc6.c	Fri Jul 14 02:02:18 2006 +0000
    19.3 @@ -0,0 +1,1298 @@
    19.4 +/*  Pawn compiler - Binary code generation (the "assembler")
    19.5 + *
    19.6 + *  Copyright (c) ITB CompuPhase, 1997-2006
    19.7 + *
    19.8 + *  This software is provided "as-is", without any express or implied warranty.
    19.9 + *  In no event will the authors be held liable for any damages arising from
   19.10 + *  the use of this software.
   19.11 + *
   19.12 + *  Permission is granted to anyone to use this software for any purpose,
   19.13 + *  including commercial applications, and to alter it and redistribute it
   19.14 + *  freely, subject to the following restrictions:
   19.15 + *
   19.16 + *  1.  The origin of this software must not be misrepresented; you must not
   19.17 + *      claim that you wrote the original software. If you use this software in
   19.18 + *      a product, an acknowledgment in the product documentation would be
   19.19 + *      appreciated but is not required.
   19.20 + *  2.  Altered source versions must be plainly marked as such, and must not be
   19.21 + *      misrepresented as being the original software.
   19.22 + *  3.  This notice may not be removed or altered from any source distribution.
   19.23 + *
   19.24 + *  Version: $Id: sc6.c 3579 2006-06-06 13:35:29Z thiadmer $
   19.25 + */
   19.26 +#include <assert.h>
   19.27 +#include <stdio.h>
   19.28 +#include <stdlib.h>     /* for macro max() */
   19.29 +#include <stddef.h>     /* for macro offsetof() */
   19.30 +#include <string.h>
   19.31 +#include <ctype.h>
   19.32 +#if defined FORTIFY
   19.33 +  #include <alloc/fortify.h>
   19.34 +#endif
   19.35 +#include "lstring.h"
   19.36 +#include "sc.h"
   19.37 +#include "amxdbg.h"
   19.38 +#if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
   19.39 +  #include <sclinux.h>
   19.40 +#endif
   19.41 +
   19.42 +
   19.43 +static void append_dbginfo(FILE *fout);
   19.44 +
   19.45 +
   19.46 +typedef cell (*OPCODE_PROC)(FILE *fbin,char *params,cell opcode);
   19.47 +
   19.48 +typedef struct {
   19.49 +  cell opcode;
   19.50 +  char *name;
   19.51 +  int segment;          /* sIN_CSEG=parse in cseg, sIN_DSEG=parse in dseg */
   19.52 +  OPCODE_PROC func;
   19.53 +} OPCODE;
   19.54 +
   19.55 +static cell codeindex;  /* similar to "code_idx" */
   19.56 +static cell *lbltab;    /* label table */
   19.57 +static int writeerror;
   19.58 +static int bytes_in, bytes_out;
   19.59 +static jmp_buf compact_err;
   19.60 +
   19.61 +/* apparently, strtol() does not work correctly on very large (unsigned)
   19.62 + * hexadecimal values */
   19.63 +static ucell hex2long(const char *s,char **n)
   19.64 +{
   19.65 +  ucell result=0L;
   19.66 +  int negate=FALSE;
   19.67 +  int digit;
   19.68 +
   19.69 +  /* ignore leading whitespace */
   19.70 +  while (*s==' ' || *s=='\t')
   19.71 +    s++;
   19.72 +
   19.73 +  /* allow a negation sign to create the two's complement of numbers */
   19.74 +  if (*s=='-') {
   19.75 +    negate=TRUE;
   19.76 +    s++;
   19.77 +  } /* if */
   19.78 +
   19.79 +  assert((*s>='0' && *s<='9') || (*s>='a' && *s<='f') || (*s>='a' && *s<='f'));
   19.80 +  for ( ;; ) {
   19.81 +    if (*s>='0' && *s<='9')
   19.82 +      digit=*s-'0';
   19.83 +    else if (*s>='a' && *s<='f')
   19.84 +      digit=*s-'a' + 10;
   19.85 +    else if (*s>='A' && *s<='F')
   19.86 +      digit=*s-'A' + 10;
   19.87 +    else
   19.88 +      break;    /* probably whitespace */
   19.89 +    result=(result<<4) | digit;
   19.90 +    s++;
   19.91 +  } /* for */
   19.92 +  if (n!=NULL)
   19.93 +    *n=(char*)s;
   19.94 +  if (negate)
   19.95 +    result=(~result)+1; /* take two's complement of the result */
   19.96 +  return (ucell)result;
   19.97 +}
   19.98 +
   19.99 +static ucell getparam(const char *s,char **n)
  19.100 +{
  19.101 +  ucell result=0;
  19.102 +  for ( ;; ) {
  19.103 +    result+=hex2long(s,(char**)&s);
  19.104 +    if (*s!='+')
  19.105 +      break;
  19.106 +    s++;
  19.107 +  } /* for */
  19.108 +  if (n!=NULL)
  19.109 +    *n=(char*)s;
  19.110 +  return result;
  19.111 +}
  19.112 +
  19.113 +#if BYTE_ORDER==BIG_ENDIAN
  19.114 +static uint16_t *align16(uint16_t *v)
  19.115 +{
  19.116 +  unsigned char *s = (unsigned char *)v;
  19.117 +  unsigned char t;
  19.118 +
  19.119 +  /* swap two bytes */
  19.120 +  t=s[0];
  19.121 +  s[0]=s[1];
  19.122 +  s[1]=t;
  19.123 +  return v;
  19.124 +}
  19.125 +
  19.126 +static uint32_t *align32(uint32_t *v)
  19.127 +{
  19.128 +  unsigned char *s = (unsigned char *)v;
  19.129 +  unsigned char t;
  19.130 +
  19.131 +  /* swap outer two bytes */
  19.132 +  t=s[0];
  19.133 +  s[0]=s[3];
  19.134 +  s[3]=t;
  19.135 +  /* swap inner two bytes */
  19.136 +  t=s[1];
  19.137 +  s[1]=s[2];
  19.138 +  s[2]=t;
  19.139 +  return v;
  19.140 +}
  19.141 +
  19.142 +#if PAWN_CELL_SIZE>=64
  19.143 +static uint64_t *align64(uint64_t *v)
  19.144 +{
  19.145 +	unsigned char *s = (unsigned char *)v;
  19.146 +	unsigned char t;
  19.147 +
  19.148 +	t=s[0];
  19.149 +	s[0]=s[7];
  19.150 +	s[7]=t;
  19.151 +
  19.152 +	t=s[1];
  19.153 +	s[1]=s[6];
  19.154 +	s[6]=t;
  19.155 +
  19.156 +	t=s[2];
  19.157 +	s[2]=s[5];
  19.158 +	s[5]=t;
  19.159 +
  19.160 +	t=s[3];
  19.161 +	s[3]=s[4];
  19.162 +	s[4]=t;
  19.163 +
  19.164 +	return v;
  19.165 +}
  19.166 +#endif
  19.167 +
  19.168 +  #if PAWN_CELL_SIZE==16
  19.169 +    #define aligncell(v)  align16(v)
  19.170 +  #elif PAWN_CELL_SIZE==32
  19.171 +    #define aligncell(v)  align32(v)
  19.172 +  #elif PAWN_CELL_SIZE==64
  19.173 +    #define aligncell(v)  align64(v)
  19.174 +  #endif
  19.175 +#else
  19.176 +  #define align16(v)    (v)
  19.177 +  #define align32(v)    (v)
  19.178 +  #define aligncell(v)  (v)
  19.179 +#endif
  19.180 +
  19.181 +static char *skipwhitespace(char *str)
  19.182 +{
  19.183 +  while (isspace(*str))
  19.184 +    str++;
  19.185 +  return str;
  19.186 +}
  19.187 +
  19.188 +static char *stripcomment(char *str)
  19.189 +{
  19.190 +  char *ptr=strchr(str,';');
  19.191 +  if (ptr!=NULL) {
  19.192 +    *ptr++='\n';        /* terminate the line, but leave the '\n' */
  19.193 +    *ptr='\0';
  19.194 +  } /* if */
  19.195 +  return str;
  19.196 +}
  19.197 +
  19.198 +static void write_encoded(FILE *fbin,ucell *c,int num)
  19.199 +{
  19.200 +  #if PAWN_CELL_SIZE == 16
  19.201 +    #define ENC_MAX   3     /* a 16-bit cell is encoded in max. 3 bytes */
  19.202 +    #define ENC_MASK  0x03  /* after 2x7 bits, 2 bits remain to make 16 bits */
  19.203 +  #elif PAWN_CELL_SIZE == 32
  19.204 +    #define ENC_MAX   5     /* a 32-bit cell is encoded in max. 5 bytes */
  19.205 +    #define ENC_MASK  0x0f  /* after 4x7 bits, 4 bits remain to make 32 bits */
  19.206 +  #elif PAWN_CELL_SIZE == 64
  19.207 +    #define ENC_MAX   10    /* a 32-bit cell is encoded in max. 10 bytes */
  19.208 +    #define ENC_MASK  0x01  /* after 9x7 bits, 1 bit remains to make 64 bits */
  19.209 +  #endif
  19.210 +
  19.211 +  assert(fbin!=NULL);
  19.212 +  while (num-->0) {
  19.213 +    if (sc_compress) {
  19.214 +      ucell p=(ucell)*c;
  19.215 +      unsigned char t[ENC_MAX];
  19.216 +      unsigned char code;
  19.217 +      int index;
  19.218 +      for (index=0; index<ENC_MAX; index++) {
  19.219 +        t[index]=(unsigned char)(p & 0x7f);     /* store 7 bits */
  19.220 +        p>>=7;
  19.221 +      } /* for */
  19.222 +      /* skip leading zeros */
  19.223 +      while (index>1 && t[index-1]==0 && (t[index-2] & 0x40)==0)
  19.224 +        index--;
  19.225 +      /* skip leading -1s */
  19.226 +      if (index==ENC_MAX && t[index-1]==ENC_MASK && (t[index-2] & 0x40)!=0)
  19.227 +        index--;
  19.228 +      while (index>1 && t[index-1]==0x7f && (t[index-2] & 0x40)!=0)
  19.229 +        index--;
  19.230 +      /* write high byte first, write continuation bits */
  19.231 +      assert(index>0);
  19.232 +      while (index-->0) {
  19.233 +        code=(unsigned char)((index==0) ? t[index] : (t[index]|0x80));
  19.234 +        writeerror |= !pc_writebin(fbin,&code,1);
  19.235 +        bytes_out++;
  19.236 +      } /* while */
  19.237 +      bytes_in+=sizeof *c;
  19.238 +      assert(AMX_COMPACTMARGIN>2);
  19.239 +      if (bytes_out-bytes_in>=AMX_COMPACTMARGIN-2)
  19.240 +        longjmp(compact_err,1);
  19.241 +    } else {
  19.242 +      assert((pc_lengthbin(fbin) % sizeof(cell)) == 0);
  19.243 +      writeerror |= !pc_writebin(fbin,aligncell(c),sizeof *c);
  19.244 +    } /* if */
  19.245 +    c++;
  19.246 +  } /* while */
  19.247 +}
  19.248 +
  19.249 +#if defined __BORLANDC__ || defined __WATCOMC__
  19.250 +  #pragma argsused
  19.251 +#endif
  19.252 +static cell noop(FILE *fbin,char *params,cell opcode)
  19.253 +{
  19.254 +  return 0;
  19.255 +}
  19.256 +
  19.257 +#if defined __BORLANDC__ || defined __WATCOMC__
  19.258 +  #pragma argsused
  19.259 +#endif
  19.260 +static cell set_currentfile(FILE *fbin,char *params,cell opcode)
  19.261 +{
  19.262 +  fcurrent=(short)getparam(params,NULL);
  19.263 +  return 0;
  19.264 +}
  19.265 +
  19.266 +#if defined __BORLANDC__ || defined __WATCOMC__
  19.267 +  #pragma argsused
  19.268 +#endif
  19.269 +static cell parm0(FILE *fbin,char *params,cell opcode)
  19.270 +{
  19.271 +  if (fbin!=NULL)
  19.272 +    write_encoded(fbin,(ucell*)&opcode,1);
  19.273 +  return opcodes(1);
  19.274 +}
  19.275 +
  19.276 +static cell parm1(FILE *fbin,char *params,cell opcode)
  19.277 +{
  19.278 +  ucell p=getparam(params,NULL);
  19.279 +  if (fbin!=NULL) {
  19.280 +    write_encoded(fbin,(ucell*)&opcode,1);
  19.281 +    write_encoded(fbin,&p,1);
  19.282 +  } /* if */
  19.283 +  return opcodes(1)+opargs(1);
  19.284 +}
  19.285 +
  19.286 +static cell parm2(FILE *fbin,char *params,cell opcode)
  19.287 +{
  19.288 +  ucell p1=getparam(params,&params);
  19.289 +  ucell p2=getparam(params,NULL);
  19.290 +  if (fbin!=NULL) {
  19.291 +    write_encoded(fbin,(ucell*)&opcode,1);
  19.292 +    write_encoded(fbin,&p1,1);
  19.293 +    write_encoded(fbin,&p2,1);
  19.294 +  } /* if */
  19.295 +  return opcodes(1)+opargs(2);
  19.296 +}
  19.297 +
  19.298 +static cell parm3(FILE *fbin,char *params,cell opcode)
  19.299 +{
  19.300 +  ucell p1=getparam(params,&params);
  19.301 +  ucell p2=getparam(params,&params);
  19.302 +  ucell p3=getparam(params,NULL);
  19.303 +  if (fbin!=NULL) {
  19.304 +    write_encoded(fbin,(ucell*)&opcode,1);
  19.305 +    write_encoded(fbin,&p1,1);
  19.306 +    write_encoded(fbin,&p2,1);
  19.307 +    write_encoded(fbin,&p3,1);
  19.308 +  } /* if */
  19.309 +  return opcodes(1)+opargs(3);
  19.310 +}
  19.311 +
  19.312 +static cell parm4(FILE *fbin,char *params,cell opcode)
  19.313 +{
  19.314 +  ucell p1=getparam(params,&params);
  19.315 +  ucell p2=getparam(params,&params);
  19.316 +  ucell p3=getparam(params,&params);
  19.317 +  ucell p4=getparam(params,NULL);
  19.318 +  if (fbin!=NULL) {
  19.319 +    write_encoded(fbin,(ucell*)&opcode,1);
  19.320 +    write_encoded(fbin,&p1,1);
  19.321 +    write_encoded(fbin,&p2,1);
  19.322 +    write_encoded(fbin,&p3,1);
  19.323 +    write_encoded(fbin,&p4,1);
  19.324 +  } /* if */
  19.325 +  return opcodes(1)+opargs(4);
  19.326 +}
  19.327 +
  19.328 +static cell parm5(FILE *fbin,char *params,cell opcode)
  19.329 +{
  19.330 +  ucell p1=getparam(params,&params);
  19.331 +  ucell p2=getparam(params,&params);
  19.332 +  ucell p3=getparam(params,&params);
  19.333 +  ucell p4=getparam(params,&params);
  19.334 +  ucell p5=getparam(params,NULL);
  19.335 +  if (fbin!=NULL) {
  19.336 +    write_encoded(fbin,(ucell*)&opcode,1);
  19.337 +    write_encoded(fbin,&p1,1);
  19.338 +    write_encoded(fbin,&p2,1);
  19.339 +    write_encoded(fbin,&p3,1);
  19.340 +    write_encoded(fbin,&p4,1);
  19.341 +    write_encoded(fbin,&p5,1);
  19.342 +  } /* if */
  19.343 +  return opcodes(1)+opargs(5);
  19.344 +}
  19.345 +
  19.346 +#if defined __BORLANDC__ || defined __WATCOMC__
  19.347 +  #pragma argsused
  19.348 +#endif
  19.349 +static cell do_dump(FILE *fbin,char *params,cell opcode)
  19.350 +{
  19.351 +  ucell p;
  19.352 +  int num = 0;
  19.353 +
  19.354 +  while (*params!='\0') {
  19.355 +    p=getparam(params,&params);
  19.356 +    if (fbin!=NULL)
  19.357 +      write_encoded(fbin,&p,1);
  19.358 +    num++;
  19.359 +    while (isspace(*params))
  19.360 +      params++;
  19.361 +  } /* while */
  19.362 +  return num*sizeof(cell);
  19.363 +}
  19.364 +
  19.365 +static cell do_call(FILE *fbin,char *params,cell opcode)
  19.366 +{
  19.367 +  char name[sNAMEMAX+1];
  19.368 +  int i;
  19.369 +  symbol *sym;
  19.370 +  ucell p;
  19.371 +
  19.372 +  for (i=0; !isspace(*params); i++,params++) {
  19.373 +    assert(*params!='\0');
  19.374 +    assert(i<sNAMEMAX);
  19.375 +    name[i]=*params;
  19.376 +  } /* for */
  19.377 +  name[i]='\0';
  19.378 +
  19.379 +  if (name[0]=='l' && name[1]=='.') {
  19.380 +    /* this is a label, not a function symbol */
  19.381 +    i=(int)hex2long(name+2,NULL);
  19.382 +    assert(i>=0 && i<sc_labnum);
  19.383 +    if (fbin!=NULL) {
  19.384 +      assert(lbltab!=NULL);
  19.385 +      p=lbltab[i];
  19.386 +    } /* if */
  19.387 +  } else {
  19.388 +    /* look up the function address; note that the correct file number must
  19.389 +     * already have been set (in order for static globals to be found).
  19.390 +     */
  19.391 +    sym=findglb(name,sGLOBAL);
  19.392 +    assert(sym!=NULL);
  19.393 +    assert(sym->ident==iFUNCTN || sym->ident==iREFFUNC);
  19.394 +    assert(sym->vclass==sGLOBAL);
  19.395 +    p=sym->addr;
  19.396 +  } /* if */
  19.397 +
  19.398 +  if (fbin!=NULL) {
  19.399 +    write_encoded(fbin,(ucell*)&opcode,1);
  19.400 +    write_encoded(fbin,&p,1);
  19.401 +  } /* if */
  19.402 +  return opcodes(1)+opargs(1);
  19.403 +}
  19.404 +
  19.405 +static cell do_jump(FILE *fbin,char *params,cell opcode)
  19.406 +{
  19.407 +  int i;
  19.408 +  ucell p;
  19.409 +
  19.410 +  i=(int)hex2long(params,NULL);
  19.411 +  assert(i>=0 && i<sc_labnum);
  19.412 +
  19.413 +  if (fbin!=NULL) {
  19.414 +    assert(lbltab!=NULL);
  19.415 +    p=lbltab[i];
  19.416 +    write_encoded(fbin,(ucell*)&opcode,1);
  19.417 +    write_encoded(fbin,&p,1);
  19.418 +  } /* if */
  19.419 +  return opcodes(1)+opargs(1);
  19.420 +}
  19.421 +
  19.422 +static cell do_switch(FILE *fbin,char *params,cell opcode)
  19.423 +{
  19.424 +  int i;
  19.425 +  ucell p;
  19.426 +
  19.427 +  i=(int)hex2long(params,NULL);
  19.428 +  assert(i>=0 && i<sc_labnum);
  19.429 +
  19.430 +  if (fbin!=NULL) {
  19.431 +    assert(lbltab!=NULL);
  19.432 +    p=lbltab[i];
  19.433 +    write_encoded(fbin,(ucell*)&opcode,1);
  19.434 +    write_encoded(fbin,&p,1);
  19.435 +  } /* if */
  19.436 +  return opcodes(1)+opargs(1);
  19.437 +}
  19.438 +
  19.439 +#if defined __BORLANDC__ || defined __WATCOMC__
  19.440 +  #pragma argsused
  19.441 +#endif
  19.442 +static cell do_case(FILE *fbin,char *params,cell opcode)
  19.443 +{
  19.444 +  int i;
  19.445 +  ucell p,v;
  19.446 +
  19.447 +  v=hex2long(params,&params);
  19.448 +  i=(int)hex2long(params,NULL);
  19.449 +  assert(i>=0 && i<sc_labnum);
  19.450 +
  19.451 +  if (fbin!=NULL) {
  19.452 +    assert(lbltab!=NULL);
  19.453 +    p=lbltab[i];
  19.454 +    write_encoded(fbin,&v,1);
  19.455 +    write_encoded(fbin,&p,1);
  19.456 +  } /* if */
  19.457 +  return opcodes(0)+opargs(2);
  19.458 +}
  19.459 +
  19.460 +static OPCODE opcodelist[] = {
  19.461 +  /* node for "invalid instruction" */
  19.462 +  {  0, NULL,         0,        noop },
  19.463 +  /* opcodes in sorted order */
  19.464 +  { 78, "add",        sIN_CSEG, parm0 },
  19.465 +  { 87, "add.c",      sIN_CSEG, parm1 },
  19.466 +  { 14, "addr.alt",   sIN_CSEG, parm1 },
  19.467 +  { 13, "addr.pri",   sIN_CSEG, parm1 },
  19.468 +  { 30, "align.alt",  sIN_CSEG, parm1 },
  19.469 +  { 29, "align.pri",  sIN_CSEG, parm1 },
  19.470 +  { 81, "and",        sIN_CSEG, parm0 },
  19.471 +  {121, "bounds",     sIN_CSEG, parm1 },
  19.472 +  {137, "break",      sIN_CSEG, parm0 },  /* version 8 */
  19.473 +  { 49, "call",       sIN_CSEG, do_call },
  19.474 +  { 50, "call.pri",   sIN_CSEG, parm0 },
  19.475 +  {  0, "case",       sIN_CSEG, do_case },
  19.476 +  {130, "casetbl",    sIN_CSEG, parm0 },  /* version 1 */
  19.477 +  {118, "cmps",       sIN_CSEG, parm1 },
  19.478 +  {  0, "code",       sIN_CSEG, set_currentfile },
  19.479 +  {156, "const",      sIN_CSEG, parm2 },  /* version 9 */
  19.480 +  { 12, "const.alt",  sIN_CSEG, parm1 },
  19.481 +  { 11, "const.pri",  sIN_CSEG, parm1 },
  19.482 +  {157, "const.s",    sIN_CSEG, parm2 },  /* version 9 */
  19.483 +  {  0, "data",       sIN_DSEG, set_currentfile },
  19.484 +  {114, "dec",        sIN_CSEG, parm1 },
  19.485 +  {113, "dec.alt",    sIN_CSEG, parm0 },
  19.486 +  {116, "dec.i",      sIN_CSEG, parm0 },
  19.487 +  {112, "dec.pri",    sIN_CSEG, parm0 },
  19.488 +  {115, "dec.s",      sIN_CSEG, parm1 },
  19.489 +  {  0, "dump",       sIN_DSEG, do_dump },
  19.490 +  { 95, "eq",         sIN_CSEG, parm0 },
  19.491 +  {106, "eq.c.alt",   sIN_CSEG, parm1 },
  19.492 +  {105, "eq.c.pri",   sIN_CSEG, parm1 },
  19.493 +/*{124, "file",       sIN_CSEG, do_file }, */
  19.494 +  {119, "fill",       sIN_CSEG, parm1 },
  19.495 +  {100, "geq",        sIN_CSEG, parm0 },
  19.496 +  { 99, "grtr",       sIN_CSEG, parm0 },
  19.497 +  {120, "halt",       sIN_CSEG, parm1 },
  19.498 +  { 45, "heap",       sIN_CSEG, parm1 },
  19.499 +  { 27, "idxaddr",    sIN_CSEG, parm0 },
  19.500 +  { 28, "idxaddr.b",  sIN_CSEG, parm1 },
  19.501 +  {109, "inc",        sIN_CSEG, parm1 },
  19.502 +  {108, "inc.alt",    sIN_CSEG, parm0 },
  19.503 +  {111, "inc.i",      sIN_CSEG, parm0 },
  19.504 +  {107, "inc.pri",    sIN_CSEG, parm0 },
  19.505 +  {110, "inc.s",      sIN_CSEG, parm1 },
  19.506 +  { 86, "invert",     sIN_CSEG, parm0 },
  19.507 +  { 55, "jeq",        sIN_CSEG, do_jump },
  19.508 +  { 60, "jgeq",       sIN_CSEG, do_jump },
  19.509 +  { 59, "jgrtr",      sIN_CSEG, do_jump },
  19.510 +  { 58, "jleq",       sIN_CSEG, do_jump },
  19.511 +  { 57, "jless",      sIN_CSEG, do_jump },
  19.512 +  { 56, "jneq",       sIN_CSEG, do_jump },
  19.513 +  { 54, "jnz",        sIN_CSEG, do_jump },
  19.514 +  { 52, "jrel",       sIN_CSEG, parm1 },  /* always a number */
  19.515 +  { 64, "jsgeq",      sIN_CSEG, do_jump },
  19.516 +  { 63, "jsgrtr",     sIN_CSEG, do_jump },
  19.517 +  { 62, "jsleq",      sIN_CSEG, do_jump },
  19.518 +  { 61, "jsless",     sIN_CSEG, do_jump },
  19.519 +  { 51, "jump",       sIN_CSEG, do_jump },
  19.520 +  {128, "jump.pri",   sIN_CSEG, parm0 },  /* version 1 */
  19.521 +  { 53, "jzer",       sIN_CSEG, do_jump },
  19.522 +  { 31, "lctrl",      sIN_CSEG, parm1 },
  19.523 +  { 98, "leq",        sIN_CSEG, parm0 },
  19.524 +  { 97, "less",       sIN_CSEG, parm0 },
  19.525 +  { 25, "lidx",       sIN_CSEG, parm0 },
  19.526 +  { 26, "lidx.b",     sIN_CSEG, parm1 },
  19.527 +/*{125, "line",       sIN_CSEG, parm2 }, */
  19.528 +  {  2, "load.alt",   sIN_CSEG, parm1 },
  19.529 +  {154, "load.both",  sIN_CSEG, parm2 },  /* version 9 */
  19.530 +  {  9, "load.i",     sIN_CSEG, parm0 },
  19.531 +  {  1, "load.pri",   sIN_CSEG, parm1 },
  19.532 +  {  4, "load.s.alt", sIN_CSEG, parm1 },
  19.533 +  {155, "load.s.both",sIN_CSEG, parm2 },  /* version 9 */
  19.534 +  {  3, "load.s.pri", sIN_CSEG, parm1 },
  19.535 +  { 10, "lodb.i",     sIN_CSEG, parm1 },
  19.536 +  {  6, "lref.alt",   sIN_CSEG, parm1 },
  19.537 +  {  5, "lref.pri",   sIN_CSEG, parm1 },
  19.538 +  {  8, "lref.s.alt", sIN_CSEG, parm1 },
  19.539 +  {  7, "lref.s.pri", sIN_CSEG, parm1 },
  19.540 +  { 34, "move.alt",   sIN_CSEG, parm0 },
  19.541 +  { 33, "move.pri",   sIN_CSEG, parm0 },
  19.542 +  {117, "movs",       sIN_CSEG, parm1 },
  19.543 +  { 85, "neg",        sIN_CSEG, parm0 },
  19.544 +  { 96, "neq",        sIN_CSEG, parm0 },
  19.545 +  {134, "nop",        sIN_CSEG, parm0 },  /* version 6 */
  19.546 +  { 84, "not",        sIN_CSEG, parm0 },
  19.547 +  { 82, "or",         sIN_CSEG, parm0 },
  19.548 +  { 43, "pop.alt",    sIN_CSEG, parm0 },
  19.549 +  { 42, "pop.pri",    sIN_CSEG, parm0 },
  19.550 +  { 46, "proc",       sIN_CSEG, parm0 },
  19.551 +  { 40, "push",       sIN_CSEG, parm1 },
  19.552 +  {133, "push.adr",   sIN_CSEG, parm1 },  /* version 4 */
  19.553 +  { 37, "push.alt",   sIN_CSEG, parm0 },
  19.554 +  { 39, "push.c",     sIN_CSEG, parm1 },
  19.555 +  { 36, "push.pri",   sIN_CSEG, parm0 },
  19.556 +  { 38, "push.r",     sIN_CSEG, parm1 },  /* obsolete (never generated) */
  19.557 +  { 41, "push.s",     sIN_CSEG, parm1 },
  19.558 +  {139, "push2",      sIN_CSEG, parm2 },  /* version 9 */
  19.559 +  {141, "push2.adr",  sIN_CSEG, parm2 },  /* version 9 */
  19.560 +  {138, "push2.c",    sIN_CSEG, parm2 },  /* version 9 */
  19.561 +  {140, "push2.s",    sIN_CSEG, parm2 },  /* version 9 */
  19.562 +  {143, "push3",      sIN_CSEG, parm3 },  /* version 9 */
  19.563 +  {145, "push3.adr",  sIN_CSEG, parm3 },  /* version 9 */
  19.564 +  {142, "push3.c",    sIN_CSEG, parm3 },  /* version 9 */
  19.565 +  {144, "push3.s",    sIN_CSEG, parm3 },  /* version 9 */
  19.566 +  {147, "push4",      sIN_CSEG, parm4 },  /* version 9 */
  19.567 +  {149, "push4.adr",  sIN_CSEG, parm4 },  /* version 9 */
  19.568 +  {146, "push4.c",    sIN_CSEG, parm4 },  /* version 9 */
  19.569 +  {148, "push4.s",    sIN_CSEG, parm4 },  /* version 9 */
  19.570 +  {151, "push5",      sIN_CSEG, parm5 },  /* version 9 */
  19.571 +  {153, "push5.adr",  sIN_CSEG, parm5 },  /* version 9 */
  19.572 +  {150, "push5.c",    sIN_CSEG, parm5 },  /* version 9 */
  19.573 +  {152, "push5.s",    sIN_CSEG, parm5 },  /* version 9 */
  19.574 +  { 47, "ret",        sIN_CSEG, parm0 },
  19.575 +  { 48, "retn",       sIN_CSEG, parm0 },
  19.576 +  { 32, "sctrl",      sIN_CSEG, parm1 },
  19.577 +  { 73, "sdiv",       sIN_CSEG, parm0 },
  19.578 +  { 74, "sdiv.alt",   sIN_CSEG, parm0 },
  19.579 +  {104, "sgeq",       sIN_CSEG, parm0 },
  19.580 +  {103, "sgrtr",      sIN_CSEG, parm0 },
  19.581 +  { 65, "shl",        sIN_CSEG, parm0 },
  19.582 +  { 69, "shl.c.alt",  sIN_CSEG, parm1 },
  19.583 +  { 68, "shl.c.pri",  sIN_CSEG, parm1 },
  19.584 +  { 66, "shr",        sIN_CSEG, parm0 },
  19.585 +  { 71, "shr.c.alt",  sIN_CSEG, parm1 },
  19.586 +  { 70, "shr.c.pri",  sIN_CSEG, parm1 },
  19.587 +  { 94, "sign.alt",   sIN_CSEG, parm0 },
  19.588 +  { 93, "sign.pri",   sIN_CSEG, parm0 },
  19.589 +  {102, "sleq",       sIN_CSEG, parm0 },
  19.590 +  {101, "sless",      sIN_CSEG, parm0 },
  19.591 +  { 72, "smul",       sIN_CSEG, parm0 },
  19.592 +  { 88, "smul.c",     sIN_CSEG, parm1 },
  19.593 +/*{127, "srange",     sIN_CSEG, parm2 }, -- version 1 */
  19.594 +  { 20, "sref.alt",   sIN_CSEG, parm1 },
  19.595 +  { 19, "sref.pri",   sIN_CSEG, parm1 },
  19.596 +  { 22, "sref.s.alt", sIN_CSEG, parm1 },
  19.597 +  { 21, "sref.s.pri", sIN_CSEG, parm1 },
  19.598 +  { 67, "sshr",       sIN_CSEG, parm0 },
  19.599 +  { 44, "stack",      sIN_CSEG, parm1 },
  19.600 +  {  0, "stksize",    0,        noop },
  19.601 +  { 16, "stor.alt",   sIN_CSEG, parm1 },
  19.602 +  { 23, "stor.i",     sIN_CSEG, parm0 },
  19.603 +  { 15, "stor.pri",   sIN_CSEG, parm1 },
  19.604 +  { 18, "stor.s.alt", sIN_CSEG, parm1 },
  19.605 +  { 17, "stor.s.pri", sIN_CSEG, parm1 },
  19.606 +  { 24, "strb.i",     sIN_CSEG, parm1 },
  19.607 +  { 79, "sub",        sIN_CSEG, parm0 },
  19.608 +  { 80, "sub.alt",    sIN_CSEG, parm0 },
  19.609 +  {132, "swap.alt",   sIN_CSEG, parm0 },  /* version 4 */
  19.610 +  {131, "swap.pri",   sIN_CSEG, parm0 },  /* version 4 */
  19.611 +  {129, "switch",     sIN_CSEG, do_switch }, /* version 1 */
  19.612 +/*{126, "symbol",     sIN_CSEG, do_symbol }, */
  19.613 +/*{136, "symtag",     sIN_CSEG, parm1 },  -- version 7 */
  19.614 +  {123, "sysreq.c",   sIN_CSEG, parm1 },
  19.615 +  {135, "sysreq.n",   sIN_CSEG, parm2 },  /* version 9 (replaces SYSREQ.d from earlier version) */
  19.616 +  {122, "sysreq.pri", sIN_CSEG, parm0 },
  19.617 +  { 76, "udiv",       sIN_CSEG, parm0 },
  19.618 +  { 77, "udiv.alt",   sIN_CSEG, parm0 },
  19.619 +  { 75, "umul",       sIN_CSEG, parm0 },
  19.620 +  { 35, "xchg",       sIN_CSEG, parm0 },
  19.621 +  { 83, "xor",        sIN_CSEG, parm0 },
  19.622 +  { 91, "zero",       sIN_CSEG, parm1 },
  19.623 +  { 90, "zero.alt",   sIN_CSEG, parm0 },
  19.624 +  { 89, "zero.pri",   sIN_CSEG, parm0 },
  19.625 +  { 92, "zero.s",     sIN_CSEG, parm1 },
  19.626 +};
  19.627 +
  19.628 +#define MAX_INSTR_LEN   30
  19.629 +static int findopcode(char *instr,int maxlen)
  19.630 +{
  19.631 +  int low,high,mid,cmp;
  19.632 +  char str[MAX_INSTR_LEN];
  19.633 +
  19.634 +  if (maxlen>=MAX_INSTR_LEN)
  19.635 +    return 0;
  19.636 +  strlcpy(str,instr,maxlen+1);
  19.637 +  /* look up the instruction with a binary search
  19.638 +   * the assembler is case insensitive to instructions (but case sensitive
  19.639 +   * to symbols)
  19.640 +   */
  19.641 +  low=1;                /* entry 0 is reserved (for "not found") */
  19.642 +  high=(sizeof opcodelist / sizeof opcodelist[0])-1;
  19.643 +  while (low<high) {
  19.644 +    mid=(low+high)/2;
  19.645 +    assert(opcodelist[mid].name!=NULL);
  19.646 +    cmp=stricmp(str,opcodelist[mid].name);
  19.647 +    if (cmp>0)
  19.648 +      low=mid+1;
  19.649 +    else
  19.650 +      high=mid;
  19.651 +  } /* while */
  19.652 +
  19.653 +  assert(low==high);
  19.654 +  if (stricmp(str,opcodelist[low].name)==0)
  19.655 +    return low;         /* found */
  19.656 +  return 0;             /* not found, return special index */
  19.657 +}
  19.658 +
  19.659 +SC_FUNC int assemble(FILE *fout,FILE *fin)
  19.660 +{
  19.661 +  AMX_HEADER hdr;
  19.662 +  AMX_FUNCSTUBNT func;
  19.663 +  int numpublics,numnatives,numlibraries,numpubvars,numtags,padding;
  19.664 +  long nametablesize,nameofs;
  19.665 +  #if PAWN_CELL_SIZE > 32
  19.666 +    char line[512];
  19.667 +  #else
  19.668 +    char line[256];
  19.669 +  #endif
  19.670 +  char *instr,*params;
  19.671 +  int i,pass,size;
  19.672 +  int16_t count;
  19.673 +  symbol *sym, **nativelist;
  19.674 +  constvalue *constptr;
  19.675 +  cell mainaddr;
  19.676 +  char nullchar = 0;
  19.677 +
  19.678 +  /* if compression failed, restart the assembly with compaction switched off */
  19.679 +  if (setjmp(compact_err)!=0) {
  19.680 +    assert(sc_compress);  /* cannot arrive here if compact encoding was disabled */
  19.681 +    sc_compress=FALSE;
  19.682 +    pc_resetbin(fout,0);
  19.683 +    error(232);           /* disabled compact encoding */
  19.684 +  } /* if */
  19.685 +
  19.686 +  #if !defined NDEBUG
  19.687 +    /* verify that the opcode list is sorted (skip entry 1; it is reserved
  19.688 +     * for a non-existant opcode)
  19.689 +     */
  19.690 +    assert(opcodelist[1].name!=NULL);
  19.691 +    for (i=2; i<(sizeof opcodelist / sizeof opcodelist[0]); i++) {
  19.692 +      assert(opcodelist[i].name!=NULL);
  19.693 +      assert(stricmp(opcodelist[i].name,opcodelist[i-1].name)>0);
  19.694 +    } /* for */
  19.695 +  #endif
  19.696 +
  19.697 +  writeerror=FALSE;
  19.698 +  nametablesize=sizeof(int16_t);
  19.699 +  numpublics=0;
  19.700 +  numnatives=0;
  19.701 +  numpubvars=0;
  19.702 +  mainaddr=-1;
  19.703 +  /* count number of public and native functions and public variables */
  19.704 +  for (sym=glbtab.next; sym!=NULL; sym=sym->next) {
  19.705 +    int match=0;
  19.706 +    if (sym->ident==iFUNCTN) {
  19.707 +      if ((sym->usage & uNATIVE)!=0 && (sym->usage & uREAD)!=0 && sym->addr>=0)
  19.708 +        match=++numnatives;
  19.709 +      if ((sym->usage & uPUBLIC)!=0 && (sym->usage & uDEFINE)!=0)
  19.710 +        match=++numpublics;
  19.711 +      if (strcmp(sym->name,uMAINFUNC)==0) {
  19.712 +        assert(sym->vclass==sGLOBAL);
  19.713 +        mainaddr=sym->addr;
  19.714 +      } /* if */
  19.715 +    } else if (sym->ident==iVARIABLE) {
  19.716 +      if ((sym->usage & uPUBLIC)!=0 && (sym->usage & (uREAD | uWRITTEN))!=0)
  19.717 +        match=++numpubvars;
  19.718 +    } /* if */
  19.719 +    if (match) {
  19.720 +      char alias[sNAMEMAX+1];
  19.721 +      assert(sym!=NULL);
  19.722 +      if ((sym->usage & uNATIVE)==0 || !lookup_alias(alias,sym->name)) {
  19.723 +        assert(strlen(sym->name)<=sNAMEMAX);
  19.724 +        strcpy(alias,sym->name);
  19.725 +      } /* if */
  19.726 +      nametablesize+=strlen(alias)+1;
  19.727 +    } /* if */
  19.728 +  } /* for */
  19.729 +  assert(numnatives==ntv_funcid);
  19.730 +
  19.731 +  /* count number of libraries */
  19.732 +  numlibraries=0;
  19.733 +  if (pc_addlibtable) {
  19.734 +    for (constptr=libname_tab.next; constptr!=NULL; constptr=constptr->next) {
  19.735 +      if (constptr->value>0) {
  19.736 +        assert(strlen(constptr->name)>0);
  19.737 +        numlibraries++;
  19.738 +        nametablesize+=strlen(constptr->name)+1;
  19.739 +      } /* if */
  19.740 +    } /* for */
  19.741 +  } /* if */
  19.742 +
  19.743 +  /* count number of public tags */
  19.744 +  numtags=0;
  19.745 +  for (constptr=tagname_tab.next; constptr!=NULL; constptr=constptr->next) {
  19.746 +    if ((constptr->value & PUBLICTAG)!=0) {
  19.747 +      assert(strlen(constptr->name)>0);
  19.748 +      numtags++;
  19.749 +      nametablesize+=strlen(constptr->name)+1;
  19.750 +    } /* if */
  19.751 +  } /* for */
  19.752 +
  19.753 +  /* pad the header to sc_dataalign
  19.754 +   * => thereby the code segment is aligned
  19.755 +   * => since the code segment is padded to a sc_dataalign boundary, the data segment is aligned
  19.756 +   * => and thereby the stack top is aligned too
  19.757 +   */
  19.758 +  assert(sc_dataalign!=0);
  19.759 +  padding= (int)(sc_dataalign - (sizeof hdr + nametablesize) % sc_dataalign);
  19.760 +  if (padding==sc_dataalign)
  19.761 +    padding=0;
  19.762 +
  19.763 +  /* write the abstract machine header */
  19.764 +  memset(&hdr, 0, sizeof hdr);
  19.765 +  hdr.magic=(unsigned short)AMX_MAGIC;
  19.766 +  hdr.file_version=(char)((pc_optimize<=sOPTIMIZE_NOMACRO) ? MAX_FILE_VER_JIT : CUR_FILE_VERSION);
  19.767 +  hdr.amx_version=(char)((pc_optimize<=sOPTIMIZE_NOMACRO) ? MIN_AMX_VER_JIT : MIN_AMX_VERSION);
  19.768 +  hdr.flags=(short)(sc_debug & sSYMBOLIC);
  19.769 +  if (sc_compress)
  19.770 +    hdr.flags|=AMX_FLAG_COMPACT;
  19.771 +  if (sc_debug==0)
  19.772 +    hdr.flags|=AMX_FLAG_NOCHECKS;
  19.773 +  if (pc_memflags & suSLEEP_INSTR)
  19.774 +    hdr.flags|=AMX_FLAG_SLEEP;
  19.775 +  hdr.defsize=sizeof(AMX_FUNCSTUBNT);
  19.776 +  hdr.publics=sizeof hdr; /* public table starts right after the header */
  19.777 +  hdr.natives=hdr.publics + numpublics*sizeof(AMX_FUNCSTUBNT);
  19.778 +  hdr.libraries=hdr.natives + numnatives*sizeof(AMX_FUNCSTUBNT);
  19.779 +  hdr.pubvars=hdr.libraries + numlibraries*sizeof(AMX_FUNCSTUBNT);
  19.780 +  hdr.tags=hdr.pubvars + numpubvars*sizeof(AMX_FUNCSTUBNT);
  19.781 +  hdr.nametable=hdr.tags + numtags*sizeof(AMX_FUNCSTUBNT);
  19.782 +  hdr.cod=hdr.nametable + nametablesize + padding;
  19.783 +  hdr.dat=hdr.cod + code_idx;
  19.784 +  hdr.hea=hdr.dat + glb_declared*sizeof(cell);
  19.785 +  hdr.stp=hdr.hea + pc_stksize*sizeof(cell);
  19.786 +  hdr.cip=mainaddr;
  19.787 +  hdr.size=hdr.hea; /* preset, this is incorrect in case of compressed output */
  19.788 +  pc_writebin(fout,&hdr,sizeof hdr);
  19.789 +
  19.790 +  /* dump zeros up to the rest of the header, so that we can easily "seek" */
  19.791 +  for (nameofs=sizeof hdr; nameofs<hdr.cod; nameofs++)
  19.792 +    pc_writebin(fout, &nullchar, 1);
  19.793 +  nameofs=hdr.nametable+sizeof(int16_t);
  19.794 +
  19.795 +  /* write the public functions table */
  19.796 +  count=0;
  19.797 +  for (sym=glbtab.next; sym!=NULL; sym=sym->next) {
  19.798 +    if (sym->ident==iFUNCTN
  19.799 +        && (sym->usage & uPUBLIC)!=0 && (sym->usage & uDEFINE)!=0)
  19.800 +    {
  19.801 +      assert(sym->vclass==sGLOBAL);
  19.802 +      func.address=sym->addr;
  19.803 +      func.nameofs=nameofs;
  19.804 +      #if BYTE_ORDER==BIG_ENDIAN
  19.805 +        align32(&func.address);
  19.806 +        align32(&func.nameofs);
  19.807 +      #endif
  19.808 +      pc_resetbin(fout,hdr.publics+count*sizeof(AMX_FUNCSTUBNT));
  19.809 +      pc_writebin(fout,&func,sizeof func);
  19.810 +      pc_resetbin(fout,nameofs);
  19.811 +      pc_writebin(fout,sym->name,strlen(sym->name)+1);
  19.812 +      nameofs+=strlen(sym->name)+1;
  19.813 +      count++;
  19.814 +    } /* if */
  19.815 +  } /* for */
  19.816 +
  19.817 +  /* write the natives table */
  19.818 +  /* The native functions must be written in sorted order. (They are
  19.819 +   * sorted on their "id", not on their name). A nested loop to find
  19.820 +   * each successive function would be an O(n^2) operation. But we
  19.821 +   * do not really need to sort, because the native function id's
  19.822 +   * are sequential and there are no duplicates. So we first walk
  19.823 +   * through the complete symbol list and store a pointer to every
  19.824 +   * native function of interest in a temporary table, where its id
  19.825 +   * serves as the index in the table. Now we can walk the table and
  19.826 +   * have all native functions in sorted order.
  19.827 +   */
  19.828 +  if (numnatives>0) {
  19.829 +    nativelist=(symbol **)malloc(numnatives*sizeof(symbol *));
  19.830 +    if (nativelist==NULL)
  19.831 +      error(103);               /* insufficient memory */
  19.832 +    #if !defined NDEBUG
  19.833 +      memset(nativelist,0,numnatives*sizeof(symbol *)); /* for NULL checking */
  19.834 +    #endif
  19.835 +    for (sym=glbtab.next; sym!=NULL; sym=sym->next) {
  19.836 +      if (sym->ident==iFUNCTN && (sym->usage & uNATIVE)!=0 && (sym->usage & uREAD)!=0 && sym->addr>=0) {
  19.837 +        assert(sym->addr < numnatives);
  19.838 +        nativelist[(int)sym->addr]=sym;
  19.839 +      } /* if */
  19.840 +    } /* for */
  19.841 +    count=0;
  19.842 +    for (i=0; i<numnatives; i++) {
  19.843 +      char alias[sNAMEMAX+1];
  19.844 +      sym=nativelist[i];
  19.845 +      assert(sym!=NULL);
  19.846 +      if (!lookup_alias(alias,sym->name)) {
  19.847 +        assert(strlen(sym->name)<=sNAMEMAX);
  19.848 +        strcpy(alias,sym->name);
  19.849 +      } /* if */
  19.850 +      assert(sym->vclass==sGLOBAL);
  19.851 +      func.address=0;
  19.852 +      func.nameofs=nameofs;
  19.853 +      #if BYTE_ORDER==BIG_ENDIAN
  19.854 +        align32(&func.address);
  19.855 +        align32(&func.nameofs);
  19.856 +      #endif
  19.857 +      pc_resetbin(fout,hdr.natives+count*sizeof(AMX_FUNCSTUBNT));
  19.858 +      pc_writebin(fout,&func,sizeof func);
  19.859 +      pc_resetbin(fout,nameofs);
  19.860 +      pc_writebin(fout,alias,strlen(alias)+1);
  19.861 +      nameofs+=strlen(alias)+1;
  19.862 +      count++;
  19.863 +    } /* for */
  19.864 +    free(nativelist);
  19.865 +  } /* if */
  19.866 +
  19.867 +  /* write the libraries table */
  19.868 +  if (pc_addlibtable) {
  19.869 +    count=0;
  19.870 +    for (constptr=libname_tab.next; constptr!=NULL; constptr=constptr->next) {
  19.871 +      if (constptr->value>0) {
  19.872 +        assert(strlen(constptr->name)>0);
  19.873 +        func.address=0;
  19.874 +        func.nameofs=nameofs;
  19.875 +        #if BYTE_ORDER==BIG_ENDIAN
  19.876 +          align32(&func.address);
  19.877 +          align32(&func.nameofs);
  19.878 +        #endif
  19.879 +        pc_resetbin(fout,hdr.libraries+count*sizeof(AMX_FUNCSTUBNT));
  19.880 +        pc_writebin(fout,&func,sizeof func);
  19.881 +        pc_resetbin(fout,nameofs);
  19.882 +        pc_writebin(fout,constptr->name,strlen(constptr->name)+1);
  19.883 +        nameofs+=strlen(constptr->name)+1;
  19.884 +        count++;
  19.885 +      } /* if */
  19.886 +    } /* for */
  19.887 +  } /* if */
  19.888 +
  19.889 +  /* write the public variables table */
  19.890 +  count=0;
  19.891 +  for (sym=glbtab.next; sym!=NULL; sym=sym->next) {
  19.892 +    if (sym->ident==iVARIABLE && (sym->usage & uPUBLIC)!=0 && (sym->usage & (uREAD | uWRITTEN))!=0) {
  19.893 +      assert((sym->usage & uDEFINE)!=0);
  19.894 +      assert(sym->vclass==sGLOBAL);
  19.895 +      func.address=sym->addr;
  19.896 +      func.nameofs=nameofs;
  19.897 +      #if BYTE_ORDER==BIG_ENDIAN
  19.898 +        align32(&func.address);
  19.899 +        align32(&func.nameofs);
  19.900 +      #endif
  19.901 +      pc_resetbin(fout,hdr.pubvars+count*sizeof(AMX_FUNCSTUBNT));
  19.902 +      pc_writebin(fout,&func,sizeof func);
  19.903 +      pc_resetbin(fout,nameofs);
  19.904 +      pc_writebin(fout,sym->name,strlen(sym->name)+1);
  19.905 +      nameofs+=strlen(sym->name)+1;
  19.906 +      count++;
  19.907 +    } /* if */
  19.908 +  } /* for */
  19.909 +
  19.910 +  /* write the public tagnames table */
  19.911 +  count=0;
  19.912 +  for (constptr=tagname_tab.next; constptr!=NULL; constptr=constptr->next) {
  19.913 +    if ((constptr->value & PUBLICTAG)!=0) {
  19.914 +      assert(strlen(constptr->name)>0);
  19.915 +      func.address=constptr->value & TAGMASK;
  19.916 +      func.nameofs=nameofs;
  19.917 +      #if BYTE_ORDER==BIG_ENDIAN
  19.918 +        align32(&func.address);
  19.919 +        align32(&func.nameofs);
  19.920 +      #endif
  19.921 +      pc_resetbin(fout,hdr.tags+count*sizeof(AMX_FUNCSTUBNT));
  19.922 +      pc_writebin(fout,&func,sizeof func);
  19.923 +      pc_resetbin(fout,nameofs);
  19.924 +      pc_writebin(fout,constptr->name,strlen(constptr->name)+1);
  19.925 +      nameofs+=strlen(constptr->name)+1;
  19.926 +      count++;
  19.927 +    } /* if */
  19.928 +  } /* for */
  19.929 +
  19.930 +  /* write the "maximum name length" field in the name table */
  19.931 +  assert(nameofs==hdr.nametable+nametablesize);
  19.932 +  pc_resetbin(fout,hdr.nametable);
  19.933 +  count=sNAMEMAX;
  19.934 +  #if BYTE_ORDER==BIG_ENDIAN
  19.935 +    align16(&count);
  19.936 +  #endif
  19.937 +  pc_writebin(fout,&count,sizeof count);
  19.938 +  pc_resetbin(fout,hdr.cod);
  19.939 +
  19.940 +  /* First pass: relocate all labels */
  19.941 +  /* This pass is necessary because the code addresses of labels is only known
  19.942 +   * after the peephole optimization flag. Labels can occur inside expressions
  19.943 +   * (e.g. the conditional operator), which are optimized.
  19.944 +   */
  19.945 +  lbltab=NULL;
  19.946 +  if (sc_labnum>0) {
  19.947 +    /* only very short programs have zero labels; no first pass is needed
  19.948 +     * if there are no labels */
  19.949 +    lbltab=(cell *)malloc(sc_labnum*sizeof(cell));
  19.950 +    if (lbltab==NULL)
  19.951 +      error(103);               /* insufficient memory */
  19.952 +    codeindex=0;
  19.953 +    pc_resetasm(fin);
  19.954 +    while (pc_readasm(fin,line,sizeof line)!=NULL) {
  19.955 +      stripcomment(line);
  19.956 +      instr=skipwhitespace(line);
  19.957 +      /* ignore empty lines */
  19.958 +      if (*instr=='\0')
  19.959 +        continue;
  19.960 +      if (tolower(*instr)=='l' && *(instr+1)=='.') {
  19.961 +        int lindex=(int)hex2long(instr+2,NULL);
  19.962 +        assert(lindex>=0 && lindex<sc_labnum);
  19.963 +        lbltab[lindex]=codeindex;
  19.964 +      } else {
  19.965 +        /* get to the end of the instruction (make use of the '\n' that fgets()
  19.966 +         * added at the end of the line; this way we will *always* drop on a
  19.967 +         * whitespace character) */
  19.968 +        for (params=instr; *params!='\0' && !isspace(*params); params++)
  19.969 +          /* nothing */;
  19.970 +        assert(params>instr);
  19.971 +        i=findopcode(instr,(int)(params-instr));
  19.972 +        if (opcodelist[i].name==NULL) {
  19.973 +          *params='\0';
  19.974 +          error(104,instr);     /* invalid assembler instruction */
  19.975 +        } /* if */
  19.976 +        if (opcodelist[i].segment==sIN_CSEG)
  19.977 +          codeindex+=opcodelist[i].func(NULL,skipwhitespace(params),opcodelist[i].opcode);
  19.978 +      } /* if */
  19.979 +    } /* while */
  19.980 +  } /* if */
  19.981 +
  19.982 +  /* Second pass (actually 2 more passes, one for all code and one for all data) */
  19.983 +  bytes_in=0;
  19.984 +  bytes_out=0;
  19.985 +  for (pass=sIN_CSEG; pass<=sIN_DSEG; pass++) {
  19.986 +    pc_resetasm(fin);
  19.987 +    while (pc_readasm(fin,line,sizeof line)!=NULL) {
  19.988 +      stripcomment(line);
  19.989 +      instr=skipwhitespace(line);
  19.990 +      /* ignore empty lines and labels (labels have a special syntax, so these
  19.991 +       * must be parsed separately) */
  19.992 +      if (*instr=='\0' || tolower(*instr)=='l' && *(instr+1)=='.')
  19.993 +        continue;
  19.994 +      /* get to the end of the instruction (make use of the '\n' that fgets()
  19.995 +       * added at the end of the line; this way we will *always* drop on a
  19.996 +       * whitespace character) */
  19.997 +      for (params=instr; *params!='\0' && !isspace(*params); params++)
  19.998 +        /* nothing */;
  19.999 +      assert(params>instr);
 19.1000 +      i=findopcode(instr,(int)(params-instr));
 19.1001 +      assert(opcodelist[i].name!=NULL);
 19.1002 +      if (opcodelist[i].segment==pass)
 19.1003 +        opcodelist[i].func(fout,skipwhitespace(params),opcodelist[i].opcode);
 19.1004 +    } /* while */
 19.1005 +  } /* for */
 19.1006 +  if (bytes_out-bytes_in>0)
 19.1007 +    error(106);         /* compression buffer overflow */
 19.1008 +
 19.1009 +  if (lbltab!=NULL) {
 19.1010 +    free(lbltab);
 19.1011 +    #if !defined NDEBUG
 19.1012 +      lbltab=NULL;
 19.1013 +    #endif
 19.1014 +  } /* if */
 19.1015 +
 19.1016 +  if (sc_compress)
 19.1017 +    hdr.size=pc_lengthbin(fout);/* get this value before appending debug info */
 19.1018 +  if (!writeerror && (sc_debug & sSYMBOLIC)!=0)
 19.1019 +    append_dbginfo(fout);       /* optionally append debug file */
 19.1020 +
 19.1021 +  if (writeerror)
 19.1022 +    error(101,"disk full");
 19.1023 +
 19.1024 +  /* adjust the header */
 19.1025 +  size=(int)hdr.cod;    /* save, the value in the header may be swapped */
 19.1026 +  #if BYTE_ORDER==BIG_ENDIAN
 19.1027 +    align32(&hdr.size);
 19.1028 +    align16(&hdr.magic);
 19.1029 +    align16(&hdr.flags);
 19.1030 +    align16(&hdr.defsize);
 19.1031 +    align32(&hdr.publics);
 19.1032 +    align32(&hdr.natives);
 19.1033 +    align32(&hdr.libraries);
 19.1034 +    align32(&hdr.pubvars);
 19.1035 +    align32(&hdr.tags);
 19.1036 +    align32(&hdr.nametable);
 19.1037 +    align32(&hdr.cod);
 19.1038 +    align32(&hdr.dat);
 19.1039 +    align32(&hdr.hea);
 19.1040 +    align32(&hdr.stp);
 19.1041 +    align32(&hdr.cip);
 19.1042 +  #endif
 19.1043 +  pc_resetbin(fout,0);
 19.1044 +  pc_writebin(fout,&hdr,sizeof hdr);
 19.1045 +
 19.1046 +  /* return the size of the header (including name tables, but excluding code
 19.1047 +   * or data sections)
 19.1048 +   */
 19.1049 +  return size;
 19.1050 +}
 19.1051 +
 19.1052 +static void append_dbginfo(FILE *fout)
 19.1053 +{
 19.1054 +  AMX_DBG_HDR dbghdr;
 19.1055 +  AMX_DBG_LINE dbgline;
 19.1056 +  AMX_DBG_SYMBOL dbgsym;
 19.1057 +  AMX_DBG_SYMDIM dbgidxtag[sDIMEN_MAX];
 19.1058 +  int index,dim,dbgsymdim;
 19.1059 +  char *str,*prevstr,*name,*prevname;
 19.1060 +  ucell codeidx,previdx;
 19.1061 +  constvalue *constptr;
 19.1062 +  char symname[2*sNAMEMAX+16];
 19.1063 +  int16_t id1,id2;
 19.1064 +  ucell address;
 19.1065 +
 19.1066 +  /* header with general information */
 19.1067 +  memset(&dbghdr, 0, sizeof dbghdr);
 19.1068 +  dbghdr.size=sizeof dbghdr;
 19.1069 +  dbghdr.magic=AMX_DBG_MAGIC;
 19.1070 +  dbghdr.file_version=CUR_FILE_VERSION;
 19.1071 +  dbghdr.amx_version=MIN_AMX_VERSION;
 19.1072 +
 19.1073 +  /* first pass: collect the number of items in various tables */
 19.1074 +
 19.1075 +  /* file table */
 19.1076 +  previdx=0;
 19.1077 +  prevstr=NULL;
 19.1078 +  prevname=NULL;
 19.1079 +  for (index=0; (str=get_dbgstring(index))!=NULL; index++) {
 19.1080 +    assert(str!=NULL);
 19.1081 +    assert(str[0]!='\0' && str[1]==':');
 19.1082 +    if (str[0]=='F') {
 19.1083 +      codeidx=hex2long(str+2,&name);
 19.1084 +      if (codeidx!=previdx) {
 19.1085 +        if (prevstr!=NULL) {
 19.1086 +          assert(prevname!=NULL);
 19.1087 +          dbghdr.files++;
 19.1088 +          dbghdr.size+=sizeof(cell)+strlen(prevname)+1;
 19.1089 +        } /* if */
 19.1090 +        previdx=codeidx;
 19.1091 +      } /* if */
 19.1092 +      prevstr=str;
 19.1093 +      prevname=skipwhitespace(name);
 19.1094 +    } /* if */
 19.1095 +  } /* for */
 19.1096 +  if (prevstr!=NULL) {
 19.1097 +    assert(prevname!=NULL);
 19.1098 +    dbghdr.files++;
 19.1099 +    dbghdr.size+=sizeof(cell)+strlen(prevname)+1;
 19.1100 +  } /* if */
 19.1101 +
 19.1102 +  /* line number table */
 19.1103 +  for (index=0; (str=get_dbgstring(index))!=NULL; index++) {
 19.1104 +    assert(str!=NULL);
 19.1105 +    assert(str[0]!='\0' && str[1]==':');
 19.1106 +    if (str[0]=='L') {
 19.1107 +      dbghdr.lines++;
 19.1108 +      dbghdr.size+=sizeof(AMX_DBG_LINE);
 19.1109 +    } /* if */
 19.1110 +  } /* for */
 19.1111 +
 19.1112 +  /* symbol table */
 19.1113 +  for (index=0; (str=get_dbgstring(index))!=NULL; index++) {
 19.1114 +    assert(str!=NULL);
 19.1115 +    assert(str[0]!='\0' && str[1]==':');
 19.1116 +    if (str[0]=='S') {
 19.1117 +      dbghdr.symbols++;
 19.1118 +      name=strchr(str+2,':');
 19.1119 +      assert(name!=NULL);
 19.1120 +      dbghdr.size+=sizeof(AMX_DBG_SYMBOL)+strlen(skipwhitespace(name+1));
 19.1121 +      if ((prevstr=strchr(name,'['))!=NULL)
 19.1122 +        while ((prevstr=strchr(prevstr+1,':'))!=NULL)
 19.1123 +          dbghdr.size+=sizeof(AMX_DBG_SYMDIM);
 19.1124 +    } /* if */
 19.1125 +  } /* for */
 19.1126 +
 19.1127 +  /* tag table */
 19.1128 +  for (constptr=tagname_tab.next; constptr!=NULL; constptr=constptr->next) {
 19.1129 +    assert(strlen(constptr->name)>0);
 19.1130 +    dbghdr.tags++;
 19.1131 +    dbghdr.size+=sizeof(AMX_DBG_TAG)+strlen(constptr->name);
 19.1132 +  } /* for */
 19.1133 +
 19.1134 +  /* automaton table */
 19.1135 +  for (constptr=sc_automaton_tab.next; constptr!=NULL; constptr=constptr->next) {
 19.1136 +    assert(constptr->index==0 && strlen(constptr->name)==0 || strlen(constptr->name)>0);
 19.1137 +    dbghdr.automatons++;
 19.1138 +    dbghdr.size+=sizeof(AMX_DBG_MACHINE)+strlen(constptr->name);
 19.1139 +  } /* for */
 19.1140 +
 19.1141 +  /* state table */
 19.1142 +  for (constptr=sc_state_tab.next; constptr!=NULL; constptr=constptr->next) {
 19.1143 +    assert(strlen(constptr->name)>0);
 19.1144 +    dbghdr.states++;
 19.1145 +    dbghdr.size+=sizeof(AMX_DBG_STATE)+strlen(constptr->name);
 19.1146 +  } /* for */
 19.1147 +
 19.1148 +
 19.1149 +  /* pass 2: generate the tables */
 19.1150 +  #if BYTE_ORDER==BIG_ENDIAN
 19.1151 +    align32((uint32_t*)&dbghdr.size);
 19.1152 +    align16(&dbghdr.magic);
 19.1153 +    align16(&dbghdr.flags);
 19.1154 +    align16(&dbghdr.files);
 19.1155 +    align16(&dbghdr.lines);
 19.1156 +    align16(&dbghdr.symbols);
 19.1157 +    align16(&dbghdr.tags);
 19.1158 +    align16(&dbghdr.automatons);
 19.1159 +    align16(&dbghdr.states);
 19.1160 +  #endif
 19.1161 +  writeerror |= !pc_writebin(fout,&dbghdr,sizeof dbghdr);
 19.1162 +
 19.1163 +  /* file table */
 19.1164 +  previdx=0;
 19.1165 +  prevstr=NULL;
 19.1166 +  prevname=NULL;
 19.1167 +  for (index=0; (str=get_dbgstring(index))!=NULL; index++) {
 19.1168 +    assert(str!=NULL);
 19.1169 +    assert(str[0]!='\0' && str[1]==':');
 19.1170 +    if (str[0]=='F') {
 19.1171 +      codeidx=hex2long(str+2,&name);
 19.1172 +      if (codeidx!=previdx) {
 19.1173 +        if (prevstr!=NULL) {
 19.1174 +          assert(prevname!=NULL);
 19.1175 +          #if BYTE_ORDER==BIG_ENDIAN
 19.1176 +            aligncell(&previdx);
 19.1177 +          #endif
 19.1178 +          writeerror |= !pc_writebin(fout,&previdx,sizeof previdx);
 19.1179 +          writeerror |= !pc_writebin(fout,prevname,strlen(prevname)+1);
 19.1180 +        } /* if */
 19.1181 +        previdx=codeidx;
 19.1182 +      } /* if */
 19.1183 +      prevstr=str;
 19.1184 +      prevname=skipwhitespace(name);
 19.1185 +    } /* if */
 19.1186 +  } /* for */
 19.1187 +  if (prevstr!=NULL) {
 19.1188 +    assert(prevname!=NULL);
 19.1189 +    #if BYTE_ORDER==BIG_ENDIAN
 19.1190 +      aligncell(&previdx);
 19.1191 +    #endif
 19.1192 +    writeerror |= !pc_writebin(fout,&previdx,sizeof previdx);
 19.1193 +    writeerror |= !pc_writebin(fout,prevname,strlen(prevname)+1);
 19.1194 +  } /* if */
 19.1195 +
 19.1196 +  /* line number table */
 19.1197 +  for (index=0; (str=get_dbgstring(index))!=NULL; index++) {
 19.1198 +    assert(str!=NULL);
 19.1199 +    assert(str[0]!='\0' && str[1]==':');
 19.1200 +    if (str[0]=='L') {
 19.1201 +      dbgline.address=hex2long(str+2,&str);
 19.1202 +      dbgline.line=(int32_t)hex2long(str,NULL);
 19.1203 +      #if BYTE_ORDER==BIG_ENDIAN
 19.1204 +        aligncell(&dbgline.address);
 19.1205 +        align32(&dbgline.line);
 19.1206 +      #endif
 19.1207 +      writeerror |= !pc_writebin(fout,&dbgline,sizeof dbgline);
 19.1208 +    } /* if */
 19.1209 +  } /* for */
 19.1210 +
 19.1211 +  /* symbol table */
 19.1212 +  for (index=0; (str=get_dbgstring(index))!=NULL; index++) {
 19.1213 +    assert(str!=NULL);
 19.1214 +    assert(str[0]!='\0' && str[1]==':');
 19.1215 +    if (str[0]=='S') {
 19.1216 +      dbgsym.address=hex2long(str+2,&str);
 19.1217 +      dbgsym.tag=(int16_t)hex2long(str,&str);
 19.1218 +      str=skipwhitespace(str);
 19.1219 +      assert(*str==':');
 19.1220 +      name=skipwhitespace(str+1);
 19.1221 +      str=strchr(name,' ');
 19.1222 +      assert(str!=NULL);
 19.1223 +      assert((int)(str-name)<sizeof symname);
 19.1224 +      strlcpy(symname,name,(int)(str-name)+1);
 19.1225 +      dbgsym.codestart=hex2long(str,&str);
 19.1226 +      dbgsym.codeend=hex2long(str,&str);
 19.1227 +      dbgsym.ident=(char)hex2long(str,&str);
 19.1228 +      dbgsym.vclass=(char)hex2long(str,&str);
 19.1229 +      dbgsym.dim=0;
 19.1230 +      str=skipwhitespace(str);
 19.1231 +      if (*str=='[') {
 19.1232 +        while (*(str=skipwhitespace(str+1))!=']') {
 19.1233 +          dbgidxtag[dbgsym.dim].tag=(int16_t)hex2long(str,&str);
 19.1234 +          str=skipwhitespace(str);
 19.1235 +          assert(*str==':');
 19.1236 +          dbgidxtag[dbgsym.dim].size=hex2long(str+1,&str);
 19.1237 +          dbgsym.dim++;
 19.1238 +        } /* while */
 19.1239 +      } /* if */
 19.1240 +      dbgsymdim = dbgsym.dim;
 19.1241 +      #if BYTE_ORDER==BIG_ENDIAN
 19.1242 +        aligncell(&dbgsym.address);
 19.1243 +        align16(&dbgsym.tag);
 19.1244 +        aligncell(&dbgsym.codestart);
 19.1245 +        aligncell(&dbgsym.codeend);
 19.1246 +        align16(&dbgsym.dim);
 19.1247 +      #endif
 19.1248 +      writeerror |= !pc_writebin(fout,&dbgsym,offsetof(AMX_DBG_SYMBOL, name));
 19.1249 +      writeerror |= !pc_writebin(fout,symname,strlen(symname)+1);
 19.1250 +      for (dim=0; dim<dbgsymdim; dim++) {
 19.1251 +        #if BYTE_ORDER==BIG_ENDIAN
 19.1252 +          align16(&dbgidxtag[dim].tag);
 19.1253 +          aligncell(&dbgidxtag[dim].size);
 19.1254 +        #endif
 19.1255 +        writeerror |= !pc_writebin(fout,&dbgidxtag[dim],sizeof dbgidxtag[dim]);
 19.1256 +      } /* for */
 19.1257 +    } /* if */
 19.1258 +  } /* for */
 19.1259 +
 19.1260 +  /* tag table */
 19.1261 +  for (constptr=tagname_tab.next; constptr!=NULL; constptr=constptr->next) {
 19.1262 +    assert(strlen(constptr->name)>0);
 19.1263 +    id1=(int16_t)(constptr->value & TAGMASK);
 19.1264 +    #if BYTE_ORDER==BIG_ENDIAN
 19.1265 +      align16(&id1);
 19.1266 +    #endif
 19.1267 +    writeerror |= !pc_writebin(fout,&id1,sizeof id1);
 19.1268 +    writeerror |= !pc_writebin(fout,constptr->name,strlen(constptr->name)+1);
 19.1269 +  } /* for */
 19.1270 +
 19.1271 +  /* automaton table */
 19.1272 +  for (constptr=sc_automaton_tab.next; constptr!=NULL; constptr=constptr->next) {
 19.1273 +    assert(constptr->index==0 && strlen(constptr->name)==0 || strlen(constptr->name)>0);
 19.1274 +    id1=(int16_t)constptr->index;
 19.1275 +    address=(ucell)constptr->value;
 19.1276 +    #if BYTE_ORDER==BIG_ENDIAN
 19.1277 +      align16(&id1);
 19.1278 +      aligncell(&address);
 19.1279 +    #endif
 19.1280 +    writeerror |= !pc_writebin(fout,&id1,sizeof id1);
 19.1281 +    writeerror |= !pc_writebin(fout,&address,sizeof address);
 19.1282 +    writeerror |= !pc_writebin(fout,constptr->name,strlen(constptr->name)+1);
 19.1283 +  } /* for */
 19.1284 +
 19.1285 +  /* state table */
 19.1286 +  for (constptr=sc_state_tab.next; constptr!=NULL; constptr=constptr->next) {
 19.1287 +    assert(strlen(constptr->name)>0);
 19.1288 +    id1=(int16_t)constptr->value;
 19.1289 +    id2=(int16_t)constptr->index;
 19.1290 +    address=(ucell)constptr->value;
 19.1291 +    #if BYTE_ORDER==BIG_ENDIAN
 19.1292 +      align16(&id1);
 19.1293 +      align16(&id2);
 19.1294 +    #endif
 19.1295 +    writeerror |= !pc_writebin(fout,&id1,sizeof id1);
 19.1296 +    writeerror |= !pc_writebin(fout,&id2,sizeof id2);
 19.1297 +    writeerror |= !pc_writebin(fout,constptr->name,strlen(constptr->name)+1);
 19.1298 +  } /* for */
 19.1299 +
 19.1300 +  delete_dbgstringtable();
 19.1301 +}
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/compiler-init/compiler-init/sc7.c	Fri Jul 14 02:02:18 2006 +0000
    20.3 @@ -0,0 +1,703 @@
    20.4 +/*  Pawn compiler - Staging buffer and optimizer
    20.5 + *
    20.6 + *  The staging buffer
    20.7 + *  ------------------
    20.8 + *  The staging buffer allows buffered output of generated code, deletion
    20.9 + *  of redundant code, optimization by a tinkering process and reversing
   20.10 + *  the ouput of evaluated expressions (which is used for the reversed
   20.11 + *  evaluation of arguments in functions).
   20.12 + *  Initially, stgwrite() writes to the file directly, but after a call to
   20.13 + *  stgset(TRUE), output is redirected to the buffer. After a call to
   20.14 + *  stgset(FALSE), stgwrite()'s output is directed to the file again. Thus
   20.15 + *  only one routine is used for writing to the output, which can be
   20.16 + *  buffered output or direct output.
   20.17 + *
   20.18 + *  staging buffer variables:   stgbuf  - the buffer
   20.19 + *                              stgidx  - current index in the staging buffer
   20.20 + *                              staging - if true, write to the staging buffer;
   20.21 + *                                        if false, write to file directly.
   20.22 + *
   20.23 + * The peephole optimizer uses a dual "pipeline". The staging buffer (described
   20.24 + * above) gets optimized for each expression or sub-expression in a function
   20.25 + * call. The peephole optimizer is recursive, but it does not span multiple
   20.26 + * sub-expressions. However, the data gets written to a second buffer that
   20.27 + * behaves much like the staging buffer. This second buffer gathers all
   20.28 + * optimized strings from the staging buffer for a complete expression. The
   20.29 + * peephole optmizer then runs over this second buffer to find optimzations
   20.30 + * across function parameter boundaries.
   20.31 + *
   20.32 + *
   20.33 + *  Copyright (c) ITB CompuPhase, 1997-2006
   20.34 + *
   20.35 + *  This software is provided "as-is", without any express or implied warranty.
   20.36 + *  In no event will the authors be held liable for any damages arising from
   20.37 + *  the use of this software.
   20.38 + *
   20.39 + *  Permission is granted to anyone to use this software for any purpose,
   20.40 + *  including commercial applications, and to alter it and redistribute it
   20.41 + *  freely, subject to the following restrictions:
   20.42 + *
   20.43 + *  1.  The origin of this software must not be misrepresented; you must not
   20.44 + *      claim that you wrote the original software. If you use this software in
   20.45 + *      a product, an acknowledgment in the product documentation would be
   20.46 + *      appreciated but is not required.
   20.47 + *  2.  Altered source versions must be plainly marked as such, and must not be
   20.48 + *      misrepresented as being the original software.
   20.49 + *  3.  This notice may not be removed or altered from any source distribution.
   20.50 + *
   20.51 + *  Version: $Id: sc7.c 3579 2006-06-06 13:35:29Z thiadmer $
   20.52 + */
   20.53 +#include <assert.h>
   20.54 +#include <stdio.h>
   20.55 +#include <stdlib.h>     /* for atoi() */
   20.56 +#include <string.h>
   20.57 +#include <ctype.h>
   20.58 +#if defined FORTIFY
   20.59 +  #include <alloc/fortify.h>
   20.60 +#endif
   20.61 +#include "sc.h"
   20.62 +
   20.63 +#if defined _MSC_VER
   20.64 +  #pragma warning(push)
   20.65 +  #pragma warning(disable:4125)  /* decimal digit terminates octal escape sequence */
   20.66 +#endif
   20.67 +
   20.68 +#include "sc7.scp"
   20.69 +
   20.70 +#if defined _MSC_VER
   20.71 +  #pragma warning(pop)
   20.72 +#endif
   20.73 +
   20.74 +static int stgstring(char *start,char *end);
   20.75 +static void stgopt(char *start,char *end,int (*outputfunc)(char *str));
   20.76 +
   20.77 +
   20.78 +#define sSTG_GROW   512
   20.79 +#define sSTG_MAX    20480
   20.80 +
   20.81 +static char *stgbuf=NULL;
   20.82 +static int stgmax=0;    /* current size of the staging buffer */
   20.83 +
   20.84 +static char *stgpipe=NULL;
   20.85 +static int pipemax=0;   /* current size of the stage pipe, a second staging buffer */
   20.86 +static int pipeidx=0;
   20.87 +
   20.88 +#define CHECK_STGBUFFER(index) if ((int)(index)>=stgmax)  grow_stgbuffer(&stgbuf, stgmax, (index)+1)
   20.89 +#define CHECK_STGPIPE(index)   if ((int)(index)>=pipemax) grow_stgbuffer(&stgpipe, pipemax, (index)+1)
   20.90 +
   20.91 +static void grow_stgbuffer(char **buffer, int curmax, int requiredsize)
   20.92 +{
   20.93 +  char *p;
   20.94 +  int clear= (*buffer==NULL); /* if previously none, empty buffer explicitly */
   20.95 +
   20.96 +  assert(curmax<requiredsize);
   20.97 +  /* if the staging buffer (holding intermediate code for one line) grows
   20.98 +   * over a few kBytes, there is probably a run-away expression
   20.99 +   */
  20.100 +  if (requiredsize>sSTG_MAX)
  20.101 +    error(102,"staging buffer");    /* staging buffer overflow (fatal error) */
  20.102 +  curmax=requiredsize+sSTG_GROW;
  20.103 +  if (*buffer!=NULL)
  20.104 +    p=(char *)realloc(*buffer,curmax*sizeof(char));
  20.105 +  else
  20.106 +    p=(char *)malloc(curmax*sizeof(char));
  20.107 +  if (p==NULL)
  20.108 +    error(102,"staging buffer");    /* staging buffer overflow (fatal error) */
  20.109 +  *buffer=p;
  20.110 +  if (clear)
  20.111 +    **buffer='\0';
  20.112 +}
  20.113 +
  20.114 +SC_FUNC void stgbuffer_cleanup(void)
  20.115 +{
  20.116 +  if (stgbuf!=NULL) {
  20.117 +    free(stgbuf);
  20.118 +    stgbuf=NULL;
  20.119 +    stgmax=0;
  20.120 +  } /* if */
  20.121 +  if (stgpipe!=NULL) {
  20.122 +    free(stgpipe);
  20.123 +    stgpipe=NULL;
  20.124 +    pipemax=0;
  20.125 +    pipeidx=0;
  20.126 +  } /* if */
  20.127 +}
  20.128 +
  20.129 +/* the variables "stgidx" and "staging" are declared in "scvars.c" */
  20.130 +
  20.131 +/*  stgmark
  20.132 + *
  20.133 + *  Copies a mark into the staging buffer. At this moment there are three
  20.134 + *  possible marks:
  20.135 + *     sSTARTREORDER    identifies the beginning of a series of expression
  20.136 + *                      strings that must be written to the output file in
  20.137 + *                      reordered order
  20.138 + *    sENDREORDER       identifies the end of 'reverse evaluation'
  20.139 + *    sEXPRSTART + idx  only valid within a block that is evaluated in
  20.140 + *                      reordered order, it identifies the start of an
  20.141 + *                      expression; the "idx" value is the argument position
  20.142 + *
  20.143 + *  Global references: stgidx  (altered)
  20.144 + *                     stgbuf  (altered)
  20.145 + *                     staging (referred to only)
  20.146 + */
  20.147 +SC_FUNC void stgmark(char mark)
  20.148 +{
  20.149 +  if (staging) {
  20.150 +    CHECK_STGBUFFER(stgidx);
  20.151 +    stgbuf[stgidx++]=mark;
  20.152 +  } /* if */
  20.153 +}
  20.154 +
  20.155 +static int rebuffer(char *str)
  20.156 +{
  20.157 +  if (sc_status==statWRITE) {
  20.158 +    if (pipeidx>=2 && stgpipe[pipeidx-1]=='\0' && stgpipe[pipeidx-2]!='\n')
  20.159 +      pipeidx-=1;                      /* overwrite last '\0' */
  20.160 +    while (*str!='\0') {               /* copy to staging buffer */
  20.161 +      CHECK_STGPIPE(pipeidx);
  20.162 +      stgpipe[pipeidx++]=*str++;
  20.163 +    } /* while */
  20.164 +    CHECK_STGPIPE(pipeidx);
  20.165 +    stgpipe[pipeidx++]='\0';
  20.166 +  } /* if */
  20.167 +  return TRUE;
  20.168 +}
  20.169 +
  20.170 +static int filewrite(char *str)
  20.171 +{
  20.172 +  if (sc_status==statWRITE)
  20.173 +    return pc_writeasm(outf,str);
  20.174 +  return TRUE;
  20.175 +}
  20.176 +
  20.177 +/*  stgwrite
  20.178 + *
  20.179 + *  Writes the string "st" to the staging buffer or to the output file. In the
  20.180 + *  case of writing to the staging buffer, the terminating byte of zero is
  20.181 + *  copied too, but... the optimizer can only work on complete lines (not on
  20.182 + *  fractions of it. Therefore if the string is staged, if the last character
  20.183 + *  written to the buffer is a '\0' and the previous-to-last is not a '\n',
  20.184 + *  the string is concatenated to the last string in the buffer (the '\0' is
  20.185 + *  overwritten). This also means an '\n' used in the middle of a string isn't
  20.186 + *  recognized and could give wrong results with the optimizer.
  20.187 + *  Even when writing to the output file directly, all strings are buffered
  20.188 + *  until a whole line is complete.
  20.189 + *
  20.190 + *  Global references: stgidx  (altered)
  20.191 + *                     stgbuf  (altered)
  20.192 + *                     staging (referred to only)
  20.193 + */
  20.194 +SC_FUNC void stgwrite(const char *st)
  20.195 +{
  20.196 +  int len;
  20.197 +
  20.198 +  if (staging) {
  20.199 +    assert(stgidx==0 || stgbuf!=NULL);  /* staging buffer must be valid if there is (apparently) something in it */
  20.200 +    if (stgidx>=2 && stgbuf[stgidx-1]=='\0' && stgbuf[stgidx-2]!='\n')
  20.201 +      stgidx-=1;                       /* overwrite last '\0' */
  20.202 +    while (*st!='\0') {                /* copy to staging buffer */
  20.203 +      CHECK_STGBUFFER(stgidx);
  20.204 +      stgbuf[stgidx++]=*st++;
  20.205 +    } /* while */
  20.206 +    CHECK_STGBUFFER(stgidx);
  20.207 +    stgbuf[stgidx++]='\0';
  20.208 +  } else {
  20.209 +    len=(stgbuf!=NULL) ? strlen(stgbuf) : 0;
  20.210 +    CHECK_STGBUFFER(len+strlen(st)+1);
  20.211 +    strcat(stgbuf,st);
  20.212 +    len=strlen(stgbuf);
  20.213 +    if (len>0 && stgbuf[len-1]=='\n') {
  20.214 +      filewrite(stgbuf);
  20.215 +      stgbuf[0]='\0';
  20.216 +    } /* if */
  20.217 +  } /* if */
  20.218 +}
  20.219 +
  20.220 +/*  stgout
  20.221 + *
  20.222 + *  Writes the staging buffer to the output file via stgstring() (for
  20.223 + *  reversing expressions in the buffer) and stgopt() (for optimizing). It
  20.224 + *  resets "stgidx".
  20.225 + *
  20.226 + *  Global references: stgidx  (altered)
  20.227 + *                     stgbuf  (referred to only)
  20.228 + *                     staging (referred to only)
  20.229 + */
  20.230 +SC_FUNC void stgout(int index)
  20.231 +{
  20.232 +  int reordered=0;
  20.233 +  int idx;
  20.234 +
  20.235 +  if (!staging)
  20.236 +    return;
  20.237 +  assert(pipeidx==0);
  20.238 +
  20.239 +  /* first pass: sub-expressions */
  20.240 +  if (sc_status==statWRITE)
  20.241 +    reordered=stgstring(&stgbuf[index],&stgbuf[stgidx]);
  20.242 +  stgidx=index;
  20.243 +
  20.244 +  /* second pass: optimize the buffer created in the first pass */
  20.245 +  if (sc_status==statWRITE) {
  20.246 +    if (reordered) {
  20.247 +      stgopt(stgpipe,stgpipe+pipeidx,filewrite);
  20.248 +    } else {
  20.249 +      /* there is no sense in re-optimizing if the order of the sub-expressions
  20.250 +       * did not change; so output directly
  20.251 +       */
  20.252 +      for (idx=0; idx<pipeidx; idx+=strlen(stgpipe+idx)+1)
  20.253 +        filewrite(stgpipe+idx);
  20.254 +    } /* if */
  20.255 +  } /* if */
  20.256 +  pipeidx=0;  /* reset second pipe */
  20.257 +}
  20.258 +
  20.259 +typedef struct {
  20.260 +  char *start,*end;
  20.261 +} argstack;
  20.262 +
  20.263 +/*  stgstring
  20.264 + *
  20.265 + *  Analyses whether code strings should be output to the file as they appear
  20.266 + *  in the staging buffer or whether portions of it should be re-ordered.
  20.267 + *  Re-ordering takes place in function argument lists; Pawn passes arguments
  20.268 + *  to functions from right to left. When arguments are "named" rather than
  20.269 + *  positional, the order in the source stream is indeterminate.
  20.270 + *  This function calls itself recursively in case it needs to re-order code
  20.271 + *  strings, and it uses a private stack (or list) to mark the start and the
  20.272 + *  end of expressions in their correct (reversed) order.
  20.273 + *  In any case, stgstring() sends a block as large as possible to the
  20.274 + *  optimizer stgopt().
  20.275 + *
  20.276 + *  In "reorder" mode, each set of code strings must start with the token
  20.277 + *  sEXPRSTART, even the first. If the token sSTARTREORDER is represented
  20.278 + *  by '[', sENDREORDER by ']' and sEXPRSTART by '|' the following applies:
  20.279 + *     '[]...'     valid, but useless; no output
  20.280 + *     '[|...]     valid, but useless; only one string
  20.281 + *     '[|...|...] valid and usefull
  20.282 + *     '[...|...]  invalid, first string doesn't start with '|'
  20.283 + *     '[|...|]    invalid
  20.284 + */
  20.285 +static int stgstring(char *start,char *end)
  20.286 +{
  20.287 +  char *ptr;
  20.288 +  int nest,argc,arg;
  20.289 +  argstack *stack;
  20.290 +  int reordered=0;
  20.291 +
  20.292 +  while (start<end) {
  20.293 +    if (*start==sSTARTREORDER) {
  20.294 +      start+=1;         /* skip token */
  20.295 +      /* allocate a argstack with sMAXARGS items */
  20.296 +      stack=(argstack *)malloc(sMAXARGS*sizeof(argstack));
  20.297 +      if (stack==NULL)
  20.298 +        error(103);     /* insufficient memory */
  20.299 +      reordered=1;      /* mark that the expression is reordered */
  20.300 +      nest=1;           /* nesting counter */
  20.301 +      argc=0;           /* argument counter */
  20.302 +      arg=-1;           /* argument index; no valid argument yet */
  20.303 +      do {
  20.304 +        switch (*start) {
  20.305 +        case sSTARTREORDER:
  20.306 +          nest++;
  20.307 +          start++;
  20.308 +          break;
  20.309 +        case sENDREORDER:
  20.310 +          nest--;
  20.311 +          start++;
  20.312 +          break;
  20.313 +        default:
  20.314 +          if ((*start & sEXPRSTART)==sEXPRSTART) {
  20.315 +            if (nest==1) {
  20.316 +              if (arg>=0)
  20.317 +                stack[arg].end=start-1; /* finish previous argument */
  20.318 +              arg=(unsigned char)*start - sEXPRSTART;
  20.319 +              stack[arg].start=start+1;
  20.320 +              if (arg>=argc)
  20.321 +                argc=arg+1;
  20.322 +            } /* if */
  20.323 +            start++;
  20.324 +          } else {
  20.325 +            start+=strlen(start)+1;
  20.326 +          } /* if */
  20.327 +        } /* switch */
  20.328 +      } while (nest); /* enddo */
  20.329 +      if (arg>=0)
  20.330 +        stack[arg].end=start-1;   /* finish previous argument */
  20.331 +      while (argc>0) {
  20.332 +        argc--;
  20.333 +        stgstring(stack[argc].start,stack[argc].end);
  20.334 +      } /* while */
  20.335 +      free(stack);
  20.336 +    } else {
  20.337 +      ptr=start;
  20.338 +      while (ptr<end && *ptr!=sSTARTREORDER)
  20.339 +        ptr+=strlen(ptr)+1;
  20.340 +      stgopt(start,ptr,rebuffer);
  20.341 +      start=ptr;
  20.342 +    } /* if */
  20.343 +  } /* while */
  20.344 +  return reordered;
  20.345 +}
  20.346 +
  20.347 +/*  stgdel
  20.348 + *
  20.349 + *  Scraps code from the staging buffer by resetting "stgidx" to "index".
  20.350 + *
  20.351 + *  Global references: stgidx (altered)
  20.352 + *                     staging (reffered to only)
  20.353 + */
  20.354 +SC_FUNC void stgdel(int index,cell code_index)
  20.355 +{
  20.356 +  if (staging) {
  20.357 +    stgidx=index;
  20.358 +    code_idx=code_index;
  20.359 +  } /* if */
  20.360 +}
  20.361 +
  20.362 +SC_FUNC int stgget(int *index,cell *code_index)
  20.363 +{
  20.364 +  if (staging) {
  20.365 +    *index=stgidx;
  20.366 +    *code_index=code_idx;
  20.367 +  } /* if */
  20.368 +  return staging;
  20.369 +}
  20.370 +
  20.371 +/*  stgset
  20.372 + *
  20.373 + *  Sets staging on or off. If it's turned off, the staging buffer must be
  20.374 + *  initialized to an empty string. If it's turned on, the routine makes sure
  20.375 + *  the index ("stgidx") is set to 0 (it should already be 0).
  20.376 + *
  20.377 + *  Global references: staging  (altered)
  20.378 + *                     stgidx   (altered)
  20.379 + *                     stgbuf   (contents altered)
  20.380 + */
  20.381 +SC_FUNC void stgset(int onoff)
  20.382 +{
  20.383 +  staging=onoff;
  20.384 +  if (staging){
  20.385 +    assert(stgidx==0);
  20.386 +    stgidx=0;
  20.387 +    CHECK_STGBUFFER(stgidx);
  20.388 +    /* write any contents that may be put in the buffer by stgwrite()
  20.389 +     * when "staging" was 0
  20.390 +     */
  20.391 +    if (strlen(stgbuf)>0)
  20.392 +      filewrite(stgbuf);
  20.393 +  } /* if */
  20.394 +  stgbuf[0]='\0';
  20.395 +}
  20.396 +
  20.397 +/* phopt_init
  20.398 + * Initialize all sequence strings of the peehole optimizer. The strings
  20.399 + * are embedded in the .EXE file in compressed format, here we expand
  20.400 + * them (and allocate memory for the sequences).
  20.401 + */
  20.402 +static SEQUENCE *sequences;
  20.403 +
  20.404 +SC_FUNC int phopt_init(void)
  20.405 +{
  20.406 +  int number, i, len;
  20.407 +  char str[160];
  20.408 +
  20.409 +  /* count number of sequences */
  20.410 +  for (number=0; sequences_cmp[number].find!=NULL; number++)
  20.411 +    /* nothing */;
  20.412 +  number++;             /* include an item for the NULL terminator */
  20.413 +
  20.414 +  if ((sequences=(SEQUENCE*)malloc(number * sizeof(SEQUENCE)))==NULL)
  20.415 +    return FALSE;
  20.416 +
  20.417 +  /* pre-initialize all to NULL (in case of failure) */
  20.418 +  for (i=0; i<number; i++) {
  20.419 +    sequences[i].find=NULL;
  20.420 +    sequences[i].replace=NULL;
  20.421 +    sequences[i].savesize=0;
  20.422 +  } /* for */
  20.423 +
  20.424 +  /* expand all strings */
  20.425 +  for (i=0; i<number-1; i++) {
  20.426 +    len = strexpand(str,(unsigned char*)sequences_cmp[i].find,sizeof str,SCPACK_TABLE);
  20.427 +    assert(len<=sizeof str);
  20.428 +    assert(len==(int)strlen(str)+1);
  20.429 +    sequences[i].find=(char*)malloc(len);
  20.430 +    if (sequences[i].find!=NULL)
  20.431 +      strcpy(sequences[i].find,str);
  20.432 +    len = strexpand(str,(unsigned char*)sequences_cmp[i].replace,sizeof str,SCPACK_TABLE);
  20.433 +    assert(len<=sizeof str);
  20.434 +    assert(len==(int)strlen(str)+1);
  20.435 +    sequences[i].replace=(char*)malloc(len);
  20.436 +    if (sequences[i].replace!=NULL)
  20.437 +      strcpy(sequences[i].replace,str);
  20.438 +    sequences[i].savesize=sequences_cmp[i].savesize;
  20.439 +    if (sequences[i].find==NULL || sequences[i].replace==NULL)
  20.440 +      return phopt_cleanup();
  20.441 +  } /* for */
  20.442 +
  20.443 +  return TRUE;
  20.444 +}
  20.445 +
  20.446 +SC_FUNC int phopt_cleanup(void)
  20.447 +{
  20.448 +  int i;
  20.449 +  if (sequences!=NULL) {
  20.450 +    i=0;
  20.451 +    while (sequences[i].find!=NULL || sequences[i].replace!=NULL) {
  20.452 +      if (sequences[i].find!=NULL)
  20.453 +        free(sequences[i].find);
  20.454 +      if (sequences[i].replace!=NULL)
  20.455 +        free(sequences[i].replace);
  20.456 +      i++;
  20.457 +    } /* while */
  20.458 +    free(sequences);
  20.459 +    sequences=NULL;
  20.460 +  } /* if */
  20.461 +  return FALSE;
  20.462 +}
  20.463 +
  20.464 +#define MAX_OPT_VARS    5
  20.465 +#define MAX_OPT_CAT     5       /* max. values that are concatenated */
  20.466 +#if sNAMEMAX > (PAWN_CELL_SIZE/4) * MAX_OPT_CAT
  20.467 +  #define MAX_ALIAS       sNAMEMAX
  20.468 +#else
  20.469 +  #define MAX_ALIAS       (PAWN_CELL_SIZE/4) * MAX_OPT_CAT
  20.470 +#endif
  20.471 +
  20.472 +static int matchsequence(char *start,char *end,char *pattern,
  20.473 +                         char symbols[MAX_OPT_VARS][MAX_ALIAS+1],
  20.474 +                         int *match_length)
  20.475 +{
  20.476 +  int var,i;
  20.477 +  char str[MAX_ALIAS+1];
  20.478 +  char *start_org=start;
  20.479 +  cell value;
  20.480 +  char *ptr;
  20.481 +
  20.482 +  *match_length=0;
  20.483 +  for (var=0; var<MAX_OPT_VARS; var++)
  20.484 +    symbols[var][0]='\0';
  20.485 +
  20.486 +  while (*start=='\t' || *start==' ')
  20.487 +    start++;
  20.488 +  while (*pattern) {
  20.489 +    if (start>=end)
  20.490 +      return FALSE;
  20.491 +    switch (*pattern) {
  20.492 +    case '%':   /* new "symbol" */
  20.493 +      pattern++;
  20.494 +      assert(isdigit(*pattern));
  20.495 +      var=atoi(pattern) - 1;
  20.496 +      assert(var>=0 && var<MAX_OPT_VARS);
  20.497 +      assert(*start=='-' || alphanum(*start));
  20.498 +      for (i=0; start<end && (*start=='-' || *start=='+' || alphanum(*start)); i++,start++) {
  20.499 +        assert(i<=MAX_ALIAS);
  20.500 +        str[i]=*start;
  20.501 +      } /* for */
  20.502 +      str[i]='\0';
  20.503 +      if (symbols[var][0]!='\0') {
  20.504 +        if (strcmp(symbols[var],str)!=0)
  20.505 +          return FALSE; /* symbols should be identical */
  20.506 +      } else {
  20.507 +        strcpy(symbols[var],str);
  20.508 +      } /* if */
  20.509 +      break;
  20.510 +    case '-':
  20.511 +      value=-strtol(pattern+1,&pattern,16);
  20.512 +      ptr=itoh((ucell)value);
  20.513 +      while (*ptr!='\0') {
  20.514 +        if (tolower(*start) != tolower(*ptr))
  20.515 +          return FALSE;
  20.516 +        start++;
  20.517 +        ptr++;
  20.518 +      } /* while */
  20.519 +      pattern--;  /* there is an increment following at the end of the loop */
  20.520 +      break;
  20.521 +    case ' ':
  20.522 +      if (*start!='\t' && *start!=' ')
  20.523 +        return FALSE;
  20.524 +      while (start<end && (*start=='\t' || *start==' '))
  20.525 +        start++;
  20.526 +      break;
  20.527 +    case '!':
  20.528 +      while (start<end && (*start=='\t' || *start==' '))
  20.529 +        start++;                /* skip trailing white space */
  20.530 +      if (*start==';')
  20.531 +        while (start<end && *start!='\n')
  20.532 +          start++;              /* skip trailing comment */
  20.533 +      if (*start!='\n')
  20.534 +        return FALSE;
  20.535 +      assert(*(start+1)=='\0');
  20.536 +      start+=2;                 /* skip '\n' and '\0' */
  20.537 +      if (*(pattern+1)!='\0')
  20.538 +        while (start<end && *start=='\t' || *start==' ')
  20.539 +          start++;              /* skip leading white space of next instruction */
  20.540 +      break;
  20.541 +    default:
  20.542 +      if (tolower(*start) != tolower(*pattern))
  20.543 +        return FALSE;
  20.544 +      start++;
  20.545 +    } /* switch */
  20.546 +    pattern++;
  20.547 +  } /* while */
  20.548 +
  20.549 +  *match_length=(int)(start-start_org);
  20.550 +  return TRUE;
  20.551 +}
  20.552 +
  20.553 +static char *replacesequence(char *pattern,char symbols[MAX_OPT_VARS][MAX_ALIAS+1],int *repl_length)
  20.554 +{
  20.555 +  char *lptr;
  20.556 +  int var;
  20.557 +  char *buffer;
  20.558 +
  20.559 +  /* calculate the length of the new buffer
  20.560 +   * this is the length of the pattern plus the length of all symbols (note
  20.561 +   * that the same symbol may occur multiple times in the pattern) plus
  20.562 +   * line endings and startings ('\t' to start a line and '\n\0' to end one)
  20.563 +   */
  20.564 +  assert(repl_length!=NULL);
  20.565 +  *repl_length=0;
  20.566 +  lptr=pattern;
  20.567 +  while (*lptr) {
  20.568 +    switch (*lptr) {
  20.569 +    case '%':
  20.570 +      lptr++;           /* skip '%' */
  20.571 +      assert(isdigit(*lptr));
  20.572 +      var=atoi(lptr) - 1;
  20.573 +      assert(var>=0 && var<MAX_OPT_VARS);
  20.574 +      assert(symbols[var][0]!='\0');    /* variable should be defined */
  20.575 +      *repl_length+=strlen(symbols[var]);
  20.576 +      break;
  20.577 +    case '!':
  20.578 +      *repl_length+=3;  /* '\t', '\n' & '\0' */
  20.579 +      break;
  20.580 +    default:
  20.581 +      *repl_length+=1;
  20.582 +    } /* switch */
  20.583 +    lptr++;
  20.584 +  } /* while */
  20.585 +
  20.586 +  /* allocate a buffer to replace the sequence in */
  20.587 +  if ((buffer=(char*)malloc(*repl_length))==NULL)
  20.588 +    return (char*)error(103);
  20.589 +
  20.590 +  /* replace the pattern into this temporary buffer */
  20.591 +  lptr=buffer;
  20.592 +  *lptr++='\t';         /* the "replace" patterns do not have tabs */
  20.593 +  while (*pattern) {
  20.594 +    assert((int)(lptr-buffer)<*repl_length);
  20.595 +    switch (*pattern) {
  20.596 +    case '%':
  20.597 +      /* write out the symbol */
  20.598 +      pattern++;
  20.599 +      assert(isdigit(*pattern));
  20.600 +      var=atoi(pattern) - 1;
  20.601 +      assert(var>=0 && var<MAX_OPT_VARS);
  20.602 +      assert(symbols[var][0]!='\0');    /* variable should be defined */
  20.603 +      strcpy(lptr,symbols[var]);
  20.604 +      lptr+=strlen(symbols[var]);
  20.605 +      break;
  20.606 +    case '!':
  20.607 +      /* finish the line, optionally start the next line with an indent */
  20.608 +      *lptr++='\n';
  20.609 +      *lptr++='\0';
  20.610 +      if (*(pattern+1)!='\0')
  20.611 +        *lptr++='\t';
  20.612 +      break;
  20.613 +    default:
  20.614 +      *lptr++=*pattern;
  20.615 +    } /* switch */
  20.616 +    pattern++;
  20.617 +  } /* while */
  20.618 +
  20.619 +  assert((int)(lptr-buffer)==*repl_length);
  20.620 +  return buffer;
  20.621 +}
  20.622 +
  20.623 +static void strreplace(char *dest,char *replace,int sub_length,int repl_length,int dest_length)
  20.624 +{
  20.625 +  int offset=sub_length-repl_length;
  20.626 +  if (offset>0) {               /* delete a section */
  20.627 +    memmove(dest,dest+offset,dest_length-offset);
  20.628 +    memset(dest+dest_length-offset,0xcc,offset); /* not needed, but for cleanlyness */
  20.629 +  } else if (offset<0) {        /* insert a section */
  20.630 +    memmove(dest-offset, dest, dest_length);
  20.631 +  } /* if */
  20.632 +  memcpy(dest, replace, repl_length);
  20.633 +}
  20.634 +
  20.635 +/*  stgopt
  20.636 + *
  20.637 + *  Optimizes the staging buffer by checking for series of instructions that
  20.638 + *  can be coded more compact. The routine expects the lines in the staging
  20.639 + *  buffer to be separated with '\n' and '\0' characters.
  20.640 + *
  20.641 + *  The longest sequences should probably be checked first.
  20.642 + */
  20.643 +
  20.644 +static void stgopt(char *start,char *end,int (*outputfunc)(char *str))
  20.645 +{
  20.646 +  char symbols[MAX_OPT_VARS][MAX_ALIAS+1];
  20.647 +  int seq,match_length,repl_length;
  20.648 +  int matches;
  20.649 +  char *debut=start;  /* save original start of the buffer */
  20.650 +
  20.651 +  assert(sequences!=NULL);
  20.652 +  /* do not match anything if debug-level is maximum */
  20.653 +  if (pc_optimize>sOPTIMIZE_NONE && sc_status==statWRITE) {
  20.654 +    do {
  20.655 +      matches=0;
  20.656 +      start=debut;
  20.657 +      while (start<end) {
  20.658 +        seq=0;
  20.659 +        while (sequences[seq].find!=NULL) {
  20.660 +          assert(seq>=0);
  20.661 +          if (*sequences[seq].find=='\0') {
  20.662 +            if (pc_optimize==sOPTIMIZE_NOMACRO) {
  20.663 +              break;    /* don't look further */
  20.664 +            } else {
  20.665 +              seq++;    /* continue with next string */
  20.666 +              continue;
  20.667 +            } /* if */
  20.668 +          } /* if */
  20.669 +          if (matchsequence(start,end,sequences[seq].find,symbols,&match_length)) {
  20.670 +            char *replace=replacesequence(sequences[seq].replace,symbols,&repl_length);
  20.671 +            /* If the replacement is bigger than the original section, we may need
  20.672 +             * to "grow" the staging buffer. This is quite complex, due to the
  20.673 +             * re-ordering of expressions that can also happen in the staging
  20.674 +             * buffer. In addition, it should not happen: the peephole optimizer
  20.675 +             * must replace sequences with *shorter* sequences, not longer ones.
  20.676 +             * So, I simply forbid sequences that are longer than the ones they
  20.677 +             * are meant to replace.
  20.678 +             */
  20.679 +            assert(match_length>=repl_length);
  20.680 +            if (match_length>=repl_length) {
  20.681 +              strreplace(start,replace,match_length,repl_length,(int)(end-start));
  20.682 +              end-=match_length-repl_length;
  20.683 +              free(replace);
  20.684 +              code_idx-=sequences[seq].savesize;
  20.685 +              seq=0;                      /* restart search for matches */
  20.686 +              matches++;
  20.687 +            } else {
  20.688 +              /* actually, we should never get here (match_length<repl_length) */
  20.689 +              assert(0);
  20.690 +              seq++;
  20.691 +            } /* if */
  20.692 +          } else {
  20.693 +            seq++;
  20.694 +          } /* if */
  20.695 +        } /* while */
  20.696 +        assert(sequences[seq].find==NULL || *sequences[seq].find=='\0' && pc_optimize==sOPTIMIZE_NOMACRO);
  20.697 +        start += strlen(start) + 1;       /* to next string */
  20.698 +      } /* while (start<end) */
  20.699 +    } while (matches>0);
  20.700 +  } /* if (pc_optimize>sOPTIMIZE_NONE && sc_status==statWRITE) */
  20.701 +
  20.702 +  for (start=debut; start<end; start+=strlen(start)+1)
  20.703 +    outputfunc(start);
  20.704 +}
  20.705 +
  20.706 +#undef SCPACK_TABLE
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/compiler-init/compiler-init/sc7.scp	Fri Jul 14 02:02:18 2006 +0000
    21.3 @@ -0,0 +1,2022 @@
    21.4 +/*  Pawn compiler - Peephole optimizer "sequences" strings (plain
    21.5 + *                   and compressed formats)
    21.6 + *
    21.7 + *  Copyright (c) ITB CompuPhase, 2000-2006
    21.8 + *
    21.9 + *  This software is provided "as-is", without any express or implied warranty.
   21.10 + *  In no event will the authors be held liable for any damages arising from
   21.11 + *  the use of this software.
   21.12 + *
   21.13 + *  Permission is granted to anyone to use this software for any purpose,
   21.14 + *  including commercial applications, and to alter it and redistribute it
   21.15 + *  freely, subject to the following restrictions:
   21.16 + *
   21.17 + *  1.  The origin of this software must not be misrepresented; you must not
   21.18 + *      claim that you wrote the original software. If you use this software in
   21.19 + *      a product, an acknowledgment in the product documentation would be
   21.20 + *      appreciated but is not required.
   21.21 + *  2.  Altered source versions must be plainly marked as such, and must not be
   21.22 + *      misrepresented as being the original software.
   21.23 + *  3.  This notice may not be removed or altered from any source distribution.
   21.24 + *
   21.25 + *  Version: $Id: sc7.sch 3577 2006-06-02 16:22:52Z thiadmer $
   21.26 + */
   21.27 +
   21.28 +SC_FUNC int strexpand(char *dest, unsigned char *source, int maxlen, unsigned char pairtable[128][2]);
   21.29 +
   21.30 +#define SCPACK_TERMINATOR ,     /* end each section with a comma */
   21.31 +
   21.32 +#define SCPACK_TABLE sequences_table
   21.33 +/*-*SCPACK start of pair table, do not change or remove this line */
   21.34 +unsigned char sequences_table[][2] = {
   21.35 +  {49,33}, {37,128}, {32,129}, {32,37}, {114,105}, {112,132}, {46,133}, {97,100}, {46,97}, {136,108}, {137,116}, {115,104}, {111,135}, {117,139}, {112,141}, {108,140},
   21.36 +  {131,50}, {144,33}, {46,115}, {138,33}, {59,36}, {134,130}, {143,146}, {115,116}, {134,145}, {110,151}, {111,153}, {99,154}, {112,147}, {135,100}, {134,33}, {114,33},
   21.37 +  {111,156}, {112,160}, {46,99}, {138,130}, {142,158}, {131,51}, {150,152}, {112,33}, {120,167}, {101,168}, {148,169}, {97,159}, {112,171}, {148,172}, {165,33}, {173,142},
   21.38 +  {122,101}, {176,114}, {101,113}, {110,100}, {149,164}, {157,114}, {33,161}, {131,49}, {103,33}, {157,33}, {104,184}, {99,186}, {120,187}, {98,111}, {118,101}, {111,190},
   21.39 +  {109,191}, {130,170}, {131,52}, {106,177}, {138,145}, {180,166}, {192,147}, {108,162}, {163,166}, {143,149}, {115,174}, {117,179}, {139,199}, {203,202}, {189,205}, {105,100},
   21.40 +  {115,103}, {115,108}, {207,120}, {195,130}, {46,135}, {178,33}, {212,114}, {204,134}, {155,149}, {142,162}, {183,145}, {150,149}, {143,152}, {194,33}, {130,175}, {97,179},
   21.41 +  {177,111}, {182,185}, {143,46}, {183,144}, {155,152}, {145,175}, {114,101}, {230,102}, {108,231}, {101,115}, {233,115}, {114,116}, {142,147}, {105,33}, {155,163}, {178,130},
   21.42 +  {215,32}, {240,50}, {143,196}, {155,197}, {181,197}, {181,200}, {108,210}, {46,98}, {241,225}, {208,235}, {209,234}, {224,158}, {143,163}, {150,163}, {155,200}
   21.43 +};
   21.44 +/*-*SCPACK end of pair table, do not change or remove this line */
   21.45 +
   21.46 +#define seqsize(o,p)    (opcodes(o)+opargs(p))
   21.47 +typedef struct {
   21.48 +  char *find;
   21.49 +  char *replace;
   21.50 +  int savesize;         /* number of bytes saved (in bytecode) */
   21.51 +} SEQUENCE;
   21.52 +static SEQUENCE sequences_cmp[] = {
   21.53 +  /* A very common sequence in four varieties
   21.54 +   *    load.s.pri n1           load.s.pri n2
   21.55 +   *    push.pri                load.s.alt n1
   21.56 +   *    load.s.pri n2           -
   21.57 +   *    pop.alt                 -
   21.58 +   *    --------------------------------------
   21.59 +   *    load.pri n1             load.s.pri n2
   21.60 +   *    push.pri                load.alt n1
   21.61 +   *    load.s.pri n2           -
   21.62 +   *    pop.alt                 -
   21.63 +   *    --------------------------------------
   21.64 +   *    load.s.pri n1           load.pri n2
   21.65 +   *    push.pri                load.s.alt n1
   21.66 +   *    load.pri n2             -
   21.67 +   *    pop.alt                 -
   21.68 +   *    --------------------------------------
   21.69 +   *    load.pri n1             load.pri n2
   21.70 +   *    push.pri                load.alt n1
   21.71 +   *    load.pri n2             -
   21.72 +   *    pop.alt                 -
   21.73 +   */
   21.74 +  {
   21.75 +    #ifdef SCPACK
   21.76 +      "load.s.pri %1!push.pri!load.s.pri %2!pop.alt!",
   21.77 +      "load.s.pri %2!load.s.alt %1!",
   21.78 +    #else
   21.79 +      "\226\305\241",
   21.80 +      "\246\375",
   21.81 +    #endif
   21.82 +    seqsize(4,2) - seqsize(2,2)
   21.83 +  },
   21.84 +  {
   21.85 +    #ifdef SCPACK
   21.86 +      "load.pri %1!push.pri!load.s.pri %2!pop.alt!",
   21.87 +      "load.s.pri %2!load.alt %1!",
   21.88 +    #else
   21.89 +      "\217\305\241",
   21.90 +      "\246\374",
   21.91 +    #endif
   21.92 +    seqsize(4,2) - seqsize(2,2)
   21.93 +  },
   21.94 +  {
   21.95 +    #ifdef SCPACK
   21.96 +      "load.s.pri %1!push.pri!load.pri %2!pop.alt!",
   21.97 +      "load.pri %2!load.s.alt %1!",
   21.98 +    #else
   21.99 +      "\226\264\334\241",
  21.100 +      "\334\375",
  21.101 +    #endif
  21.102 +    seqsize(4,2) - seqsize(2,2)
  21.103 +  },
  21.104 +  {
  21.105 +    #ifdef SCPACK
  21.106 +      "load.pri %1!push.pri!load.pri %2!pop.alt!",
  21.107 +      "load.pri %2!load.alt %1!",
  21.108 +    #else
  21.109 +      "\217\264\334\241",
  21.110 +      "\334\374",
  21.111 +    #endif
  21.112 +    seqsize(4,2) - seqsize(2,2)
  21.113 +  },
  21.114 +  /* (#1#) The above also occurs with "addr.pri" (array
  21.115 +   * indexing) as the first line; so that adds 2 cases.
  21.116 +   */
  21.117 +  {
  21.118 +    #ifdef SCPACK
  21.119 +      "addr.pri %1!push.pri!load.s.pri %2!pop.alt!",
  21.120 +      "addr.alt %1!load.s.pri %2!",
  21.121 +    #else
  21.122 +      "\364\241",
  21.123 +      "\365",
  21.124 +    #endif
  21.125 +    seqsize(4,2) - seqsize(2,2)
  21.126 +  },
  21.127 +  {
  21.128 +    #ifdef SCPACK
  21.129 +      "addr.pri %1!push.pri!load.pri %2!pop.alt!",
  21.130 +      "addr.alt %1!load.pri %2!",
  21.131 +    #else
  21.132 +      "\265\264\334\241",
  21.133 +      "\265\243\334",
  21.134 +    #endif
  21.135 +    seqsize(4,2) - seqsize(2,2)
  21.136 +  },
  21.137 +  /* And the same sequence with const.pri as either the first
  21.138 +   * or the second load instruction: four more cases.
  21.139 +   */
  21.140 +  {
  21.141 +    #ifdef SCPACK
  21.142 +      "const.pri %1!push.pri!load.s.pri %2!pop.alt!",
  21.143 +      "load.s.pri %2!const.alt %1!",
  21.144 +    #else
  21.145 +      "\363\241",
  21.146 +      "\246\356",
  21.147 +    #endif
  21.148 +    seqsize(4,2) - seqsize(2,2)
  21.149 +  },
  21.150 +  {
  21.151 +    #ifdef SCPACK
  21.152 +      "const.pri %1!push.pri!load.pri %2!pop.alt!",
  21.153 +      "load.pri %2!const.alt %1!",
  21.154 +    #else
  21.155 +      "\233\264\334\241",
  21.156 +      "\334\356",
  21.157 +    #endif
  21.158 +    seqsize(4,2) - seqsize(2,2)
  21.159 +  },
  21.160 +  {
  21.161 +    #ifdef SCPACK
  21.162 +      "load.s.pri %1!push.pri!const.pri %2!pop.alt!",
  21.163 +      "const.pri %2!load.s.alt %1!",
  21.164 +    #else
  21.165 +      "\226\264\344\241",
  21.166 +      "\344\375",
  21.167 +    #endif
  21.168 +    seqsize(4,2) - seqsize(2,2)
  21.169 +  },
  21.170 +  {
  21.171 +    #ifdef SCPACK
  21.172 +      "load.pri %1!push.pri!const.pri %2!pop.alt!",
  21.173 +      "const.pri %2!load.alt %1!",
  21.174 +    #else
  21.175 +      "\217\264\344\241",
  21.176 +      "\344\374",
  21.177 +    #endif
  21.178 +    seqsize(4,2) - seqsize(2,2)
  21.179 +  },
  21.180 +  /* The same as above, but now with "addr.pri" (array
  21.181 +   * indexing) on the first line and const.pri on
  21.182 +   * the second.
  21.183 +   */
  21.184 +  {
  21.185 +    #ifdef SCPACK
  21.186 +      "addr.pri %1!push.pri!const.pri %2!pop.alt!",
  21.187 +      "addr.alt %1!const.pri %2!",
  21.188 +    #else
  21.189 +      "\265\264\344\241",
  21.190 +      "\265\243\344",
  21.191 +    #endif
  21.192 +    seqsize(4,2) - seqsize(2,2)
  21.193 +  },
  21.194 +  {
  21.195 +    #ifdef SCPACK
  21.196 +      "addr.pri %1!push.pri!zero.pri!pop.alt!",
  21.197 +      "addr.alt %1!zero.pri!",
  21.198 +    #else
  21.199 +      "\265\264\373\241",
  21.200 +      "\265\243\373",
  21.201 +    #endif
  21.202 +    seqsize(4,1) - seqsize(2,1)
  21.203 +  },
  21.204 +  /* ??? add references */
  21.205 +  /* Chained relational operators can contain sequences like:
  21.206 +   *    move.pri                load.s.pri n1
  21.207 +   *    push.pri                -
  21.208 +   *    load.s.pri n1           -
  21.209 +   *    pop.alt                 -
  21.210 +   * The above also accurs for "load.pri" and for "const.pri",
  21.211 +   * so add another two cases.
  21.212 +   */
  21.213 +  {
  21.214 +    #ifdef SCPACK
  21.215 +      "move.pri!push.pri!load.s.pri %1!pop.alt!",
  21.216 +      "load.s.pri %1!",
  21.217 +    #else
  21.218 +      "\300\236\244\333\241",
  21.219 +      "\333",
  21.220 +    #endif
  21.221 +    seqsize(4,1) - seqsize(1,1)
  21.222 +  },
  21.223 +  {
  21.224 +    #ifdef SCPACK
  21.225 +      "move.pri!push.pri!load.pri %1!pop.alt!",
  21.226 +      "load.pri %1!",
  21.227 +    #else
  21.228 +      "\300\236\244\311\241",
  21.229 +      "\311",
  21.230 +    #endif
  21.231 +    seqsize(4,1) - seqsize(1,1)
  21.232 +  },
  21.233 +  {
  21.234 +    #ifdef SCPACK
  21.235 +      "move.pri!push.pri!const.pri %1!pop.alt!",
  21.236 +      "const.pri %1!",
  21.237 +    #else
  21.238 +      "\300\236\244\330\241",
  21.239 +      "\330",
  21.240 +    #endif
  21.241 +    seqsize(4,1) - seqsize(1,1)
  21.242 +  },
  21.243 +  /* More optimizations for chained relational operators; the
  21.244 +   * continuation sequences can be simplified if they turn out
  21.245 +   * to be termination sequences:
  21.246 +   *    xchg                    sless       also for sless, sgeq and sleq
  21.247 +   *    sgrtr                   pop.alt
  21.248 +   *    swap.alt                and
  21.249 +   *    and                     ;$exp
  21.250 +   *    pop.alt                 -
  21.251 +   *    ;$exp                   -
  21.252 +   *    --------------------------------------
  21.253 +   *    xchg                    sless       also for sless, sgeq and sleq
  21.254 +   *    sgrtr                   pop.alt
  21.255 +   *    swap.alt                and
  21.256 +   *    and                     jzer n1
  21.257 +   *    pop.alt                 -
  21.258 +   *    jzer n1                 -
  21.259 +   *    --------------------------------------
  21.260 +   *    xchg                    jsgeq  n1   also for sless, sgeq and sleq
  21.261 +   *    sgrtr                   ;$exp       (occurs for non-chained comparisons)
  21.262 +   *    jzer n1                 -
  21.263 +   *    ;$exp                   -
  21.264 +   *    --------------------------------------
  21.265 +   *    xchg                    sless       also for sless, sgeq and sleq
  21.266 +   *    sgrtr                   ;$exp       (occurs for non-chained comparisons)
  21.267 +   *    ;$exp                   -
  21.268 +   */
  21.269 +  {
  21.270 +    #ifdef SCPACK
  21.271 +      "xchg!sgrtr!swap.alt!and!pop.alt!;$exp!",
  21.272 +      "sless!pop.alt!and!;$exp!",
  21.273 +    #else
  21.274 +      "\274\371\237swa\234\337\266\252",
  21.275 +      "\372\266\337!\252",
  21.276 +    #endif
  21.277 +    seqsize(5,0) - seqsize(3,0)
  21.278 +  },
  21.279 +  {
  21.280 +    #ifdef SCPACK
  21.281 +      "xchg!sless!swap.alt!and!pop.alt!;$exp!",
  21.282 +      "sgrtr!pop.alt!and!;$exp!",
  21.283 +    #else
  21.284 +      "\274\372!swa\234\337\266\252",
  21.285 +      "\371\237\241\337!\252",
  21.286 +    #endif
  21.287 +    seqsize(5,0) - seqsize(3,0)
  21.288 +  },
  21.289 +  {
  21.290 +    #ifdef SCPACK
  21.291 +      "xchg!sgeq!swap.alt!and!pop.alt!;$exp!",
  21.292 +      "sleq!pop.alt!and!;$exp!",
  21.293 +    #else
  21.294 +      "\274\320\325swa\234\337\266\252",
  21.295 +      "\321\262\266\337!\252",
  21.296 +    #endif
  21.297 +    seqsize(5,0) - seqsize(3,0)
  21.298 +  },
  21.299 +  {
  21.300 +    #ifdef SCPACK
  21.301 +      "xchg!sleq!swap.alt!and!pop.alt!;$exp!",
  21.302 +      "sgeq!pop.alt!and!;$exp!",
  21.303 +    #else
  21.304 +      "\274\321\325swa\234\337\266\252",
  21.305 +      "\320\262\266\337!\252",
  21.306 +    #endif
  21.307 +    seqsize(5,0) - seqsize(3,0)
  21.308 +  },
  21.309 +  {
  21.310 +    #ifdef SCPACK
  21.311 +      "xchg!sgrtr!swap.alt!and!pop.alt!jzer %1!",
  21.312 +      "sless!pop.alt!and!jzer %1!",
  21.313 +    #else
  21.314 +      "\274\371\237swa\234\337\266\323",
  21.315 +      "\372\266\337!\323",
  21.316 +    #endif
  21.317 +    seqsize(5,0) - seqsize(3,0)
  21.318 +  },
  21.319 +  {
  21.320 +    #ifdef SCPACK
  21.321 +      "xchg!sless!swap.alt!and!pop.alt!jzer %1!",
  21.322 +      "sgrtr!pop.alt!and!jzer %1!",
  21.323 +    #else
  21.324 +      "\274\372!swa\234\337\266\323",
  21.325 +      "\371\237\241\337!\323",
  21.326 +    #endif
  21.327 +    seqsize(5,0) - seqsize(3,0)
  21.328 +  },
  21.329 +  {
  21.330 +    #ifdef SCPACK
  21.331 +      "xchg!sgeq!swap.alt!and!pop.alt!jzer %1!",
  21.332 +      "sleq!pop.alt!and!jzer %1!",
  21.333 +    #else
  21.334 +      "\274\320\325swa\234\337\266\323",
  21.335 +      "\321\262\266\337!\323",
  21.336 +    #endif
  21.337 +    seqsize(5,0) - seqsize(3,0)
  21.338 +  },
  21.339 +  {
  21.340 +    #ifdef SCPACK
  21.341 +      "xchg!sleq!swap.alt!and!pop.alt!jzer %1!",
  21.342 +      "sgeq!pop.alt!and!jzer %1!",
  21.343 +    #else
  21.344 +      "\274\321\325swa\234\337\266\323",
  21.345 +      "\320\262\266\337!\323",
  21.346 +    #endif
  21.347 +    seqsize(5,0) - seqsize(3,0)
  21.348 +  },
  21.349 +  {
  21.350 +    #ifdef SCPACK
  21.351 +      "xchg!sgrtr!jzer %1!;$exp!",
  21.352 +      "jsgeq %1!;$exp!",
  21.353 +    #else
  21.354 +      "\274\371\237\303\301",
  21.355 +      "j\320\262\301",
  21.356 +    #endif
  21.357 +    seqsize(3,1) - seqsize(1,1)
  21.358 +  },
  21.359 +  {
  21.360 +    #ifdef SCPACK
  21.361 +      "xchg!sless!jzer %1!;$exp!",
  21.362 +      "jsleq %1!;$exp!",
  21.363 +    #else
  21.364 +      "\274\372!\303\301",
  21.365 +      "j\321\262\301",
  21.366 +    #endif
  21.367 +    seqsize(3,1) - seqsize(1,1)
  21.368 +  },
  21.369 +  {
  21.370 +    #ifdef SCPACK
  21.371 +      "xchg!sgeq!jzer %1!;$exp!",
  21.372 +      "jsgrtr %1!;$exp!",
  21.373 +    #else
  21.374 +      "\274\320\325\303\301",
  21.375 +      "j\371r\301",
  21.376 +    #endif
  21.377 +    seqsize(3,1) - seqsize(1,1)
  21.378 +  },
  21.379 +  {
  21.380 +    #ifdef SCPACK
  21.381 +      "xchg!sleq!jzer %1!;$exp!",
  21.382 +      "jsless %1!;$exp!",
  21.383 +    #else
  21.384 +      "\274\321\325\303\301",
  21.385 +      "j\372\301",
  21.386 +    #endif
  21.387 +    seqsize(3,1) - seqsize(1,1)
  21.388 +  },
  21.389 +  {
  21.390 +    #ifdef SCPACK
  21.391 +      "xchg!sgrtr!;$exp!",
  21.392 +      "sless!;$exp!",
  21.393 +    #else
  21.394 +      "\274\371\237\252",
  21.395 +      "\372!\252",
  21.396 +    #endif
  21.397 +    seqsize(2,0) - seqsize(1,0)
  21.398 +  },
  21.399 +  {
  21.400 +    #ifdef SCPACK
  21.401 +      "xchg!sless!;$exp!",
  21.402 +      "sgrtr!;$exp!",
  21.403 +    #else
  21.404 +      "\274\372!\252",
  21.405 +      "\371\237\252",
  21.406 +    #endif
  21.407 +    seqsize(2,0) - seqsize(1,0)
  21.408 +  },
  21.409 +  {
  21.410 +    #ifdef SCPACK
  21.411 +      "xchg!sgeq!;$exp!",
  21.412 +      "sleq!;$exp!",
  21.413 +    #else
  21.414 +      "\274\320\325\252",
  21.415 +      "\321\325\252",
  21.416 +    #endif
  21.417 +    seqsize(2,0) - seqsize(1,0)
  21.418 +  },
  21.419 +  {
  21.420 +    #ifdef SCPACK
  21.421 +      "xchg!sleq!;$exp!",
  21.422 +      "sgeq!;$exp!",
  21.423 +    #else
  21.424 +      "\274\321\325\252",
  21.425 +      "\320\325\252",
  21.426 +    #endif
  21.427 +    seqsize(2,0) - seqsize(1,0)
  21.428 +  },
  21.429 +  /* The entry to chained operators is also opt to optimization
  21.430 +   *    load.s.pri n1           load.s.pri n2
  21.431 +   *    load.s.alt n2           load.s.alt n1
  21.432 +   *    xchg                    -
  21.433 +   *    --------------------------------------
  21.434 +   *    load.s.pri n1           load.pri n2
  21.435 +   *    load.alt n2             load.s.alt n1
  21.436 +   *    xchg                    -
  21.437 +   *    --------------------------------------
  21.438 +   *    load.s.pri n1           const.pri n2
  21.439 +   *    const.alt n2            load.s.alt n1
  21.440 +   *    xchg                    -
  21.441 +   *    --------------------------------------
  21.442 +   * and all permutations...
  21.443 +   */
  21.444 +  {
  21.445 +    #ifdef SCPACK
  21.446 +      "load.s.pri %1!load.s.alt %2!xchg!",
  21.447 +      "load.s.pri %2!load.s.alt %1!",
  21.448 +    #else
  21.449 +      "\333\226\304\274",
  21.450 +      "\246\375",
  21.451 +    #endif
  21.452 +    seqsize(3,2) - seqsize(2,2)
  21.453 +  },
  21.454 +  {
  21.455 +    #ifdef SCPACK
  21.456 +      "load.s.pri %1!load.alt %2!xchg!",
  21.457 +      "load.pri %2!load.s.alt %1!",
  21.458 +    #else
  21.459 +      "\333\362\274",
  21.460 +      "\334\375",
  21.461 +    #endif
  21.462 +    seqsize(3,2) - seqsize(2,2)
  21.463 +  },
  21.464 +  {
  21.465 +    #ifdef SCPACK
  21.466 +      "load.s.pri %1!const.alt %2!xchg!",
  21.467 +      "const.pri %2!load.s.alt %1!",
  21.468 +    #else
  21.469 +      "\333\233\304\274",
  21.470 +      "\344\375",
  21.471 +    #endif
  21.472 +    seqsize(3,2) - seqsize(2,2)
  21.473 +  },
  21.474 +  {
  21.475 +    #ifdef SCPACK
  21.476 +      "load.pri %1!load.s.alt %2!xchg!",
  21.477 +      "load.s.pri %2!load.alt %1!",
  21.478 +    #else
  21.479 +      "\311\226\304\274",
  21.480 +      "\246\374",
  21.481 +    #endif
  21.482 +    seqsize(3,2) - seqsize(2,2)
  21.483 +  },
  21.484 +  {
  21.485 +    #ifdef SCPACK
  21.486 +      "load.pri %1!load.alt %2!xchg!",
  21.487 +      "load.pri %2!load.alt %1!",
  21.488 +    #else
  21.489 +      "\311\362\274",
  21.490 +      "\334\374",
  21.491 +    #endif
  21.492 +    seqsize(3,2) - seqsize(2,2)
  21.493 +  },
  21.494 +  {
  21.495 +    #ifdef SCPACK
  21.496 +      "load.pri %1!const.alt %2!xchg!",
  21.497 +      "const.pri %2!load.alt %1!",
  21.498 +    #else
  21.499 +      "\311\233\304\274",
  21.500 +      "\344\374",
  21.501 +    #endif
  21.502 +    seqsize(3,2) - seqsize(2,2)
  21.503 +  },
  21.504 +  {
  21.505 +    #ifdef SCPACK
  21.506 +      "const.pri %1!load.s.alt %2!xchg!",
  21.507 +      "load.s.pri %2!const.alt %1!",
  21.508 +    #else
  21.509 +      "\330\226\304\274",
  21.510 +      "\246\356",
  21.511 +    #endif
  21.512 +    seqsize(3,2) - seqsize(2,2)
  21.513 +  },
  21.514 +  {
  21.515 +    #ifdef SCPACK
  21.516 +      "const.pri %1!load.alt %2!xchg!",
  21.517 +      "load.pri %2!const.alt %1!",
  21.518 +    #else
  21.519 +      "\330\362\274",
  21.520 +      "\334\356",
  21.521 +    #endif
  21.522 +    seqsize(3,2) - seqsize(2,2)
  21.523 +  },
  21.524 +  /* some sequences where PRI is moved to ALT can be optimized
  21.525 +   * further when considering what follows
  21.526 +   *    move.alt                const.alt n1
  21.527 +   *    const.pri %1            -
  21.528 +   *    xchg                    -
  21.529 +   * (also for load.s.pri and load.pri)
  21.530 +   *    --------------------------------------
  21.531 +   *    lref.pri %1             lref.alt %1
  21.532 +   *    move.alt                [load.pri %2]
  21.533 +   *    [load.pri %2]           -
  21.534 +   * (where [load.pri %2] may also be another operatrion loading PRI)
  21.535 +   */
  21.536 +  {
  21.537 +    #ifdef SCPACK
  21.538 +      "move.alt!const.pri %1!xchg!",
  21.539 +      "const.alt %1!",
  21.540 +    #else
  21.541 +      "\306\330\274",
  21.542 +      "\356",
  21.543 +    #endif
  21.544 +    seqsize(3,1) - seqsize(1,1)
  21.545 +  },
  21.546 +  {
  21.547 +    #ifdef SCPACK
  21.548 +      "move.alt!load.pri %1!xchg!",
  21.549 +      "load.alt %1!",
  21.550 +    #else
  21.551 +      "\306\311\274",
  21.552 +      "\374",
  21.553 +    #endif
  21.554 +    seqsize(3,1) - seqsize(1,1)
  21.555 +  },
  21.556 +  {
  21.557 +    #ifdef SCPACK
  21.558 +      "move.alt!load.s.pri %1!xchg!",
  21.559 +      "load.s.alt %1!",
  21.560 +    #else
  21.561 +      "\306\333\274",
  21.562 +      "\375",
  21.563 +    #endif
  21.564 +    seqsize(3,1) - seqsize(1,1)
  21.565 +  },
  21.566 +  /* ----- */
  21.567 +  {
  21.568 +    #ifdef SCPACK
  21.569 +      "lref.pri %1!move.alt!load.pri %2!",
  21.570 +      "lref.alt %1!load.pri %2!",
  21.571 +    #else
  21.572 +      "\350\225\306\334",
  21.573 +      "\350\243\334",
  21.574 +    #endif
  21.575 +    seqsize(3,2) - seqsize(2,2)
  21.576 +  },
  21.577 +  {
  21.578 +    #ifdef SCPACK
  21.579 +      "lref.pri %1!move.alt!load.s.pri %2!",
  21.580 +      "lref.alt %1!load.s.pri %2!",
  21.581 +    #else
  21.582 +      "\350\225\306\246",
  21.583 +      "\350\310",
  21.584 +    #endif
  21.585 +    seqsize(3,2) - seqsize(2,2)
  21.586 +  },
  21.587 +  {
  21.588 +    #ifdef SCPACK
  21.589 +      "lref.pri %1!move.alt!const.pri %2!",
  21.590 +      "lref.alt %1!const.pri %2!",
  21.591 +    #else
  21.592 +      "\350\225\306\344",
  21.593 +      "\350\243\344",
  21.594 +    #endif
  21.595 +    seqsize(3,2) - seqsize(2,2)
  21.596 +  },
  21.597 +  {
  21.598 +    #ifdef SCPACK
  21.599 +      "lref.s.pri %1!move.alt!load.pri %2!",
  21.600 +      "lref.s.alt %1!load.pri %2!",
  21.601 +    #else
  21.602 +      "\350\222\225\306\334",
  21.603 +      "\350\222\243\334",
  21.604 +    #endif
  21.605 +    seqsize(3,2) - seqsize(2,2)
  21.606 +  },
  21.607 +  {
  21.608 +    #ifdef SCPACK
  21.609 +      "lref.s.pri %1!move.alt!load.s.pri %2!",
  21.610 +      "lref.s.alt %1!load.s.pri %2!",
  21.611 +    #else
  21.612 +      "\350\222\225\306\246",
  21.613 +      "\350\222\310",
  21.614 +    #endif
  21.615 +    seqsize(3,2) - seqsize(2,2)
  21.616 +  },
  21.617 +  {
  21.618 +    #ifdef SCPACK
  21.619 +      "lref.s.pri %1!move.alt!const.pri %2!",
  21.620 +      "lref.s.alt %1!const.pri %2!",
  21.621 +    #else
  21.622 +      "\350\222\225\306\344",
  21.623 +      "\350\222\243\344",
  21.624 +    #endif
  21.625 +    seqsize(3,2) - seqsize(2,2)
  21.626 +  },
  21.627 +  /* Array indexing can merit from special instructions.
  21.628 +   * Simple indexed array lookup can be optimized quite
  21.629 +   * a bit.
  21.630 +   *    addr.pri n1             addr.alt n1
  21.631 +   *    push.pri                load.s.pri n2
  21.632 +   *    load.s.pri n2           bounds n3
  21.633 +   *    bounds n3               lidx.b n4
  21.634 +   *    shl.c.pri n4            -
  21.635 +   *    pop.alt                 -
  21.636 +   *    add                     -
  21.637 +   *    load.i                  -
  21.638 +   *
  21.639 +   * And to prepare for storing a value in an array
  21.640 +   *    addr.pri n1             addr.alt n1
  21.641 +   *    push.pri                load.s.pri n2
  21.642 +   *    load.s.pri n2           bounds n3
  21.643 +   *    bounds n3               idxaddr.b n4
  21.644 +   *    shl.c.pri n4            -
  21.645 +   *    pop.alt                 -
  21.646 +   *    add                     -
  21.647 +   *
  21.648 +   * Notes (additional cases):
  21.649 +   * 1. instruction addr.pri can also be const.pri (for
  21.650 +   *    global arrays)
  21.651 +   * 2. the bounds instruction can be absent
  21.652 +   * 3. when "n4" (the shift value) is the 2 (with 32-bit cells), use the
  21.653 +   *    even more optimal instructions LIDX and IDDXADDR
  21.654 +   *
  21.655 +   * If the array index is more complex, one can only optimize
  21.656 +   * the last four instructions:
  21.657 +   *    shl.c.pri n1            pop.alt
  21.658 +   *    pop.alt                 lidx.b n1
  21.659 +   *    add                     -
  21.660 +   *    loadi                   -
  21.661 +   *    --------------------------------------
  21.662 +   *    shl.c.pri n1            pop.alt
  21.663 +   *    pop.alt                 idxaddr.b n1
  21.664 +   *    add                     -
  21.665 +   */
  21.666 +#if !defined BIT16
  21.667 +  /* loading from array, "cell" shifted */
  21.668 +  {
  21.669 +    #ifdef SCPACK
  21.670 +      "addr.pri %1!push.pri!load.s.pri %2!bounds %3!shl.c.pri 2!pop.alt!add!load.i!",
  21.671 +      "addr.alt %1!load.s.pri %2!bounds %3!lidx!",
  21.672 +    #else
  21.673 +      "\364\316\370\342\355",
  21.674 +      "\365\316\366!",
  21.675 +    #endif
  21.676 +    seqsize(8,4) - seqsize(4,3)
  21.677 +  },
  21.678 +  {
  21.679 +    #ifdef SCPACK
  21.680 +      "const.pri %1!push.pri!load.s.pri %2!bounds %3!shl.c.pri 2!pop.alt!add!load.i!",
  21.681 +      "const.alt %1!load.s.pri %2!bounds %3!lidx!",
  21.682 +    #else
  21.683 +      "\363\316\370\342\355",
  21.684 +      "\376\316\366!",
  21.685 +    #endif
  21.686 +    seqsize(8,4) - seqsize(4,3)
  21.687 +  },
  21.688 +  {
  21.689 +    #ifdef SCPACK
  21.690 +      "addr.pri %1!push.pri!load.s.pri %2!shl.c.pri 2!pop.alt!add!load.i!",
  21.691 +      "addr.alt %1!load.s.pri %2!lidx!",
  21.692 +    #else
  21.693 +      "\364\370\342\355",
  21.694 +      "\365\366!",
  21.695 +    #endif
  21.696 +    seqsize(7,3) - seqsize(3,2)
  21.697 +  },
  21.698 +  {
  21.699 +    #ifdef SCPACK
  21.700 +      "const.pri %1!push.pri!load.s.pri %2!shl.c.pri 2!pop.alt!add!load.i!",
  21.701 +      "const.alt %1!load.s.pri %2!lidx!",
  21.702 +    #else
  21.703 +      "\363\370\342\355",
  21.704 +      "\376\366!",
  21.705 +    #endif
  21.706 +    seqsize(7,3) - seqsize(3,2)
  21.707 +  },
  21.708 +#endif
  21.709 +  /* loading from array, not "cell" shifted */
  21.710 +  {
  21.711 +    #ifdef SCPACK
  21.712 +      "addr.pri %1!push.pri!load.s.pri %2!bounds %3!shl.c.pri %4!pop.alt!add!load.i!",
  21.713 +      "addr.alt %1!load.s.pri %2!bounds %3!lidx.b %4!",
  21.714 +    #else
  21.715 +      "\364\316\327\302\341\342\355",
  21.716 +      "\365\316\366\367\335",
  21.717 +    #endif
  21.718 +    seqsize(8,4) - seqsize(4,4)
  21.719 +  },
  21.720 +  {
  21.721 +    #ifdef SCPACK
  21.722 +      "const.pri %1!push.pri!load.s.pri %2!bounds %3!shl.c.pri %4!pop.alt!add!load.i!",
  21.723 +      "const.alt %1!load.s.pri %2!bounds %3!lidx.b %4!",
  21.724 +    #else
  21.725 +      "\363\316\327\302\341\342\355",
  21.726 +      "\376\316\366\367\335",
  21.727 +    #endif
  21.728 +    seqsize(8,4) - seqsize(4,4)
  21.729 +  },
  21.730 +  {
  21.731 +    #ifdef SCPACK
  21.732 +      "addr.pri %1!push.pri!load.s.pri %2!shl.c.pri %3!pop.alt!add!load.i!",
  21.733 +      "addr.alt %1!load.s.pri %2!lidx.b %3!",
  21.734 +    #else
  21.735 +      "\364\327\256\241\271\342\355",
  21.736 +      "\365\366\367\256",
  21.737 +    #endif
  21.738 +    seqsize(7,3) - seqsize(3,3)
  21.739 +  },
  21.740 +  {
  21.741 +    #ifdef SCPACK
  21.742 +      "const.pri %1!push.pri!load.s.pri %2!shl.c.pri %3!pop.alt!add!load.i!",
  21.743 +      "const.alt %1!load.s.pri %2!lidx.b %3!",
  21.744 +    #else
  21.745 +      "\363\327\256\241\271\342\355",
  21.746 +      "\376\366\367\256",
  21.747 +    #endif
  21.748 +    seqsize(7,3) - seqsize(3,3)
  21.749 +  },
  21.750 +#if !defined BIT16
  21.751 +  /* array index calculation for storing a value, "cell" aligned */
  21.752 +  {
  21.753 +    #ifdef SCPACK
  21.754 +      "addr.pri %1!push.pri!load.s.pri %2!bounds %3!shl.c.pri 2!pop.alt!add!",
  21.755 +      "addr.alt %1!load.s.pri %2!bounds %3!idxaddr!",
  21.756 +    #else
  21.757 +      "\364\316\370",
  21.758 +      "\365\316\322\235\237",
  21.759 +    #endif
  21.760 +    seqsize(7,4) - seqsize(4,3)
  21.761 +  },
  21.762 +  {
  21.763 +    #ifdef SCPACK
  21.764 +      "const.pri %1!push.pri!load.s.pri %2!bounds %3!shl.c.pri 2!pop.alt!add!",
  21.765 +      "const.alt %1!load.s.pri %2!bounds %3!idxaddr!",
  21.766 +    #else
  21.767 +      "\363\316\370",
  21.768 +      "\376\316\322\235\237",
  21.769 +    #endif
  21.770 +    seqsize(7,4) - seqsize(4,3)
  21.771 +  },
  21.772 +  {
  21.773 +    #ifdef SCPACK
  21.774 +      "addr.pri %1!push.pri!load.s.pri %2!shl.c.pri 2!pop.alt!add!",
  21.775 +      "addr.alt %1!load.s.pri %2!idxaddr!",
  21.776 +    #else
  21.777 +      "\364\370",
  21.778 +      "\365\322\235\237",
  21.779 +    #endif
  21.780 +    seqsize(6,3) - seqsize(3,2)
  21.781 +  },
  21.782 +  {
  21.783 +    #ifdef SCPACK
  21.784 +      "const.pri %1!push.pri!load.s.pri %2!shl.c.pri 2!pop.alt!add!",
  21.785 +      "const.alt %1!load.s.pri %2!idxaddr!",
  21.786 +    #else
  21.787 +      "\363\370",
  21.788 +      "\376\322\235\237",
  21.789 +    #endif
  21.790 +    seqsize(6,3) - seqsize(3,2)
  21.791 +  },
  21.792 +#endif
  21.793 +  /* array index calculation for storing a value, not "cell" packed */
  21.794 +  {
  21.795 +    #ifdef SCPACK
  21.796 +      "addr.pri %1!push.pri!load.s.pri %2!bounds %3!shl.c.pri %4!pop.alt!add!",
  21.797 +      "addr.alt %1!load.s.pri %2!bounds %3!idxaddr.b %4!",
  21.798 +    #else
  21.799 +      "\364\316\327\302\341",
  21.800 +      "\365\316\322\265\367\335",
  21.801 +    #endif
  21.802 +    seqsize(7,4) - seqsize(4,4)
  21.803 +  },
  21.804 +  {
  21.805 +    #ifdef SCPACK
  21.806 +      "const.pri %1!push.pri!load.s.pri %2!bounds %3!shl.c.pri %4!pop.alt!add!",
  21.807 +      "const.alt %1!load.s.pri %2!bounds %3!idxaddr.b %4!",
  21.808 +    #else
  21.809 +      "\363\316\327\302\341",
  21.810 +      "\376\316\322\265\367\335",
  21.811 +    #endif
  21.812 +    seqsize(7,4) - seqsize(4,4)
  21.813 +  },
  21.814 +  {
  21.815 +    #ifdef SCPACK
  21.816 +      "addr.pri %1!push.pri!load.s.pri %2!shl.c.pri %3!pop.alt!add!",
  21.817 +      "addr.alt %1!load.s.pri %2!idxaddr.b %3!",
  21.818 +    #else
  21.819 +      "\364\327\256\241\271",
  21.820 +      "\365\322\265\367\256",
  21.821 +    #endif
  21.822 +    seqsize(6,3) - seqsize(3,3)
  21.823 +  },
  21.824 +  {
  21.825 +    #ifdef SCPACK
  21.826 +      "const.pri %1!push.pri!load.s.pri %2!shl.c.pri %3!pop.alt!add!",
  21.827 +      "const.alt %1!load.s.pri %2!idxaddr.b %3!",
  21.828 +    #else
  21.829 +      "\363\327\256\241\271",
  21.830 +      "\376\322\265\367\256",
  21.831 +    #endif
  21.832 +    seqsize(6,3) - seqsize(3,3)
  21.833 +  },
  21.834 +#if !defined BIT16
  21.835 +  /* the shorter array indexing sequences, see above for comments */
  21.836 +  {
  21.837 +    #ifdef SCPACK
  21.838 +      "shl.c.pri 2!pop.alt!add!loadi!",
  21.839 +      "pop.alt!lidx!",
  21.840 +    #else
  21.841 +      "\370\217\355",
  21.842 +      "\241\366!",
  21.843 +    #endif
  21.844 +    seqsize(4,1) - seqsize(2,0)
  21.845 +  },
  21.846 +  {
  21.847 +    #ifdef SCPACK
  21.848 +      "shl.c.pri 2!pop.alt!add!",
  21.849 +      "pop.alt!idxaddr!",
  21.850 +    #else
  21.851 +      "\370",
  21.852 +      "\241\322\235\237",
  21.853 +    #endif
  21.854 +    seqsize(3,1) - seqsize(2,0)
  21.855 +  },
  21.856 +#endif
  21.857 +  {
  21.858 +    #ifdef SCPACK
  21.859 +      "shl.c.pri %1!pop.alt!add!loadi!",
  21.860 +      "pop.alt!lidx.b %1!",
  21.861 +    #else
  21.862 +      "\314\225\241\271\217\355",
  21.863 +      "\241\366\367\202",
  21.864 +    #endif
  21.865 +    seqsize(4,1) - seqsize(2,1)
  21.866 +  },
  21.867 +  {
  21.868 +    #ifdef SCPACK
  21.869 +      "shl.c.pri %1!pop.alt!add!",
  21.870 +      "pop.alt!idxaddr.b %1!",
  21.871 +    #else
  21.872 +      "\314\225\241\271",
  21.873 +      "\241\322\265\367\202",
  21.874 +    #endif
  21.875 +    seqsize(3,1) - seqsize(2,1)
  21.876 +  },
  21.877 +  /* For packed arrays, there is another case (packed arrays
  21.878 +   * do not take advantage of the LIDX or IDXADDR instructions).
  21.879 +   *    addr.pri n1             addr.alt n1
  21.880 +   *    push.pri                load.s.pri n2
  21.881 +   *    load.s.pri n2           bounds n3
  21.882 +   *    bounds n3               -
  21.883 +   *    pop.alt                 -
  21.884 +   *
  21.885 +   * Notes (additional cases):
  21.886 +   * 1. instruction addr.pri can also be const.pri (for
  21.887 +   *    global arrays)
  21.888 +   * 2. the bounds instruction can be absent, but that
  21.889 +   *    case is already handled (see #1#)
  21.890 +   */
  21.891 +  {
  21.892 +    #ifdef SCPACK
  21.893 +      "addr.pri %1!push.pri!load.s.pri %2!bounds %3!pop.alt!",
  21.894 +      "addr.alt %1!load.s.pri %2!bounds %3!",
  21.895 +    #else
  21.896 +      "\364\316\241",
  21.897 +      "\365\316",
  21.898 +    #endif
  21.899 +    seqsize(5,3) - seqsize(3,3)
  21.900 +  },
  21.901 +  {
  21.902 +    #ifdef SCPACK
  21.903 +      "const.pri %1!push.pri!load.s.pri %2!bounds %3!pop.alt!",
  21.904 +      "const.alt %1!load.s.pri %2!bounds %3!",
  21.905 +    #else
  21.906 +      "\363\316\241",
  21.907 +      "\376\316",
  21.908 +    #endif
  21.909 +    seqsize(5,3) - seqsize(3,3)
  21.910 +  },
  21.911 +  /* Declaration of simple variables often follows the sequence:
  21.912 +   *    ;$lcl <name> <stk>      ;$lcl <name> <stk>
  21.913 +   *    stack -4                push.c <constval>
  21.914 +   *    const.pri <constval>    ;$exp
  21.915 +   *    stor.s.pri <stk>        -
  21.916 +   *    ;$exp                   -
  21.917 +   */
  21.918 +  {
  21.919 +    #ifdef SCPACK
  21.920 +      ";$lcl %1 %2!stack -4!const.pri %3!stor.s.pri %2!;$exp!",
  21.921 +      ";$lcl %1 %2!push.c %3!;$exp!",
  21.922 +    #else
  21.923 +      "\224lcl\332\227ack -4!\233\206\256\227or\222\230\252",
  21.924 +      "\224lcl\332\331\256\252",
  21.925 +    #endif
  21.926 +    seqsize(3,3) - seqsize(1,1)
  21.927 +  },
  21.928 +  {
  21.929 +    #ifdef SCPACK
  21.930 +      ";$lcl %1 %2!stack -4!zero.pri!stor.s.pri %2!;$exp!",
  21.931 +      ";$lcl %1 %2!push.c 0!;$exp!",
  21.932 +    #else
  21.933 +      "\224lcl\332\227ack -4!\373\227or\222\230\252",
  21.934 +      "\224lcl\332\331 0!\252",
  21.935 +    #endif
  21.936 +    seqsize(3,2) - seqsize(1,1)
  21.937 +  },
  21.938 +  /* During a calculation, the intermediate result must sometimes
  21.939 +   * be moved from PRI to ALT, like in:
  21.940 +   *    push.pri                move.alt
  21.941 +   *    load.s.pri n1           load.s.pri n1
  21.942 +   *    pop.alt                 -
  21.943 +   *
  21.944 +   * The above also accurs for "load.pri" and for "const.pri",
  21.945 +   * so add another two cases.
  21.946 +   */
  21.947 +  {
  21.948 +    #ifdef SCPACK
  21.949 +      "push.pri!load.s.pri %1!pop.alt!",
  21.950 +      "move.alt!load.s.pri %1!",
  21.951 +    #else
  21.952 +      "\244\333\241",
  21.953 +      "\306\333",
  21.954 +    #endif
  21.955 +    seqsize(3,1) - seqsize(2,1)
  21.956 +  },
  21.957 +  {
  21.958 +    #ifdef SCPACK
  21.959 +      "push.pri!load.pri %1!pop.alt!",
  21.960 +      "move.alt!load.pri %1!",
  21.961 +    #else
  21.962 +      "\244\311\241",
  21.963 +      "\306\311",
  21.964 +    #endif
  21.965 +    seqsize(3,1) - seqsize(2,1)
  21.966 +  },
  21.967 +  {
  21.968 +    #ifdef SCPACK
  21.969 +      "push.pri!const.pri %1!pop.alt!",
  21.970 +      "move.alt!const.pri %1!",
  21.971 +    #else
  21.972 +      "\244\330\241",
  21.973 +      "\306\330",
  21.974 +    #endif
  21.975 +    seqsize(3,1) - seqsize(2,1)
  21.976 +  },
  21.977 +  {
  21.978 +    #ifdef SCPACK
  21.979 +      "push.pri!zero.pri!pop.alt!",
  21.980 +      "move.alt!zero.pri!",
  21.981 +    #else
  21.982 +      "\244\373\241",
  21.983 +      "\306\373",
  21.984 +    #endif
  21.985 +    seqsize(3,0) - seqsize(2,0)
  21.986 +  },
  21.987 +  /* saving PRI and then loading from its address
  21.988 +   * occurs when indexing a multi-dimensional array
  21.989 +   */
  21.990 +  {
  21.991 +    #ifdef SCPACK
  21.992 +      "push.pri!load.i!pop.alt!",
  21.993 +      "move.alt!load.i!",
  21.994 +    #else
  21.995 +      "\244\342i\266",
  21.996 +      "\306\342\355",
  21.997 +    #endif
  21.998 +    seqsize(3,0) - seqsize(2,0)
  21.999 +  },
 21.1000 +  /* An even simpler PUSH/POP optimization (occurs in
 21.1001 +   * switch statements):
 21.1002 +   *    push.pri                move.alt
 21.1003 +   *    pop.alt                 -
 21.1004 +   */
 21.1005 +  {
 21.1006 +    #ifdef SCPACK
 21.1007 +      "push.pri!pop.alt!",
 21.1008 +      "move.alt!",
 21.1009 +    #else
 21.1010 +      "\244\241",
 21.1011 +      "\306",
 21.1012 +    #endif
 21.1013 +    seqsize(2,0) - seqsize(1,0)
 21.1014 +  },
 21.1015 +  /* Some simple arithmetic sequences
 21.1016 +   */
 21.1017 +  {
 21.1018 +    #ifdef SCPACK
 21.1019 +      "move.alt!load.s.pri %1!add!",
 21.1020 +      "load.s.alt %1!add!",
 21.1021 +    #else
 21.1022 +      "\306\333\271",
 21.1023 +      "\375\271",
 21.1024 +    #endif
 21.1025 +    seqsize(3,1) - seqsize(2,1)
 21.1026 +  },
 21.1027 +  {
 21.1028 +    #ifdef SCPACK
 21.1029 +      "move.alt!load.pri %1!add!",
 21.1030 +      "load.alt %1!add!",
 21.1031 +    #else
 21.1032 +      "\306\311\271",
 21.1033 +      "\374\271",
 21.1034 +    #endif
 21.1035 +    seqsize(3,1) - seqsize(2,1)
 21.1036 +  },
 21.1037 +  {
 21.1038 +    #ifdef SCPACK
 21.1039 +      "move.alt!const.pri %1!add!",
 21.1040 +      "const.alt %1!add!",
 21.1041 +    #else
 21.1042 +      "\306\330\271",
 21.1043 +      "\356\271",
 21.1044 +    #endif
 21.1045 +    seqsize(3,1) - seqsize(2,1)
 21.1046 +  },
 21.1047 +  {
 21.1048 +    #ifdef SCPACK
 21.1049 +      "move.alt!load.s.pri %1!sub.alt!",
 21.1050 +      "load.s.alt %1!sub!",
 21.1051 +    #else
 21.1052 +      "\306\333sub\223",
 21.1053 +      "\375sub!",
 21.1054 +    #endif
 21.1055 +    seqsize(3,1) - seqsize(2,1)
 21.1056 +  },
 21.1057 +  {
 21.1058 +    #ifdef SCPACK
 21.1059 +      "move.alt!load.pri %1!sub.alt!",
 21.1060 +      "load.alt %1!sub!",
 21.1061 +    #else
 21.1062 +      "\306\311sub\223",
 21.1063 +      "\374sub!",
 21.1064 +    #endif
 21.1065 +    seqsize(3,1) - seqsize(2,1)
 21.1066 +  },
 21.1067 +  {
 21.1068 +    #ifdef SCPACK
 21.1069 +      "move.alt!const.pri %1!sub.alt!",
 21.1070 +      "const.alt %1!sub!",
 21.1071 +    #else
 21.1072 +      "\306\330sub\223",
 21.1073 +      "\356sub!",
 21.1074 +    #endif
 21.1075 +    seqsize(3,1) - seqsize(2,1)
 21.1076 +  },
 21.1077 +  /* User-defined operators first load the operands into registers and
 21.1078 +   * then have them pushed onto the stack. This can give rise to sequences
 21.1079 +   * like:
 21.1080 +   *    const.pri n1            push.c n1
 21.1081 +   *    const.alt n2            push.c n2
 21.1082 +   *    push.pri                -
 21.1083 +   *    push.alt                -
 21.1084 +   * A similar sequence occurs with the two PUSH.pri/alt instructions inverted.
 21.1085 +   * The first, second, or both CONST.pri/alt instructions can also be
 21.1086 +   * LOAD.pri/alt.
 21.1087 +   * This gives 2 x 4 cases.
 21.1088 +   */
 21.1089 +  {
 21.1090 +    #ifdef SCPACK
 21.1091 +      "const.pri %1!const.alt %2!push.pri!push.alt!",
 21.1092 +      "push.c %1!push.c %2!",
 21.1093 +    #else
 21.1094 +      "\330\233\304\244\354",
 21.1095 +      "\331\202\331\221",
 21.1096 +    #endif
 21.1097 +    seqsize(4,2) - seqsize(2,2)
 21.1098 +  },
 21.1099 +  {
 21.1100 +    #ifdef SCPACK
 21.1101 +      "const.pri %1!const.alt %2!push.alt!push.pri!",
 21.1102 +      "push.c %2!push.c %1!",
 21.1103 +    #else
 21.1104 +      "\330\233\304\354\244",
 21.1105 +      "\331\221\331\202",
 21.1106 +    #endif
 21.1107 +    seqsize(4,2) - seqsize(2,2)
 21.1108 +  },
 21.1109 +  {
 21.1110 +    #ifdef SCPACK
 21.1111 +      "const.pri %1!load.alt %2!push.pri!push.alt!",
 21.1112 +      "push.c %1!push %2!",
 21.1113 +    #else
 21.1114 +      "\330\362\244\354",
 21.1115 +      "\331\202\216\221",
 21.1116 +    #endif
 21.1117 +    seqsize(4,2) - seqsize(2,2)
 21.1118 +  },
 21.1119 +  {
 21.1120 +    #ifdef SCPACK
 21.1121 +      "const.pri %1!load.alt %2!push.alt!push.pri!",
 21.1122 +      "push %2!push.c %1!",
 21.1123 +    #else
 21.1124 +      "\330\362\354\244",
 21.1125 +      "\216\221\331\202",
 21.1126 +    #endif
 21.1127 +    seqsize(4,2) - seqsize(2,2)
 21.1128 +  },
 21.1129 +  {
 21.1130 +    #ifdef SCPACK
 21.1131 +      "load.pri %1!const.alt %2!push.pri!push.alt!",
 21.1132 +      "push %1!push.c %2!",
 21.1133 +    #else
 21.1134 +      "\311\233\304\244\354",
 21.1135 +      "\216\202\331\221",
 21.1136 +    #endif
 21.1137 +    seqsize(4,2) - seqsize(2,2)
 21.1138 +  },
 21.1139 +  {
 21.1140 +    #ifdef SCPACK
 21.1141 +      "load.pri %1!const.alt %2!push.alt!push.pri!",
 21.1142 +      "push.c %2!push %1!",
 21.1143 +    #else
 21.1144 +      "\311\233\304\354\244",
 21.1145 +      "\331\221\216\202",
 21.1146 +    #endif
 21.1147 +    seqsize(4,2) - seqsize(2,2)
 21.1148 +  },
 21.1149 +  {
 21.1150 +    #ifdef SCPACK
 21.1151 +      "load.pri %1!load.alt %2!push.pri!push.alt!",
 21.1152 +      "push %1!push %2!",
 21.1153 +    #else
 21.1154 +      "\311\362\244\354",
 21.1155 +      "\216\202\216\221",
 21.1156 +    #endif
 21.1157 +    seqsize(4,2) - seqsize(2,2)
 21.1158 +  },
 21.1159 +  {
 21.1160 +    #ifdef SCPACK
 21.1161 +      "load.pri %1!load.alt %2!push.alt!push.pri!",
 21.1162 +      "push %2!push %1!",
 21.1163 +    #else
 21.1164 +      "\311\362\354\244",
 21.1165 +      "\216\221\216\202",
 21.1166 +    #endif
 21.1167 +    seqsize(4,2) - seqsize(2,2)
 21.1168 +  },
 21.1169 +  /* Function calls (parameters are passed on the stack)
 21.1170 +   *    load.s.pri n1           push.s n1
 21.1171 +   *    push.pri                -
 21.1172 +   *    --------------------------------------
 21.1173 +   *    load.pri n1             push n1
 21.1174 +   *    push.pri                -
 21.1175 +   *    --------------------------------------
 21.1176 +   *    const.pri n1            push.c n1
 21.1177 +   *    push.pri                -
 21.1178 +   *    --------------------------------------
 21.1179 +   *    zero.pri                push.c 0
 21.1180 +   *    push.pri                -
 21.1181 +   *    --------------------------------------
 21.1182 +   *    addr.pri n1             push.adr n1
 21.1183 +   *    push.pri                -
 21.1184 +   *
 21.1185 +   * However, PRI must not be needed after this instruction
 21.1186 +   * if this shortcut is used. Check for the ;$par comment.
 21.1187 +   */
 21.1188 +  {
 21.1189 +    #ifdef SCPACK
 21.1190 +      "load.s.pri %1!push.pri!;$par!",
 21.1191 +      "push.s %1!;$par!",
 21.1192 +    #else
 21.1193 +      "\226\264\255",
 21.1194 +      "\216\222\202\255",
 21.1195 +    #endif
 21.1196 +    seqsize(2,1) - seqsize(1,1)
 21.1197 +  },
 21.1198 +  {
 21.1199 +    #ifdef SCPACK
 21.1200 +      "load.pri %1!push.pri!;$par!",
 21.1201 +      "push %1!;$par!",
 21.1202 +    #else
 21.1203 +      "\217\264\255",
 21.1204 +      "\216\202\255",
 21.1205 +    #endif
 21.1206 +    seqsize(2,1) - seqsize(1,1)
 21.1207 +  },
 21.1208 +  {
 21.1209 +    #ifdef SCPACK
 21.1210 +      "const.pri %1!push.pri!;$par!",
 21.1211 +      "push.c %1!;$par!",
 21.1212 +    #else
 21.1213 +      "\233\264\255",
 21.1214 +      "\331\202\255",
 21.1215 +    #endif
 21.1216 +    seqsize(2,1) - seqsize(1,1)
 21.1217 +  },
 21.1218 +  {
 21.1219 +    #ifdef SCPACK
 21.1220 +      "zero.pri!push.pri!;$par!",
 21.1221 +      "push.c 0!;$par!",
 21.1222 +    #else
 21.1223 +      "\373\244\255",
 21.1224 +      "\331 0!\255",
 21.1225 +    #endif
 21.1226 +    seqsize(2,0) - seqsize(1,1)
 21.1227 +  },
 21.1228 +  {
 21.1229 +    #ifdef SCPACK
 21.1230 +      "addr.pri %1!push.pri!;$par!",
 21.1231 +      "push.adr %1!;$par!",
 21.1232 +    #else
 21.1233 +      "\265\264\255",
 21.1234 +      "\216\326\202\255",
 21.1235 +    #endif
 21.1236 +    seqsize(2,1) - seqsize(1,1)
 21.1237 +  },
 21.1238 +  /* References with a default value generate new cells on the heap
 21.1239 +   * dynamically. That code often ends with:
 21.1240 +   *    move.pri                push.alt
 21.1241 +   *    push.pri                -
 21.1242 +   */
 21.1243 +  {
 21.1244 +    #ifdef SCPACK
 21.1245 +      "move.pri!push.pri!",
 21.1246 +      "push.alt!",
 21.1247 +    #else
 21.1248 +      "\300\236\244",
 21.1249 +      "\354",
 21.1250 +    #endif
 21.1251 +    seqsize(2,0) - seqsize(1,0)
 21.1252 +  },
 21.1253 +  /* Simple arithmetic operations on constants. Noteworthy is the
 21.1254 +   * subtraction of a constant, since it is converted to the addition
 21.1255 +   * of the inverse value.
 21.1256 +   *    const.alt n1            add.c n1
 21.1257 +   *    add                     -
 21.1258 +   *    --------------------------------------
 21.1259 +   *    const.alt n1            add.c -n1
 21.1260 +   *    sub                     -
 21.1261 +   *    --------------------------------------
 21.1262 +   *    const.alt n1            smul.c n1
 21.1263 +   *    smul                    -
 21.1264 +   *    --------------------------------------
 21.1265 +   *    const.alt n1            eq.c.pri n1
 21.1266 +   *    eq                      -
 21.1267 +   */
 21.1268 +  {
 21.1269 +    #ifdef SCPACK
 21.1270 +      "const.alt %1!add!",
 21.1271 +      "add.c %1!",
 21.1272 +    #else
 21.1273 +      "\356\271",
 21.1274 +      "\235\242\202",
 21.1275 +    #endif
 21.1276 +    seqsize(2,1) - seqsize(1,1)
 21.1277 +  },
 21.1278 +  {
 21.1279 +    #ifdef SCPACK
 21.1280 +      "const.alt %1!sub!",
 21.1281 +      "add.c -%1!",
 21.1282 +    #else
 21.1283 +      "\356sub!",
 21.1284 +      "\235\242 -\201",
 21.1285 +    #endif
 21.1286 +    seqsize(2,1) - seqsize(1,1)
 21.1287 +  },
 21.1288 +  {
 21.1289 +    #ifdef SCPACK
 21.1290 +      "const.alt %1!smul!",
 21.1291 +      "smul.c %1!",
 21.1292 +    #else
 21.1293 +      "\356smul!",
 21.1294 +      "smu\307\202",
 21.1295 +    #endif
 21.1296 +    seqsize(2,1) - seqsize(1,1)
 21.1297 +  },
 21.1298 +  {
 21.1299 +    #ifdef SCPACK
 21.1300 +      "const.alt %1!eq!",
 21.1301 +      "eq.c.pri %1!",
 21.1302 +    #else
 21.1303 +      "\356\325",
 21.1304 +      "\262\242\225",
 21.1305 +    #endif
 21.1306 +    seqsize(2,1) - seqsize(1,1)
 21.1307 +  },
 21.1308 +  /* Some operations use the alternative subtraction operation --these
 21.1309 +   * can also be optimized.
 21.1310 +   *    const.pri n1            load.s.pri n2
 21.1311 +   *    load.s.alt n2           add.c -n1
 21.1312 +   *    sub.alt                 -
 21.1313 +   *    --------------------------------------
 21.1314 +   *    const.pri n1            load.pri n2
 21.1315 +   *    load.alt n2             add.c -n1
 21.1316 +   *    sub.alt                 -
 21.1317 +   */
 21.1318 +  {
 21.1319 +    #ifdef SCPACK
 21.1320 +      "const.pri %1!load.s.alt %2!sub.alt!",
 21.1321 +      "load.s.pri %2!add.c -%1!",
 21.1322 +    #else
 21.1323 +      "\330\226\304sub\223",
 21.1324 +      "\246\235\242 -\201",
 21.1325 +    #endif
 21.1326 +    seqsize(3,2) - seqsize(2,2)
 21.1327 +  },
 21.1328 +  {
 21.1329 +    #ifdef SCPACK
 21.1330 +      "const.pri %1!load.alt %2!sub.alt!",
 21.1331 +      "load.pri %2!add.c -%1!",
 21.1332 +    #else
 21.1333 +      "\330\362sub\223",
 21.1334 +      "\334\235\242 -\201",
 21.1335 +    #endif
 21.1336 +    seqsize(3,2) - seqsize(2,2)
 21.1337 +  },
 21.1338 +  /* With arrays indexed with constants that come from enumerations, it happens
 21.1339 +   * multiple add.c opcodes follow in sequence.
 21.1340 +   *    add.c n1                add.c n1+n2
 21.1341 +   *    add.c n2                -
 21.1342 +   */
 21.1343 +  {
 21.1344 +    #ifdef SCPACK
 21.1345 +      "add.c %1!add.c %2!",
 21.1346 +      "add.c %1+%2!",
 21.1347 +    #else
 21.1348 +      "\235\242\202\235\242\221",
 21.1349 +      "\235\242\267+%2!",
 21.1350 +    #endif
 21.1351 +    seqsize(2,2) - seqsize(1,1)
 21.1352 +  },
 21.1353 +  /* Compare and jump
 21.1354 +   *    eq                      jneq n1
 21.1355 +   *    jzer n1                 -
 21.1356 +   *    --------------------------------------
 21.1357 +   *    eq                      jeq n1
 21.1358 +   *    jnz n1                  -
 21.1359 +   *    --------------------------------------
 21.1360 +   *    neq                     jeq n1
 21.1361 +   *    jzer n1                 -
 21.1362 +   *    --------------------------------------
 21.1363 +   *    neq                     jneq n1
 21.1364 +   *    jnz n1                  -
 21.1365 +   * Compares followed by jzer occur much more
 21.1366 +   * often than compares followed with jnz. So we
 21.1367 +   * take the easy route here.
 21.1368 +   *    less                    jgeq n1
 21.1369 +   *    jzer n1                 -
 21.1370 +   *    --------------------------------------
 21.1371 +   *    leq                     jgrtr n1
 21.1372 +   *    jzer n1                 -
 21.1373 +   *    --------------------------------------
 21.1374 +   *    grtr                    jleq n1
 21.1375 +   *    jzer n1                 -
 21.1376 +   *    --------------------------------------
 21.1377 +   *    geq                     jless n1
 21.1378 +   *    jzer n1                 -
 21.1379 +   *    --------------------------------------
 21.1380 +   *    sless                   jsgeq n1
 21.1381 +   *    jzer n1                 -
 21.1382 +   *    --------------------------------------
 21.1383 +   *    sleq                    jsgrtr n1
 21.1384 +   *    jzer n1                 -
 21.1385 +   *    --------------------------------------
 21.1386 +   *    sgrtr                   jsleq n1
 21.1387 +   *    jzer n1                 -
 21.1388 +   *    --------------------------------------
 21.1389 +   *    sgeq                    jsless n1
 21.1390 +   *    jzer n1                 -
 21.1391 +   */
 21.1392 +  {
 21.1393 +    #ifdef SCPACK
 21.1394 +      "eq!jzer %1!",
 21.1395 +      "jneq %1!",
 21.1396 +    #else
 21.1397 +      "\325\323",
 21.1398 +      "jn\357",
 21.1399 +    #endif
 21.1400 +    seqsize(2,1) - seqsize(1,1)
 21.1401 +  },
 21.1402 +  {
 21.1403 +    #ifdef SCPACK
 21.1404 +      "eq!jnz %1!",
 21.1405 +      "jeq %1!",
 21.1406 +    #else
 21.1407 +      "\325jnz\202",
 21.1408 +      "j\357",
 21.1409 +    #endif
 21.1410 +    seqsize(2,1) - seqsize(1,1)
 21.1411 +  },
 21.1412 +  {
 21.1413 +    #ifdef SCPACK
 21.1414 +      "neq!jzer %1!",
 21.1415 +      "jeq %1!",
 21.1416 +    #else
 21.1417 +      "n\325\323",
 21.1418 +      "j\357",
 21.1419 +    #endif
 21.1420 +    seqsize(2,1) - seqsize(1,1)
 21.1421 +  },
 21.1422 +  {
 21.1423 +    #ifdef SCPACK
 21.1424 +      "neq!jnz %1!",
 21.1425 +      "jneq %1!",
 21.1426 +    #else
 21.1427 +      "n\325jnz\202",
 21.1428 +      "jn\357",
 21.1429 +    #endif
 21.1430 +    seqsize(2,1) - seqsize(1,1)
 21.1431 +  },
 21.1432 +  {
 21.1433 +    #ifdef SCPACK
 21.1434 +      "less!jzer %1!",
 21.1435 +      "jgeq %1!",
 21.1436 +    #else
 21.1437 +      "l\352!\323",
 21.1438 +      "jg\357",
 21.1439 +    #endif
 21.1440 +    seqsize(2,1) - seqsize(1,1)
 21.1441 +  },
 21.1442 +  {
 21.1443 +    #ifdef SCPACK
 21.1444 +      "leq!jzer %1!",
 21.1445 +      "jgrtr %1!",
 21.1446 +    #else
 21.1447 +      "l\325\323",
 21.1448 +      "jg\353r\202",
 21.1449 +    #endif
 21.1450 +    seqsize(2,1) - seqsize(1,1)
 21.1451 +  },
 21.1452 +  {
 21.1453 +    #ifdef SCPACK
 21.1454 +      "grtr!jzer %1!",
 21.1455 +      "jleq %1!",
 21.1456 +    #else
 21.1457 +      "g\353\237\323",
 21.1458 +      "jl\357",
 21.1459 +    #endif
 21.1460 +    seqsize(2,1) - seqsize(1,1)
 21.1461 +  },
 21.1462 +  {
 21.1463 +    #ifdef SCPACK
 21.1464 +      "geq!jzer %1!",
 21.1465 +      "jless %1!",
 21.1466 +    #else
 21.1467 +      "g\325\323",
 21.1468 +      "jl\352\202",
 21.1469 +    #endif
 21.1470 +    seqsize(2,1) - seqsize(1,1)
 21.1471 +  },
 21.1472 +  {
 21.1473 +    #ifdef SCPACK
 21.1474 +      "sless!jzer %1!",
 21.1475 +      "jsgeq %1!",
 21.1476 +    #else
 21.1477 +      "\372!\323",
 21.1478 +      "j\320\357",
 21.1479 +    #endif
 21.1480 +    seqsize(2,1) - seqsize(1,1)
 21.1481 +  },
 21.1482 +  {
 21.1483 +    #ifdef SCPACK
 21.1484 +      "sleq!jzer %1!",
 21.1485 +      "jsgrtr %1!",
 21.1486 +    #else
 21.1487 +      "\321\325\323",
 21.1488 +      "j\371r\202",
 21.1489 +    #endif
 21.1490 +    seqsize(2,1) - seqsize(1,1)
 21.1491 +  },
 21.1492 +  {
 21.1493 +    #ifdef SCPACK
 21.1494 +      "sgrtr!jzer %1!",
 21.1495 +      "jsleq %1!",
 21.1496 +    #else
 21.1497 +      "\371\237\323",
 21.1498 +      "j\321\357",
 21.1499 +    #endif
 21.1500 +    seqsize(2,1) - seqsize(1,1)
 21.1501 +  },
 21.1502 +  {
 21.1503 +    #ifdef SCPACK
 21.1504 +      "sgeq!jzer %1!",
 21.1505 +      "jsless %1!",
 21.1506 +    #else
 21.1507 +      "\320\325\323",
 21.1508 +      "j\372\202",
 21.1509 +    #endif
 21.1510 +    seqsize(2,1) - seqsize(1,1)
 21.1511 +  },
 21.1512 +  /* Test for zero (common case, especially for strings)
 21.1513 +   * E.g. the test expression of: "for (i=0; str{i}!=0; ++i)"
 21.1514 +   *
 21.1515 +   *    zero.alt                jzer n1
 21.1516 +   *    jeq n1                  -
 21.1517 +   *    --------------------------------------
 21.1518 +   *    zero.alt                jnz n1
 21.1519 +   *    jneq n1                 -
 21.1520 +   */
 21.1521 +  {
 21.1522 +    #ifdef SCPACK
 21.1523 +      "zero.alt!jeq %1!",
 21.1524 +      "jzer %1!",
 21.1525 +    #else
 21.1526 +      "\340\223j\357",
 21.1527 +      "\323",
 21.1528 +    #endif
 21.1529 +    seqsize(2,1) - seqsize(1,1)
 21.1530 +  },
 21.1531 +  {
 21.1532 +    #ifdef SCPACK
 21.1533 +      "zero.alt!jneq %1!",
 21.1534 +      "jnz %1!",
 21.1535 +    #else
 21.1536 +      "\340\223jn\357",
 21.1537 +      "jnz\202",
 21.1538 +    #endif
 21.1539 +    seqsize(2,1) - seqsize(1,1)
 21.1540 +  },
 21.1541 +  /* Incrementing and decrementing leaves a value in
 21.1542 +   * in PRI which may not be used (for example, as the
 21.1543 +   * third expression in a "for" loop).
 21.1544 +   *    inc n1                  inc n1  ; ++n
 21.1545 +   *    load.pri n1             ;$exp
 21.1546 +   *    ;$exp                   -
 21.1547 +   *    --------------------------------------
 21.1548 +   *    load.pri n1             inc n1  ; n++, e.g. "for (n=0; n<10; n++)"
 21.1549 +   *    inc n1                  ;$exp
 21.1550 +   *    ;$exp                   -
 21.1551 +   * Plus the varieties for stack relative increments
 21.1552 +   * and decrements.
 21.1553 +   */
 21.1554 +  {
 21.1555 +    #ifdef SCPACK
 21.1556 +      "inc %1!load.pri %1!;$exp!",
 21.1557 +      "inc %1!;$exp!",
 21.1558 +    #else
 21.1559 +      "inc\202\311\252",
 21.1560 +      "inc\301",
 21.1561 +    #endif
 21.1562 +    seqsize(2,2) - seqsize(1,1)
 21.1563 +  },
 21.1564 +  {
 21.1565 +    #ifdef SCPACK
 21.1566 +      "load.pri %1!inc %1!;$exp!",
 21.1567 +      "inc %1!;$exp!",
 21.1568 +    #else
 21.1569 +      "\311inc\301",
 21.1570 +      "inc\301",
 21.1571 +    #endif
 21.1572 +    seqsize(2,2) - seqsize(1,1)
 21.1573 +  },
 21.1574 +  {
 21.1575 +    #ifdef SCPACK
 21.1576 +      "inc.s %1!load.s.pri %1!;$exp!",
 21.1577 +      "inc.s %1!;$exp!",
 21.1578 +    #else
 21.1579 +      "inc\222\202\333\252",
 21.1580 +      "inc\222\301",
 21.1581 +    #endif
 21.1582 +    seqsize(2,2) - seqsize(1,1)
 21.1583 +  },
 21.1584 +  {
 21.1585 +    #ifdef SCPACK
 21.1586 +      "load.s.pri %1!inc.s %1!;$exp!",
 21.1587 +      "inc.s %1!;$exp!",
 21.1588 +    #else
 21.1589 +      "\333inc\222\301",
 21.1590 +      "inc\222\301",
 21.1591 +    #endif
 21.1592 +    seqsize(2,2) - seqsize(1,1)
 21.1593 +  },
 21.1594 +  {
 21.1595 +    #ifdef SCPACK
 21.1596 +      "dec %1!load.pri %1!;$exp!",
 21.1597 +      "dec %1!;$exp!",
 21.1598 +    #else
 21.1599 +      "dec\202\311\252",
 21.1600 +      "dec\301",
 21.1601 +    #endif
 21.1602 +    seqsize(2,2) - seqsize(1,1)
 21.1603 +  },
 21.1604 +  {
 21.1605 +    #ifdef SCPACK
 21.1606 +      "load.pri %1!dec %1!;$exp!",
 21.1607 +      "dec %1!;$exp!",
 21.1608 +    #else
 21.1609 +      "\311dec\301",
 21.1610 +      "dec\301",
 21.1611 +    #endif
 21.1612 +    seqsize(2,2) - seqsize(1,1)
 21.1613 +  },
 21.1614 +  {
 21.1615 +    #ifdef SCPACK
 21.1616 +      "dec.s %1!load.s.pri %1!;$exp!",
 21.1617 +      "dec.s %1!;$exp!",
 21.1618 +    #else
 21.1619 +      "dec\222\202\333\252",
 21.1620 +      "dec\222\301",
 21.1621 +    #endif
 21.1622 +    seqsize(2,2) - seqsize(1,1)
 21.1623 +  },
 21.1624 +  {
 21.1625 +    #ifdef SCPACK
 21.1626 +      "load.s.pri %1!dec.s %1!;$exp!",
 21.1627 +      "dec.s %1!;$exp!",
 21.1628 +    #else
 21.1629 +      "\333dec\222\301",
 21.1630 +      "dec\222\301",
 21.1631 +    #endif
 21.1632 +    seqsize(2,2) - seqsize(1,1)
 21.1633 +  },
 21.1634 +  /* ??? the same (increments and decrements) for references */
 21.1635 +  /* Loading the constant zero has a special opcode.
 21.1636 +   * When storing zero in memory, the value of PRI must not be later on.
 21.1637 +   *    const.pri 0             zero n1
 21.1638 +   *    stor.pri n1             ;$exp
 21.1639 +   *    ;$exp                   -
 21.1640 +   *    --------------------------------------
 21.1641 +   *    const.pri 0             zero.s n1
 21.1642 +   *    stor.s.pri n1           ;$exp
 21.1643 +   *    ;$exp                   -
 21.1644 +   *    --------------------------------------
 21.1645 +   *    zero.pri                zero n1
 21.1646 +   *    stor.pri n1             ;$exp
 21.1647 +   *    ;$exp                   -
 21.1648 +   *    --------------------------------------
 21.1649 +   *    zero.pri                zero.s n1
 21.1650 +   *    stor.s.pri n1           ;$exp
 21.1651 +   *    ;$exp                   -
 21.1652 +   *    --------------------------------------
 21.1653 +   *    const.pri 0             zero.pri
 21.1654 +   *    --------------------------------------
 21.1655 +   *    const.alt 0             zero.alt
 21.1656 +   * The last two alternatives save more memory than they save
 21.1657 +   * time, but anyway...
 21.1658 +   */
 21.1659 +  {
 21.1660 +    #ifdef SCPACK
 21.1661 +      "const.pri 0!stor.pri %1!;$exp!",
 21.1662 +      "zero %1!;$exp!",
 21.1663 +    #else
 21.1664 +      "\233\206 0!\227or\225\252",
 21.1665 +      "\340\301",
 21.1666 +    #endif
 21.1667 +    seqsize(2,2) - seqsize(1,1)
 21.1668 +  },
 21.1669 +  {
 21.1670 +    #ifdef SCPACK
 21.1671 +      "const.pri 0!stor.s.pri %1!;$exp!",
 21.1672 +      "zero.s %1!;$exp!",
 21.1673 +    #else
 21.1674 +      "\233\206 0!\227or\222\225\252",
 21.1675 +      "\340\222\301",
 21.1676 +    #endif
 21.1677 +    seqsize(2,2) - seqsize(1,1)
 21.1678 +  },
 21.1679 +  {
 21.1680 +    #ifdef SCPACK
 21.1681 +      "zero.pri!stor.pri %1!;$exp!",
 21.1682 +      "zero %1!;$exp!",
 21.1683 +    #else
 21.1684 +      "\373\227or\225\252",
 21.1685 +      "\340\301",
 21.1686 +    #endif
 21.1687 +    seqsize(2,1) - seqsize(1,1)
 21.1688 +  },
 21.1689 +  {
 21.1690 +    #ifdef SCPACK
 21.1691 +      "zero.pri!stor.s.pri %1!;$exp!",
 21.1692 +      "zero.s %1!;$exp!",
 21.1693 +    #else
 21.1694 +      "\373\227or\222\225\252",
 21.1695 +      "\340\222\301",
 21.1696 +    #endif
 21.1697 +    seqsize(2,1) - seqsize(1,1)
 21.1698 +  },
 21.1699 +  {
 21.1700 +    #ifdef SCPACK
 21.1701 +      "const.pri 0!",
 21.1702 +      "zero.pri!",
 21.1703 +    #else
 21.1704 +      "\233\206 0!",
 21.1705 +      "\373",
 21.1706 +    #endif
 21.1707 +    seqsize(1,1) - seqsize(1,0)
 21.1708 +  },
 21.1709 +  {
 21.1710 +    #ifdef SCPACK
 21.1711 +      "const.alt 0!",
 21.1712 +      "zero.alt!",
 21.1713 +    #else
 21.1714 +      "\233\212 0!",
 21.1715 +      "\340\223",
 21.1716 +    #endif
 21.1717 +    seqsize(1,1) - seqsize(1,0)
 21.1718 +  },
 21.1719 +
 21.1720 +  /* ------------------ */
 21.1721 +  /* Macro instructions */
 21.1722 +  /* ------------------ */
 21.1723 +
 21.1724 +  { "", "", 0 },    /* separator, so optimizer can stop before generating macro opcodes */
 21.1725 +
 21.1726 +  /* optimizing the calling of native functions (which always have a parameter
 21.1727 +   * count pushed before, and the stack pointer restored afterwards
 21.1728 +   */
 21.1729 +  {
 21.1730 +    #ifdef SCPACK
 21.1731 +      "push.c %1!sysreq.c %2!stack %3!",        //note: %3 == %1 + 4
 21.1732 +      "sysreq.n %2 %1!",
 21.1733 +    #else
 21.1734 +      "\331\202sysr\262\242\221\227ack\256",
 21.1735 +      "sysr\262.n\220\202",
 21.1736 +    #endif
 21.1737 +    seqsize(3,3) - seqsize(1,2)
 21.1738 +  },
 21.1739 +  /* ----- */
 21.1740 +  /* Functions with many parameters with the same "type" have sequences like:
 21.1741 +   *    push.c n1               push3.c n1 n2 n3
 21.1742 +   *    ;$par                   ;$par
 21.1743 +   *    push.c n2               -
 21.1744 +   *    ;$par                   -
 21.1745 +   *    push.c n3               -
 21.1746 +   *    ;$par                   -
 21.1747 +   *    etc.                    etc.
 21.1748 +   *
 21.1749 +   * Similar sequences occur with PUSH, PUSH.s and PUSHADDR
 21.1750 +   */
 21.1751 +  {
 21.1752 +    #ifdef SCPACK
 21.1753 +      "push.c %1!;$par!push.c %2!;$par!push.c %3!;$par!push.c %4!;$par!push.c %5!",
 21.1754 +      "push5.c %1 %2 %3 %4 %5!",
 21.1755 +    #else
 21.1756 +      "\331\336\242\345\242\256\257\242\335\257\242\2035!",
 21.1757 +      "\2165\242\343\245\302\2035!",
 21.1758 +    #endif
 21.1759 +    seqsize(5,5) - seqsize(1,5)
 21.1760 +  },
 21.1761 +  {
 21.1762 +    #ifdef SCPACK
 21.1763 +      "push.c %1!;$par!push.c %2!;$par!push.c %3!;$par!push.c %4!",
 21.1764 +      "push4.c %1 %2 %3 %4!",
 21.1765 +    #else
 21.1766 +      "\331\336\242\345\242\256\257\242\335",
 21.1767 +      "\2164\242\343\245\335",
 21.1768 +    #endif
 21.1769 +    seqsize(4,4) - seqsize(1,4)
 21.1770 +  },
 21.1771 +  {
 21.1772 +    #ifdef SCPACK
 21.1773 +      "push.c %1!;$par!push.c %2!;$par!push.c %3!",
 21.1774 +      "push3.c %1 %2 %3!",
 21.1775 +    #else
 21.1776 +      "\331\336\242\345\242\256",
 21.1777 +      "\2163\242\343\256",
 21.1778 +    #endif
 21.1779 +    seqsize(3,3) - seqsize(1,3)
 21.1780 +  },
 21.1781 +  {
 21.1782 +    #ifdef SCPACK
 21.1783 +      "push.c %1!;$par!push.c %2!",
 21.1784 +      "push2.c %1 %2!",
 21.1785 +    #else
 21.1786 +      "\331\336\242\221",
 21.1787 +      "\2162\242\332",
 21.1788 +    #endif
 21.1789 +    seqsize(2,2) - seqsize(1,2)
 21.1790 +  },
 21.1791 +  /* ----- */
 21.1792 +  {
 21.1793 +    #ifdef SCPACK
 21.1794 +      "push %1!;$par!push %2!;$par!push %3!;$par!push %4!;$par!push %5!",
 21.1795 +      "push5 %1 %2 %3 %4 %5!",
 21.1796 +    #else
 21.1797 +      "\216\336\345\256\257\335\257\2035!",
 21.1798 +      "\2165\343\245\302\2035!",
 21.1799 +    #endif
 21.1800 +    seqsize(5,5) - seqsize(1,5)
 21.1801 +  },
 21.1802 +  {
 21.1803 +    #ifdef SCPACK
 21.1804 +      "push %1!;$par!push %2!;$par!push %3!;$par!push %4!",
 21.1805 +      "push4 %1 %2 %3 %4!",
 21.1806 +    #else
 21.1807 +      "\216\336\345\256\257\335",
 21.1808 +      "\2164\343\245\335",
 21.1809 +    #endif
 21.1810 +    seqsize(4,4) - seqsize(1,4)
 21.1811 +  },
 21.1812 +  {
 21.1813 +    #ifdef SCPACK
 21.1814 +      "push %1!;$par!push %2!;$par!push %3!",
 21.1815 +      "push3 %1 %2 %3!",
 21.1816 +    #else
 21.1817 +      "\216\336\345\256",
 21.1818 +      "\2163\343\256",
 21.1819 +    #endif
 21.1820 +    seqsize(3,3) - seqsize(1,3)
 21.1821 +  },
 21.1822 +  {
 21.1823 +    #ifdef SCPACK
 21.1824 +      "push %1!;$par!push %2!",
 21.1825 +      "push2 %1 %2!",
 21.1826 +    #else
 21.1827 +      "\216\336\221",
 21.1828 +      "\2162\332",
 21.1829 +    #endif
 21.1830 +    seqsize(2,2) - seqsize(1,2)
 21.1831 +  },
 21.1832 +  /* ----- */
 21.1833 +  {
 21.1834 +    #ifdef SCPACK
 21.1835 +      "push.s %1!;$par!push.s %2!;$par!push.s %3!;$par!push.s %4!;$par!push.s %5!",
 21.1836 +      "push5.s %1 %2 %3 %4 %5!",
 21.1837 +    #else
 21.1838 +      "\216\222\336\222\345\222\256\257\222\335\257\222\2035!",
 21.1839 +      "\2165\222\343\245\302\2035!",
 21.1840 +    #endif
 21.1841 +    seqsize(5,5) - seqsize(1,5)
 21.1842 +  },
 21.1843 +  {
 21.1844 +    #ifdef SCPACK
 21.1845 +      "push.s %1!;$par!push.s %2!;$par!push.s %3!;$par!push.s %4!",
 21.1846 +      "push4.s %1 %2 %3 %4!",
 21.1847 +    #else
 21.1848 +      "\216\222\336\222\345\222\256\257\222\335",
 21.1849 +      "\2164\222\343\245\335",
 21.1850 +    #endif
 21.1851 +    seqsize(4,4) - seqsize(1,4)
 21.1852 +  },
 21.1853 +  {
 21.1854 +    #ifdef SCPACK
 21.1855 +      "push.s %1!;$par!push.s %2!;$par!push.s %3!",
 21.1856 +      "push3.s %1 %2 %3!",
 21.1857 +    #else
 21.1858 +      "\216\222\336\222\345\222\256",
 21.1859 +      "\2163\222\343\256",
 21.1860 +    #endif
 21.1861 +    seqsize(3,3) - seqsize(1,3)
 21.1862 +  },
 21.1863 +  {
 21.1864 +    #ifdef SCPACK
 21.1865 +      "push.s %1!;$par!push.s %2!",
 21.1866 +      "push2.s %1 %2!",
 21.1867 +    #else
 21.1868 +      "\216\222\336\222\221",
 21.1869 +      "\2162\222\332",
 21.1870 +    #endif
 21.1871 +    seqsize(2,2) - seqsize(1,2)
 21.1872 +  },
 21.1873 +  /* ----- */
 21.1874 +  {
 21.1875 +    #ifdef SCPACK
 21.1876 +      "push.adr %1!;$par!push.adr %2!;$par!push.adr %3!;$par!push.adr %4!;$par!push.adr %5!",
 21.1877 +      "push5.adr %1 %2 %3 %4 %5!",
 21.1878 +    #else
 21.1879 +      "\216\326\336\326\345\326\256\257\326\335\257\326\2035!",
 21.1880 +      "\2165\326\343\245\302\2035!",
 21.1881 +    #endif
 21.1882 +    seqsize(5,5) - seqsize(1,5)
 21.1883 +  },
 21.1884 +  {
 21.1885 +    #ifdef SCPACK
 21.1886 +      "push.adr %1!;$par!push.adr %2!;$par!push.adr %3!;$par!push.adr %4!",
 21.1887 +      "push4.adr %1 %2 %3 %4!",
 21.1888 +    #else
 21.1889 +      "\216\326\336\326\345\326\256\257\326\335",
 21.1890 +      "\2164\326\343\245\335",
 21.1891 +    #endif
 21.1892 +    seqsize(4,4) - seqsize(1,4)
 21.1893 +  },
 21.1894 +  {
 21.1895 +    #ifdef SCPACK
 21.1896 +      "push.adr %1!;$par!push.adr %2!;$par!push.adr %3!",
 21.1897 +      "push3.adr %1 %2 %3!",
 21.1898 +    #else
 21.1899 +      "\216\326\336\326\345\326\256",
 21.1900 +      "\2163\326\343\256",
 21.1901 +    #endif
 21.1902 +    seqsize(3,3) - seqsize(1,3)
 21.1903 +  },
 21.1904 +  {
 21.1905 +    #ifdef SCPACK
 21.1906 +      "push.adr %1!;$par!push.adr %2!",
 21.1907 +      "push2.adr %1 %2!",
 21.1908 +    #else
 21.1909 +      "\216\326\336\326\221",
 21.1910 +      "\2162\326\332",
 21.1911 +    #endif
 21.1912 +    seqsize(2,2) - seqsize(1,2)
 21.1913 +  },
 21.1914 +  /* Loading two registers at a time
 21.1915 +   *    load.pri n1             load.both n1 n2
 21.1916 +   *    load.alt n2             -
 21.1917 +   *    --------------------------------------
 21.1918 +   *    load.alt n2             load.both n1 n2
 21.1919 +   *    load.pri n1             -
 21.1920 +   *    --------------------------------------
 21.1921 +   *    load.s.pri n1           load.s.both n1 n2
 21.1922 +   *    load.s.alt n2           -
 21.1923 +   *    --------------------------------------
 21.1924 +   *    load.s.alt n2           load.s.both n1 n2
 21.1925 +   *    load.s.pri n1           -
 21.1926 +   */
 21.1927 +  {
 21.1928 +    #ifdef SCPACK
 21.1929 +      "load.pri %1!load.alt %2!",
 21.1930 +      "load.both %1 %2!",
 21.1931 +    #else
 21.1932 +      "\311\362",
 21.1933 +      "\342\275th\332",
 21.1934 +    #endif
 21.1935 +    seqsize(2,2) - seqsize(1,2)
 21.1936 +  },
 21.1937 +  {
 21.1938 +    #ifdef SCPACK
 21.1939 +      "load.alt %2!load.pri %1!",
 21.1940 +      "load.both %1 %2!",
 21.1941 +    #else
 21.1942 +      "\362\311",
 21.1943 +      "\342\275th\332",
 21.1944 +    #endif
 21.1945 +    seqsize(2,2) - seqsize(1,2)
 21.1946 +  },
 21.1947 +  {
 21.1948 +    #ifdef SCPACK
 21.1949 +      "load.s.pri %1!load.s.alt %2!",
 21.1950 +      "load.s.both %1 %2!",
 21.1951 +    #else
 21.1952 +      "\333\226\304",
 21.1953 +      "\226.\275th\332",
 21.1954 +    #endif
 21.1955 +    seqsize(2,2) - seqsize(1,2)
 21.1956 +  },
 21.1957 +  {
 21.1958 +    #ifdef SCPACK
 21.1959 +      "load.s.alt %2!load.s.pri %1!",
 21.1960 +      "load.s.both %1 %2!",
 21.1961 +    #else
 21.1962 +      "\226\304\333",
 21.1963 +      "\226.\275th\332",
 21.1964 +    #endif
 21.1965 +    seqsize(2,2) - seqsize(1,2)
 21.1966 +  },
 21.1967 +  /* Loading two registers and then pushing them occurs with user operators
 21.1968 +   *    load.both n1 n2         push2 n1 n2
 21.1969 +   *    push.pri                -
 21.1970 +   *    push.alt                -
 21.1971 +   *    --------------------------------------
 21.1972 +   *    load.s.both n1 n2       push2.s n1 n2
 21.1973 +   *    push.pri                -
 21.1974 +   *    push.alt                -
 21.1975 +   */
 21.1976 +  {
 21.1977 +    #ifdef SCPACK
 21.1978 +      "load.both %1 %2!push.pri!push.alt!",
 21.1979 +      "push2 %1 %2!",
 21.1980 +    #else
 21.1981 +      "\342\275th\332\244\354",
 21.1982 +      "\2162\332",
 21.1983 +    #endif
 21.1984 +    seqsize(3,2) - seqsize(1,2)
 21.1985 +  },
 21.1986 +  {
 21.1987 +    #ifdef SCPACK
 21.1988 +      "load.s.both %1 %2!push.pri!push.alt!",
 21.1989 +      "push2.s %1 %2!",
 21.1990 +    #else
 21.1991 +      "\226.\275th\332\244\354",
 21.1992 +      "\2162\222\332",
 21.1993 +    #endif
 21.1994 +    seqsize(3,2) - seqsize(1,2)
 21.1995 +  },
 21.1996 +  /* Load a constant in a variable
 21.1997 +   *    const.pri n1            const n2 n1
 21.1998 +   *    stor.pri n2             -
 21.1999 +   *    --------------------------------------
 21.2000 +   *    const.pri n1            const.s n2 n1
 21.2001 +   *    stor.s.pri n2           -
 21.2002 +   */
 21.2003 +  {
 21.2004 +    #ifdef SCPACK
 21.2005 +      "const.pri %1!stor.pri %2!",
 21.2006 +      "const %2 %1!",
 21.2007 +    #else
 21.2008 +      "\330\227or\230",
 21.2009 +      "\233\220\202",
 21.2010 +    #endif
 21.2011 +    seqsize(2,2) - seqsize(1,2)
 21.2012 +  },
 21.2013 +  {
 21.2014 +    #ifdef SCPACK
 21.2015 +      "const.pri %1!stor.s.pri %2!",
 21.2016 +      "const.s %2 %1!",
 21.2017 +    #else
 21.2018 +      "\330\227or\222\230",
 21.2019 +      "\233\222\220\202",
 21.2020 +    #endif
 21.2021 +    seqsize(2,2) - seqsize(1,2)
 21.2022 +  },
 21.2023 +  /* ----- */
 21.2024 +  { NULL, NULL, 0 }
 21.2025 +};
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/compiler-init/compiler-init/scexpand.c	Fri Jul 14 02:02:18 2006 +0000
    22.3 @@ -0,0 +1,68 @@
    22.4 +/* expand.c -- Byte Pair Encoding decompression */
    22.5 +/* Copyright 1996 Philip Gage */
    22.6 +
    22.7 +/* Byte Pair Compression appeared in the September 1997
    22.8 + * issue of C/C++ Users Journal. The original source code
    22.9 + * may still be found at the web site of the magazine
   22.10 + * (www.cuj.com).
   22.11 + *
   22.12 + * The decompressor has been modified by me (Thiadmer
   22.13 + * Riemersma) to accept a string as input, instead of a
   22.14 + * complete file.
   22.15 + */
   22.16 +#include <assert.h>
   22.17 +#include <stdio.h>
   22.18 +#include "sc.h"
   22.19 +
   22.20 +#define STACKSIZE 16
   22.21 +
   22.22 +SC_FUNC int strexpand(char *dest, unsigned char *source, int maxlen, unsigned char pairtable[128][2])
   22.23 +{
   22.24 +  unsigned char stack[STACKSIZE];
   22.25 +  short c, top = 0;
   22.26 +  int len;
   22.27 +
   22.28 +  assert(maxlen > 0);
   22.29 +  len = 1;              /* already 1 byte for '\0' */
   22.30 +  for (;;) {
   22.31 +
   22.32 +    /* Pop byte from stack or read byte from the input string */
   22.33 +    if (top)
   22.34 +      c = stack[--top];
   22.35 +    else if ((c = *(unsigned char *)source++) == '\0')
   22.36 +      break;
   22.37 +
   22.38 +    /* Push pair on stack or output byte to the output string */
   22.39 +    if (c > 127) {
   22.40 +      assert(top+2 <= STACKSIZE);
   22.41 +      stack[top++] = pairtable[c-128][1];
   22.42 +      stack[top++] = pairtable[c-128][0];
   22.43 +    }
   22.44 +    else {
   22.45 +      len++;
   22.46 +      if (maxlen > 1) { /* reserve one byte for the '\0' */
   22.47 +        *dest++ = (char)c;
   22.48 +        maxlen--;
   22.49 +      }
   22.50 +    }
   22.51 +  }
   22.52 +  *dest = '\0';
   22.53 +  return len;           /* return number of bytes decoded */
   22.54 +}
   22.55 +
   22.56 +#if 0 /*for testing*/
   22.57 +#include "sc5.scp"
   22.58 +
   22.59 +int main (int argc, char **argv)
   22.60 +{
   22.61 +  int i;
   22.62 +  char str[128];
   22.63 +
   22.64 +  for (i=0; i<58; i++) {
   22.65 +    strexpand(str, errmsg[i], sizeof str, SCPACK_TABLE);
   22.66 +    printf("%s", str);
   22.67 +  } /* for */
   22.68 +  return 0;
   22.69 +}
   22.70 +#endif
   22.71 +
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/compiler-init/compiler-init/sci18n.c	Fri Jul 14 02:02:18 2006 +0000
    23.3 @@ -0,0 +1,428 @@
    23.4 +/*  Codepage translation to Unicode, and UTF-8 support
    23.5 + *
    23.6 + *  The translation is based on codepage mapping files that are distributed
    23.7 + *  by the Unicode consortium, see ftp://ftp.unicode.org/Public/MAPPINGS/.
    23.8 + *
    23.9 + *  Character sets with a maximum of 256 codes are translated via a lookup
   23.10 + *  table (these are Single-Byte Character Sets). Character sets like Shift-JIS
   23.11 + *  with single-byte characters and multi-byte characters (introduced by a
   23.12 + *  leader byte) are split into two tables: the 256-entry lookup table for
   23.13 + *  the single-byte characters and an extended table for the multi-byte
   23.14 + *  characters. The extended table is allocated dynamically; the lookup table
   23.15 + *  is allocated statically, so loading SBCS tables cannot fail (if the tables
   23.16 + *  themselves are valid, of course).
   23.17 + *
   23.18 + *  Copyright (c) ITB CompuPhase, 2004-2006
   23.19 + *
   23.20 + *  This software is provided "as-is", without any express or implied warranty.
   23.21 + *  In no event will the authors be held liable for any damages arising from
   23.22 + *  the use of this software.
   23.23 + *
   23.24 + *  Permission is granted to anyone to use this software for any purpose,
   23.25 + *  including commercial applications, and to alter it and redistribute it
   23.26 + *  freely, subject to the following restrictions:
   23.27 + *
   23.28 + *  1.  The origin of this software must not be misrepresented; you must not
   23.29 + *      claim that you wrote the original software. If you use this software in
   23.30 + *      a product, an acknowledgment in the product documentation would be
   23.31 + *      appreciated but is not required.
   23.32 + *  2.  Altered source versions must be plainly marked as such, and must not be
   23.33 + *      misrepresented as being the original software.
   23.34 + *  3.  This notice may not be removed or altered from any source distribution.
   23.35 + *
   23.36 + *  Version: $Id: CODEPAGE.C,v 1.0 2004-02-18 12:13:04+01 thiadmer Exp thiadmer $
   23.37 + */
   23.38 +#include <assert.h>
   23.39 +#include <stdio.h>
   23.40 +#include <stddef.h>
   23.41 +#include <stdlib.h>
   23.42 +#include <string.h>
   23.43 +#include "sc.h"
   23.44 +
   23.45 +#if !defined TRUE
   23.46 +  #define FALSE         0
   23.47 +  #define TRUE          1
   23.48 +#endif
   23.49 +#if !defined _MAX_PATH
   23.50 +  #define _MAX_PATH     250
   23.51 +#endif
   23.52 +#if !defined DIRSEP_CHAR
   23.53 +  #if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
   23.54 +    #define DIRSEP_CHAR '/'
   23.55 +  #elif defined macintosh
   23.56 +    #define DIRSEP_CHAR ':'
   23.57 +  #else
   23.58 +    #define DIRSEP_CHAR '\\'
   23.59 +  #endif
   23.60 +#endif
   23.61 +
   23.62 +#if !defined ELEMENTS
   23.63 +  #define ELEMENTS(array)       (sizeof(array) / sizeof(array[0]))
   23.64 +#endif
   23.65 +
   23.66 +#if !defined NO_CODEPAGE
   23.67 +
   23.68 +#if !defined MAXCODEPAGE
   23.69 +  #define MAXCODEPAGE   12      /* typically "cp" + 4 digits + ".txt" */
   23.70 +#endif
   23.71 +#define INVALID         0xffffu /* 0xffff and 0xfffe are invalid Unicode characters */
   23.72 +#define LEADBYTE        0xfffeu
   23.73 +
   23.74 +struct wordpair {
   23.75 +  unsigned short index;
   23.76 +  wchar_t code;
   23.77 +};
   23.78 +static char cprootpath[_MAX_PATH] = { DIRSEP_CHAR, '\0' };
   23.79 +static wchar_t bytetable[256];
   23.80 +static struct wordpair *wordtable = NULL;
   23.81 +static unsigned wordtablesize = 0;
   23.82 +static unsigned wordtabletop = 0;
   23.83 +
   23.84 +
   23.85 +/* read in a line delimited by '\r' or '\n'; do NOT store the '\r' or '\n' into
   23.86 + * the string and ignore empty lines
   23.87 + * returns 1 for success and 0 for failure
   23.88 + */
   23.89 +static int cp_readline(FILE *fp,char *string,size_t size)
   23.90 +{
   23.91 +  size_t count=0;
   23.92 +  int c;
   23.93 +  assert(size>1);
   23.94 +  while ((c=fgetc(fp))!=EOF && count<size-1) {
   23.95 +    if (c=='\r' || c=='\n') {
   23.96 +      if (count>0)  /* '\r' or '\n' ends a string */
   23.97 +        break;
   23.98 +      /* if count==0, the line started with a '\r' or '\n', or perhaps line
   23.99 +       * ends in the file are '\r\n' and we read and stopped on the '\r' of
  23.100 +       * the preceding line
  23.101 +       */
  23.102 +    } else {
  23.103 +      string[count++]=(char)c;
  23.104 +    } /* if */
  23.105 +  } /* while */
  23.106 +  string[count]='\0';
  23.107 +  return count>0;
  23.108 +}
  23.109 +
  23.110 +/* cp_path() sets the directory where all codepage files must be found (if
  23.111 + * the parameter to cp_set() specifies a full path, that is used instead).
  23.112 + * The path is specified into two parts: root and directory; the full path
  23.113 + * for the codepage direcory is just the concatenation of the two, with a
  23.114 + * directory separator in between. The directory is given in two parts,
  23.115 + * because often a program already retrieves its "home" directory and the
  23.116 + * codepages are most conveniently stored in a subdirectory of this home
  23.117 + * directory.
  23.118 + */
  23.119 +SC_FUNC int cp_path(const char *root, const char *directory)
  23.120 +{
  23.121 +  size_t len1,len2;
  23.122 +  int add_slash1,add_slash2;
  23.123 +
  23.124 +  len1= (root!=NULL) ? strlen(root) : 0;
  23.125 +  add_slash1= (len1==0 || root[len1-1]!=DIRSEP_CHAR);
  23.126 +  len2= (directory!=NULL) ? strlen(directory) : 0;
  23.127 +  add_slash2= (len2>0 && root[len2-1]!=DIRSEP_CHAR);
  23.128 +  if (len1+add_slash1+len2+add_slash2>=(_MAX_PATH-MAXCODEPAGE))
  23.129 +    return FALSE;       /* full filename may not fit */
  23.130 +  if (root!=NULL)
  23.131 +    strcpy(cprootpath,root);
  23.132 +  if (add_slash1) {
  23.133 +    assert(len1==0 || cprootpath[len1]=='\0');
  23.134 +    cprootpath[len1]=DIRSEP_CHAR;
  23.135 +    cprootpath[len1+1]='\0';
  23.136 +  } /* if */
  23.137 +  if (directory!=NULL)
  23.138 +    strcat(cprootpath,directory);
  23.139 +  if (add_slash2) {
  23.140 +    assert(cprootpath[len1+add_slash1+len2]=='\0');
  23.141 +    cprootpath[len1+add_slash1+len2]=DIRSEP_CHAR;
  23.142 +    cprootpath[len1+add_slash1+len2+1]='\0';
  23.143 +  } /* if */
  23.144 +  cp_set(NULL);         /* start with a "linear" table (no translation) */
  23.145 +  return TRUE;
  23.146 +}
  23.147 +
  23.148 +/* cp_set() loads a codepage from a file. The name parameter may be a
  23.149 + * filename (including a full path) or it may be a partial codepage name.
  23.150 + * If the name parameter is NULL, the codepage is cleared to be a "linear"
  23.151 + * table (no translation).
  23.152 + * The following files are attempted to open (where <name> specifies the
  23.153 + * value of the parameter):
  23.154 + *    <name>
  23.155 + *    <cprootpath>/<name>
  23.156 + *    <cprootpath>/<name>.txt
  23.157 + *    <cprootpath>/cp<name>
  23.158 + *    <cprootpath>/cp<name>.txt
  23.159 + */
  23.160 +SC_FUNC int cp_set(const char *name)
  23.161 +{
  23.162 +  char filename[_MAX_PATH];
  23.163 +  FILE *fp=NULL;
  23.164 +  unsigned index;
  23.165 +
  23.166 +  /* for name==NULL, set up an identity table */
  23.167 +  if (name==NULL || *name=='\0') {
  23.168 +    if (wordtable!=NULL) {
  23.169 +      free(wordtable);
  23.170 +      wordtable=NULL;
  23.171 +      wordtablesize=0;
  23.172 +      wordtabletop=0;
  23.173 +    } /* if */
  23.174 +    for (index=0; index<ELEMENTS(bytetable); index++)
  23.175 +      bytetable[index]=(wchar_t)index;
  23.176 +    return TRUE;
  23.177 +  } /* if */
  23.178 +
  23.179 +  /* try to open the file as-is */
  23.180 +  if (strchr(name,DIRSEP_CHAR)!=NULL)
  23.181 +    fp=fopen(name,"rt");
  23.182 +  if (fp==NULL) {
  23.183 +    /* try opening the file in the "root path" for codepages */
  23.184 +    if (strlen(name)>MAXCODEPAGE)
  23.185 +      return 0;
  23.186 +    assert(strlen(name)+strlen(cprootpath)<_MAX_PATH);
  23.187 +    strcpy(filename,cprootpath);
  23.188 +    strcat(filename,name);
  23.189 +    fp=fopen(filename,"rt");
  23.190 +  } /* if */
  23.191 +  if (fp==NULL) {
  23.192 +    /* try opening the file in the "root path" for codepages, with a ".txt" extension */
  23.193 +    if (strlen(name)+4>=MAXCODEPAGE)
  23.194 +      return 0;
  23.195 +    assert(strlen(filename)+4<_MAX_PATH);
  23.196 +    strcat(filename,".txt");
  23.197 +    fp=fopen(filename,"rt");
  23.198 +  } /* if */
  23.199 +  if (fp==NULL) {
  23.200 +    /* try opening the file in the "root path" for codepages, with "cp" prefixed before the name */
  23.201 +    if (strlen(name)+2>MAXCODEPAGE)
  23.202 +      return 0;
  23.203 +    assert(2+strlen(name)+strlen(cprootpath)<_MAX_PATH);
  23.204 +    strcpy(filename,cprootpath);
  23.205 +    strcat(filename,"cp");
  23.206 +    strcat(filename,name);
  23.207 +    fp=fopen(filename,"rt");
  23.208 +  } /* if */
  23.209 +  if (fp==NULL) {
  23.210 +    /* try opening the file in the "root path" for codepages, with "cp" prefixed an ".txt" appended */
  23.211 +    if (strlen(name)+2+4>MAXCODEPAGE)
  23.212 +      return 0;
  23.213 +    assert(strlen(filename)+4<_MAX_PATH);
  23.214 +    strcat(filename,".txt");
  23.215 +    fp=fopen(filename,"rt");
  23.216 +  } /* if */
  23.217 +  if (fp==NULL)
  23.218 +    return FALSE;       /* all failed */
  23.219 +
  23.220 +  /* clear the tables */
  23.221 +  for (index=0; index<ELEMENTS(bytetable); index++)
  23.222 +    bytetable[index]=INVALID;   /* special code meaning "not found" */
  23.223 +  assert(wordtablesize==0 && wordtabletop==0 && wordtable==NULL
  23.224 +         || wordtablesize>0 && wordtable!=NULL);
  23.225 +  if (wordtable!=NULL) {
  23.226 +    free(wordtable);
  23.227 +    wordtable=NULL;
  23.228 +    wordtablesize=0;
  23.229 +    wordtabletop=0;
  23.230 +  } /* if */
  23.231 +
  23.232 +  /* read in the table */
  23.233 +  while (cp_readline(fp,filename,sizeof filename)) {
  23.234 +    char *ptr;
  23.235 +    if ((ptr=strchr(filename,'#'))!=NULL)
  23.236 +      *ptr='\0';                /* strip of comment */
  23.237 +    for (ptr=filename; *ptr>0 && *ptr<' '; ptr++)
  23.238 +      /* nothing */;            /* skip leading whitespace */
  23.239 +    if (*ptr!='\0') {
  23.240 +      /* content on line */
  23.241 +      unsigned code=LEADBYTE;
  23.242 +      int num=sscanf(ptr,"%i %i",&index,&code);
  23.243 +      /* if sscanf() returns 1 and the index is in range 0..255, then the
  23.244 +       * code is a DBCS lead byte; if sscanf() returns 2 and index>=256, this
  23.245 +       * is a double byte pair (lead byte + follower)
  23.246 +       */
  23.247 +      if (num>=1 && index<256) {
  23.248 +        bytetable[index]=(wchar_t)code;
  23.249 +      } else if (num==2 && index>=256 && index<LEADBYTE) {
  23.250 +        /* store the DBCS character in wordtable */
  23.251 +        if (wordtabletop>=wordtablesize) {
  23.252 +          /* grow the list */
  23.253 +          int newsize;
  23.254 +          struct wordpair *newblock;
  23.255 +          newsize= (wordtablesize==0) ? 128 : 2*wordtablesize;
  23.256 +          newblock=(struct wordpair *)malloc(newsize*sizeof(*wordtable));
  23.257 +          if (newblock!=NULL) {
  23.258 +            memcpy(newblock,wordtable,wordtabletop*sizeof(*wordtable));
  23.259 +            free(wordtable);
  23.260 +            wordtable=newblock;
  23.261 +            wordtablesize=newsize;
  23.262 +          } /* if */
  23.263 +        } /* if */
  23.264 +        if (wordtabletop<wordtablesize) {
  23.265 +          /* insert at sorted position */
  23.266 +          int pos=wordtabletop;
  23.267 +          assert(wordtable!=NULL);
  23.268 +          while (pos>0 && (unsigned)wordtable[pos-1].index>index) {
  23.269 +            wordtable[pos]=wordtable[pos-1];
  23.270 +            pos--;
  23.271 +          } /* while */
  23.272 +          wordtable[pos].index=(unsigned short)index;
  23.273 +          wordtable[pos].code=(wchar_t)code;
  23.274 +        } /* if */
  23.275 +      } /* if */
  23.276 +    } /* if */
  23.277 +  } /* while */
  23.278 +
  23.279 +  fclose(fp);
  23.280 +  return TRUE;
  23.281 +}
  23.282 +
  23.283 +SC_FUNC cell cp_translate(const unsigned char *string,const unsigned char **endptr)
  23.284 +{
  23.285 +  wchar_t result;
  23.286 +
  23.287 +  result=bytetable[*string++];
  23.288 +  /* check whether this is a leader code */
  23.289 +  if ((unsigned)result==LEADBYTE && wordtable!=NULL) {
  23.290 +    /* look up the code via binary search */
  23.291 +    int low,high,mid;
  23.292 +    unsigned short index=(unsigned short)(((*(string-1)) << 8) | *string);
  23.293 +    string++;
  23.294 +    assert(wordtabletop>0);
  23.295 +    low=0;
  23.296 +    high=wordtabletop-1;
  23.297 +    while (low<high) {
  23.298 +      mid=(low+high)/2;
  23.299 +      assert(low<=mid && mid<high);
  23.300 +      if (index>wordtable[mid].index)
  23.301 +        low=mid+1;
  23.302 +      else
  23.303 +        high=mid;
  23.304 +    } /* while */
  23.305 +    assert(low==high);
  23.306 +    if (wordtable[low].index==index)
  23.307 +      result=wordtable[low].code;
  23.308 +  } /* if */
  23.309 +
  23.310 +  if (endptr!=NULL)
  23.311 +    *endptr=string;
  23.312 +  return (cell)result;
  23.313 +}
  23.314 +
  23.315 +#endif  /* NO_CODEPAGE */
  23.316 +
  23.317 +#if !defined NO_UTF8
  23.318 +SC_FUNC cell get_utf8_char(const unsigned char *string,const unsigned char **endptr)
  23.319 +{
  23.320 +  int follow=0;
  23.321 +  long lowmark=0;
  23.322 +  unsigned char ch;
  23.323 +  cell result=0;
  23.324 +
  23.325 +  if (endptr!=NULL)
  23.326 +    *endptr=string;
  23.327 +
  23.328 +  for ( ;; ) {
  23.329 +    ch=*string++;
  23.330 +
  23.331 +    if (follow>0 && (ch & 0xc0)==0x80) {
  23.332 +      /* leader code is active, combine with earlier code */
  23.333 +      result=(result << 6) | (ch & 0x3f);
  23.334 +      if (--follow==0) {
  23.335 +        /* encoding a character in more bytes than is strictly needed,
  23.336 +         * is not really valid UTF-8; we are strict here to increase
  23.337 +         * the chance of heuristic dectection of non-UTF-8 text
  23.338 +         * (JAVA writes zero bytes as a 2-byte code UTF-8, which is invalid)
  23.339 +         */
  23.340 +        if (result<lowmark)
  23.341 +          return -1;
  23.342 +        /* the code positions 0xd800--0xdfff and 0xfffe & 0xffff do not
  23.343 +         * exist in UCS-4 (and hence, they do not exist in Unicode)
  23.344 +         */
  23.345 +        if (result>=0xd800 && result<=0xdfff || result==0xfffe || result==0xffff)
  23.346 +          return -1;
  23.347 +      } /* if */
  23.348 +      break;
  23.349 +    } else if (follow==0 && (ch & 0x80)==0x80) {
  23.350 +      /* UTF-8 leader code */
  23.351 +      if ((ch & 0xe0)==0xc0) {
  23.352 +        /* 110xxxxx 10xxxxxx */
  23.353 +        follow=1;
  23.354 +        lowmark=0x80L;
  23.355 +        result=ch & 0x1f;
  23.356 +      } else if ((ch & 0xf0)==0xe0) {
  23.357 +        /* 1110xxxx 10xxxxxx 10xxxxxx (16 bits, BMP plane) */
  23.358 +        follow=2;
  23.359 +        lowmark=0x800L;
  23.360 +        result=ch & 0x0f;
  23.361 +      } else if ((ch & 0xf8)==0xf0) {
  23.362 +        /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
  23.363 +        follow=3;
  23.364 +        lowmark=0x10000L;
  23.365 +        result=ch & 0x07;
  23.366 +      } else if ((ch & 0xfc)==0xf8) {
  23.367 +        /* 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */
  23.368 +        follow=4;
  23.369 +        lowmark=0x200000L;
  23.370 +        result=ch & 0x03;
  23.371 +      } else if ((ch & 0xfe)==0xfc) {
  23.372 +        /* 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx (32 bits) */
  23.373 +        follow=5;
  23.374 +        lowmark=0x4000000L;
  23.375 +        result=ch & 0x01;
  23.376 +      } else {
  23.377 +        /* this is invalid UTF-8 */
  23.378 +        return -1;
  23.379 +      } /* if */
  23.380 +    } else if (follow==0 && (ch & 0x80)==0x00) {
  23.381 +      /* 0xxxxxxx (US-ASCII) */
  23.382 +      result=ch;
  23.383 +      break;
  23.384 +    } else {
  23.385 +      /* this is invalid UTF-8 */
  23.386 +      return -1;
  23.387 +    } /* if */
  23.388 +
  23.389 +  } /* for */
  23.390 +
  23.391 +  if (endptr!=NULL)
  23.392 +    *endptr=string;
  23.393 +  return result;
  23.394 +}
  23.395 +#endif
  23.396 +
  23.397 +SC_FUNC int scan_utf8(FILE *fp,const char *filename)
  23.398 +{
  23.399 +  #if defined NO_UTF8
  23.400 +    return 0;
  23.401 +  #else
  23.402 +    void *resetpos=pc_getpossrc(fp);
  23.403 +    int utf8=TRUE;
  23.404 +    int firstchar=TRUE,bom_found=FALSE;
  23.405 +    const unsigned char *ptr;
  23.406 +
  23.407 +    while (utf8 && pc_readsrc(fp,pline,sLINEMAX)!=NULL) {
  23.408 +      ptr=pline;
  23.409 +      if (firstchar) {
  23.410 +        /* check whether the very first character on the very first line
  23.411 +         * starts with a BYTE order mark
  23.412 +         */
  23.413 +        cell c=get_utf8_char(ptr,&ptr);
  23.414 +        bom_found= (c==0xfeff);
  23.415 +        utf8= (c>=0);
  23.416 +        firstchar=FALSE;
  23.417 +      } /* if */
  23.418 +      while (utf8 && *ptr!='\0')
  23.419 +        utf8= (get_utf8_char(ptr,&ptr)>=0);
  23.420 +    } /* while */
  23.421 +    pc_resetsrc(fp,resetpos);
  23.422 +    if (bom_found) {
  23.423 +      unsigned char bom[3];
  23.424 +      if (!utf8)
  23.425 +        error(77,filename);     /* malformed UTF-8 encoding */
  23.426 +      pc_readsrc(fp,bom,3);
  23.427 +      assert(bom[0]==0xef && bom[1]==0xbb && bom[2]==0xbf);
  23.428 +    } /* if */
  23.429 +    return utf8;
  23.430 +  #endif  /* NO_UTF8 */
  23.431 +}
    24.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.2 +++ b/compiler-init/compiler-init/sclist.c	Fri Jul 14 02:02:18 2006 +0000
    24.3 @@ -0,0 +1,486 @@
    24.4 +/*  Pawn compiler  - maintenance of various lists
    24.5 + *
    24.6 + *  o  Name list (aliases)
    24.7 + *  o  Include path list
    24.8 + *  o  Macro defintions (text substitutions)
    24.9 + *
   24.10 + *  Copyright (c) ITB CompuPhase, 2001-2006
   24.11 + *
   24.12 + *  This software is provided "as-is", without any express or implied warranty.
   24.13 + *  In no event will the authors be held liable for any damages arising from
   24.14 + *  the use of this software.
   24.15 + *
   24.16 + *  Permission is granted to anyone to use this software for any purpose,
   24.17 + *  including commercial applications, and to alter it and redistribute it
   24.18 + *  freely, subject to the following restrictions:
   24.19 + *
   24.20 + *  1.  The origin of this software must not be misrepresented; you must not
   24.21 + *      claim that you wrote the original software. If you use this software in
   24.22 + *      a product, an acknowledgment in the product documentation would be
   24.23 + *      appreciated but is not required.
   24.24 + *  2.  Altered source versions must be plainly marked as such, and must not be
   24.25 + *      misrepresented as being the original software.
   24.26 + *  3.  This notice may not be removed or altered from any source distribution.
   24.27 + *
   24.28 + *  Version: $Id: sclist.c 3579 2006-06-06 13:35:29Z thiadmer $
   24.29 + */
   24.30 +#include <assert.h>
   24.31 +#include <limits.h>
   24.32 +#include <stdlib.h>
   24.33 +#include <string.h>
   24.34 +#include "sc.h"
   24.35 +
   24.36 +#if defined FORTIFY
   24.37 +  #include <alloc/fortify.h>
   24.38 +#endif
   24.39 +
   24.40 +/* a "private" implementation of strdup(), so that porting
   24.41 + * to other memory allocators becomes easier.
   24.42 + * By S�ren Hannibal.
   24.43 + */
   24.44 +SC_FUNC char* duplicatestring(const char* sourcestring)
   24.45 +{
   24.46 +  char* result=(char*)malloc(strlen(sourcestring)+1);
   24.47 +  strcpy(result,sourcestring);
   24.48 +  return result;
   24.49 +}
   24.50 +
   24.51 +
   24.52 +static stringpair *insert_stringpair(stringpair *root,char *first,char *second,int matchlength)
   24.53 +{
   24.54 +  stringpair *cur,*pred;
   24.55 +
   24.56 +  assert(root!=NULL);
   24.57 +  assert(first!=NULL);
   24.58 +  assert(second!=NULL);
   24.59 +  /* create a new node, and check whether all is okay */
   24.60 +  if ((cur=(stringpair*)malloc(sizeof(stringpair)))==NULL)
   24.61 +    return NULL;
   24.62 +  cur->first=duplicatestring(first);
   24.63 +  cur->second=duplicatestring(second);
   24.64 +  cur->matchlength=matchlength;
   24.65 +  if (cur->first==NULL || cur->second==NULL) {
   24.66 +    if (cur->first!=NULL)
   24.67 +      free(cur->first);
   24.68 +    if (cur->second!=NULL)
   24.69 +      free(cur->second);
   24.70 +    free(cur);
   24.71 +    return NULL;
   24.72 +  } /* if */
   24.73 +  /* link the node to the tree, find the position */
   24.74 +  for (pred=root; pred->next!=NULL && strcmp(pred->next->first,first)<0; pred=pred->next)
   24.75 +    /* nothing */;
   24.76 +  cur->next=pred->next;
   24.77 +  pred->next=cur;
   24.78 +  return cur;
   24.79 +}
   24.80 +
   24.81 +static void delete_stringpairtable(stringpair *root)
   24.82 +{
   24.83 +  stringpair *cur, *next;
   24.84 +
   24.85 +  assert(root!=NULL);
   24.86 +  cur=root->next;
   24.87 +  while (cur!=NULL) {
   24.88 +    next=cur->next;
   24.89 +    assert(cur->first!=NULL);
   24.90 +    assert(cur->second!=NULL);
   24.91 +    free(cur->first);
   24.92 +    free(cur->second);
   24.93 +    free(cur);
   24.94 +    cur=next;
   24.95 +  } /* while */
   24.96 +  memset(root,0,sizeof(stringpair));
   24.97 +}
   24.98 +
   24.99 +static stringpair *find_stringpair(stringpair *cur,char *first,int matchlength)
  24.100 +{
  24.101 +  int result=0;
  24.102 +
  24.103 +  assert(matchlength>0);  /* the function cannot handle zero-length comparison */
  24.104 +  assert(first!=NULL);
  24.105 +  while (cur!=NULL && result<=0) {
  24.106 +    result=(int)*cur->first - (int)*first;
  24.107 +    if (result==0 && matchlength==cur->matchlength) {
  24.108 +      result=strncmp(cur->first,first,matchlength);
  24.109 +      if (result==0)
  24.110 +        return cur;
  24.111 +    } /* if */
  24.112 +    cur=cur->next;
  24.113 +  } /* while */
  24.114 +  return NULL;
  24.115 +}
  24.116 +
  24.117 +static int delete_stringpair(stringpair *root,stringpair *item)
  24.118 +{
  24.119 +  stringpair *cur;
  24.120 +
  24.121 +  assert(root!=NULL);
  24.122 +  cur=root;
  24.123 +  while (cur->next!=NULL) {
  24.124 +    if (cur->next==item) {
  24.125 +      cur->next=item->next;     /* unlink from list */
  24.126 +      assert(item->first!=NULL);
  24.127 +      assert(item->second!=NULL);
  24.128 +      free(item->first);
  24.129 +      free(item->second);
  24.130 +      free(item);
  24.131 +      return TRUE;
  24.132 +    } /* if */
  24.133 +    cur=cur->next;
  24.134 +  } /* while */
  24.135 +  return FALSE;
  24.136 +}
  24.137 +
  24.138 +/* ----- string list functions ----------------------------------- */
  24.139 +static stringlist *insert_string(stringlist *root,char *string)
  24.140 +{
  24.141 +  stringlist *cur;
  24.142 +
  24.143 +  assert(string!=NULL);
  24.144 +  if ((cur=(stringlist*)malloc(sizeof(stringlist)))==NULL)
  24.145 +    error(103);       /* insufficient memory (fatal error) */
  24.146 +  if ((cur->line=duplicatestring(string))==NULL)
  24.147 +    error(103);       /* insufficient memory (fatal error) */
  24.148 +  /* insert as "last" */
  24.149 +  assert(root!=NULL);
  24.150 +  while (root->next!=NULL)
  24.151 +    root=root->next;
  24.152 +  cur->next=root->next;
  24.153 +  root->next=cur;
  24.154 +  return cur;
  24.155 +}
  24.156 +
  24.157 +static char *get_string(stringlist *root,int index)
  24.158 +{
  24.159 +  stringlist *cur;
  24.160 +
  24.161 +  assert(root!=NULL);
  24.162 +  cur=root->next;
  24.163 +  while (cur!=NULL && index-->0)
  24.164 +    cur=cur->next;
  24.165 +  if (cur!=NULL) {
  24.166 +    assert(cur->line!=NULL);
  24.167 +    return cur->line;
  24.168 +  } /* if */
  24.169 +  return NULL;
  24.170 +}
  24.171 +
  24.172 +static int delete_string(stringlist *root,int index)
  24.173 +{
  24.174 +  stringlist *cur,*item;
  24.175 +
  24.176 +  assert(root!=NULL);
  24.177 +  for (cur=root; cur->next!=NULL && index>0; cur=cur->next,index--)
  24.178 +    /* nothing */;
  24.179 +  if (cur->next!=NULL) {
  24.180 +    item=cur->next;
  24.181 +    cur->next=item->next;       /* unlink from list */
  24.182 +    assert(item->line!=NULL);
  24.183 +    free(item->line);
  24.184 +    free(item);
  24.185 +    return TRUE;
  24.186 +  } /* if */
  24.187 +  return FALSE;
  24.188 +}
  24.189 +
  24.190 +SC_FUNC void delete_stringtable(stringlist *root)
  24.191 +{
  24.192 +  stringlist *cur,*next;
  24.193 +
  24.194 +  assert(root!=NULL);
  24.195 +  cur=root->next;
  24.196 +  while (cur!=NULL) {
  24.197 +    next=cur->next;
  24.198 +    assert(cur->line!=NULL);
  24.199 +    free(cur->line);
  24.200 +    free(cur);
  24.201 +    cur=next;
  24.202 +  } /* while */
  24.203 +  memset(root,0,sizeof(stringlist));
  24.204 +}
  24.205 +
  24.206 +
  24.207 +/* ----- alias table --------------------------------------------- */
  24.208 +static stringpair alias_tab = {NULL, NULL, NULL};   /* alias table */
  24.209 +
  24.210 +SC_FUNC stringpair *insert_alias(char *name,char *alias)
  24.211 +{
  24.212 +  stringpair *cur;
  24.213 +
  24.214 +  assert(name!=NULL);
  24.215 +  assert(strlen(name)<=sNAMEMAX);
  24.216 +  assert(alias!=NULL);
  24.217 +  assert(strlen(alias)<=sNAMEMAX);
  24.218 +  if ((cur=insert_stringpair(&alias_tab,name,alias,strlen(name)))==NULL)
  24.219 +    error(103);       /* insufficient memory (fatal error) */
  24.220 +  return cur;
  24.221 +}
  24.222 +
  24.223 +SC_FUNC int lookup_alias(char *target,char *name)
  24.224 +{
  24.225 +  stringpair *cur=find_stringpair(alias_tab.next,name,strlen(name));
  24.226 +  if (cur!=NULL) {
  24.227 +    assert(strlen(cur->second)<=sNAMEMAX);
  24.228 +    strcpy(target,cur->second);
  24.229 +  } /* if */
  24.230 +  return cur!=NULL;
  24.231 +}
  24.232 +
  24.233 +SC_FUNC void delete_aliastable(void)
  24.234 +{
  24.235 +  delete_stringpairtable(&alias_tab);
  24.236 +}
  24.237 +
  24.238 +/* ----- include paths list -------------------------------------- */
  24.239 +static stringlist includepaths = {NULL, NULL};  /* directory list for include files */
  24.240 +
  24.241 +SC_FUNC stringlist *insert_path(char *path)
  24.242 +{
  24.243 +  return insert_string(&includepaths,path);
  24.244 +}
  24.245 +
  24.246 +SC_FUNC char *get_path(int index)
  24.247 +{
  24.248 +  return get_string(&includepaths,index);
  24.249 +}
  24.250 +
  24.251 +SC_FUNC void delete_pathtable(void)
  24.252 +{
  24.253 +  delete_stringtable(&includepaths);
  24.254 +  assert(includepaths.next==NULL);
  24.255 +}
  24.256 +
  24.257 +
  24.258 +/* ----- text substitution patterns ------------------------------ */
  24.259 +#if !defined NO_DEFINE
  24.260 +
  24.261 +static stringpair substpair = { NULL, NULL, NULL};  /* list of substitution pairs */
  24.262 +
  24.263 +static stringpair *substindex['z'-PUBLIC_CHAR+1]; /* quick index to first character */
  24.264 +static void adjustindex(char c)
  24.265 +{
  24.266 +  stringpair *cur;
  24.267 +  assert(c>='A' && c<='Z' || c>='a' && c<='z' || c=='_' || c==PUBLIC_CHAR);
  24.268 +  assert(PUBLIC_CHAR<'A' && 'A'<'_' && '_'<'z');
  24.269 +
  24.270 +  for (cur=substpair.next; cur!=NULL && cur->first[0]!=c; cur=cur->next)
  24.271 +    /* nothing */;
  24.272 +  substindex[(int)c-PUBLIC_CHAR]=cur;
  24.273 +}
  24.274 +
  24.275 +SC_FUNC stringpair *insert_subst(char *pattern,char *substitution,int prefixlen)
  24.276 +{
  24.277 +  stringpair *cur;
  24.278 +
  24.279 +  assert(pattern!=NULL);
  24.280 +  assert(substitution!=NULL);
  24.281 +  if ((cur=insert_stringpair(&substpair,pattern,substitution,prefixlen))==NULL)
  24.282 +    error(103);       /* insufficient memory (fatal error) */
  24.283 +  adjustindex(*pattern);
  24.284 +  return cur;
  24.285 +}
  24.286 +
  24.287 +SC_FUNC stringpair *find_subst(char *name,int length)
  24.288 +{
  24.289 +  stringpair *item;
  24.290 +  assert(name!=NULL);
  24.291 +  assert(length>0);
  24.292 +  assert(*name>='A' && *name<='Z' || *name>='a' && *name<='z' || *name=='_' || *name==PUBLIC_CHAR);
  24.293 +  item=substindex[(int)*name-PUBLIC_CHAR];
  24.294 +  if (item!=NULL)
  24.295 +    item=find_stringpair(item,name,length);
  24.296 +  return item;
  24.297 +}
  24.298 +
  24.299 +SC_FUNC int delete_subst(char *name,int length)
  24.300 +{
  24.301 +  stringpair *item;
  24.302 +  assert(name!=NULL);
  24.303 +  assert(length>0);
  24.304 +  assert(*name>='A' && *name<='Z' || *name>='a' && *name<='z' || *name=='_' || *name==PUBLIC_CHAR);
  24.305 +  item=substindex[(int)*name-PUBLIC_CHAR];
  24.306 +  if (item!=NULL)
  24.307 +    item=find_stringpair(item,name,length);
  24.308 +  if (item==NULL)
  24.309 +    return FALSE;
  24.310 +  delete_stringpair(&substpair,item);
  24.311 +  adjustindex(*name);
  24.312 +  return TRUE;
  24.313 +}
  24.314 +
  24.315 +SC_FUNC void delete_substtable(void)
  24.316 +{
  24.317 +  int i;
  24.318 +  delete_stringpairtable(&substpair);
  24.319 +  for (i=0; i<sizeof substindex/sizeof substindex[0]; i++)
  24.320 +    substindex[i]=NULL;
  24.321 +}
  24.322 +
  24.323 +#endif /* !defined NO_SUBST */
  24.324 +
  24.325 +
  24.326 +/* ----- input file list ----------------------------------------- */
  24.327 +static stringlist sourcefiles = {NULL, NULL};
  24.328 +
  24.329 +SC_FUNC stringlist *insert_sourcefile(char *string)
  24.330 +{
  24.331 +  return insert_string(&sourcefiles,string);
  24.332 +}
  24.333 +
  24.334 +SC_FUNC char *get_sourcefile(int index)
  24.335 +{
  24.336 +  return get_string(&sourcefiles,index);
  24.337 +}
  24.338 +
  24.339 +SC_FUNC void delete_sourcefiletable(void)
  24.340 +{
  24.341 +  delete_stringtable(&sourcefiles);
  24.342 +  assert(sourcefiles.next==NULL);
  24.343 +}
  24.344 +
  24.345 +
  24.346 +/* ----- documentation tags -------------------------------------- */
  24.347 +#if !defined SC_LIGHT
  24.348 +static stringlist docstrings = {NULL, NULL};
  24.349 +
  24.350 +SC_FUNC stringlist *insert_docstring(char *string)
  24.351 +{
  24.352 +  return insert_string(&docstrings,string);
  24.353 +}
  24.354 +
  24.355 +SC_FUNC char *get_docstring(int index)
  24.356 +{
  24.357 +  return get_string(&docstrings,index);
  24.358 +}
  24.359 +
  24.360 +SC_FUNC void delete_docstring(int index)
  24.361 +{
  24.362 +  delete_string(&docstrings,index);
  24.363 +}
  24.364 +
  24.365 +SC_FUNC void delete_docstringtable(void)
  24.366 +{
  24.367 +  delete_stringtable(&docstrings);
  24.368 +  assert(docstrings.next==NULL);
  24.369 +}
  24.370 +#endif /* !defined SC_LIGHT */
  24.371 +
  24.372 +
  24.373 +/* ----- autolisting --------------------------------------------- */
  24.374 +static stringlist autolist = {NULL, NULL};
  24.375 +
  24.376 +SC_FUNC stringlist *insert_autolist(char *string)
  24.377 +{
  24.378 +  return insert_string(&autolist,string);
  24.379 +}
  24.380 +
  24.381 +SC_FUNC char *get_autolist(int index)
  24.382 +{
  24.383 +  return get_string(&autolist,index);
  24.384 +}
  24.385 +
  24.386 +SC_FUNC void delete_autolisttable(void)
  24.387 +{
  24.388 +  delete_stringtable(&autolist);
  24.389 +  assert(autolist.next==NULL);
  24.390 +}
  24.391 +
  24.392 +
  24.393 +/* ----- debug information --------------------------------------- */
  24.394 +
  24.395 +/* These macros are adapted from LibDGG libdgg-int64.h, see
  24.396 + * http://www.dennougedougakkai-ndd.org/pub/libdgg/
  24.397 + */
  24.398 +#if defined(__STDC_VERSION__) && __STDC_VERSION__>=199901L
  24.399 +  #define __STDC_FORMAT_MACROS
  24.400 +  #define __STDC_CONSTANT_MACROS
  24.401 +  #include <inttypes.h>         /* automatically includes stdint.h */
  24.402 +#elif (defined _MSC_VER || defined __BORLANDC__) && (defined _I64_MAX || defined HAVE_I64)
  24.403 +  #define PRId64 "I64d"
  24.404 +  #define PRIx64 "I64x"
  24.405 +#else
  24.406 +  #define PRId64 "lld"
  24.407 +  #define PRIx64 "llx"
  24.408 +#endif
  24.409 +#if PAWN_CELL_SIZE==64
  24.410 +  #define PRIdC  PRId64
  24.411 +  #define PRIxC  PRIx64
  24.412 +#elif PAWN_CELL_SIZE==32
  24.413 +  #define PRIdC  "ld"
  24.414 +  #define PRIxC  "lx"
  24.415 +#else
  24.416 +  #define PRIdC  "d"
  24.417 +  #define PRIxC  "x"
  24.418 +#endif
  24.419 +
  24.420 +static stringlist dbgstrings = {NULL, NULL};
  24.421 +
  24.422 +SC_FUNC stringlist *insert_dbgfile(const char *filename)
  24.423 +{
  24.424 +
  24.425 +  if (sc_status==statWRITE && (sc_debug & sSYMBOLIC)!=0) {
  24.426 +    char string[_MAX_PATH+40];
  24.427 +    assert(filename!=NULL);
  24.428 +    assert(strlen(filename)+40<sizeof string);
  24.429 +    sprintf(string,"F:%" PRIxC " %s",code_idx,filename);
  24.430 +    return insert_string(&dbgstrings,string);
  24.431 +  } /* if */
  24.432 +  return NULL;
  24.433 +}
  24.434 +
  24.435 +SC_FUNC stringlist *insert_dbgline(int linenr)
  24.436 +{
  24.437 +  if (sc_status==statWRITE && (sc_debug & sSYMBOLIC)!=0) {
  24.438 +    char string[40];
  24.439 +    if (linenr>0)
  24.440 +      linenr--;         /* line numbers are zero-based in the debug information */
  24.441 +    sprintf(string,"L:%" PRIxC " %x",code_idx,linenr);
  24.442 +    return insert_string(&dbgstrings,string);
  24.443 +  } /* if */
  24.444 +  return NULL;
  24.445 +}
  24.446 +
  24.447 +SC_FUNC stringlist *insert_dbgsymbol(symbol *sym)
  24.448 +{
  24.449 +  if (sc_status==statWRITE && (sc_debug & sSYMBOLIC)!=0) {
  24.450 +    char string[2*sNAMEMAX+128];
  24.451 +    char symname[2*sNAMEMAX+16];
  24.452 +
  24.453 +    funcdisplayname(symname,sym->name);
  24.454 +    /* address tag:name codestart codeend ident vclass [tag:dim ...] */
  24.455 +    if (sym->ident==iFUNCTN) {
  24.456 +      sprintf(string,"S:%" PRIxC " %x:%s %" PRIxC " %" PRIxC " %x %x",
  24.457 +              sym->addr,sym->tag,symname,sym->addr,sym->codeaddr,sym->ident,sym->vclass);
  24.458 +    } else {
  24.459 +      sprintf(string,"S:%" PRIxC " %x:%s %" PRIxC " %" PRIxC " %x %x",
  24.460 +              sym->addr,sym->tag,symname,sym->codeaddr,code_idx,sym->ident,sym->vclass);
  24.461 +    } /* if */
  24.462 +    if (sym->ident==iARRAY || sym->ident==iREFARRAY) {
  24.463 +      #if !defined NDEBUG
  24.464 +        int count=sym->dim.array.level;
  24.465 +      #endif
  24.466 +      symbol *sub;
  24.467 +      strcat(string," [ ");
  24.468 +      for (sub=sym; sub!=NULL; sub=finddepend(sub)) {
  24.469 +        assert(sub->dim.array.level==count--);
  24.470 +        sprintf(string+strlen(string),"%x:%x ",sub->x.tags.index,sub->dim.array.length);
  24.471 +      } /* for */
  24.472 +      strcat(string,"]");
  24.473 +    } /* if */
  24.474 +
  24.475 +    return insert_string(&dbgstrings,string);
  24.476 +  } /* if */
  24.477 +  return NULL;
  24.478 +}
  24.479 +
  24.480 +SC_FUNC char *get_dbgstring(int index)
  24.481 +{
  24.482 +  return get_string(&dbgstrings,index);
  24.483 +}
  24.484 +
  24.485 +SC_FUNC void delete_dbgstringtable(void)
  24.486 +{
  24.487 +  delete_stringtable(&dbgstrings);
  24.488 +  assert(dbgstrings.next==NULL);
  24.489 +}
    25.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.2 +++ b/compiler-init/compiler-init/scmemfil.c	Fri Jul 14 02:02:18 2006 +0000
    25.3 @@ -0,0 +1,179 @@
    25.4 +/*  Pawn compiler
    25.5 + *
    25.6 + *  Routines to maintain a "text file" in memory.
    25.7 + *
    25.8 + *  Copyright (c) ITB CompuPhase, 2003-2006
    25.9 + *
   25.10 + *  This software is provided 'as-is', without any express or implied warranty.
   25.11 + *  In no event will the authors be held liable for any damages arising from the
   25.12 + *  use of this software.
   25.13 + *
   25.14 + *  Permission is granted to anyone to use this software for any purpose,
   25.15 + *  including commercial applications, and to alter it and redistribute it
   25.16 + *  freely, subject to the following restrictions:
   25.17 + *
   25.18 + *  1. The origin of this software must not be misrepresented; you must not
   25.19 + *     claim that you wrote the original software. If you use this software in
   25.20 + *     a product, an acknowledgment in the product documentation would be
   25.21 + *     appreciated but is not required.
   25.22 + *
   25.23 + *  2. Altered source versions must be plainly marked as such, and must not be
   25.24 + *     misrepresented as being the original software.
   25.25 + *
   25.26 + *  3. This notice may not be removed or altered from any source distribution.
   25.27 + *
   25.28 + *  Version: $Id: scmemfil.c 3579 2006-06-06 13:35:29Z thiadmer $
   25.29 + */
   25.30 +
   25.31 +#include <assert.h>
   25.32 +#include <stdio.h>
   25.33 +#include <stdlib.h>
   25.34 +#include <string.h>
   25.35 +#include "memfile.h"
   25.36 +
   25.37 +#if defined FORTIFY
   25.38 +  #include <alloc/fortify.h>
   25.39 +#endif
   25.40 +
   25.41 +
   25.42 +#define BUFFERSIZE 512u
   25.43 +
   25.44 +/* For every block, except the first:
   25.45 + *   buffer points to a block that is BUFFERSIZE long that holds the data
   25.46 + *   bufpos is the "used size" of the block
   25.47 + * For the first block:
   25.48 + *   buffer points to the "file name"
   25.49 + *   bufpos is the current "file pointer"
   25.50 + */
   25.51 +typedef memfile_t MEMFILE;
   25.52 +#define tMEMFILE  1
   25.53 +
   25.54 +#include "sc.h"
   25.55 +
   25.56 +
   25.57 +MEMFILE *mfcreate(char *filename)
   25.58 +{
   25.59 +  return memfile_creat(filename, 4096);
   25.60 +}
   25.61 +
   25.62 +void mfclose(MEMFILE *mf)
   25.63 +{
   25.64 +  memfile_destroy(mf);
   25.65 +}
   25.66 +
   25.67 +int mfdump(MEMFILE *mf)
   25.68 +{
   25.69 +  FILE *fp;
   25.70 +  int okay;
   25.71 +
   25.72 +  assert(mf!=NULL);
   25.73 +  /* create the file */
   25.74 +  fp=fopen(mf->name, "wb");
   25.75 +  if (fp==NULL)
   25.76 +    return 0;
   25.77 +
   25.78 +  okay=1;
   25.79 +  okay = okay & (fwrite(mf->base, mf->usedoffs, 1, fp)==(size_t)mf->usedoffs);
   25.80 +  
   25.81 +  fclose(fp);
   25.82 +  return okay;
   25.83 +}
   25.84 +
   25.85 +long mflength(MEMFILE *mf)
   25.86 +{
   25.87 +  return mf->usedoffs;
   25.88 +}
   25.89 +
   25.90 +long mfseek(MEMFILE *mf,long offset,int whence)
   25.91 +{
   25.92 +  long length;
   25.93 +
   25.94 +  assert(mf!=NULL);
   25.95 +  if (mf->usedoffs == 0)
   25.96 +    return 0L;          /* early exit: not a single byte in the file */
   25.97 +
   25.98 +  /* find the size of the memory file */
   25.99 +  length=mflength(mf);
  25.100 +
  25.101 +  /* convert the offset to an absolute position */
  25.102 +  switch (whence) {
  25.103 +  case SEEK_SET:
  25.104 +    break;
  25.105 +  case SEEK_CUR:
  25.106 +    offset+=mf->offs;
  25.107 +    break;
  25.108 +  case SEEK_END:
  25.109 +    assert(offset<=0);
  25.110 +    offset+=length;
  25.111 +    break;
  25.112 +  } /* switch */
  25.113 +
  25.114 +  /* clamp to the file length limit */
  25.115 +  if (offset<0)
  25.116 +    offset=0;
  25.117 +  else if (offset>length)
  25.118 +    offset=length;
  25.119 +
  25.120 +  /* set new position and return it */
  25.121 +  memfile_seek(mf, offset);
  25.122 +
  25.123 +  return offset;
  25.124 +}
  25.125 +
  25.126 +unsigned int mfwrite(MEMFILE *mf,unsigned char *buffer,unsigned int size)
  25.127 +{
  25.128 +  return (memfile_write(mf, buffer, size) ? size : 0);
  25.129 +}
  25.130 +
  25.131 +unsigned int mfread(MEMFILE *mf,unsigned char *buffer,unsigned int size)
  25.132 +{
  25.133 +  return memfile_read(mf, buffer, size);
  25.134 +}
  25.135 +
  25.136 +char *mfgets(MEMFILE *mf,char *string,unsigned int size)
  25.137 +{
  25.138 +  char *ptr;
  25.139 +  unsigned int read;
  25.140 +  long seek;
  25.141 +
  25.142 +  assert(mf!=NULL);
  25.143 +
  25.144 +  read=mfread(mf,(unsigned char *)string,size);
  25.145 +  if (read==0)
  25.146 +    return NULL;
  25.147 +  seek=0L;
  25.148 +
  25.149 +  /* make sure that the string is zero-terminated */
  25.150 +  assert(read<=size);
  25.151 +  if (read<size) {
  25.152 +    string[read]='\0';
  25.153 +  } else {
  25.154 +    string[size-1]='\0';
  25.155 +    seek=-1;            /* undo reading the character that gets overwritten */
  25.156 +  } /* if */
  25.157 +
  25.158 +  /* find the first '\n' */
  25.159 +  ptr=strchr(string,'\n');
  25.160 +  if (ptr!=NULL) {
  25.161 +    *(ptr+1)='\0';
  25.162 +    seek=(long)(ptr-string)+1-(long)read;
  25.163 +  } /* if */
  25.164 +
  25.165 +  /* undo over-read */
  25.166 +  assert(seek<=0);      /* should seek backward only */
  25.167 +  if (seek!=0)
  25.168 +    mfseek(mf,seek,SEEK_CUR);
  25.169 +
  25.170 +  return string;
  25.171 +}
  25.172 +
  25.173 +int mfputs(MEMFILE *mf,char *string)
  25.174 +{
  25.175 +  unsigned int written,length;
  25.176 +
  25.177 +  assert(mf!=NULL);
  25.178 +
  25.179 +  length=strlen(string);
  25.180 +  written=mfwrite(mf,(unsigned char *)string,length);
  25.181 +  return written==length;
  25.182 +}
    26.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.2 +++ b/compiler-init/compiler-init/scstate.c	Fri Jul 14 02:02:18 2006 +0000
    26.3 @@ -0,0 +1,375 @@
    26.4 +/*  Pawn compiler
    26.5 + *
    26.6 + *  Machine and state maintenance.
    26.7 + *
    26.8 + *  Three lists are maintained here:
    26.9 + *  - A list of automatons (state machines): these hold a name, a unique id
   26.10 + *    (in the "index" field) and the memory address of a cell that holds the
   26.11 + *    current state of the automaton (in the "value" field).
   26.12 + *  - A list of states for each automaton: a name, an automaton id (in the
   26.13 + *    "index" field) and a unique id for the state (unique in the automaton;
   26.14 + *    states belonging to different automatons may have the same id).
   26.15 + *  - A list of state combinations. Each function may belong to a set of states.
   26.16 + *    This list assigns a unique id to the combination of the automaton and all
   26.17 + *    states.
   26.18 + *
   26.19 + *  For a function/variable that has states, there is a fourth list, which is
   26.20 + *  attached to the "symbol" structure. This list contains the code label (in
   26.21 + *  the "name" field, only for functions), the id of the state combinations (the
   26.22 + *  state list id; it is stored in the "index" field) and the code address at
   26.23 + *  which the function starts. The latter is currently unused.
   26.24 + *
   26.25 + *  At the start of the compiled code, a set of stub functions is generated.
   26.26 + *  Each stub function looks up the value of the "state selector" value for the
   26.27 + *  automaton, and goes with a "switch" instruction to the start address of the
   26.28 + *  function. This happens in SC4.C.
   26.29 + *
   26.30 + *
   26.31 + *  Copyright (c) ITB CompuPhase, 2005-2006
   26.32 + *
   26.33 + *  This software is provided "as-is", without any express or implied warranty.
   26.34 + *  In no event will the authors be held liable for any damages arising from
   26.35 + *  the use of this software.
   26.36 + *
   26.37 + *  Permission is granted to anyone to use this software for any purpose,
   26.38 + *  including commercial applications, and to alter it and redistribute it
   26.39 + *  freely, subject to the following restrictions:
   26.40 + *
   26.41 + *  1.  The origin of this software must not be misrepresented; you must not
   26.42 + *      claim that you wrote the original software. If you use this software in
   26.43 + *      a product, an acknowledgment in the product documentation would be
   26.44 + *      appreciated but is not required.
   26.45 + *  2.  Altered source versions must be plainly marked as such, and must not be
   26.46 + *      misrepresented as being the original software.
   26.47 + *  3.  This notice may not be removed or altered from any source distribution.
   26.48 + *
   26.49 + *  Version: $Id: scstate.c 3579 2006-06-06 13:35:29Z thiadmer $
   26.50 + */
   26.51 +#include <assert.h>
   26.52 +#include <limits.h>
   26.53 +#include <stdio.h>
   26.54 +#include <stdlib.h>
   26.55 +#include <string.h>
   26.56 +#include "sc.h"
   26.57 +#if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
   26.58 +  #include <sclinux.h>
   26.59 +#endif
   26.60 +
   26.61 +#if defined FORTIFY
   26.62 +  #include <alloc/fortify.h>
   26.63 +#endif
   26.64 +
   26.65 +typedef struct s_statelist {
   26.66 +  struct s_statelist *next;
   26.67 +  int *states;          /* list of states in this combination */
   26.68 +  int numstates;        /* number of items in the above list */
   26.69 +  int fsa;              /* automaton id */
   26.70 +  int listid;           /* unique id for this combination list */
   26.71 +} statelist;
   26.72 +
   26.73 +static statelist statelist_tab = { NULL, NULL, 0, 0, 0};   /* state combinations table */
   26.74 +
   26.75 +
   26.76 +static constvalue *find_automaton(const char *name,int *last)
   26.77 +{
   26.78 +  constvalue *ptr;
   26.79 +
   26.80 +  assert(last!=NULL);
   26.81 +  *last=0;
   26.82 +  ptr=sc_automaton_tab.next;
   26.83 +  while (ptr!=NULL) {
   26.84 +    if (strcmp(name,ptr->name)==0)
   26.85 +      return ptr;
   26.86 +    if (ptr->index>*last)
   26.87 +      *last=ptr->index;
   26.88 +    ptr=ptr->next;
   26.89 +  } /* while */
   26.90 +  return NULL;
   26.91 +}
   26.92 +
   26.93 +SC_FUNC constvalue *automaton_add(const char *name)
   26.94 +{
   26.95 +  constvalue *ptr;
   26.96 +  int last;
   26.97 +
   26.98 +  assert(strlen(name)<sizeof(ptr->name));
   26.99 +  ptr=find_automaton(name,&last);
  26.100 +  if (ptr==NULL) {
  26.101 +    assert(last+1 <= SHRT_MAX);
  26.102 +    ptr=append_constval(&sc_automaton_tab,name,(cell)0,(short)(last+1));
  26.103 +  } /* if */
  26.104 +  return ptr;
  26.105 +}
  26.106 +
  26.107 +SC_FUNC constvalue *automaton_find(const char *name)
  26.108 +{
  26.109 +  int last;
  26.110 +  return find_automaton(name,&last);
  26.111 +}
  26.112 +
  26.113 +SC_FUNC constvalue *automaton_findid(int id)
  26.114 +{
  26.115 +  constvalue *ptr;
  26.116 +  for (ptr=sc_automaton_tab.next; ptr!=NULL && ptr->index!=id; ptr=ptr->next)
  26.117 +    /* nothing */;
  26.118 +  return ptr;
  26.119 +}
  26.120 +
  26.121 +
  26.122 +static constvalue *find_state(const char *name,int fsa,int *last)
  26.123 +{
  26.124 +  constvalue *ptr;
  26.125 +
  26.126 +  assert(last!=NULL);
  26.127 +  *last=0;
  26.128 +  ptr=sc_state_tab.next;
  26.129 +  while (ptr!=NULL) {
  26.130 +    if (ptr->index==fsa) {
  26.131 +      if (strcmp(name,ptr->name)==0)
  26.132 +        return ptr;
  26.133 +      if ((int)ptr->value>*last)
  26.134 +        *last=(int)ptr->value;
  26.135 +    } /* if */
  26.136 +    ptr=ptr->next;
  26.137 +  } /* while */
  26.138 +  return NULL;
  26.139 +}
  26.140 +
  26.141 +SC_FUNC constvalue *state_add(const char *name,int fsa)
  26.142 +{
  26.143 +  constvalue *ptr;
  26.144 +  int last;
  26.145 +
  26.146 +  assert(strlen(name)<sizeof(ptr->name));
  26.147 +  ptr=find_state(name,fsa,&last);
  26.148 +  if (ptr==NULL) {
  26.149 +    assert(fsa <= SHRT_MAX);
  26.150 +    ptr=append_constval(&sc_state_tab,name,(cell)(last+1),(short)fsa);
  26.151 +  } /* if */
  26.152 +  return ptr;
  26.153 +}
  26.154 +
  26.155 +SC_FUNC constvalue *state_find(const char *name,int fsa_id)
  26.156 +{
  26.157 +  int last;     /* dummy */
  26.158 +  return find_state(name,fsa_id,&last);
  26.159 +}
  26.160 +
  26.161 +SC_FUNC constvalue *state_findid(int id)
  26.162 +{
  26.163 +  constvalue *ptr;
  26.164 +  for (ptr=sc_state_tab.next; ptr!=NULL && ptr->value!=id; ptr=ptr->next)
  26.165 +    /* nothing */;
  26.166 +  return ptr;
  26.167 +}
  26.168 +
  26.169 +SC_FUNC void state_buildlist(int **list,int *listsize,int *count,int stateid)
  26.170 +{
  26.171 +  int idx;
  26.172 +
  26.173 +  assert(list!=NULL);
  26.174 +  assert(listsize!=NULL);
  26.175 +  assert(*listsize>=0);
  26.176 +  assert(count!=NULL);
  26.177 +  assert(*count>=0);
  26.178 +  assert(*count<=*listsize);
  26.179 +
  26.180 +  if (*count==*listsize) {
  26.181 +    /* To avoid constantly calling malloc(), the list is grown by 4 states at
  26.182 +     * a time.
  26.183 +     */
  26.184 +    *listsize+=4;
  26.185 +    *list=(int*)realloc(*list,*listsize*sizeof(int));
  26.186 +    if (*list==NULL)
  26.187 +      error(103);               /* insufficient memory */
  26.188 +  } /* if */
  26.189 +
  26.190 +  /* find the insertion point (the list has to stay sorted) */
  26.191 +  for (idx=0; idx<*count && *list[idx]<stateid; idx++)
  26.192 +    /* nothing */;
  26.193 +  if (idx<*count)
  26.194 +    memmove(&(*list)[idx+1],&(*list)[idx],(int)((*count-idx+1)*sizeof(int)));
  26.195 +  (*list)[idx]=stateid;
  26.196 +  *count+=1;
  26.197 +}
  26.198 +
  26.199 +static statelist *state_findlist(int *list,int count,int fsa,int *last)
  26.200 +{
  26.201 +  statelist *ptr;
  26.202 +  int i;
  26.203 +
  26.204 +  assert(count>0);
  26.205 +  assert(last!=NULL);
  26.206 +  *last=0;
  26.207 +  ptr=statelist_tab.next;
  26.208 +  while (ptr!=NULL) {
  26.209 +    if (ptr->listid>*last)
  26.210 +      *last=ptr->listid;
  26.211 +    if (ptr->fsa==fsa && ptr->numstates==count) {
  26.212 +      /* compare all states */
  26.213 +      for (i=0; i<count && ptr->states[i]==list[i]; i++)
  26.214 +        /* nothing */;
  26.215 +      if (i==count)
  26.216 +        return ptr;
  26.217 +    } /* if */
  26.218 +    ptr=ptr->next;
  26.219 +  } /* while */
  26.220 +  return NULL;
  26.221 +}
  26.222 +
  26.223 +static statelist *state_getlist_ptr(int listid)
  26.224 +{
  26.225 +  statelist *ptr;
  26.226 +
  26.227 +  assert(listid>0);
  26.228 +  for (ptr=statelist_tab.next; ptr!=NULL && ptr->listid!=listid; ptr=ptr->next)
  26.229 +    /* nothing */;
  26.230 +  return ptr;
  26.231 +}
  26.232 +
  26.233 +SC_FUNC int state_addlist(int *list,int count,int fsa)
  26.234 +{
  26.235 +  statelist *ptr;
  26.236 +  int last;
  26.237 +
  26.238 +  assert(list!=NULL);
  26.239 +  assert(count>0);
  26.240 +  ptr=state_findlist(list,count,fsa,&last);
  26.241 +  if (ptr==NULL) {
  26.242 +    if ((ptr=(statelist*)malloc(sizeof(statelist)))==NULL)
  26.243 +      error(103);       /* insufficient memory */
  26.244 +    if ((ptr->states=(int*)malloc(count*sizeof(int)))==NULL) {
  26.245 +      free(ptr);
  26.246 +      error(103);       /* insufficient memory */
  26.247 +    } /* if */
  26.248 +    memcpy(ptr->states,list,count*sizeof(int));
  26.249 +    ptr->numstates=count;
  26.250 +    ptr->fsa=fsa;
  26.251 +    ptr->listid=last+1;
  26.252 +    ptr->next=statelist_tab.next;
  26.253 +    statelist_tab.next=ptr;
  26.254 +  } /* if */
  26.255 +  assert(ptr!=NULL);
  26.256 +  return ptr->listid;
  26.257 +}
  26.258 +
  26.259 +SC_FUNC void state_deletetable(void)
  26.260 +{
  26.261 +  statelist *ptr;
  26.262 +
  26.263 +  while (statelist_tab.next!=NULL) {
  26.264 +    ptr=statelist_tab.next;
  26.265 +    /* unlink first */
  26.266 +    statelist_tab.next=ptr->next;
  26.267 +    /* then delete */
  26.268 +    assert(ptr->states!=NULL);
  26.269 +    free(ptr->states);
  26.270 +    free(ptr);
  26.271 +  } /* while */
  26.272 +}
  26.273 +
  26.274 +SC_FUNC int state_getfsa(int listid)
  26.275 +{
  26.276 +  statelist *ptr;
  26.277 +
  26.278 +  assert(listid>=0);
  26.279 +  if (listid==0)
  26.280 +    return -1;
  26.281 +
  26.282 +  ptr=state_getlist_ptr(listid);
  26.283 +  return (ptr!=NULL) ? ptr->fsa : -1; /* fsa 0 exists */
  26.284 +}
  26.285 +
  26.286 +SC_FUNC int state_count(int listid)
  26.287 +{
  26.288 +  statelist *ptr=state_getlist_ptr(listid);
  26.289 +  if (ptr==NULL)
  26.290 +    return 0;           /* unknown list, no states in it */
  26.291 +  return ptr->numstates;
  26.292 +}
  26.293 +
  26.294 +SC_FUNC int state_inlist(int listid,int state)
  26.295 +{
  26.296 +  statelist *ptr;
  26.297 +  int i;
  26.298 +
  26.299 +  ptr=state_getlist_ptr(listid);
  26.300 +  if (ptr==NULL)
  26.301 +    return FALSE;       /* unknown list, state not in it */
  26.302 +  for (i=0; i<ptr->numstates; i++)
  26.303 +    if (ptr->states[i]==state)
  26.304 +      return TRUE;
  26.305 +  return FALSE;
  26.306 +}
  26.307 +
  26.308 +SC_FUNC int state_listitem(int listid,int index)
  26.309 +{
  26.310 +  statelist *ptr;
  26.311 +
  26.312 +  ptr=state_getlist_ptr(listid);
  26.313 +  assert(ptr!=NULL);
  26.314 +  assert(index>=0 && index<ptr->numstates);
  26.315 +  return ptr->states[index];
  26.316 +}
  26.317 +
  26.318 +static int checkconflict(statelist *psrc,statelist *ptgt)
  26.319 +{
  26.320 +  int s,t;
  26.321 +
  26.322 +  assert(psrc!=NULL);
  26.323 +  assert(ptgt!=NULL);
  26.324 +  for (s=0; s<psrc->numstates; s++)
  26.325 +    for (t=0; t<ptgt->numstates; t++)
  26.326 +      if (psrc->states[s]==ptgt->states[t])
  26.327 +        return 1;       /* state conflict */
  26.328 +  return 0;
  26.329 +}
  26.330 +
  26.331 +/* This function searches whether one of the states in the list of statelist id's
  26.332 + * of a symbol exists in any other statelist id's of the same function; it also
  26.333 + * verifies that all definitions of the symbol are in the same automaton.
  26.334 + */
  26.335 +SC_FUNC void state_conflict(symbol *root)
  26.336 +{
  26.337 +  statelist *psrc,*ptgt;
  26.338 +  constvalue *srcptr,*tgtptr;
  26.339 +  symbol *sym;
  26.340 +
  26.341 +  assert(root!=NULL);
  26.342 +  for (sym=root->next; sym!=NULL; sym=sym->next) {
  26.343 +    if (sym->parent!=NULL || sym->ident!=iFUNCTN)
  26.344 +      continue;                 /* hierarchical data type or no function */
  26.345 +    if (sym->states==NULL)
  26.346 +      continue;                 /* this function has no states */
  26.347 +    for (srcptr=sym->states->next; srcptr!=NULL; srcptr=srcptr->next) {
  26.348 +      if (srcptr->index==-1)
  26.349 +        continue;               /* state list id -1 is a special case */
  26.350 +      psrc=state_getlist_ptr(srcptr->index);
  26.351 +      assert(psrc!=NULL);
  26.352 +      for (tgtptr=srcptr->next; tgtptr!=NULL; tgtptr=tgtptr->next) {
  26.353 +        if (tgtptr->index==-1)
  26.354 +          continue;             /* state list id -1 is a special case */
  26.355 +        ptgt=state_getlist_ptr(tgtptr->index);
  26.356 +        assert(ptgt!=NULL);
  26.357 +        if (psrc->fsa!=ptgt->fsa && strcmp(sym->name,uENTRYFUNC)!=0)
  26.358 +          error(83,sym->name);  /* this function is part of another machine */
  26.359 +        if (checkconflict(psrc,ptgt))
  26.360 +          error(84,sym->name);  /* state conflict */
  26.361 +      } /* for (tgtptr) */
  26.362 +    } /* for (srcptr) */
  26.363 +  } /* for (sym) */
  26.364 +}
  26.365 +
  26.366 +/* check whether the two state lists (whose ids are passed in) share any
  26.367 + * states
  26.368 + */
  26.369 +SC_FUNC int state_conflict_id(int listid1,int listid2)
  26.370 +{
  26.371 +  statelist *psrc,*ptgt;
  26.372 +
  26.373 +  psrc=state_getlist_ptr(listid1);
  26.374 +  assert(psrc!=NULL);
  26.375 +  ptgt=state_getlist_ptr(listid2);
  26.376 +  assert(ptgt!=NULL);
  26.377 +  return checkconflict(psrc,ptgt);
  26.378 +}
    27.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.2 +++ b/compiler-init/compiler-init/scvars.c	Fri Jul 14 02:02:18 2006 +0000
    27.3 @@ -0,0 +1,113 @@
    27.4 +/*  Pawn compiler
    27.5 + *
    27.6 + *  Global (cross-module) variables.
    27.7 + *
    27.8 + *  Copyright (c) ITB CompuPhase, 1997-2006
    27.9 + *
   27.10 + *  This software is provided "as-is", without any express or implied warranty.
   27.11 + *  In no event will the authors be held liable for any damages arising from
   27.12 + *  the use of this software.
   27.13 + *
   27.14 + *  Permission is granted to anyone to use this software for any purpose,
   27.15 + *  including commercial applications, and to alter it and redistribute it
   27.16 + *  freely, subject to the following restrictions:
   27.17 + *
   27.18 + *  1.  The origin of this software must not be misrepresented; you must not
   27.19 + *      claim that you wrote the original software. If you use this software in
   27.20 + *      a product, an acknowledgment in the product documentation would be
   27.21 + *      appreciated but is not required.
   27.22 + *  2.  Altered source versions must be plainly marked as such, and must not be
   27.23 + *      misrepresented as being the original software.
   27.24 + *  3.  This notice may not be removed or altered from any source distribution.
   27.25 + *
   27.26 + *  Version: $Id: scvars.c 3577 2006-06-02 16:22:52Z thiadmer $
   27.27 + */
   27.28 +#include <stdio.h>
   27.29 +#include <stdlib.h>     /* for _MAX_PATH */
   27.30 +#include "sc.h"
   27.31 +
   27.32 +/*  global variables
   27.33 + *
   27.34 + *  All global variables that are shared amongst the compiler files are
   27.35 + *  declared here.
   27.36 + */
   27.37 +SC_VDEFINE symbol loctab;                   /* local symbol table */
   27.38 +SC_VDEFINE symbol glbtab;                   /* global symbol table */
   27.39 +SC_VDEFINE cell *litq;                      /* the literal queue */
   27.40 +SC_VDEFINE unsigned char pline[sLINEMAX+1]; /* the line read from the input file */
   27.41 +SC_VDEFINE const unsigned char *lptr;       /* points to the current position in "pline" */
   27.42 +SC_VDEFINE constvalue tagname_tab = { NULL, "", 0, 0};  /* tagname table */
   27.43 +SC_VDEFINE constvalue libname_tab = { NULL, "", 0, 0};  /* library table (#pragma library "..." syntax) */
   27.44 +SC_VDEFINE constvalue *curlibrary = NULL;   /* current library */
   27.45 +SC_VDEFINE int pc_addlibtable = TRUE;       /* is the library table added to the AMX file? */
   27.46 +SC_VDEFINE symbol *curfunc;                 /* pointer to current function */
   27.47 +SC_VDEFINE char *inpfname;                  /* pointer to name of the file currently read from */
   27.48 +SC_VDEFINE char outfname[_MAX_PATH];        /* intermediate (assembler) file name */
   27.49 +SC_VDEFINE char binfname[_MAX_PATH];        /* binary file name */
   27.50 +SC_VDEFINE char errfname[_MAX_PATH];        /* error file name */
   27.51 +SC_VDEFINE char sc_ctrlchar = CTRL_CHAR;    /* the control character (or escape character)*/
   27.52 +SC_VDEFINE char sc_ctrlchar_org = CTRL_CHAR;/* the default control character */
   27.53 +SC_VDEFINE int litidx    = 0;               /* index to literal table */
   27.54 +SC_VDEFINE int litmax    = sDEF_LITMAX;     /* current size of the literal table */
   27.55 +SC_VDEFINE int stgidx    = 0;      /* index to the staging buffer */
   27.56 +SC_VDEFINE int sc_labnum = 0;      /* number of (internal) labels */
   27.57 +SC_VDEFINE int staging   = 0;      /* true if staging output */
   27.58 +SC_VDEFINE cell declared = 0;      /* number of local cells declared */
   27.59 +SC_VDEFINE cell glb_declared=0;    /* number of global cells declared */
   27.60 +SC_VDEFINE cell code_idx = 0;      /* number of bytes with generated code */
   27.61 +SC_VDEFINE int ntv_funcid= 0;      /* incremental number of native function */
   27.62 +SC_VDEFINE int errnum    = 0;      /* number of errors */
   27.63 +SC_VDEFINE int warnnum   = 0;      /* number of warnings */
   27.64 +SC_VDEFINE int sc_debug  = sCHKBOUNDS; /* by default: bounds checking+assertions */
   27.65 +SC_VDEFINE int sc_packstr= FALSE;  /* strings are packed by default? */
   27.66 +SC_VDEFINE int sc_asmfile= FALSE;  /* create .ASM file? */
   27.67 +SC_VDEFINE int sc_listing= FALSE;  /* create .LST file? */
   27.68 +SC_VDEFINE int sc_compress=TRUE;   /* compress bytecode? */
   27.69 +SC_VDEFINE int sc_needsemicolon=TRUE;/* semicolon required to terminate expressions? */
   27.70 +SC_VDEFINE int sc_dataalign=sizeof(cell);/* data alignment value */
   27.71 +SC_VDEFINE int sc_alignnext=FALSE; /* must frame of the next function be aligned? */
   27.72 +SC_VDEFINE int pc_docexpr=FALSE;   /* must expression be attached to documentation comment? */
   27.73 +SC_VDEFINE int curseg    = 0;      /* 1 if currently parsing CODE, 2 if parsing DATA */
   27.74 +SC_VDEFINE cell pc_stksize=sDEF_AMXSTACK;/* default stack size */
   27.75 +SC_VDEFINE cell pc_amxlimit=0;     /* default abstract machine size limit = none */
   27.76 +SC_VDEFINE cell pc_amxram=0;       /* default abstract machine data size limit = none */
   27.77 +SC_VDEFINE int freading  = FALSE;  /* Is there an input file ready for reading? */
   27.78 +SC_VDEFINE int fline     = 0;      /* the line number in the current file */
   27.79 +SC_VDEFINE short fnumber = 0;      /* the file number in the file table (debugging) */
   27.80 +SC_VDEFINE short fcurrent= 0;      /* current file being processed (debugging) */
   27.81 +SC_VDEFINE short sc_intest=FALSE;  /* true if inside a test */
   27.82 +SC_VDEFINE int sideeffect= 0;      /* true if an expression causes a side-effect */
   27.83 +SC_VDEFINE int stmtindent= 0;      /* current indent of the statement */
   27.84 +SC_VDEFINE int indent_nowarn=FALSE;/* skip warning "217 loose indentation" */
   27.85 +SC_VDEFINE int sc_tabsize=8;       /* number of spaces that a TAB represents */
   27.86 +SC_VDEFINE short sc_allowtags=TRUE;  /* allow/detect tagnames in lex() */
   27.87 +SC_VDEFINE int sc_status;          /* read/write status */
   27.88 +SC_VDEFINE int sc_rationaltag=0;   /* tag for rational numbers */
   27.89 +SC_VDEFINE int rational_digits=0;  /* number of fractional digits */
   27.90 +SC_VDEFINE int sc_allowproccall=0; /* allow/detect tagnames in lex() */
   27.91 +SC_VDEFINE short sc_is_utf8=FALSE; /* is this source file in UTF-8 encoding */
   27.92 +SC_VDEFINE char *pc_depricate=NULL;/* if non-null, mark next declaration as depricated */
   27.93 +SC_VDEFINE int sc_curstates=0;     /* ID of the current state list */
   27.94 +SC_VDEFINE int pc_optimize=sOPTIMIZE_NOMACRO; /* (peephole) optimization level */
   27.95 +SC_VDEFINE int pc_memflags=0;      /* special flags for the stack/heap usage */
   27.96 +
   27.97 +SC_VDEFINE constvalue sc_automaton_tab = { NULL, "", 0, 0}; /* automaton table */
   27.98 +SC_VDEFINE constvalue sc_state_tab = { NULL, "", 0, 0};   /* state table */
   27.99 +
  27.100 +SC_VDEFINE FILE *inpf    = NULL;   /* file read from (source or include) */
  27.101 +SC_VDEFINE FILE *inpf_org= NULL;   /* main source file */
  27.102 +SC_VDEFINE FILE *outf    = NULL;   /* (intermediate) text file written to */
  27.103 +
  27.104 +SC_VDEFINE jmp_buf errbuf;
  27.105 +
  27.106 +#if !defined SC_LIGHT
  27.107 +  SC_VDEFINE int sc_makereport=FALSE; /* generate a cross-reference report */
  27.108 +#endif
  27.109 +
  27.110 +#if defined __WATCOMC__ && !defined NDEBUG
  27.111 +  /* Watcom's CVPACK dislikes .OBJ files without functions */
  27.112 +  static int dummyfunc(void)
  27.113 +  {
  27.114 +    return 0;
  27.115 +  }
  27.116 +#endif
    28.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.2 +++ b/compiler-init/compiler-init/spcomp.sln	Fri Jul 14 02:02:18 2006 +0000
    28.3 @@ -0,0 +1,21 @@
    28.4 +Microsoft Visual Studio Solution File, Format Version 8.00
    28.5 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spcomp", "spcomp.vcproj", "{B4C844FF-008D-4BD5-B82F-DC06E706C64B}"
    28.6 +	ProjectSection(ProjectDependencies) = postProject
    28.7 +	EndProjectSection
    28.8 +EndProject
    28.9 +Global
   28.10 +	GlobalSection(SolutionConfiguration) = preSolution
   28.11 +		Debug = Debug
   28.12 +		Release = Release
   28.13 +	EndGlobalSection
   28.14 +	GlobalSection(ProjectConfiguration) = postSolution
   28.15 +		{B4C844FF-008D-4BD5-B82F-DC06E706C64B}.Debug.ActiveCfg = Debug|Win32
   28.16 +		{B4C844FF-008D-4BD5-B82F-DC06E706C64B}.Debug.Build.0 = Debug|Win32
   28.17 +		{B4C844FF-008D-4BD5-B82F-DC06E706C64B}.Release.ActiveCfg = Release|Win32
   28.18 +		{B4C844FF-008D-4BD5-B82F-DC06E706C64B}.Release.Build.0 = Release|Win32
   28.19 +	EndGlobalSection
   28.20 +	GlobalSection(ExtensibilityGlobals) = postSolution
   28.21 +	EndGlobalSection
   28.22 +	GlobalSection(ExtensibilityAddIns) = postSolution
   28.23 +	EndGlobalSection
   28.24 +EndGlobal
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/compiler-init/compiler-init/spcomp.vcproj	Fri Jul 14 02:02:18 2006 +0000
    29.3 @@ -0,0 +1,305 @@
    29.4 +<?xml version="1.0" encoding="Windows-1252"?>
    29.5 +<VisualStudioProject
    29.6 +	ProjectType="Visual C++"
    29.7 +	Version="7.10"
    29.8 +	Name="spcomp"
    29.9 +	ProjectGUID="{B4C844FF-008D-4BD5-B82F-DC06E706C64B}"
   29.10 +	RootNamespace="spcomp"
   29.11 +	Keyword="Win32Proj"
   29.12 +	>
   29.13 +	<Platforms>
   29.14 +		<Platform
   29.15 +			Name="Win32"
   29.16 +		/>
   29.17 +	</Platforms>
   29.18 +	<ToolFiles>
   29.19 +	</ToolFiles>
   29.20 +	<Configurations>
   29.21 +		<Configuration
   29.22 +			Name="Debug|Win32"
   29.23 +			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
   29.24 +			IntermediateDirectory="$(ConfigurationName)"
   29.25 +			ConfigurationType="1"
   29.26 +			CharacterSet="1"
   29.27 +			>
   29.28 +			<Tool
   29.29 +				Name="VCPreBuildEventTool"
   29.30 +			/>
   29.31 +			<Tool
   29.32 +				Name="VCCustomBuildTool"
   29.33 +			/>
   29.34 +			<Tool
   29.35 +				Name="VCXMLDataGeneratorTool"
   29.36 +			/>
   29.37 +			<Tool
   29.38 +				Name="VCWebServiceProxyGeneratorTool"
   29.39 +			/>
   29.40 +			<Tool
   29.41 +				Name="VCMIDLTool"
   29.42 +			/>
   29.43 +			<Tool
   29.44 +				Name="VCCLCompilerTool"
   29.45 +				Optimization="0"
   29.46 +				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE"
   29.47 +				MinimalRebuild="true"
   29.48 +				BasicRuntimeChecks="3"
   29.49 +				RuntimeLibrary="3"
   29.50 +				UsePrecompiledHeader="0"
   29.51 +				WarningLevel="3"
   29.52 +				Detect64BitPortabilityProblems="false"
   29.53 +				DebugInformationFormat="4"
   29.54 +			/>
   29.55 +			<Tool
   29.56 +				Name="VCManagedResourceCompilerTool"
   29.57 +			/>
   29.58 +			<Tool
   29.59 +				Name="VCResourceCompilerTool"
   29.60 +			/>
   29.61 +			<Tool
   29.62 +				Name="VCPreLinkEventTool"
   29.63 +			/>
   29.64 +			<Tool
   29.65 +				Name="VCLinkerTool"
   29.66 +				LinkIncremental="2"
   29.67 +				GenerateDebugInformation="true"
   29.68 +				SubSystem="1"
   29.69 +				TargetMachine="1"
   29.70 +			/>
   29.71 +			<Tool
   29.72 +				Name="VCALinkTool"
   29.73 +			/>
   29.74 +			<Tool
   29.75 +				Name="VCManifestTool"
   29.76 +			/>
   29.77 +			<Tool
   29.78 +				Name="VCXDCMakeTool"
   29.79 +			/>
   29.80 +			<Tool
   29.81 +				Name="VCBscMakeTool"
   29.82 +			/>
   29.83 +			<Tool
   29.84 +				Name="VCFxCopTool"
   29.85 +			/>
   29.86 +			<Tool
   29.87 +				Name="VCAppVerifierTool"
   29.88 +			/>
   29.89 +			<Tool
   29.90 +				Name="VCWebDeploymentTool"
   29.91 +			/>
   29.92 +			<Tool
   29.93 +				Name="VCPostBuildEventTool"
   29.94 +			/>
   29.95 +		</Configuration>
   29.96 +		<Configuration
   29.97 +			Name="Release|Win32"
   29.98 +			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
   29.99 +			IntermediateDirectory="$(ConfigurationName)"
  29.100 +			ConfigurationType="1"
  29.101 +			CharacterSet="1"
  29.102 +			WholeProgramOptimization="1"
  29.103 +			>
  29.104 +			<Tool
  29.105 +				Name="VCPreBuildEventTool"
  29.106 +			/>
  29.107 +			<Tool
  29.108 +				Name="VCCustomBuildTool"
  29.109 +			/>
  29.110 +			<Tool
  29.111 +				Name="VCXMLDataGeneratorTool"
  29.112 +			/>
  29.113 +			<Tool
  29.114 +				Name="VCWebServiceProxyGeneratorTool"
  29.115 +			/>
  29.116 +			<Tool
  29.117 +				Name="VCMIDLTool"
  29.118 +			/>
  29.119 +			<Tool
  29.120 +				Name="VCCLCompilerTool"
  29.121 +				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE"
  29.122 +				RuntimeLibrary="2"
  29.123 +				UsePrecompiledHeader="0"
  29.124 +				WarningLevel="3"
  29.125 +				Detect64BitPortabilityProblems="false"
  29.126 +				DebugInformationFormat="3"
  29.127 +			/>
  29.128 +			<Tool
  29.129 +				Name="VCManagedResourceCompilerTool"
  29.130 +			/>
  29.131 +			<Tool
  29.132 +				Name="VCResourceCompilerTool"
  29.133 +			/>
  29.134 +			<Tool
  29.135 +				Name="VCPreLinkEventTool"
  29.136 +			/>
  29.137 +			<Tool
  29.138 +				Name="VCLinkerTool"
  29.139 +				LinkIncremental="1"
  29.140 +				GenerateDebugInformation="true"
  29.141 +				SubSystem="1"
  29.142 +				OptimizeReferences="2"
  29.143 +				EnableCOMDATFolding="2"
  29.144 +				TargetMachine="1"
  29.145 +			/>
  29.146 +			<Tool
  29.147 +				Name="VCALinkTool"
  29.148 +			/>
  29.149 +			<Tool
  29.150 +				Name="VCManifestTool"
  29.151 +			/>
  29.152 +			<Tool
  29.153 +				Name="VCXDCMakeTool"
  29.154 +			/>
  29.155 +			<Tool
  29.156 +				Name="VCBscMakeTool"
  29.157 +			/>
  29.158 +			<Tool
  29.159 +				Name="VCFxCopTool"
  29.160 +			/>
  29.161 +			<Tool
  29.162 +				Name="VCAppVerifierTool"
  29.163 +			/>
  29.164 +			<Tool
  29.165 +				Name="VCWebDeploymentTool"
  29.166 +			/>
  29.167 +			<Tool
  29.168 +				Name="VCPostBuildEventTool"
  29.169 +			/>
  29.170 +		</Configuration>
  29.171 +	</Configurations>
  29.172 +	<References>
  29.173 +	</References>
  29.174 +	<Files>
  29.175 +		<Filter
  29.176 +			Name="Source Files"
  29.177 +			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
  29.178 +			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
  29.179 +			>
  29.180 +			<File
  29.181 +				RelativePath=".\libpawnc.c"
  29.182 +				>
  29.183 +			</File>
  29.184 +			<File
  29.185 +				RelativePath=".\lstring.c"
  29.186 +				>
  29.187 +			</File>
  29.188 +			<File
  29.189 +				RelativePath=".\memfile.c"
  29.190 +				>
  29.191 +			</File>
  29.192 +			<File
  29.193 +				RelativePath=".\pawncc.c"
  29.194 +				>
  29.195 +			</File>
  29.196 +			<File
  29.197 +				RelativePath=".\sc1.c"
  29.198 +				>
  29.199 +			</File>
  29.200 +			<File
  29.201 +				RelativePath=".\sc2.c"
  29.202 +				>
  29.203 +			</File>
  29.204 +			<File
  29.205 +				RelativePath=".\sc3.c"
  29.206 +				>
  29.207 +			</File>
  29.208 +			<File
  29.209 +				RelativePath=".\sc4.c"
  29.210 +				>
  29.211 +			</File>
  29.212 +			<File
  29.213 +				RelativePath=".\sc5.c"
  29.214 +				>
  29.215 +			</File>
  29.216 +			<File
  29.217 +				RelativePath=".\sc6.c"
  29.218 +				>
  29.219 +			</File>
  29.220 +			<File
  29.221 +				RelativePath=".\sc7.c"
  29.222 +				>
  29.223 +			</File>
  29.224 +			<File
  29.225 +				RelativePath=".\scexpand.c"
  29.226 +				>
  29.227 +			</File>
  29.228 +			<File
  29.229 +				RelativePath=".\sci18n.c"
  29.230 +				>
  29.231 +			</File>
  29.232 +			<File
  29.233 +				RelativePath=".\sclist.c"
  29.234 +				>
  29.235 +			</File>
  29.236 +			<File
  29.237 +				RelativePath=".\scmemfil.c"
  29.238 +				>
  29.239 +				<FileConfiguration
  29.240 +					Name="Debug|Win32"
  29.241 +					>
  29.242 +					<Tool
  29.243 +						Name="VCCLCompilerTool"
  29.244 +						Detect64BitPortabilityProblems="false"
  29.245 +					/>
  29.246 +				</FileConfiguration>
  29.247 +			</File>
  29.248 +			<File
  29.249 +				RelativePath=".\scstate.c"
  29.250 +				>
  29.251 +			</File>
  29.252 +			<File
  29.253 +				RelativePath=".\scvars.c"
  29.254 +				>
  29.255 +			</File>
  29.256 +		</Filter>
  29.257 +		<Filter
  29.258 +			Name="Header Files"
  29.259 +			Filter="h;hpp;hxx;hm;inl;inc;xsd"
  29.260 +			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
  29.261 +			>
  29.262 +			<File
  29.263 +				RelativePath=".\amx.h"
  29.264 +				>
  29.265 +			</File>
  29.266 +			<File
  29.267 +				RelativePath=".\lstring.h"
  29.268 +				>
  29.269 +			</File>
  29.270 +			<File
  29.271 +				RelativePath=".\memfile.h"
  29.272 +				>
  29.273 +			</File>
  29.274 +			<File
  29.275 +				RelativePath=".\osdefs.h"
  29.276 +				>
  29.277 +			</File>
  29.278 +			<File
  29.279 +				RelativePath=".\sc.h"
  29.280 +				>
  29.281 +			</File>
  29.282 +			<File
  29.283 +				RelativePath=".\svnrev.h"
  29.284 +				>
  29.285 +			</File>
  29.286 +		</Filter>
  29.287 +		<Filter
  29.288 +			Name="Resource Files"
  29.289 +			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
  29.290 +			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
  29.291 +			>
  29.292 +			<File
  29.293 +				RelativePath=".\libpawnc.rc"
  29.294 +				>
  29.295 +			</File>
  29.296 +			<File
  29.297 +				RelativePath=".\sc5.scp"
  29.298 +				>
  29.299 +			</File>
  29.300 +			<File
  29.301 +				RelativePath=".\sc7.scp"
  29.302 +				>
  29.303 +			</File>
  29.304 +		</Filter>
  29.305 +	</Files>
  29.306 +	<Globals>
  29.307 +	</Globals>
  29.308 +</VisualStudioProject>
    30.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.2 +++ b/compiler-init/compiler-init/svnrev.h	Fri Jul 14 02:02:18 2006 +0000
    30.3 @@ -0,0 +1,9 @@
    30.4 +#define SMC_VERSION		1
    30.5 +#define SMC_REVISION	0
    30.6 +#define SMC_BUILD		1
    30.7 +#define SMC_VERSTRING	"1.0.1.3599"
    30.8 +
    30.9 +#define SVN_REV		3599
   30.10 +#define SVN_REVSTR	"3599"
   30.11 +#define SVN_REVDATE	"2006-07-05"
   30.12 +#define SVN_REVSTAMP	20060705L