You are probably used to the fact that computers keep permanent information in collections called files. Some systems use other names such as data sets, but they are essentially the same thing. These files have names by which you can identify them to the computer. Programs can read from these collections of information and write to them.
SIMULA has objects called Files as well. When you want to read from or write to a file on your computer, you must use a SIMULA File object to stand for the external file and tell the computer which external file you want. The exact way that this works may vary slightly from one computer to another, but the important points are the same.
In fact a SIMULA File can stand for any source of or destination for information. A printer can also be written to by using a File object to represent it in your programs. A magnetic tape reader can be used as a source of input in the same way.
In fact you have already been using two File objects without being told that that was what you were doing. These are the standard input File, SysIn, and the standard output File, SysOut. Whenever you have used InInt, OutImage and any other input/output instructions you have been using File attributes.
Put more simply, class File defines a type of object with a number of attributes used to access sources of and destinations for information on a computer, such as files, printers, terminals and tape readers.
File class ImageFile is a sub-class of File. It has all the attributes of its parent class File, some of which it redefines, and in addition some extra attributes used to handle information in certain ways.
ImageFile class InFile is a sub-class of ImageFile. It has all the attributes of both File and ImageFile plus extra ones for reading information using the ways suited to ImageFile's attributes.
This probably sounds far from simple on first reading, but the idea of thinking of objects as classes and sub-classes is central to SIMULA and so we use it to describe formally the relationships of the various sub-types of File.
Example 7.1 is a program using an InFile to provide its information. Notice the familiar names used for the same purposes, but now prefixed with a File name.
Example 7.1: Simple input using InFile.
begin ref (InFile) Inf; text T1; Inf :- new InFile("MYRECORDS"); Inf.Open(Blanks(80)); Inf.InImage; T :- Inf.Image; OutText(T); OutImage; OutInt(Inf.InInt); OutImage; Inf.Close endThere are a few new concepts in this program. Let us look at them one by one.
Firstly, we have a new type of declaration. It declares Inf to be a ref variable, but has the word InFile in parentheses between the keyword ref and the identifier Inf. A ref variable is a pointer to an object of a complex type. The class which defines that type is given in parentheses after the keyword ref. Thus Inf is a location which can be used to hold a pointer to an object which is of type InFile. It is initially pointed at an imaginary object called None, just as text variables initially reference NoText.
Inf is pointed at a real object by making a reference assignment to it, using the reference assignment operator, :-. Value assignments are not possible since Inf can only hold a pointer to an object, not the object itself.
In our program Inf is pointed at a new object of the required type by using an object generator as the right hand side of a reference assignment to it. The statement
Inf :- new InFile("MYRECORDS")thus creates a new InFile type object and points Inf at it. When an object is created in this way one or more parameters may be passed to it, depending on its type.
InFile demands a text value parameter. In fact this parameter is demanded by the grandparent class File and must be given to all new objects whose type is a sub-class of File. This parameter provides the link between the SIMULA InFile object and the file or device on the actual computer which it will represent inside the program. The exact way in which this text is interpreted on any particular computer and its meaning to that computer varies considerably and you should consult the Users' Guide or Programmer's Reference Manual for the system you are using.
In principle the statement is saying that an InFile object which is initially pointed at (or referenced) by Inf will be used in this program to represent some source of input on the computer where the program is to run. The string "MYRECORDS" identifies to that computer the actual source to be used in a way which that computer can understand.
Having created the InFile object the program then prepares it for use by calling the procedure Open, which is an attribute of InFile and so is specified by the prefix "Inf.". This also takes a parameter, in this case a text reference parameter, which must reference a variable text frame. This text frame will be used to hold the input read from the source. The parameter is reference assigned to a text attribute of ImageFile called Image.
Most of the rest of the program should be familiar, except for the prefixing of InImage and InInt by Inf. This tells the SIMULA system to read from the source associated with Inf rather than the standard input, as in our previous programs.
The final statement calls the procedure Close, to tell the SIMULA system that this File is not required until Open is called for it again.
Example 7.2 is a simple example of the use of OutFile. It corresponds to the InFile example fairly closely and so no further explanation is given yet.
Example 7.2: Simple output using OutFile.
begin ref (OutFile) Outf; Outf :- new OutFile("MYSTORAGE"); Outf.Open(Blanks(132)); Outf.OutText("This goes to a File"); Outf.OutImage; Outf.OutInt(43,3); Outf.OutImage; Outf.Close end
7.1 Write a program which prints the integer values 1, 2, 3 and 4 to an OutFile. Check what sort of File your system has created on the computer. See if you are able to examine its contents and list them to a printer.
7.2 Write a program which reads the contents of the File produced in 7.1, using an InFile, and writes it to the terminal or batch output stream.
Image is a text variable within the ImageFile object. In an InFile, the parameter passed to Open is used initially as its Image, i.e. is assigned by reference to Image. This is usually an anonymous text created by giving the text generator Blanks as the parameter to Open. The number given as parameter to Blanks determines the length of Image and should match the record or line length of the external file or device. Where the external record length is not fixed, the length of Image should be the maximum record length possible or expected.
Older systems will have Open as a type-less procedure and attempting to open a file which is not available will cause a runtime error on these systems.
If Open succeeds, it will reserve the file or device for future use as a source of input by the program. It is not possible to write to an InFile.
Open also assigns its text reference parameter to Image, creating a "buffer" text into which all records from the external file or device will be read. It is possible to assign a new text as Image later in the program.
A successful call on Open will return the value True.
Older systems may not have IsOpen as a File attribute.
All SIMULA systems which meet the current standard will allow files with the following properties.
Mode | File type is | Affects | ||
---|---|---|---|---|
In- | Out- | Direct- | ||
Shared | shared | noshared | noshared | Open |
Append | N/A | noappend | noappend | Open |
Create | N/A | anycreate | nocreate | Open |
Readwrite | N/A | N/A | readwrite | Open |
Bytesize:n | * | * | * | Open |
Rewind | norewind | norewind | N/A | Open/Close |
Purge | nopurge | nopurge | nopurge | Close |
In the first case InRecord copies it into the start of Image, but leaves the rest of Image's text frame unchanged. Image.Pos will be set to the point to the first unchanged character. In this case InRecord returns false.
Where the external record is longer than Image, only enough is read in to fill Image. In this case InRecord returns true, indicating that a further call will read in the missing part of the current Image, not a new record.
Where the lengths are the same InRecord acts exactly as InImage, but returns false.
If Close is unable to perform its task, it returns false. Otherwise it returns true. Older systems will only have Close as a type-less procedure.
If a File is left open at the end of a program, it will be closed by the runtime system, with a warning in most systems. It is safer to close files in the program.
Example 7.3 shows of the use of EndFile to read and print the whole of a record structured File.
Once the last record of the real file is read in by InImage, a further call will assign the ISO end of file character, !25!, as the first character of Image. EndFile now returns the value True. Example 7.3 uses the new keyword not, which reverses the condition being tested. Thus the while loop is performed as long as Inf.EndFile is not True.
Example 7.3: Use of EndFile.
begin ref (InFile) Inf; Inf :- new InFile("Source"); if Inf.Open(Blanks(80)) then ! Assumes no records longer than 80; begin ! Use Open as a Boolean procedure in case File not there; while not Inf.EndFile do begin Inf.InImage; OutText(Inf.Image); OutImage end; Inf.Close end end
Example 7.4 is a word counting program which uses LastItem.
Example 7.4: Use of LastItem in word counting.
begin ref (InFile) Words; integer WordCount; text ThisWord; Boolean ThisisFirstSpace; character Item; Words :- new InFile("LATESTPAPER"); Words.Open(Blanks(132)); ! Assume line length of 132; ThisisFirstSpace := True; ThisWord :- Blanks(132); while not Words.LastItem do begin while Words.More do begin Item := Words.Image.GetChar; if Item ne ' ' then begin ThisisFirstSpace := True; ThisWord.PutChar(Item); end else if ThisisFirstSpace then begin ThisisFirstSpace := False; OutText(ThisWord.Strip); ThisWord :- Blanks(132); OutText(" "); WordCount := WordCount + 1 end--of--a--word; end--of--a--line; if ThisisFirstSpace then begin WordCount := WordCount + 1; OutText(ThisWord); ThisWord :- Blanks(132) end; OutImage; OutText(" ### Words so far = "); OutInt(WordCount,6); OutImage; end--of--word--counting--loop; OutText("Total word count is "); OutInt(WordCount,6); OutImage; Words.Close end begin
Since SIMULA specifies that a call on InImage once the last record of the real File has been read will place the ISO end of file character, !25!, as the first in Image. A call on InChar once the last character of the real file has been read will return this non-printing character and EndFile will then return True. If the end of the File has been reached, i.e. EndFile returns True, a call on InImage will cause a runtime error. We can rewrite our word counting program, using InChar to replace Image.GetChar, as shown in example 7.5.
Example 7.5: LastItem and InChar in word counting.
begin ref (InFile) Words; integer WordCount; text ThisWord; Boolean ThisisFirstSpace; character Item; Words :- new InFile("LATESTPAPER"); Words.Open(Blanks(132)); ! Assume line length of 132; ThisisFirstSpace := True; ThisWord :- Blanks(132); while not Words.LastItem do begin while Words.More do begin Item := Words.InChar; if Item ne ' ' then begin ThisisFirstSpace := True; ThisWord.PutChar(Item); end else if ThisisFirstSpace then begin ThisisFirstSpace := False; OutText(ThisWord.Strip); ThisWord :- Blanks(132); OutText(" "); WordCount := WordCount + 1 end--of--a--word; end--of--a--line; if ThisisFirstSpace then begin WordCount := WordCount + 1; OutText(ThisWord); ThisWord :- Blanks(132) end; OutImage; OutText(" ### Words so far = "); OutInt(WordCount,6); OutImage; end--of--word--counting--loop; OutText("Total word count is "); OutInt(WordCount,6); OutImage; Words.Close end begin
Example 7.6 is a new line splitting program, using InText. Note that it assumes an input file with lines 132 characters long. Note also that it does not deal with blanks at the end of Image.
Example 7.6: Line splitting with InText.
begin ref(InFile) OldLines; OldLines:- new InFile("MANUSCRIPT"); OldLines.Open(Blanks (132)); while not OldLines.EndFile do begin OutText (OldLines.InText (80)); OutImage end; OldLines.Close end
Image is then filled with spaces as if by
Image :- Blanks (Image.Length);
Older systems will not have OutRecord.
It is intended to allow prompts to be displayed on interactive terminals, in a manner that allows input to be typed on the same line.
Where an operating system does not support output without line terminators, BreakOutImage is exactly equivalent to OutRecord. Older systems will not have BreakOutImage.
Again, files will be closed automatically at the end of the program, although it is tidier and safer to close them in the program.
This means that the programs 7.7 a, b and c are equivalent.
It is much safer to call OutImage and Close explicitly, when they are needed. Consider the effect of extending the program to do further writing to Out1, if you are depending on the end of the program to output the Image containing "SUCCESS".
Example 7.7a.
begin ref(OutFile) Out1; Out1:- new OutFile ("DESTINATION"); if Out1.Open (Blanks (132)) then begin Out1.OutText ("SUCCESS"); Out1.OutImage; Out1.Close end else begin OutText ("File DESTINATION could not be opened"); OutImage end endExample 7.7b.
begin ref(OutFile)Out1; Out1:-new OutFile("DESTINATION"); if Out1.Open(Blanks (132)) then begin Out1.OutText("SUCCESS"); Out1.OutImage ; COMMENT do not call Out1.Close; end else begin OutText("File DESTINATION could not be opened"); OutImage end endExample 7.7c.
begin ref(OutFile)Out1; Out1:-new OutFile("DESTINATION"); if Out1.Open(Blanks (132)) then begin Out1.OutText("SUCCESS"); COMMENT do not call Out1.OutImage or Out1.Close; end else begin OutText("File DESTINATION could not be opened"); COMMENT do not call OutImage; end end
7.4 Write a program to remove blank lines from a file, producing a new file.
7.5 Write a program which reads a file with no blank lines and produces a double spaced copy, i.e. a file with a blank line between each line of its contents.
7.6 Write a program which asks for the following information:
input file; output file; line spacing (double/single); multiple space removal required?; word count wanted?; number of spaces after full stop; number of spaces after comma;and then copies the input file to the output file in the required format.
The attributes of PrintFile are designed for output with a maximum number of lines on each page. The length of each line will depend on Image.Length. Printing of lines can be set to be double or multiple spaced.
Some of the attributes of OutFile are redefined to allow for this page oriented output. It is a feature of classes in SIMULA, that an attribute of a class can be redeclared with a different meaning in a sub-class. The meaning in the sub-class is then used for objects which are referred to as being of the sub-class.
Only those attributes of PrintFile which are not in OutFile or which are redefined in PrintFile are listed here. All the other attributes of OutFile exist for PrintFile.
During execution of a program, this number can be reset to fit the printer or paper being used, by calling the procedure LinesPerPage, which has a single integer value parameter. The value of the parameter sets a new maximum number of lines per page.
A value of zero resets the default. A negative value indicates continous printing without page breaks. A positive value is the new number of lines per page.
Example 7.8 writes pages containing only ten lines. Try it and see the effect when you list the output to a printer. (Not all terminals behave like printers and so the effect may not show up if you use one as your output device). In recent SIMULA systems LinesPerPage is an integer procedure returning the value prior to this call. Older will have it as a type-less procedure.
Example 7.8: Small pages using a PrintFile.
begin ref(PrintFile) Printer; ref(InFile) Source; Printer:- new PrintFile ("LP23"); Source:- new InFile ("MYTEXT"); Printer.Open (Blanks (80)); ! Sets line length; Source.Open (Blanks (80)); Printer.LinesPerPage (10); while not Source.EndFile do begin Source.InImage; Printer.OutText (SOURCE.Image); Printer.OutImage end; Printer.Close; Source.Close end
Example 7.9 shows the effect of Spacing.
Example 7.9: The effect of Spacing in PrintFile.
begin ref(PrintFile) Prnt1; Prnt1:- new PrintFile ("Out1"); Prnt1.Open (Blanks (132)); Prnt1.OutText ("LINE 1"); Prnt1.OutImage; Prnt1.OutText ("LINE 2"); Prnt1.OutImage; Prnt1.Spacing (2); Prnt1.OutText ("LINE 3"); Prnt1.OutImage; Prnt1.Spacing (3); Prnt1.OutText ("LINE 4"); Prnt1.OutImage; Prnt1.OutText ("LINE 5"); Prnt1.OutImage; Prnt1.Close end
Example 7.10: Legal variations of Eject in PrintFile.
begin ref(PrintFile) Prnt2; Prnt2:- new PrintFile ("OUT2"); Prnt2.Open (Blanks (132)); Prnt2.LinesPerPage (20); Prnt2.OutText ("LINE 1"); Prnt2.OutImage; Prnt2.Eject (10); ! Greater than current Line; Prnt2.OutText ("LINE 2"); Prnt2.OutImage; Prnt2.Eject (6); ! Less than current Line; Prnt2.OutText ("LINE 3"); Prnt2.OutImage; Prnt2.Eject (7); ! Equal to current line; Prnt2.OutText ("LINE 4"); Prnt2.OutImage; Prnt2.Eject (30); ! Greater than LinesPerPage; Prnt2.OutText ("LINE 5"); Prnt2.OutImage; Prnt2.Close end
Prnt2.OutImage; Prnt2.Eject(30)etc. when the prefixing name is always Prnt2. SIMULA allows a shorthand, known as an inspect statement. This may not be used for prefixes which are text identifiers, however, since text is not defined as a class, but is a special type on its own.
The following statements are equivalent for the purposes described here.
Prnt2.OutImage inspect Prnt2 do OutImageObviously, the new form is longer for this simple case, but consider the syntax of this inspect statement. There is the keyword inspect, followed by an identifier referencing an object, followed by the keyword do, followed by a statement.
The semantic rule for an inspect statement is that any use of an attribute of the referenced object (i.e. the one whose identifier appears between inspect and do) inside the statement following do is not required to be prefixed by the identifier and a dot.
If we use a compound statement or block as the statement following do, we can save a lot of tedious writing. Thus, programs 7.11 a and b are exactly equivalent.
Where we want to use more than one object we are allowed to use nested inspect statements. In other words we can use another inspect statement as the statement following the do. This is shown by example 7.12.
Examples 7.11: Use of simple inspect. 7.11a.
begin ref (PrintFile) P1; P1:- new PrintFile ("OUT"); P1.Open (Blanks (80)); P1.OutText ("Message"); P1.OutInt (2,3); P1.OutImage; P1.Close end7.11b.
begin ref (PrintFile) P1; P1:- new PrintFile ("OUT"); inspect P1 do begin Open (Blanks (80)); OutText ("Message"); OutInt (2,3); OutImage; Close end endExample 7.12: Nested inspect statements.
begin ref(PrintFile) P1; ref(InFile) I1; P1:-new PrintFile ("OUT"); I1:-new InFile ("IN1"); inspect P1 do inspect I1 do begin P1.Open (Blanks (132)); ! Needs P1; Open (Blanks (80)); ! refers to I1; InImage; ! Can only refer to I1; OutText (Image); ! OutText is P1, Image is I1; OutImage; ! Can only be P1; Close; ! refers to I1; P1.Close; ! Needs P1; end*of*inspect*I1; endNotice that all attributes are taken to be of I1, which is the innermost object inspected, if they might be of P1 as well. Thus, when P1 is opened, we must use P1.Open explicitly, whereas I1 only requires Open, with no prefix. Where an attribute only exists in one of the objects there is no ambiguity. For instance, OutImage does not exist for the InFile, I1, but does exist for the PrintFile, P1.
The default input device is accessed through a system InFile referred to as SysIn. The default output device is accessed through a system PrintFile referred to as SysOut.
The program block of a SIMULA program acts as if it were inside a nested inspect statement. This would look as follows:
inspect SysIn do inspect SysOut do begin ...... ...... ...... ...... endSysOut is defined, not as a ref(PrintFile) variable, but as a ref(PrintFile) procedure.
This means that you cannot assign another File to be SysOut during your programs. Similarly, SysIn is defined as a ref(InFile) procedure.
This is not as complex as it may sound. The implications are roughly as follow:
We have looked especially at "record oriented" input and output, based on File class ImageFile.
We have seen the idea of a class and a sub-class.
We have looked at the attributes of three sub-classes of ImageFile, namely InFile, OutFile and PrintFile.
We have seen the use of inspect statements as an alternative to dot notation for accessing attributes of objects, when the object is not a text.
We have seen the way in which SysIn and SysOut provide default input and output devices.