First: The provided example solution in DM4 is partial, and the provided block must be inserted before the for loop from the Ex 110 solution, or the call to LTI_Insert()
in the Ex 110 loop will invalidate the word location information returned by WordAddress()
in the Ex 111 block. Local variables added by the new block (word
and at
) must be added to the routine declaration.
Second: The use of local variable at
in the commands intended to replace characters in the player input is incorrect. WordAddress()
returns a memory location; this value is far too large to be used as an index against the buffer
array, so the code as provided in the example solution causes RTEs. This can be fixed by changing the assignment of at
to:
at = WordAddress(x) - buffer;
and adjusting calls to LTI_Insert()
to:
LTI_Insert(at, ' ');
Perhaps these should be added to the list of DM4 errata. Is there a more complete list than the one at https://inform-fiction.org/patches/misprints.html ?
Third: To break the circular dependency, zarf’s solution of setting up a helper function definitely does get the job done. (Thanks, zarf!) To use it, change line:
wn = x; word = NextWord();
to
word = NextWordArg(x);
and adhere to the following order of directives and definitions in the source code:
-
Replace LanguageToInformese;
! causes LanguageToInformese() in english.h to be ignored
-
[ LanguageToInformese ... ];
! defines routine, hiding dependency on wn via indirect usage
-
Include "Parser";
! causes parser to be compiled to invoke LanguageToInformese(), because routine is defined
-
[ NextWordArg ... ];
! OK to make use of wn because compiler has seen its declaration in parser code
Finally: it’s not easy to tell whether or not this routine is working without playing back the contents of buffer. The following routine does that:
[ ShowCurrentCommand linelen i;
linelen = buffer->1; ! characters parsed, see DM4 p. 44
print "^MODIFIED COMMAND: ";
for (i=0: i<linelen: i++)
print (char) buffer->(i+2);
print "^";
];
A call to this can be added at the end of LanguageToInformese()
to show the post-modification contents of buffer
.
Here’s a complete working example:
(compiles and works under Inform 6.31)
Constant Story “DM4 Exercise 111b (example solution)”;
Constant Headline “^from p. 268^”;
Replace LanguageToInformese;
[ LanguageToInformese x word at ;
! Insert a space before each hyphen and after each apostrophe.
for (x=1: x<=parse->1: x++) {
word = NextWordArg(x); ! THIS LINE MODIFIED FROM DM4
at = WordAddress(x) - buffer; ! THIS LINE MODIFIED FROM DM4
if (word == ‘dessus’) {
LTI_Insert(at, ’ '); ! THIS LINE MODIFIED FROM DM4
buffer->at = ‘s’; buffer->(at+1) = ‘u’; buffer->(at+2) = ‘r’;
buffer->(at+3) = ’ '; buffer->(at+4) = ‘l’; buffer->(at+5) = ‘u’;
buffer->(at+6) = ‘i’;
break;
}
if (word == ‘dedans’) {
LTI_Insert(at, ’ '); ! THIS LINE MODIFIED FROM DM4
LTI_Insert(at, ’ '); ! THIS LINE MODIFIED FROM DM4
buffer->at = ‘d’; buffer->(at+1) = ‘a’; buffer->(at+2) = ‘n’;
buffer->(at+3) = ‘s’; buffer->(at+4) = ’ '; buffer->(at+5) = ‘l’;
buffer->(at+6) = ‘u’; buffer->(at+7) = ‘i’;
break;
}
}
for (x=2: x<2+buffer->1: x++) {
if (buffer->x == ‘-’) LTI_Insert(x++, ’ ‘);
if (buffer->x == ‘’’) LTI_Insert(++x, ’ ‘);
}
#ifdef DEBUG;
if (parser_trace >= 1) {
print “[ After LTI: '”;
for (x=2: x<2+buffer->1: x++) print (char) buffer->x;
print "’]^";
}
#endif;
ShowCurrentCommand(); ! THIS LINE ADDED; optional, see below
];
Include “Parser”;
Include “VerbLib”;
Include “Grammar”;
[ NextWordArg val oldwn res ;
oldwn = wn;
wn = val;
res = NextWord();
wn = oldwn;
return res;
];
[ ShowCurrentCommand linelen i; ! plays back contents of buffer to see changes
linelen = buffer->1; ! characters parsed, see DM4 p. 44
print "^MODIFIED COMMAND: ";
for (i=0: i<linelen: i++)
print (char) buffer->(i+2);
print “^”;
];
Class Room
has light;
Room Start “Starting Point”
with description
“An uninteresting room.”;
[ Initialise ;
location = Start;
];
Test commands like >DONNE-LUI L’OISEAU and >METTEZ L’EAU DESSUS are transformed as required by the exercise instructions.
The above process is simplified somewhat by creating an alternate language file (i.e. a modified version of english.h
) and replacing the definition of LanguageToInformese()
directly within it, then telling the compiler to substitute that file using the +language_name="<modified file name>"
switch, as explained in the header of Standard Library file english.h
. (Although this switch is not covered in DM4, the text does suggest that the reader inspect the contents of english.h near the start of the section on p. 258 [https://inform-fiction.org/manual/html/s36.html]). As far as I can tell, this approach must be used for Exercises 115 through 118 on pages 272-273 of the following section 37 [https://inform-fiction.org/manual/html/s37.html], as there is no way to modify the size of the relevant arrays LanguageGNAsToArticles
and LanguageArticles
once they have been defined.
Hopefully, all of the above will help someone else working through DM4 to be less confused than I was by this exercise!