Printing of bignums basically done, not tested.
This commit is contained in:
parent
342f0308d3
commit
489f008044
|
@ -12,11 +12,28 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
/*
|
||||||
|
* wide characters
|
||||||
|
*/
|
||||||
|
#include <wchar.h>
|
||||||
|
#include <wctype.h>
|
||||||
|
|
||||||
#include "conspage.h"
|
#include "conspage.h"
|
||||||
#include "consspaceobject.h"
|
#include "consspaceobject.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hexadecimal digits for printing numbers.
|
||||||
|
*/
|
||||||
|
const wchar_t *hex_digits = L"0123456789ABCDEF";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Doctrine from here on in is that ALL integers are bignums, it's just
|
||||||
|
* that integers less than 65 bits are bignums of one cell only.
|
||||||
|
*
|
||||||
|
* TODO: I have no idea at all how I'm going to print bignums!
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* return the numeric value of this cell, as a C primitive double, not
|
* return the numeric value of this cell, as a C primitive double, not
|
||||||
* as a cons-space object. Cell may in principle be any kind of number.
|
* as a cons-space object. Cell may in principle be any kind of number.
|
||||||
|
@ -68,14 +85,17 @@ struct cons_pointer make_integer( int64_t value, struct cons_pointer more ) {
|
||||||
* Return the sum of the integers pointed to by `a` and `b`. If either isn't
|
* Return the sum of the integers pointed to by `a` and `b`. If either isn't
|
||||||
* an integer, will return nil.
|
* an integer, will return nil.
|
||||||
*/
|
*/
|
||||||
struct cons_pointer add_integers( struct cons_pointer a, struct cons_pointer b) {
|
struct cons_pointer add_integers( struct cons_pointer a,
|
||||||
|
struct cons_pointer b ) {
|
||||||
struct cons_pointer result = NIL;
|
struct cons_pointer result = NIL;
|
||||||
int64_t carry = 0;
|
int64_t carry = 0;
|
||||||
|
|
||||||
if ( integerp( a ) && integerp( b ) ) {
|
if ( integerp( a ) && integerp( b ) ) {
|
||||||
while ( !nilp( a ) || !nilp( b ) || carry != 0 ) {
|
while ( !nilp( a ) || !nilp( b ) || carry != 0 ) {
|
||||||
int64_t av = integerp(a) ? pointer2cell(a).payload.integer.value : 0;
|
int64_t av =
|
||||||
int64_t bv = integerp(b) ? pointer2cell(b).payload.integer.value : 0;
|
integerp( a ) ? pointer2cell( a ).payload.integer.value : 0;
|
||||||
|
int64_t bv =
|
||||||
|
integerp( b ) ? pointer2cell( b ).payload.integer.value : 0;
|
||||||
|
|
||||||
__int128_t rv = av + bv + carry;
|
__int128_t rv = av + bv + carry;
|
||||||
|
|
||||||
|
@ -99,14 +119,17 @@ struct cons_pointer add_integers( struct cons_pointer a, struct cons_pointer b)
|
||||||
* Return the product of the integers pointed to by `a` and `b`. If either isn't
|
* Return the product of the integers pointed to by `a` and `b`. If either isn't
|
||||||
* an integer, will return nil.
|
* an integer, will return nil.
|
||||||
*/
|
*/
|
||||||
struct cons_pointer multiply_integers( struct cons_pointer a, struct cons_pointer b) {
|
struct cons_pointer multiply_integers( struct cons_pointer a,
|
||||||
|
struct cons_pointer b ) {
|
||||||
struct cons_pointer result = NIL;
|
struct cons_pointer result = NIL;
|
||||||
int64_t carry = 0;
|
int64_t carry = 0;
|
||||||
|
|
||||||
if ( integerp( a ) && integerp( b ) ) {
|
if ( integerp( a ) && integerp( b ) ) {
|
||||||
while ( !nilp( a ) || !nilp( b ) || carry != 0 ) {
|
while ( !nilp( a ) || !nilp( b ) || carry != 0 ) {
|
||||||
int64_t av = integerp(a) ? pointer2cell(a).payload.integer.value : 1;
|
int64_t av =
|
||||||
int64_t bv = integerp(b) ? pointer2cell(b).payload.integer.value : 1;
|
integerp( a ) ? pointer2cell( a ).payload.integer.value : 1;
|
||||||
|
int64_t bv =
|
||||||
|
integerp( b ) ? pointer2cell( b ).payload.integer.value : 1;
|
||||||
|
|
||||||
__int128_t rv = ( av * bv ) + carry;
|
__int128_t rv = ( av * bv ) + carry;
|
||||||
|
|
||||||
|
@ -125,3 +148,46 @@ struct cons_pointer multiply_integers( struct cons_pointer a, struct cons_pointe
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The general principle of printing a bignum is that you print the least
|
||||||
|
* significant digit in whatever base you're dealing with, divide through
|
||||||
|
* by the base, print the next, and carry on until you've none left.
|
||||||
|
* Obviously, that means you print from right to left. Given that we build
|
||||||
|
* strings from right to left, 'printing' an integer to a lisp string
|
||||||
|
* would seem reasonably easy. The problem is when you jump from one integer
|
||||||
|
* object to the next. 64 bit integers don't align with decimal numbers, so
|
||||||
|
* when we get to the last digit from one integer cell, we have potentially
|
||||||
|
* to be looking to the next. H'mmmm.
|
||||||
|
*/
|
||||||
|
struct cons_pointer integer_to_string( struct cons_pointer int_pointer,
|
||||||
|
int base ) {
|
||||||
|
struct cons_pointer result = NIL;
|
||||||
|
struct cons_space_object integer = pointer2cell( int_pointer );
|
||||||
|
int64_t accumulator = integer.payload.integer.value;
|
||||||
|
bool is_negative = accumulator < 0;
|
||||||
|
accumulator = llabs( accumulator );
|
||||||
|
|
||||||
|
while ( accumulator > 0 ) {
|
||||||
|
while ( accumulator > base ) {
|
||||||
|
result = make_string( hex_digits[accumulator % base], result );
|
||||||
|
accumulator = accumulator / base;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( integerp( integer.payload.integer.more ) ) {
|
||||||
|
integer = pointer2cell( integer.payload.integer.more );
|
||||||
|
int64_t i = integer.payload.integer.value;
|
||||||
|
|
||||||
|
/* TODO: I don't believe it's as simple as this! */
|
||||||
|
accumulator += ( base * ( i % base ) );
|
||||||
|
result = make_string( hex_digits[accumulator % base], result );
|
||||||
|
accumulator += ( base * ( i / base ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( is_negative ) {
|
||||||
|
result = make_string( L'-', result );
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
|
@ -18,8 +18,13 @@ long double numeric_value( struct cons_pointer pointer );
|
||||||
*/
|
*/
|
||||||
struct cons_pointer make_integer( int64_t value, struct cons_pointer more );
|
struct cons_pointer make_integer( int64_t value, struct cons_pointer more );
|
||||||
|
|
||||||
struct cons_pointer add_integers( struct cons_pointer a, struct cons_pointer b);
|
struct cons_pointer add_integers( struct cons_pointer a,
|
||||||
|
struct cons_pointer b );
|
||||||
|
|
||||||
struct cons_pointer multiply_integers( struct cons_pointer a, struct cons_pointer b);
|
struct cons_pointer multiply_integers( struct cons_pointer a,
|
||||||
|
struct cons_pointer b );
|
||||||
|
|
||||||
|
struct cons_pointer integer_to_string( struct cons_pointer int_pointer,
|
||||||
|
int base );
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -411,8 +411,9 @@ struct cons_pointer inverse( struct cons_pointer frame,
|
||||||
case RATIOTV:
|
case RATIOTV:
|
||||||
result = make_ratio( frame,
|
result = make_ratio( frame,
|
||||||
make_integer( 0 -
|
make_integer( 0 -
|
||||||
to_long_int( cell.payload.ratio.
|
to_long_int( cell.payload.
|
||||||
dividend ), NIL ),
|
ratio.dividend ),
|
||||||
|
NIL ),
|
||||||
cell.payload.ratio.divisor );
|
cell.payload.ratio.divisor );
|
||||||
break;
|
break;
|
||||||
case REALTV:
|
case REALTV:
|
||||||
|
@ -452,7 +453,8 @@ struct cons_pointer lisp_subtract( struct
|
||||||
break;
|
break;
|
||||||
case INTEGERTV:
|
case INTEGERTV:
|
||||||
result = make_integer( cell0.payload.integer.value
|
result = make_integer( cell0.payload.integer.value
|
||||||
- cell1.payload.integer.value, NIL );
|
- cell1.payload.integer.value,
|
||||||
|
NIL );
|
||||||
break;
|
break;
|
||||||
case RATIOTV:{
|
case RATIOTV:{
|
||||||
struct cons_pointer tmp =
|
struct cons_pointer tmp =
|
||||||
|
|
|
@ -61,10 +61,10 @@ struct cons_pointer simplify_ratio( struct cons_pointer frame_pointer,
|
||||||
|
|
||||||
if ( ratiop( arg ) ) {
|
if ( ratiop( arg ) ) {
|
||||||
int64_t ddrv =
|
int64_t ddrv =
|
||||||
pointer2cell( pointer2cell( arg ).payload.ratio.dividend ).payload.
|
pointer2cell( pointer2cell( arg ).payload.ratio.dividend ).
|
||||||
integer.value, drrv =
|
payload.integer.value, drrv =
|
||||||
pointer2cell( pointer2cell( arg ).payload.ratio.divisor ).payload.
|
pointer2cell( pointer2cell( arg ).payload.ratio.divisor ).
|
||||||
integer.value, gcd = greatest_common_divisor( ddrv, drrv );
|
payload.integer.value, gcd = greatest_common_divisor( ddrv, drrv );
|
||||||
|
|
||||||
if ( gcd > 1 ) {
|
if ( gcd > 1 ) {
|
||||||
if ( drrv / gcd == 1 ) {
|
if ( drrv / gcd == 1 ) {
|
||||||
|
@ -203,10 +203,10 @@ struct cons_pointer divide_ratio_ratio( struct cons_pointer frame_pointer,
|
||||||
struct cons_pointer arg1,
|
struct cons_pointer arg1,
|
||||||
struct cons_pointer arg2 ) {
|
struct cons_pointer arg2 ) {
|
||||||
struct cons_pointer i = make_ratio( frame_pointer,
|
struct cons_pointer i = make_ratio( frame_pointer,
|
||||||
pointer2cell( arg2 ).payload.ratio.
|
pointer2cell( arg2 ).payload.
|
||||||
divisor,
|
ratio.divisor,
|
||||||
pointer2cell( arg2 ).payload.ratio.
|
pointer2cell( arg2 ).payload.
|
||||||
dividend ), result =
|
ratio.dividend ), result =
|
||||||
multiply_ratio_ratio( frame_pointer, arg1, i );
|
multiply_ratio_ratio( frame_pointer, arg1, i );
|
||||||
|
|
||||||
dec_ref( i );
|
dec_ref( i );
|
||||||
|
|
|
@ -103,10 +103,10 @@ void dump_object( FILE * output, struct cons_pointer pointer ) {
|
||||||
case RATIOTV:
|
case RATIOTV:
|
||||||
fwprintf( output,
|
fwprintf( output,
|
||||||
L"\t\tRational cell: value %ld/%ld, count %u\n",
|
L"\t\tRational cell: value %ld/%ld, count %u\n",
|
||||||
pointer2cell( cell.payload.ratio.dividend ).payload.
|
pointer2cell( cell.payload.ratio.dividend ).
|
||||||
integer.value,
|
payload.integer.value,
|
||||||
pointer2cell( cell.payload.ratio.divisor ).payload.
|
pointer2cell( cell.payload.ratio.divisor ).
|
||||||
integer.value, cell.count );
|
payload.integer.value, cell.count );
|
||||||
break;
|
break;
|
||||||
case READTV:
|
case READTV:
|
||||||
fwprintf( output, L"\t\tInput stream\n" );
|
fwprintf( output, L"\t\tInput stream\n" );
|
||||||
|
|
|
@ -80,14 +80,15 @@ bool equal( struct cons_pointer a, struct cons_pointer b ) {
|
||||||
&& ( equal( cell_a->payload.string.cdr,
|
&& ( equal( cell_a->payload.string.cdr,
|
||||||
cell_b->payload.string.cdr )
|
cell_b->payload.string.cdr )
|
||||||
|| ( end_of_string( cell_a->payload.string.cdr )
|
|| ( end_of_string( cell_a->payload.string.cdr )
|
||||||
&& end_of_string( cell_b->payload.string.
|
&& end_of_string( cell_b->payload.
|
||||||
cdr ) ) );
|
string.cdr ) ) );
|
||||||
break;
|
break;
|
||||||
case INTEGERTV:
|
case INTEGERTV:
|
||||||
result =
|
result =
|
||||||
( cell_a->payload.integer.value ==
|
( cell_a->payload.integer.value ==
|
||||||
cell_b->payload.integer.value ) &&
|
cell_b->payload.integer.value ) &&
|
||||||
equal(cell_a->payload.integer.more, cell_b->payload.integer.more);
|
equal( cell_a->payload.integer.more,
|
||||||
|
cell_b->payload.integer.more );
|
||||||
break;
|
break;
|
||||||
case REALTV:
|
case REALTV:
|
||||||
{
|
{
|
||||||
|
|
|
@ -246,7 +246,8 @@ eval_lambda( struct cons_space_object cell, struct stack_frame *frame,
|
||||||
|
|
||||||
/* if a result is not the terminal result in the lambda, it's a
|
/* if a result is not the terminal result in the lambda, it's a
|
||||||
* side effect, and needs to be GCed */
|
* side effect, and needs to be GCed */
|
||||||
if (!nilp(result)) dec_ref(result);
|
if ( !nilp( result ) )
|
||||||
|
dec_ref( result );
|
||||||
|
|
||||||
result = eval_form( frame, frame_pointer, sexpr, new_env );
|
result = eval_form( frame, frame_pointer, sexpr, new_env );
|
||||||
}
|
}
|
||||||
|
@ -352,8 +353,9 @@ c_apply( struct stack_frame *frame, struct cons_pointer frame_pointer,
|
||||||
result = next_pointer;
|
result = next_pointer;
|
||||||
} else {
|
} else {
|
||||||
result =
|
result =
|
||||||
( *fn_cell.payload.special.
|
( *fn_cell.payload.
|
||||||
executable ) ( get_stack_frame( next_pointer ),
|
special.executable ) ( get_stack_frame
|
||||||
|
( next_pointer ),
|
||||||
next_pointer, env );
|
next_pointer, env );
|
||||||
debug_print( L"Special form returning: ", DEBUG_EVAL );
|
debug_print( L"Special form returning: ", DEBUG_EVAL );
|
||||||
debug_print_object( result, DEBUG_EVAL );
|
debug_print_object( result, DEBUG_EVAL );
|
||||||
|
|
|
@ -124,17 +124,21 @@ struct cons_pointer print( FILE * output, struct cons_pointer pointer ) {
|
||||||
case FUNCTIONTV:
|
case FUNCTIONTV:
|
||||||
fwprintf( output, L"(Function)" );
|
fwprintf( output, L"(Function)" );
|
||||||
break;
|
break;
|
||||||
case INTEGERTV:
|
case INTEGERTV:{
|
||||||
|
struct cons_pointer s = integer_to_string( pointer, 10 );
|
||||||
|
inc_ref( s );
|
||||||
if ( print_use_colours ) {
|
if ( print_use_colours ) {
|
||||||
fputws( L"\x1B[34m", output );
|
fputws( L"\x1B[34m", output );
|
||||||
}
|
}
|
||||||
fwprintf( output, L"%ld%", cell.payload.integer.value );
|
print_string_contents( output, s );
|
||||||
|
dec_ref( s );
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case LAMBDATV:{
|
case LAMBDATV:{
|
||||||
struct cons_pointer to_print = make_cons( c_string_to_lisp_symbol( L"lambda" ),
|
struct cons_pointer to_print =
|
||||||
|
make_cons( c_string_to_lisp_symbol( L"lambda" ),
|
||||||
make_cons( cell.payload.lambda.args,
|
make_cons( cell.payload.lambda.args,
|
||||||
cell.payload.
|
cell.payload.lambda.body ) );
|
||||||
lambda.body ));
|
|
||||||
inc_ref( to_print );
|
inc_ref( to_print );
|
||||||
|
|
||||||
print( output, to_print );
|
print( output, to_print );
|
||||||
|
@ -146,10 +150,10 @@ struct cons_pointer print( FILE * output, struct cons_pointer pointer ) {
|
||||||
fwprintf( output, L"nil" );
|
fwprintf( output, L"nil" );
|
||||||
break;
|
break;
|
||||||
case NLAMBDATV:{
|
case NLAMBDATV:{
|
||||||
struct cons_pointer to_print = make_cons( c_string_to_lisp_symbol( L"nlambda" ),
|
struct cons_pointer to_print =
|
||||||
|
make_cons( c_string_to_lisp_symbol( L"nlambda" ),
|
||||||
make_cons( cell.payload.lambda.args,
|
make_cons( cell.payload.lambda.args,
|
||||||
cell.payload.
|
cell.payload.lambda.body ) );
|
||||||
lambda.body ));
|
|
||||||
inc_ref( to_print );
|
inc_ref( to_print );
|
||||||
|
|
||||||
print( output, to_print );
|
print( output, to_print );
|
||||||
|
|
Loading…
Reference in a new issue