Merge pull request #116 from Arkshine/update-compiler-safe-fix-feature

Update compiler
This commit is contained in:
Vincent Herbet 2014-08-26 09:07:45 +02:00
commit 1463103cd7
24 changed files with 6922 additions and 5730 deletions

View File

@ -130,6 +130,8 @@ class AMXXConfig(object):
'-Wno-uninitialized',
'-Wno-unused',
'-Wno-switch',
'-Wno-format',
'-Wno-format-security',
'-m32',
]
cfg.cxxflags += [

View File

@ -1,9 +1,50 @@
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
import os.path
# Build the packing binary garbage.
scpack = AMXX.Program(builder, 'scpack')
if builder.target_platform == 'windows':
scpack.compiler.linkflags.remove('/SUBSYSTEM:WINDOWS')
scpack.compiler.linkflags.append('/SUBSYSTEM:CONSOLE')
scpack.sources = ['scpack.c']
scpack = builder.Add(scpack)
# Generate pack files.
packed_files = ['sc5', 'sc7']
packed_includes = []
for packed_file in packed_files:
# The absolute path to sc5-in.scp etc.
in_path = os.path.join(builder.currentSourcePath, '{0}-in.scp'.format(packed_file))
# The output file relative to the output folder, i.e. sourcepawn/compiler/sc5.scp.
out_path = os.path.join(builder.buildFolder, '{0}.scp'.format(packed_file))
# The absolute path to the build folder, i.e. /Users/.../sourcepawn/compiler.
build_folder = os.path.join(builder.buildPath, builder.buildFolder)
# scpack runs in ./sourcepawn/compiler/scpack/ so we build relative paths
# from there.
scpack_argv = [
os.path.join(builder.buildPath, scpack.binary.path),
os.path.relpath(in_path, build_folder),
os.path.relpath(os.path.join(builder.buildPath, out_path), build_folder),
]
_, (entry,) = builder.AddCommand(
inputs = [scpack.binary, in_path],
argv = scpack_argv,
outputs = ['{0}.scp'.format(packed_file)],
)
packed_includes += [entry]
binary = AMXX.Library(builder, 'amxxpc32')
binary.compiler.includes += [builder.currentSourcePath]
binary.compiler.includes += [
builder.currentSourcePath,
os.path.join(builder.buildPath, builder.buildFolder),
]
binary.compiler.sourcedeps += packed_includes
if builder.target_platform in ['mac', 'linux']:
binary.compiler.defines += ['ENABLE_BINRELOC']
@ -34,6 +75,7 @@ binary.sources = [
'libpawnc.c',
'prefix.c',
'memfile.c',
'sp_symhash.c',
]
if builder.target_platform == 'windows':

View File

@ -23,6 +23,7 @@
#include <assert.h>
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "sc.h"
@ -55,6 +56,10 @@
}
#endif /* PAWNC_DLL */
#if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__
#include <sys/types.h>
#include <sys/stat.h>
#endif
/* pc_printf()
* Called for general purpose "console" output. This function prints general
@ -119,6 +124,14 @@ static char *prefix[3]={ "error", "fatal error", "warning" };
return 0;
}
typedef struct src_file_s {
FILE *fp; // Set if writing.
char *buffer; // IO buffer.
char *pos; // IO position.
char *end; // End of buffer.
size_t maxlength; // Maximum length of the writable buffer.
} src_file_t;
/* pc_opensrc()
* Opens a source file (or include file) for reading. The "file" does not have
* to be a physical file, one might compile from memory.
@ -133,7 +146,46 @@ static char *prefix[3]={ "error", "fatal error", "warning" };
*/
void *pc_opensrc(char *filename)
{
return fopen(filename,"rt");
FILE *fp = NULL;
long length;
src_file_t *src = NULL;
#if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__ || defined DARWIN
struct stat fileInfo;
if (stat(filename, &fileInfo) != 0) {
return NULL;
}
if (S_ISDIR(fileInfo.st_mode)) {
return NULL;
}
#endif
if ((fp = fopen(filename, "rb")) == NULL)
return NULL;
if (fseek(fp, 0, SEEK_END) == -1)
goto err;
if ((length = ftell(fp)) == -1)
goto err;
if (fseek(fp, 0, SEEK_SET) == -1)
goto err;
if ((src = (src_file_t *)calloc(1, sizeof(src_file_t))) == NULL)
goto err;
if ((src->buffer = (char *)calloc(length, sizeof(char))) == NULL)
goto err;
if (fread(src->buffer, length, 1, fp) != 1)
goto err;
src->pos = src->buffer;
src->end = src->buffer + length;
fclose(fp);
return src;
err:
pc_closesrc(src);
fclose(fp);
return NULL;
}
/* pc_createsrc()
@ -150,7 +202,23 @@ void *pc_opensrc(char *filename)
*/
void *pc_createsrc(char *filename)
{
return fopen(filename,"wt");
src_file_t *src = (src_file_t *)calloc(1, sizeof(src_file_t));
if (!src)
return NULL;
if ((src->fp = fopen(filename, "wt")) == NULL) {
pc_closesrc(src);
return NULL;
}
src->maxlength = 1024;
if ((src->buffer = (char *)calloc(1, src->maxlength)) == NULL) {
pc_closesrc(src);
return NULL;
}
src->pos = src->buffer;
src->end = src->buffer;
return src;
}
/* pc_closesrc()
@ -159,8 +227,15 @@ void *pc_createsrc(char *filename)
*/
void pc_closesrc(void *handle)
{
assert(handle!=NULL);
fclose((FILE*)handle);
src_file_t *src = (src_file_t *)handle;
if (!src)
return;
if (src->fp) {
fwrite(src->buffer, src->pos - src->buffer, 1, src->fp);
fclose(src->fp);
}
free(src->buffer);
free(src);
}
/* pc_resetsrc()
@ -169,8 +244,12 @@ void pc_closesrc(void *handle)
*/
void pc_resetsrc(void *handle,void *position)
{
assert(handle!=NULL);
fsetpos((FILE*)handle,(fpos_t *)position);
src_file_t *src = (src_file_t *)handle;
ptrdiff_t pos = (ptrdiff_t)position;
assert(!src->fp);
assert(pos >= 0 && src->buffer + pos <= src->end);
src->pos = src->buffer + pos;
}
/* pc_readsrc()
@ -179,7 +258,35 @@ void pc_resetsrc(void *handle,void *position)
*/
char *pc_readsrc(void *handle,unsigned char *target,int maxchars)
{
return fgets((char*)target,maxchars,(FILE*)handle);
src_file_t *src = (src_file_t *)handle;
char *outptr = (char *)target;
char *outend = outptr + maxchars;
assert(!src->fp);
if (src->pos == src->end)
return NULL;
while (outptr < outend && src->pos < src->end) {
char c = *src->pos++;
*outptr++ = c;
if (c == '\n')
break;
if (c == '\r') {
// Handle CRLF.
if (src->pos < src->end && *src->pos == '\n') {
src->pos++;
if (outptr < outend)
*outptr++ = '\n';
}
break;
}
}
// Caller passes in a buffer of size >= maxchars+1.
*outptr = '\0';
return (char *)target;
}
/* pc_writesrc()
@ -188,20 +295,51 @@ char *pc_readsrc(void *handle,unsigned char *target,int maxchars)
*/
int pc_writesrc(void *handle,unsigned char *source)
{
return fputs((char*)source,(FILE*)handle) >= 0;
char *str = (char *)source;
size_t len = strlen(str);
src_file_t *src = (src_file_t *)handle;
assert(src->fp && src->maxlength);
if (src->pos + len > src->end) {
char *newbuf;
size_t newmax = src->maxlength;
size_t newlen = (src->pos - src->buffer) + len;
while (newmax < newlen) {
// Grow by 1.5X
newmax += newmax + newmax / 2;
if (newmax < src->maxlength)
abort();
}
newbuf = (char *)realloc(src->buffer, newmax);
if (!newbuf)
abort();
src->pos = newbuf + (src->pos - src->buffer);
src->end = newbuf + newmax;
src->buffer = newbuf;
src->maxlength = newmax;
}
strcpy(src->pos, str);
src->pos += len;
return 0;
}
void *pc_getpossrc(void *handle)
{
static fpos_t lastpos; /* may need to have a LIFO stack of such positions */
src_file_t *src = (src_file_t *)handle;
fgetpos((FILE*)handle,&lastpos);
return &lastpos;
assert(!src->fp);
return (void *)(ptrdiff_t)(src->pos - src->buffer);
}
int pc_eofsrc(void *handle)
{
return feof((FILE*)handle);
src_file_t *src = (src_file_t *)handle;
assert(!src->fp);
return src->pos == src->end;
}
/* should return a pointer, which is used as a "magic cookie" to all I/O

View File

@ -51,7 +51,7 @@
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBPC300_EXPORTS;PAWNC_DLL;PAWN_CELL_SIZE=32;NO_MAIN;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBPC300_EXPORTS;PAWNC_DLL;PAWN_CELL_SIZE=32;NO_MAIN;_CRT_SECURE_NO_DEPRECATE;HAVE_STDINT_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeader>
@ -71,7 +71,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBPC300_EXPORTS;PAWNC_DLL;PAWN_CELL_SIZE=32;NO_MAIN;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBPC300_EXPORTS;PAWNC_DLL;PAWN_CELL_SIZE=32;NO_MAIN;_CRT_SECURE_NO_DEPRECATE;HAVE_STDINT_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>StackFrameRuntimeCheck</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
@ -105,11 +105,13 @@
<ClCompile Include="scmemfil.c" />
<ClCompile Include="scstate.c" />
<ClCompile Include="scvars.c" />
<ClCompile Include="sp_symhash.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="amx.h" />
<ClInclude Include="memfile.h" />
<ClInclude Include="sc.h" />
<ClInclude Include="sp_symhash.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="libpawnc.rc" />

View File

@ -60,6 +60,9 @@
<ClCompile Include="scvars.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="sp_symhash.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="amx.h">
@ -71,6 +74,9 @@
<ClInclude Include="sc.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="sp_symhash.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="libpawnc.rc">

View File

@ -55,7 +55,7 @@
#define sCHARBITS 8 /* size of a packed character */
#define sDIMEN_MAX 3 /* maximum number of array dimensions */
#define sLINEMAX 1023 /* input line length (in characters) */
#define sLINEMAX 4095 /* input line length (in characters) */
#define sCOMP_STACK 32 /* maximum nesting of #if .. #endif sections */
#define sDEF_LITMAX 500 /* initial size of the literal pool, in "cells" */
#define sDEF_AMXSTACK 4096 /* default stack size for AMX files */
@ -128,6 +128,7 @@ typedef struct s_symbol {
char vclass; /* sLOCAL if "addr" refers to a local symbol */
char ident; /* see below for possible values */
char usage; /* see below for possible values */
char flags; /* see below for possible values */
int compound; /* compound level (braces nesting level) */
int tag; /* tagname id */
int fieldtag; /* enumeration fields, where a size is attached to the field */
@ -147,6 +148,7 @@ typedef struct s_symbol {
} dim; /* for 'dimension', both functions and arrays */
constvalue *states; /* list of state function addresses */
int fnumber; /* static global variables: file number in which the declaration is visible */
int lnumber; /* line number (in the current source file) for the declaration */
struct s_symbol **refer; /* referrer list, functions that "use" this symbol */
int numrefers; /* number of entries in the referrer list */
char *documentation; /* optional documentation string */
@ -221,6 +223,8 @@ typedef struct s_symbol {
*/
#define uRETNONE 0x10
#define flgDEPRECATED 0x01 /* symbol is deprecated (avoid use) */
#define uTAGOF 0x40 /* set in the "hasdefault" field of the arginfo struct */
#define uSIZEOF 0x80 /* set in the "hasdefault" field of the arginfo struct */
@ -270,6 +274,8 @@ typedef struct s_stringpair {
char *first;
char *second;
int matchlength;
char flags;
char *documentation;
} stringpair;
/* macros for code generation */
@ -365,6 +371,7 @@ typedef struct s_stringpair {
#define tLABEL 331
#define tSTRING 332
#define tEXPR 333 /* for assigment to "lastst" only */
#define tEMPTYBLOCK 334 /* empty blocks for AM bug 4825 */
/* (reversed) evaluation of staging buffer */
#define sSTARTREORDER 0x01
@ -400,6 +407,8 @@ typedef struct s_stringpair {
#define sFORCESET 1 /* force error flag on */
#define sEXPRMARK 2 /* mark start of expression */
#define sEXPRRELEASE 3 /* mark end of expression */
#define sSETLINE 4 /* set line number for the error */
#define sSETFILE 5 /* set file number for the error */
typedef enum s_regid {
sPRI, /* indicates the primary register */
@ -508,6 +517,7 @@ SC_FUNC void delete_consttable(constvalue *table);
SC_FUNC symbol *add_constant(char *name,cell val,int vclass,int tag);
SC_FUNC void exporttag(int tag);
SC_FUNC void sc_attachdocumentation(symbol *sym);
SC_FUNC int get_actual_compound(symbol *sym);
/* function prototypes in SC2.C */
#define PUSHSTK_P(v) { stkitem s_; s_.pv=(v); pushstk(s_); }
@ -535,7 +545,6 @@ SC_FUNC void delete_symbol(symbol *root,symbol *sym);
SC_FUNC void delete_symbols(symbol *root,int level,int del_labels,int delete_functions);
SC_FUNC int refer_symbol(symbol *entry,symbol *bywhom);
SC_FUNC void markusage(symbol *sym,int usage);
SC_FUNC uint32_t namehash(const char *name);
SC_FUNC symbol *findglb(const char *name);
SC_FUNC symbol *findloc(const char *name);
SC_FUNC symbol *findconst(const char *name);
@ -641,7 +650,7 @@ SC_FUNC void outval(cell val,int newline);
/* function prototypes in SC5.C */
SC_FUNC int error(int number,...) INVISIBLE;
SC_FUNC void errorset(int code);
SC_FUNC void errorset(int code, int line);
/* function prototypes in SC6.C */
SC_FUNC int assemble(FILE *fout,FILE *fin);
@ -674,6 +683,9 @@ SC_FUNC void delete_substtable(void);
SC_FUNC stringlist *insert_sourcefile(char *string);
SC_FUNC char *get_sourcefile(int index);
SC_FUNC void delete_sourcefiletable(void);
SC_FUNC stringlist *insert_inputfile(char *string);
SC_FUNC char *get_inputfile(int index);
SC_FUNC void delete_inputfiletable(void);
SC_FUNC stringlist *insert_docstring(char *string);
SC_FUNC char *get_docstring(int index);
SC_FUNC void delete_docstring(int index);
@ -728,6 +740,8 @@ SC_FUNC void state_conflict(symbol *root);
/* external variables (defined in scvars.c) */
#if !defined SC_SKIP_VDECL
typedef struct HashTable HashTable;
SC_VDECL struct HashTable *sp_Globals;
SC_VDECL symbol loctab; /* local symbol table */
SC_VDECL symbol glbtab; /* global symbol table */
SC_VDECL cell *litq; /* the literal queue */
@ -770,8 +784,8 @@ SC_VDECL cell sc_stksize; /* stack size */
SC_VDECL cell sc_amxlimit; /* abstract machine size limit */
SC_VDECL int freading; /* is there an input file ready for reading? */
SC_VDECL int fline; /* the line number in the current file */
SC_VDECL short fnumber; /* number of files in the file table (debugging) */
SC_VDECL short fcurrent; /* current file being processed (debugging) */
SC_VDECL short fnumber; /* number of files in the input file table */
SC_VDECL short fcurrent; /* current file being processed */
SC_VDECL short sc_intest; /* true if inside a test */
SC_VDECL int sideeffect; /* true if an expression causes a side-effect */
SC_VDECL int stmtindent; /* current indent of the statement */
@ -783,6 +797,7 @@ SC_VDECL int sc_rationaltag; /* tag for rational numbers */
SC_VDECL int rational_digits; /* number of fractional digits */
SC_VDECL int sc_allowproccall;/* allow/detect tagnames in lex() */
SC_VDECL short sc_is_utf8; /* is this source file in UTF-8 encoding */
SC_VDECL char *pc_deprecate; /* if non-NULL, mark next declaration as deprecated */
SC_VDECL constvalue sc_automaton_tab; /* automaton table */
SC_VDECL constvalue sc_state_tab; /* state table */

View File

@ -32,6 +32,7 @@
#if defined __WIN32__ || defined _WIN32 || defined __MSDOS__
#include <conio.h>
#include <io.h>
#define snprintf _snprintf
#endif
#if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__
@ -64,8 +65,10 @@
#include <time.h>
#include "sc.h"
#include "sp_symhash.h"
#define VERSION_STR "3.0.3367-amxx"
#define VERSION_INT 0x300
#define VERSION_INT 0x30A
int pc_anytag;
@ -102,7 +105,7 @@ static void doarg(char *name,int ident,int offset,int tags[],int numtags,
int fpublic,int fconst,arginfo *arg);
static void make_report(symbol *root,FILE *log,char *sourcefile);
static void reduce_referrers(symbol *root);
static long max_stacksize(symbol *root);
static long max_stacksize(symbol *root, int *recursion);
static int testsymbols(symbol *root,int level,int testlabs,int testconst);
static void destructsymbols(symbol *root,int level);
static constvalue *find_constval_byval(constvalue *table,cell val);
@ -113,7 +116,7 @@ static int doexpr(int comma,int chkeffect,int allowarray,int mark_endexpr,
static void doassert(void);
static void doexit(void);
static void test(int label,int parens,int invert);
static void doif(void);
static int doif(void);
static void dowhile(void);
static void dodo(void);
static void dofor(void);
@ -130,6 +133,7 @@ static void addwhile(int *ptr);
static void delwhile(void);
static int *readwhile(void);
static void inst_datetime_defines(void);
static void inst_binary_name(char *binfname);
static int lastst = 0; /* last executed statement type */
static int nestlevel = 0; /* number of active (open) compound statements */
@ -404,6 +408,38 @@ void inst_datetime_defines()
insert_subst("__TIME__", ltime, 8);
}
static void inst_binary_name(char *binfname)
{
size_t i, len;
char *binptr;
char newpath[512], newname[512];
binptr = NULL;
len = strlen(binfname);
for (i = len - 1; i < len; i--)
{
if (binfname[i] == '/'
#if defined WIN32 || defined _WIN32
|| binfname[i] == '\\'
#endif
)
{
binptr = &binfname[i + 1];
break;
}
}
if (binptr == NULL)
{
binptr = binfname;
}
snprintf(newpath, sizeof(newpath), "\"%s\"", binfname);
snprintf(newname, sizeof(newname), "\"%s\"", binptr);
insert_subst("__BINARY_PATH__", newpath, 15);
insert_subst("__BINARY_NAME__", newname, 15);
}
/* "main" of the compiler
*/
@ -427,8 +463,8 @@ int pc_compile(int argc, char *argv[])
/* set global variables to their initial value */
binf=NULL;
initglobals();
errorset(sRESET);
errorset(sEXPRRELEASE);
errorset(sRESET,0);
errorset(sEXPRRELEASE,0);
lexinit();
/* make sure that we clean up on a fatal error; do this before the first
@ -436,6 +472,10 @@ int pc_compile(int argc, char *argv[])
if ((jmpcode=setjmp(errbuf))!=0)
goto cleanup;
sp_Globals = NewHashTable();
if (!sp_Globals)
error(123);
/* allocate memory for fixed tables */
inpfname=(char*)malloc(_MAX_PATH);
if (inpfname==NULL)
@ -474,7 +514,7 @@ int pc_compile(int argc, char *argv[])
if (get_sourcefile(1)!=NULL) {
/* there are at least two or more source files */
char *tname,*sname;
FILE *ftmp,*fsrc;
void *ftmp,*fsrc;
int fidx;
#if defined __WIN32__ || defined _WIN32
tname=_tempnam(NULL,"pawn");
@ -490,10 +530,10 @@ int pc_compile(int argc, char *argv[])
close(mkstemp(buffer));
tname=buffer;
#endif
ftmp=(FILE*)pc_createsrc(tname);
ftmp=(void*)pc_createsrc(tname);
for (fidx=0; (sname=get_sourcefile(fidx))!=NULL; fidx++) {
unsigned char tstring[128];
fsrc=(FILE*)pc_opensrc(sname);
fsrc=(void*)pc_opensrc(sname);
if (fsrc==NULL)
error(100,sname);
pc_writesrc(ftmp,(unsigned char*)"#file ");
@ -511,7 +551,7 @@ int pc_compile(int argc, char *argv[])
} else {
strcpy(inpfname,get_sourcefile(0));
} /* if */
inpf_org=(FILE*)pc_opensrc(inpfname);
inpf_org=(void*)pc_opensrc(inpfname);
if (inpf_org==NULL)
error(100,inpfname);
freading=TRUE;
@ -556,13 +596,14 @@ int pc_compile(int argc, char *argv[])
#if !defined NO_DEFINE
delete_substtable();
inst_datetime_defines();
inst_binary_name(binfname);
#endif
resetglobals();
sc_ctrlchar=sc_ctrlchar_org;
sc_packstr=lcl_packstr;
sc_needsemicolon=lcl_needsemicolon;
sc_tabsize=lcl_tabsize;
errorset(sRESET);
errorset(sRESET,0);
/* reset the source file */
inpf=inpf_org;
freading=TRUE;
@ -620,13 +661,14 @@ int pc_compile(int argc, char *argv[])
#if !defined NO_DEFINE
delete_substtable();
inst_datetime_defines();
inst_binary_name(binfname);
#endif
resetglobals();
sc_ctrlchar=sc_ctrlchar_org;
sc_packstr=lcl_packstr;
sc_needsemicolon=lcl_needsemicolon;
sc_tabsize=lcl_tabsize;
errorset(sRESET);
errorset(sRESET,0);
/* reset the source file */
inpf=inpf_org;
freading=TRUE;
@ -635,7 +677,8 @@ int pc_compile(int argc, char *argv[])
lexinit(); /* clear internal flags of lex() */
sc_status=statWRITE; /* allow to write --this variable was reset by resetglobals() */
writeleader(&glbtab);
insert_dbgfile(inpfname);
insert_dbgfile(inpfname); /* attach to debug information */
insert_inputfile(inpfname); /* save for the error system */
if (strlen(incfname)>0) {
if (strcmp(incfname,sDEF_PREFIX)==0)
plungefile(incfname,FALSE,TRUE); /* parse "default.inc" (again) */
@ -675,7 +718,8 @@ cleanup:
#if !defined SC_LIGHT
if (errnum==0 && strlen(errfname)==0) {
long stacksize=max_stacksize(&glbtab);
int recursion;
long stacksize=max_stacksize(&glbtab,&recursion);
int flag_exceed=0;
if (sc_amxlimit > 0 && (long)(hdrsize+code_idx+glb_declared*sizeof(cell)+sc_stksize*sizeof(cell)) >= sc_amxlimit)
flag_exceed=1;
@ -708,6 +752,7 @@ cleanup:
delete_symbols(&loctab,0,TRUE,TRUE); /* delete local variables if not yet
* done (i.e. on a fatal error) */
delete_symbols(&glbtab,0,TRUE,TRUE);
DestroyHashTable(sp_Globals);
delete_consttable(&tagname_tab);
delete_consttable(&libname_tab);
delete_consttable(&sc_automaton_tab);
@ -716,6 +761,7 @@ cleanup:
delete_aliastable();
delete_pathtable();
delete_sourcefiletable();
delete_inputfiletable();
delete_dbgstringtable();
#if !defined NO_DEFINE
delete_substtable();
@ -754,7 +800,7 @@ cleanup:
#endif
int pc_addconstant(char *name,cell value,int tag)
{
errorset(sFORCESET); /* make sure error engine is silenced */
errorset(sFORCESET,0); /* make sure error engine is silenced */
sc_status=statIDLE;
add_constant(name,value,sGLOBAL,tag);
return 1;
@ -828,6 +874,7 @@ static void resetglobals(void)
pc_addlibtable=TRUE; /* by default, add a "library table" to the output file */
sc_alignnext=FALSE;
pc_docexpr=FALSE;
pc_deprecate = FALSE;
}
static void initglobals(void)
@ -1071,7 +1118,11 @@ static void parseoptions(int argc,char **argv,char *oname,char *ename,char *pnam
skipinput=atoi(option_value(ptr));
break;
case 't':
sc_tabsize=atoi(option_value(ptr));
i=atoi(option_value(ptr));
if (i>0)
sc_tabsize=i;
else
about();
break;
case 'v':
verbosity= isdigit(*option_value(ptr)) ? atoi(option_value(ptr)) : 2;
@ -1408,6 +1459,7 @@ static void setconstants(void)
add_constant("ucharmax",(1 << (sizeof(cell)-1)*8)-1,sGLOBAL,0);
add_constant("__Pawn",VERSION_INT,sGLOBAL,0);
add_constant("__LINE__", 0, sGLOBAL, 0);
pc_anytag=pc_addtag("any");
@ -2206,6 +2258,24 @@ static void initials(int ident,int tag,cell *size,int dim[],int numdim,
err++;
} /* if */
} /* for */
if (numdim>1 && dim[numdim-1]==0 && !errorfound && err==0) {
/* also look whether, by any chance, all "counted" final dimensions are
* the same value; if so, we can store this
*/
constvalue *ld=lastdim.next;
int d,match;
for (d=0; d<dim[numdim-2]; d++) {
assert(ld!=NULL);
assert(strtol(ld->name,NULL,16)==d);
if (d==0)
match=ld->value;
else if (match!=ld->value)
break;
ld=ld->next;
} /* for */
if (d==dim[numdim-2])
dim[numdim-1]=match;
} /* if */
/* after all arrays have been initalized, we know the (major) dimensions
* of the array and we can properly adjust the indirection vectors
*/
@ -2733,14 +2803,26 @@ SC_FUNC symbol *fetchfunc(char *name,int tag)
sym=addsym(name,code_idx,iFUNCTN,sGLOBAL,tag,0);
assert(sym!=NULL); /* fatal error 103 must be given on error */
/* assume no arguments */
sym->dim.arglist=(arginfo*)malloc(1*sizeof(arginfo));
sym->dim.arglist[0].ident=0;
sym->dim.arglist=(arginfo*)calloc(1, sizeof(arginfo));
/* set library ID to NULL (only for native functions) */
sym->x.lib=NULL;
/* set the required stack size to zero (only for non-native functions) */
sym->x.stacksize=1; /* 1 for PROC opcode */
} /* if */
if (pc_deprecate!=NULL) {
assert(sym!=NULL);
sym->flags |= flgDEPRECATED;
if (sc_status==statWRITE) {
if (sym->documentation!=NULL) {
free(sym->documentation);
sym->documentation=NULL;
} /* if */
sym->documentation=pc_deprecate;
} else {
free(pc_deprecate);
} /* if */
pc_deprecate=NULL;
}/* if */
return sym;
}
@ -2886,8 +2968,10 @@ static int operatoradjust(int opertok,symbol *sym,char *opername,int resulttag)
refer_symbol(sym,oldsym->refer[i]);
delete_symbol(&glbtab,oldsym);
} /* if */
RemoveFromHashTable(sp_Globals, sym);
strcpy(sym->name,tmpname);
sym->hash=namehash(sym->name);/* calculate new hash */
sym->hash=NameHash(sym->name);/* calculate new hash */
AddToHashTable(sp_Globals, sym);
/* operators should return a value, except the '~' operator */
if (opertok!='~')
@ -3244,6 +3328,10 @@ static int newfunc(char *firstname,int firsttag,int fpublic,int fstatic,int stoc
cidx=code_idx;
glbdecl=glb_declared;
} /* if */
if ((sym->flags & flgDEPRECATED) != 0 && (sym->usage & uSTOCK) == 0) {
char *ptr = (sym->documentation != NULL) ? sym->documentation : "";
error(233, symbolname, ptr); /* deprecated (probably a public function) */
} /* if */
begcseg();
sym->usage|=uDEFINE; /* set the definition flag */
if (fpublic)
@ -3559,7 +3647,7 @@ static int declargs(symbol *sym)
} /* for */
sym->usage|=uPROTOTYPED;
errorset(sRESET); /* reset error flag (clear the "panic mode")*/
errorset(sRESET,0); /* reset error flag (clear the "panic mode")*/
return argcnt;
}
@ -4160,31 +4248,47 @@ static void reduce_referrers(symbol *root)
}
#if !defined SC_LIGHT
static long max_stacksize_recurse(symbol *sym,long basesize,int *pubfuncparams)
static long max_stacksize_recurse(symbol **sourcesym,symbol *sym,long basesize,int *pubfuncparams,int *recursion)
{
long size,maxsize;
int i;
int i,stkpos;
assert(sourcesym!=NULL);
assert(sym!=NULL);
assert(sym->ident==iFUNCTN);
assert((sym->usage & uNATIVE)==0);
/* recursion detection */
if (sym->compound==0)
return -1; /* this function was processed already -> recursion */
sym->compound=0;
assert(recursion!=NULL);
maxsize=sym->x.stacksize;
for (i=0; i<sym->numrefers; i++) {
if (sym->refer[i]!=NULL) {
assert(sym->refer[i]->ident==iFUNCTN);
assert((sym->refer[i]->usage & uNATIVE)==0); /* a native function cannot refer to a user-function */
size=max_stacksize_recurse(sym->refer[i],sym->x.stacksize,pubfuncparams);
if (size<0)
return size; /* recursion was detected, quit */
if (maxsize<size)
maxsize=size;
for (stkpos=0; sourcesym[stkpos]!=NULL; stkpos++) {
if (sym->refer[i]==sourcesym[stkpos]) { /* recursion detection */
if ((sc_debug & sSYMBOLIC)!=0 || verbosity>=2) {
char symname[2*sNAMEMAX+16];/* allow space for user defined operators */
funcdisplayname(symname,sym->name);
errorset(sSETFILE,sym->fnumber);
errorset(sSETLINE,sym->lnumber);
error(237,symname); /* recursive function */
} /* if */
*recursion=1;
goto break_recursion; /* recursion was detected, quit loop */
} /* if */
} /* for */
/* add this symbol to the stack */
sourcesym[stkpos]=sym;
sourcesym[stkpos+1]=NULL;
/* check size of callee */
size=max_stacksize_recurse(sourcesym,sym->refer[i],sym->x.stacksize,pubfuncparams,recursion);
if (maxsize<size)
maxsize=size;
/* remove this symbol from the stack */
sourcesym[stkpos]=NULL;
} /* if */
} /* for */
break_recursion:
if ((sym->usage & uPUBLIC)!=0) {
/* Find out how many parameters a public function has, then see if this
@ -4202,10 +4306,13 @@ static long max_stacksize_recurse(symbol *sym,long basesize,int *pubfuncparams)
*pubfuncparams=count;
} /* if */
errorset(sEXPRRELEASE,0); /* clear error data */
errorset(sRESET,0);
return maxsize+basesize;
}
static long max_stacksize(symbol *root)
static long max_stacksize(symbol *root,int *recursion)
{
/* Loop over all non-native functions. For each function, loop
* over all of its referrers, accumulating the stack requirements.
@ -4218,39 +4325,44 @@ static long max_stacksize(symbol *root)
* stack requirements are thus only an estimate.
*/
long size,maxsize;
int maxparams;
int maxparams,numfunctions;
symbol *sym;
symbol **symstack;
#if !defined NDEBUG
for (sym=root->next; sym!=NULL; sym=sym->next)
if (sym->ident==iFUNCTN)
assert(root!=NULL);
assert(recursion!=NULL);
/* count number of functions (for allocating the stack for recursion detection) */
numfunctions=0;
for (sym=root->next; sym!=NULL; sym=sym->next) {
if (sym->ident==iFUNCTN) {
assert(sym->compound==0);
#endif
if ((sym->usage & uNATIVE)==0)
numfunctions++;
} /* if */
} /* if */
/* allocate function symbol stack */
symstack=(symbol **)malloc((numfunctions+1)*sizeof(symbol*));
if (symstack==NULL)
error(103); /* insufficient memory (fatal error) */
memset(symstack,0,(numfunctions+1)*sizeof(symbol*));
maxsize=0;
maxparams=0;
*recursion=0; /* assume no recursion */
for (sym=root->next; sym!=NULL; sym=sym->next) {
symbol *tmpsym;
/* drop out if this is not a user-implemented function */
if (sym->ident!=iFUNCTN || (sym->usage & uNATIVE)!=0)
continue;
/* set a "mark" on all functions */
for (tmpsym=root->next; tmpsym!=NULL; tmpsym=tmpsym->next)
if (tmpsym->ident==iFUNCTN)
tmpsym->compound=1;
/* accumulate stack size for this symbol */
size=max_stacksize_recurse(sym,0L,&maxparams);
if (size<0)
return size; /* recursion was detected */
symstack[0]=sym;
assert(symstack[1]==NULL);
size=max_stacksize_recurse(symstack,sym,0L,&maxparams,recursion);
assert(size>=0);
if (maxsize<size)
maxsize=size;
} /* for */
/* clear all marks */
for (sym=root->next; sym!=NULL; sym=sym->next)
if (sym->ident==iFUNCTN)
sym->compound=0;
free((void*)symstack);
maxsize++; /* +1 because a zero cell is always pushed on top
* of the stack to catch stack overwrites */
return maxsize+(maxparams+1);/* +1 because # of parameters is always pushed on entry */
@ -4276,22 +4388,28 @@ static int testsymbols(symbol *root,int level,int testlabs,int testconst)
int entry=FALSE;
symbol *sym=root->next;
while (sym!=NULL && sym->compound>=level) {
while (sym != NULL && get_actual_compound(sym) >= level) {
switch (sym->ident) {
case iLABEL:
if (testlabs) {
if ((sym->usage & uDEFINE)==0)
if ((sym->usage & uDEFINE)==0) {
error(19,sym->name); /* not a label: ... */
else if ((sym->usage & uREAD)==0)
} else if ((sym->usage & uREAD)==0) {
errorset(sSETFILE,sym->fnumber);
errorset(sSETLINE,sym->lnumber);
error(203,sym->name); /* symbol isn't used: ... */
} /* if */
} /* if */
break;
case iFUNCTN:
if ((sym->usage & (uDEFINE | uREAD | uNATIVE | uSTOCK))==uDEFINE) {
funcdisplayname(symname,sym->name);
if (strlen(symname)>0)
if (strlen(symname)>0) {
errorset(sSETFILE,sym->fnumber);
errorset(sSETLINE,sym->lnumber);
error(203,symname); /* symbol isn't used ... (and not native/stock) */
} /* if */
} /* if */
if ((sym->usage & uPUBLIC)!=0 || strcmp(sym->name,uMAINFUNC)==0)
entry=TRUE; /* there is an entry point */
/* also mark the function to the debug information */
@ -4299,21 +4417,31 @@ static int testsymbols(symbol *root,int level,int testlabs,int testconst)
insert_dbgsymbol(sym);
break;
case iCONSTEXPR:
if (testconst && (sym->usage & uREAD)==0)
if (testconst && (sym->usage & uREAD)==0) {
errorset(sSETFILE,sym->fnumber);
errorset(sSETLINE,sym->lnumber);
error(203,sym->name); /* symbol isn't used: ... */
} /* if */
break;
default:
/* a variable */
if (sym->parent!=NULL)
break; /* hierarchical data type */
if ((sym->usage & (uWRITTEN | uREAD | uSTOCK))==0)
error(203,sym->name); /* symbol isn't used (and not stock) */
else if ((sym->usage & (uREAD | uSTOCK | uPUBLIC))==0)
if ((sym->usage & (uWRITTEN | uREAD | uSTOCK))==0) {
errorset(sSETFILE,sym->fnumber);
errorset(sSETLINE,sym->lnumber);
error(203,sym->name,sym->lnumber); /* symbol isn't used (and not stock) */
} else if ((sym->usage & (uREAD | uSTOCK | uPUBLIC))==0) {
errorset(sSETFILE,sym->fnumber);
errorset(sSETLINE,sym->lnumber);
error(204,sym->name); /* value assigned to symbol is never used */
#if 0 // ??? not sure whether it is a good idea to force people use "const"
else if ((sym->usage & (uWRITTEN | uPUBLIC | uCONST))==0 && sym->ident==iREFARRAY)
} else if ((sym->usage & (uWRITTEN | uPUBLIC | uCONST))==0 && sym->ident==iREFARRAY) {
errorset(sSETFILE,sym->fnumber);
errorset(sSETLINE,sym->lnumber);
error(214,sym->name); /* make array argument "const" */
#endif
} /* if */
/* also mark the variable (local or global) to the debug information */
if ((sym->usage & (uWRITTEN | uREAD))!=0 && (sym->usage & uNATIVE)==0)
insert_dbgsymbol(sym);
@ -4321,6 +4449,8 @@ static int testsymbols(symbol *root,int level,int testlabs,int testconst)
sym=sym->next;
} /* while */
errorset(sEXPRRELEASE, 0); /* clear error data */
errorset(sRESET, 0);
return entry;
}
@ -4407,7 +4537,7 @@ static constvalue *insert_constval(constvalue *prev,constvalue *next,const char
error(103); /* insufficient memory (fatal error) */
memset(cur,0,sizeof(constvalue));
if (name!=NULL) {
assert(strlen(name)<sNAMEMAX);
assert(strlen(name)<=sNAMEMAX);
strcpy(cur->name,name);
} /* if */
cur->value=val;
@ -4531,7 +4661,7 @@ static void statement(int *lastindent,int allow_decl)
error(36); /* empty statement */
return;
} /* if */
errorset(sRESET);
errorset(sRESET,0);
tok=lex(&val,&st);
if (tok!='{') {
@ -4567,16 +4697,19 @@ static void statement(int *lastindent,int allow_decl)
break;
case '{':
tok=fline;
if (!matchtoken('}')) /* {} is the empty statement */
if (!matchtoken('}')) { /* {} is the empty statement */
compound(tok==fline);
/* lastst (for "last statement") does not change */
} else {
lastst = tEMPTYBLOCK;
}
/* lastst (for "last statement") does not change
you're not my father, don't tell me what to do */
break;
case ';':
error(36); /* empty statement */
break;
case tIF:
doif();
lastst=tIF;
lastst=doif();
break;
case tWHILE:
dowhile();
@ -4655,6 +4788,7 @@ static void compound(int stmt_sameline)
int indent=-1;
cell save_decl=declared;
int count_stmt=0;
int block_start=fline; /* save line where the compound block started */
/* if there is more text on this line, we should adjust the statement indent */
if (stmt_sameline) {
@ -4682,7 +4816,7 @@ static void compound(int stmt_sameline)
nestlevel+=1; /* increase compound statement level */
while (matchtoken('}')==0){ /* repeat until compound statement is closed */
if (!freading){
needtoken('}'); /* gives error: "expected token }" */
error(30,block_start); /* compound block not closed at end of file */
break;
} else {
if (count_stmt>0 && (lastst==tRETURN || lastst==tBREAK || lastst==tCONTINUE))
@ -4720,7 +4854,7 @@ static int doexpr(int comma,int chkeffect,int allowarray,int mark_endexpr,
assert(stgidx==0);
} /* if */
index=stgidx;
errorset(sEXPRMARK);
errorset(sEXPRMARK,0);
do {
/* on second round through, mark the end of the previous expression */
if (index!=stgidx)
@ -4735,7 +4869,7 @@ static int doexpr(int comma,int chkeffect,int allowarray,int mark_endexpr,
} while (comma && matchtoken(',')); /* more? */
if (mark_endexpr)
markexpr(sEXPR,NULL,0); /* optionally, mark the end of the expression */
errorset(sEXPRRELEASE);
errorset(sEXPRRELEASE,0);
if (localstaging) {
stgout(index);
stgset(FALSE); /* stop staging */
@ -4752,7 +4886,7 @@ SC_FUNC int constexpr(cell *val,int *tag,symbol **symptr)
stgset(TRUE); /* start stage-buffering */
stgget(&index,&cidx); /* mark position in code generator */
errorset(sEXPRMARK);
errorset(sEXPRMARK,0);
ident=expression(val,tag,symptr,FALSE);
stgdel(index,cidx); /* scratch generated code */
stgset(FALSE); /* stop stage-buffering */
@ -4765,7 +4899,7 @@ SC_FUNC int constexpr(cell *val,int *tag,symbol **symptr)
if (symptr!=NULL)
*symptr=NULL;
} /* if */
errorset(sEXPRRELEASE);
errorset(sEXPRRELEASE,0);
return (ident==iCONSTEXPR);
}
@ -4846,10 +4980,11 @@ static void test(int label,int parens,int invert)
} /* if */
}
static void doif(void)
static int doif(void)
{
int flab1,flab2;
int ifindent;
int lastst_true;
ifindent=stmtindent; /* save the indent of the "if" instruction */
flab1=getlabel(); /* get label number for false branch */
@ -4858,6 +4993,7 @@ static void doif(void)
if (matchtoken(tELSE)==0){ /* if...else ? */
setlabel(flab1); /* no, simple if..., print false label */
} else {
lastst_true=lastst;
/* to avoid the "dangling else" error, we want a warning if the "else"
* has a lower indent than the matching "if" */
if (stmtindent<ifindent && sc_tabsize>0)
@ -4868,7 +5004,14 @@ static void doif(void)
setlabel(flab1); /* print false label */
statement(NULL,FALSE); /* do "else" clause */
setlabel(flab2); /* print true label */
/* if both the "true" branch and the "false" branch ended with the same
* kind of statement, set the last statement id to that kind, rather than
* to the generic tIF; this allows for better "unreachable code" checking
*/
if (lastst == lastst_true)
return lastst;
} /* endif */
return tIF;
}
static void dowhile(void)
@ -5230,18 +5373,6 @@ static symbol *fetchlab(char *name)
return sym;
}
static int is_variadic(symbol *sym)
{
arginfo *arg;
assert(sym->ident==iFUNCTN);
for (arg = sym->dim.arglist; arg->ident; arg++) {
if (arg->ident == iVARARGS)
return TRUE;
}
return FALSE;
}
/* doreturn
*
* Global references: rettype (altered)
@ -5258,6 +5389,11 @@ static void doreturn(void)
error(78); /* mix "return;" and "return value;" */
ident=doexpr(TRUE,FALSE,TRUE,TRUE,&tag,&sym,TRUE);
needtoken(tTERM);
if (ident == iARRAY && sym == NULL) {
/* returning a literal string is not supported (it must be a variable) */
error(39);
ident = iCONSTEXPR; /* avoid handling an "array" case */
} /* if */
/* see if this function already has a sub type (an array attached) */
sub=finddepend(curfunc);
assert(sub==NULL || sub->ident==iREFARRAY);
@ -5341,11 +5477,7 @@ static void doreturn(void)
* it stays on the heap for the moment, and it is removed -usually- at
* the end of the expression/statement, see expression() in SC3.C)
*/
if (is_variadic(curfunc)) {
load_hidden_arg();
} else {
address(sub,sALT); /* ALT = destination */
}
arraysize=calc_arraysize(dim,numdim,0);
memcopy(arraysize*sizeof(cell)); /* source already in PRI */
/* moveto1(); is not necessary, callfunction() does a popreg() */
@ -5460,6 +5592,7 @@ static void dostate(void)
pc_docexpr=TRUE; /* attach expression as a documentation string */
test(flabel,FALSE,FALSE); /* get expression, branch to flabel if false */
pc_docexpr=FALSE;
pc_deprecate=NULL;
needtoken(')');
} else {
flabel=-1;
@ -5607,4 +5740,3 @@ static int *readwhile(void)
return (wqptr-wqSIZE);
} /* if */
}

View File

@ -29,6 +29,7 @@
#if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__
#include <sclinux.h>
#endif
#include "sp_symhash.h"
#if defined FORTIFY
#include "fortify.h"
@ -120,18 +121,18 @@ SC_FUNC void clearstk(void)
SC_FUNC int plungequalifiedfile(char *name)
{
static char *extensions[] = { ".inc", ".p", ".pawn" };
FILE *fp;
void *fp;
char *ext;
int ext_idx;
ext_idx=0;
do {
fp=(FILE*)pc_opensrc(name);
fp=(void*)pc_opensrc(name);
ext=strchr(name,'\0'); /* save position */
if (fp==NULL) {
/* try to append an extension */
strcpy(ext,extensions[ext_idx]);
fp=(FILE*)pc_opensrc(name);
fp=(void*)pc_opensrc(name);
if (fp==NULL)
*ext='\0'; /* on failure, restore filename */
} /* if */
@ -162,8 +163,10 @@ static char *extensions[] = { ".inc", ".p", ".pawn" };
fline=0; /* set current line number to 0 */
fcurrent=fnumber;
icomment=0; /* not in a comment */
insert_dbgfile(inpfname);
setfiledirect(inpfname);
insert_dbgfile(inpfname); /* attach to debug information */
insert_inputfile(inpfname); /* save for the error system */
assert(sc_status == statFIRST || strcmp(get_inputfile(fcurrent), inpfname) == 0);
setfiledirect(inpfname); /* (optionally) set in the list file */
listline=-1; /* force a #line directive when changing the file */
sc_is_utf8=(short)scan_utf8(inpf,name);
return TRUE;
@ -281,6 +284,7 @@ static void readline(unsigned char *line)
{
int i,num,cont;
unsigned char *ptr;
symbol *sym;
if (lptr==term_expr)
return;
@ -319,6 +323,7 @@ static void readline(unsigned char *line)
inpf=(FILE *)POPSTK_P();
insert_dbgfile(inpfname);
setfiledirect(inpfname);
assert(sc_status==statFIRST || strcmp(get_inputfile(fcurrent),inpfname)==0);
listline=-1; /* force a #line directive when changing the file */
} /* if */
@ -358,6 +363,9 @@ static void readline(unsigned char *line)
line+=strlen((char*)line);
} /* if */
fline+=1;
sym=findconst("__LINE__");
assert(sym!=NULL);
sym->addr=fline;
} while (num>=0 && cont);
}
@ -850,6 +858,7 @@ static int command(void)
char *str;
int index;
cell code_index;
size_t len;
while (*lptr<=' ' && *lptr!='\0')
lptr+=1;
@ -889,7 +898,7 @@ static int command(void)
assert(iflevel>=0);
if (iflevel==0) {
error(26); /* no matching #if */
errorset(sRESET);
errorset(sRESET,0);
} else {
/* check for earlier #else */
if ((ifstack[iflevel-1] & HANDLED_ELSE)==HANDLED_ELSE) {
@ -897,7 +906,7 @@ static int command(void)
error(61); /* #elseif directive may not follow an #else */
else
error(60); /* multiple #else directives between #if ... #endif */
errorset(sRESET);
errorset(sRESET,0);
} else {
assert(iflevel>0);
/* if there has been a "parse mode" on this level, set "skip mode",
@ -906,11 +915,27 @@ static int command(void)
if ((ifstack[iflevel-1] & PARSEMODE)==PARSEMODE) {
/* there has been a parse mode already on this level, so skip the rest */
ifstack[iflevel-1] |= (char)SKIPMODE;
/* if we were already skipping this section, allow expressions with
* undefined symbols; otherwise check the expression to catch errors
*/
if (tok==tpELSEIF) {
if (skiplevel==iflevel)
preproc_expr(&val,NULL); /* get, but ignore the expression */
else
lptr=(unsigned char*)strchr((char*)lptr,'\0');
} /* if */
} else {
/* previous conditions were all FALSE */
if (tok==tpELSEIF) {
/* get new expression */
/* if we were already skipping this section, allow expressions with
* undefined symbols; otherwise check the expression to catch errors
*/
if (skiplevel==iflevel) {
preproc_expr(&val,NULL); /* get value (or 0 on error) */
} else {
lptr=(unsigned char*)strchr((char*)lptr,'\0');
val=0;
} /* if */
ifstack[iflevel-1]=(char)(val ? PARSEMODE : SKIPMODE);
} else {
/* a simple #else, clear skip mode */
@ -925,7 +950,7 @@ static int command(void)
ret=CMD_IF;
if (iflevel==0){
error(26); /* no matching "#if" */
errorset(sRESET);
errorset(sRESET,0);
} else {
iflevel--;
if (iflevel<skiplevel)
@ -1003,6 +1028,19 @@ static int command(void)
error(27); /* invalid character constant */
sc_ctrlchar=(char)val;
} /* if */
}
else if (strcmp(str, "deprecated") == 0) {
while (*lptr <= ' ' && *lptr != '\0')
lptr++;
len = strlen((char*)lptr);
pc_deprecate = (char*)malloc(len + 1);
if (pc_deprecate != NULL)
{
strcpy(pc_deprecate, (char*)lptr);
if (pc_deprecate[len - 1] == '\n') /* remove extra \n as already appended in .scp file */
pc_deprecate[len-1] = '\0';
}
lptr = (unsigned char*)strchr((char*)lptr, '\0'); /* skip to end (ignore "extra characters on line") */
} else if (strcmp(str,"dynamic")==0) {
preproc_expr(&sc_stksize,NULL);
} else if ( !strcmp(str,"library") ||
@ -1117,6 +1155,7 @@ static int command(void)
} else if (strcmp(str,"tabsize")==0) {
cell val;
preproc_expr(&val,NULL);
if (val>0)
sc_tabsize=(int)val;
} else if (strcmp(str,"align")==0) {
sc_alignnext=TRUE;
@ -1251,7 +1290,7 @@ static int command(void)
} /* while */
end=lptr;
/* check pattern to match */
if (!isalpha(*start) && *start!='_') {
if (!alpha(*start)) {
error(74); /* pattern must start with an alphabetic character */
break;
} /* if */
@ -1302,7 +1341,7 @@ static int command(void)
} /* while */
substitution[count]='\0';
/* check whether the definition already exists */
for (prefixlen=0,start=(unsigned char*)pattern; isalpha(*start) || isdigit(*start) || *start=='_'; prefixlen++,start++)
for (prefixlen=0,start=(unsigned char*)pattern; alphanum(*start); prefixlen++,start++)
/* nothing */;
assert(prefixlen>0);
if ((def=find_subst(pattern,prefixlen))!=NULL) {
@ -1458,7 +1497,7 @@ static int substpattern(unsigned char *line,size_t buffersize,char *pattern,char
memset(args,0,sizeof args);
/* check the length of the prefix */
for (prefixlen=0,s=(unsigned char*)pattern; isalpha(*s) || isdigit(*s) || *s=='_'; prefixlen++,s++)
for (prefixlen=0,s=(unsigned char*)pattern; alphanum(*s); prefixlen++,s++)
/* nothing */;
assert(prefixlen>0);
assert(strncmp((char*)line,pattern,prefixlen)==0);
@ -1618,7 +1657,7 @@ static void substallpatterns(unsigned char *line,int buffersize)
/* find the start of a prefix (skip all non-alphabetic characters),
* also skip strings
*/
while (!isalpha(*start) && *start!='_' && *start!='\0') {
while (!alpha(*start) && *start!='\0') {
/* skip strings */
if (is_startstring(start)) {
start=(unsigned char *)skipstring(start);
@ -1636,7 +1675,7 @@ static void substallpatterns(unsigned char *line,int buffersize)
while ((*start<=' ' && *start!='\0') || *start=='(')
start++;
/* skip the symbol behind it */
while (isalpha(*start) || isdigit(*start) || *start=='_')
while (alphanum(*start))
start++;
/* drop back into the main loop */
continue;
@ -1644,7 +1683,7 @@ static void substallpatterns(unsigned char *line,int buffersize)
/* get the prefix (length), look for a matching definition */
prefixlen=0;
end=start;
while (isalpha(*end) || isdigit(*end) || *end=='_') {
while (alphanum(*end)) {
prefixlen++;
end++;
} /* while */
@ -1688,7 +1727,7 @@ SC_FUNC void preprocess(void)
lptr=pline; /* set "line pointer" to start of the parsing buffer */
iscommand=command();
if (iscommand!=CMD_NONE)
errorset(sRESET); /* reset error flag ("panic mode") on empty line or directive */
errorset(sRESET,0); /* reset error flag ("panic mode") on empty line or directive */
#if !defined NO_DEFINE
if (iscommand==CMD_NONE) {
assert(lptr!=term_expr);
@ -1882,7 +1921,7 @@ SC_FUNC int lex(cell *lexvalue,char **lexsym)
while (i<=tLAST) { /* match reserved words and compiler directives */
if (*lptr==**tokptr && match(*tokptr,TRUE)) {
_lextok=i;
errorset(sRESET); /* reset error flag (clear the "panic mode")*/
errorset(sRESET,0); /* reset error flag (clear the "panic mode")*/
if (pc_docexpr) /* optionally concatenate to documentation string */
insert_autolist(*tokptr);
return _lextok;
@ -1974,7 +2013,7 @@ SC_FUNC int lex(cell *lexvalue,char **lexsym)
} else if (*lptr==';') { /* semicolumn resets "error" flag */
_lextok=';';
lptr+=1;
errorset(sRESET); /* reset error flag (clear the "panic mode")*/
errorset(sRESET,0); /* reset error flag (clear the "panic mode")*/
} else {
_lextok=*lptr; /* if every match fails, return the character */
lptr+=1; /* increase the "lptr" pointer */
@ -2332,6 +2371,7 @@ SC_FUNC int ishex(char c)
static symbol *add_symbol(symbol *root,symbol *entry,int sort)
{
symbol *newsym;
int global = root==&glbtab;
if (sort)
while (root->next!=NULL && strcmp(entry->name,root->next->name)>0)
@ -2344,6 +2384,8 @@ static symbol *add_symbol(symbol *root,symbol *entry,int sort)
memcpy(newsym,entry,sizeof(symbol));
newsym->next=root->next;
root->next=newsym;
if (global)
AddToHashTable(sp_Globals, newsym);
return newsym;
}
@ -2388,6 +2430,7 @@ static void free_symbol(symbol *sym)
SC_FUNC void delete_symbol(symbol *root,symbol *sym)
{
symbol *origRoot = root;
/* find the symbol and its predecessor
* (this function assumes that you will never delete a symbol that is not
* in the table pointed at by "root")
@ -2398,13 +2441,27 @@ SC_FUNC void delete_symbol(symbol *root,symbol *sym)
assert(root!=NULL);
} /* while */
if (origRoot==&glbtab)
RemoveFromHashTable(sp_Globals, sym);
/* unlink it, then free it */
root->next=sym->next;
free_symbol(sym);
}
SC_FUNC int get_actual_compound(symbol *sym)
{
if (sym->ident == iARRAY || sym->ident == iREFARRAY) {
while (sym->parent)
sym = sym->parent;
}
return sym->compound;
}
SC_FUNC void delete_symbols(symbol *root,int level,int delete_labels,int delete_functions)
{
symbol *origRoot=root;
symbol *sym,*parent_sym;
constvalue *stateptr;
int mustdelete=0;
@ -2413,7 +2470,7 @@ SC_FUNC void delete_symbols(symbol *root,int level,int delete_labels,int delete_
* specified nesting level */
while (root->next!=NULL) {
sym=root->next;
if (sym->compound<level)
if (get_actual_compound(sym)<level)
break;
switch (sym->ident) {
case iLABEL:
@ -2458,6 +2515,8 @@ SC_FUNC void delete_symbols(symbol *root,int level,int delete_labels,int delete_
break;
} /* switch */
if (mustdelete) {
if (origRoot == &glbtab)
RemoveFromHashTable(sp_Globals, sym);
root->next=sym->next;
free_symbol(sym);
} else {
@ -2475,31 +2534,17 @@ SC_FUNC void delete_symbols(symbol *root,int level,int delete_labels,int delete_
/* for user defined operators, also remove the "prototyped" flag, as
* user-defined operators *must* be declared before use
*/
if (sym->ident==iFUNCTN && !isalpha(*sym->name) && *sym->name!='_' && *sym->name!=PUBLIC_CHAR)
if (sym->ident==iFUNCTN && !alpha(*sym->name))
sym->usage &= ~uPROTOTYPED;
root=sym; /* skip the symbol */
} /* if */
} /* if */
}
/* The purpose of the hash is to reduce the frequency of a "name"
* comparison (which is costly). There is little interest in avoiding
* clusters in similar names, which is why this function is plain simple.
*/
SC_FUNC uint32_t namehash(const char *name)
{
const unsigned char *ptr=(const unsigned char *)name;
int len=strlen(name);
if (len==0)
return 0L;
assert(len<256);
return (len<<24Lu) + (ptr[0]<<16Lu) + (ptr[len-1]<<8Lu) + (ptr[len>>1Lu]);
}
static symbol *find_symbol(const symbol *root,const char *name,int fnumber,int includechildren)
{
symbol *ptr=root->next;
unsigned long hash=namehash(name);
unsigned long hash=NameHash(name);
while (ptr!=NULL) {
if (hash==ptr->hash && strcmp(name,ptr->name)==0
&& (ptr->parent==NULL || includechildren)
@ -2569,7 +2614,10 @@ SC_FUNC int refer_symbol(symbol *entry,symbol *bywhom)
SC_FUNC void markusage(symbol *sym,int usage)
{
assert(sym!=NULL);
sym->usage |= (char)usage;
if ((usage & uWRITTEN) != 0)
sym->lnumber=fline;
/* check if (global) reference must be added to the symbol */
if ((usage & (uREAD | uWRITTEN))!=0) {
/* only do this for global symbols */
@ -2610,7 +2658,7 @@ SC_FUNC symbol *findconst(const char *name)
sym=find_symbol(&loctab,name,-1,TRUE); /* try local symbols first */
if (sym==NULL || sym->ident!=iCONSTEXPR) /* not found, or not a constant */
sym=find_symbol(&glbtab,name,fcurrent,TRUE);
sym=FindInHashTable(sp_Globals,name,fcurrent);
if (sym==NULL || sym->ident!=iCONSTEXPR)
return NULL;
assert(sym->parent==NULL || (sym->usage & uENUMFIELD)!=0);
@ -2651,16 +2699,18 @@ SC_FUNC symbol *addsym(const char *name,cell addr,int ident,int vclass,int tag,i
/* first fill in the entry */
strcpy(entry.name,name);
entry.hash=namehash(name);
entry.hash=NameHash(name);
entry.addr=addr;
entry.codeaddr=code_idx;
entry.vclass=(char)vclass;
entry.ident=(char)ident;
entry.tag=tag;
entry.usage=(char)usage;
entry.flags=0;
entry.compound=0; /* may be overridden later */
entry.states=NULL;
entry.fnumber=-1; /* assume global visibility (ignored for local symbols) */
entry.lnumber=fline;
entry.numrefers=1;
entry.refer=refer;
entry.parent=NULL;
@ -2670,7 +2720,6 @@ SC_FUNC symbol *addsym(const char *name,cell addr,int ident,int vclass,int tag,i
/* then insert it in the list */
if (vclass==sGLOBAL)
return add_symbol(&glbtab,&entry,TRUE);
else
return add_symbol(&loctab, &entry, FALSE);
}
@ -2685,7 +2734,7 @@ SC_FUNC symbol *addvariable(const char *name,cell addr,int ident,int vclass,int
* this special case.
*/
assert(vclass!=sGLOBAL || (sym=findglb(name))==NULL || (sym->usage & uDEFINE)==0
|| sym->ident==iFUNCTN && sym==curfunc);
|| (sym->ident==iFUNCTN && sym==curfunc));
if (ident==iARRAY || ident==iREFARRAY) {
symbol *parent=NULL,*top;

View File

@ -289,7 +289,6 @@ SC_FUNC int matchtag(int formaltag,int actualtag,int allowcoerce)
*/
if (!allowcoerce || formaltag!=0 || (actualtag & FIXEDTAG)!=0)
return FALSE;
} /* if */
return TRUE;
}
@ -488,6 +487,7 @@ static int plnge_rel(int *opstr,int opoff,int (*hier)(value *lval),value *lval)
int lvalue,opidx;
value lval2 = {0}; /* intialize, to avoid a compiler warning */
int count;
char boolresult;
/* this function should only be called for relational operators */
assert(op1[opoff]==os_le);
@ -504,7 +504,9 @@ static int plnge_rel(int *opstr,int opoff,int (*hier)(value *lval),value *lval)
error(212);
if (count>0) {
relop_prefix();
boolresult = lval->boolresult;
*lval=lval2; /* copy right hand expression of the previous iteration */
lval->boolresult = boolresult;
} /* if */
opidx+=opoff;
plnge2(op1[opidx],hier,lval,&lval2);
@ -1126,6 +1128,7 @@ static int hier2(value *lval)
symbol *sym=NULL;
int saveresult;
sym = NULL;
tok=lex(&val,&st);
switch (tok) {
case tINC: /* ++lval */
@ -1290,7 +1293,7 @@ static int hier2(value *lval)
return error(17,st); /* undefined symbol (symbol is in the table, but it is "used" only) */
tag=sym->tag;
} /* if */
if (sym->ident==iARRAY || sym->ident==iREFARRAY) {
if (sym!=NULL && (sym->ident==iARRAY || sym->ident==iREFARRAY)) {
int level;
symbol *idxsym=NULL;
for (level=0; matchtoken('['); level++) {
@ -1862,6 +1865,11 @@ static int nesting=0;
assert(nest_stkusage==0);
#endif
if ((sym->flags & flgDEPRECATED)!=0) {
char *ptr= (sym->documentation!=NULL) ? sym->documentation : "";
error(233,sym->name,ptr); /* deprecated (probably a native function) */
} /* if */
/* run through the arguments */
arg=sym->dim.arglist;
assert(arg!=NULL);
@ -2039,7 +2047,7 @@ static int nesting=0;
error(47); /* array sizes must match */
} /* if */
} /* if */
if (lval.ident!=iARRAYCELL) {
if (lval.ident!=iARRAYCELL|| lval.constval>0) {
/* save array size, for default values with uSIZEOF flag */
cell array_sz=lval.constval;
assert(array_sz!=0);/* literal array must have a size */

View File

@ -829,7 +829,7 @@ SC_FUNC void defstorage(void)
stgwrite("dump ");
}
/*
/**
* Inclrement/decrement stack pointer. Note that this routine does
* nothing if the delta is zero.
*/

View File

@ -290,6 +290,7 @@ static char *warnmsg[] = {
/*230*/ "no implementation for state \"%s\" / function \"%s\", no fall-back\n",
/*231*/ "state specification on forward declaration is ignored\n",
/*232*/ "output file is written, but with compact encoding disabled\n"
/*233*/ "symbol \"%s\" is marked as deprecated: %s\n",
#else
"\345 \274tr\240\226\233\277 %\206\273\337c\367\305",
"\222\323i\231\300\344\224t/\314cr\375\364",

View File

@ -41,7 +41,7 @@
#pragma warning(disable:4125) /* decimal digit terminates octal escape sequence */
#endif
#include "sc5.scp"
#include <sc5.scp>
#if defined _MSC_VER
#pragma warning(pop)
@ -51,7 +51,9 @@
static unsigned char warndisable[(NUM_WARNINGS + 7) / 8]; /* 8 flags in a char */
static int errflag;
static int errfile;
static int errstart; /* line number at which the instruction started */
static int errline; /* forced line number for the error message */
/* error
*
@ -70,7 +72,7 @@ SC_FUNC int error(int number,...)
static char *prefix[3]={ "error", "fatal error", "warning" };
static int lastline,errorcount;
static short lastfile;
char *msg,*pre;
char *msg,*pre,*filename;
va_list argptr;
char string[128];
@ -107,11 +109,22 @@ static short lastfile;
strexpand(string,(unsigned char *)msg,sizeof string,SCPACK_TABLE);
assert(errstart<=fline);
if (errline>0)
errstart=errline; /* forced error position, set single line destination */
else
errline=fline; /* normal error, errstart may (or may not) have been marked, endpoint is current line */
if (errstart>errline)
errstart=errline; /* special case: error found at end of included file */
if (errfile>=0)
filename=get_inputfile(errfile);/* forced filename */
else
filename=inpfname; /* current file */
assert(filename!=NULL);
va_start(argptr,number);
if (strlen(errfname)==0) {
int start= (errstart==fline) ? -1 : errstart;
if (pc_error(number,string,inpfname,start,fline,argptr)) {
int start= (errstart==errline) ? -1 : errstart;
if (pc_error((int)number,string,filename,start,errline,argptr)) {
if (outf!=NULL) {
pc_closeasm(outf,TRUE);
outf=NULL;
@ -121,10 +134,10 @@ static short lastfile;
} else {
FILE *fp=fopen(errfname,"a");
if (fp!=NULL) {
if (errstart>=0 && errstart!=fline)
fprintf(fp,"%s(%d -- %d) : %s %03d: ",inpfname,errstart,fline,pre,number);
if (errstart>=0 && errstart!=errline)
fprintf(fp,"%s(%d -- %d) : %s %03d: ",filename,errstart,errline,pre,number);
else
fprintf(fp,"%s(%d) : %s %03d: ",inpfname,fline,pre,number);
fprintf(fp,"%s(%d) : %s %03d: ",filename,errline,pre,number);
vfprintf(fp,string,argptr);
fclose(fp);
} /* if */
@ -144,6 +157,8 @@ static short lastfile;
longjmp(errbuf,2); /* fatal error, quit */
} /* if */
errline=-1;
errfile=-1;
/* check whether we are seeing many errors on the same line */
if ((errstart<0 && lastline!=fline) || lastline<errstart || lastline>fline || fcurrent!=lastfile)
errorcount=0;
@ -157,7 +172,7 @@ static short lastfile;
return 0;
}
SC_FUNC void errorset(int code)
SC_FUNC void errorset(int code,int line)
{
switch (code) {
case sRESET:
@ -171,6 +186,15 @@ SC_FUNC void errorset(int code)
break;
case sEXPRRELEASE:
errstart=-1; /* forget start line number */
errline=-1;
errfile=-1;
break;
case sSETLINE:
errstart=-1; /* force error line number, forget start line */
errline=line;
break;
case sSETFILE:
errfile=line;
break;
} /* switch */
}

View File

View File

@ -51,7 +51,7 @@
#pragma warning(disable:4125) /* decimal digit terminates octal escape sequence */
#endif
#include "sc7.scp"
#include <sc7.scp>
#if defined _MSC_VER
#pragma warning(pop)

View File

@ -255,16 +255,16 @@ SC_FUNC void delete_pathtable(void)
static stringpair substpair = { NULL, NULL, NULL}; /* list of substitution pairs */
static stringpair *substindex['z'-'A'+1]; /* quick index to first character */
static stringpair *substindex['z'-PUBLIC_CHAR+1]; /* quick index to first character */
static void adjustindex(char c)
{
stringpair *cur;
assert(c>='A' && c<='Z' || c>='a' && c<='z' || c=='_');
assert('A'<'_' && '_'<'z');
assert(c>='A' && c<='Z' || c>='a' && c<='z' || c=='_' || c==PUBLIC_CHAR);
assert(PUBLIC_CHAR<'A' && 'A'<'_' && '_'<'z');
for (cur=substpair.next; cur!=NULL && cur->first[0]!=c; cur=cur->next)
/* nothing */;
substindex[(int)c-'A']=cur;
substindex[(int)c-PUBLIC_CHAR]=cur;
}
SC_FUNC stringpair *insert_subst(char *pattern,char *substitution,int prefixlen)
@ -276,6 +276,26 @@ SC_FUNC stringpair *insert_subst(char *pattern,char *substitution,int prefixlen)
if ((cur=insert_stringpair(&substpair,pattern,substitution,prefixlen))==NULL)
error(103); /* insufficient memory (fatal error) */
adjustindex(*pattern);
if (pc_deprecate != NULL) {
assert(cur != NULL);
cur->flags |= flgDEPRECATED;
if (sc_status == statWRITE) {
if (cur->documentation != NULL) {
free(cur->documentation);
cur->documentation = NULL;
} /* if */
cur->documentation = pc_deprecate;
}
else {
free(pc_deprecate);
} /* if */
pc_deprecate = NULL;
}
else {
cur->flags = 0;
cur->documentation = NULL;
} /* if */
return cur;
}
@ -284,10 +304,26 @@ SC_FUNC stringpair *find_subst(char *name,int length)
stringpair *item;
assert(name!=NULL);
assert(length>0);
assert(*name>='A' && *name<='Z' || *name>='a' && *name<='z' || *name=='_');
item=substindex[(int)*name-'A'];
assert(*name>='A' && *name<='Z' || *name>='a' && *name<='z' || *name=='_' || *name==PUBLIC_CHAR);
item=substindex[(int)*name-PUBLIC_CHAR];
if (item!=NULL)
item=find_stringpair(item,name,length);
if (item && (item->flags & flgDEPRECATED) != 0) {
static char macro[128];
char *rem, *msg = (item->documentation != NULL) ? item->documentation : "";
strncpy(macro, item->first, sizeof(macro));
macro[sizeof(macro) - 1] = '\0';
/* If macro contains an opening parentheses and a percent sign, then assume that
* it takes arguments and remove them from the warning message.
*/
if ((rem = strchr(macro, '(')) != NULL && strchr(macro, '%') > rem) {
*rem = '\0';
}
error(233, macro, msg); /* deprecated (macro/constant) */
}
return item;
}
@ -296,8 +332,8 @@ SC_FUNC int delete_subst(char *name,int length)
stringpair *item;
assert(name!=NULL);
assert(length>0);
assert(*name>='A' && *name<='Z' || *name>='a' && *name<='z' || *name=='_');
item=substindex[(int)*name-'A'];
assert(*name>='A' && *name<='Z' || *name>='a' && *name<='z' || *name=='_' || *name==PUBLIC_CHAR);
item=substindex[(int)*name-PUBLIC_CHAR];
if (item!=NULL)
item=find_stringpair(item,name,length);
if (item==NULL)
@ -318,7 +354,7 @@ SC_FUNC void delete_substtable(void)
#endif /* !defined NO_SUBST */
/* ----- input file list ----------------------------------------- */
/* ----- input file list (explicit files)------------------------- */
static stringlist sourcefiles = {NULL, NULL};
SC_FUNC stringlist *insert_sourcefile(char *string)
@ -338,6 +374,28 @@ SC_FUNC void delete_sourcefiletable(void)
}
/* ----- parsed file list (explicit + included files) ------------ */
static stringlist inputfiles = {NULL, NULL};
SC_FUNC stringlist *insert_inputfile(char *string)
{
if (sc_status!=statFIRST)
return insert_string(&inputfiles,string);
return NULL;
}
SC_FUNC char *get_inputfile(int index)
{
return get_string(&inputfiles,index);
}
SC_FUNC void delete_inputfiletable(void)
{
delete_stringtable(&inputfiles);
assert(inputfiles.next==NULL);
}
/* ----- documentation tags -------------------------------------- */
#if !defined SC_LIGHT
static stringlist docstrings = {NULL, NULL};

450
compiler/libpc300/scpack.c Normal file
View File

@ -0,0 +1,450 @@
/* compress.c -- Byte Pair Encoding compression */
/* Copyright 1996 Philip Gage */
/* This program appeared in the September 1997 issue of
* C/C++ Users Journal. The original source code may still
* be found at the web site of the magazine (www.cuj.com).
*
* It has been modified by me (Thiadmer Riemersma) to
* compress only a section of the input file and to store
* the compressed output along with the input as "C" strings.
*
* Compiling instructions:
* Borland C++ 16-bit (large memory model is required):
* bcc -ml scpack.c
*
* Watcom C/C++ 32-bit:
* wcl386 scpack.c
*
* GNU C (Linux), 32-bit:
* gcc scpack.c -o scpack
*/
#include <assert.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if UINT_MAX > 0xFFFFU
#define MAXSIZE 1024*1024L
#else
#define MAXSIZE UINT_MAX /* Input file buffer size */
#endif
#define HASHSIZE 8192 /* Hash table size, power of 2 */
#define THRESHOLD 3 /* Increase for speed, min 3 */
#define START_TOKEN "#ifdef SCPACK" /* start reading the buffer here */
#define NAME_TOKEN "#define SCPACK_TABLE"
#define SEP_TOKEN "#define SCPACK_SEPARATOR"
#define TERM_TOKEN "#define SCPACK_TERMINATOR"
#define TEMPFILE "~SCPACK.TMP"
static char tablename[32+1] = "scpack_table";
static char separator[16]=",";
static char terminator[16]="";
int compress(unsigned char *buffer, unsigned buffersize, unsigned char pairtable[128][2])
{
unsigned char *left, *right, *count;
unsigned char a, b, bestcount;
unsigned i, j, index, bestindex, code=128;
/* Dynamically allocate buffers and check for errors */
left = (unsigned char *)malloc(HASHSIZE);
right = (unsigned char *)malloc(HASHSIZE);
count = (unsigned char *)malloc(HASHSIZE);
if (left==NULL || right==NULL || count==NULL) {
printf("Error allocating memory\n");
exit(1);
}
/* Check for errors */
for (i=0; i<buffersize; i++)
if (buffer[i] > 127) {
printf("This program works only on text files (7-bit ASCII)\n");
exit(1);
}
memset(pairtable, 0, 128*2*sizeof(char));
do { /* Replace frequent pairs with bytes 128..255 */
/* Enter counts of all byte pairs into hash table */
memset(count,0,HASHSIZE);
for (i=0; i<buffersize-1; i++) {
a = buffer[i];
b = buffer[i+1];
/* ignore any pair with a '\0' */
if (a == 0 || b == 0)
continue;
index = (a ^ (b << 6)) & (HASHSIZE-1);
while ((left[index] != a || right[index] != b) &&
count[index] != 0)
index = (index + 1) & (HASHSIZE-1);
left[index] = a;
right[index] = b;
if (count[index] < 255)
count[index] += (unsigned char)1;
}
/* Search hash table for most frequent pair */
bestcount = THRESHOLD - 1;
for (i=0; i<HASHSIZE; i++) {
if (count[i] > bestcount) {
bestcount = count[i];
bestindex = i;
}
}
/* Compress if enough occurrences of pair */
if (bestcount >= THRESHOLD) {
/* Add pair to table using code as index */
a = pairtable[code-128][0] = left[bestindex];
b = pairtable[code-128][1] = right[bestindex];
/* Replace all pair occurrences with unused byte */
for (i=0, j=0; i<buffersize; i++, j++)
if (a == buffer[i] && b == buffer[i+1]) {
buffer[j] = (unsigned char)code;
++i;
}
else
buffer[j] = buffer[i];
buffersize = j;
}
else
break;
} while (++code < 255);
/* done */
free(left); free(right); free(count);
return buffersize; /* return adjusted buffersize */
}
static int strmatch(char *str, char *token, int *indent)
{
int i = 0;
/* skip whitespace */
while (*str==' ' || *str=='\t') {
str++;
i++;
} /* while */
if (strncmp(str,token,strlen(token))!=0)
return 0;
if (indent != NULL)
*indent = i;
return 1;
}
static void check_if(char *str,int linenr)
{
if (strmatch(str,"#if",NULL)) {
printf("Error: \"#if...\" preprocessor statement should not be in SCPACK section "
"(line %d)\n", linenr);
exit(1);
} /* if */
}
static int check_tablename(char *str)
{
int i;
if (strmatch(str,NAME_TOKEN,NULL)) {
str += strlen(NAME_TOKEN);
while (*str==' ' || *str=='\t')
str++;
for (i=0; i<(sizeof tablename - 1) && *str!='\0' && strchr(" \t\n",*str)==NULL; i++, str++)
tablename[i] = *str;
tablename[i] = '\0';
return 1;
} /* if */
return 0;
}
static int check_separator(char *str)
{
int i;
if (strmatch(str,SEP_TOKEN,NULL)) {
str += strlen(SEP_TOKEN);
while (*str==' ' || *str=='\t')
str++;
for (i=0; i<(sizeof separator - 1) && *str!='\0' && strchr(" \t\n",*str)==NULL; i++, str++)
separator[i] = *str;
separator[i] = '\0';
return 1;
} /* if */
if (strmatch(str,TERM_TOKEN,NULL)) {
str += strlen(TERM_TOKEN);
while (*str==' ' || *str=='\t')
str++;
for (i=0; i<(sizeof terminator - 1) && *str!='\0' && strchr(" \t\n",*str)==NULL; i++, str++)
terminator[i] = *str;
terminator[i] = '\0';
return 1;
} /* if */
return 0;
}
/* readbuffer
* Reads in the input file and stores all strings in the
* section between "#ifdef SCPACK" and "#else" in a buffer.
* Only text that is between double quotes is added to the
* buffer; the \" escape code is handled. Multiple strings
* on one line are handled.
*/
unsigned readbuffer(FILE *input, unsigned char *buffer)
{
char str[256];
unsigned buffersize;
int i,linenr;
linenr=0;
buffersize=0;
rewind(input);
while (!feof(input)) {
while (fgets(str,sizeof str,input)!=NULL) {
linenr++;
check_tablename(str);
check_separator(str);
if (strmatch(str,START_TOKEN,NULL))
break;
} /* while */
if (!strmatch(str,START_TOKEN,NULL))
return buffersize; /* no (more) section found, quit */
while (fgets(str,sizeof str,input)!=NULL) {
linenr++;
check_if(str,linenr);
if (check_tablename(str))
printf("Error: table name definition should not be in SCPACK section (line %d)\n", linenr);
check_separator(str);
if (strmatch(str,"#else",NULL))
break; /* done */
/* add to the buffer only what is between double quotes */
i=0;
do {
while (str[i]!='\0' && str[i]!='"')
i++;
if (str[i]=='"') {
/* we are in a string */
i++;
while (str[i]!='\0' && str[i]!='"') {
/* handle escape sequences */
if (str[i]=='\\') {
i++;
switch (str[i]) {
case 'a': /* alarm */
buffer[buffersize++]='\a';
i++;
break;
case 'b': /* backspace */
buffer[buffersize++]='\b';
i++;
break;
case 'f': /* form feed */
buffer[buffersize++]='\f';
i++;
break;
case 'n': /* newline */
buffer[buffersize++]='\n';
i++;
break;
case 'r': /* carriage return */
buffer[buffersize++]='\n';
i++;
break;
case 't': /* tab */
buffer[buffersize++]='\t';
i++;
break;
case '\'':
buffer[buffersize++]='\'';
i++;
break;
case '"':
buffer[buffersize++]='"';
i++;
break;
default:
// ??? octal character code escapes and hexadecimal escapes
// not supported
printf("Unknown escape sequence '\\%c' on line %d\n",
str[i], linenr);
} /* switch */
} else {
buffer[buffersize++]=str[i++];
} /* if */
} /* while */
if (str[i]=='"') {
buffer[buffersize++]='\0'; /* terminate each string */
i++;
} else {
printf("Error: unterminated string on line %d\n",linenr);
} /* if */
} /* if */
} while (str[i]!='\0');
} /* while - in SCPACK section */
/* put in another '\0' to terminate the section */
buffer[buffersize++]='\0';
} /* while - !feof(input) */
return buffersize;
}
static void write_pairtable(FILE *output, unsigned char pairtable[128][2], char *tablename)
{
int i;
/* dump the pair table */
fprintf(output, "/*-*SCPACK start of pair table, do not change or remove this line */\n");
fprintf(output, "unsigned char %s[][2] = {", tablename);
for (i=0; i<128 && pairtable[i][0]!=0 && pairtable[i][1]!=0; i++) {
if ((i % 16)==0)
fprintf(output, "\n ");
else
fprintf(output, " ");
fprintf(output, "{%d,%d}", pairtable[i][0], pairtable[i][1]);
/* check if something follows this pair */
if (i+1<128 && pairtable[i+1][0]!=0 && pairtable[i+1][1]!=0)
fprintf(output, ",");
} /* for */
fprintf(output, "\n};\n");
fprintf(output, "/*-*SCPACK end of pair table, do not change or remove this line */\n");
}
void writefile(FILE *input, FILE *output, unsigned char *buffer, unsigned buffersize, unsigned char pairtable[128][2])
{
char str[256];
int insection, indent, needseparator;
unsigned char *bufptr;
bufptr = buffer;
insection = 0;
rewind(input);
while (!feof(input)) {
while (fgets(str,sizeof str,input)!=NULL) {
fprintf(output,"%s",str);
if (check_tablename(str)) {
write_pairtable(output, pairtable, tablename);
/* strip an existing pair table from the file */
if (fgets(str,sizeof str,input)!=NULL) {
if (strmatch(str,"/*-*SCPACK",NULL)) {
while (fgets(str,sizeof str,input)!=NULL)
if (strmatch(str,"/*-*SCPACK",NULL))
break;
} else {
fprintf(output,"%s",str);
} /* if */
} /* if */
} /* if */
if (strmatch(str,START_TOKEN,NULL))
insection = 1;
if (insection && strmatch(str,"#else",NULL))
break;
} /* while */
if (!strmatch(str,"#else",&indent))
return; /* no (more) section found, quit */
insection=0;
/* dump the buffer as strings, separated with commas */
needseparator = 0;
while (*bufptr != '\0') {
assert((unsigned)(bufptr-buffer) < buffersize);
if (needseparator)
fprintf(output, "%s\n",separator);
fprintf(output, "%*c\"",indent+2,' ');
/* loop over string */
while (*bufptr != '\0') {
if (*bufptr<' ' || *bufptr >= 128 || *bufptr == '"' || *bufptr == '\\')
fprintf(output, "\\%03o", *bufptr);
else
fprintf(output, "%c", *bufptr);
bufptr++;
} /* while */
fprintf(output, "\"");
needseparator = 1;
bufptr++; /* skip '\0' */
} /* while */
fprintf(output, "%s\n",terminator);
bufptr++;
/* skip the input file until the #endif section */
while (fgets(str,sizeof str,input)!=NULL) {
if (strmatch(str,"#endif",NULL)) {
fprintf(output,"%s",str);
break; /* done */
} /* if */
} /* while */
} /* while - !feof(input) */
}
static void usage(void)
{
printf("Usage: scpack <filename> [output file]\n");
exit(1);
}
int main(int argc, char **argv)
{
FILE *in, *out;
unsigned char *buffer;
unsigned buffersize, orgbuffersize;
unsigned char pairtable[128][2];
if (argc < 2 || argc > 3)
usage();
if ((in=fopen(argv[1],"rt"))==NULL) {
printf("SCPACK: error opening input %s\n",argv[1]);
usage();
} /* if */
if (argc == 2) {
if ((out=fopen(TEMPFILE,"wt"))==NULL) {
printf("SCPACK: error opening temporary file %s\n",TEMPFILE);
usage();
} /* if */
} else {
if ((out=fopen(argv[2],"wt"))==NULL) {
printf("SCPACK: error opening output file %s\n",argv[2]);
usage();
} /* if */
} /* if */
buffer = (unsigned char *)malloc(MAXSIZE);
if (buffer == NULL) {
printf("SCPACK: error allocating memory\n");
return 1;
} /* if */
/* 1. read the buffer
* 2. compress the buffer
* 3. copy the file, insert the compressed buffer
*/
buffersize = readbuffer(in, buffer);
orgbuffersize = buffersize;
if (buffersize > 0) {
buffersize = compress(buffer, buffersize, pairtable);
writefile(in, out, buffer, buffersize, pairtable);
printf("SCPACK: compression ratio: %ld%% (%d -> %d)\n",
100L-(100L*buffersize)/orgbuffersize, orgbuffersize, buffersize);
} else {
printf("SCPACK: no SCPACK section found, nothing to do\n");
} /* if */
fclose(out);
fclose(in);
/* let the new file replace the old file */
if (buffersize == 0) {
if (argc == 2)
remove(TEMPFILE);
else
remove(argv[2]);
} else if (argc == 2) {
remove(argv[1]);
rename(TEMPFILE,argv[1]);
} /* if */
return 0;
}

View File

@ -24,6 +24,7 @@
#include <stdio.h>
#include <stdlib.h> /* for _MAX_PATH */
#include "sc.h"
#include "sp_symhash.h"
/* global variables
*
@ -84,6 +85,7 @@ SC_VDEFINE int sc_rationaltag=0; /* tag for rational numbers */
SC_VDEFINE int rational_digits=0; /* number of fractional digits */
SC_VDEFINE int sc_allowproccall=0; /* allow/detect tagnames in lex() */
SC_VDEFINE short sc_is_utf8=FALSE; /* is this source file in UTF-8 encoding */
SC_VDEFINE char *pc_deprecate = NULL;/* if non-null, mark next declaration as deprecated */
SC_VDEFINE int sc_showincludes=0; /* show include files */
SC_VDEFINE constvalue sc_automaton_tab = { NULL, "", 0, 0}; /* automaton table */
@ -95,6 +97,8 @@ SC_VDEFINE FILE *outf = NULL; /* (intermediate) text file written to */
SC_VDEFINE jmp_buf errbuf;
SC_VDEFINE HashTable *sp_Globals = NULL;
#if !defined SC_LIGHT
SC_VDEFINE int sc_makereport=FALSE; /* generate a cross-reference report */
#endif

View File

@ -0,0 +1,229 @@
/* vim: set ts=4 sw=4 tw=99 et: */
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "sc.h"
#include "sp_symhash.h"
SC_FUNC uint32_t
NameHash(const char *str)
{
size_t len = strlen(str);
const uint8_t *data = (uint8_t *)str;
#undef get16bits
#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
|| defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
#define get16bits(d) (*((const uint16_t *) (d)))
#endif
#if !defined (get16bits)
#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
+(uint32_t)(((const uint8_t *)(d))[0]) )
#endif
uint32_t hash = len, tmp;
int rem;
if (len <= 0 || data == NULL) return 0;
rem = len & 3;
len >>= 2;
/* Main loop */
for (;len > 0; len--) {
hash += get16bits (data);
tmp = (get16bits (data+2) << 11) ^ hash;
hash = (hash << 16) ^ tmp;
data += 2*sizeof (uint16_t);
hash += hash >> 11;
}
/* Handle end cases */
switch (rem) {
case 3: hash += get16bits (data);
hash ^= hash << 16;
hash ^= data[sizeof (uint16_t)] << 18;
hash += hash >> 11;
break;
case 2: hash += get16bits (data);
hash ^= hash << 11;
hash += hash >> 17;
break;
case 1: hash += *data;
hash ^= hash << 10;
hash += hash >> 1;
}
/* Force "avalanching" of final 127 bits */
hash ^= hash << 3;
hash += hash >> 5;
hash ^= hash << 4;
hash += hash >> 17;
hash ^= hash << 25;
hash += hash >> 6;
return hash;
#undef get16bits
}
SC_FUNC HashTable *NewHashTable()
{
HashTable *ht = (HashTable*)malloc(sizeof(HashTable));
if (!ht)
return ht;
ht->buckets = (HashEntry **)calloc(32, sizeof(HashEntry *));
if (!ht->buckets) {
free(ht);
return NULL;
}
ht->nbuckets = 32;
ht->nused = 0;
ht->bucketmask = 32 - 1;
return ht;
}
SC_FUNC void
DestroyHashTable(HashTable *ht)
{
uint32_t i;
if (!ht)
return;
for (i = 0; i < ht->nbuckets; i++) {
HashEntry *he = ht->buckets[i];
while (he != NULL) {
HashEntry *next = he->next;
free(he);
he = next;
}
}
free(ht->buckets);
free(ht);
}
SC_FUNC symbol *
FindTaggedInHashTable(HashTable *ht, const char *name, int fnumber,
int *cmptag)
{
int count=0;
symbol *firstmatch=NULL;
uint32_t hash = NameHash(name);
uint32_t bucket = hash & ht->bucketmask;
HashEntry *he = ht->buckets[bucket];
assert(cmptag!=NULL);
while (he != NULL) {
symbol *sym = he->sym;
if ((sym->parent==NULL || sym->ident==iCONSTEXPR) &&
(sym->fnumber<0 || sym->fnumber==fnumber) &&
(strcmp(sym->name, name) == 0))
{
/* return closest match or first match; count number of matches */
if (firstmatch==NULL)
firstmatch=sym;
if (*cmptag==0)
count++;
if (*cmptag==sym->tag) {
*cmptag=1; /* good match found, set number of matches to 1 */
return sym;
}
}
he = he->next;
}
if (firstmatch!=NULL)
*cmptag=count;
return firstmatch;
}
SC_FUNC symbol *
FindInHashTable(HashTable *ht, const char *name, int fnumber)
{
uint32_t hash = NameHash(name);
uint32_t bucket = hash & ht->bucketmask;
HashEntry *he = ht->buckets[bucket];
while (he != NULL) {
symbol *sym = he->sym;
if ((sym->parent==NULL || sym->ident==iCONSTEXPR) &&
(sym->fnumber<0 || sym->fnumber==fnumber) &&
(strcmp(sym->name, name) == 0))
{
return sym;
}
he = he->next;
}
return NULL;
}
static void
ResizeHashTable(HashTable *ht)
{
uint32_t i;
uint32_t xnbuckets = ht->nbuckets * 2;
uint32_t xbucketmask = xnbuckets - 1;
HashEntry **xbuckets = (HashEntry **)calloc(xnbuckets, sizeof(HashEntry*));
if (!xbuckets)
return;
for (i = 0; i < ht->nbuckets; i++) {
HashEntry *he = ht->buckets[i];
while (he != NULL) {
HashEntry *next = he->next;
uint32_t bucket = he->sym->hash & xbucketmask;
he->next = xbuckets[bucket];
xbuckets[bucket] = he;
he = next;
}
}
free(ht->buckets);
ht->buckets = xbuckets;
ht->nbuckets = xnbuckets;
ht->bucketmask = xbucketmask;
}
SC_FUNC void
AddToHashTable(HashTable *ht, symbol *sym)
{
uint32_t bucket = sym->hash & ht->bucketmask;
HashEntry **hep, *he;
hep = &ht->buckets[bucket];
while (*hep) {
assert((*hep)->sym != sym);
hep = &(*hep)->next;
}
he = (HashEntry *)malloc(sizeof(HashEntry));
if (!he)
error(163);
he->sym = sym;
he->next = NULL;
*hep = he;
ht->nused++;
if (ht->nused > ht->nbuckets && ht->nbuckets <= INT_MAX / 2)
ResizeHashTable(ht);
}
SC_FUNC void
RemoveFromHashTable(HashTable *ht, symbol *sym)
{
uint32_t bucket = sym->hash & ht->bucketmask;
HashEntry **hep = &ht->buckets[bucket];
HashEntry *he = *hep;
while (he != NULL) {
if (he->sym == sym) {
*hep = he->next;
free(he);
ht->nused--;
return;
}
hep = &he->next;
he = *hep;
}
assert(0);
}

View File

@ -0,0 +1,28 @@
/* vim: set ts=4 sw=4 tw=99 et: */
#ifndef _INCLUDE_SPCOMP_SYMHASH_H_
#define _INCLUDE_SPCOMP_SYMHASH_H_
SC_FUNC uint32_t NameHash(const char *str);
typedef struct HashEntry {
symbol *sym;
struct HashEntry *next;
} HashEntry;
struct HashTable {
uint32_t nbuckets;
uint32_t nused;
uint32_t bucketmask;
HashEntry **buckets;
};
SC_FUNC HashTable *NewHashTable();
SC_FUNC void DestroyHashTable(HashTable *ht);
SC_FUNC void AddToHashTable(HashTable *ht, symbol *sym);
SC_FUNC void RemoveFromHashTable(HashTable *ht, symbol *sym);
SC_FUNC symbol *FindInHashTable(HashTable *ht, const char *name, int fnumber);
SC_FUNC symbol *FindTaggedInHashTable(HashTable *ht, const char *name, int fnumber,
int *cmptag);
#endif /* _INCLUDE_SPCOMP_SYMHASH_H_ */

View File

@ -2535,6 +2535,7 @@ native plugin_flags(hdr=0, plid=-1);
*
* @noreturn
*/
#pragma deprecated Module dependency is now automatically handled by the compiler. This forward is no longer called.
forward plugin_modules();
/**
@ -2545,6 +2546,7 @@ forward plugin_modules();
*
* @noreturn
*/
#pragma deprecated Module dependency is now automatically handled by the compiler. This native has no effect.
native require_module(const module[]);
/**
@ -2556,6 +2558,7 @@ native require_module(const module[]);
*
* @return 1 if the server is 64 bit, 0 otherwise
*/
#pragma deprecated AMXX is not shipping 64bits builds anymore. This native is basically guaranteed to return 0.
native is_amd64_server();
/**

View File

@ -62,7 +62,7 @@ native bool:geoip_code3_ex(const ip[], result[4]);
*
* @return 1 on a successful lookup, 0 otherwise.
*/
//#pragma deprecated Use geoip_code2_ex() instead.
#pragma deprecated Use geoip_code2_ex() instead.
native geoip_code2(const ip[], ccode[3]);
/**
@ -76,7 +76,7 @@ native geoip_code2(const ip[], ccode[3]);
*
* @return 1 on a successful lookup, 0 otherwise.
*/
//#pragma deprecated Use geoip_code3() instead.
#pragma deprecated Use geoip_code3() instead.
native geoip_code3(const ip[], result[4]);
/**

View File

@ -543,6 +543,7 @@ forward client_spawn(id);
* @param Damage The amount of damage being done.
* @param DamageType The damage type being done (bitmask).
*/
#pragma deprecated It is suggested to use hamsandwich for this action instead.
native ns_takedamage(IDVictim, IDInflictor, IDAttacker, Float:Damage, DamageType);
/**

View File

@ -711,7 +711,7 @@ native strncmp(const string1[], const string2[], num, bool:ignorecase=false);
* Backwards compatibility stock - use argbreak or argparse.
* @deprecated this function does not work properly.
*/
//#pragma deprecated Use argbreak() instead
#pragma deprecated Use argbreak() instead
stock strbreak(const text[], Left[], leftLen, Right[], rightLen)
{
return argbreak(text, Left, leftLen, Right, rightLen);

View File

@ -14,7 +14,7 @@
#include <amxmodx>
#include <amxmisc>
#pragma tabsize 0
#pragma tabsize 4
new g_TeamOneAck[12];
new g_TeamTwoAck[12];