Google
 

Trailing-Edge - PDP-10 Archives - decuslib10-04 - 43,50334/gnotop.alg
There are no other files named gnotop.alg in the archive.
COMMENT   -------------------------------------------------

GNOSIS provides a simple CAI authoring language which  makes
it  easy  for  any  teacher  with  a  basic understanding of
"programmed" textbooks to develop computerized tutorials for
his  students.   Although material already written in such a
format can be transformed virtually as-is by GNOSIS  into  a
form  suitable  for  computer  delivery,  the  teacher would
normally be writing his own "script." This  script,  because
it simulates the dialogue one might overhear if that teacher
were tutoring a student in private, can be made to "come  to
life" on a computer terminal by the addition of a few simple
GNOSIS command words.  The computer driven tutorial  is,  in
reality,  a  compiled  version  of  the ALGOL program GNOSIS
writes in response to the script prepared by the teacher.

As in the ordinary tutoring environment, the student's  path
through  the  material  can  be guided in various and subtle
ways,  e.g.,  by  routing  students  having  difficulty   to
supplementary  material.   The  program  qua  tutor can also
react in helpful ways to  a  variety  of  anticipated  false
answers to questions, e.g., by giving appropriate diagnostic
commentary or hints, followed by a repetition of the wrongly
answered  question.  Although unanticipated responses can be
saved for inclusion  in  the  teacher  reports  (along  with
statistics  on  individual  student  performance),  the data
which are generated exist for  the  sake  of  improving  the
lesson  pedagogically.   This is in keeping with the general
design philosophy that GNOSIS should be  a  TEACHING  system
rather than a TESTING system.

If anyone makes any additions or modifications to the GNOSIS
translator,  then  please  send  a  copy  either to (1)Jacob
Palme,  Research  Institute  of  National  Defense,  S-10450
Stockholm 80, Sweden, or (2)Dr.  Walter Maner, Department of
Philosophy,  Old  Dominion  University,  Norfolk,   Virginia
23508,  USA.   With  your  cooperation,  we can prepare more
powerful versions of GNOSIS for distribution to GNOSIS users
like yourself.  THANK YOU.


ALPHABETICAL LIST OF GLOBAL VARIABLES
=====================================

NAME           TYPE            CONTENT
-------------------------------------------------------------------

A              INTEGER         A
ALLNEUTRAL     BOOLEAN         TRUE IF ALL ANSWER PATTERNS SO FAR TO THIS
.                              QUESTION HAVE BEEN NEUTRAL. THIS INFLUENCES
.                              THE WORDING OF MESSAGES FOR UNEXPECTED STUDENT
.                              ANSWERS.
ANSWER         STRING          BUFFER FOR INPUT LINES OF THE LESSON. ONE LINE
.                              AT A TIME IS STORED IN THIS BUFFER.
ANSWERLENGTH   INTEGER         LENGTH OF LESSON LINE.
BELL           BOOLEAN         TRUE IF LESSON CONTAINS A %BELL COMMAND
.                              RINGS BELL ON STUDENT'S TERMINAL WHEN INPUT
.                              FROM HIM IS REQUIRED.
BLANK          INTEGER
CARRIAGERETURN INTEGER         13
CHARVALUE      INTEGER         TEMPORARY STORAGE OF INTEGRAL VALUE OF ONE
.                              CHARACTER IN A STRING WHICH IS
.                              BEING OUTPUTTED.
COLON          INTEGER         :
CONTROLCHAR    INTEGER         BINARY VALUE OF THE FIRST CHARACTER IN THE
.                              LESSON. THIS CHARACTER BEGINS ALL COMMAND
.                              LINES. IT IS USUALLY = "%".
CONTROLINLINE  BOOLEAN         CONTROLCHAR INSIDE INPUT LINE.
CONTROLSTART   STRING          SUBSTRING OF CHARACTER 2-4 OF COMMAND.
COPYRIGHT      STRING          LESSON AUTHOR'S COPYRIGHT NOTICE
DISK           BOOLEAN         TRUE IF LESSON CONTAINS A %DISK COMMAND.
.                              SENDS TEACHER REPORT TO A DISK FILE
.                              WITH THE NAME "LESSONNAME.DTA".
DOT            INTEGER         .
DOUBLEQUOTE    INTEGER         "
EMPTY          BOOLEAN         TRUE IF TEACHER ANSWER PATTERN IS EMPTY.
EQUALSIGN      INTEGER         =
ERRLINES       INTEGER         COUNTER OF LINES TO BE PRINTED AFTER ERROR.
EXCLAMATION    INTEGER         !
EXTRA          BOOLEAN         ARE EXTRA WORDS PERMITTED IN STUDENT ANSWERS?
FIRSTRIGHT     STRING          FIRST RIGHT ANSWER TO A QUESTION.
FORMFEED       INTEGER         12
IFSET          BOOLEAN ARRAY   IF ON GNOSIS-TIME SWITCH IS ACTIVE.
IFVAL          BOOLEAN ARRAY   VALUE OF IF ON GNOSIS-TIME SWITCH.
INFILE         STRING          FILENAME WITH EXTENSION OF INPUT FILE.
JUSTIFY        BOOLEAN         TRUE IF TEXT BLOCKS ARE TO BE RIGHT
.                              JUSTIFIED ("RAGGED RIGHT") AT COLUMN 72
KEEP           BOOLEAN         KEEP TEACHER REPORTS AT COMPUTING CENTER,
.                              DO NOT ASK THE STUDENT TO SEND THEM IN.
LAB            STRING          USED FOR GENERATION OF LABELS IN THE PRODUCED
LABELCOUNT     INTEGER         COUNTER OF NUMBER OF MAINLABS.
LACK           BOOLEAN         TRUE AFTER A %LACK COMMAND.
LANGUAGE       INTEGER         LANGUAGE = 1 -> LESSON IS IN ENGLISH,
.                              (ENGLISH IS THE DEFAULT)
.                              LANGUAGE = 2 -> LESSON IS IN SWEDISH.
LCAA           INTEGER         } = BINARY VALUE OF SWEDISH LETTER
LCAE           INTEGER         {
LCE            INTEGER         e
LCOE           INTEGER         `
LEFTSQUARE     INTEGER         [
LESSONNAME     STRING          FILENAME OF THE LESSON WITH EXTENSION REMOVED.
.                              THIS NAME WITH THE EXTENSION ".ALG" IS THE
.                              NAME OF THE OUTPUT FILE.
LINEFEED       INTEGER         10 = BINARY VALUE OF ASCII CHARACTER
LINENUMBER     STRING          LINENUMBER FOR LINENUMBERED FILES.
LINENUMBERED   BOOLEAN         THE GNOSIS TEXT IS A LINE-NUMBERED FILE.
LOCK           BOOLEAN         TRUE IF LESSON CONTAINS A %LOCK COMMAND.
.                              DISABLES BACKSTEPPING AND SKIPPING
.                              PROVISIONS OF GNOSIS.
MAINLAB        STRING          USED FOR GENERATION OF LABELS IN THE PRODUCED
.                              ALGOL PROGRAM, TO BE USED FOR BACKSTEPPING.
NAME           BOOLEAN         TRUE IF LESSON CONTAINS A %NAME COMMAND.
.                              STUDENT'S FIRST NAME USED FOR I/O AND
.                              HIS FULL NAME GOES TO TEACHER REPORT (IF ANY).
NEUTRAL        BOOLEAN         TRUE FOR A %NEUTRAL COMMAND.
OPENED         BOOLEAN         TRUE WHEN THE OUTPUT FILE FROM GNOSIS
.                              HAS BEEN OPENED AND THE PREAMBLE OF THE
.                              ALGOL TRANSLATION OF THE LESSON HAS BEEN
.                              OUTPUTTED.
ORDER          BOOLEAN         MUST STUDENT ANSWER WORDS BE IN ORDER?
POS            INTEGER         POSITION IN THE TEXT OF THE LESSON LINE.
POS2           INTEGER         POSITION IN THE TEXT OF THE LESSON LINE.
PREVIOUSLAB    STRING          LABEL FOR PREVIOUS TEXT OR QUESTION.  GNOSIS
.                              WRITES INTO LESSON A GOTO STATEMENT WITH THIS
.                              LABEL AS ARGUMENT SO STUDENT MAY BACK UP IN
.                              THE LESSON ONE ITEM AT A TIME.
PUT            BOOLEAN         TRUE IF THE LESSON CONTAINED A %TEACHER COMMAND,
.                              SO THAT TEACHER REPORTS ARE TO BE GENERATED.
QCOUNT         INTEGER         COUNTER OF THE NUMBER OF QUESTIONS
.                              (%QUESTION COMMANDS) IN THE LESSON.
QUESTION       STRING          QUESTION IDENTIFICATION WHICH IS OUTPUT
.                              ON THE TEACHER REPORTS TO SHOW HIM WHICH
.                              QUESTION GAVE UNEXPECTED ANSWERS.
.                              ALGOL PROGRAM, TO BE USED INSIDE QUESTIONS.
RIGHT          BOOLEAN         TRUE FOR A %RIGHT COMMAND, FALSE FOR
.                              A %WRONG COMMAND.
RIGHTFOUND     BOOLEAN         TRUE IF ANY RIGHT ANSWER HAS BEEN FOUND
.                              TO THE CURRENT OR PREVIOUS QUESTION.
RIGHTSQUARE    INTEGER         ]
SAME           STRING          LABEL TO JUMP TO IF A %SAME COMMAND IS
.                              ENCOUNTERD.
SAVEANLEN      INTEGER         SAVED VALUE OF ANSWERLENGTH.
SEMICOLON      INTEGER         ;                 COMMENT
SGNOSIS        BOOLEAN         DO NOT PRINT INITIAL MESSAGE TELLING THE
.                              STUDENT THAT HE IS RUNNING GNOSIS.
SKIP           BOOLEAN         SKIP INPUT LINES BECAUSE OF GNOSIS-TIME
.                              SWITCH SETTINGS.
SWITCHCOUNT    INTEGER         NUMBER OF GNOSIS-TIME SWITCHES.
SWITCHNAME     STRING ARRAY    NAME OF ALL GNOSIS-TIME SWITCHES.
SWITCHNUMBER   INTEGER         INDEX OF ONE GNOSIS-TIME SWITCH.
SWITCHVAL      BOOLEAN ARRAY   SETTING OF GNOSIS-TIME SWITCH VALUES.
SWITCHWORD     STRING          NAME OF ONE GNOSIS-TIME SWITCH.
TEACHER        STRING          NAME AND ADDRESS OF THE TEACHER.
TEMP                           TEMPORARY STRING.
TEXCOUNT       INTEGER         COUNTER OF THE NUMBER OF TEXT SEGMENTS
.                              (%TEXT COMMANDS) IN THE LESSON
UCAA           INTEGER         $
UCAE           INTEGER         #
UCE            INTEGER         E
UCOE           INTEGER         @
UPARROW        INTEGER         ^
WORD           STRING          ONE WORD FROM A TEACHER ANSWER PATTERN.
WPOS           INTEGER         POSITION IN THE TEXT OF THE LESSON LINE.
Z              INTEGER         Z
ZEROPRINTED    BOOLEAN         A TEST FOR EMPTY STUDENT ANSWERS
.                              HAS BEEN PRINTED FOR THIS QUESTION.
-------------------------------------------------------------------
;








BEGIN

   INTEGER
   controlchar, language, carriagereturn, linefeed, tabchar, blank, exclamation,
   answerlength, saveanlen, pos, pos2, wpos, charvalue, doublequote,
   a, z, formfeed, dot, qcount, texcount, semicolon, colon, equalsign, errlines, labelcount,
   linecount, leftsquare, rightsquare, switchcount, switchnumber, rightmargin,
   lcaa, lcae, lcoe, ucaa, ucae, ucoe, lce, uce;

   STRING
   controlstart, word, lessonname, copyright, teacher, answer, firstright, previouslab,
   nextlesson, temp, question, lab, mainlab, same, infile, switchword, linenumber;

   STRING ARRAY
   switchname[1:9];

   BOOLEAN
   extra, empty, order, right, neutral, allneutral, opened, put, sgnosis,
   nocontrolc, transferlesson, justify, controlinline, bell, name, lock, disk,
   lack, zeroprinted, keep, rightfound, skip, linenumbered;

   BOOLEAN ARRAY
   switchval[1:9], ifset[0:9], ifval[1:9];


   FORWARD PROCEDURE makemainlab, getcontrolstart, upcase, pastoperation;



   FORWARD STRING PROCEDURE getword;



   PROCEDURE delet(s);
   STRING s;
   COMMENT   -------------------------------------------------
   Delet  will  delete  non-empty  STRINGs,  but will not (like
   Delete) cause an error if an attempt is made  to  delete  an
   empty string.
   -----------------------------------------------------------;
   IF Length(s) > 0 THEN Delete(s);



   PROCEDURE errmess(toggle, message);
   BOOLEAN toggle;
   VALUE message;
   STRING message;
   COMMENT   -------------------------------------------------
   This procedure causes a GNOSIS error (or warning) message to
   be displayed.  The troublesome line and the next three lines
   of the lesson are displayed on the terminal.  If  the  souce
   file  contains  line  numbers,  these  will  be displayed as
   reference points.  If it does not, then the APPROXIMATE line
   numbers  which are generated by the 'getline' PROCEDURE will
   be displayed.  The identification number of the GNOSIS error
   message   corresponds  to  the  line  in  THIS  file  (i.e.,
   GNOSIS.ALG) from which  this  error  procedure  was  called.
   This  is  useful  for  debugging purposes since same kind of
   error can occur at many different points  (e.g.,  errors  in
   precedence).
   -----------------------------------------------------------;
   BEGIN
      Selectoutput(0);
      IF errlines = 0 THEN
      BEGIN
         IF linenumbered THEN
         BEGIN
            temp:= Copy(linenumber);
            Write(temp);
            delet(temp)
         END
         ELSE
         BEGIN
            Write("LINE ");
            Print(linecount - 1, 5);
            Write(": ")
         END;
         temp:= Copy(answer,1,answerlength);
         Write(temp);
         Newline;
         IF answerlength > 0 THEN delet(temp)
      END;
      errlines:= 3;
      IF toggle THEN Write("****** ERROR Message No. ") ELSE Write("****** WARNING Message No. ");
      Write(message);
      Newline;
      Selectoutput(2)
   END of PR*CEDURE errmess;



   PROCEDURE getline;
   COMMENT   -------------------------------------------------
   'Getline'  reads  in  a  line  of  the  lesson  script.  Any
   sequence of characters (including the null  sequence)  which
   is  terminated  by a <CR><LF> or <FF> constitutes a line.  A
   <FF> immediately after a <LF> will not cause any blank line.

   This procedure ignores any line  beginning  with  a  '!'  in
   column one, thus conforming to DEC comment conventions.
   -----------------------------------------------------------;
   BEGIN
      INTEGER s, t, i;
      BOOLEAN taberror;

      getnextline:
      linecount:= linecount+1;
      taberror:= FALSE;
      IF linenumbered THEN
      BEGIN
         FOR i:= 1 STEP 1 UNTIL 5 DO
         BEGIN
            Insymbol(t);
            linenumber.[i]:= t
         END;
         Insymbol(t);
         taberror:= t > 32
      END;
      controlinline:= FALSE;
      FOR i:= 1 STEP 1 UNTIL 133 DO
      BEGIN

         loop:
         Insymbol(t);
         answer.[i]:= t;
         IF t = controlchar THEN
         BEGIN
            IF i # 1 THEN controlinline:= TRUE
         END;
         IF t = linefeed THEN GOTO out;
         IF t = formfeed THEN
         BEGIN
            Outsymbol(t);
            IF i = 1 THEN GOTO loop;
            i:= i+1;
            GOTO out
         END
      END;
      errmess(FALSE, "0316: Long input line will be truncated to 132 characters.");

      out:
      answerlength:= i-2;
      IF answer.[1] = exclamation THEN GOTO getnextline;
      IF taberror THEN
      errmess(FALSE, "0322: Character after line-number is not TAB.") ELSE
      IF controlinline THEN
      errmess(FALSE, "0324: Command character not first in line.");
      IF errlines > 0 THEN
      BEGIN
         errlines:= errlines-1;
         Selectoutput(0);
         IF linenumbered THEN
         BEGIN
            temp:= Copy(linenumber);
            Write(temp);
            delet(temp)
         END
         ELSE
         BEGIN
            Write("LINE ");
            Print(linecount - 1, 5);
            Write(": ")
         END;
         temp:= Copy(answer,1,answerlength);
         Write(temp);
         Newline;
         IF answerlength > 0 THEN delet(temp);
         IF errlines = 0 THEN
         Write("----------------------------------------------------------------------[N]");
         Selectoutput(2)
      END;
      COMMENT   -------------------------------------------------
      Now we check to see whether the  current  line  is  an  %IF,
      %IFNOT  or  %IFEND  command  line and, if so, "skip" will be
      reset accordingly.   "Skip"  is  the  BOOLEAN  which  GNOSIS
      checks to determine whether or not to skip certain lines.
      -----------------------------------------------------------;
      IF answer.[1] # controlchar THEN GOTO noif;
      getcontrolstart(3);
      IF controlstart = "IF" THEN
      COMMENT   --------------------------------------------------
      Since the parameter passed to 'getcontrolstart' was 3 rather
      than the usual 4, %IF, %IFNOT and %IFEND will look the  same
      at  this  point.   (They  do not differ in their first three
      characters.)
      -----------------------------------------------------------;
      BEGIN
         pastoperation;
         switchword:= getword;
         upcase(switchword);
         IF Length(switchword) <= 0 THEN errmess(TRUE, "0368: No switchname in %IF-class command.[N]****** Line will be ignored.");
         FOR switchnumber:= 1 STEP 1 UNTIL switchcount DO
         IF switchname[switchnumber] = switchword THEN GOTO found;
         errmess(TRUE, "0371: Unknown switchname in %IF-class command.[N]****** Line will be ignored.");
         GOTO getnextline;

         found:
         IF answer.[4] = lce OR answer.[4] = uce THEN
         COMMENT   --------------------------------------------------
         Since this command line began with "%IF" and had an  "E"  in
         the fourth position, it must be an %IFEND command.

         This command turns off the %IF/%IFNOT  facility.   In  other
         words,  the  SCOPE of each %IF or %IFNOT extends to the next
         occurrence of a %IFEND command.  Thus,  all  text  following
         %IFEND  will  be included in the translated lesson as usual,
         regardless of previous %IF's or %IFNOT's.  Subsequent  %IF's
         or  %IFNOT's  will,  of  course,  create another need for an
         %IFEND to define THEIR scope -- unless  that  scope  extends
         all the way to the end of the lesson.  %IFEND must therefore
         follow some %IF or %IFNOT command.
         -----------------------------------------------------------;
         BEGIN
            IF NOT ifset[switchnumber] THEN
            errmess(FALSE, "0392: %IFEND on non-active switch -- will have no effect.");
            ifset[switchnumber]:= FALSE
         END ELSE
         BEGIN
            ifset[switchnumber]:= TRUE;
            ifval[switchnumber]:= answer.[4] = blank
            COMMENT   --------------------------------------------------
            The line above handles both %IFNOT and  %IF  command  lines.
            If  no  blank follows the "IF", then the appropriate item in
            the BOOLEAN  ARRAY  'ifval'  is  switched  FALSE  since  the
            trailing character (in position 4) can only be an "N" (i.e.,
            a %IFNOT command line).  On the othr hand, if a  blank  does
            follow the "IF", then the item is switched TRUE (i.e., since
            the command was a %IF).

            Assuming <switchname> has been declared and initialized by a
            %SWITCH  command,  the occurrence of %IF will cause the text
            between the %IF and the next %IFEND to be deposited  in  the
            translated lesson ONLY if <switchname> was initialized TRUE.
            Otherwise   these   lines   of   text   will   be   skipped.
            Correspondingly, the text between %IFNOT and the next %IFEND
            command will be included in the  ALGOL  translation  of  the
            lesson ONLY if <switchname> is FALSE.
            -----------------------------------------------------------;
         END;
         skip:= FALSE;
         FOR switchnumber:= 1 STEP 1 UNTIL switchcount DO
         skip:= skip OR ( ifset[switchnumber] AND NOT
         ( ifval[switchnumber] EQV switchval[switchnumber] ));
         GOTO getnextline
      END ELSE

      noif:
      IF skip THEN GOTO getnextline;
      pos:= 1
   END of PR*CEDURE getline;



   PROCEDURE upcase(s);
   STRING s;
   COMMENT   --------------------------------------------------
   'Upcase'  will transform all letters in the parameter STRING
   from lower case to upper  case.   If  the  language  of  the
   lesson  is swedish, then the swedish letters }, { and ` will
   also be transformed to upper case
   -----------------------------------------------------------;
   BEGIN
      INTEGER t, i;
      FOR i:= 1 STEP 1 UNTIL Length(s) DO
      BEGIN
         IF s.[i] >= 97 AND s.[i] <= 122 THEN
         s.[i]:= s.[i]-32
         ELSE IF language = 2 THEN
         BEGIN
            IF s.[i] = lcaa THEN s.[i]:= ucaa ELSE
            IF s.[i] = lcae THEN s.[i]:= ucae ELSE
            IF s.[i] = lcoe THEN s.[i]:= ucoe
         END
      END
   END of PR*CEDURE upcase;



   PROCEDURE getcontrolstart(i);
   VALUE i;
   INTEGER i;
   COMMENT   --------------------------------------------------
   'Getcontrolstart' extracts that part of a command line which
   contains  the beginning of the command text.  This beginning
   determines what GNOSIS will do until it  encounters  another
   command  line.   The PROCEDURE also passes over unrecognized
   commands and any non-command line(s) which may follow  them.
   This  ensures  that  the error scan will be able to generate
   meaningful messages for the user and, with  a  little  luck,
   may  enable  GNOSIS  to produce a program the ALGOL compiler
   will accept despite user error.
   -----------------------------------------------------------;
   BEGIN

      repeat:
      delet(controlstart);
      controlstart:= Copy(answer,2,i);
      upcase(controlstart);
      IF i = 4 THEN
      BEGIN
         COMMENT   --------------------------------------------------
         We scan down this list, eliminating the most frequently used
         GNOSIS  commands  first.   The  semicolon  after 'THEN' is a
         dummy statement  used  to  outwit  the  compiler  (it  still
         complains  some).  This is as close as we can come to a case
         statement in ALGOL.
         -----------------------------------------------------------;
         IF controlstart = "RIG" THEN ;
         ELSE IF controlstart = "WRO" THEN ;
         ELSE IF controlstart = "SAM" THEN ;
         ELSE IF controlstart = "ORD" THEN ;
         ELSE IF controlstart = "NOO" THEN ;
         ELSE IF controlstart = "EXT" THEN ;
         ELSE IF controlstart = "NOE" THEN ;
         ELSE IF controlstart = "QUE" THEN ;
         ELSE IF controlstart = "NEU" THEN ;
         ELSE IF controlstart = "LAC" THEN ;
         ELSE IF controlstart = "GO " THEN ;
         ELSE IF controlstart = "GOT" THEN ;
         ELSE IF controlstart = "TEX" THEN ;
         ELSE IF controlstart = "JUS" THEN ;
         ELSE IF controlstart = "NOJ" THEN ;
         ELSE IF controlstart = "HEL" THEN ;
         ELSE IF controlstart = "VAR" THEN ;
         ELSE IF controlstart = "PRO" THEN ;
         ELSE IF controlstart = "INI" THEN ;
         ELSE IF controlstart = "ALG" THEN ;
         ELSE IF controlstart = "QEN" THEN ;
         ELSE IF controlstart = "END" THEN ;
         ELSE IF controlstart = "TEA" THEN ;
         ELSE IF controlstart = "NAM" THEN ;
         ELSE IF controlstart = "KEE" THEN ;
         ELSE IF controlstart = "BEL" THEN ;
         ELSE IF controlstart = "DSK" THEN ;
         ELSE IF controlstart = "DIS" THEN ;
         ELSE IF controlstart = "LOC" THEN ;
         ELSE IF controlstart = "COP" THEN ;
         ELSE IF controlstart = "LAN" THEN ;
         ELSE IF controlstart = "SGN" THEN ;
         ELSE IF controlstart = "SWI" THEN ;
         ELSE IF controlstart = "NOC" THEN ;
         ELSE IF controlstart = "NEX" THEN ;
         ELSE IF controlstart = "FIN" THEN ;
         ELSE IF controlstart = "IF " THEN ;
         ELSE IF controlstart = "IFE" THEN ;
         ELSE IF controlstart = "IFN" THEN ;
         ELSE
         BEGIN
            errmess(TRUE,
            "0527:  Unrecognized command line found.  As a result,[N]****** this line up to next command line will be ignored.");
            getline;
            WHILE answer.[1] # controlchar DO getline;
            i:= 4;
            GOTO repeat
         END
      END
   END of PR*CEDURE getcontrolstart;



   STRING PROCEDURE getword;
   COMMENT   --------------------------------------------------
   'Getword' scans the input  line,  beginning  at  'pos',  and
   finds a word.  For purposes of this PROCEDURE, any STRING of
   non-blank characters terminated by a  blank  or  a  <CR><LF>
   will constitute a word.  Leading and trailing blanks are not
   assumed to be part of the word.  'Getword' will  move  'pos'
   to the end of the found word.
   -----------------------------------------------------------;
   BEGIN
      INTEGER pos1, t;
      pos1:= pos;
      IF pos1 # 1 THEN GOTO blankloop;

      textloop:
      t:= answer.[pos1];
      IF t = carriagereturn THEN GOTO null;
      IF t # blank THEN
      BEGIN
         pos1:= pos1+1;
         GOTO textloop
      END;

      blankloop:
      t:= answer.[pos1];
      IF t = carriagereturn THEN GOTO null;
      IF t = blank THEN
      BEGIN
         pos1:= pos1+1;
         GOTO blankloop
      END;
      IF answer.[pos1] = carriagereturn THEN GOTO null;
      pos:= pos1+1;

      wordloop:
      t:= answer.[pos];
      IF t # blank AND t # carriagereturn THEN
      BEGIN
         pos:= pos+1;
         GOTO wordloop
      END;
      getword:= Copy(answer,pos1,pos-1);
      GOTO out;

      null:
      getword:= "";

      out:
   END of PR*CEDURE getword;



   PROCEDURE alglin(s);
   VALUE s;
   STRING s;
   COMMENT   --------------------------------------------------
   'Alglin' will dump the STRING passed to it  as  a  parameter
   into  the  translated  lesson.   Since  this parameter could
   contain characters which are  not  supposed  to  have  their
   usual  ALGOL  function  (i.e.,  the  semicolon, the left and
   right square bracket, and the doubequote), we could not take
   advantage  of the built-in PROCEDURE 'Write'.  A <CR><LF> is
   output after the STRING.
   -----------------------------------------------------------;
   BEGIN
      FOR wpos:= 1 STEP 1 UNTIL Length(s) DO
      Outsymbol(s.[wpos]);
      Newline
   END of PR*CEDURE alglin;



   PROCEDURE textline(s);
   VALUE s;
   STRING s;
   COMMENT   --------------------------------------------------
   'Textline'  will output a line in an Algol 10 program.  This
   line contains a call to the Algol 10 PROCEDURE "Write"  such
   that  the  input  STRING is written.  Example:  If the input
   STRING is "ABCD[I]" then this PROCEDURE will output the line
   "Write("ABCD[[I]]").

   We developed this PROCEDURE so that we would not go  bonkers
   trying  to  nest  square brackets and doublequotes -- not to
   mention a 'Write'  inside  another  'Write'.   However,  the
   program   was  mostly  finished  before  we  began  to  take
   advantage of it.
   -----------------------------------------------------------;
   BEGIN
      INTEGER pos, t;
      Write("Write(""");
      FOR pos:= 1 STEP 1 UNTIL Length(s) DO
      BEGIN
         t:= s.[pos];
         IF t = doublequote OR t = semicolon OR
         t = leftsquare OR t = rightsquare
         THEN Outsymbol(t);
         IF t = 27 then Write("$") else Outsymbol(t)
      END;
      Write("[[N]]"");;[N]")
   END of PR*CEDURE textline;



   PROCEDURE textlines;
   COMMENT   --------------------------------------------------
   'Textlines'  will  take  text  from  the  GNOSIS  lesson and
   translate that text to an Algol 10 program  sequence  which,
   in  turn, will write that text to the user.  Succesive lines
   from the GNOSIS lesson are translated until a line is  found
   which contains a GNOSIS command.

   In %NOJUSTIFY mode, GNOSIS watches  vertical  spacing  only,
   ensuring  that scrolling will cease as soon as the screen is
   full.  (A call to 'pause' is inserted for this purpose.)  In
   %JUSTIFY  mode, GNOSIS not only watches vertical spacing but
   also edits the text in such  a  way  that  a  semi-justified
   right  margin is produced (at or before column 72).  In this
   mode, GNOSIS will be sensitive  to  the  occurrence  of  the
   semicolon,   right   and   left   square  bracket,  and  the
   doublequote.  This sensitivity will probably be  removed  in
   later versions.
   -----------------------------------------------------------;
   BEGIN
      INTEGER outpos, screenlines;
      STRING nextword;
      BOOLEAN writingaline, morewords;



      STRING PROCEDURE getnextword;
      COMMENT   --------------------------------------------------
      Same as 'getword' except does not scan past  first  word  in
      'answer'.
      -----------------------------------------------------------;
      BEGIN
         INTEGER pos1, t;
         pos1:= pos;
         t:= answer.[pos1];
         IF t = carriagereturn THEN GOTO null;

         blankloop:
         t:= answer.[pos1];
         IF t = carriagereturn THEN GOTO null;
         IF t = blank OR t = tabchar THEN
         BEGIN
            pos1:= pos1+1;
            GOTO blankloop
         END;
         IF answer.[pos1] = carriagereturn THEN GOTO null;
         pos:= pos1+1;

         wordloop:
         t:= answer.[pos];
         IF t # blank AND t # carriagereturn THEN
         BEGIN
            pos:= pos+1;
            GOTO wordloop
         END;
         getnextword:= Copy(answer,pos1,pos-1);
         GOTO out;

         null:
         getnextword:= "";

         out:
      END of PR*CEDURE getnextword;

      getline;
      IF NOT justify THEN
      BEGIN
         screenlines:= 0;
         WHILE answer.[1] # controlchar DO
         BEGIN
            IF answerlength = 0 THEN
            BEGIN
               screenlines:= screenlines + 1;
               IF screenlines < 30 THEN Write("Newline;;[N]") ELSE
               BEGIN
                  screenlines:= 0;
                  Write("pause;;[N]")
               END
            END
            ELSE
            BEGIN
               screenlines:=screenlines + 1;
               IF screenlines > 21 THEN
               BEGIN
                  Write("pause;;[N]");
                  screenlines:= 0
               END;
               textline((temp:=Copy(answer,1,answerlength)));
               delet(temp)
            END;
            getline
         END
      END
      ELSE
      BEGIN
         writingaline:= FALSE;
         screenlines:= 0;
         outpos:= 1;
         WHILE answer.[1] # controlchar DO
         BEGIN
            IF answerlength = 0 THEN
            BEGIN
               IF writingaline THEN
               BEGIN
                  Write("[[N]]"");;[N]");
                  screenlines:= screenlines + 1;
                  IF screenlines < 22 THEN
                  BEGIN
                     Write("Newline;;[N]");
                     screenlines:= screenlines + 1
                  END
                  ELSE
                  BEGIN
                     Write("pause;;[N]");
                     screenlines:= 0
                  END;
                  writingaline:= FALSE;
                  outpos:= 1
               END
               ELSE
               BEGIN
                  screenlines:= screenlines + 1;
                  IF screenlines < 22 THEN
                  BEGIN
                     Write("Newline;;[N]");
                     screenlines:= screenlines + 1
                  END
                  ELSE
                  BEGIN
                     Write("pause;;[N]");
                     screenlines:= 0
                  END
               END
            END
            ELSE
            BEGIN
               morewords:= TRUE;
               IF NOT writingaline THEN Write("Write(""");
               writingaline:= TRUE;
               WHILE morewords DO
               BEGIN
                  delet(nextword);
                  nextword:= getnextword;
                  IF nextword = "" THEN morewords:= FALSE
                  ELSE
                  BEGIN
                     outpos:= outpos + Length(nextword) + 1;
                     IF outpos < rightmargin THEN
                     BEGIN
                        Write(nextword);
                        Write(" ")
                     END
                     ELSE
                     BEGIN
                        Write("[[N]]"");;[N]");
                        screenlines:= screenlines + 1;
                        IF screenlines > 21 THEN
                        BEGIN
                           Write("pause;;[N]");
                           screenlines:= 0
                        END;
                        outpos:= Length(nextword) + 1;
                        Write("Write(""");
                        Write(nextword);
                        Write(" ")
                     END
                  END
               END morewords loop;
            END writing cycle for string currently in "answer";
            getline
         END WHIL* answer.[1] # controlchar;
         IF writingaline THEN Write("[[N]]"");;[N]")
      END;
      IF screenlines > 18 THEN Write("pause;;[N]");
      getcontrolstart(4)
   END of PR*CEDURE textlines;



   PROCEDURE pastoperation;
   COMMENT   --------------------------------------------------
   'Pastoperation'  will  scan  an input line (usually a GNOSIS
   command line) and find the first non-blank  character  after
   the first blank.  Thus, the PROCEDURE scans past the command
   word.  The array address of the found character is stored in
   'pos'.
   -----------------------------------------------------------;
   BEGIN
      FOR pos:= 1 STEP 1 UNTIL answerlength+1 DO
      IF answer.[pos] = blank THEN GOTO bskip;

      bskip:
      FOR pos:= pos STEP 1 UNTIL answerlength+1 DO
      IF answer.[pos] # blank THEN GOTO out;
      out:
   END of PR*CEDURE pastoperation;



   PROCEDURE shortalgol;
   COMMENT   --------------------------------------------------
   Many  GNOSIS  commands  can  contain  a  short ALGOL program
   sequence after the  end  of  the  command  (e.g.,  '%QUE  IF
   lasterrors  >  0  THEN').   'Shortalgol'  will transfer that
   short ALGOL  program  sequence  unchanged  from  the  GNOSIS
   lesson into the ALGOL translation of the lesson.
   -----------------------------------------------------------;
   BEGIN
      pastoperation;
      IF pos <= answerlength THEN
      alglin((temp:=Copy(answer,pos,answerlength)));
      delet(temp)
   END of PR*CEDURE shortalgol;



   PROCEDURE goanywherecommands;
   COMMENT   --------------------------------------------------
   'Goanywherecommands'  will  determine  whether  the   GNOSIS
   command at the current command line is one of te go-anywhere
   commands  (i.e.,  %JUSTIFY,  %NOJUSTIFY,  %EXTRA,  %NOEXTRA,
   %ORDER,  %NOORDER,  %GOTO,  or  %ALGOL) and take appropriate
   action.  The first six will set internal  BOOLEAN  variables
   in  the  GNOSIS program.  %ALGOL will cause an ALGOL program
   sequence to be transferred unchanged from the GNOSIS  lesson
   into  the  ALGOL  translation  of that lesson.  If there are
   more than one of these commands in succession, they will all
   be  handled by this PROCEDURE.  The PROCEDURE returns when a
   GNOSIS command is encountered which is  none  of  the  eight
   handled by this PROCEDURE.

   Note:  In terms of their behavior, %IF, %IFEND,  and  %IFNOT
   function  like  the  'goanywhere'  commands.  They, too, may
   appear anywhere in the lesson as long as a  %SWITCH  command
   precedes them.
   -----------------------------------------------------------;
   BEGIN

      loop:
      IF controlstart = "JUS" THEN justify:= TRUE ELSE
      IF controlstart = "NOJ" THEN justify:= FALSE ELSE
      COMMENT   --------------------------------------------------
      The  %JUSTIFY  command causes all text, includin the text in
      %QUESTION blocks and %HELP blocks, to be  semi-justified  to
      produce a ragged right at column =< 72.  It also causes such
      text material to be paged out in such  a  way  that  nothing
      will be lost scrolling off the top of a CRT.

      Although GNOSIS  begins  processing  text  material  in  the
      %NOJUSTIFY  mode, an occurrence of the %JUSTIFY command will
      change th mode of processing until a  subsequent  %NOJUSTIFY
      command is encountered.

      In %NOJUSTIFY mode GNOSIS continues to  recognize  when  the
      CRT  screen  heigth is about to be exceeded and arranges for
      the lesson to issue a call to the 'pause' PROCEDURE  at  the
      appropriate time.  However, there is in this mode no attempt
      at right-justification.  Consequently, in  %NOJUSTIFY  mode,
      text  will be displayed to the student exactly as it appears
      in the GNOSIS source script.
      -----------------------------------------------------------;
      IF controlstart = "EXT" THEN extra:= TRUE ELSE
      IF controlstart = "NOE" THEN extra:= FALSE ELSE
      COMMENT   --------------------------------------------------
      The above  commands  influence  the  way  in  which  student
      answers  are  compared  to  canned answer patterns.  After a
      %EXTRA command, and until the next %NOEXTRA command, student
      answers  will  be  considered  correct  even if they contain
      extra characters not  part  of  the  %RIGHT  answer  pattern
      PROVIDED   they  do  at  least  contain  all  the  essential
      characters.  If they answer DOES contain  extra  characters,
      then   GNOSIS   will  flag  the  essential  characters  with
      uparrows.
      -----------------------------------------------------------;
      IF controlstart = "ORD" THEN order:= TRUE ELSE
      IF controlstart = "NOO" THEN order:= FALSE ELSE
      COMMENT   --------------------------------------------------
      These commands also  influence  the  way  in  which  student
      answers  are  compared  to  canned answer patterns.  After a
      %ORDER command -- and until the next %NOORDER command  --  a
      student's  answer  will  be  considered  correct only if the
      elements of the student's answer  appear  in  PRECISELY  the
      same order as the elements of the canned answer pattern.
      -----------------------------------------------------------;
      IF controlstart = "GOT" OR controlstart = "GO " THEN
      COMMENT   --------------------------------------------------
      The  %GOTO  command works just the way 'GOTO' works in ALGOL
      itself.  Since the  old  version  of  GNOSIS  allowed  %GOTO
      command lines to end without a semicolon and the new version
      doesn't, the code below was added to make the  old  and  new
      versions  compatible.   Also,  in  this  version,  the %GOTO
      command can appear anywhere in the lesson  script,  not  (as
      was formerly the case) just in %QUESTION environments.
      -----------------------------------------------------------;
      BEGIN
         INTEGER i;
         alglin((temp:= Copy(answer,2,answerlength)));
         i:= answerlength;
         WHILE answer.[i] = blank AND i > 4 DO i:= i-1;
         IF answer.[i] # semicolon THEN
         BEGIN
            errmess(FALSE, "0943: Semicolon omitted at end of '%GOTO' command.[N]****** GNOSIS will supply one for you.");
            Outsymbol(semicolon);
            Newline
         END;
         delet(temp)
      END ELSE
      IF controlstart = "ALG" THEN
      COMMENT   --------------------------------------------------
      This command causes one or more lines of ALGOL  code  to  be
      transferred  unchanged  to  the  ALGOL  translation  of  the
      lesson.   The  segment  must  be  legal  in  ALGOL  and,  in
      addition,  must  mesh with the GNOSIS lesson at the point of
      isertion.
      -----------------------------------------------------------;
      BEGIN
         shortalgol;

         algloop:
         getline;
         IF answer.[1] = controlchar THEN GOTO out;
         IF answerlength = 0 THEN Newline ELSE
         BEGIN
            alglin((temp:=Copy(answer,1,answerlength)));
            delet(temp)
         END;
         GOTO algloop
      END ELSE GOTO return;
      getline;
      IF answer.[1] # controlchar THEN
      BEGIN
         errmess(TRUE,
"0974: A command line is required at this point.  As a result,[N]******  this line up to next command line will be ignored.");
         WHILE answer.[1] # controlchar DO getline
      END;

      out:
      getcontrolstart(4);
      GOTO loop;

      return:
   END of PR*CEDURE goanywherecommands;



   PROCEDURE putaway;
   COMMENT   --------------------------------------------------
   'Putaway'  writes  into  the lesson identifying phrases.  If
   teacher reports are generated and the student's answer to  a
   question  is unexpected, then this identifier will be paired
   with his answer and both  will  be  routed  to  the  teacher
   reports.   If  the  teacher  gave the question a label, then
   this label will also be included as part of the  identifying
   phrase.

   -----------------------------------------------------------;
   BEGIN
      INTEGER t;
      BEGIN
         Write("putaway(""%QUE");
         Print(qcount,2);
         IF Length(question) > 0 THEN
         BEGIN
            Write(";;;;");
            FOR pos2:= 1 STEP 1 UNTIL Length(question) DO
            BEGIN
               t:= question.[pos2];
               IF t = leftsquare OR t = rightsquare
               OR t = semicolon OR t = doublequote
               THEN Outsymbol(t);
               Outsymbol(t)
            END
         END;
         Write(""");;[N]")
      END
   END of PR*CEDURE putaway;



   PROCEDURE unknownmessage;
   COMMENT   --------------------------------------------------
   'Unknownmessage'  will  output  that  ALGOL program sequence
   which handles an answer  from  the  student  which  was  not
   expected  by  the  teacher  (i.e.,  a  "%NEUTRAL  or %WRONG"
   command with no teacher answer pattern following  it).   The
   ALGOL  program  produced will give an appropriate message to
   the student and write the unexpected answer into the teacher
   reports (if any) so that the teacher can study the answer in
   order to improve the lesson.  Unless ALL the answer commands
   following  a particular %QUESTION command have been %NEUTRAL
   commands, 'unknownmessage' causes a call  on  'wrongmessage'
   to be issued.
   -----------------------------------------------------------;
   BEGIN
      Write("BEGIN[N]");
      IF allneutral THEN
      BEGIN
         IF language = 1 THEN
         Write("Write(""I don't understand your answer.[[N]]"");;[N]")
         ELSE IF language = 2 THEN
         Write("Write(""Jag f`rst}r inte ditt svar.[[N]]"");;[N]")
      END
      ELSE Write("wrongmessage;;[N]");
      IF put THEN putaway
   END of PR*CEDURE unknownmessage;



   PROCEDURE zeroprint;
   COMMENT   --------------------------------------------------
   'Zeroprint' will output an ALGOL program sequence which will
   determine  whether the student answer was empty and, in that
   case, tell the student what happened and give  the  question
   once more to the student.
   -----------------------------------------------------------;
   BEGIN
      Write("IF answerlength = 0 THEN[N]");
      Write("BEGIN[N]");
      Write("noanswer;;[N]GOTO repeat;;[N]END;;[N]");
      zeroprinted:= TRUE
   END of PR*CEDURE zeroprint;



   PROCEDURE checkprecedence(n);
   INTEGER n;
   COMMENT   -------------------------------------------------
   'Checkprecedence'   does   some   rudimentary   checking  to
   determine whether the lesson author used GNOSIS commands  in
   the  proper  order,  warns  him  if he did not, and tries to
   recover from the error.  Not all errors  of  precedence  are
   caught  by  this  check since some are context-dependent.  A
   complete precedence table for GNOSIS commands appears below:

   =======================================================
   PRECEDENCE      COMMAND         COMMENT
   =======================================================
   0          %ALGOL          Use of these commands is
   0          %EXTRA          unrestricted.  They may go
   0          %GOTO           anywhere in the lesson.
   0          %IF
   0          %IFEND          However, the %SWITCH
   0          %IFNOT          command must precede
   0          %JUSTIFsY        %IF, %IFENDs and %IFNOTs.
   0          %NOEXTRA
   0          %NOJUSTIFY
   0          %NOORDER
   0          %ORDER
   -------------------------------------------------------
   1          %BELL           These commands (if used)
   1          %COPYRIGHT      must precede all those > 1.
   1          %DISK (also %DSK or %DSIC)
   1          %KEEP
   1          %LANGUAGE
   1          %LOCK
   1          %NAME
   1          %NEXTLESSON
   1          %NOCONTROLC
   1          %SGNOSIS
   1          %SWITCH
   1          %TEACHER
   -------------------------------------------------------
   2          %VARIABLES      This command (if used)
   must precede all those > 2.
   -------------------------------------------------------
   3          %HELP           These commands (if used)
   3          %PROCEDURE      must precede all those > 3.
   -------------------------------------------------------
   4          %INITIALIZE     This command (if used)
   must precede all those > 4.
   -------------------------------------------------------
   5          %LACK           These commands (if used)
   5          %NEUTRAL        must precede all those > 5.
   5          %QEND
   5          %QUESTION       After %QUESTION, %RIGHTs
   5          %RIGHT          precede %WRONGs (or %LACKs).
   5          %SAME           %NEUTRALs can go anywhere..
   5          %TEXT           Empty patterns of each type
   5          %WRONG          should appear last.
   -------------------------------------------------------
   6          %FINISH         This command (if used) must
   precede only the %END.
   -------------------------------------------------------
   7          %END            This command must be last.
   =======================================================

   Note:   GNOSIS  will  accept   some   contextually   awkward
   orderings  of  the  answer  pattern  commands.  For example,
   GNOSIS will accept %NEUTRAL at  any  point  after  %QUESTION
   even  though,  in the context of the lesson, that occurrence
   of %NEUTRAL may have unintended effects.
   -----------------------------------------------------------;
   BEGIN
      BOOLEAN legalcommand;
      STRING ARRAY command [1:16];
      INTEGER i;
      command[1]:= "LAN";
      command[2]:= "TEA";
      command[3]:= "COP";
      command[4]:= "NOC";
      command[5]:= "NEX";
      command[6]:= "SGN";
      command[7]:= "SWI";
      command[8]:= "KEE";
      command[9]:= "LOC";
      command[10]:= "BEL";
      command[11]:= "NAM";
      command[12]:= "DIS";
      command[13]:= "DSK";
      command[14]:= "VAR";
      command[15]:= "HEL";
      command[16]:= "PRO";
      WHILE NOT legalcommand DO
      BEGIN
         FOR i:= 1 STEP 1 UNTIL n DO
         BEGIN
            IF controlstart = command[i] THEN
            BEGIN
               errmess(FALSE,
               "1161:  Command is out of place here.  As a result,[N]****** this line up to next command line will be ignored.");
               getline;
               WHILE answer.[1] # controlchar DO getline;
               getcontrolstart(4);
               GOTO earlyexit
            END
            ELSE IF i = n THEN legalcommand:= TRUE;
         END;
         earlyexit:
      END
   END PR*CEDURE checkprecedence;



   PROCEDURE putvariables;
   COMMENT   -------------------------------------------------
   The translated GNOSIS lesson is prefaced by (1)  a  preamble
   of  global variable declarations (output by "putvariables"),
   (2) a  set  of  global  PROCEDURE  declarations  (output  by
   "putprocedures"),  (3) a set of statements to initialize the
   value of global variables (output by "putvalues"), and (4) a
   lesson   header   (output  by  putheader)  which  does  some
   additional initialization of I/O.
   -----------------------------------------------------------;
   BEGIN
      Write("BEGIN");
      Write(" COMMENT: This is the lesson """);
      Write(lessonname);
      Write(""";;[N]");
      IF put AND teacher # "" THEN
      BEGIN
         Write("COMMENT: This lesson was written by[N]");
         alglin(teacher);
         Write(";;");
         Newline
      END;
      COMMENT   -------------------------------------------------
      Output of data declarations follows.
      -----------------------------------------------------------;
      Write("BOOLEAN firsttry, ihaveblanked, nopause, skip, back, stop, message;;[N]");
      Write("INTEGER lasterrors, score, latescore, qcount, lastqcount, lastqkount, carriagereturn, linefeed, pos, blank;;[N]");
      Write("INTEGER lastscorecount, lastlatescorecount, lastscorekount, lastlatescorekount;;[N]");
      IF language = 2 THEN
      BEGIN
         Write("INTEGER lcaa, lcae, lcoe, ucaa, ucae, ucoe;;[N]")
      END;
      Write("INTEGER randno, answerlength, controlstart, controlg, uparrow;;[N]");
      Write("INTEGER lastrights;;[N]");
      Write("STRING answer, answercopy, char, endofline, lessonname, firstname, tempfile1, tempfile2, prompt;;[N]");
      Write("STRING ARRAY right, rightatlast, wrong[[0:9]];;[2N]");
   END of PR*CEDURE putvariables;


   PROCEDURE putprocedures;
   COMMENT   -------------------------------------------------
   'Putprocedures' is the second in a series of four procedures
   to output the lesson preface
   -----------------------------------------------------------;
   BEGIN
      IF nocontrolc THEN Write("EXTERNAL PROCEDURE stopkc;;[2N]");
      IF transferlesson THEN Write("EXTERNAL PROCEDURE pub, nolpt, run, r;;[2N]");

      IF put THEN Write("FORWARD PROCEDURE putaway;;[N]");

      Write("FORWARD BOOLEAN PROCEDURE anywhere;;[2N]");

      Write("PROCEDURE seloutputandstopkc(chan);;[N]");
      Write("INTEGER chan;;[N]");
      Write("BEGIN Selectoutput(chan);;[N]");
      IF nocontrolc THEN Write("stopkc;;[N]");
      Write("END;;[N]");
      Write("PROCEDURE getline;;[N]");
      Write("COMMENT: 'Getline' reads in a line of text input by the student,[N]");
      Write("dumping it in the STRING 'answer'. Column one of the line is checked[N]");
      Write("to see if the student typed '%', indicating that he wanted[N]");
      Write("to interrupt the flow of the lesson;;[N]");
      Write("BEGIN[N]INTEGER s, t, i;;[N]BOOLEAN quit;;[N]");
      Write("Breakoutput;;[N]quit:= FALSE;;[N]");
      Write("[N]again:[N]FOR i:= 1 STEP 1 UNTIL 132 DO[N]");
      Write("BEGIN[N]Insymbol(t);;[N]");
      Write("COMMENT: Lower case transform;;[N]");
      Write("IF t >= 97 AND t <= 122 THEN t:= t-32");
      IF language = 1 THEN Write(";;[N]")
      ELSE IF language = 2 THEN
      BEGIN
         Write(" ELSE[N]");
         Write("IF t = lcaa THEN t:= ucaa ELSE[N]");
         Write("IF t = lcae THEN t:= ucae ELSE[N]");
         Write("IF t = lcoe THEN t:= ucoe;;[N]")
      END;
      Write("answer.[[i]]:= t;;[N]");
      Write("IF t = carriagereturn THEN GOTO out;;[N]");
      Write("END;;[N]");
      Write("GOTO again;;[N]");
      Write("[N]out:[N]Insymbol(t);;[N]i:= i+1;;[N]answer.[[i]]:= t;;[N]pos:= 1;;[N]answerlength:= i-2;;[N]");
      Write("IF answerlength < 0 THEN answerlength:= 0;;[N]");
      Write("Delete(answercopy);;[N]answercopy:= Copy(answer,1,i);;[N]");
      Write("ihaveblanked:= FALSE;;[N]");
      Write("IF answerlength = 1 THEN[N]");
      Write("BEGIN[N]IF answer.[[1]] = controlstart THEN[N]");
      IF language = 1 THEN
      BEGIN
         Write("BEGIN[N]Write(""Answer 'STOP'"");;[N]");
         IF NOT lock THEN Write("Write("", 'SKIP', 'BACK', "");;[N]");
         Write("Write(""or 'CONTINUE'.[[N]]"");;[N]")
      END
      ELSE IF language = 2 THEN
      BEGIN
         Write("BEGIN[N]Write(""Svara """"STOPP"""" om Du vill l{mna lektionen,[[N]]"");;[N]");
         IF NOT lock THEN Write("Write(""""""SKIPPA"""" om Du vill skippa denna fr}ga,[[N]]"");;[N]");
         IF NOT lock THEN Write("Write(""""""BACKA"""" om Du vill g} tillbaka till en tidigare del av lektionen,[[N]]"");;[N]");
         Write("Write(""""""FORTS#TT"""" om Du vill forts{tta.[[N]]"");;[N]")
      END;
      IF bell THEN Write("Outsymbol(controlg);;[N]");
      Write("Write(prompt);;[N]Breakoutput;;[N]");
      Write("quit:= TRUE;;[N]GOTO again;;[N]");
      Write("END;;[N]END;;[N]");
      Write("IF quit THEN[N]");
      Write("BEGIN[N]quit:= FALSE;;[N]IF anywhere(""");
      IF language = 1 THEN Write("STOP")
      ELSE IF language = 2 THEN Write("STOPP");
      Write(""") THEN[N]BEGIN[N]");
      Write("stop:= TRUE;;[N]");
      IF language = 1 THEN Write("Write(""Lesson aborted."");;[N]") ELSE
      IF language = 2 THEN Write("Write(""Lektionen avbr`t.[[N]]"");;[N]");
      Write("GOTO exit;;[N]END;;[N]");
      Write("pos:= 1;;[N]IF anywhere(""");
      IF language = 1 THEN Write("SKIP")
      ELSE IF language = 2 THEN Write("SKIPPA");
      Write(""") THEN[N]");
      Write("BEGIN[N]Write(""");
      IF NOT lock THEN
      BEGIN
         IF language = 1 THEN Write("Question skipped.")
         ELSE IF language = 2 THEN Write("Fr}gan skippad.");
         Write("[[N]]"");;[N]skip:= TRUE;;[N]")
      END
      ELSE
      BEGIN
         IF language = 1 THEN Write("??? Skipping not allowed in this lesson.")
         ELSE IF language = 2 THEN Write("???");
         Write("[[N]]"");;[N]")
      END;
      Write("END[N]ELSE[N]BEGIN[N]");
      Write("pos:= 1;;[N]IF anywhere(""");
      IF language = 1 THEN Write("BACK")
      ELSE IF language = 2 THEN Write("BACKA");
      Write(""") THEN[N]");
      Write("BEGIN[N]Write(""");
      IF NOT lock THEN
      BEGIN
         IF language = 1 THEN Write("Lesson is backing.")
         ELSE IF language = 2 THEN Write("Lektionen g}r tillbaka.");
         Write("[[N]]"");;[N]back:= TRUE;;[N]")
      END
      ELSE
      BEGIN
         IF language = 1 THEN Write("??? Backing not allowed in this lesson.")
         ELSE IF language = 2 THEN Write("???");
         Write("[[N]]"");;[N]")
      END;
      Write("END[N]ELSE[N]BEGIN[N]");
      IF language = 1 THEN
      BEGIN
         Write("Write(""Please continue, then, giving your response[[N]]"");;[N]");
         Write("Write(""to the PREVIOUS '-->' or 'RETURN' prompt...[[N]]"");;[N]")
      END
      ELSE IF language = 2 THEN
      Write("Write(""Du vill inte avbryta nu. Forts{tt d} med ditt ordinarie svar.[[N]]"");;[N]");
      Write("GOTO again;;[N]");
      Write("END;;[N]END;;[N]");
      Write("END;;[2N]exit:[N]END;;[2N]");

      Write("BOOLEAN PROCEDURE here(comp);;[N]VALUE comp;;[N]STRING comp;;[N]");
      Write("COMMENT: 'Here' determines whether the argument string can be found[N]");
      Write("beginning at 'pos' in the student answer. Blanks, but nothing[N]");
      Write("else, may precede the matching word. 'Here' is mostly used[N]");
      Write("for answers matched in the %NOEXTRA mode;;[N]");
      Write("BEGIN[N]INTEGER cpos;;[N]");
      Write("[N]blankline:[N]IF answercopy.[[pos]] = blank THEN[N]");
      Write("BEGIN[N]pos:= pos+1;;[N]GOTO blankline;;[N]");
      Write("END;;[N]");
      Write("FOR cpos:= 1 STEP 1 UNTIL Length(comp) DO[N]");
      Write("BEGIN[N]");
      Write("IF answercopy.[[pos]] # comp.[[cpos]] THEN GOTO nofit;;[N]");
      Write("pos:= pos+1;;[N]");
      Write("END;;[N]");
      Write("here:= TRUE;;[N]GOTO out;;[N]");
      Write("[N]nofit:[N]here:= FALSE;;[N]");
      Write("[N]out:[N]END;;[2N]");

      Write("BOOLEAN PROCEDURE anywhere(comp);;[N]VALUE comp;;[N]STRING comp;;[N]");
      Write("COMMENT: 'Anywhere' determines whether the argument string can be [N]");
      Write("found anywhere in the student answer after 'pos'.  Blanks and[N]");
      Write("unmatched strings will be bypassed. 'Anywhere' is used in[N]");
      Write("the %EXTRA mode and in the %NOEXTRA %NOORDER mode.[N]");
      Write("'Anywhere' will substitute blanks for all characters in[N]");
      Write("the matched strings. This allows the program (e.g., in the[N]");
      Write("%NOEXTRA mode) to determine whether there are[N]");
      Write("any non-blank characters in the student answer. In the[N]");
      Write("%NOEXTRA mode, his answer will be wrong if any non-blank characters remain;;[N]");
      Write("BEGIN[N]INTEGER cpos, nextpos;;[N]");
      Write("[N]blankline:[N]IF answercopy.[[pos]] = blank THEN[N]");
      Write("BEGIN[N]pos:= pos+1;;[N]GOTO blankline;;[N]");
      Write("END;;[N]");
      Write("nextpos:= pos+1;;[N]");
      Write("FOR cpos:= 1 STEP 1 UNTIL Length(comp) DO[N]");
      Write("BEGIN[N]");
      Write("IF answercopy.[[pos]] # comp.[[cpos]] THEN GOTO nofit;;[N]");
      Write("pos:= pos+1;;[N]");
      Write("END;;[N]");
      Write("FOR cpos:= pos-Length(comp) STEP 1 UNTIL pos-1 DO[N]");
      Write("BEGIN[N]answercopy.[[cpos]]:= blank;;[N]");
      Write("END;;[N]");
      Write("anywhere:= ihaveblanked:= TRUE;;[N]GOTO out;;[N]");
      Write("[N]nofit:[N]IF answercopy.[[pos]] # carriagereturn THEN[N]");
      Write("BEGIN[N]pos:= nextpos;;[N]GOTO blankline;;[N]");
      Write("END;;[N]");
      Write("anywhere:= FALSE;;[N]");
      Write("[N]out:[N]END;;[2N]");

      Write("PROCEDURE restore;;[N]");
      Write("COMMENT: Since 'anywhere' substitutes blanks for matched parts of the student[N]");
      Write("answer, the original response must be restored before comparing[N]");
      Write("it to other target patterns. This restoration is done here;;[N]");
      Write("BEGIN[N]ihaveblanked:= FALSE;;[N]");
      Write("Delete(answercopy);;[N]answercopy:= Copy(answer,1,answerlength+2);;[N]");
      Write("END;;[2N]");
      Write("INTEGER PROCEDURE random;;[N]");
      Write("COMMENT: 'Random' is a number generator which gives a random[N]");
      Write("number between 0 and 9. The generator will not repeat[N]");
      Write("itself until after 862 generations;;[N]");
      Write("BEGIN[N]");
      Write("randno:= randno*10 rem 863;;[N]");
      Write("random:= randno div 87;;[N]");
      Write("END;;[2N]");

      Write("PROCEDURE personalize(message);;[N]VALUE message;;[N]STRING message;;[N]");
      Write("COMMENT:  'Personalize' uses the student's firstname in conversational[N]");
      Write("I/O to give a personal touch to the lessons.  To avoid monotony[N]");
      Write("and to further efficiency, the probability that the message will be[N]");
      Write("personalized is only .2;;[N]");
      Write("BEGIN[N]IF firstname = """" OR random < 8 THEN Write(message)[N]");
      Write("ELSE BEGIN[N]INTEGER i, j;;[N]i:= 1;;[N]j:= Length(message);;[N]");
      Write("WHILE i < j DO[N]BEGIN[N]Outsymbol(message.[[i]]);;i:= i + 1;;[N]END;;[N]");
      Write("Write("", "");;[N]Write(firstname);;[N]Outsymbol(message.[[j]]);;[N]");
      Write("END;;[N]END;;[2N]");


      Write("PROCEDURE rightmessage;;[N]");
      Write("COMMENT: 'Rightmessage' is called when a student has[N]");
      Write("made a correct answer. He is told about this, and the[N]");
      Write("score is updated. The message to the student is different[N]");
      Write("depending on whether he succeeds on the fist try or[N]");
      Write("only after previous fruitless attempts.  Random numbers are[N]");
      Write("used to choose between ten different messages to give[N]");
      Write("some variation to the conversation;;[N]");
      Write("BEGIN[N]");
      Write("lastrights:= lastrights+1;;[N]");
      Write("IF firsttry THEN[N]");
      Write("BEGIN[N]score:= score+1;;[N]qcount:= qcount+1;;[N]firsttry:= FALSE;;[N]");
      Write("personalize(right[[random]]);;[N]");
      Write(
      "END[N]ELSE[N]BEGIN[N]personalize(right[[random]]);;[N]IF lasterrors > 1 THEN Write(rightatlast[[random]]);;[N]END;;[N]");
      IF language = 1 THEN
      BEGIN
         Write("IF lasterrors > 3 THEN[N]BEGIN[N]");
         Write("personalize(""[[N]]I must admit that last one was a bit tricky!"");;[N]");
         Write("Newline;;[N]END;;[N]");
      END;
      Write("latescore:= latescore+1;;[N]Newline;;[N]");
      Write("END;;[2N]");

      Write("PROCEDURE wrongmessage;;[N]");
      Write("COMMENT: 'Wrongmessage' is called when a student[N]");
      Write("has made an erroneous answer. He is told about this,[N]");
      Write("and the lesson statistics are updated.  Random numbers[N]");
      Write("are used to choose between ten different messages in order[N]");
      Write("provide some variation in the conversation;;[N]");
      Write("BEGIN[N]");
      Write("lasterrors:= lasterrors+1;;[N]");
      Write("IF firsttry THEN[N]");
      Write("BEGIN[N]qcount:= qcount+1;;[N]firsttry:= FALSE;;[N]");
      Write("END;;[N]");
      Write("personalize(wrong[[random]]);;[N]Newline;;[N]");
      Write("END;;[2N]");


      Write("PROCEDURE pause;;[N]");
      Write("COMMENT: Lesson text is given to the student in small portions.[N]");
      Write("One reason for this is that it is easier to read a little[N]");
      Write("at a time. Another reason is that display terminals have[N]");
      Write("a limited screen size. The 'pause' PROCEDURE produces a pause[N]");
      Write("in the display of text to the student, and she can continue[N]");
      Write("whenever she has finished examining the displayed material.[N]");
      Write("To go on, she simply pushes the 'RETURN' key. Normally, this[N]");
      Write("PROCEDURE is called between each %TEXT or %QUESTION,[N]");
      Write("but GNOSIS will introduce ADDITIONAL automatic pause points[N]");
      Write("within large blocks of text or question material.[N]");
      Write("The teacher can inhibit pauses BETWEEN '%' commands by 'nopause:= TRUE', but[N]");
      Write("the pauses which GNOSIS inserts in long text blocks cannot be inhibited;;[N]");
      Write("IF nopause THEN nopause:= FALSE ELSE[N]");
      Write("BEGIN[2N][N]");
      IF language = 1 THEN Write("Write(""[[N]]Push RETURN "");;[N]") ELSE
      IF language = 2 THEN Write("Write(""[[N]]Tryck RETURN "");;[N]");
      Write("write(prompt);;[N]");
      IF bell THEN Write("Outsymbol(controlg);;[N]");
      Write("getline;;[N]Newline;;[N]");
      Write("IF stop THEN[N]BEGIN[N]stop:= FALSE;;[N]GOTO endoflesson[N]END;;[N]");
      Write("IF answerlength > 0 THEN[N]");
      Write("BEGIN[N]pos:= 1;;[N]");
      Write("IF NOT here(endofline) THEN[N]BEGIN[N]");
      IF language = 1 THEN textline("Eh?   The computer expected you would just push the RETURN button.") ELSE
      IF language = 2 THEN textline("??? Datorn v{ntade sig bara RETURN fr}n Dig.");
      Write("END;;[N]END;;[N]");
      Write("END;;[2N]");

      Write("PROCEDURE page;;[N]");
      Write("COMMENT: 'Page' can be called by the teacher when he[N]");
      Write("wants to blank the screen on a display terminal).[N]");
      Write("The effect produced is, of course, terminal dependent;;[N]");
      Write("BEGIN[N]pause;;[N]Outsymbol(12);;[N]Outsymbol(12);;[N]Newline;;[N]");
      Write("END;;[2N]");

      Write("PROCEDURE extratest;;[N]");
      Write("COMMENT: 'Extratest' will flag and display those parts of the student answer [N]");
      Write("which WERE matched by the teacher answer pattern IF the[N]");
      Write("student response contained extra (i.e., superfluous) characters[N]");
      Write("'Extratest' is called automatically for %RIGHT answers in the[N]");
      Write("%EXTRA mode.  Recall that 'here' scans past leading blanks;;[N]");
      Write("BEGIN[N]");
      Write("pos:= 1;;[N]IF NOT here(endofline) THEN[N]");
      Write("BEGIN[N]Newline;;[N]");
      Write("FOR pos:= 1 STEP 1 UNTIL answerlength + 2 DO Outsymbol(answer.[[pos]]);;[N]");
      Write("FOR pos:= 1 STEP 1 UNTIL answerlength DO[N]");
      Write("IF answercopy.[[pos]] = blank AND answer.[[pos]] # blank THEN Outsymbol(uparrow) ELSE Outsymbol(blank);;[N]");
      Write("Newline;;[N]Newline;;[N]");
      Write("END;;[N]");
      Write("END;;[2N]");

      Write("REAL PROCEDURE percent;;[N]");
      Write("COMMENT: 'Percent' returns the percentage of questions answered correctly[N]");
      Write("by the student on his very first try since the start of the lesson;;[N]");
      Write("percent:= IF qcount = 0 or score = 0 THEN 0.0 ELSE 100.0 * score/qcount;;[2N]");

      Write("REAL PROCEDURE latepercent;;[N]");
      Write("COMMENT: 'Latepercent' returns the percentage of questions answered correctly[N]");
      Write("by the student since the start of the lesson whether[N]");
      Write("student was correct on the first try or afterward;;[N]");
      Write("latepercent:= IF qcount = 0 or latescore = 0 THEN 0.0 ELSE 100.0 * latescore/qcount;;[2N]");

      Write("INTEGER PROCEDURE lastscore;;[N]");
      Write("COMMENT: 'Lastscore' returns number of questions answered correctly on the[N]");
      Write("very first try since this PROCEDURE was last called;;[N]");
      Write("BEGIN[N]lastscore:= score - lastscorecount;;[N]lastscorecount:= score[N]END;;[2N]");

      Write("INTEGER PROCEDURE lastlatescore;;[N]");
      Write("COMMENT: 'Lastlatescore' returns number of questions answered correctly[N]");
      Write("since this PROCEDURE was last called whether student was correct on the[N]");
      Write("very first try or afterward;;[N]");
      Write("BEGIN[N]lastlatescore:= latescore - lastlatescorecount;;[N]lastlatescorecount:= latescore[N]END;;[2N]");

      Write("REAL PROCEDURE lastpercent;;[N]");
      Write("COMMENT: 'Lastpercent' returns the percentage of questions answered correctly[N]");
      Write("on the very first try since this PROCEDURE was last called;;[N]");
      Write("BEGIN[N]INTEGER x;;[N]");
      Write("x:= score - lastscorekount;;[N]lastscorekount:= score;;[N]lastqcount:= qcount - lastqcount;;[N]");
      Write("lastpercent:= IF lastqcount = 0 or x = 0 THEN 0.0 ELSE 100.0 * x/lastqcount;;[N]");
      Write("END;;[2N]");

      Write("REAL PROCEDURE lastlatepercent;;[N]");
      Write("COMMENT: 'Lastlatepercent' returns the percentage of questions answered correctly[N]");
      Write("since this PROCEDURE was last called whether student was correct on the first try[N]");
      Write("or afterward;;[N]");
      Write("BEGIN[N]INTEGER x;;[N]");
      Write("x:= latescore - lastlatescorekount;;[N]lastlatescorekount:= latescore;;[N]lastqkount:= qcount - lastqkount;;[N]");
      Write("lastlatepercent:= IF lastqkount = 0 or x = 0 THEN 0.0 ELSE 100.0 * x/lastqkount;;[N]");
      Write("END;;[2n]");
      IF put THEN
      BEGIN

         Write("PROCEDURE putaway(question);;[N]");
         Write("COMMENT: If the lesson contained a report-generating command,[N]");
         Write("then unexpected student answers are written into a pair of reports,[N]");
         Write("<lessonname>.DTA and <lessonname>.SRT, which the teacher can use to improve the[N]");
         Write("lesson. 'Putaway' writes the unexpected answers in these files;;[N]");
         Write("VALUE question;;[N]STRING question;;[N]");
         Write("BEGIN[N]INTEGER i;;[N]");
         Write("Breakoutput;;[N]");
         Write("seloutputandstopkc(2);;[N]");
         Write("Write(question);;[N]Write("": "");;[N]");
         Write("FOR i:= 1 STEP 1 UNTIL answerlength DO Outsymbol(answer.[[i]]);;[N]");
         Write("Newline;;[N]");
         Write("Breakoutput;;[N]");
         Write("seloutputandstopkc(3);;[N]");
         Write("Write(question);;[N]Write("": "");;[N]");
         Write("FOR i:= 1 STEP 1 UNTIL answerlength DO Outsymbol(answer.[[i]]);;[N]");
         Write("Newline;;[N]");
         Write("Breakoutput;;[N]");
         Write("seloutputandstopkc(0);;[N]");
         Write("END;;[2N]");
         IF teacher # "" THEN
         BEGIN

            Write("PROCEDURE putmessage;;[N]");
            Write("COMMENT: If no disk files are being generated for teacher reports,[N]");
            Write("'Putmessage' will tell the student to send hardcopy reports [N]");
            Write("to the teacher -- unless no teacher's name and address[N]");
            Write("was supplied with %TEACHER command);;[N]");
            Write("BEGIN[N]");
            IF language = 1 THEN
            BEGIN
               textline("He needs the listing to improve the lesson.");
               IF NOT name THEN textline("You can send it anonymously - the teacher will");
               IF NOT name THEN textline("not know which student sent it to him.");
               Write("Newline;;[N]");
               textline("The name and address of the teacher is:")
            END
            ELSE IF language = 2 THEN
            BEGIN
               textline("Han beh`ver den f`r att kunna g`ra lektionen b{ttre.");
               IF NOT name THEN textline("Du kan s{nda den anonymt - l{raren beh`ver inte veta");
               IF NOT name THEN textline("vilken elev som s{nde den till honom.");
               Write("Newline;;[N]");
               textline("L{rarens namn och adress {r:")
            END;
            textline(teacher);
            Write("Newline;;[N]END;;[2N]")
         END
      END;

      Write("PROCEDURE noanswer;;[N]");
      Write("BEGIN[N]");
      IF language = 1 THEN
      BEGIN
         Write("personalize(""??? You gave no answer at all."");;[N]Newline;;[N]");
         Write("Write(""If you want to interrupt the lesson, then type the single character """"")
      END
      ELSE IF language = 2 THEN
      BEGIN
         Write("personalize(""??? Du gav inget svar alls."");;[N]Newline;;[N]");
         Write("Write(""Om Du vill g} ut ur fr}gan, s} skriv det enda tecknet """"")
      END;
      Outsymbol(controlchar);
      Write(""""".[[N]]"");;[N]");
      Write("end noanswer;;[2N]");

      Write("PROCEDURE tryagain;;[N]");
      Write("COMMENT:  Questions output to students who give no answer, a wrong[N]");
      Write("answer, or an incomplete answer are usually repeated by GNOSIS.[N]");
      Write("'Tryagain' will output to such students a 'try again' message[N]");
      Write("which varies according to circumstances.  In %NEUTRAL mode,[N]");
      Write("the message will always be 'Please try again'.  Otherwise,[N]");
      Write("the content of the message depends on the number of times[N]");
      Write("the student has failed to give a correct response;;[N]");
      IF language = 1 THEN
      BEGIN
         Write("BEGIN[N]Newline;;[N]");
         Write("personalize(""Please try again."");;[N]");
         Write("IF lasterrors = 3 THEN Write(""[[N]]You have at least eliminated some of the possibilities."") ELSE[N]");
         Write("IF lasterrors = 4 THEN Write(""[[N]](You might want to rethink some of your previous answers.)"") ELSE[N]");
         Write("IF lasterrors > 4 THEN Write(""[[N]]Or...interrupt the lesson by typing the symbol """"");
         Outsymbol(controlchar);
         Write("""""."");;[N]");
         Write("Newline;;[N]Newline;;[N]");
         Write("END;;[2N]")
      END
      ELSE IF language = 2 THEN
      BEGIN
         Write("BEGIN[N]Newline;;[N]");
         Write("personalize(""F`rs`k igen."");;[N]");
         Write("IF lasterrors = 3 THEN Write(""[[N]]Ddu har eliminerat flera m`jligheter redan."") ELSE[N]");
         Write("IF lasterrors > 3 THEN Write(""[[N]]Eller...avbryt lektionen genom att skriva symbolen """"");
         Outsymbol(controlchar);
         Write("""""."");;[N]");
         Write("[N]Newline;;[N]Newline;;[N]END;;[2N]")
      END;

      Write("PROCEDURE giveanswer;;[N]");
      Write("COMMENT:  'Giveanswer' displays a right answer to a student who is skipping[N]");
      Write("the question or who repeatedly fails to give a right answer.[N]");
      Write("The answer given will always be the one following the FIRST[N]");
      Write("%RIGHT command for the preceding %QUESTION;;[N]");
      Write("BEGIN[N]");
      IF language = 1 THEN
      BEGIN
         Write("Newline;;[N]personalize(""Just for the record,"");;[N]");
         Write("Write("" GNOSIS will simulate an acceptable answer:[[2N]]-->"");;[N]");
      END
      ELSE IF language = 2 THEN
      BEGIN
         Write("Newline;;[N]personalize(""F`r den h{ndelse du {r intresserad,"");;[N]");
         Write("Write("" h{r {r ett svar[[N]]"");;[N]");
         Write("Write(""vilket skulle ha varit acceptabelt:[2N]-->"");;[N]")
      END;
      Write("END;;[N]");
   END of PR*CEDURE putprocedures;


   PROCEDURE putvalues;
   COMMENT   -------------------------------------------------
   'Putvalues' writes code which handles the initialization  of
   variables  before  the  start  of the lesson.  This is phase
   three of the preface output routines.
   -----------------------------------------------------------;
   BEGIN
      Write(
      "[4N]lasterrors:= latescore:= score:= lastqcount:= lastqkount:= qcount:= 0;;[N]");
      Write("carriagereturn:= 13;;[N]linefeed:= 10;;[N]");
      Write("lastrights:= lastscorecount:= lastscorekount:= lastlatescorecount:= lastlatescorekount:= 0;;[N]");
      Write("blank:= "" "".[[1]];;uparrow:= ""^"".[[1]];;[N]controlg:="""".[[1]];;[N]");
      IF language = 2 THEN
      BEGIN
         Write("ucaa:= ""$"".[[1]];;[N]ucae:= ""#"".[[1]];;[N]ucoe:= ""@"".[[1]];;[N]");
         Write("lcaa:= ""}"".[[1]];;[N]lcae:= ""{"".[[1]];;[N]lcoe:= ""`"".[[1]];;[N]")
      END;
      Write("answer:= Newstring(135,7);;[N]answercopy:= Copy("" "");;[N]firstname:= """";;[N]prompt:= Copy(""-->"");;[N]");
      Write("answer.[[134]]:= carriagereturn;;[N]answer.[[135]]:= linefeed;;[N]");
      Write("char:= Newstring(1,7);;[N]");
      Write("endofline:= Newstring(1,7);;[N]endofline.[[1]]:= carriagereturn;;[N]");
      Write("randno:= 1;;[N]nopause:= skip:= message:= FALSE;;[N]");
      Write("controlstart:= """);
      Outsymbol(controlchar);
      Write(""".[[1]];;[N]");
      Write("lessonname:= """);
      Write(lessonname);
      Write(""";;[N]");
      BEGIN
         COMMENT   -------------------------------------------------
         Here the 30 STRINGs with different responses  to  right  and
         wrong  student  answers are initialized.  A simple PROCEDURE
         "m"  is  used  to  simplify  the  repetitive  part  of  this
         initialization.
         -----------------------------------------------------------;
         INTEGER type, index;
         STRING arrayname;



         PROCEDURE m(message);
         STRING message;
         BEGIN
            IF index = 9 THEN
            BEGIN
               index:= 0;
               type:= type+1;
               IF type = 1 THEN arrayname:= "right" ELSE
               IF type = 2 THEN arrayname:= "rightatlast" ELSE
               IF type = 3 THEN arrayname:= "wrong"
            END ELSE index:= index+1;
            Write(arrayname);
            Write("[[");
            Print(index,1);
            Write("]]:= """);
            Write(message);
            Write(""";;[N]")
         END of PR*CEDURE m;

         type:= 0;
         index:= 9;
         IF language = 1 THEN
         BEGIN
            m("Good for you!");
            m("Very good.");
            m("Sure!");
            m("Bravo!");
            m("Exactly right!");
            m("Right!");
            m("Well done!");
            m("That's it!");
            m("Excellent!");
            m("OK!");
            m("  You're doing better!");
            m("  Now you're catching on!");
            m("  You're improving!");
            m("  Yo've got the idea now!");
            m("  I knew you could do it.");
            m("  There is hope for you after all!");
            m("  You're making progress.");
            m("  Aren't you glad you kept trying?");
            m("  Keep up the good work!");
            m("  You've got the hang of it now.");
            m("Wrong!");
            m("No!");
            m("You gave the wrong answer.");
            m("Your answer was wrong.");
            m("Incorrect!");
            m("No, you're wrong this time.");
            m("Sorry.");
            m("That wasn't correct.");
            m("You're mistaken.");
            m("No, you missed this one.")
         END
         ELSE IF language = 2 THEN
         BEGIN
            m("Bra gjort!");
            m("Mycket bra.");
            m("Javisst!");
            m("Utm{rkt!");
            m("Precis r{tt.");
            m("R{tt!");
            m("Korrekt.");
            m("Du svarade r{tt igen.");
            m("Bra!");
            m("OK!");
            m("  Just det - Du klarar dig b{ttre nu.");
            m("  Nu b`rjar Du fatta!");
            m("  B{ttre och b{ttre!");
            m("  Nu har Du fattat det hela!");
            m("  Javisst! Nu klarar Du det h{r.");
            m("  S}ja, till slut g}r det bra!");
            m("  Du g`r framsteg.");
            m("  #ntligen r{tt!");
            m("  Bra! Forts{tt p} det s{ttet.");
            m("  Just det. Bara man anstr{nger sig lite s} g}r det bra.");
            m("Fel!");
            m("Nej!");
            m("Du valde fel svar.");
            m("Ditt svar var felaktigt.");
            m("Det {r inte r{tt!");
            m("Nej, den h{r g}ngen svarade Du fel.");
            m("Tyv{rr inte r{tt.");
            m("Det d{r {r inte riktigt.");
            m("Nej, inte riktigt s}.");
            m("Nej, den fr}gan missade Du.")
         END;
         Newline
      END;
   END of PR*CEDURE putvalues;


   PROCEDURE putheader;
   COMMENT   -------------------------------------------------
   'Putheader' is the last of four procedures  used  to  output
   the  lesson  preface.   This  procedure  writes  code  which
   handles I/O initialization.
   -----------------------------------------------------------;
   BEGIN
      Write("[N]Input(0,""TTY"");;[N]");
      IF put THEN
      BEGIN
         IF NOT disk THEN Write("Output(2,""LPT"");;[N]seloutputandstopkc(2);;[N]");
         IF disk THEN Write("Input(1,""DSK"");;[N]Output(2,""DSK"");;[N]Output(3,""DSK"");;[N]");
         IF NOT disk AND NOT keep THEN
         BEGIN
            IF language = 1 THEN textline("Please send this listing to the teacher.") ELSE
            IF language = 2 THEN textline("L{raren {r tacksam om Du s{nder denna lista till honom.");
            Write("putmessage;;[N]")
         END;
         Write("Breakoutput;;[N]");
         Write("seloutputandstopkc(0);;[2N]")
      END;
      IF nocontrolc THEN Write("stopkc;;[N]");
      COMMENT   -------------------------------------------------
      Now we write  code  which  displays  certain  standard  text
      material  to  the  student at the beginning of a new lesson.
      Most of this code will  NOT  be  written  into  the  lesson,
      however, if the %SGNOSIS command was used.
      -----------------------------------------------------------;
      IF name THEN
      BEGIN
         IF language = 1 THEN
         BEGIN
            Write("Write(""[[N]]Hello!  This is GNOSIS talking.[[N]]"");;[N]");
            Write("[N]repeat:[N]Write(""I'd like to know your full name--[[N]]just type it in after the arrow.[[N]]"");;[N]");
            IF put THEN
            BEGIN
               COMMENT The following code brings GNOSIS into compliance with privacy laws;
               Write("Write(""[[NT]](Unless you enter a made-up name, GNOSIS will"");;[N]");
               Write("Write(""[[NT]]generate personal data based on this session.)[[2N]]"");;[N]")
            END;
            IF bell THEN Write("Outsymbol(controlg);;[N]");
            Write("Write(prompt);;[N]getline;;[N]");
            Write("IF answerlength < 6 THEN[N]");
            Write("BEGIN[N]Write(""That's too short to be your FULL name.[[N]]"");;[N]Newline;;[N]GOTO repeat;;[N]END;;[N]");
            Write("FOR pos:= 1 STEP 1 UNTIL answerlength DO IF answer.[[pos]] = blank THEN GOTO continue;;[N]");
            Write("Write(""That's only ONE of your names.[[N]]"");;[N]GOTO repeat;;[N]");
            Write("[N]continue:[N]Write(""Glad to meet you, "");;[N]")
         END
         ELSE IF language = 2 THEN
         BEGIN
            Write("Write(""[[N]]Hej!  Det h{r {r GNOSIS-programmet som talar.[[N]]"");;[N]");
            Write("[N]repeat:[N]Write(""Jag skulle vilja veta ditt fullst{ndiga namn--skriv det p} terminalen.[[N]]"");;[N]");
            IF bell THEN Write("Outsymbol(controlg);;[N]");
            Write("Write(prompt);;[N]getline;;[N]");
            Write("IF answerlength < 6 THEN[N]");
            Write("BEGIN[N]Write(""???[[N]]"");;[N]Newline;;[N]GOTO repeat;;[N]END;;[N]");
            Write("FOR pos:= 1 STEP 1 UNTIL answerlength DO IF answer.[[pos]] = blank THEN GOTO continue;;[N]");
            Write("Write(""???[[N]]"");;[N]GOTO repeat;;[N]");
            Write("[N]continue:[N]Write(""Trevligt att tr{ffas, "");;[N]")
         END;
         Write("BEGIN[N]INTEGER pos, t;;[N]");
         Write("pos:=1;;[N]");
         Write("[N]nameloop:[N]t:=answer.[[pos]];;[N]");
         Write("IF pos<answerlength THEN[N]");
         Write("BEGIN[N]IF t#blank THEN[N]");
         Write("BEGIN[N]pos:=pos+1;;[N]GOTO nameloop;;[N]");
         Write("END;;[N]");
         Write("END;;[N]");
         Write("firstname:=Copy(answer,1,pos-1);;[N]");
         Write("Write(firstname);;[N]Write(""!"");;[N]");
         Write("END;;[N]");
         IF disk THEN
         BEGIN
            Write("tempfile1:= tempfile2:= Newstring(Length(firstname)+5,7);;[N]");
            Write("FOR pos:= 1 STEP 1 UNTIL Length(firstname) DO tempfile1.[[pos]]:= tempfile2.[[pos]]:= firstname.[[pos]];;[N]");
            Write("IF firstname.[[Length(firstname)]] # ""."".[[1]] THEN ");
            Write("tempfile1.[[pos+1]]:= tempfile2.[[pos+1]]:= ""."".[[1]][N]");
            Write("ELSE pos:= pos - 2;;[N]");
            Write("tempfile1.[[pos+2]]:= ""D"".[[1]];;[N]");
            Write("tempfile1.[[pos+3]]:= ""T"".[[1]];;[N]");
            Write("tempfile1.[[pos+4]]:= ""A"".[[1]];;[N]");
            Write("tempfile2.[[pos+2]]:= ""S"".[[1]];;[N]");
            Write("tempfile2.[[pos+3]]:= ""R"".[[1]];;[N]");
            Write("tempfile2.[[pos+4]]:= ""T"".[[1]];;[N]");
            Write("Openfile(2,tempfile1,%057);;[N]");
            Write("Openfile(3,tempfile2,%057);;[N]");
            IF nocontrolc THEN Write("stopkc;;[N]")
         END;
         IF put THEN
         BEGIN
            Write("seloutputandstopkc(2);;[N]");
            IF language = 1 THEN
            BEGIN
               Write("Write(""[[P]]TEACHER REPORT FOR THE LESSON: ");
               Write(lessonname);
               Write("[[2N]]"");;[N]");
               Write("Write(""STUDENT'S NAME: "");;[N]");
               Write("FOR pos:= 1 STEP 1 UNTIL answerlength DO Outsymbol(answer.[[pos]]);;[N]");
               Write("Newline;;[N]");
               Write("Write(""[[N]]TRACE OF UNEXPECTED ANSWERS:[[N]]"");;[N]Breakoutput;;[N]seloutputandstopkc(0);;[N]")
            END
            ELSE IF language = 2 THEN
            BEGIN
               Write("Write(""[[P]]L#RARRAPPORT F@R LEKTIONEN: ");
               Write(lessonname);
               Write("[[2N]]"");;[N]");
               Write("seloutputandstopkc(2);;[N]");
               Write("Write(""ELEVENS NAMN: "");;[N]");
               Write("FOR pos:= 1 STEP 1 UNTIL answerlength DO Outsymbol(answer.[[pos]]);;[N]");
               Write("Newline;;[N]");
               Write("Write(""[[N]]SP$RNING AV OV#NTADE SVAR:[[N]]"");;[N]Breakoutput;;[N]seloutputandstopkc(0);;[N]")
            END
         END
      END;
      IF NOT sgnosis THEN
      BEGIN
         IF language = 1 THEN
         BEGIN
            Write("Write(""[[2N]]Welcome to the lesson '"");;[N]");
            Write("Write(lessonname);;[N]");
            Write("Write(""'"");;[N]");
            IF copyright # "" THEN
            BEGIN
               Write("Write("",[[N]]");
               Write(copyright);
               Write(""");;[N]");
            END;
            Write("Write("".[[2N]]"");;[N]");
            Write("Write(""This lesson was  produced  by  the  GNOSIS  system  for  computer  aided[[N]]"");;[N]");
            Write("Write(""instruction  (CAI)  from  the  Research  Institute  of National Defense[[N]]"");;[N]");
            Write("Write(""Stockholm, Sweden, and the Old Dominion University Research Foundation.[[N]]"");;[N]")
         END
         ELSE IF language = 2 THEN
         BEGIN
            Write("Write(""[[2N]]Detta {r lektionen '");
            Write(lessonname);
            Write("'"");;[N]");
            IF copyright # "" THEN
            BEGIN
               Write("Write("",[[N]]");
               Write(copyright);
               Write(","");;[N]");
            END;
            Write("Write(""[[N]]producerad av GNOSIS-systemet "");;[N]");
            textline("f`r datorst`dd undervisning(DU) fr}n");
            textline("F`rsvarets forskningsanstalt, Stockholm.")
         END;
         Write("Newline;;[N]");
         IF put THEN
         BEGIN
            IF teacher # "" THEN
            BEGIN
               IF language = 1 THEN textline("The author of this lesson is...") ELSE
               IF language = 2 THEN textline("Den l{rare som skrev den h{r lektionen {r...");
               textline(teacher)
            END
         END;
         IF language = 1 THEN
         Write("Write(""[[N]]IMPORTANT: You can interrupt the lesson at any time by typing the[[N]]single character """"")
         ELSE
         IF language = 2 THEN Write("Write(""Du kan avbryta lektionen n{r som helst genom att skriva[[N]]det enda tecknet """"");
         Outsymbol(controlchar);
         IF language = 1 THEN Write(""""""");;[N]") ELSE
         IF language = 2 THEN Write(""""""");;[N]");
         IF language = 1 THEN Write("Write("" on your terminal and then pushing the RETURN button.[[2N]]"");;[N]")
         ELSE IF language = 2 THEN Write("Write("" p} Din terminal och sedan trycka p} RETURN-knappen.[[N]]"");;[N]");
         IF NOT lock THEN
         BEGIN
            IF language = 1 THEN
            BEGIN
               Write("Write(""GNOSIS will then explain how you can type"");;[N]");
               Write("Write(""[[NT]](1) 'STOP' to end the lesson immediately;;;;"");;[N]");
               Write("Write(""[[NT]](2) 'SKIP' to move on to the next question (or text);;;; or"");;[N]");
               Write("Write(""[[NT]](3) 'BACK' to return to the previous question (or text).[[2N]]"");;[N]")
            END
            ELSE IF language = 2 THEN
            BEGIN
               Write("Write(""D{refter kan du[[NT]]- avsluta hela lektionen eller[[NT]]- bara hoppa");
               IF NOT lock THEN Write(" `ver en fr}ga eller[[NT]]- g} tillbaka i lektionen.[[2N]]"");;[N]")
            END
         END;
         Write("page;;[2N]")
      END;
      Newline;
      Write(mainlab);
      Write(": ");
      Write("[N]start:[N]");
      Write("BEGIN[N]INTEGER blockmaker;;[N]")
   END of PR*CEDURE putheader;



   PROCEDURE putfinish;
   COMMENT   -------------------------------------------------
   'Putfinish' prints that part  of  the  ALGOL  program  which
   comes  after  the  proper  translation of the lesson itself.
   This part tells the student his score, accepts messages from
   him  for the teacher, and closes the files which contain the
   teacher reports.  In %SGNOSIS mode, however,  code  will  be
   written  which  causes  the  lesson  to  end  more directly,
   without issuing score reports, etc.
   -----------------------------------------------------------;
   BEGIN
      Write("END of block started with makeblock INTEGER;;[4N]");
      IF NOT lock AND labelcount > 0 THEN
      BEGIN
         INTEGER i, j;
         mainlab:= Copy("ZQXAAA");
         Write("IF FALSE THEN[N]BEGIN[N]");
         j:= labelcount;
         FOR i:= 1 STEP 1 UNTIL j DO
         BEGIN
            makemainlab;
            Newline;
            Write(mainlab);
            Write(":[N]")
         END;
         IF language = 1 THEN
         BEGIN
            Write("Write(""NOTE:  The backing procedure is unable to go back just ONE step [[N]]"");;[N]");
            Write("Write(""from this point.  It is going all the way back to the start.[[N]]"");;[N]")
         END
         ELSE IF language = 2 THEN
         BEGIN
            Write("Write(""Jag kan inte g} en liten bit bak}t p.g.a. lektionens komplexitet[[N]]"");;[N]");
            Write("Write(""utan m}ste backa till lektionens b`rjan. F`rl}t![[N]]"");;[N]")
         END;
         Write("GOTO start;;[N]END;;[N]")
      END;
      Write("[N]endoflesson:[N]Newline;;[N]");
      IF NOT sgnosis THEN
      BEGIN
         IF language = 1 THEN
         BEGIN
            Write("Write(""During the lesson """"");
            Write(lessonname);
            Write(""""" you answered"");;[N]Print(qcount,3);;[N]");
            Write("Write("" questions,[[N]]and you gave the right answer"");;[N]Print(latescore,3);;[N]");
            Write("Write("" times.[[N]]On"");;[N]Print(score,3);;[N]");
            Write("Write("" questions your answer was right on your very first try.[[N]]"");;[N]")
         END
         ELSE IF language = 2 THEN
         BEGIN
            Write("Write(""Lektion """"");
            Write(lessonname);
            Write(""""" {r slut.[[N]]Du har svarat p}"");;[N]Print(qcount,3);;[N]");
            Write("Write("" fr}gor, [[N]]och Du gav r{tt svar"");;[N]Print(latescore,3);;[N]");
            Write("Write("" g}nger.[[N]]P}"");;[N]Print(score,3);;[N]");
            Write("Write("" fr}gor gav Du r{tt svar f`rsta g}ngen Du fick fr}gan.[[N]]"");;[N]")
         END
      END;
      IF put THEN
      BEGIN
         IF NOT keep AND NOT disk THEN
         BEGIN
            IF language = 1 THEN
            BEGIN
               Write("Write(""[[2N]]This lesson has produced a report sheet for the teacher.[[N]]"");;[N]");
               Write("Write(""This sheet will be printed on the line printer.[[N]]"");;[N]")
            END ELSE
            IF language = 2 THEN
            BEGIN
               textline("[[2N]]Denna lektion har producerat ett rapportblad till l{raren.");
               textline("Detta blad kommer att skrivas ut p} radskrivaren.")
            END;
            IF language = 1 THEN
            BEGIN
               textline("Please send the line printer listing (not the listing");
               textline("at the conversational terminal!) to the teacher.")
            END ELSE
            IF language = 2 THEN
            BEGIN
               textline("L{raren {r tacksam om Du s{nder radskrivarlistan");
               textline("(inte dialogterminallistan!) till honom.")
            END;
            Write("putmessage;;[N]")
         END;
         Write("Breakoutput;;[N]");
         Write("seloutputandstopkc(2);;[N]Newline;;[N]");
         IF language = 1 THEN Write("Write(""SCORES:  "");;[N]") ELSE
         IF language = 2 THEN Write(" Write(""Antal r{tt:  "");;[N]");
         Write(
         "Print(latepercent,2,1);;[N]Write(""%  ("");;[N]Print(percent,2,1);;[N]Write(""%)[[NT]]-"");;[N]Print(score,3);;[N]"
         );
         IF language = 1 THEN Write("Write("" right answers on first tries and[[NT]]-"");;[N]")
         ELSE IF language = 2 THEN Write("Write("" f`rstasvar och[[NT]]-"");;[N]");
         Write("Print(latescore,3);;[N]");
         IF language = 1 THEN
         Write(
         "Write("" total right out of a total of[[NT]]-"");;[N]Print(qcount,3);;[N]Write("" questions attempted.[[2N]]"");;[N]")
         ELSE
         IF language = 2 THEN
         Write("Write("" totalt av[[NT]]-"");;[N]Print(qcount,3);;[N]Write("" givna fr}gor.[[2N]]"");;[N]");
         Write("Breakoutput;;[N]");
         Write("seloutputandstopkc(0);;[N]")
      END;
      Write("Newline;;[N]");
      IF put THEN
      BEGIN
         IF language = 1 THEN
         BEGIN
            Write("Write(""If you have any message for the teacher, then type it now, one[[N]]"");;[N]");
            Write("Write(""line at a time.  Finish with an EXTRA push on the RETURN key.[[2N]]"");;[N]")
         END
         ELSE IF language = 2 THEN
         BEGIN
            Write("Write(""Om Du har n}got meddelande till l{raren, s} skriv det nu.[[N]]"");;[N]");
            Write("Write(""Sluta med att trycka en extra g}ng p} RETURN-knappen.[[2N]]"");;[N]")
         END;
         Write("[N]mess:[N]");
         IF bell THEN Write("Outsymbol(controlg);;[N]");
         Write("seloutputandstopkc(0);;[N]");
         Write("Write(prompt);;[N]Breakoutput;;[N]getline;;[N]");
         IF NOT lock THEN
         BEGIN
            Write("IF back THEN[N]BEGIN[N]back:= FALSE;;[N]GOTO ");
            Write(mainlab);
            Write(";;[N]END;;[N]")
         END;
         Write("IF answerlength > 0 THEN[N]");
         Write("BEGIN[N]message:= TRUE;;[N]");
         Write("seloutputandstopkc(2);;[N]");
         IF language = 1 THEN
         Write("Write(""MESSAGE: "");;[N]")
         ELSE IF language = 2 THEN
         Write("Write(""MEDDELANDE: "");;[N]");
         Write("FOR pos:= 1 STEP 1 UNTIL answerlength DO Outsymbol(answer.[[pos]]);;[N]");
         Write("GOTO mess;;[N]END;;[N]")
      END;
      Write("Breakoutput;;[N]");
      Write("seloutputandstopkc(0);;[N]");
      IF NOT sgnosis THEN
      BEGIN
         IF language = 1 THEN Write("Write(""Leaving the lesson """"") ELSE
         IF language = 2 THEN Write("Write(""G}r ut ur lektion """"");
         Write(lessonname);
         Write("""""...[[N]]"");;[N]")
      END;
      IF disk THEN
      BEGIN
         Write("Openfile(1,""");
         Write(lessonname);
         Write(".DTA"", %155);;[N]");
         Write("Selectinput(1);;[N]Breakoutput;;[N]seloutputandstopkc(2);;[N]Transfile;;[N]");
         Write("Openfile (1,"""");;[N]Openfile (2,""");
         Write(lessonname);
         Write(".DTA"", %155);;[N]");
         Write("Closefile(1);;[N]");
         Write("Openfile(1,""");
         Write(lessonname);
         Write(".SRT"", %155);;[N]");
         Write("Selectinput(1);;[N]seloutputandstopkc(3);;[N]Transfile;;[N]");
         Write("Openfile (1,"""");;[N]Openfile (3,""");
         Write(lessonname);
         Write(".SRT"", %155);;[N]")
      END;
      Write("seloutputandstopkc(0);;[N]");
      IF language=1 THEN
      BEGIN
         Write("Write(""[[2N]]Have a nice day"");;[N]");
         Write("IF firstname # """" THEN[N]BEGIN[N]Write("", "");;[N]Write(firstname);;[N]END;;[N]");
         Write("Write(""!"");;[N]")
      END
   END of PR*CEDURE putfinish;



   PROCEDURE gotoput;
   COMMENT   -------------------------------------------------
   'Gotoput' determines whether the current GNOSIS command is a
   "%SAME"  command  and, if so, outputs the appropriate "GOTO"
   into the translated Algol program.  If the  command  is  not
   %SAME,  then a default GOTO statement is output.  Of course,
   if the teacher provided an explicit %GOTO  in  the  previous
   line,  then  the  default  GOTO  statement  (which is always
   output) is superfluous.
   -----------------------------------------------------------;
   BEGIN
      goanywherecommands;
      IF controlstart = "SAM" THEN
      COMMENT   -------------------------------------------------
      This  command  is  used  to avoid storing duplicate comments
      whenever  the  comment  provided  for  the  prvious  %RIGHT,
      %WRONG, %LACK, or %NEUTRAL answer pattern can be reused.

      Obviously,  the  first  answer  command  after  a  %QUESTION
      command  cannot  be  followed by a %SAME command since there
      would, in this case, be no previous comment to reuse.
      -----------------------------------------------------------;
      BEGIN
         IF same = "" THEN
         errmess(TRUE, "2177: No previous comment available.[N]****** Command will be ignored.") ELSE
         BEGIN
            Write("GOTO SAME");
            Write(same);
            Write(";;[N]")
         END;
         getline;
         IF answer.[1] # controlchar THEN
         BEGIN
            errmess(TRUE,
"2187: A command line is required at this point.  As a result,[N]******  this line up to next command line will be ignored.");
            WHILE answer.[1] # controlchar DO getline
         END;
         getcontrolstart(4)
      END ELSE
      BEGIN
         delet(same);
         same:= Copy(lab);
         IF NOT right AND NOT neutral THEN Write("GOTO repeat;;[N]")
         ELSE Write("GOTO next;;[N]");
         empty:= FALSE
      END;
      Newline;
      Write(lab);
      Write(":[N]")
   END of PR*CEDURE gotoput;



   PROCEDURE makelabel;
   COMMENT   -------------------------------------------------
   Extra labels have to  be  created  for  insertion  into  the
   translated  ALGOL  program.  'Makelabel' will generate a new
   label at each call (i.e, QZXAAA, QZXAAB, QZXAAC etc.).   The
   label  is  stored  in  the  global  STRING  'lab'  which  is
   initialized to "QZXAAA" for each new  %QUESTION  command  in
   the lesson.
   -----------------------------------------------------------;
   BEGIN
      INTEGER i, k;
      i:= Length(lab);

      letterchange:
      k:= lab.[i];
      IF k >= z THEN
      BEGIN
         lab.[i]:= a;
         i:= i-1;
         GOTO letterchange
      END ELSE lab.[i]:= k+1
   END of PR*CEDURE makelabel;



   PROCEDURE makemainlab;
   COMMENT   -------------------------------------------------
   A  different  set of labels have to be created for insertion
   in  the  translated  ALGOL  program.    'Makemainlab'   will
   generate  a  new  label for this purpose at each call (i.e.,
   ZQXAAA, ZQXAAB, ZQXAAC etc.).  The label is  stored  in  the
   global  STRING  "mainlab"  which  is initialized to "ZQXAAA"
   once for each lesson.  This set of labels is used to  enable
   the student to skip backward in a lesson.  His backward path
   will be strictly linear -- not necessarily  the  reverse  of
   the path he followed when moving forward.
   -----------------------------------------------------------;
   BEGIN
      INTEGER i, k;
      labelcount:= labelcount+1;
      i:= Length(mainlab);

      letterchange:
      k:= mainlab.[i];
      IF k >= z THEN
      BEGIN
         mainlab.[i]:= a;
         i:= i-1;
         GOTO letterchange
      END ELSE mainlab.[i]:= k+1
   END of PR*CEDURE makemainlabel;



   PROCEDURE openoutput;
   COMMENT   -------------------------------------------------
   The output file is given the  same  filename  as  the  input
   GNOSIS  lesson but another extension:  '.ALG'.  That file is
   opened by the PROCEDURE 'openoutput'.
   -----------------------------------------------------------;
   BEGIN
      STRING filename;
      INTEGER i;
      filename:= Newstring(Length(lessonname)+5,7);
      FOR i:= 1 STEP 1 UNTIL Length(lessonname) DO
      filename.[i]:= lessonname.[i];
      filename.[i+1]:= ".".[1];
      filename.[i+2]:= "A".[1];
      filename.[i+3]:= "L".[1];
      filename.[i+4]:= "G".[1];
      Openfile(2,filename,%057);
      opened:= TRUE;
      Selectoutput(2)
   END of PR*CEDURE openoutput;








   COMMENT   -------------------------------------------------
   Initialization of program CONSTANTS follows.
   -----------------------------------------------------------;
   carriagereturn:= 13;
   linefeed:= 10;
   formfeed:= 12;
   tabchar:= 9;
   linenumber:= Newstring(6,7);
   linenumber.[6]:= 9;
   answer:= Newstring(135,7);
   answer.[134]:= carriagereturn;
   answer.[135]:= linefeed;
   colon:= ":".[1];
   equalsign:= "=".[1];
   semicolon:= ";;".[1];
   dot:= ".".[1];
   blank:= " ".[1];
   exclamation:= "!".[1];
   doublequote:= """".[1];
   leftsquare:= "[[".[1];
   rightsquare:= "]]".[1];
   rightmargin:= 72;
   temp:= controlstart:= lessonname:= word:= teacher:= question:= word:= "";
   a:= "A".[1];
   z:= "Z".[1];
   lab:= "";
   lcaa:= "}".[1];
   lcae:= "{".[1];
   lcoe:= "`".[1];
   lce:= "e".[1];
   ucaa:= "$".[1];
   ucae:= "#".[1];
   ucoe:= "@".[1];
   uce:= "E".[1];
   COMMENT   -------------------------------------------------
   Channel 3 is binary to check if the file is linenumbered.
   -----------------------------------------------------------;
   Input(0,"TTY");
   Input(1,"DSK");
   Input(3,"DSK",11);
   Output(2,"DSK");








   Write("GNOSIS Version 2 (June, 1978)[N]");
   Write("Copyright (c) 1978 by Jacob Palme and Walter Maner");
   Write("[2N]Do NOT type ahead while running the GNOSIS translator.[N]");

   start:
   COMMENT   -------------------------------------------------
   Initialization   of   program  VARIABLES  follows.   Program
   defaults are handled first.

   GNOSIS returns  to  this  point  after  a  lesson  has  been
   translated  and  initializes  for the translation of another
   lesson.
   -----------------------------------------------------------;
   switchcount:= 0;
   linenumbered:= skip:= FALSE;
   linecount:= 0;
   labelcount:= 0;
   mainlab:= Copy("ZQXAAA");
   COMMENT   -------------------------------------------------
   Many  of  the  following  BOOLEAN  values will be reset when
   GNOSIS begins to read the lesson script.
   -----------------------------------------------------------;
   extra:= TRUE;
   sgnosis:= put:= keep:= order:= opened:= nocontrolc:= disk:= transferlesson:= lock:= bell:= name:= FALSE;
   language:= 1;
   COMMENT   -------------------------------------------------
   GNOSIS defaults to language 1 (English).
   -----------------------------------------------------------;
   errlines:= controlchar:= qcount:= texcount:= 0;
   delet(teacher);
   teacher:= "";
   Write("[2N]Enter lesson name with extension, or push RETURN to exit from GNOSIS.[N]");
   Write("-->[B]");
   getline;
   infile:= Copy(answer,1,answerlength);
   IF infile = "" THEN GOTO stop;
   upcase(infile);
   pos:= 1;
   WHILE pos < Length(infile) AND infile.[pos] # ".".[1] DO pos:= pos + 1;
   IF pos = Length(infile) THEN
   BEGIN
      STRING temp;
      temp:= Newstring(Length(infile)+5,7);
      FOR pos:= 1 STEP 1 UNTIL Length(infile) DO temp.[pos]:=infile.[pos];
      temp.[pos+1]:= ".".[1];
      temp.[pos+2]:= "G".[1];
      temp.[pos+3]:= "N".[1];
      temp.[pos+4]:= "O".[1];
      infile:= Newstring(Length(temp),7);
      infile:= temp
   END;
   Write("[2N]Translation of the lesson """);
   Write(infile);
   Write(""" has begun...[2N]");
   COMMENT   -------------------------------------------------
   Now we check if the file is linenumbered or not.
   -----------------------------------------------------------;
   Openfile(3,infile);
   Selectinput(3);
   Insymbol(pos);
   linenumbered:= pos REM 2 # 0;
   Closefile(3);
   Openfile(1,infile);
   Selectinput(1);
   COMMENT   -------------------------------------------------
   The part before the extension of the lessonname is found.
   -----------------------------------------------------------;
   FOR pos:= 1 STEP 1 UNTIL Length(infile) DO
   IF infile.[pos] = dot THEN
   BEGIN
      pos:= pos-1;
      GOTO leavefor
   END;

   leavefor:
   delet(teacher);
   delet(copyright);
   delet(lessonname);
   lessonname:= Copy(infile,1,pos);
   openoutput;
   COMMENT   -------------------------------------------------
   The  first  lesson  line is read, and the first character of
   that line is assumed to be the  command  indicator  (usually
   '%').
   -----------------------------------------------------------;

   startloop:
   getline;
   IF controlchar = 0 THEN
   BEGIN
      WHILE answerlength = 0 DO getline;
      controlchar:= answer.[1];
      IF controlchar # "%".[1] THEN
      errmess(FALSE, "2430: You are not using '%' as a command indicator.")
   END;
   IF answer.[1] # controlchar THEN
   BEGIN
      errmess(TRUE,
      "2435: A command line is required at this point.  As a result,[N]******  this line up to next command line will be ignored.");
      WHILE answer.[1] # controlchar DO getline
   END;
   COMMENT   -------------------------------------------------
   Here the program starts looking for  those  GNOSIS  commands
   which  are  expected before the start of the lesson, that is
   %BELL, %KEEP, %LOCK, %DISK, %SGNOSIS,  %NAME,  %TEACHER  and
   %LANGUAGE command lines.
   -----------------------------------------------------------;
   getcontrolstart(4);
   goanywherecommands;
   IF controlstart = "NOC" THEN
   BEGIN
      COMMENT   -------------------------------------------------
      In this mode, if a student types a CTRL-C, he  will  not  be
      returned  to  the monitor level.  Instead, he will be logged
      off the system without further ado.  (Thus  CTRL-C's  become
      functionally equivalent to the 'BYE' command in BASIC.)
      -----------------------------------------------------------;
      nocontrolc:= TRUE;
      errmess(FALSE,
      "2456:  The GNOLIB.REL file must reside in 'SYS:'. [N]****** Load as follows: '.LOAD <lessonname>.ALG, SYS:GNOLIB.REL'.");
      GOTO startloop
   END;
   IF controlstart = "NEX" THEN
   COMMENT   -------------------------------------------------
   This command tells GNOSIS which  lesson  to  run  after  the
   student  finishes  the  current  lesson.   Transfer  to this
   lesson is wholly automatic at the point of exit, just as  if
   the  new  lesson  had  been  called  up  by GNOSIS directly,
   without intervention of the monitor.

   The next lesson can be any RUN-able or R-able program, i.e.,
   any   program  with  the  extension  .SAV,  .EXE  or  .SHR).
   'run("<lesson name>")' is should appear on  the  same  line,
   after this command, when the lesson resides in the student's
   area Or, 'r("<lesson name>")' should appear when it  resides
   in the SYS:  area.

   Technical Note:  The literal which replaces '<lesson  name>'
   must be a single filename, without extension.
   -----------------------------------------------------------;
   BEGIN
      nextlesson:= getword;
      upcase(nextlesson);
      transferlesson:= TRUE;
      errmess(FALSE,
      "2482:  The GNOLIB.REL file must reside in 'SYS:'. [N]****** Load as follows: '.LOAD <lessonname>.ALG, SYS:GNOLIB.REL'.");
      GOTO startloop
   END;
   IF controlstart = "LAN" THEN
   COMMENT   -------------------------------------------------
   This  command  tells  the  system  which  language to use in
   communication  with  the  student.   The  command   is   not
   necessary  if  the language is to be English.  (The language
   used in communicating with  the  teacher  at  the  time  his
   script  is  being processed by GNOSIS is not affected by the
   %LANGUAGE command.  It is always English.)
   -----------------------------------------------------------;
   BEGIN
      delet(word);
      word:= getword;
      upcase(word);
      IF word = "ENGLISH" THEN language:= 1 ELSE
      IF word = "SWEDISH" THEN language:= 2 ELSE
      BEGIN
         errmess(FALSE, "2501: Unknown language.[N]****** GNOSIS will default to English..")
      END;
      GOTO startloop
   END;
   IF controlstart = "SGN" THEN
   COMMENT   --------------------------------------------------
   GNOSIS lessons normally output  a  header  which  tells  the
   student  that  he  is  running  a GNOSIS lesson, that it was
   authored by so-and-so, and that he can do certain things  to
   control  his  path  through the lesson.  Also, at the end of
   the question-and-answer section of the lesson,  GNOSIS  will
   normally  output  a  corresponding  trailer  which tells the
   student how he scored.  %SGNOSIS (for  (S)top  GNOSIS)  will
   inhibit the display of this header and trailer.  The command
   is useful when you  want  to  use  GNOSIS  to  administer  a
   questionnaire.
   -----------------------------------------------------------;
   BEGIN
      sgnosis:= TRUE;
      GOTO startloop
   END;
   IF controlstart = "SWI" THEN
   BEGIN
      COMMENT   -------------------------------------------------
      The %SWITCH  command  declares  and  initializes  a  BOOLEAN
      variable  used  to control skipping in conjunction with %IF,
      %IFNOT and %IFEND  commands.   The  variable  appears  after
      '%SWITCH', on the same command line.
      -----------------------------------------------------------;
      pastoperation;
      switchword:= getword;
      upcase(switchword);
      IF Length(switchword) <= 0 THEN errmess(TRUE, "2530: No switchname in %SWITCH command.[N]****** Line will be ignored.");
      FOR switchnumber:= 1 STEP 1 UNTIL switchcount DO
      IF switchword = switchname[switchnumber] THEN
      errmess(FALSE, "2536: This switch is doubly defined.");
      IF switchcount = 9 THEN
      errmess(TRUE, "2538: More than 9 switches not allowed.[N]THIS switch will replace the old number nine.")
      ELSE switchcount:= switchcount+1;
      switchname[switchcount]:= Copy(switchword);
      switchword:= getword;
      upcase(switchword);
      IF switchword = "TRUE" THEN switchval[switchcount]:= TRUE ELSE
      IF switchword = "FALSE" THEN switchval[switchcount]:= FALSE ELSE
      errmess(TRUE, "2545: Switch value neither 'TRUE' nor 'FALSE'.[N]****** The effect of this error is undefined.");
      ifset[switchcount]:= FALSE;
      GOTO startloop
   END;
   IF controlstart = "KEE" THEN
   BEGIN
      COMMENT   -------------------------------------------------
      This  command  is useful only in association with a %TEACHER
      command, i.e., in report-generating lessons.   Unless  %KEEP
      is  used  in  such  a lesson (or unless %DISK is used, which
      executes an implicit %KEEP command),  the  student  will  be
      directed  to  pick  up  the  teacher report generated by the
      lesson (after it has been printed by the  lineprinter),  and
      to  bring  this  report  to  the  teacher.   This command is
      probably  not  needed   any   longer   since   reports   can
      conveniently be kept on disk.
      -----------------------------------------------------------;
      keep:= TRUE;
      GOTO startloop
   END;
   IF controlstart = "LOC" THEN
   COMMENT   -------------------------------------------------
   This  command  PERMANENTLY  disables  the  backstepping  and
   skipping  provisions  of  GNOSIS.   The student is in effect
   "locked" into the lesson path defined by the teacher  unless
   the  teacher  explicitly supplies branching opportunities in
   the lesson itself.  (Note, however,  that  the  student  can
   still  END  the  lesson  by  typing  'stop'.) There does not
   exist, as yet, a corresponding %UNLOCK command.
   -----------------------------------------------------------;
   BEGIN
      lock:= TRUE;
      GOTO startloop
   END;
   IF controlstart = "BEL" THEN
   BEGIN
      COMMENT   -------------------------------------------------
      This command causes the bell to be  rung  at  the  student's
      terminal  whenever  the computer is awaiting input from him.
      Useful in noisy environments and  with  first-time  computer
      users.
      -----------------------------------------------------------;
      bell:= TRUE;
      GOTO startloop
   END;
   IF controlstart = "NAM" THEN
   COMMENT   -------------------------------------------------
   This command causes the GNOSIS lesson to exchange  greetings
   with  the student at the start of the lesson.  The student's
   full name is requested (and routed to  the  <lessonname>.DTA
   file,  if  any)  and  his first name is saved for use in I/O
   routines.
   -----------------------------------------------------------;
   BEGIN
      name:= TRUE;
      GOTO startloop
   END;
   IF controlstart = "DIS" OR controlstart = "DSK" THEN
   BEGIN
      COMMENT   -------------------------------------------------
      This command causes teacher reports to be created at  lesson
      runtime,   then  routed  to  preexisting  disk  files  named
      <lessonname>.DTA and <lessonname>.SRT.  The <lessonname>.DTA
      file  contains  a  page  of data for each run of the lesson.
      These data include  the  student's  name,  a  trace  of  his
      unexpected  answers,  lesson  statistics, and any message he
      may have left for the teacher.   The  <lessonname>.SRT  file
      contains only the "unexpected answer" traces, converted to a
      format suitable for sorting.

      Unless the %DISK (or %DISC or %DSK) command  is  used,  then
      teacher  reports  (if any) will be routed to the lineprinter
      and no machine readable records will  remain.   The  reports
      queued  to  the  lineprinter  are  equivalent to those which
      would have  been  contained  in  the  <lessonname>.DTA  file
      except  that  each  page  is  printed  as  a  separate item.
      Without the  %DISK  command,  no  <lessonname>.SRT  file  is
      generated.

      When using the %DISK command, care must be taken  to  ensure
      that  the  blank files <lessonname>.DTA and <lessonname>.SRT
      have been created IN THE ACCOUNT WHERE THE  LESSON  WILL  BE
      RUN.   They  must  exist there before the lesson is used for
      the first time.  Otherwise a mysterious error  message  will
      be  sent  to  the student by ALGDDT as he tries to exit from
      the lesson.  A protection of <155> should be given to  these
      report  files.   This  isn't  adequate  for all purposes, of
      course, but it is a workable compromise for the teacher  who
      wishes to inspect, print or copy-and-sort these records from
      another account.

      The %DISK  command  executes  implicit  %TEACHER  and  %KEEP
      commands.   Thus,  an  explicit  %TEACHER  command  will  be
      required only if it is necessary to add the  teacher's  name
      and address.

      Technical Note:  Unless %NAME is used  in  conjunction  with
      %DISK,   only   one   student   at   a   time   may   use  a
      report-generating lesson.  When the %NAME command  is  used,
      however,  temporary  .DTA and .SRT files (based on his first
      name) are opened at runtime.  Writing to these files  (until
      the   very   end   of   the   lesson)   usually  avoids  any
      conflict-of-access problems connected with writing the  main
      <lessonname>.DTA and <lessonname>.SRT files.
      -----------------------------------------------------------;
      disk:= keep:= put:= TRUE;
      errmess(FALSE, "2651: Ignore this message if you have created");
      Selectoutput(0);
      Write("****** ");
      Write(lessonname);
      Write(".DTA<155> and ");
      Write(lessonname);
      Write(".SRT<155> files to receive teacher reports.");
      Newline;
      Selectoutput(2);
      GOTO startloop
   END;
   IF controlstart = "COP" THEN
   BEGIN
      COMMENT   -------------------------------------------------
      If this command is used then, each time the lesson is run, a
      copyright  notice  will  be  output  as  part  of the lesson
      header.  This copyright applies only to the  lesson  itself,
      of course -- not to the GNOSIS software.
      -----------------------------------------------------------;
      pastoperation;
      copyright:= Copy(answer,pos,answerlength);
      GOTO startloop
   END;
   IF controlstart  = "TEA" THEN
   BEGIN
      COMMENT   -------------------------------------------------
      If this command  is  included  in  a  lesson,  then  teacher
      reports  (of some kind) will be produced for the lesson, and
      students will be told who authored the lesson each time  the
      lesson  is  run.   If  the  %TEACHER command is used with an
      empty argument, then an anonymous  teacher  report  will  be
      generated and no information about lesson authorship will be
      displayed to the student at runtime.

      The <lessonname>.DTA teacher report contains  the  following
      information:

      ----  The student's full name, if operating in %NAME mode.

      ----  Unexpected answers to questions in the lesson.

      This trace will include any unforeseen student response  or,
      roughly  speaking,  all  those  responses  students  entered
      without getting any specific diagnostic feedback.  Recurrent
      unanticipated responses usually signal a need to rewrite the
      lesson with that response  as  an  argument  for  an  answer
      command  --  followed  of  course by appropriate comments or
      hints.


      ----  Basic   statistical   data   about    the    student's
      performance.

      This data should not be taken too seriously, especially when
      the  lesson  permits  the  student  to exercise control over
      skipping and backstepping.

      ----  Student comments about the lesson.

      GNOSIS can store as lengthy a comment as the  student  wants
      to  type,  even if his comment should run on for pages.  The
      <lessonname>.SRT report, which is generated if %DISK is used
      in   conjunction   with  %TEACHER,  contains  the  trace  of
      unexpected answers in a  form  ready  to  be  input  to  the
      utility  program SORT.  The following command string usually
      does the job:

      .R SORT
      *x.SRT=x.SRT/KEY:1:60:A/ALPHA/RECORD:132

      where 'x' = <lessonname>.
      -----------------------------------------------------------;
      pastoperation;
      teacher:= Copy(answer,pos,answerlength);
      IF teacher = "" THEN
      BEGIN
         errmess(FALSE, "2727: Ignore this message if you meant to omit[N]****** teacher's name and address.");
         keep:=TRUE
      END;
      put:=TRUE;
      GOTO startloop
   END;
   COMMENT   -------------------------------------------------
   Since all of the 'IF controlstart = <command  abbreviation>'
   tests  above  have  failed, the current command line must be
   something other than %BELL, %COPYRIGHT, %DISK  (or  %DSK  or
   %DISC),   %KEEP,   %LANGUAGE,   %LOCK,  %NAME,  %NEXTLESSON,
   %NOCONTROLC, %SGNOSIS, %SWITCH or %TEACHER.  This being  so,
   it  is  time to output that part of the lesson preface which
   contains the data declarations.
   -----------------------------------------------------------;
   putvariables;
   WHILE controlstart = "VAR" DO
   COMMENT   -------------------------------------------------
   The %VARIABLES command  causes  user-defined  variables  (if
   any) to be written into the lesson.
   -----------------------------------------------------------;
   BEGIN
      controlstart:= Copy("ALG");
      goanywherecommands
   END;
   checkprecedence(13);
   COMMENT   -------------------------------------------------
   Now   it   is  time  to  output  the  user's  own  PROCEDURE
   declarations.
   -----------------------------------------------------------;
   putprocedures;
   WHILE (controlstart = "PRO" OR controlstart = "HEL") DO
   BEGIN
      WHILE controlstart = "PRO" DO
      COMMENT   -------------------------------------------------
      This command is used to  make  a  standard  ALGOL  PROCEDURE
      declaration.    Code   followingthe  %PROCEDURE  command  is
      processed like code following the %ALGOL command except that
      it  is  written into the lesson at the point where PROCEDURE
      declarations belong.

      The %PROCEDURE command itself is not copied, since it  might
      as  well  have  been  abbreviated to '%PRO'.  Thus the terms
      'PROCEDURE', 'EXTERNAL PROCEDURE', and so  on  should  occur
      immediately after '%PROCEDURE' even though this might appear
      redundant.
      -----------------------------------------------------------;
      BEGIN
         controlstart:= Copy("ALG");
         Newline;
         Newline;
         goanywherecommands
      END controlstart = "PRO";
      WHILE controlstart = "HEL" DO
      COMMENT   -------------------------------------------------
      The  %HELP  command causes GNOSIS to establish a golbal help
      text, i.e., one  which  is  potentially  accessible  by  the
      student  from  any  part  of the lesson.  '%ALGOL <help text
      name>',  wherever  it  may  appear  in  the   script,   will
      subsequently cause the help text to be displayed.

      The name of the help procedure (limited to  a  single  word)
      must  immediately  follow '%HELP', on the same command line.
      Unlike the %PROCEDURE command (see above),  GNOSIS  does  in
      his  case  write  the  word  'PROCEDURE' into the translated
      lesson.
      -----------------------------------------------------------;
      BEGIN
         Write("[2N]PROCEDURE ");
         Write(getword);
         Write(";;[N]");
         Write("BEGIN[N]");
         textlines;
         Write("END;;[N]");
         goanywherecommands
      END controlstart = "HEL";
   END "PRO" or "HEL";
   checkprecedence(14);
   putvalues;
   WHILE controlstart = "INI" DO
   COMMENT   -------------------------------------------------
   This command is normally used to initialize global variables
   which  have  been  declared  with  the  %VARIABLES  command,
   although  it  could  just  as  well  be used to reinitialize
   GNOSIS system parameters if that should ever  be  necessary.
   %INITIALIZE  operates  like  %ALGOL (see above), except that
   the code following %INITIALIZE is written into the lesson at
   the  point where data are initialized, just before the start
   of the main program.
   -----------------------------------------------------------;
   BEGIN
      controlstart:= Copy("ALG");
      Newline;
      Newline;
      goanywherecommands
   END;
   checkprecedence(16);
   COMMENT   -------------------------------------------------
   Now  we  finish  the  lesson preface by outputting the final
   portion of the header.  This code sets up some I/O  routines
   and does some further initialization.
   -----------------------------------------------------------;
   putheader;

   whichcontrol:
   COMMENT   -------------------------------------------------
   Check  which  of  the remaining GNOSIS command lines we have
   here.
   -----------------------------------------------------------;
   goanywherecommands;
   IF controlstart = "QEN" THEN
   COMMENT   -------------------------------------------------
   This command is used because, as a  side-effect,  it  causes
   GNOSIS   to   finishing   writing   code  for  a  particular
   question-and-answer processing loop.  This command is rarely
   used  since  %TEXT,  %QUESTION and %END contain this command
   implicitly.   However,  %QEND  is  sometimes  useful  before
   certain   %ALGOL   commands  since  those  commands  do  NOT
   implicitly close  the  question-and-answer  loop.   So,  for
   example,  if  you  had an independent block of ALGOL code to
   insert between two %QUESTION commands, it would be necessary
   to use %QEND after the first question and answer patterns.
   -----------------------------------------------------------;
   BEGIN
      shortalgol;
      GOTO checkline
   END;
   IF controlstart = "TEX" THEN
   COMMENT   -------------------------------------------------
   The  text on the lines following this command, and until the
   next GNOSIS command, will be displayed to the student.  Like
   many  other  commands, the %TEXT command can take any single
   line of ALGOL code as an argument.  Usually this  code  will
   contain  conditions  (as  arguments for IF-statemens) and/or
   labels.
   -----------------------------------------------------------;
   BEGIN
      texcount:= texcount + 1;
      Write("[4N]COMMENT: Text");
      Print(texcount,2);
      Write(";;[N]");
      shortalgol;
      previouslab:= mainlab;
      makemainlab;
      Newline;
      Write(mainlab);
      Write(":[N]BEGIN[N]");
      textlines;
      Write("pause;;[N]");
      IF NOT lock THEN
      BEGIN
         COMMENT   -------------------------------------------------
         When  the  student  executes a BACK command, he is backed to
         the previous %TEXT or %QUESTION.  What usually follows is  a
         repetition  of  the  material  he  just encountered, but not
         always.  If he arrived at the point where he issues the BACK
         command  via a GOTO, then the backstepping (which is alaways
         linear)  will  not  return  him   to   the   material   just
         encountered.   We  have a fix for this, but do not feel that
         the  additional  overhead  required  by  the  fix   can   be
         justified.
         -----------------------------------------------------------;
         Write("IF back THEN[N]BEGIN[N]back:= FALSE;;[N]GOTO ");
         Write(previouslab);
         Write(";;[N]END;;[N]")
      END;
      Write("END;;[N]");
      GOTO whichcontrol
   END;
   IF controlstart = "QUE" THEN
   BEGIN
      COMMENT   -------------------------------------------------
      Code which initializes question handling is written into the
      lesson at this point.  With the exception of the incremental
      comment GNOSIS supplies to identify the question, this  code
      is   rewritten   in  essentially  the  same  form  for  each
      occurrence of '%QUESTION' in the lesson script.

      The %QUESTION command can take any single line of ALGOL code
      as  an  argument.  Uusally this code will contain conditions
      (as arguments for IF-statements) and/or labels.  If a  label
      is supplied following this command, then it is extracted for
      further use in preparing identifying phrases for the teacher
      reports.

      GNOSIS assumes teachers will usually  not  bother  to  label
      their  questions,  so  a  count  is  kept  of  the number of
      %QUESTION commands encountered in the lesson.  The value  of
      this  count will be paried with students' unexpected answers
      to the question so that the  the  question  which  generated
      these  unexpected  answers  may be identified in the teacher
      reports.
      -----------------------------------------------------------;
      INTEGER errcount;
      delet(lab);
      lab:= Copy("QZXAAA");
      delet(same);
      same:= "";
      errcount:= 0;
      allneutral:= TRUE;
      rightfound:= zeroprinted:= FALSE;
      qcount:= qcount+1;
      Write("[4N]COMMENT: Question");
      Print(qcount,2);
      Write(";;[N]");
      IF put THEN
      BEGIN
         INTEGER pos1, pos2;
         delet(question);
         FOR pos1:= 1 STEP 1 UNTIL answerlength DO
         BEGIN
            IF answer.[pos1] = colon THEN
            BEGIN
               IF pos1 < answerlength THEN pos1:= pos1 + 1 ELSE BEGIN
                  pos2:= pos1 - 1;
                  GOTO ditto
               END;
               IF answer.[pos1] # equalsign THEN
               BEGIN
                  pos2:= pos1 - 2;
                  pos1:= pos1 - 1;

                  ditto:
                  IF answer.[pos1] # blank AND answer.[pos1] # semicolon THEN
                  BEGIN
                     pos1:= pos1 - 1;
                     GOTO ditto
                  END;
                  delet(question);
                  question:= Copy(answer,pos1+1,pos2);
                  pos1:= pos2 + 1
               END
            END
         END
      END;
      shortalgol;
      previouslab:= mainlab;
      makemainlab;
      Newline;
      Write(mainlab);
      Write(":[N]");
      Write("BEGIN[N]INTEGER subblock;;[N]");
      Write("firsttry:= TRUE;;[N]lastrights:= lasterrors:= 0;;[N]");
      Write("ihaveblanked:= FALSE;;[N]");
      COMMENT   -------------------------------------------------
      Repetition of the same question loop begins here.
      -----------------------------------------------------------;
      Write("IF FALSE THEN[N]");
      Write("BEGIN[2N]repeat:[N]");
      Write("tryagain;;[N]");
      Write("END;;[N]");
      Write("Newline;;[N]");
      COMMENT   -------------------------------------------------
      Output of the question text - Input of the answer.
      -----------------------------------------------------------;
      textlines;
      IF bell THEN Write("Outsymbol(controlg);;[N]");
      Write("Write(prompt);;[N]getline;;[N]");
      Write("IF stop THEN[N]");
      Write("BEGIN[N]");
      IF put THEN
      BEGIN
         saveanlen:= answerlength;
         answerlength:= 0;
         putaway;
         answerlength:= saveanlen
      END;
      Write("stop:= FALSE;;[N]GOTO endoflesson;;[N]END;;[N]");
      IF NOT lock THEN
      BEGIN
         Write("IF back THEN[N]");
         Write("BEGIN[N]");
         IF put THEN
         BEGIN
            saveanlen:= answerlength;
            answerlength:= 0;
            putaway;
            answerlength:= saveanlen
         END;
         Write("back:= FALSE;;[N]GOTO ");
         Write(previouslab);
         Write(";;[N]END;;[N]");
         Write("IF skip THEN[N]");
         Write("BEGIN[N]");
         IF put THEN
         BEGIN
            saveanlen:= answerlength;
            answerlength:= 0;
            putaway;
            answerlength:= saveanlen
         END;
         Write("skip:= FALSE;;[N]GOTO simulate;;[N]END;;[N]")
      END;
      COMMENT   -------------------------------------------------
      Loop  for  answer  commands:   %RIGHT,  %WRONG,   %LACK   or
      %NEUTRAL.
      -----------------------------------------------------------;

      answerfind:
      neutral:= FALSE;
      goanywherecommands;
      lack:= FALSE;
      IF controlstart = "RIG" THEN
      BEGIN
         COMMENT   -------------------------------------------------
         This  command  causes GNOSIS to search for an answer pattern
         and, if it is found, to consider it correct.  If a match for
         the  canned  answer is found in the student's response, then
         the following happens:

         ----  The GNOSIS system gives the  student  one  of  several
         stock  messages,  all  of which have the effect of providing
         positive feedback.

         ----  If  he  had  previously  missed  this  question  then,
         depending  on  the circumstances, GNOSIS provides additional
         stock messages designed to encourage him.

         ----  The text on the optional line(s) following the  %RIGHT
         command  (until the next GNOSIS command) is displayed to the
         student.

         ----  Various statistical variables (see %TEXT command)  are
         updated.

         ----  GNOSIS moves on to the next item of business.  We save
         first  %RIGHT  answer  to  give  to  the  student  (1) if he
         executes a SKIP command or (2) if  he  repeatedly  fails  to
         give a right answer.
         -----------------------------------------------------------;
         right:= TRUE;
         IF NOT rightfound THEN
         BEGIN
            IF pos <= answerlength THEN
            BEGIN
               delet(firstright);
               pastoperation;
               firstright:= Copy(answer, pos, answerlength);
               rightfound:= TRUE;
               pos:= 1
            END
         END
      END ELSE
      IF controlstart = "WRO" THEN right:= FALSE ELSE
      COMMENT   -------------------------------------------------
      This command causes GNOSIS to search for an  answer  pattern
      and,  if  it is found, to consider it wrong.  If a match for
      the canned answer is found in the student's  response,  then
      the following happens:

      ----  The GNOSIS system gives the  student  one  of  several
      stock  messages,  all  of which have the effect of providing
      negative feedback.

      ----  The text on the optional line(s) following the  %WRONG
      command  (until the next GNOSIS command) is displayed to the
      student.

      ----  If the student is still getting meaningful  help  from
      the  program, he is recycled through the question once more.
      Otherwise,  GNOSIS  simulates   a   correct   answer   (plus
      commentary for such an answer) and moves on to the next item
      of business.
      -----------------------------------------------------------;
      IF controlstart = "NEU" THEN neutral:= TRUE ELSE
      COMMENT   -------------------------------------------------
      This command tells GNOSIS to search for an answer and, if it
      is found, to interpret  it  as  being  neither  correct  nor
      incorrect.   If  the  neutral  target  text  is found in the
      student's response, then any line(s) of  comments  or  hints
      provided  by the teacher will be displayed to the student at
      that point.  The default for  %NEUTRAL  commands  is  '%GOTO
      next'  so  the  teacher  who wants a question repeated after
      GNOSIS has found a neutral match will have to insert  '%GOTO
      repeat' after that %NEUTRAL command (and comments, if any).

      Technical Note:  The procedure "extratest" is NOT called for
      %NEUTRAL  commands  with empty answer patterns.  Thus clever
      use of '%NEUTRAL <empty>' should enable the teacher to  trap
      most  misspelled  answers with no prejudice to the student's
      score -- or ego.
      -----------------------------------------------------------;
      IF controlstart = "LAC" THEN
      COMMENT   -------------------------------------------------
      This command causes GNOSIS to search for something which (a)
      is essential to a correct response but which (b)  is  likely
      to  be  missing.   If  the  the  item  is  not  found in the
      student's answer,  then  he  receives  appropriate  negative
      feedback  from  GNOSIS and the text (if any) on the optional
      line(s) after the %LACK command is displayed to him at  that
      point.   If  more than one element is expected to be lacking
      from the student's response, then he receives  feedback  and
      commentary (if any) as soon as ANY of the elements cannot be
      detected in his response.  The chief advantage of the  %LACK
      command  does not lie in its increased efficiency but rather
      in the opportunity it provides for writing  highly  specific
      diagnostic comments.

      Technical Note:  Regardless of context, %LACK  works  as  if
      %NOORDER and %EXTRA were declared immediately above it.
      -----------------------------------------------------------;
      BEGIN
         lack:= TRUE;
         right:= FALSE;
         IF NOT zeroprinted THEN zeroprint
      END ELSE
      BEGIN
         COMMENT   -------------------------------------------------
         There are no more answer  commands  (i.e.,  %RIGHT,  %WRONG,
         %LACK or %NEUTRAL) for the current question, so now we write
         the trailing code for this question segment and recycle  via
         'GOTO whichcontrol' to the next non-answer command.
         -----------------------------------------------------------;
         IF NOT zeroprinted THEN zeroprint;
         unknownmessage;
         Write("END;;[N]");
         Write("[N]simulate:[N]");
         IF rightfound THEN
         BEGIN
            Write("giveanswer;;[N]");
            textline(firstright);
            Write("Write(right[[random]]);;[N]Newline;;[N]GOTO SAMEQZXAAB;;[N]")
         END;
         Write("[N]next:[N]");
         Write("pause;;[N]");
         IF NOT lock THEN
         BEGIN
            Write("IF back THEN[N]BEGIN[N]back:= FALSE;;[N]GOTO ");
            Write(previouslab);
            Write(";;[N]END;;[N]")
         END;
         Write("END;;[N]");
         GOTO whichcontrol
      END;
      Write("IF ihaveblanked THEN restore;;[N]");
      delet(word);
      word:= getword;
      upcase(word);
      IF word = "" THEN empty:= TRUE;
      IF empty AND NOT right AND NOT neutral AND NOT lack THEN
      BEGIN
         COMMENT   -------------------------------------------------
         %WRONG with no answer pattern causes GNOSIS to generate code
         which handles unexpected answers.
         -----------------------------------------------------------;
         errcount:= errcount+1;
         IF errcount = 1 THEN
         BEGIN
            IF NOT zeroprinted THEN zeroprint
         END;
         Write("IF lasterrors =");
         Print(errcount - 1,2,0);
         Write(" THEN[N]");
         makelabel;
         unknownmessage;
         Newline;
         Write("SAME");
         Write(lab);
         Write(":[N]");
         textlines;
         gotoput;
         Write("END;;[N]");
         GOTO answerfind
      END ELSE
      BEGIN
         COMMENT   -------------------------------------------------
         Now we interpret the teacher answer pattern and translate it
         into  an  ALGOL program sequence for comparing the student's
         answer with the pattern.
         -----------------------------------------------------------;
         IF NOT neutral THEN allneutral:= FALSE;
         IF errcount # 0 THEN
         BEGIN
            errmess(TRUE, "3200: Expected answers must precede first [N]****** empty answer pattern. Command will be ignored.");

            orderloop:
            getline;
            IF answer.[1] # controlchar THEN GOTO orderloop;
            getcontrolstart(4);
            GOTO answerfind
         END;
         makelabel;
         IF order THEN
         BEGIN
            Write("pos:= 1;;");
            Newline
         END;
         WHILE word # "" DO
         BEGIN
            IF NOT lack THEN
            BEGIN
               IF NOT order THEN Write("pos:= 1;;[N]");
               Write("IF NOT ");
               IF NOT order OR extra THEN Write("anyw");
               Write("here(""")
            END;
            IF lack THEN Write("pos:= 1;;[N]IF NOT anywhere(""");
            FOR wpos:= 1 STEP 1 UNTIL Length(word) DO
            BEGIN
               charvalue:= word.[wpos];
               IF charvalue = doublequote THEN Outsymbol(charvalue);
               IF charvalue = semicolon THEN Outsymbol(semicolon);
               Outsymbol(charvalue)
            END;
            Write(""") THEN GOTO ");
            IF lack THEN Write("LACK");
            Write(lab);
            Write(";;[N]");
            delet(word);
            word:= getword;
            upcase(word)
         END;
         IF NOT(extra OR lack) AND NOT(neutral AND empty) THEN
         BEGIN
            IF NOT order THEN Write("pos:= 1;;[N]");
            Write("IF NOT here(endofline) THEN GOTO ");
            Write(lab);
            Write(";;[N]")
         END;
         IF lack THEN
         BEGIN
            Write("GOTO ");
            Write(lab);
            Write(";;[N]");
            Newline;
            Write("LACK");
            Write(lab);
            Write(":[N]")
         END;
         COMMENT   -------------------------------------------------
         This  code  will  tell  the  student whether he was right or
         wrong and will update the score statistics.
         -----------------------------------------------------------;
         IF NOT neutral THEN
         BEGIN
            IF right THEN Write("rightmessage") ELSE Write("wrongmessage");
            Write(";;[N]")
         END;
         IF lack THEN
         BEGIN
            IF put THEN putaway
         END;
         IF extra THEN
         BEGIN
            IF (neutral AND NOT empty) OR right THEN Write("extratest;;[N]")
         END;
         Newline;
         Write("SAME");
         Write(lab);
         Write(":[N]");
         COMMENT   -------------------------------------------------
         This  code  will  output the comment the teacher wrote to go
         with a student's answer.
         -----------------------------------------------------------;
         textlines;
         gotoput;
         GOTO answerfind
      END
   END;
   IF controlstart = "FIN" THEN
   COMMENT   -------------------------------------------------

   This command will enable the user to place one or more lines
   of  ALGOL  code  in the GNOSIS translated lesson immediately
   before its final 'END'.  (Ordinarily this would be  possible
   only  through  editing  the  .ALG  file produced by GNOSIS.)
   '%ALGOL <one or more lines of ALGOL code>' MUST  follow  the
   %FINISH  command.   Note too that %FINISH does NOT terminate
   the lesson script.  A '%END' is still necessary to close the
   lesson.
   -----------------------------------------------------------;
   BEGIN
      putfinish;
      getline;
      IF answer.[1] # controlchar THEN GOTO finclose;
      getcontrolstart(4);
      goanywherecommands;
      GOTO finclose
   END;
   IF controlstart = "END" THEN
   COMMENT   -------------------------------------------------
   This  is  --  MUST  be -- the last command of a lesson.  Any
   text after this command will be ignored by GNOSIS.
   -----------------------------------------------------------;
   BEGIN
      putfinish;

      finclose:
      IF transferlesson THEN Write(nextlesson);
      Write("[N]END;;[N]");
      delet(infile);
      Selectinput(0);
      Selectoutput(0);
      Closefile(1);
      Closefile(2);
      Write("...and is ready.[N]");
      GOTO start
   END;

   COMMENT   -------------------------------------------------
   Since  'getcontrolstart' has validated the command, the only
   possible reason for reaching this point would be an error in
   precedence.     Thus   it   is   not   necessary   to   call
   'checkprecedence' to discover this.
   -----------------------------------------------------------;
   errmess(TRUE,
   "3330: Command is out of place here.  As a result,[N]****** this line up to next command line will be ignored.");

   checkline:
   getline;
   IF answer.[1] # controlchar THEN
   BEGIN
      errmess(TRUE,
      "3340: A command line is required at this point.  As a result,[N]******  this line up to next command line will be ignored.");
      WHILE answer.[1] # controlchar DO getline
   END;

   controlline:
   getcontrolstart(4);
   GOTO whichcontrol;

   stop:
END