Skip to content

Instantly share code, notes, and snippets.

@lsparrish
Created January 2, 2010 23:48
Show Gist options
  • Save lsparrish/267730 to your computer and use it in GitHub Desktop.
Save lsparrish/267730 to your computer and use it in GitHub Desktop.

The program:

( buffering input )

{{
64 constant width
4  constant lines
variable num
create buffer lines width * allot
: incr      (   -   ) num dup @ lines 1- >if 0 swap ! ;then ++  ;
: this      (   -$  ) num @ width * buffer + ;
: "accept"  ( n"-   ) accept tib dup getLength incr this swap 1+ copy ;
---reveal---
: input     (  "-   )
   whitespace off
   10 "accept"
   whitespace on ;
: echo      (  "-"  ) input this type ;
: listen    (  "-   ) input this dup getLength eval ;
}}

The breakdown:

{{                        ::: Start local dictionary space.
64 constant width         ::: Lines may be up to 64 chars in length.
4  constant lines         ::: Number of lines that will be stored.
variable num              ::: Which line we are looking at.
create buffer             ::: Pointer to the beginning of the first line
lines width * allot       ::: Make room on the stack for 4 * 64 characters

We have just created a list of lines (buffer) with an index (num). However, we want to be able to access it conveniently. The best structure for our purposes is a circular list. So all we need to do is make sure num is set back to zero if it is ever equal to one less than lines.

: incr      (   -   ) num dup @ lines 1- >if 0 swap ! ;then ++  ;
: this      (   -$  ) num @ width * buffer + ;

incr alters num to either increase its value by one, or if it gets too high, set it to zero. this uses num to calculate the actual address of the line we are looking at. The returned address is somewhat like the tib where "accept" is concerned -- a place where parsed strings are sent.

: "accept"  ( n"-   )
accept tib dup getLength   ::: create a counted string of the input
incr this swap             ::: prepare the next line, move length to tos
1+ copy ;                  ::: copy string, including the null character

"accept" is a word which behaves much like accept but writes to our custom buffer instead of using the tib. It starts by calling accept, then copies what that places at tib to an address in our list specified by this. Before it does this, it calls incr so the previous call of "accept" remains in the buffer space that was previously used.

---reveal---               ::: begin defining public words
: input     (  "-   )      ::: accept a line of input to the buffer
   whitespace off          ::: turn off whitespace filtering
   10 "accept"             ::: parse for the enter key
   whitespace on ;         ::: whitespace filtering back on

input is a word that makes use of "accept" to read a line of input into the buffer. Based on this we can make custom words that re-type the same line, or which pass it to eval.

: echo      (  "-"  ) input this type ;
: listen    (  "-   ) input this dup getLength eval ;
}}

echo simply reads a line, uses this to get its address in the buffer, and uses type to display it to the screen. listen uses dup getLength to convert to a counted string and passes it to eval so that it is much like simply typing the line into the interpreter. The exception is that the evaluation is delayed, so you can fix typos involving spaces. Finally, the private words are hidden from the dictionary using }}.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment