From 85cc542d74879af14ef96ea347975242f162cf7c Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Sat, 7 Jan 2017 02:17:54 +0000 Subject: [PATCH] Reads, stores and prints numbers correctly. Reads and stores lists and strings, but they don't print correctly. --- src/conspage.c | 111 ++++++++++++++++++++++----------------- src/conspage.h | 10 ++-- src/consspaceobject.c | 119 ++++++++++++++++++++++++++++++------------ src/consspaceobject.h | 34 +++++++++--- src/init.c | 10 ++-- src/integer.c | 8 +-- src/integer.h | 2 +- src/print.c | 15 +++--- src/read.c | 42 ++++++++++----- 9 files changed, 226 insertions(+), 125 deletions(-) diff --git a/src/conspage.c b/src/conspage.c index 410bb68..77187b9 100644 --- a/src/conspage.c +++ b/src/conspage.c @@ -29,7 +29,7 @@ bool conspageinitihasbeencalled = false; /** * the number of cons pages which have thus far been initialised. */ -int initialisedconspages = 0; +int initialised_cons_pages = 0; /** * The (global) pointer to the (global) freelist. Not sure whether this ultimately @@ -48,49 +48,54 @@ struct cons_page* conspages[NCONSPAGES]; * Initialise all cells and prepend each to the freelist; if pageno is zero, do not prepend * cells 0 and 1 to the freelist but initialise them as NIL and T respectively. */ -void makeconspage() { +void make_cons_page() { struct cons_page* result = malloc( sizeof( struct cons_page)); if ( result != NULL) { + conspages[initialised_cons_pages] = result; + for (int i = 0; i < CONSPAGESIZE; i++) { - if ( initialisedconspages == 0 && i < 2) { + struct cons_space_object * cell = &conspages[initialised_cons_pages]->cell[i]; + if ( initialised_cons_pages == 0 && i < 2) { if ( i == 0) { /* initialise cell as NIL */ - 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; + strncpy( &cell->tag.bytes[0], NILTAG, TAGLENGTH); + cell->count = MAXREFERENCE; + cell->payload.free.car = NIL; + cell->payload.free.cdr = NIL; + fprintf( stderr, "Allocated special cell NIL\n"); } else if ( i == 1) { /* initialise cell as T */ - 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}; + strncpy( &cell->tag.bytes[0], TRUETAG, TAGLENGTH); + cell->count = MAXREFERENCE; + cell->payload.free.car = (struct cons_pointer){ 0, 1}; + cell->payload.free.cdr = (struct cons_pointer){ 0, 1}; + fprintf( stderr, "Allocated special cell T\n"); } + } else { + /* otherwise, standard initialisation */ + strncpy( &cell->tag.bytes[0], FREETAG, TAGLENGTH); + cell->payload.free.car = NIL; + cell->payload.free.cdr = freelist; + freelist.page = initialised_cons_pages; + freelist.offset = i; } - - /* otherwise, standard initialisation */ - strncpy( result->cell[i].tag, FREETAG, TAGLENGTH); - result->cell[i].payload.free.car = NIL; - result->cell[i].payload.free.cdr = freelist; - freelist.page = initialisedconspages; - freelist.offset = i; } + + initialised_cons_pages ++; } else { - fprintf( stderr, "FATAL: Failed to allocate memory for cons page %d\n", initialisedconspages); + fprintf( stderr, "FATAL: Failed to allocate memory for cons page %d\n", initialised_cons_pages); exit(1); } - conspages[initialisedconspages] = result; - initialisedconspages++; } /** * dump the allocated pages to this output stream. */ -void dumppages( FILE* output) { - for ( int i = 0; i < initialisedconspages; i++) { +void dump_pages( FILE* output) { + for ( int i = 0; i < initialised_cons_pages; i++) { fprintf( output, "\nDUMPING PAGE %d\n", i); for ( int j = 0; j < CONSPAGESIZE; j++) { @@ -107,20 +112,22 @@ void dumppages( FILE* output) { * @pointer the cell to free */ void free_cell(struct cons_pointer pointer) { - struct cons_space_object cell = conspages[pointer.page]->cell[pointer.offset]; + struct cons_space_object* cell = &pointer2cell( pointer); - if ( strncmp( cell.tag, FREETAG, 4) != 0) { - if ( cell.count == 0) { - strncpy( cell.tag, FREETAG, 4); - cell.payload.free.car = NIL; - cell.payload.free.cdr = freelist; + if ( !check_tag(pointer, FREETAG)) { + if ( cell->count == 0) { + strncpy( &cell->tag.bytes[0], FREETAG, 4); + cell->payload.free.car = NIL; + cell->payload.free.cdr = freelist; freelist = pointer; } else { - fprintf( stderr, "Attempt to free cell with %d dangling references at page %d, offset %d\n", - cell.count, pointer.page, pointer.offset); + fprintf( stderr, + "Attempt to free cell with %d dangling references at page %d, offset %d\n", + cell->count, pointer.page, pointer.offset); } } else { - fprintf( stderr, "Attempt to free cell which is already FREE at page %d, offset %d\n", + fprintf( stderr, + "Attempt to free cell which is already FREE at page %d, offset %d\n", pointer.page, pointer.offset); } } @@ -133,28 +140,36 @@ void free_cell(struct cons_pointer pointer) { * @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) { +struct cons_pointer allocate_cell( char* tag) { struct cons_pointer result = freelist; if ( result.page == NIL.page && result.offset == NIL.offset) { - makeconspage(); - result = allocatecell( tag); + make_cons_page(); + result = allocate_cell( tag); } else { - struct cons_space_object cell = conspages[result.page]->cell[result.offset]; + struct cons_space_object* cell = &pointer2cell(result); - freelist = cell.payload.free.cdr; + if ( strncmp( &cell->tag.bytes[0], FREETAG, TAGLENGTH) == 0) { + 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]); + fprintf( stderr, "Before: %c%c%c%c (%d)\n", + cell->tag.bytes[0], cell->tag.bytes[1], cell->tag.bytes[2], + cell->tag.bytes[3], cell->tag.value); + strncpy( &cell->tag.bytes[0], tag, 4); + fprintf( stderr, "After: %c%c%c%c (%d)\n", + cell->tag.bytes[0], cell->tag.bytes[1], cell->tag.bytes[2], + cell->tag.bytes[3], cell->tag.value); - cell.count = 1; - cell.payload.cons.car = NIL; - cell.payload.cons.cdr = NIL; + cell->count = 0; + 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); + fprintf( stderr, "Allocated cell of type '%s' at %d, %d \n", + tag, result.page, result.offset); + dump_object( stderr, result); + } else { + fprintf( stderr, "WARNING: Allocating non-free cell!"); + } } return result; @@ -164,13 +179,13 @@ struct cons_pointer allocatecell( char* tag) { /** * initialise the cons page system; to be called exactly once during startup. */ -void conspagesinit() { +void initialise_cons_pages() { if ( conspageinitihasbeencalled == false) { for (int i = 0; i < NCONSPAGES; i++) { conspages[i] = (struct cons_page *) NULL; } - makeconspage(); + make_cons_page(); conspageinitihasbeencalled = true; } else { fprintf( stderr, "WARNING: conspageinit() called a second or subsequent time\n"); diff --git a/src/conspage.h b/src/conspage.h index 2d461ba..db7b13e 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 64 +#define CONSPAGESIZE 8 /** * 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 64 +#define NCONSPAGES 8 /** * a cons page is essentially just an array of cons space objects. It might later have a local @@ -56,17 +56,17 @@ void free_cell(struct cons_pointer pointer); * @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); +struct cons_pointer allocate_cell( char* tag); /** * initialise the cons page system; to be called exactly once during startup. */ -void conspagesinit(); +void initialise_cons_pages(); /** * dump the allocated pages to this output stream. */ -void dumppages( FILE* output); +void dump_pages( FILE* output); #endif diff --git a/src/consspaceobject.c b/src/consspaceobject.c index e28059e..a390cdb 100644 --- a/src/consspaceobject.c +++ b/src/consspaceobject.c @@ -15,6 +15,14 @@ #include "conspage.h" #include "consspaceobject.h" +/** + * Check that the tag on the cell at this pointer is this tag + */ +int check_tag( struct cons_pointer pointer, char* tag) { + struct cons_space_object cell = pointer2cell(pointer); + return strncmp( &cell.tag.bytes[0], tag, TAGLENGTH) == 0; +} + /** * increment the reference count of the object at this cons pointer. @@ -22,11 +30,11 @@ * 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); +void inc_ref( struct cons_pointer pointer) { + struct cons_space_object* cell = &pointer2cell( pointer); - if (cell.count < MAXREFERENCE) { - cell.count ++; + if (cell->count < MAXREFERENCE) { + cell->count ++; } } @@ -37,13 +45,13 @@ void incref( struct cons_pointer 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); +void dec_ref( struct cons_pointer pointer) { + struct cons_space_object* cell = &pointer2cell( pointer); - if (cell.count < MAXREFERENCE) { - cell.count --; + if (cell->count <= MAXREFERENCE) { + cell->count --; - if (cell.count == 0) { + if (cell->count == 0) { free_cell( pointer); } } @@ -54,30 +62,73 @@ 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) { - 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); + struct cons_space_object cell = pointer2cell(pointer); + fprintf( output, + "\tDumping object at page %d, offset %d with tag %c%c%c%c (%d), count %u\n", + pointer.page, + pointer.offset, + cell.tag.bytes[0], + cell.tag.bytes[1], + cell.tag.bytes[2], + cell.tag.bytes[3], + cell.tag.value, + cell.count); - 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); - }; + if ( check_tag(pointer, CONSTAG)) { + 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 ( check_tag(pointer, INTEGERTAG)) { + fprintf( output, "\t\tInteger cell: value %ld\n", cell.payload.integer.value); + } else if ( check_tag( pointer, FREETAG)) { + fprintf( output, "\t\tFree cell: next at page %d offset %d\n", + cell.payload.cons.cdr.page, cell.payload.cons.cdr.offset); + } else if ( check_tag(pointer, REALTAG)) { + fprintf( output, "\t\tReal cell: value %Lf\n", cell.payload.real.value); + } else if ( check_tag( pointer, STRINGTAG)) { + 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); + }; +} + + +/** + * Construct a cons cell from this pair of pointers. + */ +struct cons_pointer make_cons( struct cons_pointer car, struct cons_pointer cdr) { + struct cons_pointer pointer = allocate_cell( CONSTAG); + + struct cons_space_object* cell = &conspages[pointer.page]->cell[pointer.offset]; + + inc_ref(car); + inc_ref(cdr); + cell->payload.cons.car = car; + cell->payload.cons.cdr = cdr; + + return pointer; +} + +/** + * Construct a string from this character (which later will be UTF) and + * this tail. A string is implemented as a flat list of cells each of which + * has one character and a pointer to the next; in the last cell the + * pointer to next is NIL. + */ +struct cons_pointer make_string( char c, struct cons_pointer tail) { + struct cons_pointer pointer = NIL; + + if ( check_tag( tail, STRINGTAG) || check_tag( tail, NILTAG)) { + pointer = allocate_cell( STRINGTAG); + struct cons_space_object* cell = &conspages[pointer.page]->cell[pointer.offset]; + + inc_ref(tail); + cell->payload.string.character = (uint32_t) c; + cell->payload.string.cdr = tail; + } else { + fprintf( stderr, "Warning: only NIL and STRING can be appended to STRING\n"); + } + + return pointer; } diff --git a/src/consspaceobject.h b/src/consspaceobject.h index 96e10e5..fdce9a4 100644 --- a/src/consspaceobject.h +++ b/src/consspaceobject.h @@ -41,7 +41,7 @@ /** * the maximum possible value of a reference count */ -#define MAXREFERENCE ((2 ^ 32) - 1) +#define MAXREFERENCE 4294967295 /** * a macro to convert a tag into a number @@ -50,21 +50,20 @@ #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) +#define nilp(conspoint) (check_tag(conspoint,NILTAG)==0) /** * true if conspointer points to a cons cell, else false */ -#define consp(conspoint) (strncmp(pointer2cell(conspoint).tag, CONSTAG, TAGLENGTH)==0) +#define consp(conspoint) (check_tag(conspoint,CONSTAG)==0) /** * true if conspointer points to a string cell, else false */ -#define stringp(conspoint) (strncmp(pointer2cell(conspoint).tag, STRINGTAG, TAGLENGTH)==0) +#define stringp(conspoint) (check_tag(conspoint,STRINGTAG)==0) /** * An indirect pointer to a cons cell @@ -123,7 +122,10 @@ struct string_payload { * an object in cons space. */ struct cons_space_object { - char tag[TAGLENGTH]; /* the tag (type) of this cell */ + union { + char bytes[TAGLENGTH]; /* the tag (type) of this cell, considered as bytes */ + uint32_t value; /* the tag considered as a number */ + } tag; uint32_t count; /* the count of the number of references to this cell */ struct cons_pointer access; /* cons pointer to the access control list of this cell */ union { @@ -145,16 +147,22 @@ struct cons_space_object { }; +/** + * Check that the tag on the cell at this pointer is this tag + */ +int check_tag( struct cons_pointer pointer, char* tag); + + /** * increment the reference count of the object at this cons pointer */ -void incref( struct cons_pointer pointer); +void inc_ref( struct cons_pointer pointer); /** * decrement the reference count of the object at this cons pointer */ -void decref( struct cons_pointer pointer); +void dec_ref( struct cons_pointer pointer); /** @@ -162,4 +170,14 @@ void decref( struct cons_pointer pointer); */ void dump_object( FILE* output, struct cons_pointer pointer); +struct cons_pointer make_cons( struct cons_pointer car, struct cons_pointer cdr); + +/** + * Construct a string from this character (which later will be UTF) and + * this tail. A string is implemented as a flat list of cells each of which + * has one character and a pointer to the next; in the last cell the + * pointer to next is NIL. + */ +struct cons_pointer make_string( char c, struct cons_pointer tail); + #endif diff --git a/src/init.c b/src/init.c index 0add6da..f3d442d 100644 --- a/src/init.c +++ b/src/init.c @@ -19,16 +19,16 @@ int main (int argc, char *argv[]) { printf( "Post scarcity software environment version %s\n", VERSION); - conspagesinit(); + initialise_cons_pages(); - printf( "Ready\n>>"); + printf( "Ready\n>> "); struct cons_pointer input = read( stdin); - incref( input); - printf( "\n"); + inc_ref( input); + printf( "\n:: "); print( stdout, input); - dumppages(stdout); + dump_pages(stdout); // printf( "Tag2uint(\"FREE\") = %d\n", tag2uint("FREE")); return(0); diff --git a/src/integer.c b/src/integer.c index 9ab1951..e9a5d43 100644 --- a/src/integer.c +++ b/src/integer.c @@ -14,10 +14,10 @@ /** * 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; +struct cons_pointer make_integer( int value) { + struct cons_pointer result = allocate_cell( 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 index ed3d799..83f4f57 100644 --- a/src/integer.h +++ b/src/integer.h @@ -14,6 +14,6 @@ /** * Allocate an integer cell representing this value and return a cons pointer to it. */ -struct cons_pointer makeinteger( int value); +struct cons_pointer make_integer( int value); #endif diff --git a/src/print.c b/src/print.c index 446f936..6e0452e 100644 --- a/src/print.c +++ b/src/print.c @@ -20,7 +20,7 @@ void print( FILE* output, struct cons_pointer pointer) { struct cons_space_object cell = pointer2cell( pointer); - if ( strncmp( cell.tag, CONSTAG, TAGLENGTH) == 0) { + if ( check_tag( pointer, CONSTAG)) { fputc( '(', output); for (struct cons_pointer p = pointer; consp( p); p = pointer2cell( p).payload.cons.cdr) { @@ -28,20 +28,21 @@ void print( FILE* output, struct cons_pointer pointer) { fputc( ' ', output); } fputc( ')', output); - } else if ( strncmp( cell.tag, INTEGERTAG, TAGLENGTH) == 0) { + } else if ( check_tag( pointer, INTEGERTAG)) { fprintf( output, " %ld", cell.payload.integer.value); - } else if ( strncmp( cell.tag, NILTAG, TAGLENGTH) == 0) { + } else if ( check_tag( pointer, NILTAG)) { fprintf( output, "NIL"); - } else if ( strncmp( cell.tag, REALTAG, TAGLENGTH) == 0) { + } else if ( check_tag( pointer, REALTAG)) { fprintf( output, "%Lf", cell.payload.real.value); - } else if ( strncmp( cell.tag, STRINGTAG, TAGLENGTH) == 0) { + } else if ( check_tag( pointer, STRINGTAG)) { 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); + // TODO: That's potentially a UTF character, needs more handling. + fprintf( output, "%c", (char)pointer2cell( p).payload.string.character); } fputc( '"', output); - } else if ( strncmp( cell.tag, TRUETAG, TAGLENGTH) == 0) { + } else if ( check_tag( pointer, TRUETAG)) { fprintf( output, "T"); } } diff --git a/src/read.c b/src/read.c index 0ccd35e..a5236f1 100644 --- a/src/read.c +++ b/src/read.c @@ -24,7 +24,7 @@ /** * read a number from this input stream, given this initial character. */ -struct cons_pointer readnumber( FILE* input, char initial) { +struct cons_pointer read_number( FILE* input, char initial) { int accumulator = 0; char c; @@ -36,17 +36,35 @@ struct cons_pointer readnumber( FILE* input, char initial) { /* push back the character read which was not a digit */ fputc( c, input); - return makeinteger( accumulator); + return make_integer( accumulator); } -struct cons_pointer readlist( FILE* input) { - return NIL; +struct cons_pointer read_list( FILE* input) { + struct cons_pointer car = read( input); + struct cons_pointer cdr = NIL; + + char c = fgetc( input); + + if ( c != ')' ) { + cdr = read_list( input); + } + + return make_cons( car, cdr); } -struct cons_pointer readstring( FILE* input) { - return NIL; +struct cons_pointer read_string( FILE* input) { + struct cons_pointer cdr = NIL; + struct cons_pointer result= NIL; + + char c = fgetc( input); + + if ( c != '"' ) { + result = make_string( c, read_string( input)); + } + + return result; } @@ -56,16 +74,14 @@ struct cons_pointer readstring( FILE* input) { struct cons_pointer read( FILE* input) { struct cons_pointer result = NIL; - char c = fgetc( input); + char c; - while ( isblank( c)) { - c = fgetc( input); - } + for (c = fgetc( input); isblank( c); c = fgetc( input)); switch( c) { - case '(' : result = readlist(input); + case '(' : result = read_list(input); break; - case '"': result = readstring(input); + case '"': result = read_string(input); break; case '0': case '1': @@ -78,7 +94,7 @@ struct cons_pointer read( FILE* input) { case '8': case '9': // case '.': - result = readnumber( input, c); + result = read_number( input, c); break; default: fprintf( stderr, "Unrecognised start of input character %c\n", c);