.TL \" Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. A User's Guide to the B system .AU Steven Pemberton CWI, Amsterdam .ds B \fIB\fP .so bfont.def .AB \*B is a new interactive programming language being developed at the CWI. This report gives a brief introduction to using the current \*B implementation. It does not teach you about the language, for which you should refer elsewhere. .AE .SH .bp Introduction .PP .de BX 'nh \v'-\\n(.su/2u'\(br\v'\\n(.su/2u'\|\\$1\|\v'-\\n(.su/2u'\(br\v'\\n(.su/2u'\\h'-\\w'|'u/2u'\l'|0+(\\w'|'u/2u)\(rn'\\h'-\\w'|'u/2u'\l'|0\(ul'\\$2 'hy .. .de BR [\\$1]\\$2 .. .de KY .ie t .BX \\$1 \\$2 .el .BR \\$1 \\$2 .. This guide is a brief introduction to using the current \*B system. It does not attempt to teach you about the language, for which you should refer elsewhere. .PP Furthermore, certain details such as how to start the system up, and which keys on your terminal correspond to the keys mentioned, depend on your local installation, and are not mentioned in this guide. Keys are just referred to here by their name, such as .KY accept . Refer to the ``bterminal(5)'' manual entry for these details. .PP Some older \*B systems don't let you make changes to immediate commands, nor give you suggestions to immediate commands, but only in units. .SH Starting up .PP The first response you should get from the \*B system when you start it up is a prompt that looks like this: .DS \*(<:>>> _?\*(:> .DE The underlined question mark is the indication from the \*B system that it is expecting input from you. (In fact, it depends on the sort of terminal you have whether it is underlined, displayed in reverse video, or what. In any case it is displayed in some special way, and we shall use underlining in this guide.) When it follows the three arrows \*(<:>>>\*(:>, called the \fIcommand prompt\fP, it is expecting you to type in a command. The question mark is called a \fIhole\fP and indicates that something should be filled in; the underline is called the \fIfocus\fP and shows where you are currently working. .PP You can fill this hole by typing in a \*(<:WRITE\*(:> command for instance: you type a \*(<:W\*(:> (which you don't have to type in upper-case: the system knows that it may only be upper-case here), and you immediately see: .DS \*(<:>>> W_?RITE ?\*(:> .DE This extra stuff to the right of the focus is a \fIsuggestion\fP. Most times that you type a \*(<:W\*(:> as the first letter of a command, it is because you want a \*(<:WRITE\*(:>. Therefore the editor suggests this, with an additional hole for the expression that you want to write. If you do want a \*(<:WRITE\*(:> (as in this case) you may press the .KY accept key to accept the suggestion \(em the editor then moves to the first unfilled hole in the command, which in this case is the only one, and you get: .DS \*(<:>>> WRITE _?\*(:> .DE You can now type an expression and press the .KY newline key. The system evaluates the expression, prints the result, and then gives you a new command prompt. Here are a few examples of \*(<:WRITE\*(:> commands: .DS \*(<:>>> WRITE 2+2 4 >>> WRITE root 2 1.414213562373095 >>> WRITE pi 3.141592653589793\*(:> .DE If you make a mistake while typing and spot it before you type .KY newline , an easy way to correct it is to use the .KY back key. Pressing .KY back takes you back to the situation before you typed the last key (\fIexactly\fP the situation, as you will see clearly after a little use). If you type .KY back twice, you will be taken back to the situation as it was two keys ago, and so forth. You can regard the .KY back key as a way of travelling back in time. .LP Thus, if you meant to type \*(<:WRITE pi\*(:>, but instead typed \*(<:WRITE po\*(:>, you will see this: .DS \*(<:>>> WRITE po_?\*(:> .DE Now pressing .KY back will give you .DS \*(<:>>> WRITE p_?\*(:> .DE Now you can type the \*(<:i\*(:> and the .KY newline . Currently you can only go back a maximum of 100 keystrokes, and in any case only as far as the command prompt (and thus not back to previous commands). You will see other ways to correct mistakes shortly. .PP If you make a mistake so that the result is illegal \*B, but don't notice before you press .KY newline you will get an error message: .DS \*(<:>>> WRITE root 3**2+4**2 *** There's something I don't understand in your command WRITE root 3**2+4**2 ^ *** The problem is: priorities? use ( and ) to resolve\*(:> .DE The problem here is that the system doesn't know if you want to apply \*(<:root\*(:> to \*(<:3\*(:> or \*(<:3**2\*(:> or \*(<:3**2+4**2\*(:> and you should use brackets to show which. .PP When you type an open bracket, the system automatically supplies the matching closing bracket for you: .DS \*(<:>>> WRITE root(_?)\*(:> .DE You now type in the expression .DS \*(<:>>> WRITE root(3**2+4**2_?)\*(:> .DE You may now type .KY newline \^( .KY accept will take you over the closing bracket, but it is not necessary to do this): .DS \*(<:>>> WRITE root(3**2+4**2) 5\*(:> .DE .LP You can write any legal \*B value: .DS \*(<:>>> WRITE {1..10} {1; 2; 3; 4; 5; 6; 7; 8; 9; 10} >>> WRITE 'Hello! '^^3 Hello! Hello! Hello!\*(:> .DE Just as with brackets, the system automatically supplies the closing brace \*(<:}\*(:>, and the closing quote \*(<:'\*(:>. In the latter case, where you want to type something after the closing quote you may either use .KY accept or type the quote yourself, in order to position after it. .PP Commands typed as a response to the command prompt are called `immediate' commands, since they are executed immediately. Another example is the \*(<:PUT\*(:> command. Just as with \*(<:WRITE\*(:>, when you type the first letter of the command, the system provides a suggestion: .DS \*(<:>>> P_?UT ? IN ?\*(:> .DE Again, you use .KY accept to go to the first hole: .DS \*(<:>>> PUT _? IN ?\*(:> .DE Here you type an expression, .DS \*(<:>>> PUT root 2?_ IN ?\*(:> .DE followed by another .KY accept to take you to the second hole: .DS \*(<:>>> PUT root 2 IN _?\*(:> .DE where you can type a target, followed by .KY newline : .DS \*(<:>>> PUT root 2 IN a >>> PUT root 3 IN b >>> WRITE a 1.414213562373095 >>> WRITE b 1.732050807568877 >>> WRITE a,b 1.414213562373095 1.732050807568877 >>> WRITE a*a, b*b 2 3\*(:> .DE The targets that you create in this way, through immediate commands, are called `permanent targets', because if you stop using the system, and log out, and come back later and start using the system again you will find that the targets are still there, with the same values as before. .PP You can find out which targets exist by typing two equals signs after the prompt: .DS \*(<:>>> == a b >>> PUT 'hello', {1..10} IN message, list >>> == a b list message >>> WRITE list {1; 2; 3; 4; 5; 6; 7; 8; 9; 10} >>> WRITE message hello\*(:> .DE To get rid of targets you no longer want, use the \*(<:DELETE\*(:> command: .DS \*(<:>>> DELETE a, b >>> == list message >>> WRITE a *** Can't cope with problem in your command WRITE a *** The problem is: a has not yet received a value\*(:> .DE As you can see, after the \*(<:DELETE\*(:> command both \*(<:a\*(:> and \*(<:b\*(:> have ceased to exist. .SH Other Immediate Commands .PP In fact, almost any \*B command can be used as an immediate command; the only exceptions are the commands used to terminate \*(<:TEST\*(:>s and \*(<:YIELD\*(:>s, namely \*(<:RETURN\*(:>, \*(<:REPORT\*(:>, \*(<:SUCCEED\*(:> and \*(<:FAIL\*(:>. .DS \*(<:>>> WRITE list {1; 2; 3; 4; 5; 6; 7; 8; 9; 10} >>> INSERT 5 IN list >>> REMOVE 6 FROM list >>> WRITE list {1; 2; 3; 4; 5; 5; 7; 8; 9; 10} >>> CHOOSE number FROM list >>> WRITE number 9 >>> CHECK 5 in list >>> CHECK 6 in list *** Your check failed in your command CHECK 6 in list >>> FOR i IN list: WRITE 10*i 10 20 30 40 50 50 70 80 90 100 >>> == list message number\*(:> .DE Note that a \*(<:CHECK\*(:> command that succeeds doesn't print any message. Also note carefully that the target \*(<:i\*(:> used in the \*(<:FOR\*(:> command doesn't exist afterwards. .PP When you want to type a \*(<:WHILE\*(:> command, and you type the initial \*(<:W\*(:>, the suggestion you get is of course \*(<:W_?RITE ?\*(:>. Here you must type an \*(<:H\*(:>, and the system then suggests .DS \*(<:>>> WH_?ILE ?:\*(:> .DE Now you can press .KY accept to go to the hole, type the test, and press .KY newline : .DS \*(<:>>> WHILE list <> {}: _?\*(:> .DE Because the \*B system knows that the commands of a \*(<:WHILE\*(:> must be indented, it indents for you automatically. You may now type in the commands to be part of the \*(<:WHILE\*(:>, and each time the system indents you to the right place. After the last command you just need to type an extra .KY newline , and the system undoes the indentation one level, and executes the \*(<:WHILE\*(:>. (If there is only one simple command to be repeated, it may be on the same line as the \*(<:WHILE\*(:>, but doesn't have to be). .DS \*(<:>>> WHILE list <> {}: CHOOSE number FROM list REMOVE number FROM list WRITE number 2 8 4 7 9 5 3 1 5 10 >>> WRITE list {}\*(:> .DE .SH Finishing a B Session .PP The one command that has a different meaning when you type it after a prompt is \*(<:QUIT\*(:>, which just terminates the \*B session. When you type the \*(<:Q\*(:> you will get a suggestion as usual. .DS \*(<:>>> Q_?UIT\*(:> .DE Here there are no holes, but you must still press .KY accept to accept the suggestion, before pressing .KY newline . .SH Making your own Commands .PP You can create your own commands by typing in a how-to unit that defines what your command means. Suppose you type in response to the \*B prompt: .DS \*(<:>>> HOW'TO GREET: WRITE 'Hello'\*(:> .DE The system gives a suggestion for \*(<:HOW'TO\*(:>, and supplies indentation for you, just as with \*(<:WHILE\*(:>, and you finish by pressing .KY newline until you get the command prompt again. Well, now you've defined your first command, and can execute it by typing its name after the prompt. You will notice that after typing the \*(<:G\*(:> you will get a suggestion for it: .DS \*(<:>>> G_?REET\*(:> .DE Just as with \*(<:QUIT\*(:>, there are no holes, but you must .KY accept the suggestion. .DS \*(<:>>> GREET_?\*(:> .DE Now press .KY newline and your command gets executed, and you get the prompt again: .DS \*(<:>>> GREET Hello >>>\*(:> .DE You may use your own commands just like any in-built command: .DS \*(<:>>> FOR i IN {1..10}: GREET HelloHelloHelloHelloHelloHelloHelloHelloHelloHello\*(:> .DE .SH Correcting errors .PP Apart from .KY back , another way of correcting errors is to correct a whole line. Here you use the ability to move the focus about. Earlier the focus was a single character, just the hole. However, the focus may be more than one character: it may be several characters, a whole command, or even several commands. .PP Two of the eight keys for moving the focus are .KY up and .KY down . .PP The .KY up key moves the focus up to the previous line so that it includes the whole line. So if you have the following situation: .DS \*(<:>>> FOR i IN {1..3}: WRITE / GREET WRITE /_?\*(:> .DE then typing .KY up gives you .DS \*(<:>>> FOR i IN {1..3}: WRITE / GREET_____ WRITE /\*(:> .DE Here the hole in the last line has disappeared (because the line is legal \*B) and the focus has moved up to the whole of the preceding line. You may press .KY up several time to go up several lines. So, pressing .KY up again gives: .DS \*(<:>>> FOR i IN {1..3}: WRITE /_______ GREET WRITE /\*(:> .DE The .KY down key does the same but in the other direction. .PP Now the point of all this is, that if you have a line in a command or unit that you want to change, you can move the focus to it, and press .KY delete to get rid of it. This leaves a hole in its place so that you can type a replacement line: .DS \*(<:>>> FOR i IN {1..3}: ?_ GREET WRITE /\*(:> .DE If you don't want to replace the line, but completely delete it, then pressing .KY delete again deletes the hole too: .DS \*(<:>>> FOR i IN {1..3}: GREET_____ WRITE /\*(:> .DE .SH Changing Existing Units .PP Just as you can type two equals signs to find out what permanent targets you have, you can type two colons to find out what units you have in the current workspace. This gives you a list of the first line of each unit in the workspace: .DS \*(<:>>> :: HOW'TO GREET:\*(:> .DE If you want to change any of these units, you can type a colon followed by the name of the unit you want: .DS \*(<:>>> :GREET\*(:> .DE (If the unit you want to change is the last unit you typed in or changed in this session, or the last unit that you got an error message about, then you don't even need to type its name: the system remembers the name of the unit, so all you need to do is type a single colon.) .PP What happens now is that the whole unit is displayed (or as much as will fit on the screen if it is big) with the focus on the line you were last at in the unit. You can now use all the focus moving keys to position to the lines you want to change, and change them. When you have finished, you use the .KY exit key. .SH Errors in Units .PP If when you type in or change a unit, the result has an error in it, you will get an error message from the \*B system. This may happen when you press .KY exit , or when you run the unit, depending on the sort of error it is. For instance, in this unit, the parameter is \*(<:x\*(:>, but \*(<:n\*(:> is used instead: .DS \*(<:>>> HOW'TO SQUARE x: WRITE n*n >>> SQUARE 4 *** Can't cope with problem in line 2 of your unit SQUARE WRITE n*n *** The problem is: n has not yet received a value\*(:> .DE When you get such a message, it is very easy to make the necessary correction: since the unit you want to change is the last one that you got an error message for, you only need to type a colon after the prompt: .DS \*(<:>>> : HOW'TO SQUARE x: WRITE n*n_________\*(:> .DE As you see, you are positioned at the line that gave the error message. Now you can either press .KY delete and retype the whole line, or use the other focus-moving keys to focus on only the part that is in error. .SH Other Focus Moving Keys .PP Apart from .KY up and .KY down there are six other keys for moving the focus, two for making the focus smaller: .KY first and .KY last , two for enlarging it: .KY widen and .KY extend , and two for moving it sideways: .KY previous and .KY next . .PP In this case we want to make the focus smaller, by going to the last part of the line. Thus, we can press .KY last and we see: .DS \*(<:HOW'TO SQUARE x: WRITE n*n___\*(:> .DE Pressing .KY delete deletes the part in the focus, leaving only a hole: .DS \*(<:HOW'TO SQUARE x: WRITE ?_\*(:> .DE Now we can type the correct expression and then press .KY exit : .DS \*(<:HOW'TO SQUARE x: WRITE x*x\*(:> .DE Suppose now you have the following unit to solve quadratic equations (if you don't know what these are, it doesn't matter): .DS \*(<:HOW'TO SOLVE a X2 b X c: PUT root (b**2-4*a*c) IN x WRITE (-b+x)/2*a, (-b-x)/2*a / *** There's something I don't understand in line 3 of your unit SOLVE WRITE (-b+x)/2*a, (-b-x)/2*a / ^ *** The problem is: priorities? use ( and ) to resolve\*(:> .DE The system doesn't know whether to divide by \*(<:2\*(:> or \*(<:2*a\*(:>, so you must insert brackets. .DS \*(<:>>> : HOW'TO SOLVE a X2 b X c: PUT root (b**2-4*a*c) IN x WRITE (-b+x)/2*a, (-b-x)/2*a /______________________________\*(:> .DE Now we want to narrow down to \*(<:2*a\*(:>. Pressing .KY last gives .DS \*(<:HOW'TO SOLVE a X2 b X c: PUT root (b**2-4*a*c) IN x WRITE (-b+x)/2*a, (-b-x)/2*a /________________________\*(:> .DE and then .KY first gives .DS \*(<:HOW'TO SOLVE a X2 b X c: PUT root (b**2-4*a*c) IN x WRITE (-b+x)/2*a, (-b-x)/2*a /___________\*(:> .DE and another .KY first gives .DS \*(<:HOW'TO SOLVE a X2 b X c: PUT root (b**2-4*a*c) IN x WRITE (-b+x)/2*a, (-b-x)/2*a /__________\*(:> .DE Now .KY last gives us .DS \*(<:HOW'TO SOLVE a X2 b X c: PUT root (b**2-4*a*c) IN x WRITE (-b+x)/2*a_, (-b-x)/2*a /\*(:> .DE The key .KY extend tries whenever possible to extend the focus to the right. But it sometimes can't, if what is to the right isn't associated with what is in the focus. This is the case here: the comma is associated with the \fIwhole\fP expression \*(<:(-b+x)/2*a\*(:>, and so .KY extend extends to the left instead: .DS \*(<:HOW'TO SOLVE a X2 b X c: PUT root (b**2-4*a*c) IN x WRITE (-b+x)/2*a__, (-b-x)/2*a /\*(:> .DE and once more pressing .KY extend : .DS \*(<:HOW'TO SOLVE a X2 b X c: PUT root (b**2-4*a*c) IN x WRITE (-b+x)/2*a___, (-b-x)/2*a /\*(:> .DE Now we have the expression we want, and typing an opening bracket encloses the whole expression: .DS \*(<:HOW'TO SOLVE a X2 b X c: PUT root (b**2-4*a*c) IN x WRITE (-b+x)/(?_2*a), (-b-x)/2*a /\*(:> .DE Now you can use the focus moves to do the same to the second \*(<:2*a\*(:>. .LP The focus move keys are very easy to use. After a little practice you will find they come very naturally. .SH Copying .PP It is often the case that you want to duplicate a piece of program. If the focus is on something other than a hole, the .KY copy key copies whatever is in the focus to what is called the .I "copy buffer" and lets you know that there is something in the copy buffer by displaying the words \*(<:[copy\ buffer]\*(:> at the bottom of the screen, along with the first bit of what is stored. .PP If, however, the focus is on a hole, then the .KY copy key copies the contents of the buffer into that hole. The \*(<:[copy\ buffer]\*(:> message then disappears, though actually the contents of the buffer remain, so you can continue to use it. However, if the contents of the buffer may not be copied there, you just get a bleep; for instance you can't copy a \*(<:WRITE\*(:> command to a place where an expression must be. .PP You can use the .KY copy key for moving things too: focus on what you want, press .KY copy , press .KY delete twice to delete it and the hole that gets left after the first delete, move to where you want, make a hole, and press .KY copy again. .PP Making a hole is straightforward. A .KY newline always makes a hole on a new blank line after the line that the focus was positioned on. An .KY accept always takes you to the first hole on a line, or if there is no hole on the line, then it makes one at the end of the line. Finally, pressing .KY first or .KY last enough times makes one, .KY first in front of the focus, .KY last after it. .PP You can use the .KY copy key for copying between different units too. Even if you log out, and come back later, and start using \*B again, the copy buffer is kept. .PP Additionally, if the \*(<:[copy buffer]\*(:> message isn't being displayed, that is, if the copy buffer is empty, and you .KY delete something, whatever you delete is put into the copy buffer; similarly if the copy buffer is empty, each immediate command is stored in the copy buffer. Thus if you mis-type an immediate command, you can use .KY copy to bring it back, and edit it. .SH Renaming and deleting units .PP If you change the name of a unit, or the adicity of a \*(<:YIELD\*(:> or \*(<:TEST\*(:> (such as making a dyadic \*(<:YIELD\*(:> into a monadic one) by changing its heading, then you get the new unit .I and the old one. So, renaming \*(<:GREET\*(:> into \*(<:HELLO\*(:>, and then giving a \*(<:::\*(:> command would give: .DS \*(<:>>> :: HOW'TO GREET: HOW'TO HELLO: HOW'TO SOLVE a X2 b X c: HOW'TO SQUARE x:\*(:> .DE If you delete the .I whole of a unit (by pressing .KY widen until the focus is on the whole unit, and then pressing .KY delete ) the unit disappears. Thus deleting \*(<:GREET\*(:> will give you: .DS \*(<:>>> :: HOW'TO HELLO: HOW'TO SOLVE a X2 b X c: HOW'TO SQUARE x:\*(:> .DE .SH Changing targets .PP You may also use the editor for changing permanent targets. Just as you use a single colon for editing units, a single equals followed by the name of a target will display the contents of the target, and let you make changes in the usual way. In fact, you may replace the contents by any .I expression. When you press .KY exit , the expression is evaluated, and if all is ok the value is put in the target. .SH Workspaces .PP A workspace is a collection of units plus a permanent environment. You can have several workspaces: to create a new one you just start \*B up in a new directory in the filestore. .PP To move units and targets between workspaces, just use the .KY copy key: start \*B up in the one workspace, save whatever you want to move in the copy buffer, exit \*B, move to the destination workspace, re-enter \*B, and copy the buffer back. .SH Record and play .PP Sometimes you need to repeat a sequence of keystrokes several times. For instance, if you want to rename a target in a unit, you have to do it once for each occurrence of the target. An easy way to do this is to .I record a sequence of keystrokes. If you press .KY record , the message \*(<:[recording]\*(:> appears at the bottom of the screen, and any keys that you type thereafter are processed normally and recorded at the same time, until you press .KY record again. Then pressing .KY play plays those recorded keystrokes back. .PP So, for instance, focus on the target you want to rename, press .KY record , press .KY delete , type the new name, and press .KY record again. Then focus on the next occurrence of the target, and press .KY play . .PP Keystrokes that cause an error during recording are not recorded. .SH Redisplaying the screen .PP Sometimes the screen can get messed up (for instance, if your terminal gets accidentally unplugged). If this happens, or you don't believe what you see on the screen, you can always get confirmation by pressing .KY look . This causes the screen to be redisplayed. .SH Interrupting a running command .PP If a command is executing, and you want to stop it, pressing .KY interrupt aborts the command and gives you a prompt again. .SH Incomplete units .PP If, when typing in or correcting a command or unit, you press .KY exit and there are still unfilled holes, the system tells you so, and you must fill or delete them. If you want to exit leaving the holes, to fill them later, use the .KY interrupt key. The system won't let you run an incomplete unit. .SH Getting help .PP Pressing the .KY help key gives you a quick summary of all the keys. Refer to the ``Quick Reference'' card for a brief reminder of the features of the \*B language, and the ``Description of \*B'' for more detailed explanations. .SH Running \*B in the background .PP If your computer system lets you, you can also run \*B non-interactively. In this case \*B commands are read from the standard input, and executed. You may only use normal \*B commands in this case: no focus moves, or editing, and no \*(<:::\*(:> or \*(<:==\*(:> commands.