home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / forth / compiler / fpc / doc / chapter6.txt < prev    next >
Text File  |  1989-10-29  |  19KB  |  470 lines

  1. CHAPTER 6.  SEQUENTIAL FILES
  2.  
  3.  
  4.  
  5.  
  6. 6.1.    SEQUENTIAL FILES IN F-PC
  7.  
  8.  
  9. More than 90% of what is in F-PC kernel came from F83.  Much of what you
  10. are seeing should be somewhat familiar.  Things that are different are
  11. normally different because they need to be.  There are a significant
  12. number of things about F83 that should have been changed, but were not
  13. for compatibility reasons.  However since BLOCK is not present (it is
  14. available as a load-on utility in the file BLOCK.SEQ in the ZIMMER
  15. archive) and is replaced by sequential files, you will have to adjust to
  16. them.  Nevertheless, many of the familiar file manipulation words from
  17. F83 are still present, and those that are will work in a very similar if
  18. not identical way.  Some of these are:
  19.  
  20.         OPEN, CLOSE, VIEW, OK, ED, EDIT, LOAD, LIST
  21.  
  22. Some words, like BLOCK and BUFFER, simply did not fit into the new scheme
  23. of things in a logical manner, and so were omitted.  To load an entire
  24. file, use the sequence
  25.  
  26.         FLOAD <filename>
  27.  
  28. Scanning through a file is best done with VIEW, although of course the
  29. file must have already been loaded. To scan through a file which has not
  30. been loaded, you can use LIST, which lists from a line number, rather
  31. than from a block, but the following sequence is easier:
  32.  
  33.         OPEN <filename>         Open a file
  34.         n LIST                  List 23 lines from n'th line in the SED
  35.                                 window
  36.  
  37. These words are very fast, using indices into the file to maintain their
  38. line pointer information.  The text of the entire file is stored in a
  39. text segment, and the line number indices are stored in a line segment.
  40. Similar to LIST, LOAD and EDIT also take a line number as input to start
  41. the loading or editing function in the middle of the current file. The
  42. line number before LIST, LOAD, or EDIT is optional.  If the line number
  43. is omitted, the listing or loading starts from line 1.
  44.  
  45. The compiler in F-PC has been tailored to be as fast as it could be made.
  46. Since much of the functionality of WORD has been reworked into assembly
  47. code for performance and all text data are in RAM memory, F-PC compiles
  48. sequential text files much faster than standard F83 compiles BLOCKs.  The
  49. compilation speed averages 20,000 lines per minute on a 10 MHz AT.
  50.  
  51. Utilities are provided to convert large BLOCK files into sequential files
  52. and vice versa.  Converting a block file to a sequential file typically
  53. saves more than 60% in mass storage.
  54.  
  55.  
  56. 6.2.    HANDLES
  57.  
  58.  
  59. According to DOS manual, a handle is a 16 bit number used by the
  60. operating system to identify a file or a device when it is opened or
  61. created.  I F-PC, a handle is a data structure which contains several
  62. fields,.  Words have been defined to traverse to the various fields.
  63. Here is a picture of the data structure of a handle as shown in Figure
  64. 6.1.
  65.  
  66.  
  67. Figure  6.1.    The file handle array
  68.  
  69.  
  70.  
  71.  
  72.  
  73.  
  74.  
  75.  
  76.  
  77.  
  78.  
  79.  
  80.  
  81.  
  82.  
  83.  
  84.  
  85.  
  86.  
  87.  
  88.                                                   
  89.  
  90.  
  91.  
  92.  
  93.  
  94.  
  95. Each of the words shown in Figure 6.1 after 'handle array', steps from
  96. the address returned by the handle name, to the field indicated. The word
  97. HANDLE followed by <name> creates and initializes the above structure.
  98. When <name> is later used, it returns the address labeled +0 above.
  99.  
  100. A file handle stack is used in F-PC to allow a file to load other files.
  101. SEQHANDLE is a value which contains the pointer to the currently opened
  102. file in the handle stack.  A sequential line read word LINEREAD is
  103. provided, which reads one line at a time from the file whose handle is in
  104. SEQHANDLE, returning an address of a counted string which also includes
  105. the CRLF characters at the end of the line.  You will have to strip them
  106. off if you don't want them.  The LINEREAD word is used as follows:
  107.  
  108. : sample        (  -- )                         \ followed by <filename>
  109.         open                    \ open a file
  110.         0.0 seek                \ reset file pointer buffer
  111.         begin
  112.                 lineread        \ read a line, returns an address of counted $
  113.                 dup c@          \ check for length,
  114.         0 <> while              \ while buffer contains something
  115.                 cr count 2- type\ type line just read without the CRLF chars.
  116.         repeat  drop            \ repeat till file empty.
  117.         close ;                 \ close the file.
  118.  
  119. This simple example may seem complicated, but it really is easy to read
  120. the lines of a sequential file, and writing is just as easy.  The word
  121. LINEREAD automatically buffers the reads from disk in a 4K buffer to
  122. minimize the number of DOS calls performed.  Lines up to 250 characters
  123. can be read with LINEREAD.  Longer lines or lines not terminated by a
  124. CRLF will be split at 250 characters.
  125.  
  126. For more detailed and comprehensive examples, please consult the files
  127. SEQTOBLK.SEQ and BLKTOSEQ.SEQ.  These two files contain code which
  128. converts sequential files to block files and vice versa.  You will find
  129. useful word sequences which open and close files, read data from a file,
  130. write data to a file, move the file pointer around, pushing and pooping
  131. the file stack, etc.
  132.  
  133.  
  134. 6.3.   SEQUENTIAL FILE WORD SET
  135.  
  136.   The file system interface in F-PC uses handles to talk to DOS, and
  137. only the number representing the File ID is passed to DOS from Forth. To
  138. make the interface as simple and clean as possible, you the Forth
  139. programmer need never deal with the details of how this works.  You only
  140. need to know that handles are created with the word HANDLE.  Handles are
  141. arrays within which special file information is stored, and when a
  142. handle's name is executed, it returns an address which is the address
  143. that is passed to the handle file control words.  Word definitions and
  144. usage in this set of file handling words are as follows:
  145.  
  146. .FILES                          ( -- )
  147.  
  148. Print to the screen a list of the files currently open. 
  149.  
  150. .LOADED                 ( -- )
  151.  
  152. Print a list of the files that have been loaded.  This list is used to
  153. locate the source file for a particular word that has been compiled.
  154.  
  155. ">$                     ( char-addr count -- counted-string )
  156.  
  157. Convert a string compiled as a 'quoted string' to a counted string, by
  158. dropping the count and decrementing the char-addr by one.
  159.  
  160. $>HANDLE                ( a1 handle-addr -- )
  161.  
  162. Move the counted string at a1 into the filename field in a handle. 
  163.  
  164. $>EXT                   ( a1 handle-addr -- )
  165.  
  166. Move the counted string at a1 into the extension field of handle.  The
  167. extension string should not contain a decimal point, and should be
  168. exactly (3) three characters long.
  169.  
  170. $HOPEN                  ( a1 -- return-code )
  171.  
  172. Close the current file if one is open.  Move the counted string from
  173. address a1 to the current handle on the handle stack.  Return the result
  174. code from DOS as return-code.
  175.  
  176. !HCB <filename> ( handle-addr -- )
  177.  
  178. Pick up text from the input stream with WORD, and place the name into the
  179. handle array.
  180.  
  181. ?DEF.EXT                ( -- )
  182.  
  183. Conditionally apply the extension specified in the array DEFEXT to the
  184. filename in handle. DEFEXT is a counted string, three characters long
  185. plus a count.
  186.  
  187. CHARREAD                ( -- c1 )
  188.  
  189. Read a character from the currently open file specified by SEQHANDLE.
  190. Before using this word, you will need to initialize the sequential input
  191. buffer to empty ( to force a refill from the currently selected file) by
  192. saying IBRESET.  This will force a disk read on the next call to
  193. CHARREAD, insuring that you get data from the file you selected.
  194.  
  195. CLOSE                   ( -- )
  196.  
  197. Close the currently open file on SEQHANDLE.  Move down one level on the
  198. handle stack, so another file may be open after performing this
  199. operation.  Normally you will be able to operate on the handle in SHNDL
  200. as an empty handle after performing CLOSE.
  201.  
  202. CLR-HCB                 ( handle-addr -- )
  203.  
  204. Clear the handle to nulls, and reset the handle identifier field to -1 to
  205. indicate no file is open.
  206.  
  207. CURPOINTER              ( handle-addr -- double-current-ptr )
  208.  
  209. Return the current 32-bit double pointer into the file specified by
  210. handle.
  211.  
  212. DEFEXT                  ( -- a1 )
  213.  
  214. Return the address of the default file extension that will be applied to
  215. any file to be opened, if no extension is specified in the filename when
  216. the HOPEN occurs.  The address a1 is the address of a 4 byte array
  217. containing a count byte, and three extension bytes following.  In no case
  218. should a string longer than 3 characters plus count be placed in DEFEXT.
  219.  
  220. ENDFILE                 ( handle-addr -- double-end-ptr )
  221.  
  222. Return the double-end number which represents the length of the file
  223. specified by handle.  The file must already be open.
  224.  
  225. EXHREAD                 ( a1 n1 handle-addr segment -- n2 )
  226.  
  227. Read from file handle into the buffer specified by segment and address a1
  228. for a length of bytes n1, and return n2 the length of bytes actually
  229. read.  The file must already be open.  Useful for reading from a file
  230. into memory other than Forth's Code Segment. A read from a file is
  231. limited to 65535 bytes.
  232.  
  233. EXHWRITE                ( a1 n1 handle-addr segment -- n2 )
  234.  
  235. Write from segment and address a1 for a length of n1 bytes to file
  236. handle, and return n2, the length of bytes actually written.  The file
  237. must already be open.  Useful for writing from memory other than Forth
  238. code segment to a file.  A write to a file is limited to 65535 bytes.
  239.  
  240. FILE>TIB                ( a1 -- )
  241.  
  242. Move the counted string filename from address a1 to the Terminal Input
  243. Buffer (TIB), available for use by !HCB.
  244.  
  245. FLOAD <filename>        ( -- )
  246.  
  247. Open and load the file specified by filename. 
  248.  
  249. HANDLE  <handlename>            (  -- )
  250.  
  251. Create a handle with name <handlename>.  When <handlename> is later
  252. executed, it returns the address of the handle array created.
  253.  
  254. HANDLE>EXT              ( handle-addr -- a1 )
  255.  
  256. Step from the handle address to the address of the file extension in the
  257. handle, if an extension exists; else it steps to the null following the
  258. filename.  The address a1 will be the address of a decimal point
  259. character if the file contains an extension, or the address of a null if
  260. no extension was contained in the handle.
  261.  
  262. HCLOSE                  ( handle-addr -- return-code )
  263.  
  264. Close the file currently open on handle, and return the result code from
  265. DOS as return-code.
  266.  
  267. HCREATE                 ( handle-addr -- return-code )
  268.  
  269. Create a file with the filename specified by the handle array, and return
  270. the DOS result code as return-code.
  271.  
  272. HDELETE                 ( handle-addr -- return-code )
  273.  
  274. Delete the filename as specified by handle name, and return the result
  275. code from DOS as return- code.
  276.  
  277. HIDELINES               ( -- )
  278.  
  279. Specify that lines loaded with FLOAD NOT be displayed to the display
  280. screen.
  281.  
  282. HOPEN                   ( handle-addr -- return-code )
  283.  
  284. Given the handle address, open the filename in it, and return the result
  285. code from DOS as return- code.
  286.  
  287. HREAD                   ( a1 n1 handle-addr -- n2 )
  288.  
  289. Read from file handle into the buffer address a1 for length of bytes n1,
  290. and return n2 the length of bytes actually read.  The file must already
  291. be open.  A read from a file is limited to 65535 bytes.
  292.  
  293. HRENAME                 ( handle1 handle2 -- return-code )
  294.  
  295. Rename the filename specified by handle1 to be the name specified in
  296. handle2, and return the DOS result code as return-code.
  297.  
  298. HWRITE                  ( a1 n1 handle-addr -- n2 )
  299.  
  300. Write from address a1 for length n1 bytes to file handle, and return n2
  301. the length of bytes actually written.  The file must already be open.  A
  302. write to a file is limited to 65535 bytes.
  303.  
  304. IBRESET                 ( -- )
  305.  
  306. Clear the input read buffer in preparation for reading a new file.  This
  307. is done by OPEN.
  308.  
  309. LINEREAD                ( -- a1 )
  310.  
  311. Read one line from the current file, buffered by INBUF, which holds 4k
  312. bytes.  Return a1 the address of OUTBUF, a 256 byte buffer used to hold
  313. lines read.  When switching to a new file, use MOVEPOINTER to reset the
  314. file pointer to the beginning of the file, and execute IBRESET so the
  315. next LINEREAD will cause a read from the disk file.  The read line length
  316. is limited to 250 bytes. Lines read with LINEREAD are terminated with
  317. LF=$0A.
  318.  
  319. LIST                            ( line-number -- )
  320.  
  321. List 18 lines starting at line-number from the currently open file.
  322. Default to line 1 if line-number is omitted.
  323.  
  324. LOAD                            ( line-number -- )
  325.  
  326. Start loading the currently open file, at line-number.  Used alone
  327. without a line number, it defaults to load from line 1.  Load through the
  328. end of the file or until \S if no errors are encountered.
  329.  
  330. MOVEPOINTER             ( double-offset handle-addr -- )
  331.  
  332. Move the filepointer into the file handle to the offset location
  333. specified by double-offset.  The file must already be open.
  334.  
  335. PATHSET                 ( handle -- f1 )
  336.  
  337. Check the file contained in handle.  If it does not contain a path, then
  338. apply the current drive and path to the handle. Return f1 FALSE if it
  339. succeeded; else TRUE if it failed to read the path from DOS.
  340.  
  341. RWMODE                  ( -- a1 )
  342.  
  343. A variable which holds the read/write attributes for any file to be
  344. opened by HOPEN, normally contains a two (2) for read/write.  It may be
  345. set to one (1) for write only, or to zero (0) for read only.
  346.  
  347. SEEK                            ( d1 -- )
  348.  
  349. Position the file pointer for the file currently open on SEQHANDLE, to
  350. d1, that is SEEK to position d1 relative to the beginning.
  351.  
  352. SEQDOWN                 ( -- )
  353.  
  354. Close the current file on the current level of the handle stack, and step
  355. down one level to the previous handle.  The handle stack is five levels
  356. deep allowing files to load files.
  357.  
  358. SEQHANDLE       ( -- a1 )
  359.  
  360. A VALUE that returns the address of the current file handle in the handle
  361. stack.
  362.  
  363. SEQHANDLE+      ( -- a1 )
  364.  
  365. A VALUE that returns the address of the next available handle in the
  366. handle stack.  This handle is used by the SED editor for temporary file
  367. operations like renaming, or deleting.  You can use SEQHANDLE+ as well,
  368. but its usage duration should be kept very short to avoid problems with
  369. other sections of the program using it.
  370.  
  371. SEQUP                   ( -- )
  372.  
  373. Step up one Handle on the handle stack, if there is a file open on that
  374. stack level, close it.  The handle stack is five levels deep.  FLOAD can
  375. thus be nested for four levels.
  376.  
  377. SHOWLINES               ( -- )
  378.  
  379. Specify that lines loaded with FLOAD will be displayed to the display
  380. screen.
  381.  
  382.  
  383. 6.4.    CONVERSION BETWEEN SEQUENTIAL AND BLOCK FILES
  384.  
  385.  
  386. To ease your transition from F83 to F-PC, utilities are provided to
  387. convert block files used by F83 to the sequential files required by F-PC.
  388.  
  389. The command sequence is :
  390.  
  391.         FLOAD BLKTOSEQ <enter>     \ load converter
  392.  
  393.         CONV <filespec> <enter>
  394.  
  395. The file specified after CONV will be converted to a sequential file of
  396. the same name with .SEQ extension.  If a file specification is not given
  397. after CONV, CONV will request a valid file name to be converted.  CONV
  398. also assumes that the block file has shadow blocks in its second half if
  399. the source file has an extension of .BLK.  It then brackets the text in
  400. the shadow blocks between COMMENT: and COMMENT; , and inserts them after
  401. the corresponding source block.  However, if the source file has an
  402. extension of .SCR, the entire file will be converted as source blocks and
  403. the second half of the file is not treated as shadow blocks.
  404.  
  405. The utility package SEQTOBLK.SEQ will do the opposite: converting a
  406. sequential file back to a block file.  The commands are:
  407.  
  408.         FLOAD SEQTOBLK <enter>
  409.  
  410.         CONV <enter>
  411.  
  412. CONV will request the names of the sequential and block files.  The
  413. extensions must not be given, as the sequential file defaults to .SEQ and
  414. the block file to .SCR.  CONV does a line to line conversions and does
  415. not try to detect boundaries between definitions.  It tends to break long
  416. definitions and puts them in consecutive blocks.  However, as all
  417. experienced Forth programmers tend to write single line short
  418. definitions, the block file thus produced should be compilable under F83
  419. without trouble, we hope.
  420.  
  421. These two conversion utility files contain the best examples on how to
  422. open/create files and how to read/write them.  If you have to use files
  423. in your application, pay special attention to these two files for advice
  424. and guidance.  The meanings of the words in the glossary become clear as
  425. you see them in action.
  426.  
  427.  
  428. 6.5.    PROGRAMMING STYLE AND SEQUENTIAL FILES
  429.  
  430.  
  431. The use of sequential files for source code instead of blocks has its
  432. most significant influence on the style of Forth programming.  Using
  433. blocks, the favored style of Forth code is the 'Horizontal code style' by
  434. which code is arranged in horizontal lines with many Forth words spread
  435. in the same line.  This style emphasizes the structure of words, whose
  436. definitions appear to be small, modular units.  These units are then used
  437. to form other words which are again small units to build other words.
  438. Word definitions expressed in the horizontal style are concise and
  439. powerful.  The problem is that it tends to leave little space for
  440. comments and documentation.  The lack of comments and in-line
  441. documentation make Forth code difficult to understand and hard to
  442. maintain.
  443.  
  444. There are only 16 lines in a block, while each line has 64 characters.
  445. The aspect ratio of a block is 4:1, an much elongated rectangle.  The
  446. block seems to exert a great pressure on the source code in the vertical
  447. directions and presses the code into flat, horizontal lines.  In a text
  448. file, the vertical pressure is completely released because the file does
  449. not have practical limitation on the number of lines it can contain.  The
  450. residual pressure is from the limited number of characters that one can
  451. put in a line.  This pressure in the horizontal direction tends to press
  452. the code into the 'Vertical code style' favored by traditional
  453. programming languages.  In the vertical code style, each line is limited
  454. to have one statement, leaving plenty of white space for comments and
  455. documentation.
  456.  
  457. It is thus natural that you will find most of the source files in F-PC
  458. follows the vertical code style. It is especially evident in the low
  459. level code definitions.  Each line contains only a small number of Forth
  460. words, allowing much space for documentation, which may or may not be
  461. filled in by the author.  Nevertheless, this mechanism is apparently
  462. favoring less code in a line.  Indentation can also be used with much
  463. more freedom than under the pressure between block boundaries.
  464.  
  465. By removing blocks from the system, F-PC also eliminates the last excuse
  466. for Forth programmers not to write clear and well-documented code.
  467. Henceforth, if we see bad, undocumented code in F- PC, we will shoot the
  468. programmer and leave Forth in peace.
  469.  
  470.