Chapter 9

[*]Ex 9.1
   PROGRAM ex9 1 CONTEXT VOID
   USE standard
   BEGIN
      FILE f;
      IF   open(f,
                "textbook",
                stand in channel)/=0
      THEN
         print("Cannot open textbook");
         exit(1)
      FI;

      STRING s;
      WHILE get(f,(s,newline));  UPB s /= 0
      DO
         print((s,newline))
      OD;

      close(f)
   END
   FINISH
[*]Ex 9.2
   PROGRAM ex9 2 CONTEXT VOID
   USE standard
   BEGIN
      FILE f;

      IF   open(f,
                "textbook",
                stand in channel)/=0
      THEN
         print("Cannot open textbook");
         exit(1)
      FI;

      REAL r, sum:=0, INT n;  get(f,n);

      TO n DO get(f,r); sum+:=r OD;
      print(sum);  close(f)
   END
   FINISH

[*]Ex 9.3
   PROGRAM ex9 3 CONTEXT VOID
   USE standard
   BEGIN
      FILE inf,outf;

      IF   open(inf,
                "textbook",
                stand in channel)/=0
      THEN
         print("cannot open textbook");
         exit(1)
      ELIF establish(outf,
                     "result",
                     stand out channel,
                     0,0,0)/=0
      THEN
         print("Cannot create result");
         exit(2)
      FI;

      REAL sum:=0, r, INT n;

      get(inf,n);
      TO n
      DO
         get(inf,r);  sum+:=r
      OD;
      put(outf,sum);
      close(inf);  close(outf)
   END
   FINISH
[*]Ex 9.4
Note that in this answer, you will have to find some means of obviating the a68toc bug for the BY construct.
   PROGRAM ex9 4 CONTEXT VOID
   USE standard
   BEGIN
      INT size = 10 000;
      [2:size]BOOL flags;

      FOR i
      FROM LWB flags TO UPB flags
      DO flags[i]:=TRUE OD;

      FOR i
      FROM LWB flags TO UPB flags
      DO
         IF flags[i]
         THEN
            FOR k
            FROM i+i BY --i TO UPB flags
            DO
               flags[k]:=FALSE
            OD
         FI
      OD;

      #Now the file is needed#
      FILE f;
      IF   establish(f,
                     "primes",
                      stand out channel,
                      0,0,0)/=0
      THEN
         print("Cannot create primes");
         exit(1)
      FI;

      FOR i FROM LWB flags TO UPB flags
      DO
         IF flags[i]
         THEN put(f,(i,newline))
         FI
      OD;

      close(f)
   END
   FINISH

[*]Ex 9.5
Notice that the processing of a line is done entirely within the WHILE clause.
   PROGRAM ex9 5 CONTEXT VOID
   USE standard
   BEGIN
      FILE inf, outf;

      IF   open(inf,
                "inbook",
                stand in channel)/=0
      THEN
         print("Cannot open inbook");
         exit(1)
      ELIF establish(outf,
                     "outbook",
                     stand out channel,
                     0,0,0)/=0
      THEN
         print("Cannot create outbook");
         exit(2)
      FI;

      STRING line;

      WHILE
         get(inf,(line,newline));
         put(outf,(line,newline));
         IF UPB line = 0
         THEN FALSE
         ELSE line /= UPB line * blank
         FI
      DO SKIP OD;

      close(inf);  close(outf)
   END
   FINISH
[*]Ex 9.6
   PROGRAM ex9 6 CONTEXT VOID
   USE transput
   BEGIN
      FILE inf, outf;

      IF   open(inf,
                "lines",
                stand in channel)/=0
      THEN
         print("Cannot open book lines");
         exit(1)
      ELIF establish(outf,
                     "words",
                     stand out channel,
                     0,0,0)/=0
      THEN
         print("Cannot create book words");
         exit(2)
      FI;

      []CHAR terminators=" *"+cr+lf;
      make term(inf,terminators);

      STRING word, CHAR ch:=blank;

      WHILE
         get(inf,word);
         IF ch/=blank
         THEN ch PLUSTO word
         FI;

         WHILE
            get(inf,ch);
         CO String terminator,
            but cr/lf ignored CO
            ch = blank
         DO SKIP OD;  #Skip spaces#
         put(outf,(word,newline));
         ch /= "*"
      DO SKIP OD;

      close(inf);  close(outf)
   END
   FINISH

[*]Ex 9.7
If the on logical file end procedure yields
FALSE, the standard prelude causes an error message to be displayed and the program itself exits with an equivalent error number. Here is the code for the program:-
   PROGRAM ex9 7 CONTEXT VOID
   USE standard
   IF FILE inf;
      STRING line;  INT n,sum:=0;
      open(inf,
           "inbook",
            stand in channel)/=0
   THEN
      print(("Cannot open inbook",
             newline));
      exit(1)
   ELSE
      on logical file end(inf,
       (REF FILE f)BOOL:
         IF FILE ouf;
            establish(ouf,
                      "outbook",
                      stand out channel,
                      0,0,0)/=0
         THEN
            print(("Cannot establish ",
                   "outbook",newline));
            exit(2); SKIP
         ELSE
            put(ouf,(sum/n,newline));
            close(ouf);  FALSE
         FI);

      FOR i
      DO
         get(inf,(line,newline));
         n:=i;  sum+:=UPB line
      OD
   FI
   FINISH

[*]Ex 9.8
In the following solution, note how skip terminators is called immediately after reading the first argument (the full path of the program):-
   PROGRAM ex9 8 CONTEXT VOID
   USE standard
   IF FILE arg, inf, ouf;
      STRING line, infn, oufn;
      INT n,sum:=0;

      open(arg,"",arg channel)/=0
   THEN
      put(stand error,
          ("Cannot access the ",
           "program arguments",
           newline));
        exit(1)
   ELIF
      on logical file end(arg,
       (REF FILE f)BOOL:
        (put(stand error,
             ("Insufficient arguments",
              newline));
         stop;  SKIP));
      get(arg,(LOC STRING,skip terminators,
               infn,skip terminators,
                oufn));
      open(inf,infn,stand in channel)/=0
   THEN
      print(("Cannot open ",infn,newline));
      exit(2)
   ELSE
      on logical file end(inf,
       (REF FILE f)BOOL:
        IF establish(ouf,
                     oufn,
                     stand out channel,
                     0,0,0)/=0
        THEN
           print(("Cannot establish ",
                  oufn,
                  newline));
           exit(3); SKIP
        ELSE
           put(ouf,("Average=",sum/n,
                    newline));
           close(ouf);
           FALSE
        FI);

      FOR i
      DO
         get(inf,(line,newline));
         n:=i;  sum+:=UPB line
      OD
   FI
   FINISH
[*]Ex 9.9
Notice that the physical file end of the output file has also been covered:-
   PROGRAM ex9 9 CONTEXT VOID
   USE standard
   IF FILE arg, inf, ouf;
      STRING line, infn, oufn;
      open(arg,"",arg channel)/=0
   THEN
      put(stand error,
          ("Cannot access the arguments",
           newline));
      exit(1)
   ELIF
      on logical file end(arg,
       (REF FILE f)BOOL:
        (put(stand error,
             ("Insufficient arguments",
              newline));  stop;  SKIP));
      get(arg,(LOC STRING,
               skip terminators,
               infn,skip terminators,
               oufn));
      open(inf,infn,stand in channel)/=0
   THEN
      print(("Cannot open ",infn,newline));
      exit(2)
   ELIF
      establish(ouf,
                oufn,
                stand out channel,
                0,0,0)/=0
   THEN
      print(("Cannot establish ",oufn,
             newline));
             exit(3)
   ELSE
      on logical file end(inf,
       (REF FILE f)BOOL:
        (close(ouf);  close(inf);
         stop;  SKIP));
      on physical file end(ouf,
       (REF FILE f)BOOL:
        (put(stand error,
             ("Write error on ",idf(ouf),
              newline));
         exit(4); SKIP));
      DO
         get(inf,(line,newline));
         FOR i FROM LWB line TO UPB line
         DO
            REF CHAR li=line[i];
            IF li=blank THEN li:="*" FI
         OD;
         put(ouf,(line,newline))
      OD
   FI
   FINISH

[*]Ex 9.10
    PROGRAM ex9 10 CONTEXT VOID
    USE standard
    IF FILE env;
       open(env,"PATH",env channel)=0
    THEN
       on logical file end(env,
        (REF FILE e)BOOL: (stop; SKIP));
       make term(env,":"+nul ch);
       STRING s;
       DO
          get(env,s);
          IF UPB s >= LWB s
          THEN print((s,newline))
          FI;
          skip delimiters(env)
       OD;
       close(env)
    FI
    FINISH
[*]Ex 9.11
   PROGRAM ex9 11 CONTEXT VOID
   USE standard
   IF FILE arg;
      open(arg,"",arg channel)/=0
   THEN
      put(stand error,
          ("Cannot access arguments",
           newline));
      exit(1)
   ELSE
      on logical file end(arg,
       (REF FILE a)BOOL: (stop;  SKIP));
      get(arg,(LOC STRING,
               LOC CHAR,
               skip terminators));
      DO
         make term(arg,"/");
         STRING env name;
         CHAR terminator:=nul ch;
         get(arg,
             (env name,
              skip terminators,
              terminator));
         IF FILE env;
            open(env,
                 env name,
                 env channel)/=0
         THEN
            print((env name," undefined",
                   newline))
         ELSE
            make term(env,
                      terminator+nul ch);
            STRING s;
            on logical file end(
               env,
               (REF FILE f)BOOL:
                 (GOTO continue; SKIP));
            DO
               get(env,s);
               IF UPB s >= LWB s
               THEN print((s,newline))
               FI;
               skip terminators(env)
            OD;
            continue:
            close(env)
         FI;
         make term(arg,blank);
         skip terminators(arg)
      OD
   FI
   FINISH
Notice the addition of nul ch to cater for the lack of a specific terminator in the environment string.
[*]Ex 9.12
    PROGRAM ex9 12 CONTEXT VOID
    USE standard
    IF FILE abc;
        open(abc,"ABC",env channel)/=0
    THEN
        print(("Environment string ABC",
              "is undefined",newline));
        stop
    ELSE
        INT sum:=0, n;
        on logical file end(
         abc,
         (REF FILE f)BOOL:
          (close(f);
           print(("Total=",sum,newline));
           stop;  SKIP));
       DO
          get(abc,n);
          sum+:=n
       OD
    FI
    FINISH

[*]Ex 9.13
Notice how the size of the month denotation is used to ensure that the rainfall is aligned appropriately.
   PROGRAM ex9 13 CONTEXT VOID
   USE standard
   BEGIN
   []STRING months=
       ("January","February","March",
        "April","May","June","July",
        "August","September",
        "October","November",
        "December");

   []REAL rainfall=
       ( 6.54, 12.3,  10.1,  13.83,
         5.04, 9.15,  14.34, 16.38,
         13.84, 10.45, 8.49, 7.57);

   FOR m TO UPB months
   DO
      STRING mm=months[m];
      print((mm,(12-UPB mm)*blank,
             fixed(rainfall[m],-5,2),
             newline))
   OD
   END
   FINISH
[*]Ex 9.14
The difficult part is calculating which number to print at each position.
   PROGRAM ex9 14 CONTEXT VOID
   USE standard
   BEGIN
      print(("Table of square roots ",
             "1 to 100",
             newline,newline));

      FOR i TO 25
      DO
         FOR j TO 4
         DO
            INT number = (j-1)*25+i;
            print((whole(number,-6),
                   fixed(sqrt(number),
                         -8,4)))
         OD;
         print(newline)
      OD
   END
   FINISH
[*]Ex 9.15
   PROGRAM ex9 15 CONTEXT VOID
   USE standard
   BEGIN
      REAL pi power:=1;
      print(("Table of powers of pi",
             " 1 to 10",
           newline,newline));

      FOR i TO 10
      DO
        pi power*:=pi;
        print((whole(i,-3),"  ",
               float(pi power,
                     12,6,2),
               newline))
      OD
   END
   FINISH

[*]Ex 9.16
To write this program, you need to know how many bytes Algol 68 uses to store an integer in a binary book. In the program below, that number is presumed to be identified by int bin bytes. You will need to write a short program to output a couple of integers to a binary book and then see how long it is (and you might find its contents of interest).
   PROGRAM ex9 16 CONTEXT VOID
   USE standard
   BEGIN
   FILE work;

   IF   establish(work,
                  "ex9 9 1.tmp",
                  stand back channel,
                  0,0,0)/=0
   THEN
      print("Cannot create workbook");
      exit(1)
   FI;

   FOR i TO 1000 DO put bin(work,i) OD;

   INT int bin bytes=?;
   CO Your value replaces ? CO

   FOR i FROM 17 BY --17 TO 1000
   DO
      set(work,0,0,(i-1)*int bin bytes);
      INT n;  get bin(work,n);
      print((n,newline))
   OD;

   close(work)
   END
   FINISH
[*]Ex 9.17
Reading the words should not present any problems to you. The only new bit is the output. However, for the sake of completeness, here is the whole program.
   PROGRAM ex9 17 CONTEXT VOID
   USE standard
   BEGIN
      FILE inf, out1, out2;

      IF open(inf,
              "inbook",
              stand in channel)/=0
      THEN
         print("Cannot open inbook");
         exit(1)
      ELIF establish(out1,
                     "outbook1",
                     stand out channel,
                     0,0,0)/=0
      THEN
         print("Cannot create outbook1");
         exit(2)
      ELIF establish(out2,
                     "outbook2",
                     stand out channel,
                     0,0,0)/=0
      THEN
         print("Cannot create outbook2");
         exit(3)
      FI;

      make term(inf, blank+cr+lf);

      STRING word; CHAR ch:=blank;

      on logical file end(inf,
       (REF FILE f)BOOL:
        (close(out1);
         close(out2);
         close(f);
         stop;  SKIP));

      DO
         get(inf,(word,
                  skip terminators));

         IF UPB word > 0
         THEN
            put bin(out2,
                    (current pos(out1),
                     UPB word));
            put bin(out1,word)
         FI
      OD
   END
   FINISH

[*]Ex 9.18
A useful wrinkle is to end your report with the words END OF REPORT so that your reader knows that there are no pages of the report which could have been lost. In a professionally written program, you would put a page number and the date of the report, but we have not yet covered how that can be done (see chapter 12).
   PROGRAM ex9 18 CONTEXT VOID
   USE standard
   IF []STRING
        months =
         ("January","February","March",
          "April","May","June",
          "July","August","September",
          "October","November","December");
      []REAL
        rainfall =
         ( 6.54, 12.30, 10.10, 13,83,
           5.04,  9.15, 14.34, 16.38,
          13.84, 10.45, 8.49,   7.57);
      FILE prn;
      establish(prn,
                "rainfall.out",
                stand out channel,
                0,0,0)/=0
   THEN
      put(stand error,
          ("Cannot establish rainfall.out",
           newline));  stop
   ELSE
      put(prn,
          ("Rainfall figures in 1995",
           newline,newline,
           "Month",7*blank,
           "Rainfall in mm",
           newline));

      FOR m TO UPB months
      DO
        STRING mm = months[m];
        put(prn,
            (mm,(12-UPB mm)*blank,
             fixed(rainfall[m],-5,2),
             newline))
      OD;
      put(prn,
          (newline,
           "END OF REPORT",
           newline));
      close(prn)
   END
   FINISH
[*]Ex 9.19
You will need to get the identification of the file from the argument line.
   PROGRAM ex9 19 CONTEXT VOID
   USE standard
   IF STRING in idf;  FILE arg, inf, prn;
      open(arg,"",arg channel)/=0
   THEN
      put(stand error,
          ("Cannot access arguments",
           newline));
      exit(1)
   ELIF
      on logical file end(arg,
       (REF FILE f)BOOL:
        (put(stand error,
             ("Usage: tt idf",
              newline));
         stop;  SKIP));
      get(arg,(LOC STRING,skip terminators,
               in idf));
      close(arg);
      open(inf,in idf,stand in channel)/=0
   THEN
       put(stand error,
           ("Cannot open ",in idf,
            newline));
      exit(2)
   ELIF
      establish(prn,"tt.out",
                stand out channel,
                0,0,0)/=0
   THEN
      put(stand error,
          ("Cannot establish tt.out",
           newline));
      exit(3)
   ELSE
      STRING line;
      on logical file end(inf,
       (REF FILE f)BOOL:
        (close(f);  close(prn);
         stop;  SKIP));

      FOR i
      DO
         get(inf,(line,newline));
         put(prn,(whole(i,-6),": "));
         IF UPB line > 0
         THEN put(prn,line)
         FI;
         newline(prn)
      OD
   FI
   FINISH

[*]Ex 9.20
   PROGRAM ex9 20 CONTEXT VOID
   USE standard
   BEGIN
      REAL r;

      WHILE read(r); r/=0.0
      DO
         print((float(r,-12,3,-2),newline))
      OD
   END
   FINISH
[*]Ex 9.21
This program is not all that difficult. Take it slowly, step by step. Although reading an employee record only appears once in the program, it is better to write it as a procedure so as not to obscure the main logic. Likewise, printing each line of the report is also declared as a procedure. Notice how the given solution checks for errors.
   PROGRAM ex9 21 CONTEXT VOID
   USE standard
   BEGIN
      FILE arg, emp, prn;
      STRING emp idf;
      INT week:=0;

      IF open(arg,"",arg channel)/=0
      THEN
        put(stand error,
           ("Cannot access the arguments",
            newline));
        exit(1)
      ELIF
        on logical file end(arg,
         (REF FILE f)BOOL:
         (put(stand error,
             ("Usage: tt emp-book week-no",
              newline));
          exit(2); SKIP));
        get(arg,
           (LOC STRING,LOC CHAR,
            emp idf,week));
        week < 1 OR week > 53
      THEN
         put(stand error,
             ("Invalid week number",
              newline));
         exit(3)
      ELIF open(emp,
                emp idf,
                stand in channel)/=0
      THEN
        put(stand error,
           ("Cannot open ",emp idf,
            newline));
        exit(4)
      ELIF
        establish(prn,
                  "report",
                  stand out channel,
                  0,0,0)/=0
      THEN
        put(stand error,
           ("Cannot establish report",
            newline));
        exit(5)
      FI;

      MODE
        EMPLOYEE=STRUCT(STRING name,
                        [2]STRING address,
                        STRING dept,
                               ni code,
                               tax code,
                        REAL basic,
                             overtime,
                        [52]REAL
                           net pay,tax);

      PROC get emp=(REF FILE f,
                    REF EMPLOYEE e)VOID:
      BEGIN
        [80]CHAR s;

        PROC get str=[]CHAR:
        (
           INT len;  get bin(f,len);
           [len]CHAR s;
           get bin(f,s);
           s
        ); \#get str\#

        IF (name OF e:=get str) /= ""
        THEN
          FOR i TO UPB address OF e
          DO
            (address OF e)[i]:=get str
          OD;
          dept OF e:=get str;
          ni code OF e:=get str;
          tax code OF e:=get str;
          get bin(f,(basic OF e,
                     overtime OF e,
                     net pay OF e,
                     tax OF e))
        FI
      END #get emp#;

      PROC put emp=(REF FILE f,
                    REF EMPLOYEE e)VOID:
        put(f,(name OF e,
               (40-UPB name OF e)*blank,
                fixed((net pay OF e)[week],
                       -8,2),
                newline));

      INT line:=60, page:=0;

      PROC heading = (REF FILE f)VOID:
      IF line = 60
      THEN line:=0; #reset the line count#
        put(f,
            (newpage,
             "Report of net pay for week ",
             whole(week,0),
             40*blank,"Page ",
             whole(page+:=1,0),
             newline,newline,
             "Employee name",
             28*blank,"Net pay",
             newline,newline))
      FI #heading#;

      EMPLOYEE employee;
      REAL total pay:=0; INT n:=0;

      on logical file end(emp,
       (REF FILE f)BOOL:
        (put(prn,
             ("Total net pay for ",
              whole(n,0),
              " employees =",
              fixed(total pay,-11,2),
              newline,
              newline,
              "End of report",newline));
        close(f);  close(prn);  stop;
        SKIP));

      DO
         heading(prn);
         get emp(emp,employee);

        IF name OF employee /= ""
        THEN
           total pay+:=
            (net pay OF employee)[week];
           n+:=1;
           #count of total employees#
           put emp(prn,employee);
           line+:=1
        FI
      OD
   END
   FINISH

Sian Mountbatten 2012-01-19