Teach You, Teach Me (Part 1)
This section of MWM is a tutorial on M. You may have already read how efficient and fast it is; well why not try it out for yourself. It's as easy as they say. This tutorial assumes no knowledge of programming whatsoever. If you missed previous issues, you will find them listed in the index.
Our tutorial is based on the Student version of Micronetics Standard M (MSM/Student). For more information about this company jump over to their web page. In order to download a copy of this program check out Chris Bonnici's Download M section. Before you leave this page be sure to bookmark it so that you can find your way back with ease. For a free subscription to MWM click the Subscribe button show in the banner above.
We're new to web publishing and the section is appropriately called Teach You, Teach Me (TYTM). The reason for such a name is that we want this tutorial to be as useful to you as is possible on the web. We know what we want to pass on, but we want you, through your feedback, to guide us on this route. Your input could be in the form of general comments giving us the green light, hitting the expand-topic button and even taking us back a step or two.
No two people will generate the same solution to a problem. We welcome any code you send in, be it different approaches to what we present here or other code of your choice. All accepted submissions will be prominently displayed in MWM.
Last time we looked at looping constructs and demonstrated various forms of conditions. We also delved slightly into the area of flowcharts. Today we focus on formatting and introduce what can be classified as one of the most important steps in programming; modularity.
Click here to download this issue's routines.
The last program we talked about in MWM002 is show here. Program Section 1 never appears to do anything because the FOR loop quits (variable MONEY being zero) before it performs the READ instruction.
In Program Section 2, the check is set after the READ within the loop and so the user will be prompted for the money.
IF004Þ
;Conditional Loops - ACB - Feb 1997
Þ;(C) M Web Magazine @
http://geocities.datacellar.net/SiliconValley/7041/mwm.html
Þ;You are using this program at your own risk
Þ;
ÞW #,"Program Section 1"
ÞS MONEY=0
ÞF Q:(MONEY=0) R !,"How much money do you
have (0 - exit)? ",MONEY
Þ;
ÞW !!,"Program Section 2"
ÞS MONEY=0
ÞF R !,"How much money do you have (0 -
exit)? ",MONEY Q:(MONEY=0)
ÞQ
Putting it differently, the main difference between the two sections is the placement of the conditional test relating to the QUIT command. In section 1, the condition is tested for at the beginning of the loop, while in section 2, this same test (MONEY=0) is being made after the input.
As the two flowcharts demonstrate, in section 1 we are first setting MONEY = 0 after which we instruct the computer to quit if MONEY is 0. In the second part we also set MONEY to zero, but this time we allow the user to alter it before the test. Do appreciate that in different contexts these two different conditions are equally important and could facilitate some programming tasks.
Write a program asking the user if s/he has a car. If the answer is "Y" prompt for the cars CC. Loop until a value greater than 0 is entered.
Write a program that works out the paint needed to paint a number of walls (were assuming no windows here):
Ask the user to specify how many walls are to be painted into a variable called WALLS.
Set variable TOTAREA equal to 0
While WALLS > 0
Input Length of Wall (must be greater than 0)
Input Breadth of Wall (must be greater than 0)
Compute AREA = Length * Breadth
Add AREA to TOTAREA
Subtract 1 from WALLS
Display the Total Area to be covered
Ask user to specify the paint spread (store it call variable SPREAD), i.e. the area covered by one can of paint.
Display the number of cans required, i.e. TOTAREA divided by SPREAD. Ideally round up the number of cans to the nearest Integer (whole number).
You are in charge of an opinion poll. You have assigned a number of people to take random samples of various areas. Based on the data you receive, you have to give an estimate on how each area thinks. The table below summarizes the results on your desk.
Area | % of Sample In Favor (P) | Population Size (n) |
1 | (0.60) 60% | 6540 |
2 | (0.56) 56% | 2000 |
3 | (0.42) 42% | 8931 |
Since we are assuming that no one replied "No Opinion" the remainder of the sample are against.
The formula to calculate the how the population in each area will respond is . This formula allows an error of 5%. For example for Area 1 the value would be . This means that with a 5% chance of error, in Area 1 those in favor are between 59% and 61%.
Your program should ask for an area number. If this is zero the program should quit. If not it should request the Sample % in Favor and the Population Size. Apply the above formula and display the result. (Hint: If you feel that the computation is getting a bit out of hand, either use brackets or split it up into smaller (manageable parts, eventually getting to the answer from various subtotals).
Formatting
While functionality is paramount in a program, we must admit that a program should be attractive. Up till now we were restricted to items falling one after the other with very little control. If we look at the majority of programs we notice that displays and inputs are laid out in a consistent manner. For example, the first input is on the top left. After filling in that field we shift to the right on the same line. The third input is again logically placed. Error messages are all focused in one area of the program. The examples we are giving here all constitute formatting.
The program below uses two nested for loops to fill the screen with Xs. The positioning is achieved using the mnemonic /CUP with the row and column specified in parenthesis. The READ commands prompt is positioned on the first column of row 23. Following the READ, we erase the "Press any Key" and go into another loop, erasing parts of the lines we had drawn before. A point to note is how one can combine different mnemonics on the same line.
SCRN001Þ
;Program demonstrates the various input/output controls - Feb
1997 - ACB
Þ;M Web Magazine @
http://geocities.datacellar.net/SiliconValley/7041/mwm.html
Þ;You are using this program at your own risk
Þ;
ÞFOR ROW=1:1:20 FOR COL=1:1:80 WRITE
/CUP(ROW,COL),"X" ;fill lines 1 to 20 with X's
ÞREAD /CUP(23,1),"Press any
key",*ANS
ÞW /CUP(23,1),/EL(2) ;Erase Entire Prompt Line
ÞFOR ROW=1:1:20 S ELTYP=ROW#3 WRITE
/CUP(ROW,40),/EL(ELTYP),/CUP(ROW,1),ELTYP
ÞQUIT
Adjust the Wall Painting Program mentioned previously so that inputs are controlled. You may want to clear the screen before asking the length and breadth of each wall.
SCRN002Þ
;Program demonstrates the various input/output controls - Feb
1997
Þ;M Web Magazine @
http://geocities.datacellar.net/SiliconValley/7041/mwm.html
Þ;You are using this program at your own risk
Þ;
ÞFOR ROW=1:1:20 FOR COL=1:1:80 WRITE
/CUP(ROW,COL),"X" ;fill lines 1 to 20 with X's
ÞREAD /CUP(23,1),"Press any
key",ANS#1
ÞW /CUP(23,1),/EL(2) ;Erase Entire Line
ÞS ROW=20
ÞFOR COL=80:-4:1 WRITE
/BEL,/CUP(ROW,COL),/EL(1) S ROW=ROW-1
ÞW /CUP(23,1)
ÞQUIT
The mnemonic /BEL noises out the program. The operation of the SCRN002 is very similar to SCRN001 and we feel that with the list of mnemonics given below you can easily understand what the program is doing. While it is clear what /BEL does, we would like to point out that sounds are very useful in programs because, when used properly, they can draw attention to an event. Have you ever seen a data entry clerk entering data into a computer? Many of these people rarely focus on what is being typed on the screen. So if a mistake takes place they might not even notice it. A sound can draw their attention though. SCRN002 does just that.
SCRN003Þ ;Program demonstrates the various input/output controls - Feb 1997
Þ;M Web Magazine @
http://geocities.datacellar.net/SiliconValley/7041/mwm.html
Þ;You are using this program at your own risk
Þ;
ÞWRITE /CUP(12,39),"W"
ÞH 2
ÞWRITE "W"
ÞH 2
ÞWRITE "W"
ÞH 2
ÞWRITE /BS
ÞH 2
ÞWRITE "M"
ÞH 2
ÞWRITE /BS
ÞH 2
ÞWRITE /BS
ÞH 2
ÞWRITE /BS
ÞH 2
ÞWRITE "M"
ÞH 2
ÞQUIT
The program above introduces the mnemonic /BS (Backspace) with a small, yet cute example.
Dry Run
We already talked about how important dry running techniques are in helping you understand a program and also in enhancing your knowledge of programming. Although many people associate dry running techniques with computed algorithms, leaning how to interpret formatting can be helpful because, eventually, you will be able to visualize a screen layout and will find it relatively easy to convert the memory picture into M. Since screens are many-a-times dynamically updated you should equip yourself with the following materials to get you going: light pencil, an eraser and grid paper. The gird paper should be boxed 80x24 with each box sufficiently large to allow you to write a character. The pencil and eraser to clear characters as they are erased from the screen. There are standard techniques on how to mark a screen-layout forms (as they are called) and well be discussing them below.
Modularity
RTN001Þ
;Program demonstrates procedure calls - May 1997
Þ;M Web Magazine @
http://geocities.datacellar.net/SiliconValley/7041/mwm.html
Þ;You are using this program at your own risk
Þ;
GETNMEÞ
;Procedure asks user to enter member's name and checks for a NULL
(empty) string
ÞW #,/CUP(24,1),"Enter Member's Name and
Surname"
ÞW /CUP(2,5),"Details:" R
/CUP(2,30),WHO ;Get Actual Details
ÞW /CUP(24,1),/EL(2) ;Clear Line 24
ÞI WHO="" W
/BEL,/CUP(23,1),"This field cannot be left blank" R
*ERR W /CUP(23,1),/EL(2) G GETNME
GETAGEÞ;Member
Age must be below 18
ÞW /CUP(24,1),"Enter age as at last
birthday"
ÞW /CUP(4,5),/EL(0),"Age:"
ÞR /CUP(4,30),AGE
ÞW /CUP(24,1),/EL(2)
ÞI AGE>17 W /BEL,/CUP(23,1),"This
person is too old" R *ERR W /CUP(23,1),/EL(2) G GETAGE
ÞW /BEL,/CUP(23,1),"Thank You" R
*ERR W /CUP(23,1),/EL(2)
ÞQ
Up to now all our programs have been written as one block as demonstrated by RTN001. Do appreciate that this is a small program but we will be using it to demonstrate the concept of a module. There is nothing theoretically wrong when writing large programs in this manner, but in practice a programmer faces the following hurdles as programs grow larger and more complex:
If an error occurs it may be tedious to trace where the error took place. Suppose we split this program into blocks. We will have one block that takes care of the details and another module handling the age aspect of this input. RTN002 is this program.
RTN002Þ
;Program demonstrates procedure calls - May 1997
Þ;M Web Magazine @
http://geocities.datacellar.net/SiliconValley/7041/mwm.html
Þ;You are using this program at your own risk
Þ;
ÞD GETNME
ÞD GETAGE
ÞW /BEL,/CUP(23,1),"Thank You" R
*ERR W /CUP(23,1),/EL(2)
ÞQ
Þ;*** EOR ***
GETNMEÞ
;Procedure asks user to enter member's name and checks for a NULL
(empty) string
ÞW #,/CUP(24,1),"Enter Member's Name and
Surname"
ÞW /CUP(2,5),"Details:" R
/CUP(2,30),WHO ;Get Actual Details
ÞW /CUP(24,1),/EL(2) ;Clear Line 24
ÞI WHO="" W
/BEL,/CUP(23,1),"This field cannot be left blank" R
*ERR W /CUP(23,1),/EL(2) G GETNME
ÞQ
Þ;*** EOR ***
GETAGEÞ;Member
Age must be below 18
ÞW /CUP(24,1),"Enter age as at last
birthday"
ÞW /CUP(4,5),/EL(0),"Age:"
ÞR /CUP(4,30),AGE
ÞW /CUP(24,1),/EL(2)
ÞI AGE>17 W /BEL,/CUP(23,1),"This
person is too old" R *ERR W /CUP(23,1),/EL(2) G GETAGE
ÞQ
In RTN002 each routine has its own QUIT. A comment marker ;*** EOR *** is used to emphasize the boundary between one area and another. To us, EOR is synonymous with End of Routine, but if you find it more intuitive to use so something else, you can easily replace this string.
Besides GETNME and GETAGE, we also have a third block. This normally lies on top and is implicitly referred to as the MAIN block. MAIN controls all actions and just like the other modules must have its own QUIT. When we D ^RTN002 we start off in MAIN. The keyword to call a module from another is DO.
RTN003Þ
;Program demonstrates procedure calls - May 1997
Þ;M Web Magazine @
http://geocities.datacellar.net/SiliconValley/7041/mwm.html
Þ;You are using this program at your own risk
Þ;
ÞD GETNME
ÞD GETAGE
ÞD SHOWMSG("Thank You")
ÞQ
Þ;*** EOR ***
GETNMEÞ
;Procedure asks user to enter member's name and checks for a NULL
(empty) string
ÞW # D HELPLINE("Enter Member's Name and
Surname")
ÞW /CUP(2,5),"Details:" R
/CUP(2,30),WHO ;Get Actual Details
ÞW /CUP(24,1),/EL(2) ;Clear Line 24
ÞI WHO="" D SHOWMSG("This field
cannot be left blank") G GETNME
ÞQ
Þ;*** EOR ***
GETAGEÞ;Member
Age must be below 18
ÞD HELPLINE("Enter age as at last
birthday")
ÞW /CUP(4,5),/EL(0),"Age:"
ÞR /CUP(4,30),AGE
ÞW /CUP(24,1),/EL(2)
ÞI AGE>17 D SHOWMSG("This person is
too old") G GETAGE
ÞQ
Þ;*** EOR ***
SHOWMSG(MESSAGE)Þ
W /BEL,/CUP(23,1),MESSAGE
ÞR *ERR
ÞW /CUP(23,1),/EL(2)
ÞQ
Þ;*** EOR ***
HELPLINE(MESSAGE)Þ
W /CUP(24,1),MESSAGE
ÞQ
Up to now we have used the terms modules, blocks and routines. Their universal name is Procedures. In RTN003 we have 4 procedures: GETNME, GETAGE, SHOWMSG and HELPLINE. On closer inspection of this program we can observe the following:
- The command to call a procedure is DO (as stated above).
- In M, there need not be any sequencing of procedures, i.e. there is no need for the called module to be below or above the calling module.
- Some procedures take parameters. Parameters allow us to pass one (as in our program) or more values to a procedure. When the procedure is invoked, the value passed is stored inside the parameter and can be utilized as if it where a normal variable. For example, in GETAGE we have D SHOWMSG("This person is too old"). The string literal "This person is too old" will be assigned to the parameter MESSAGE. When SHOWMSG is called from MAIN, the literal is difference and this instance of SHOWMSG will result in a totally different value stored in MESSAGE. This makes procedures a lot more flexible.
- Parameters are only defined while the procedure is invoked. MESSAGE will not exist in the calling module as its instance is destroyed after the procedure terminates. This topic merits further discussion and we will be tackling it in future issue of MWM.
Try writing the variable MESSAGE in MAIN. Did it work? Why?
Adjust the sampling and paint examples to make use of procedures.
Using procedures allows programmers to operate a divide and conquer philosophy. By dividing a program into procedures we can focus on individual blocks rather than have a view of the entire program. Even when developing a large program programmers can start testing individual modules independently before joining everything up. This helps eliminate a lot of errors. You can think about modularity on the same lines as looking through a telescope. The naked eye is great at obtaining an overall picture, but for detail and concentration, nothing beats the lens.
Complete the diagram so that it reflects the operation of RTN003.
Send in thy humor, be it
a joke or a funny picture. If you know of a site with
jokes, send in their URL so that we can ask permission to
publish a joke ourselves, or better still act as our
ambassador.
Address you input to mwm@mcenter.com with the subject line set to MWM Wasted. |