[Date Prev] [Date Next] [Thread Prev] [Thread Next] Date Index Thread Index Search archive:
Date:Tue, 4 May 2004 19:52:07 +0000 (UTC) 
Subject:Re: how to convert numbers to string??? 
From:steve 
Volume-ID: 

Hi,

>Thanks for the below email, really useful ! Could you please explain what it does exactly if you know??
 
Pop-11's string concatenation operator "><" is actually very simple to
understand.  It uses the normal print operator "pr" to print both its
arguments - but catches the characters instead of actually sending them
to the screen.

The way it does that is very neat.  The normal printing functions work
by calling "cucharout" (CUrrent CHARacter OUTput) on each character in
turn.  But "cucharout" can be temporarily redefined using dlocal (Dynamic
LOCALisation).

If you are a Java programmer you would expect to be able to write
a version of string concatenation like this:

    define my_string_concatenation( x, y );
        lvars buffer = new_string_buffer();

        define dlocal cucharout( ch );
            add_last( ch, buffer )
        enddefine;
      
        pr( x );
        pr( y );
        return to_string( buffer )
    enddefine;

However, Pop-11 doesn't have anything like Java's StringBuffer!  Instead
Pop-11 programmers tend to use the stack or lists.  So a Pop-11 programmer
would tend to write it more like this ...

    define my_string_concatenation( x, y );
        dlocal cucharout = identfn;
        consstring(#| pr( x ), pr( y ) |#)
    enddefine;

... get it?!  We locally define cucharout to do nothing (!) so that it just
drops the character on the stack, then we count how many characters get
dropped and call consstring on that count.  It is worth saying that this
definition does mean that programmers cannot rely on cucharout returning
0 results when writing printing functions - but that's a common Pop-11
idiom.

And if you don't fancy that, you could always implement a simple
StringBuffer.  Here's a fairly reasonable example which uses the usual
character array + count.

;;; A string with excess capacity.
defclass string_buffer {
    string_buffer_excess_capacity,
    string_buffer_store
};

;;; Create an empty string buffer.
define new_string_buffer();
    consstring_buffer( 0, nullstring )
enddefine;

;;; Add a character onto the end.
define add_last( ch, b );

    ;;; Is there enough room?
    lvars xs = b.string_buffer_excess_capacity;
    if xs <= 0 then
        ;;; Nope - so add some room.
        lblock
            lvars s = b.string_buffer_store;
            lvars n = s.datalength;
            lvars t = inits( max( 64, n * 2 ) );
            move_bytes( 1, s, 1, t, n );
            t -> b.string_buffer_store;
            t.datalength - n ->> b.string_buffer_excess_capacity -> xs;
        endlblock;
    endif;

    ;;; There is enough room (i.e. xs is the excess capacity > 0)
    lvars s = b.string_buffer_store;
    lvars n = s.datalength;

    ;;; Decrement the excess capacity by 1.
    xs - 1 ->> xs ->  b.string_buffer_excess_capacity;
    ;;; Update the last character.
    ch -> subscrs( n - xs, s );
enddefine;

;;; Fish out the string i.e. exclude the excess capacity.
define to_string( b );
    lvars s = b.string_buffer_store;
    substring( 1, s.datalength - b.string_buffer_excess_capacity, s )
enddefine;

I hope this all helps!

-- 
Steve