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 < 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,"<");
13.3818 + ptr+=4;
13.3819 + break;
13.3820 + case '>':
13.3821 + strcpy(ptr,">");
13.3822 + ptr+=4;
13.3823 + break;
13.3824 + case '&':
13.3825 + strcpy(ptr,"&");
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,"&%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," &");
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,¶ms);
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,¶ms);
19.301 + ucell p2=getparam(params,¶ms);
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,¶ms);
19.315 + ucell p2=getparam(params,¶ms);
19.316 + ucell p3=getparam(params,¶ms);
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,¶ms);
19.331 + ucell p2=getparam(params,¶ms);
19.332 + ucell p3=getparam(params,¶ms);
19.333 + ucell p4=getparam(params,¶ms);
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,¶ms);
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,¶ms);
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