CPebble
	CPebble is an experiment at a modern and de-cluttered re-write of
    	Pebble in C. At some point this will be re-named to Pebble once
    	it is deemed stable enough to replace the current Zig version.
	The older Zig version can be viewed at ../../old/ relative to
	this current path.
	Please note this does not fully implement pebble schematics
	yet and is a work-in-progress, unlike the Zig version, which
	is feature-complete.
    	As the Zig version, the license can be viewed at
	http://thenuoviorizzonticompany.org/license/openlicense/3.txt

Building from source
	Building from source only requires a small subset of a C99 hosted Libc
	and a standard C99 compiler. CPebble uses it's own build system, which
	has the same requirements. The interface to this build system is simular
	to Make. The build system accepts arguments

	target - target operating system to build for - view the platform support
		list to know what to place here. The default is 'c', which uses
		pure C99 + Libc.

	graphics - graphics library to use. The default is none.

	build - the type of build to use - these include fast, debug, and
		default. The default is 'default'. Please note fast builds
		are not guaranteed to work on any machine besides the host
		compiling.

	analyzer - the name of the static analyzer to use when building.
		No default, not required.

	cc - the selected C compiler to use - defaults to 'cc'.

	program - the path to place the finished binary - defaults to
		'./bin/vm'.

	cflags - the C compiler flags to use before adding the build-specific
		compiler flags. The default is '-std=c99'.

	
	To build from source, simply run

		$ cc -o build build.c # build the building tool
		$ ./build # build the VM
		$ ./bin/vm tools/test.pebble # test suite one
		$ ./bin/vm tools/test-new.pebble # test suite two

Supported Platforms
	All supported platforms include:

		freestand 	-> freestanding
					The common denominator

		c 		-> pure C99 & Libc + platform freestand
					Differences between freestand:
					  - Adds extra libraries for core VM 
					    functionality which use a C99 Libc

		posix		-> POSIX.1-2008-compliant system + platform c
					Differences between c:
					  - Adds kernel-backed random number generation
					    using rand(3) instead of the software
					    C algorithm using nondeterministic hardware
					    behavior and address randomization

		openbsd 	-> OpenBSD kernel and Libc + platform posix
					Differences between posix:
					  - Adds OpenBSD pledge(2) and unveil(2) system
					    calls to initialization code
					  - Uses OpenBSD arc4random(3) instead of the
					    posix platform's rand(3)

		puredarwin	-> Darwin/PureDarwin kernel and Libc + platform posix
					Differences between posix:
					  - Adds PureDarwin-specific Libc shims

	Depreciated platforms include:

		puredarwin
			Random number generation is currently not provided.

	For a list of tested environments, please visit 
		- http://pebblevm.org/platforms.html	

FFI Code
	Code targetting the CPebble FFI is different from code targetting the FFI
	used in the older versions of Zig Pebble. FFI code is called as

		void escape_name(FFIvars *vars, unsigned long long random_seed, 
			FFIArena *scratchAlloc, FFIArena *tempAlloc, 
			FFIArena *persistAlloc);

	FFIvars is a type used to hold a representation of the VM internal variable
	table suitable for the FFI interface. The layout does not need to be known by
	the FFI code. 

	Two functions may act on this, being
		void FFIallocateVariable(FFIvars *variables, const char *variable_name, 
			void *pointer_to_value, FFIArena *persistAlloc);

	and
		void *FFIreadVariable(FFIvars *variables, const char *varname);

	with FFIallocateVariable used to store a variable and FFIreadVariable to
	read one to/from the internal VM variable table.

	It is important to note FFIreadVariable will exit on an error condition. If you
	do not want this, use FFIreadvariableUnsafe, which is the same, except it will
	return a NULL pointer if the variable does not exist. 

	random_seed is a random seed specific to this FFI name. The seed is generated
	once at VM startup and a seed to be given to the FFI code is generated at
	calling. This new seed is a derivitave of the main VM seed and the last 8 (or
	closest to it) characters of the FFI function's name. The seed is unique to each
	VM startup and FFI call. This means if I run the same FFI call twice in the
	same VM lifetime, I will get the same seed. This seed is not cryptographically
	secure.

	FFI sequence names should follow the convention of 'escape_(class(es)_(name))',
	where classes is the one or more subgroups the FFI call is in, and name is 
	the name of the FFI call. Eg. for std.io.print, it would be escape_std_io_print.
	std.io.print is the name that Pebble code calls, while escape_std_io_print is
	the defined name internally.

	The three allocators, tempAlloc, scratchAlloc, and persistAlloc, are each
	arena allocator pointers who map to the internal VM allocators. temp may
	be cleared at instruction boundaries (an FFI call is an instruction), 
	scratch may be cleared in-between functions, and persist will never be
	cleared until a VM exit. These can be managed using the function

		void *FFIallocateMemory(FFIArena *arena, unsigned long long size);

	which returns a pointer to a buffer allocated on allocator arena of size size.

	The FFI also provides a simple structure for interfacing with CPebble internal
	types. This structure can be laid out as

		typedef struct {
			ValueTypes Type;
			union {
				unsigned long word;
				long sword;
				double flt;
				char *str;
				ExprNode *expr;
			}as;
		} FFIValue;

	This is the structure that is used when storing Pebble values and what is
	returned when reading them. The first entry, Type, defines which type the
	second, as is. The Type entries map 1:1 to the as entries. Eg. if I wanted
	to store a numerical value that is negative as a Pebble variable, I need to
	first format it as this. This could be done as, say

		FFIValue f = (FFIValue){ .Type = type_sword, .as.sword = -3 };

	Other functions which may be useful are present, such as

		void FFIstdoutPrint(char *msg); /* print to standard output */
		void FFIexit(int status); /* exit the VM */
		FFIValue FFIconvertValueToWord(FFIValue v, FFIvars *vars, 
			FFIArena *persistAlloc); /* convert an FFI type into an FFI
						  * type word */
		int FFIconvertValueToString(char *buffer, unsigned long size, FFIValue v);
						 /* convert an FFI value into a string
						  * and write it into buffer of size size
						  * - returns nonzero on error */

	Please note a standard C library cannot be assumed for FFI code. Please use
	the functions provided in the h/ folder of the source directory.


Please make sure all code follows the standards defined by the .clang-format file before
attempting to push a commit.


Product of The Nuovi Orizzonti Company
http://thenuoviorizzonticompany.org
http://pebblevm.org
