Read negative numbers

This commit is contained in:
Simon Brooke 2018-12-25 13:51:15 +00:00
parent 6ee9f9b59a
commit 9e5af35aa0

View file

@ -86,6 +86,16 @@ struct cons_pointer read_continuation( struct stack_frame *frame, FILE * input,
case '"': case '"':
result = read_string( input, fgetwc( input ) ); result = read_string( input, fgetwc( input ) );
break; break;
case '-': {
wint_t next = fgetwc( input );
ungetwc( next, input );
if ( iswdigit( next ) ) {
result = read_number( frame, input, c, false );
} else {
result = read_symbol( input, c );
}
}
break;
case '.': case '.':
{ {
wint_t next = fgetwc( input ); wint_t next = fgetwc( input );
@ -113,6 +123,7 @@ struct cons_pointer read_continuation( struct stack_frame *frame, FILE * input,
( "Unrecognised start of input character" ), ( "Unrecognised start of input character" ),
frame ); frame );
} }
break;
} }
} }
@ -121,6 +132,8 @@ struct cons_pointer read_continuation( struct stack_frame *frame, FILE * input,
/** /**
* read a number from this input stream, given this initial character. * read a number from this input stream, given this initial character.
* TODO: to be able to read bignums, we need to read the number from the
* input stream into a Lisp string, and then convert it to a number.
*/ */
struct cons_pointer read_number( struct stack_frame *frame, FILE * input, struct cons_pointer read_number( struct stack_frame *frame, FILE * input,
wint_t initial, bool seen_period ) { wint_t initial, bool seen_period ) {
@ -129,11 +142,19 @@ struct cons_pointer read_number( struct stack_frame *frame, FILE * input,
int64_t dividend = 0; int64_t dividend = 0;
int places_of_decimals = 0; int places_of_decimals = 0;
wint_t c; wint_t c;
bool negative = initial == btowc( '-');
if (negative) {
initial = fgetwc( input );
}
#ifdef DEBUG
fwprintf( stderr, L"read_number starting '%c' (%d)\n", initial, initial ); fwprintf( stderr, L"read_number starting '%c' (%d)\n", initial, initial );
#endif
for ( c = initial; iswdigit( c ) for ( c = initial; iswdigit( c )
|| c == btowc( '.' ) || c == btowc( '/' ); c = fgetwc( input ) ) { || c == btowc( '.' ) || c == btowc( '/' ); c = fgetwc( input ) ) {
if ( c == btowc( '.' ) ) { if ( c == btowc( '.' ) ) {
if ( seen_period || dividend > 0 ) { if ( seen_period || dividend != 0 ) {
return make_exception( c_string_to_lisp_string return make_exception( c_string_to_lisp_string
( "Malformed number: too many periods" ), ( "Malformed number: too many periods" ),
frame ); frame );
@ -146,14 +167,17 @@ struct cons_pointer read_number( struct stack_frame *frame, FILE * input,
( "Malformed number: dividend must be integer" ), ( "Malformed number: dividend must be integer" ),
frame ); frame );
} else { } else {
dividend = accumulator; dividend = negative ? 0 - accumulator : accumulator;
accumulator = 0; accumulator = 0;
} }
} else { } else {
accumulator = accumulator * 10 + ( ( int ) c - ( int ) '0' ); accumulator = accumulator * 10 + ( ( int ) c - ( int ) '0' );
#ifdef DEBUG
fwprintf( stderr, fwprintf( stderr,
L"Added character %c, accumulator now %ld\n", L"Added character %c, accumulator now %ld\n",
c, accumulator ); c, accumulator );
#endif
if ( seen_period ) { if ( seen_period ) {
places_of_decimals++; places_of_decimals++;
} }
@ -167,13 +191,21 @@ struct cons_pointer read_number( struct stack_frame *frame, FILE * input,
if ( seen_period ) { if ( seen_period ) {
long double rv = ( long double ) long double rv = ( long double )
( accumulator / pow( 10, places_of_decimals ) ); ( accumulator / pow( 10, places_of_decimals ) );
if (negative) {
rv = 0 - rv;
}
#ifdef DEBUG
fwprintf( stderr, L"read_numer returning %Lf\n", rv ); fwprintf( stderr, L"read_numer returning %Lf\n", rv );
#endif
result = make_real( rv ); result = make_real( rv );
} else if ( dividend > 0 ) { } else if ( dividend != 0 ) {
result = result =
make_ratio( frame, make_integer( dividend ), make_ratio( frame, make_integer( dividend ),
make_integer( accumulator ) ); make_integer( accumulator ) );
} else { } else {
if (negative) {
accumulator = 0 - accumulator;
}
result = make_integer( accumulator ); result = make_integer( accumulator );
} }
@ -189,14 +221,19 @@ struct cons_pointer read_list( struct
*frame, FILE * input, wint_t initial ) { *frame, FILE * input, wint_t initial ) {
struct cons_pointer result = NIL; struct cons_pointer result = NIL;
if ( initial != ')' ) { if ( initial != ')' ) {
#ifdef DEBUG
fwprintf( stderr, fwprintf( stderr,
L"read_list starting '%C' (%d)\n", initial, initial ); L"read_list starting '%C' (%d)\n", initial, initial );
#endif
struct cons_pointer car = read_continuation( frame, input, struct cons_pointer car = read_continuation( frame, input,
initial ); initial );
result = make_cons( car, read_list( frame, input, fgetwc( input ) ) ); result = make_cons( car, read_list( frame, input, fgetwc( input ) ) );
} else { }
#ifdef DEBUG
else {
fwprintf( stderr, L"End of list detected\n" ); fwprintf( stderr, L"End of list detected\n" );
} }
#endif
return result; return result;
} }
@ -267,9 +304,12 @@ struct cons_pointer read_symbol( FILE * input, wint_t initial ) {
break; break;
} }
#ifdef DEBUG
fputws( L"Read symbol '", stderr ); fputws( L"Read symbol '", stderr );
print( stderr, result ); print( stderr, result );
fputws( L"'\n", stderr ); fputws( L"'\n", stderr );
#endif
return result; return result;
} }