All Modula-2 programs must have the general form shown in the sample above. The word MODULE comes first, followed by some descriptive name. If there are any IMPORT commands, these come next. The words BEGIN and END (which must be all in upper case) mark off the block of actual program instructions or statements. They serve more or less as parentheses, even though they are spelled out as words. There may be several such blocks opened and closed in this manner throughout a program (more on this later), but it is important to note that this main one must end with a period, and that any block that has a name such as HiThere as this one does must have that name mentioned again just after the corresponding END. Note the following definition:
A statement is an instruction directing a computer to take some action. It usually is written out in a high level notation for subsequent translation by the computer into one or more low level instructions and their corresponding actions.
The semicolons between statements are not optional, except before an END marker. They separate the statements from each other, in effect telling the computer that one instruction is finished and that it is time to start another one. As indicated, an END marker is not a statement, but punctuation, so the semicolon can be left out before it.
There are far more complex programs, but this one, perhaps the simplest that actually does something, is a start. In the short sections that follow, some aspects of this program are analyzed in detail.
This section considers the first word of the sample program, a word that every program will have at or near the beginning.
A Module is a container to hold the items and information that constitute all or part of an executable program.
Obviously, this thing called a module is important. It doesn't take much deep thinking to realize that the whole Modula-2 programming notation is named after it. Unfortunately, this initial attempt at a description does not tell the whole story about modules, and a complete description must wait until later in this book. It will have to suffice for now to say that a program is a module, and that there are other modules available in the system from which we can import things (like WriteString) that may be useful to us. For instance, if all the entities mentioned below actually existed, this too would be a legitimate program:
MODULE Lunch; FROM LunchBag IMPORT sandwich, apple, Eat; BEGIN Eat (sandwich); Eat (apple); END Lunch.
Here, the modules are Lunch and LunchBag, while sandwich and apple are evidently some sort of entities that can be acted upon, and Eat is some kind of procedure (like WriteString) that causes an action to take place. The term procedure will be defined more carefully later.
Certain special punctuation markers in the sample program are capitalized (and printed in bold for emphasis.) All such special symbols were defined and reserved for a particular purpose by Niklaus Wirth when he first designed Modula-2. Every programming notation has such symbols and uses them in much the same way as does Modula-2.
A Modula-2 reserved word is a special word or marker used to outline the structure of a program. It must be entirely written in upper case letters, and it cannot be used for any other purpose.
The reserved words encountered in the sample program were: MODULE, BEGIN, FROM, IMPORT, and END. Others will be encountered later, and each one will be pointed out as a reserved word when it first occurs in an example. A complete list can be found in Appendix 1.
Other items (such as WriteString) are imported from a pre-existing library, and can also be thought of as being, in some sense, a standard part of every Modula-2 system. Many modern programming notations share this concept; it is not unique to Modula-2.
A Modula-2 Standard Library Item is an entity that can be found by a particular name and in a specified library in every implementation of standard Modula-2.
When Niklaus Wirth defined the Modula-2 notation, he included a few sample or suggested library modules along with his definition of the language proper. Many of these, and their entire contents, have been adopted and used for a wide variety of Modula-2 versions and constitute a de facto standard for Modula-2 libraries. There is also a de jure international standard specified by the International Organization for Standards (ISO) for Modula-2, and it also specifies certain (different) libraries that are required to accompany any implementation designated as standard under its terms.
Most implementors follow (or at least include) material from the de facto standard suggested by Wirth. Others have adopted the ISO modules for standard Modula-2 (though that is new), and still others ignore both and design libraries as they see fit. For this reason, the name of typical imported procedures (such as WriteString) may vary, and so may the name of the library module from which they are imported. In this text, the ISO standard for Modula-2 will be used for most programs, and any that use other libraries will be noted.
NOTE: There are also language differences between Wirth's definition of Modula-2 and the ISO definition. There are even some between different editions of Programming in Modula-2. These too will be observed in the context where they are relevant.
In the examples above, each module had a name. This is required both in the MODULE heading and in its corresponding END. However, not only modules have names. In fact, there are many other entities in a typical program that also have to be identified in this manner. (There were some in the last example.)
For instance, if one wanted to write code using a formula like:
a = b + c ( in Modula-2 it is a := b + c)
then a, b, and c must all be names for program entities (variable names.) One could call them number1, number2, and number3, or any other name--provided that the name is legal in Modula-2.
The technical term for such names is identifier. It is important to know the rules that must be followed for creating identifiers.
A Modula-2 identifier is a sequence of non-blank letters or digits beginning with a letter.
This definition is illustrated in Figure 2.2 by what is sometimes termed a railroad diagram. The arrows indicate the sequence of symbols or characters that define an identifier.
The alternate path, or loop shows clearly that, after an initial letter, any sequence of letters and numbers is permitted. Notice that the definition not only excludes blanks, but also any special symbols, such as +, -, /, $, %. To conform with past practice in other languages, or with the requirements of other software on the system, some versions of Modula-2 may allow the dollar symbol, spaces and/or some of these other symbols that are supposed to be forbidden. In this book, "plain vanilla" rules will be followed in such matters, and such compromises will be ignored.
NOTE: In ISO standard Modula-2 the low-line (also sometimes called an underscore) is counted as a letter. This was done to conform to the practice in Pascal. However, it is easier to type and to read, say, SideOfSquare than side_of_square, so the former style will be used exclusively in this texts. Programmers are urged to avoid the use of low-lines in identifiers unless these are absolutely necessary to conform to some local practices over which they have no control.
Here are a few examples of identifiers:
|Compound Interest||(has a blank)|
|23Skidoo||(does not start with a letter)|
Permitted in ISO standard, but very poor style:
this__longer___identifier (how many low-lines are there?
Although the definition itself does not make this clear, there is also a distinction made between upper case and lower case letters. Consider the following examples:
These are Different:
Help, help, HELP, HeLP, etc.
BEGIN, Begin (the first is a reserved system word)
NOTE: As the second-to-last example shows, it is essential to type every identifier or command with the correct (consistent) upper case or lower case letters. Do not type Writestring or writestring instead of WriteString, for example.
In some implementations of Modula-2, the last two in this list of examples might not actually be interpreted as different by other parts of the system, even if they are by the language. For instance, in dealing with file names on the disk or other external device, only the first eight or ten (or some other number) of characters may be checked. Operating systems, and notations other than Modula-2 may recognize only upper case letters, or treat upper case and lower case versions of a letter as the same. These peculiarities are holdovers from days when computer terminals had only upper case letters on their keyboards. They apply only when sending such information to the operating system, not within the program.
NOTE: 1. As previously indicated, words like MODULE, BEGIN, END, FROM, and IMPORT are reserved words, and cannot be used as identifiers.
2. Other words are also already taken. They too are entirely capitalized and are called standard identifiers. (See section 2.5.2 for a full discussion.) Still others may be commonly imported identifiers (such as WriteString.) It would be unwise to use these as names for something else, even though you may get away with it.
3. There is a certain style or taste to the matter of appropriate capitalization of identifiers. Specific rules shall be outlined later; for now, imitate.
The sample program contained the line:
WriteString ("Hello Master, how may I serve you?")
The portion between the double quotes is called a literal string and the effect of this particular statement will be to write out the characters between the quotes onto the computer's main output device (usually a screen, but sometimes a printer).
A literal string is a sequence of characters that is enclosed between either single quotes or double quotes.
Here are some examples of literal strings:
"How are you doing today?" 'Do you think "hello" is the correct word?' "Don't you like tea?" "Your mark is 100%." 'What a nice day!' "He said 'Hi there!' to me yesterday." 'The distance between studs is 16".'
Notice that if the string contains a single quote (apostrophe) it must be in double quotes and if it contains double quotes it must be enclosed in single quotes. No string can contain both single and double quotes, but there are no other restrictions on the characters it contains, except that it cannot contain a carriage return.
WriteString ("This is an example of an illegal string, because it is too long to fit on one line of the original text form of the program.")
Here is how to do this legally:
WriteString ("This one is better because it ") WriteString ("has been broken up into pieces, ") WriteString ("each of a more manageable size.")
Notice the spaces at the end of each of the first two literals in this last example. These are needed to ensure that the words in the successive strings will in fact be separated from one another in the output as it is printed on the screen (or elsewhere). This does not, however, solve another problem--if one writes several strings like these one after another, the computer will perform a carriage return of its own when it gets to the end of a line on the screen.
A carriage return is an action taken by an output device such as a screen or printer that causes the printing position for the next character to be placed at the beginning of a new line.
This could be right in the middle of a word. In fact, if one had a 40 column screen, the output from this last example would be:
This one is better because it has been b roken up into pieces, each of a more man ageable size.
To prevent this, the programmer inserts carriage returns in the correct places (between words) by using the WriteLn statement. The output in the next two examples has been formatted in this way.
Here's the same one again:
WriteString ("This one is better because it "); WriteLn; WriteString ("has been broken up into pieces, "); WriteLn; WriteString ("each of a more manageable size."); WriteLn;
The purpose of WriteLn is to reposition the cursor (the next character location) to the beginning of the next line. Here's another example--this time a complete Module.
MODULE Notice; FROM STextIO IMPORT WriteString, WriteLn; BEGIN WriteString ("* * * * * * * * * *"); WriteLn; WriteString ("* This Program *"); WriteLn; WriteString ("* * Copyright * *"); WriteLn; WriteString ("* * * 2005 * * *"); WriteLn; WriteString ("* * * * by * * * *"); WriteLn; WriteString ("* Nellie Hacker *"); WriteLn; WriteString ("* * * * * * * * * *"); WriteLn; END Notice.
The output from this program is:
* * * * * * * * * * * This Program * * * Copyright * * * * * 2005 * * * * * * * by * * * * * Nellie Hacker * * * * * * * * * * *
NOTES: 1. It is a good idea to use a WriteLn after the last actual output of text to ensure that the cursor is correctly positioned for the next output.
2. If WriteString is imported from another place than STextIO, say from InOut, then is also WriteLn.
The railroad diagram in figures 2.3 and 2.4 summarize the discussions of syntax (correct structure) of a module as discussed thus far.
These diagrams are more complex than Figure 2.2, with necessary reserved words or symbols in circles and ovals and the parts supplied by the programmer in boxes. Notice that the diagram places no limit on the number of import lists or statements.
NOTE: Neither of these diagrams is complete. More will be added to both later in the text. Complete versions are in Appendix 2.