diff --git a/src/conspage.c b/src/conspage.c index 541dc86..410bb68 100644 --- a/src/conspage.c +++ b/src/conspage.c @@ -27,7 +27,13 @@ bool conspageinitihasbeencalled = false; /** - * The (global) pointer to the (global) freelist. Not sure whether this ultimately belongs in this file. + * the number of cons pages which have thus far been initialised. + */ +int initialisedconspages = 0; + +/** + * The (global) pointer to the (global) freelist. Not sure whether this ultimately + * belongs in this file. */ struct cons_pointer freelist = NIL; @@ -36,11 +42,6 @@ struct cons_pointer freelist = NIL; */ struct cons_page* conspages[NCONSPAGES]; -/** - * the number of cons pages which have thus far been initialised. - */ -int initialisedconspages = 0; - /** * Make a cons page whose serial number (i.e. index in the conspages directory) is pageno. @@ -55,21 +56,21 @@ void makeconspage() { if ( initialisedconspages == 0 && i < 2) { if ( i == 0) { /* initialise cell as NIL */ - strncpy( result->cell[i].tag, NILTAG, 4); - result->cell[i].count = (2 ^ 32) - 1; // should be max value of unsigned 32 bit integer + strncpy( result->cell[i].tag, NILTAG, TAGLENGTH); + result->cell[i].count = MAXREFERENCE; result->cell[i].payload.free.car = NIL; result->cell[i].payload.free.cdr = NIL; } else if ( i == 1) { /* initialise cell as T */ - strncpy( result->cell[i].tag, TRUETAG, 4); - result->cell[i].count = (2 ^ 32) - 1; // should be max value of unsigned 32 bit integer + strncpy( result->cell[i].tag, TRUETAG, TAGLENGTH); + result->cell[i].count = MAXREFERENCE; result->cell[i].payload.free.car = (struct cons_pointer){ 0, 1}; result->cell[i].payload.free.cdr = (struct cons_pointer){ 0, 1}; } } /* otherwise, standard initialisation */ - strncpy( result->cell[i].tag, FREETAG, 4); + strncpy( result->cell[i].tag, FREETAG, TAGLENGTH); result->cell[i].payload.free.car = NIL; result->cell[i].payload.free.cdr = freelist; freelist.page = initialisedconspages; @@ -85,6 +86,20 @@ void makeconspage() { } +/** + * dump the allocated pages to this output stream. + */ +void dumppages( FILE* output) { + for ( int i = 0; i < initialisedconspages; i++) { + fprintf( output, "\nDUMPING PAGE %d\n", i); + + for ( int j = 0; j < CONSPAGESIZE; j++) { + dump_object( output, (struct cons_pointer){i, j}); + } + } +} + + /** * Frees the cell at the specified pointer. Dangerous, primitive, low * level. @@ -129,10 +144,17 @@ struct cons_pointer allocatecell( char* tag) { freelist = cell.payload.free.cdr; + fprintf( stderr, "Before: %c\n", cell.tag[0]); strncpy( cell.tag, tag, 4); + fprintf( stderr, "After: %c\n", cell.tag[0]); + cell.count = 1; cell.payload.cons.car = NIL; cell.payload.cons.cdr = NIL; + + fprintf( stderr, "Allocated cell of type '%s' at %d, %d \n", + tag, result.page, result.offset); + dump_object( stderr, result); } return result; diff --git a/src/conspage.h b/src/conspage.h index 4a60900..2d461ba 100644 --- a/src/conspage.h +++ b/src/conspage.h @@ -9,14 +9,14 @@ * the size which, by version 1, it will default to) is the maximum value of an unsigned 32 * bit integer, which is to say 4294967296. However, we'll start small. */ -#define CONSPAGESIZE 256 +#define CONSPAGESIZE 64 /** * the number of cons pages we will initially allow for. For convenience we'll set up an array * of cons pages this big; however, later we will want a mechanism for this to be able to grow * dynamically to the maximum we can currently allow, which is 4294967296. */ -#define NCONSPAGES 256 +#define NCONSPAGES 64 /** * a cons page is essentially just an array of cons space objects. It might later have a local @@ -28,9 +28,45 @@ struct cons_page { }; +/** + * The (global) pointer to the (global) freelist. Not sure whether this ultimately + * belongs in this file. + */ +extern struct cons_pointer freelist; + +/** + * An array of pointers to cons pages. + */ +extern struct cons_page* conspages[NCONSPAGES]; + + +/** + * Frees the cell at the specified pointer. Dangerous, primitive, low + * level. + * + * @pointer the cell to free + */ +void free_cell(struct cons_pointer pointer); + + +/** + * Allocates a cell with the specified tag. Dangerous, primitive, low + * level. + * + * @param tag the tag of the cell to allocate - must be a valid cons space tag. + * @return the cons pointer which refers to the cell allocated. + */ +struct cons_pointer allocatecell( char* tag); + + /** * initialise the cons page system; to be called exactly once during startup. */ void conspagesinit(); +/** + * dump the allocated pages to this output stream. + */ +void dumppages( FILE* output); + #endif diff --git a/src/consspaceobject.c b/src/consspaceobject.c index 8c5e433..e28059e 100644 --- a/src/consspaceobject.c +++ b/src/consspaceobject.c @@ -8,7 +8,76 @@ * Licensed under GPL version 2.0, or, at your option, any later version. */ - #include +#include +#include +#include "conspage.h" #include "consspaceobject.h" + + +/** + * increment the reference count of the object at this cons pointer. + * + * You can't roll over the reference count. Once it hits the maximum + * value you cannot increment further. + */ +void incref( struct cons_pointer pointer) { + struct cons_space_object cell = pointer2cell( pointer); + + if (cell.count < MAXREFERENCE) { + cell.count ++; + } +} + + +/** + * Decrement the reference count of the object at this cons pointer. + * + * If a count has reached MAXREFERENCE it cannot be decremented. + * If a count is decremented to zero the cell should be freed. + */ +void decref( struct cons_pointer pointer) { + struct cons_space_object cell = pointer2cell( pointer); + + if (cell.count < MAXREFERENCE) { + cell.count --; + + if (cell.count == 0) { + free_cell( pointer); + } + } +} + + +/** + * dump the object at this cons_pointer to this output stream. + */ +void dump_object( FILE* output, struct cons_pointer pointer) { + struct cons_space_object cell = conspages[pointer.page]->cell[pointer.offset]; + char * tag = malloc( TAGLENGTH + 1); + memset( tag, 0, TAGLENGTH + 1); + strncpy( tag, cell.tag, TAGLENGTH); + + fprintf( output, "\tDumping object at page %d, offset %d with tag %s, count %d\n", + pointer.page, + pointer.offset, + tag, + cell.count); + + if ( strncmp( tag, CONSTAG, TAGLENGTH) == 0) { + fprintf( output, "\tCons cell: car at page %d offset %d, cdr at page %d offset %d\n", + cell.payload.cons.car.page, cell.payload.cons.car.offset, cell.payload.cons.cdr.page, cell.payload.cons.cdr.offset); + } else if ( strncmp( tag, INTEGERTAG, TAGLENGTH) == 0) { + fprintf( output, "\t\tInteger cell: value %ld\n", cell.payload.integer.value); + } else if ( strncmp( tag, FREETAG, TAGLENGTH) == 0) { + fprintf( output, "\t\tFree cell: next at page %d offset %d\n", + cell.payload.cons.cdr.page, cell.payload.cons.cdr.offset); + } else if ( strncmp( tag, REALTAG, TAGLENGTH) == 0) { + fprintf( output, "\t\tReal cell: value %Lf\n", cell.payload.real.value); + } else if ( strncmp( tag, STRINGTAG, TAGLENGTH) == 0) { + fprintf( output, "\t\tString cell: character '%c' next at page %d offset %d\n", + cell.payload.string.character, cell.payload.string.cdr.page, + cell.payload.string.cdr.offset); + }; +} diff --git a/src/consspaceobject.h b/src/consspaceobject.h index 266c61e..96e10e5 100644 --- a/src/consspaceobject.h +++ b/src/consspaceobject.h @@ -8,8 +8,8 @@ * Licensed under GPL version 2.0, or, at your option, any later version. */ - #include +#include #ifndef __consspaceobject_h #define __consspaceobject_h @@ -38,11 +38,33 @@ */ #define NIL (struct cons_pointer){ 0, 0} +/** + * the maximum possible value of a reference count + */ +#define MAXREFERENCE ((2 ^ 32) - 1) + /** * a macro to convert a tag into a number */ #define tag2uint(tag) ((uint32_t)*tag) +#define pointer2cell(pointer) ((conspages[pointer.page]->cell[pointer.offset])) + + +/** + * true if conspointer points to the special cell NIL, else false + */ +#define nilp(conspoint) (strncmp(pointer2cell(conspoint).tag, NILTAG, TAGLENGTH)==0) + +/** + * true if conspointer points to a cons cell, else false + */ +#define consp(conspoint) (strncmp(pointer2cell(conspoint).tag, CONSTAG, TAGLENGTH)==0) + +/** + * true if conspointer points to a string cell, else false + */ +#define stringp(conspoint) (strncmp(pointer2cell(conspoint).tag, STRINGTAG, TAGLENGTH)==0) /** * An indirect pointer to a cons cell @@ -76,7 +98,7 @@ struct free_payload { * optional bignum object. */ struct integer_payload { - long int integer; + long int value; }; @@ -85,7 +107,7 @@ struct integer_payload { * precision, but I'm not sure of the detail. */ struct real_payload { - long double real; + long double value; }; /** @@ -123,4 +145,21 @@ struct cons_space_object { }; +/** + * increment the reference count of the object at this cons pointer + */ +void incref( struct cons_pointer pointer); + + +/** + * decrement the reference count of the object at this cons pointer + */ +void decref( struct cons_pointer pointer); + + +/** + * dump the object at this cons_pointer to this output stream. + */ +void dump_object( FILE* output, struct cons_pointer pointer); + #endif diff --git a/src/init.c b/src/init.c index 61eaefb..0add6da 100644 --- a/src/init.c +++ b/src/init.c @@ -14,11 +14,21 @@ #include "version.h" #include "conspage.h" #include "consspaceobject.h" +#include "print.h" +#include "read.h" int main (int argc, char *argv[]) { printf( "Post scarcity software environment version %s\n", VERSION); conspagesinit(); + printf( "Ready\n>>"); + + struct cons_pointer input = read( stdin); + incref( input); + printf( "\n"); + print( stdout, input); + + dumppages(stdout); // printf( "Tag2uint(\"FREE\") = %d\n", tag2uint("FREE")); return(0); diff --git a/src/integer.c b/src/integer.c new file mode 100644 index 0000000..9ab1951 --- /dev/null +++ b/src/integer.c @@ -0,0 +1,24 @@ +/** + * integer.c + * + * functions for integer cells. + * + * (c) 2017 Simon Brooke + * Licensed under GPL version 2.0, or, at your option, any later version. + */ + +#include "conspage.h" +#include "consspaceobject.h" +#include "read.h" + +/** + * Allocate an integer cell representing this value and return a cons pointer to it. + */ +struct cons_pointer makeinteger( int value) { + struct cons_pointer result = allocatecell( INTEGERTAG); + struct cons_space_object cell = conspages[result.page]->cell[result.offset]; + cell.payload.integer.value = value; + + return result; +} + diff --git a/src/integer.h b/src/integer.h new file mode 100644 index 0000000..ed3d799 --- /dev/null +++ b/src/integer.h @@ -0,0 +1,19 @@ +/** + * integer.h + * + * functions for integer cells. + * + * + * (c) 2017 Simon Brooke + * Licensed under GPL version 2.0, or, at your option, any later version. + */ + +#ifndef __integer_h +#define __integer_h + +/** + * Allocate an integer cell representing this value and return a cons pointer to it. + */ +struct cons_pointer makeinteger( int value); + +#endif diff --git a/src/print.c b/src/print.c new file mode 100644 index 0000000..446f936 --- /dev/null +++ b/src/print.c @@ -0,0 +1,47 @@ +/** + * print.c + * + * First pass at a printer, for bootstrapping. + * + * + * (c) 2017 Simon Brooke + * Licensed under GPL version 2.0, or, at your option, any later version. + */ + +#include +#include +#include + +#include "conspage.h" +#include "consspaceobject.h" +#include "integer.h" +#include "print.h" + +void print( FILE* output, struct cons_pointer pointer) { + struct cons_space_object cell = pointer2cell( pointer); + + if ( strncmp( cell.tag, CONSTAG, TAGLENGTH) == 0) { + fputc( '(', output); + for (struct cons_pointer p = pointer; consp( p); + p = pointer2cell( p).payload.cons.cdr) { + print( output, p); + fputc( ' ', output); + } + fputc( ')', output); + } else if ( strncmp( cell.tag, INTEGERTAG, TAGLENGTH) == 0) { + fprintf( output, " %ld", cell.payload.integer.value); + } else if ( strncmp( cell.tag, NILTAG, TAGLENGTH) == 0) { + fprintf( output, "NIL"); + } else if ( strncmp( cell.tag, REALTAG, TAGLENGTH) == 0) { + fprintf( output, "%Lf", cell.payload.real.value); + } else if ( strncmp( cell.tag, STRINGTAG, TAGLENGTH) == 0) { + fputc( '"', output); + for (struct cons_pointer p = pointer; stringp( p); + p = pointer2cell( p).payload.string.cdr) { + fprintf( output, '%c', (char)pointer2cell( p).payload.string.character); + } + fputc( '"', output); + } else if ( strncmp( cell.tag, TRUETAG, TAGLENGTH) == 0) { + fprintf( output, "T"); + } +} diff --git a/src/print.h b/src/print.h new file mode 100644 index 0000000..4ee1e5b --- /dev/null +++ b/src/print.h @@ -0,0 +1,19 @@ +/** + * print.h + * + * First pass at a printer, for bootstrapping. + * + * + * (c) 2017 Simon Brooke + * Licensed under GPL version 2.0, or, at your option, any later version. + */ + +#include +#include + +#ifndef __print_h +#define __print_h + +void print( FILE* output, struct cons_pointer pointer); + +#endif diff --git a/src/quickbool.h b/src/quickbool.h deleted file mode 100644 index ab3ee10..0000000 --- a/src/quickbool.h +++ /dev/null @@ -1,19 +0,0 @@ -/** - * quickbool.h - * - * Currently, just a macro to test whether a cons_pointer is the - * special NIL cons_pointer. - * - * (c) 2017 Simon Brooke - * Licensed under GPL version 2.0, or, at your option, any later version. - */ - -#include "consspaceobject.h" - -#ifndef __quickbool_h -#define __quickbool_h - -/* true if conspointer points to the special cell NIL, else false */ -#define nilp(conspoint) ((((struct cons_pointer)conspoint).page == NIL.page) && ((struct conspoint).offser == NIL.offset)) - -#endif diff --git a/src/read.c b/src/read.c new file mode 100644 index 0000000..0ccd35e --- /dev/null +++ b/src/read.c @@ -0,0 +1,92 @@ +/** + * read.c + * + * First pass at a reader, for bootstrapping. + * + * + * (c) 2017 Simon Brooke + * Licensed under GPL version 2.0, or, at your option, any later version. + */ + +#include +#include + +#include "consspaceobject.h" +#include "integer.h" +#include "read.h" + +/* for the time being things which may be read are: + strings + numbers - either integer or real, but not yet including ratios or bignums + lists + Can't read atoms because I don't yet know what an atom is or how it's stored. */ + +/** + * read a number from this input stream, given this initial character. + */ +struct cons_pointer readnumber( FILE* input, char initial) { + int accumulator = 0; + char c; + + for (c = initial; isdigit( c); c = fgetc( input)) { + int digitvalue = (int)c - (int)'0'; + accumulator = accumulator * 10 + digitvalue; + } + + /* push back the character read which was not a digit */ + fputc( c, input); + + return makeinteger( accumulator); +} + + +struct cons_pointer readlist( FILE* input) { + return NIL; +} + + +struct cons_pointer readstring( FILE* input) { + return NIL; +} + + +/** + * read the next object on this input stream and return a cons_pointer to it. + */ +struct cons_pointer read( FILE* input) { + struct cons_pointer result = NIL; + + char c = fgetc( input); + + while ( isblank( c)) { + c = fgetc( input); + } + + switch( c) { + case '(' : result = readlist(input); + break; + case '"': result = readstring(input); + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + // case '.': + result = readnumber( input, c); + break; + default: + fprintf( stderr, "Unrecognised start of input character %c\n", c); + } + + return result; +} + + + + diff --git a/src/read.h b/src/read.h new file mode 100644 index 0000000..00e74c8 --- /dev/null +++ b/src/read.h @@ -0,0 +1,19 @@ +/** + * read.c + * + * First pass at a reader, for bootstrapping. + * + * + * (c) 2017 Simon Brooke + * Licensed under GPL version 2.0, or, at your option, any later version. + */ + +#ifndef __read_h +#define __read_h + +/** + * read the next object on this input stream and return a cons_pointer to it. + */ +struct cons_pointer read( FILE* input); + +#endif