retroforth/source/interfaces/rre.forth
crc 7b443158fe remove full screen listener; refactor the listener; expose ok as a hookable word
FossilOrigin-Name: 36c3f4e7168881d02b354d441a559a6d6ee0c9907c823cc22c8c08ead7394e96
2019-05-22 14:20:01 +00:00

126 lines
3.5 KiB
Forth

# RRE Listener and Extensions
In this file I am implementing the interactive listener that
RRE will run when started with `-i`, `-i,c`, or `-i,fs`.
The basic image has a space allocated for input at the end of
the kernel. This is at address 1024 (the kernel space is fixed
at addresses 0 to 1023).
~~~
#1024 'TIB const
~~~
~~~
:image:save (s-) #1000 io:scan-for io:invoke ;
~~~
## Console Input
The RRE interface provides a keyboard device. This exposes it
via `c:get`.
~~~
{{
'io:Keyboard var
:identify
@io:Keyboard n:zero? [
#1 io:scan-for dup n:negative?
[ drop 'IO_DEVICE_TYPE_0001_NOT_FOUND s:put nl ]
[ !io:Keyboard ] choose ] if ;
---reveal---
:c:get (-c) identify @io:Keyboard io:invoke ;
}}
~~~
Now that I can read characters, it's time to support reading
strings. I do this via two words. The first is `parse-until`.
This will setup a temporary string as an input buffer, then
read input, passing each character ot a provided quote. When
the quote returns `TRUE`, it ends and returns the string. When
not `TRUE` it will add the character to the buffer.
~~~
{{
:gather (c-)
dup [ #8 eq? ] [ #127 eq? ] bi or [ drop ] [ buffer:add ] choose ;
:cycle (q-qc) repeat c:get dup-pair swap call not 0; drop gather again ;
---reveal---
:parse-until (q-s)
[ s:empty buffer:set cycle drop-pair buffer:start ] buffer:preserve ;
}}
~~~
Using this, a simple `s:get` can be implemented very easily as
a quote which looks for an end of line character.
~~~
:s:get (-s) [ [ ASCII:LF eq? ] [ ASCII:CR eq? ] bi or ] parse-until ;
~~~
## Scripting: Command Line Arguments
RRE also provides access to the command line arguments passed
to a script. The next few words map the scripting device to
words we can use.
~~~
{{
'io:Scripting var
:identify
@io:Scripting n:zero? [
#9 io:scan-for dup n:negative?
[ drop 'IO_DEVICE_TYPE_0009_NOT_FOUND s:put nl ]
[ !io:Scripting ] choose ] if ;
---reveal---
:sys:argc (-n) identify #0 @io:Scripting io:invoke ;
:sys:argv (n-s) s:empty swap identify #1 @io:Scripting io:invoke ;
:include (s-) identify #2 @io:Scripting io:invoke ;
:sys:name (-s) s:empty identify #3 @io:Scripting io:invoke ;
}}
~~~
~~~
:clear #27 c:put '[2J s:put #27 c:put '[0;0H s:put ;
~~~
Hide the support words.
# Standard Interactive Listener
The main part of this file is the *listener*, an interactive
read-eval-print loop.
RRE's C part will access a couple parts of this, based on the
startup flags passed.
~~~
'NoEcho var
:bye #0 unix:exit ;
:ok hook @NoEcho [ compiling? [ nl 'Ok_ s:put ] -if ] -if ;
{{
(-nn) :version @Version #100 /mod ;
(c-f) :done? [ ASCII:CR eq? ]
[ ASCII:LF eq? ]
[ ASCII:SPACE eq? ] tri or or ;
(s-sf) :valid? dup s:length n:strictly-positive? ;
(c-c) :check-eof dup [ #-1 eq? ] [ ASCII:EOT eq? ] bi or &bye if ;
:bs buffer:get buffer:get drop-pair ;
(c-c) :check-bs dup [ #8 eq? ] [ #127 eq? ] bi or &bs if ;
(c-c) :check check-eof check-bs ;
(-c) :character c:get dup buffer:add ;
(q-) :buffer [ TIB buffer:set call buffer:start ] buffer:preserve ;
(-s) :read-token [ [ character check done? ] until ] buffer s:chop ;
(-sf) :input read-token valid? ;
(sf-) :process [ interpret ok ] &drop choose ;
---reveal---
:banner version 'RETRO_12_(%n.%n)\n s:format s:put
EOM here - here EOM '%n_Max,_%n_Used,_%n_Free\n s:format s:put ;
:listen @NoEcho [ banner ] -if ok repeat input process again ;
}}
&listen #1 store
~~~