Introduction ============ Small is a simple, typeless, 32-bit extension language with a C-like syntax. The Small compiler outputs P-code (or bytecode) that subsequently runs on an abstract machine. Execution speed, stability, simplicity and a small footprint were essential design criterions for both the language and the abstract machine. Through the evolution of the Small toolkit, this README has steadily been growing, as more and more compilers were tested and more components were added. More recently, the compiling instructions were moved to a separate document entitled ``The Small booklet: Implementor's Guide''. To get the Small toolkit working on your system, please (also) consult that document. To learn about the Small language, consult the document ``The Small booklet: The Language''. Both these documents are available from the web page devoted to Small: http://www.compuphase.com/small.htm Below is a list of topics that this README covers, in this order: o Getting started How to get your first Small program running o Acknowledgements For components not written by CompuPhase o Using the AMX DLL How to create a program that uses the pre-built DLL. o Building the AMX DLL Notes on how the DLL must be built itself. o Building extension modules for the AMX DLL Getting started =============== The first question is: what do you need? You should always download the "Small toolkit" archive ("smallkit.zip"), because it is the only archive that contains the include files and the example files. If you are running on a Win32 platform, I suggest that you also get the precompiled binaries of the Small compiler ("smallwin32.zip"). If you are running on another platform, you must build the compiler and the abstract machine first, from the source files of the "Small toolkit". When "unzipping" these archives, make sure that the directory structure in the ZIP files is retained. Otherwise, the Small compiler will not be able to find its "include" files, for example. Assuming that you have obtained (somehow) an executable version of the Small compiler and the Small run-time, you should put it in a directory. However, the Small compiler also needs to locate "include files". On many operating systems, the Small compiler is able to automatically read these header files from the directory "include" that is below the directory that the compiler is in itself. Thus, if the Small compiler is in directory "C:\WhatEver\Small", I suggest that you also create directory "C:\WhatEver\Small\include" and copy the ".inc" files there. If your operating system is not compatible with Win32 or Linux, the Small compiler may not know how to locate the "include" directory and you have to specify it yourself with the "-i" command line option (when running the compiler). That behind your back, locate one of the example scripts (e.g. "hello.sma") and compile it with: sc hello This should produce "hello.amx", which you can then run with: srun hello.amx Many applications that use Small, run the Small compiler as a child process; i.e. the Small compiler is often a separate, self-contained program. The abstract machine, however, is almost never a separate process: typically you want the abstract machine to be integrated in the application so that scripts can call into the application. In other words, you might be using "sc" as is, but you won't be using "srun" as is. This is why srun is kept short and dump, "srun" is a program that is mostly developed in the Small manual to show you what you should do at a minimum to embed Small into a program. The first paragraph mentioned that, if you are not running on Windows, you must build the tools yourself before you can compile and run the simple scripts in the archive. There are separate sections on that task in this readme. For the abstract machine, see the "GNU GCC" section as it is the only section that has a comment on other operating systems than DOS/Windows. The section on building the compiler has a few notes on Linux (which may be important for other operating systems as well) and, more importantly, it mentions a separate makefile for Linux. Acknowledgements ================ This work is based on the "Small C Compiler" by Ron Cain and James E. Hendrix, as published in the book "Dr. Dobb's Toolbook of C", Brady Books, 1986. The assembler version of the abstract machine (five times faster than the ANSI C version and over two times faster than the GNU C version) was written by Marc Peter (macpete@gmx.de). Marc holds the copyright of the file AMXEXEC.ASM, but its distribution and license fall under the same conditions as those stated in LICENSE.TXT. The Just-In-Time compiler (JIT) included in this release was also written by Marc Peter. As is apparent from the source code, the JIT is an evolutionary step from his earlier abstract machine. The JIT falls under the same (liberal) license as the other components in the Small toolkit. The abstract machine has evolved slightly since Marc Peter wrote the JIT and the JIT does currently not handle the "sleep" instruction correctly. Greg Garner from Artran Inc. (gmg@artran.com) compiled the source files as C++ files (rather than C), added type casts where needed and fixed two bugs in the Small compiler in the process. Greg Garner also wrote (and contributed) the extension module for floating point support (files FLOAT.CPP and FLOAT.INC). Dark Fiber contributed an extension module for the AMX to provide decent quality pseudo-random numbers, starting with any seed. To illustrate the module, he also wrote a simple card game (TWENTY1.SMA) as a non-trivial small script. Dieter Neubauer made a 16-bit version of the Small tools (meaning that a cell is 16-bit, instead of the default 32-bit). His changes were merged in the original distribution. Note that fixed or floating point arithmetic will be near to impossible with a 16-bit cell. Robert Daniels ported Small to ucLinux and corrected a few errors that had to do with the "Endianness" of the CPU. His corrections make the Small compiler and abstract machine better portable to Big Endian machines. Frank Condello (pox@planetquake.com) ported the toolkit to the Macintosh and donated the changes. Using the AMX DLL ================= The 32-bit AMX DLL (file AMX32.DLL) uses __stdcall calling convention, which is the most common calling convention for Win32 DLLs. If your compiler defaults to a different calling convention (most do), you must specify the __stdcall calling convention explicitly. This can be done in two ways: 1. a command line option for the C/C++ compiler (look up the manual) 2. setting the macros AMX_NATIVE_CALL and AMXAPI to __stdcall before including AMX.H. The macros AMX_NATIVE_CALL and AMXAPI are explained earlier in this README. The 32-bit AMX DLL comes with import libraries for various Win32 compilers: o for Microsoft Visual C/C++ version 4.0 and above, use AMX32M.LIB o for Borland C++ version 5.0 and for Borland C++ Builder, use AMX32B.LIB o for Watcom C/C++ version 10.6 and 11.0, use AMX32W.LIB The AMX DLL already includes "core" and "console" functions, which are the equivalents of the C files AMXCORE.C and AMXCONS.C. Console output goes to a text window (with 30 lines of 80 characters per line) that the DLL creates. The core and console functions are automatically registered to any Small program by amx_Init(). Microsoft Visual C/C++ version 5.0 or 6.0, 32-bit: cl -DAMXAPI=__stdcall srun-dll.c amx32m.lib (Note: the "srun-dll" example does not register additional native functions. Therefore, AMX_NATIVE_CALL does not need to be defined.) Watcom C/C++ version 11.0, 32-bit: wcl386 /l=nt_win /dAMXAPI=__stdcall srun-dll.c amx32w.lib (Note: the "srun-dll" example does not register additional native functions. Therefore, AMX_NATIVE_CALL does not need to be defined.) Borland C++ version 3.1, 16-bit: bcc -DAMXAPI=__cdecl -W -ml srun-dll.c amx16.lib (Note: the program must be compiled as a Win16 application, because only Windows programs can use DLLs (option -W). Using large memory model, option -ml, is not strictly required, but it is the most convenient. Finally, note that the 16-bit DLL uses __cdecl calling convention for its exported functions, for reasons explained below.) Building the AMX DLL ==================== The 32-bit DLL is made from the files AMX.C, AMXDLL.C, AMXCONS.C, AMXCORE.C and AMXEXEC.ASM. The first point to address is, again, that of calling conventions. AMXAPI and AMX_NATIVE_CALL must be set to __stdcall. I did this by adding the macros onto the command line for the compiler, but you could also create an include file with these macros before including AMX.H. The function amx_Init() of the DLL is not identical to the standard version: it also registers the "core" and "console" modules and registers external libraries if it can find these. The original amx_Init() in AMX.C is renamed to amx_InitAMX(), via macros, at compile time. AMXDLL.C implements the new amx_Init() and this one is not translated. All in all, the makefile for the AMX DLL plays a few tricks with macros in order to keep the original distribution untouched. When you need to recompile the AMX DLL, you may, of course, also opt for modifying AMX.H and AMX.C to suit the needs for Win32 DLLs. If you rebuild the DLL for 16-bit Windows, keep the following points in mind: o You must use the ANSI C version of the abstract machine; there is no 16-bit assembler implementation. o Use large memory model: pointers used in "interface" functions must be far pointers to bridge the data spaces of the .EXE and the DLL. The source code is (mostly) ANSI C, however, and "far pointers" are an extension to ANSI C. The easiest way out is to make all pointers "far" by using large memory model. o AMX_NATIVE_CALL are best set to "__far __pascal". This is the "standard" calling convention for have interface functions in 16-bit Windows. o The native functions should also be exported, so that the data segment is set to that of the module that the native functions reside in. o AMXAPI, however, must be set to "__cdecl", because amx_Exec() uses a variable length argument list. This is incompatible with the "pascal" calling convention. The distribution for the AMX DLL comes with two makefiles: the makefile for the 32-bit DLL is for Watcom C/C++ and the makefile for the 16-bit DLL is for Borland C++ (Inprise). Building extension modules for the AMX DLL ========================================== The AMX DLL can automatically register the native functions that reside inside "extension DLLs". The AMX DLL does this for libraries that are listed in the compiled Small program with the "#pragma library ..." instruction. The extension DLL must already be loaded in memory. The AMX DLL skips libraries that are not loaded. The extension DLL must furthermore have an exported function with the declaration: AMX_NATIVE_INFO FAR *amx_NativeList(void); which must return a pointer to the list of native functions in the extension DLL. This pointer must be in the format that amx_Register() expects (the list must be terminated with a NULL pointer). Refer to the Small manual for general information on native functions and (statically linked) extension modules.