File:  [gforth] / gforth / kernel / input.fs
Revision 1.16: download - view: text, annotated - select for diffs
Mon Feb 6 09:59:06 2006 UTC (18 years, 2 months ago) by anton
Branches: MAIN
CVS tags: HEAD
even better error reporting (wrt trailing delimiters)

    1: \ Input handling (object oriented)                      22oct00py
    2: 
    3: \ Copyright (C) 2000,2003,2004,2005 Free Software Foundation, Inc.
    4: 
    5: \ This file is part of Gforth.
    6: 
    7: \ Gforth is free software; you can redistribute it and/or
    8: \ modify it under the terms of the GNU General Public License
    9: \ as published by the Free Software Foundation; either version 2
   10: \ of the License, or (at your option) any later version.
   11: 
   12: \ This program is distributed in the hope that it will be useful,
   13: \ but WITHOUT ANY WARRANTY; without even the implied warranty of
   14: \ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15: \ GNU General Public License for more details.
   16: 
   17: \ You should have received a copy of the GNU General Public License
   18: \ along with this program; if not, write to the Free Software
   19: \ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
   20: 
   21: \ input handling structure:
   22: 
   23: | : input-method ( m "name" -- m' )  Create dup , cell+
   24: DOES> ( ... -- ... ) @ current-input @ @ + perform ;
   25: | : input-var ( v size "name" -- v' )  Create  over , +
   26: DOES> ( -- addr ) @ current-input @ + ;
   27: 
   28: 0
   29: input-method source ( -- addr u ) \ core-ext,file source
   30:     \G Return address @i{addr} and length @i{u} of the current input
   31:     \G buffer
   32: input-method refill ( -- flag ) \ core-ext,block-ext,file-ext
   33:     \G Attempt to fill the input buffer from the input source.  When
   34:     \G the input source is the user input device, attempt to receive
   35:     \G input into the terminal input device. If successful, make the
   36:     \G result the input buffer, set @code{>IN} to 0 and return true;
   37:     \G otherwise return false. When the input source is a block, add 1
   38:     \G to the value of @code{BLK} to make the next block the input
   39:     \G source and current input buffer, and set @code{>IN} to 0;
   40:     \G return true if the new value of @code{BLK} is a valid block
   41:     \G number, false otherwise. When the input source is a text file,
   42:     \G attempt to read the next line from the file. If successful,
   43:     \G make the result the current input buffer, set @code{>IN} to 0
   44:     \G and return true; otherwise, return false.  A successful result
   45:     \G includes receipt of a line containing 0 characters.
   46: input-method source-id ( -- 0 | -1 | fileid ) \ core-ext,file source-i-d
   47:     \G Return 0 (the input source is the user input device), -1 (the
   48:     \G input source is a string being processed by @code{evaluate}) or
   49:     \G a @i{fileid} (the input source is the file specified by
   50:     \G @i{fileid}).
   51: | input-method (save-input) ( -- x1 .. xn n ) \ gforth
   52: | input-method (restore-input) ( x1 .. xn n -- ) \ gforth
   53: drop
   54: 
   55: cell \ the first cell points to the method table
   56: cell input-var >in ( -- addr ) \ core to-in
   57:     \G @code{input-var} variable -- @i{a-addr} is the address of a
   58:     \G cell containing the char offset from the start of the input
   59:     \G buffer to the start of the parse area.
   60: cell input-var input-parse-start ( -- a-addr ) \ gforth
   61:     \G @code{input-var} variable -- @i{a-addr} is the address of a
   62:     \G cell containing a pointer to the start of the last parsed
   63:     \G string (but after skipped characters, if any); this is set
   64:     \G automatically by @code{parse}, @code{parse-name} and
   65:     \G @code{word}, but not if you set @code{>in} yourself.
   66: cell input-var input-parse-end ( -- a-addr ) \ gforth
   67:     \G @code{input-var} variable -- @i{a-addr} is the address of a
   68:     \G cell containing a pointer to the end of the last parsed
   69:     \G string (but after skipped characters, if any); this is set
   70:     \G automatically by @code{parse}, @code{parse-name} and
   71:     \G @code{word}, but not if you set @code{>in} yourself.
   72: cell input-var #tib ( -- addr ) \ core-ext number-t-i-b
   73:     \G @code{input-var} variable -- @i{a-addr} is the address of a
   74:     \G cell containing the number of characters in the terminal input
   75:     \G buffer. OBSOLESCENT: @code{source} superceeds the function of
   76:     \G this word.
   77: cell input-var max#tib ( -- addr ) \ gforth max-number-t-i-b
   78:     \G @code{input-var} variable -- This cell contains the maximum
   79:     \G size of the current tib.
   80: cell input-var old-input ( -- addr ) \ gforth
   81:     \G @code{input-var} variable -- This cell contains the pointer to
   82:     \G the previous input buffer
   83: cell input-var loadline ( -- addr ) \ gforth
   84:     \G @code{input-var} variable -- This cell contains the line that's
   85:     \G currently loaded from
   86: has? file [IF]
   87: cell input-var loadfile ( -- addr ) \ gforth
   88:     \G @code{input-var} variable -- This cell contains the file the
   89:     \G input buffer is associated with (0 if none)
   90: cell input-var blk ( -- addr ) \ block
   91:     \G @code{input-var} variable -- This cell contains the current
   92:     \G block number
   93: cell input-var #fill-bytes ( -- addr ) \ gforth
   94:     \G @code{input-var} variable -- number of bytes read via
   95:     \G (read-line) by the last refill
   96: 2 cells input-var loadfilename ( -- addr ) \ gforth
   97:     \G @code{input-var} variable -- addr u describes name of currently
   98:     \G interpreted input (file name or somesuch)
   99: [THEN]
  100: 0 input-var tib ( -- addr ) \ core
  101: 
  102: Constant tib+
  103: 
  104: \ helper words
  105: 
  106: : input-start-line ( -- )
  107:     >in off  input-parse-start off input-parse-end off ;
  108: 
  109: : input-lexeme! ( c-addr u -- )
  110:     \ record that the current lexeme us c-addr u
  111:     >r source drop - dup input-parse-start ! r> + input-parse-end ! ;
  112: 
  113: \ terminal input implementation
  114: 
  115: :noname ( in 1 -- ) 1 <> -12 and throw >in ! ;
  116:                        \ restore-input
  117: :noname ( -- in 1 ) >in @ 1 ;     \ save-input
  118: ' false                \ source-id
  119: :noname ( -- flag ) [ has? file [IF] ] 
  120:     stdin file-eof?  IF  false  EXIT  THEN [ [THEN] ]
  121:     tib max#tib @ accept #tib !
  122:     input-start-line true 1 loadline +! ;     \ refill
  123: :noname ( -- addr u ) tib #tib @ ;   \ source
  124: 
  125: | Create terminal-input   A, A, A, A, A,
  126: :noname ( -- addr u ) tib @ #tib @ ; \ source
  127: | Create evaluate-input
  128:     A,                  \ source
  129:     ' false A,          \ refill
  130:     ' true A,           \ source-id
  131:     terminal-input 3 cells + @ A, \ terminal::restore-input
  132:     terminal-input 4 cells + @ A, \ terminal::save-input
  133: 
  134: \ file input implementation
  135: 
  136: has? file [IF]
  137: : read-line ( c_addr u1 wfileid -- u2 flag wior ) \ file
  138:     (read-line) nip ;
  139: 
  140: :noname  ( in line# udpos 4 -- ) 4 <> -12 and throw
  141:     loadfile @ reposition-file throw
  142:     refill 0= -36 and throw \ should never throw
  143:     loadline ! >in ! ; \ restore-input
  144: :noname  ( -- in line# udpos 4 ) >in @ sourceline#
  145:     loadfile @ file-position throw #fill-bytes @ 0 d-
  146:     4 ;                \ save-input
  147: :noname  ( -- file ) loadfile @ ;  \ source-id
  148: :noname  ( -- flag )
  149:     #tib off #fill-bytes off input-start-line
  150:     BEGIN
  151: 	tib max#tib @ #tib @ /string
  152: 	loadfile @ (read-line) throw #fill-bytes +!
  153: 	swap #tib +!
  154: 	\ auto-expanding the tib
  155: 	dup #tib @ #fill-bytes @ = and WHILE
  156: 	    drop max#tib @ 2* expand-tib
  157:     REPEAT
  158:     1 loadline +! ;
  159:                        \ refill
  160: terminal-input @       \ source -> terminal-input::source
  161: 
  162: | Create file-input  A, A, A, A, A,
  163: [THEN]
  164: 
  165: \ push-file, pop-file
  166: 
  167: : new-tib ( method n -- ) \ gforth
  168:     \G Create a new entry of the tib stack, size @i{n}, method table
  169:     \G @i{method}.
  170:     dup >r tib+ + dup allocate throw tuck swap 0 fill
  171:     current-input @ swap current-input ! old-input ! r> max#tib !
  172:     current-input @ ! ;
  173: : expand-tib ( n -- )
  174:     dup tib+ + current-input @ swap resize throw current-input !
  175:     max#tib ! tib max#tib @ #tib @ /string 0 fill ;
  176: has? file [IF]
  177: : push-file  ( -- ) \ gforth
  178:     \G Create a new file input buffer
  179:     file-input def#tib new-tib ;
  180: [THEN]
  181: : pop-file ( throw-code -- throw-code ) \ gforth
  182:     \G pop and free the current top input buffer
  183:     dup IF
  184: 	input-error-data >error
  185:     THEN
  186:     current-input @ old-input @ current-input ! free throw ;
  187: 
  188: \ save-input, restore-input
  189: 
  190: : save-input ( -- x1 .. xn n ) \ core-ext
  191:     \G The @i{n} entries @i{xn - x1} describe the current state of the
  192:     \G input source specification, in some platform-dependent way that can
  193:     \G be used by @code{restore-input}.
  194:     (save-input) current-input @ swap 1+ ;
  195: : restore-input ( x1 .. xn n -- flag ) \ core-ext
  196:     \G Attempt to restore the input source specification to the state
  197:     \G described by the @i{n} entries @i{xn - x1}. @i{flag} is true if
  198:     \G the restore fails.  In Gforth with the new input code, it fails
  199:     \G only with a flag that can be used to throw again; it is also
  200:     \G possible to save and restore between different active input
  201:     \G streams. Note that closing the input streams must happen in the
  202:     \G reverse order as they have been opened, but in between
  203:     \G everything is allowed.
  204:     current-input @ >r swap current-input ! 1- dup >r
  205:     ['] (restore-input) catch
  206:     dup IF  r> 0 ?DO  nip  LOOP  r> current-input !  EXIT  THEN
  207:     rdrop rdrop ;
  208: 
  209: \ create terminal input block
  210: 
  211: : create-input ( -- )
  212:     \G create a new terminal input
  213:     terminal-input def#tib new-tib ;
  214:     \ s" *the terminal*" loadfilename 2!
  215: 
  216: : execute-parsing-wrapper ( ... addr1 u1 xt addr2 u2 -- ... ) \ gforth-internal
  217:     \ addr1 u1 is the string to be processed, xt is the word for
  218:     \ processing it, addr2 u2 is the name of the input source
  219:     rot >r 2>r evaluate-input cell new-tib 2r> 
  220: [ has? file [IF] ]
  221:     loadfilename 2!
  222: [ [ELSE] ]
  223:     2drop
  224: [ [THEN] ]
  225:     -1 loadline ! #tib ! tib !
  226:     r> catch pop-file throw ;
  227: 
  228: : execute-parsing ( ... addr u xt -- ... ) \ gforth
  229: \G Make @i{addr u} the current input source, execute @i{xt @code{(
  230: \G ... -- ... )}}, then restore the previous input source.
  231:     s" *evaluated string*" execute-parsing-wrapper ;
  232: 
  233: : evaluate ( ... addr u -- ... ) \ core,block
  234: \G Save the current input source specification. Store @code{-1} in
  235: \G @code{source-id} and @code{0} in @code{blk}. Set @code{>IN} to
  236: \G @code{0} and make the string @i{c-addr u} the input source and
  237: \G input buffer. Interpret. When the parse area is empty, restore the
  238: \G input source specification.
  239:     ['] interpret execute-parsing ;
  240: 
  241: \ clear tibstack
  242: 
  243: : clear-tibstack ( -- ) \ gforth
  244:     \G clears the tibstack; if there is none, create the bottom entry:
  245:     \G the terminal input buffer.
  246:     current-input @ 0= IF  create-input  THEN
  247:     BEGIN  old-input @  WHILE  0 pop-file drop  REPEAT ;
  248: 
  249: : query ( -- ) \ core-ext
  250:     \G Make the user input device the input source. Receive input into
  251:     \G the Terminal Input Buffer. Set @code{>IN} to zero. OBSOLESCENT:
  252:     \G superceeded by @code{accept}.
  253:     clear-tibstack  refill 0= -39 and throw ;
  254: 
  255: \ load a file
  256: 
  257: has? file [IF]
  258: defer line-end-hook ( -- ) \ gforth
  259: \G called at every end-of-line when text-interpreting from a file    
  260: \ alternatively we could use a wrapper for REFILL
  261: ' noop is line-end-hook
  262:     
  263: : read-loop ( i*x -- j*x ) \ gforth
  264:     \G refill and interpret a file until EOF
  265:     BEGIN  refill  WHILE  interpret line-end-hook REPEAT ;
  266: 
  267: : execute-parsing-named-file ( i*x wfileid filename-addr filename-u xt -- j*x )
  268:     >r push-file \ dup 2* cells included-files 2@ drop + 2@ type
  269:     loadfilename 2!  loadfile !
  270:     r> catch
  271:     loadfile @ close-file swap 2dup or
  272:     pop-file  drop throw throw ;
  273: 
  274: : execute-parsing-file ( i*x fileid xt -- j*x ) \ gforth
  275: \G Make @i{fileid} the current input source, execute @i{xt @code{( i*x
  276: \G -- j*x )}}, then restore the previous input source.
  277:     s" *a file*" rot execute-parsing-named-file ;
  278: 
  279: : include-file ( i*x wfileid -- j*x ) \ file
  280:     \G Interpret (process using the text interpreter) the contents of
  281:     \G the file @var{wfileid}.
  282:     ['] read-loop execute-parsing-file ;
  283: [THEN]

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>