home *** CD-ROM | disk | FTP | other *** search
- B-1
-
-
- APPENDIX B: SAMPLES AND TUTORIALS
-
-
-
-
- F-PC is such a monstrous system that most Forth users would feel lost
- facing it the first time. To make a new user feel more at home with it
- and help him overcome the initial shock, Tom Zimmer prepared a set of
- tutorial examples illustrating many unique and interesting features in
- F-PC. These examples are collected in the EXAMPLES.ARC file. You will
- also find many good tutorial materials in the user contributed files.
- However, these user contributed files are more application oriented and
- do assume that you are familiar with the F-PC system.
-
-
- B1. MEMORY ALLOCATION
-
-
- SALLOC.SEQ contains an example of how to use the memory allocation and
- deallocation words. This example allocates space at F-PC cold start time
- by placing the word MY-INIT into the deferred word chain called
- INITSTUFF. You do not have to allocate your memory at this time, but it
- will prevent your memory allocation from interfering with the editor's
- usage of memory. It is fairly easy using allocation and deallocation to
- cause memory to get fragmented to the point where almost any ALLOC will
- fail.
-
-
- hidden clearmem forth \ make sure the editor is not using memory
-
- 16000 constant bytes_needed \ Size of the array I need in bytes.
-
- 0 value myseg \ a place to put my base segment pointer.
-
- : alloc-myseg ( --- ) \ allocate the space I need
- myseg ?exit \ don't allocate again if already done
- bytes_needed paragraph \ adjust needed to # of paragraphs
- alloc \ allocate the space test for error in alloc
- 8 = abort" Not enough memory forMYSEG"
- nip \ discard largest block available
- !> myseg ; \ asign start of array into MYSEG
-
- alloc-myseg \ really allocate the space now so we can
- \ experiment
-
- : my-init ( --- )
- defers initstuff \ inserted into INITSTUFF chain
- off> myseg
- alloc-myseg ;
-
- \ ' my-init is init-stuff \ un-comment this line to cause
- \ initialization to be done at cold boot
-
- If you need to deallocate the space that you have allocated, you can use
- DEALLOC to release the space back to DOS.
-
- : release-myseg ( -- )
- myseg dealloc abort" failed to deallocate MYSEG" ;
-
- The other operation you can perform on an allocated memory segment is to
- resize it to a new size. This is done with SETBLOCK.
-
- : resize-myseg ( n1 -- ) \ adjust myseg to new size n1 in bytes
- myseg swap paragraph setblock
- abort" Failed to resize MYSEG" ;
-
- To put something into the array MYSEG, I might do something like the
- following.
-
- : string-save ( | <string> -- ) \ accept a <string> to save
- ?cs: 0 word dup>r \ moving FROM here
- myseg 0 \ TO the beginning of MYSEG
- r> c@ 1+ CMOVEL ; \ move the data with CMOVE LONG
-
- And you can then display the text from MYSEG.
-
- : type-string ( -- )
- myseg 0 \ FROM myseg
- 2dup c@L >r \ fetch the count
- ?cs: here \ TO here
- r> 1+ CMOVEL \ move data to HERE
- here count type ; \ display it
-
-
- B2. USER BOOT PROCESS
-
-
- SBOOT.SEQ contains an example of how to make F-PC perform your own
- function in place of starting F-PC and just running Forth. Before
- describing how to modify F-PC, let us first look at the things F-PC does
- at BOOT time so you can have a better understanding of the startup
- process.
-
- At BOOT time F-PC proceeds through the following sequence:
-
- : COLD
- {deferred} SETSEG
- Setup Segments
- Verify DOS > 2
- Adjust memory allocation
- Seg cursor position
- {deferred} VMODE.SET
- test Video mode
- Adjust display attributes
- {deferred} >COLOR
- or
- {deferred} >MONO
- Set the Video segment
- {deferred} INITSTUFF
- \ Various initializations, performed in a chain through this
- \ Deferred word. Things like:
- MACROS
- EDITOR
- SAVE SCREEN
- READ BUFFER SIZE
- FILE SYSTEM
- DIRECTORY BUFFER etc.
- {deferred} BOOT
- HELLO
- Initialize TIB
- Initialize VOCABULARY to FORTH
- {deferred} DEFAULT
- HDEFAULT
- Move command line to TIB
- OPEN a file if available
- {deferred} .HELLO
- Display signon message
- {deferred} .CURFILE
- Display current file
- {deferred} INTERPRET
- Process command line
- QUIT ;
-
- As you can see from the above sequence, there are several places you can
- modify what F-PC does at boot time. A substantial portion of the above
- process must be done, and so we want to be careful to tie in at the right
- point. In general eveything before BOOT must be done for F-PC to operate
- properly. If we tie in at BOOT though we will have to do some additional
- initialization to specifically much of the stuff done by HELLO. If we
- tie in at DEFAULT, we usually still want the DOS command line to be moved
- to TIB, and probably still want a file to be opened, so my normal choice
- would be to use DEFERS to link into DEFAULT without eliminating the
- function that is already there. This will then turn DEFAULT into a
- DEFERred chain. If we want in addition to have our own sign-on message,
- we can replace the functions in .HELLO and/or .CURFILE although a user
- application need not return from the chained DEFAULT, and as such .HELLO
- will never get performed. Here then without further delay is MYDEFAULT.
-
- : mydefault ( -- )
- defers default \ link into default as additional
- \ stuff to be done.
-
- \ Your program stuff goes here.
- \ *****************************
-
- cr ." This is my program "
- cr ." Press a key to terminate "
- key drop \ wait for a key before leaving
- cr
-
- \ This ends your program, so leave.
- \ *************************
-
- bye ; \ got it so leave
-
- ' mydefault is default
-
- FSAVE MYBOOT.EXE \ Now save the system back to disk with the
- \ name MYBOOT.EXE.
-
-
- B3. F-PC KEYSTROKE MACROS
-
-
- SMACRO.SEQ contains an example of how to use macros in the F-PC editor to
- reduce the keystrokes required to perform a given task. The first
- example is a real one. We want to shorten the glossary entries. A
- typical entry is shown below for +! :
-
- +! ( n1 a1 -- )
- FORTH KERNEL1
- Increment the value at a1 by n1. This is equivalent
- to the following: DUP @ ROT + SWAP ! but
- much faster.
-
- Since all of the words in the glossary are in the FORTH vocabulary, we
- can delete the word FORTH . Furthermore, the second line containing the
- source file name can be joint with the first line, and a little more
- editing can also be done at the same time. The desired new entry would
- be:
-
- +! ( n1 a1 -- ) KERNEL1
- Increment the value at a1 by n1. This is equivalent
- to the following: DUP @ ROT + SWAP ! but
- much faster.
-
- The glossary is a very large file, and the manual editing required to
- correct this would have been prohibitive, so a macro is created to join
- the second line with the first line and remove the Vocabulary from each
- entry when a single MACRO key is pressed.
-
- Here then is the key sequence that will make a macro to join the first
- and second lines of the second type glossary entry and remove the
- vocabulary from the entry. The macro will then go to the next paragraph
- which starts the next entry.
-
- This macro is always executed when the cursor in on the first line of a
- glossary entry at the leftmost column, and we are in INSERT mode.
-
- Alt-M Start a MACRO
- Alt-1 We are starting the macro for Alt-1
- INS Select OVERWRITE mode
- TAB Move to first TAB position
- Ctrl-T Remove spaces before stack picture
- TAB Move to 2nd TAB
- TAB Move to 3rd TAB
- TAB Move to 4th TAB
- INS Go back into INSERT mode
- DEL Delete the last char in the line forcing a join line. Cursor is now on
- the word FORTH
- Ctrl-T Delete the Vocabulary
- HOME Move back to beginning of line
- Alt-G_N Goto Next paragraph
- Alt-M Complete macro
-
- Macros are performed as they are created, so you must be on a glossary
- entry that needs to be modified while you are in the process of making
- the macro.
-
- In the following section I have included several copies of the +!
- glossary entry. Try making the macro described above while you are on
- the first entry, then press Alt-1 to try the macro on each successive
- entry.
-
- Macros can be saved with Alt-M_S, and loaded again with Alt-M_L. You can
- view the currently defined macros with Alt-M_V, but they will look very
- funny since they are mostly graphics characters.
-
-
- ---------------------- Try some macros here --------------------
-
- +! ( n1 a1 -- )
- FORTH KERNEL1
- Increment the value at a1 by n1. This is equivalent
- to the following: DUP @ ROT + SWAP ! but
- much faster.
-
- +! ( n1 a1 -- )
- FORTH KERNEL1
- Increment the value at a1 by n1. This is equivalent
- to the following: DUP @ ROT + SWAP ! but
- much faster.
-
- +! ( n1 a1 -- )
- FORTH KERNEL1
- Increment the value at a1 by n1. This is equivalent
- to the following: DUP @ ROT + SWAP ! but
- much faster.
-
- +! ( n1 a1 -- )
- FORTH KERNEL1
- Increment the value at a1 by n1. This is equivalent
- to the following: DUP @ ROT + SWAP ! but
- much faster.
-
- +! ( n1 a1 -- )
- FORTH KERNEL1
- Increment the value at a1 by n1. This is equivalent
- to the following: DUP @ ROT + SWAP ! but
- much faster.
-
- +! ( n1 a1 -- )
- FORTH KERNEL1
- Increment the value at a1 by n1. This is equivalent
- to the following: DUP @ ROT + SWAP ! but
- much faster.
-
- HRENAME ( handle1 handle2 -- return-code )
- FORTH HANDLES
- Change the name of the file specified in handle1 to the name
- specified in handle2. Can be used to move a file from one
- directory to another on the same drive. Returns 18 if the
- rename was good, not zero.
-
- HRENAME ( handle1 handle2 -- return-code )
- FORTH HANDLES
- Change the name of the file specified in handle1 to the name
- specified in handle2. Can be used to move a file from one
- directory to another on the same drive. Returns 18 if the
- rename was good, not zero.
-
- As you can see, having performed the macro on one of the last two
- glossary entries for HRENAME, a macro will not always work as you expect.
- If the information being manipulated does not follow the rules, you can
- get quite unexpected results. Use caution with macro, they can be
- wonderful time savers, but it is difficult to make a macro that will
- always work.
-
- This is only the start for macros. Experiment with some junk text to see
- what other neat things they can do. When you leave this file you
- probably DO NOT want to save your changes.
-
- Press Alt-F10 to leave SED without saving any changes.
-
- cr .( Use LISTING to print this file and then try editing it. )
-
-
- B4. A SAMPLE MENU FILE
-
-
- SMENU.SEQ is an example of menu usage. You can make a copy of this file
- and edit it to suit your need. Deferred routine to handle all keys the
- menu handler doesn't understand. It can be used to insert any unknown
- key pressed in an editor if you want, or it can just throw the keys away
- as is done here. The character the menu driver didn't understand is on
- the stack when AOTHER is called.
-
- The word AMENU is then called whenever a menu operation is to be
- performed. In an editing application, use ESC to enable this menu. To
- do this you look for the user to press the ESC key while typing in text.
- If ESC key is pressed, then execute RMENU rather than inserting the next
- key pressed.
-
-
- only forth also definitions hidden also
-
- \ Install the functions into these deferred words you want performed when
- \ a menu item is selected.
-
- defer item1
- defer item2
- defer item3
- defer item4
- defer item5
- defer item6
- defer item7
- defer item8
- defer item9
-
- 0 value amsave \ a place to save the previous menu column
- 0 value amline \ Menu starting line and column on screen
- 0 value amcolumn
-
- newmenu menu1$
- menuline" A item1 Alt-1 " item1
- menuline" B item2 Alt-2 " item2
- menuline" --------------------------" noop
- menuline" C item3 " item3
- menuline" D item4 Alt-4 " item4
- menuline" --------------------------" noop
- menuline" Quit item5 F10 " item5
- endmenu
-
- newmenu menu2$
- menuline" E item6 Alt-6 " item6
- menuline" F item7 Alt-7 " item7
- menuline" --------------------------" noop
- menuline" G item8 F8 " item8
- menuline" --------------------------" noop
- menuline" H item9 F9 " item9
- endmenu
-
- newmenubar amenubar
- +," A menu1 " \ the menu bar contains only two items
- +," B menu2 "
- endmenu
-
- create amenulist menu1$ , \ and two lists of functions
- menu2$ ,
-
- \ initialize the default condition of the menu bar
-
- amenubar =: menubar
- amenulist =: menulist
- ' amline is mline
- ' amcolumn is mcolumn
- ' drop is doother
-
- defer aother ' drop is aother
-
- : amenu ( -- ) \ the sample menu driver
- amsave =: mcol
- savemenu
- amenubar =: menubar
- amenulist =: menulist
- ['] amline is mline
- ['] amcolumn is mcolumn
- ['] aother is doother
- menu
- restmenu
- mcol =: amsave ;
-
-
- B5. MY STARTUP MESSAGE
-
-
- SMESSAGE.SEQ contains an example of how to change the sign-on message to
- display a user defined message in place of the default system message.
-
- : myhello ( -- )
- ." Hello!" ; \ here is the message
-
- ' myhello is .hello \ install new hello function into .HELLO
-
- \ We will also disable the displaying of the current file at boot time
-
- ' noop is .curfile
-
-
- B6. SUBSCREEN SCROLLING
-
-
- SSCROLL.SEQ contains an example of how to make the screen scroll only a
- limited set of lines. The file contains three user words as follows:
-
- SUB-SET ( n1 -- ) \ set the line where scrolling starts
- SUB-ON \ start sub screen scrolling
- SUB-OFF \ stop sub screen scrolling
-
- Following is the code to implement sub-screen scrolling:
-
- 0 value sub-line
-
- : sub-scroll ( -- ) \ scroll only a portion of the screen
- #line @ sub-line <
- if crlf \ scroll only a portion
- else 0 sub-line 1 max rows 1- min at -line
- 0 rows 1- at \ move to last line of screen
- then ;
-
- \ ******************* User words start here *******************
-
- : sub-set ( n1 -- ) \ set the starting sub screen scroll line
- 1 max 23 min !> sub-line ;
-
- : sub-on ( -- ) \ Turn on sub screen scrolling
- ['] sub-scroll is cr ;
-
- : sub-off ( -- ) \ Turn off sub screen scrolling
- ['] crlf is cr ;
-
-
- B7. USAGE OF VALUES
-
-
- SVALUES.SEQ contains an example of how an existing program can be
- modified to use a VALUE word in place of a VARIABLE to enhance program
- readability and performance. You must be aware that VALUEs are not
- portable. It will make your programs more difficult to move to another
- Forth system.
-
- Observe the use of the word COUNTER in the following program segments.
-
- \ Program segment using a VARIABLE named COUNTER
-
- create vowels ," aeiouAEIOU"
- variable counter
-
- : vcount ( | <string> -- ) \ get count of vowels in <string>
- counter off
- 0 word drop
- vowels count bounds
- ?do here count
- begin i c@ scan dup
- while 1 counter +!
- 1 -1 d+
- repeat 2drop
- loop
- cr ." Found "
- counter @ . ." vowels" ;
-
- \ Program segment using a VALUE named COUNTER
-
- create vowels ," aeiouAEIOU"
- 0 value counter
-
- : vvcount ( | <string> -- ) \ get count of vowels in <string>
- off> counter
- 0 word drop
- vowels count bounds
- ?do here count
- begin i c@ scan dup
- while incr> counter
- 1 -1 d+
- repeat 2drop
- loop
- cr ." Found "
- counter . ." vowels" ;
-
-
- B8. POPUP WINDOW
-
-
- SWINDOW.SEQ contains an example on how to make a popup window. While it
- may seem complicated at first, we are really doing only a few simple
- things. We save the screen positon, turn off the cursor, and save the
- screen before drawing the box and writing into it. After the user views
- the box and presses a key, we restore the things we saved. It is
- actually pretty simple.
-
- : popup ( -- )
- #out @ #line @ 2>r \ save cursor position for later
- cursor-off \ remove cursor from screen
- savescr \ preserve current screen contents
- 15 05 60 09 box&fill \ DRAW THE BOX on the screen
- \ PUT SOME TEXT IN IT
- ." This is a sample POPUP window" bcr
- \ following line in reverse video
- >rev ." Screen attributes can be used as well "
- >norm bcr
- ." Press a key to restore the previous screen"
- key drop \ wait for user to press a key
- restscr \ restore previous screen
- cursor-on \ turn cursor back on
- 2r> at ; \ restore cursor position
-
-