Trailing-Edge
-
PDP-10 Archives
-
decuslib10-04
-
43,50323/gnosis.alg
There are 2 other files named gnosis.alg in the archive. Click here to see a list.
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);
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 < 22 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 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("Selectoutput(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("Selectoutput(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("Selectoutput(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]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]Selectoutput(2);;[N]");
IF disk THEN Write("Input(1,""DSK"");;[N]Output(2,""DSK"");;[N]Output(3,""DSK"");;[N]");
IF nocontrolc THEN Write("stopkc;;[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("Selectoutput(0);;[2N]")
END;
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("Selectoutput(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]Selectoutput(0);;[N]")
END
ELSE IF language = 2 THEN
BEGIN
Write("Write(""[[P]]L#RARRAPPORT F@R LEKTIONEN: ");
Write(lessonname);
Write("[[2N]]"");;[N]");
Write("Selectoutput(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]Selectoutput(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("Selectoutput(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("Selectoutput(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("Selectoutput(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("Selectoutput(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("Selectoutput(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]Selectoutput(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]Selectoutput(3);;[N]Transfile;;[N]");
Write("Openfile (1,"""");;[N]Openfile (3,""");
Write(lessonname);
Write(".SRT"", %155);;[N]")
END;
Write("Selectoutput(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]");
textlines;
Write("BEGIN[N]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