diff --git a/README.md b/README.md index fb892e0ce..2e70af8ae 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Inform 7 -[Version](notes/versioning.md): 10.2.0-beta+6W35 'Krypton' (22 April 2023) +[Version](notes/versioning.md): 10.2.0-beta+6W55 'Krypton' (4 June 2023) ## About Inform @@ -148,7 +148,7 @@ Other extensions shipped with Inform are not presented as webs, but as single fi * [Inanimate Listeners by Emily Short]() - __v1__ * [Locksmith by Emily Short]() - __v13__ * [Menus by Emily Short]() - __v3__ -* [Punctuation Removal by Emily Short]() - __v5__ +* [Punctuation Removal by Emily Short]() - __v6__ * [Skeleton Keys by Emily Short]() - __v1__ * [Epistemology by Eric Eve]() - __v9__ * [Approximate Metric Units by Graham Nelson]() - __v1__ diff --git a/build.txt b/build.txt index a39ec3e66..81647cdd1 100644 --- a/build.txt +++ b/build.txt @@ -1,3 +1,3 @@ Prerelease: beta -Build Date: 22 April 2023 -Build Number: 6W35 +Build Date: 4 June 2023 +Build Number: 6W55 diff --git a/docs/BasicInformExtrasKit/S-msc.html b/docs/BasicInformExtrasKit/S-msc.html index 485b1abb9..853374bfd 100644 --- a/docs/BasicInformExtrasKit/S-msc.html +++ b/docs/BasicInformExtrasKit/S-msc.html @@ -98,7 +98,7 @@ before it is known how they will be used. [ INITIALISE_MEMORY_R; #ifdef TARGET_GLULX; VM_PreInitialise(); #Endif; - #Ifdef LanguageInitialise; LanguageInitialise(); #Endif; + LanguageInitialise(); HeapInitialise(); Create a completely unused memory allocation heap StackFramingInitialise(); Create an empty stack @@ -117,7 +117,7 @@ before it is known how they will be used. [ VM_Initialise i; standard_interpreter = HDR_TERPSTANDARD-->0; - if (KIT_CONFIGURATION_BITMAP & FIX_RNG_TCBIT) { + if (BasicInformKit`FIX_RNG_CFGF) { @random 10000 -> i; i = -i-2000; print "[Random number generator seed is ", i, "]^"; @@ -139,23 +139,50 @@ buffer and then altering the first character.

-Array StorageForShortName buffer 250;
+Constant SHORT_NAME_BUFFER_LEN = 160;
+
+#Ifdef TARGET_ZCODE;
+Allow a generous overrun
+Array StorageForShortName buffer SHORT_NAME_BUFFER_LEN+90;
+#Ifnot;
+Array StorageForShortName --> SHORT_NAME_BUFFER_LEN;
+#Endif;
 
 [ CPrintOrRun obj prop  v length i;
-    if ((obj ofclass String or Routine) || (prop == 0))
-        VM_PrintToBuffer (StorageForShortName, 160, obj);
+    if ((obj ofclass String or Routine) || (prop == 0)) {
+        #Ifdef TARGET_ZCODE;
+        length = VM_PrintToBuffer (StorageForShortName, SHORT_NAME_BUFFER_LEN, obj);
+        #Ifnot;
+        length = Glulx_PrintAnyToArrayUni(StorageForShortName, SHORT_NAME_BUFFER_LEN, obj);
+        #Endif;
+    }
     else {
         if (obj.prop == NULL) rfalse;
-        if (metaclass(obj.prop) == Routine or String)
-            VM_PrintToBuffer(StorageForShortName, 160, obj, prop);
-        else return RunTimeError(2, obj, prop);
+        if (metaclass(obj.prop) == Routine or String) {
+            #Ifdef TARGET_ZCODE;
+            length = VM_PrintToBuffer(StorageForShortName, SHORT_NAME_BUFFER_LEN, obj, prop);
+            #Ifnot;
+            length = Glulx_PrintAnyToArrayUni(StorageForShortName, SHORT_NAME_BUFFER_LEN, obj.prop);
+            #Endif;
+        }
+        else {
+             return RunTimeError(2, obj, prop);
+        }
     }
 
-    length = StorageForShortName-->0;
-
+    #Ifdef TARGET_ZCODE;
     StorageForShortName->WORDSIZE = VM_LowerToUpperCase(StorageForShortName->WORDSIZE);
     for (i=WORDSIZE: i<length+WORDSIZE: i++) print (char) StorageForShortName->i;
-    if (i>WORDSIZE) say__p = 1;
+    #Ifnot;
+    if (length > SHORT_NAME_BUFFER_LEN) length = SHORT_NAME_BUFFER_LEN;
+    ### length = glk_buffer_to_title_case_uni(StorageForShortName, SHORT_NAME_BUFFER_LEN, length, false);
+    ### glk_put_buffer_uni(StorageForShortName, length);
+    if (length)
+        StorageForShortName-->0 = VM_LowerToUpperCase(StorageForShortName-->0);
+    glk_put_buffer_uni(StorageForShortName, length);
+    #Endif;
+
+    if (length) say__p = 1;
 
     return;
 ];
@@ -204,9 +231,7 @@ the following "for" rule.
         String:   print "<string ~", (string) obj, "~>"; return;
         nothing:  print "<illegal object number ", obj, ">"; return;
     }
-    #Ifdef LanguagePrintShortName;
     if (LanguagePrintShortName(obj)) return;
-    #Endif; LanguagePrintShortName
     if (indef_mode && obj provides short_name_indef &&
         PrintOrRun(obj, short_name_indef, true) ~= 0) return;
     if (caps_mode &&
@@ -262,6 +287,7 @@ indefinite singular depends on the text of the object's name.
         if (i < 3 || (i >= 6 && i < 9)) i = i + 3;
     }
     i = LanguageGNAsToArticles-->i;
+
     artform = LanguageArticles
         + 3*WORDSIZE*LanguageContractionForms*(short_name_case + i*LanguageCases);
 
@@ -276,7 +302,7 @@ indefinite singular depends on the text of the object's name.
     }
     #Ifdef TARGET_ZCODE;
     if (standard_interpreter ~= 0 && findout) {
-        StorageForShortName-->0 = 160;
+        StorageForShortName-->0 = SHORT_NAME_BUFFER_LEN;
         @output_stream 3 StorageForShortName;
         if (pluralise) print (number) pluralise; else print (PSN__) obj;
         @output_stream -3;
@@ -285,9 +311,9 @@ indefinite singular depends on the text of the object's name.
     #Ifnot; TARGET_GLULX
     if (findout) {
         if (pluralise)
-            Glulx_PrintAnyToArray(StorageForShortName, 160, EnglishNumber, pluralise);
+            Glulx_PrintAnyToArrayUni(StorageForShortName, SHORT_NAME_BUFFER_LEN, EnglishNumber, pluralise);
         else
-            Glulx_PrintAnyToArray(StorageForShortName, 160, PSN__, obj);
+            Glulx_PrintAnyToArrayUni(StorageForShortName, SHORT_NAME_BUFFER_LEN, PSN__, obj);
         acode = acode + 3*LanguageContraction(StorageForShortName);
     }
     #Endif; TARGET_
diff --git a/docs/BasicInformKit/S-blc.html b/docs/BasicInformKit/S-blc.html
index ea1367b08..858817364 100644
--- a/docs/BasicInformKit/S-blc.html
+++ b/docs/BasicInformKit/S-blc.html
@@ -593,8 +593,6 @@ depending on the task in hand.
 Constant WRITE_FILE_KOVS  = 13;
 Constant HASH_KOVS        = 14;
 Constant DEBUG_KOVS       = 15;
-
-Constant BLKVALUE_TRACE; ! Uncomment this to expose masses of tracery
 

§13. Creation. To create a block value, call:

@@ -630,7 +628,7 @@ outside the heap, for reasons to be seen below. kovs = KOVSupportFunction(strong_kind, "impossible allocation"); short_block = kovs(CREATE_KOVS, strong_kind, short_block); - #ifdef BLKVALUE_TRACE; print "Created: ", (BlkValueDebug) short_block, "^"; #endif; + #ifdef LKTRACE_HEAP; print "Created: ", (BlkValueDebug) short_block, "^"; #endif; The new value is represented in I6 as the pointer to its short block: return short_block; @@ -854,7 +852,7 @@ asking the kind's support function: if (from_bv == 0) BlkValueError("copy from null value"); if (to_bv == from_bv) return; - #ifdef BLKVALUE_TRACE; + #ifdef LKTRACE_HEAP; print "Copy: ", (BlkValueDebug) to_bv, " to equal ", (BlkValueDebug) from_bv, "^"; #endif; @@ -902,7 +900,7 @@ a list must not, for example, contain itself.
 [ BlkValueDestroyPrimitive bv kovs long_block;
-    #ifdef BLKVALUE_TRACE; print "Destroying ", (BlkValueDebug) bv, "^"; #endif;
+    #ifdef LKTRACE_HEAP; print "Destroying ", (BlkValueDebug) bv, "^"; #endif;
     if (BlkValueDecRefCountPrimitive(bv) == 0) {
         kovs(DESTROY_KOVS, bv);
         long_block = BlkValueGetLongBlock(bv);
@@ -919,7 +917,7 @@ replace the small block with a new one (at the same address).
 
 
 [ BlkValueRecyclePrimitive bv kovs;
-    #ifdef BLKVALUE_TRACE; print "Recycling ", (BlkValueDebug) bv, "^"; #endif;
+    #ifdef LKTRACE_HEAP; print "Recycling ", (BlkValueDebug) bv, "^"; #endif;
     if (BlkValueDecRefCountPrimitive(bv) == 0) {
         kovs(DESTROY_KOVS, bv);
         BlkValueIncRefCountPrimitive(bv);
@@ -952,7 +950,7 @@ a temporary one-value stack frame instead to hold it.
     if (bv == 0) BlkValueError("tried to make null block mutable");
 
     if (BlkValueGetRefCountPrimitive(bv) > 1) {
-        #ifdef BLKVALUE_TRACE; print "Make mutable: ", (BlkValueDebug) bv, "^"; #endif;
+        #ifdef LKTRACE_HEAP; print "Make mutable: ", (BlkValueDebug) bv, "^"; #endif;
 
         BlkValueDecRefCountPrimitive(bv);
 
diff --git a/docs/BasicInformKit/S-dfn.html b/docs/BasicInformKit/S-dfn.html
index 8489b337d..efcb78102 100644
--- a/docs/BasicInformKit/S-dfn.html
+++ b/docs/BasicInformKit/S-dfn.html
@@ -65,12 +65,13 @@ MathJax = {
     
 

Miscellaneous constant definitions, usually providing symbolic names for otherwise inscrutable numbers, which are used throughout the template layer.

-
+

§1. Identification.

 Constant BASICINFORMKIT = 1;
+Constant SERIAL_COMMA = BasicInformKit`SERIAL_COMMA_CFGF;
 

§2. Z-Machine Definitions. The Z-machine contains certain special constants and variables at fixed position in its "header"; the addresses of these are given below. See @@ -150,8 +151,12 @@ of the template layer, and would only get in the way here. Constant ROM_GAMERELEASE = $34; short word Constant ROM_GAMESERIAL = $36; six ASCII characters -Constant #dict_par1 = 11; -Constant #dict_par2 = 13; +The following constants describe the layout of a dictionary word entry. +The math is copied from the I6 compiler. + +Constant DICT_ENTRY_BYTES = 12+DICT_WORD_SIZE*WORDSIZE; +Constant #dict_par1 = DICT_WORD_SIZE*WORDSIZE+4+1; +Constant #dict_par2 = DICT_WORD_SIZE*WORDSIZE+4+3; #Endif;

@@ -634,23 +639,6 @@ future use. Global formal_par7; Global unicode_temp;
-

§23. Template Configuration. To minimise the need for conditional compilation in the template, the -constant KIT_CONFIGURATION_BITMAP must be generated by the user -(i.e., by I7). It's made up of these bits: -

- -
-Constant USE_SCORING_TCBIT = 1;
-Constant PREVENT_UNDO_TCBIT = 2;
-Constant SERIAL_COMMA_TCBIT = 4;
-Constant PROGRAMMING_EXPONENTS_TCBIT = 8;
-Constant FIX_RNG_TCBIT = 16;
-Constant ECHO_COMMANDS_TCBIT = 32;
-Constant NO_VERB_VERB_DEFINED_TCBIT = 64;
-Constant DIALECT_US_TCBIT = 128;
-Constant STORY_AUTHOR_TCBIT = 256;
-Constant RANKING_TABLE_TCBIT = 512;
-
diff --git a/docs/BasicInformKit/S-flx.html b/docs/BasicInformKit/S-flx.html index 350512107..cc7081937 100644 --- a/docs/BasicInformKit/S-flx.html +++ b/docs/BasicInformKit/S-flx.html @@ -65,7 +65,7 @@ MathJax = {

To allocate flexible-sized blocks of memory as needed to hold arbitrary-length strings of text, stored actions or other block values.

-
+

§1. Blocks. The purpose of the Flex routines is to manage flexible-sized "blocks" of memory for any general-purpose use. The main customer for this service is @@ -166,10 +166,17 @@ byte offset BLK_DATA_MULTI_OF Constant BLK_DATA_MULTI_OFFSET = BLK_DATA_OFFSET + 2*WORDSIZE; Constant BLK_NEXT 3; Constant BLK_PREV 4; - -Constant BLKVALUE_TRACE = 1; ! Uncomment this for debugging purposes -

§3. The Heap. Properly speaking, a "heap" is a specific kind of structure often used for +

§3. Tracing. Uncomment this line and rebuild the kit to enable tracing of what the algorithm +below is doing. (This constant should not be used anywhere except in this file +and in BlockValues.i6t, where #Ifdef on it will have the expected effect: +elsewhere, it might not.) +

+ +
+Constant LKTRACE_HEAP;
+
+

§4. The Heap. Properly speaking, a "heap" is a specific kind of structure often used for managing uneven-sized or unpredictably changing data. We use "heap" here in the looser sense of being an amorphous-sized collection of blocks of memory, some free, others allocated; our actual representation of free space on the @@ -221,7 +228,7 @@ freed and added to the free space object.

 Array Flex_Heap -> (MEMORY_HEAP_SIZE + BLK_DATA_MULTI_OFFSET); allow room for head-free-block
 
-

§4. Initialisation. To recap: the constant MEMORY_HEAP_SIZE has been predefined by the Inform compiler, +

§5. Initialisation. To recap: the constant MEMORY_HEAP_SIZE has been predefined by the Inform compiler, and is always itself a power of 2, say \(2^n\). We therefore have \(2^n + 2^4\) bytes available to us, and we format these as a free space list of two blocks: the \(2^4\)-sized "head-free-block" described above followed by @@ -246,7 +253,7 @@ a \(2^n\)-sized block exactly containing the whole of the rest of the heap. blk2-->BLK_PREV = Flex_Heap; ]; -

§5. Net Free Space. "Net" in the sense of "after deductions for the headers": this is the +

§6. Net Free Space. "Net" in the sense of "after deductions for the headers": this is the actual number of free bytes left on the heap which could be used for data. Note that it is used to predict whether it is possible to fit something further in: so there are two answers, depending on whether the something @@ -264,7 +271,7 @@ data) or single-block data (smaller header, more room). return asize; ]; -

§6. Make Space. The following routine determines if there is enough free space to accommodate +

§7. Make Space. The following routine determines if there is enough free space to accommodate another size bytes of data, given that it has to be multiple-block data if the multiple flag is set. If the answer turns out to be "no", we see if the host virtual machine is able to allocate more for us: if it is, then @@ -317,7 +324,7 @@ which handles non-multiple blocks better.) Flex_Heap-->BLK_NEXT = newblock; newblock-->BLK_PREV = Flex_Heap; .Linked; ; - #ifdef BLKVALUE_TRACE; + #ifdef LKTRACE_HEAP; print "Increasing heap to free space map: "; FlexDebugDecomposition(Flex_Heap, 0); #endif; } @@ -346,7 +353,7 @@ which handles non-multiple blocks better.) } ]; -

§7. Block Allocation. Now for the Flex routines. Those with names ending in Internal are private +

§8. Block Allocation. Now for the Flex routines. Those with names ending in Internal are private and should only be called by other Flex routines. Even the public ones must be used with care, or memory leaks or crashes will occur.

@@ -479,7 +486,7 @@ $$ 10000000_2 - 00001000_2 = 01111000_2 $$ return free_block; ]; -

§8. Errors. In the event that FlexAllocate returns 0, the caller may not be able +

§9. Errors. In the event that FlexAllocate returns 0, the caller may not be able to survive, so the following is provided as a standardised way to halt the virtual machine.

@@ -491,7 +498,7 @@ the virtual machine. @quit; ]; -

§9. Merging. Given a free block block, find the maximal contiguous run of free blocks +

§10. Merging. Given a free block block, find the maximal contiguous run of free blocks which contains it, and then call FlexRecutInternal to recut it to conform to invariant (b) above.

@@ -506,17 +513,17 @@ invariant (b) above. first = first-->BLK_PREV; pv = first-->BLK_PREV; nx = last-->BLK_NEXT; - #ifdef BLKVALUE_TRACE; + #ifdef LKTRACE_HEAP; print "Merging: "; FlexDebugDecomposition(pv-->BLK_NEXT, nx); print "^"; #endif; if (FlexRecutInternal(first, last)) { - #ifdef BLKVALUE_TRACE; + #ifdef LKTRACE_HEAP; print " --> "; FlexDebugDecomposition(pv-->BLK_NEXT, nx); print "^"; #endif; } ]; -

§10. Recutting. Given a segment of the free block list, containing blocks known to be contiguous +

§11. Recutting. Given a segment of the free block list, containing blocks known to be contiguous in memory, we recut into a sequence of blocks satisfying invariant (b): we repeatedly cut the largest \(2^m\)-sized chunk off the back end until it is all used up. @@ -552,7 +559,7 @@ used up. rtrue; ]; -

§11. Deallocation. As noted above, FlexFree must be called exactly once on each nonzero +

§12. Deallocation. As noted above, FlexFree must be called exactly once on each nonzero pointer returned by FlexAllocate.

@@ -613,7 +620,7 @@ that is, are indestructible. This enables Inform to compile constant values. } ]; -

§12. Resizing. A block which has been allocated, but not yet freed, can sometimes have +

§13. Resizing. A block which has been allocated, but not yet freed, can sometimes have its data capacity changed by FlexResize.

@@ -656,7 +663,7 @@ allocated and freed, which is probably good. } ]; -

§13. Block Size. These two routines are provided for the use of the BlockValue routines +

§14. Block Size. These two routines are provided for the use of the BlockValue routines only.

@@ -678,7 +685,7 @@ only. return size_in_bytes; ]; -

§14. Debugging Routines. These two routines are purely for testing the above code. +

§15. Debugging Routines. These two routines are purely for testing the above code.

diff --git a/docs/BasicInformKit/S-gll.html b/docs/BasicInformKit/S-gll.html
index a43696a29..08819d2e3 100644
--- a/docs/BasicInformKit/S-gll.html
+++ b/docs/BasicInformKit/S-gll.html
@@ -104,9 +104,9 @@ wants out of these arrays.
 Constant MAX_BUFFER_WORDS = 20;
 Constant PARSE_BUFFER_LEN = 61;
 
-Array  buffer    buffer INPUT_BUFFER_LEN;
-Array  buffer2   buffer INPUT_BUFFER_LEN;
-Array  buffer3   buffer INPUT_BUFFER_LEN;
+Array  buffer   --> INPUT_BUFFER_LEN;
+Array  buffer2  --> INPUT_BUFFER_LEN;
+Array  buffer3  --> INPUT_BUFFER_LEN;
 Array  parse     --> PARSE_BUFFER_LEN;
 Array  parse2    --> PARSE_BUFFER_LEN;
 
@@ -1054,7 +1054,7 @@ light to the Dark Room.") gg_backgroundchan = glk_schannel_create(GG_BACKGROUNDCHAN_ROCK); } - if (KIT_CONFIGURATION_BITMAP & FIX_RNG_TCBIT) { + if (BasicInformKit`FIX_RNG_CFGF) { @random 10000 i; i = -i-2000; @setrandom i; @@ -1315,8 +1315,8 @@ to document all of that. [ VM_ReadKeyboard a_buffer a_table done ix; if (gg_commandstr ~= 0 && gg_command_reading ~= false) { - done = glk_get_line_stream(gg_commandstr, a_buffer+WORDSIZE, - (INPUT_BUFFER_LEN-WORDSIZE)-1); + done = glk_get_line_stream_uni(gg_commandstr, a_buffer+WORDSIZE, + (INPUT_BUFFER_LEN-1)-1); if (done == 0) { glk_stream_close(gg_commandstr, 0); gg_commandstr = 0; @@ -1324,17 +1324,17 @@ to document all of that. } else { Trim the trailing newline - if ((a_buffer+WORDSIZE)->(done-1) == 10) done = done-1; + if ((a_buffer+WORDSIZE)-->(done-1) == 10) done = done-1; a_buffer-->0 = done; VM_Style(INPUT_VMSTY); - glk_put_buffer(a_buffer+WORDSIZE, done); + glk_put_buffer_uni(a_buffer+WORDSIZE, done); VM_Style(NORMAL_VMSTY); print "^"; jump KPContinue; } } done = false; - glk_request_line_event(gg_mainwin, a_buffer+WORDSIZE, INPUT_BUFFER_LEN-WORDSIZE, 0); + glk_request_line_event_uni(gg_mainwin, a_buffer+WORDSIZE, INPUT_BUFFER_LEN-1, 0); while (~~done) { glk_select(gg_event); switch (gg_event-->0) { @@ -1361,9 +1361,9 @@ to document all of that. glk_window_close(gg_quotewin, 0); gg_quotewin = 0; } - if (KIT_CONFIGURATION_BITMAP & ECHO_COMMANDS_TCBIT) { + if (BasicInformKit`ECHO_COMMANDS_CFGF) { print "** "; - for (ix=WORDSIZE: ix<(a_buffer-->0)+WORDSIZE: ix++) print (char) a_buffer->ix; + for (ix=0: ix<(a_buffer-->0): ix++) print (char) a_buffer-->(1+ix); print "^"; } ]; @@ -1393,46 +1393,50 @@ languages of play, and is not called in the template.
 [ VM_CopyBuffer bto bfrom i;
-    for (i=0: i<INPUT_BUFFER_LEN: i++) bto->i = bfrom->i;
+    for (i=0: i<INPUT_BUFFER_LEN: i++) bto-->i = bfrom-->i;
 ];
 
 [ VM_PrintToBuffer buf len a b c;
     if (b) {
         if (metaclass(a) == Object && a.#b == WORDSIZE
             && metaclass(a.b) == String)
-            buf-->0 = Glulx_PrintAnyToArray(buf+WORDSIZE, len, a.b);
+            buf-->0 = Glulx_PrintAnyToArrayUni(buf+WORDSIZE, len, a.b);
         else if (metaclass(a) == Routine)
-            buf-->0 = Glulx_PrintAnyToArray(buf+WORDSIZE, len, a, b, c);
+            buf-->0 = Glulx_PrintAnyToArrayUni(buf+WORDSIZE, len, a, b, c);
         else
-            buf-->0 = Glulx_PrintAnyToArray(buf+WORDSIZE, len, a, b);
+            buf-->0 = Glulx_PrintAnyToArrayUni(buf+WORDSIZE, len, a, b);
     }
     else if (metaclass(a) == Routine)
-        buf-->0 = Glulx_PrintAnyToArray(buf+WORDSIZE, len, a, b, c);
+        buf-->0 = Glulx_PrintAnyToArrayUni(buf+WORDSIZE, len, a, b, c);
     else
-        buf-->0 = Glulx_PrintAnyToArray(buf+WORDSIZE, len, a);
+        buf-->0 = Glulx_PrintAnyToArrayUni(buf+WORDSIZE, len, a);
     if (buf-->0 > len) buf-->0 = len;
     return buf-->0;
 ];
 
+Constant LOWERCASE_BUF_SIZE = 2*DICT_WORD_SIZE;
+Array gg_lowercasebuf --> LOWERCASE_BUF_SIZE;
+
 [ VM_Tokenise buf tab
-    cx numwords len bx ix wx wpos wlen val res dictlen entrylen;
+    cx numwords len bx ix wx wpos wlen val res dictlen ch bytesperword uninormavail;
     len = buf-->0;
     buf = buf+WORDSIZE;
+
     First, split the buffer up into words. We use the standard Infocom
     list of word separators (comma, period, double-quote).
 
     cx = 0;
     numwords = 0;
     while (cx < len) {
-        while (cx < len && buf->cx == ' ') cx++;
+        while (cx < len && buf-->cx == ' ') cx++;
         if (cx >= len) break;
         bx = cx;
-        if (buf->cx == '.' or ',' or '"') cx++;
+        if (buf-->cx == '.' or ',' or '"') cx++;
         else {
-            while (cx < len && buf->cx ~= ' ' or '.' or ',' or '"') cx++;
+            while (cx < len && buf-->cx ~= ' ' or '.' or ',' or '"') cx++;
         }
         tab-->(numwords*3+2) = (cx-bx);
-        tab-->(numwords*3+3) = WORDSIZE+bx;
+        tab-->(numwords*3+3) = 1+bx;
         numwords++;
         if (numwords >= MAX_BUFFER_WORDS) break;
     }
@@ -1441,20 +1445,37 @@ languages of play, and is not called in the template.
     Now we look each word up in the dictionary.
 
     dictlen = #dictionary_table-->0;
-    entrylen = DICT_WORD_SIZE + 7;
+    bytesperword = DICT_WORD_SIZE * WORDSIZE;
+    uninormavail = glk_gestalt(16, 0);
 
     for (wx=0 : wx<numwords : wx++) {
         wlen = tab-->(wx*3+2);
         wpos = tab-->(wx*3+3);
 
         Copy the word into the gg_tokenbuf array, clipping to DICT_WORD_SIZE
-        characters and lower case.
+        characters and lower case. We'll do this in two steps, because
+        lowercasing might (theoretically) condense characters and allow more
+        to fit into gg_tokenbuf.
+        if (wlen > LOWERCASE_BUF_SIZE) wlen = LOWERCASE_BUF_SIZE;
+        cx = wpos - 1;
+        for (ix=0 : ix<wlen : ix++) {
+            ch = buf-->(cx+ix);
+            gg_lowercasebuf-->ix = ch;
+        }
+        wlen = glk_buffer_to_lower_case_uni(gg_lowercasebuf, LOWERCASE_BUF_SIZE, wlen);
+        if (uninormavail) {
+            Also normalize the Unicode — combine accent marks with letters
+            where possible.
+            wlen = glk_buffer_canon_normalize_uni(gg_lowercasebuf, LOWERCASE_BUF_SIZE, wlen); buffer_canon_normalize_uni
+        }
         if (wlen > DICT_WORD_SIZE) wlen = DICT_WORD_SIZE;
-        cx = wpos - WORDSIZE;
-        for (ix=0 : ix<wlen : ix++) gg_tokenbuf->ix = VM_UpperToLowerCase(buf->(cx+ix));
-        for (: ix<DICT_WORD_SIZE : ix++) gg_tokenbuf->ix = 0;
+        for (ix=0: ix<wlen : ix++) {
+            gg_tokenbuf-->ix = gg_lowercasebuf-->ix;
+        }
+        for (: ix<DICT_WORD_SIZE : ix++) gg_tokenbuf-->ix = 0;
+
         val = #dictionary_table + WORDSIZE;
-        @binarysearch gg_tokenbuf DICT_WORD_SIZE val entrylen dictlen 1 1 res;
+        @binarysearch gg_tokenbuf bytesperword val DICT_ENTRY_BYTES dictlen 4 1 res;
         tab-->(wx*3+1) = res;
     }
 ];
@@ -1463,6 +1484,8 @@ languages of play, and is not called in the template.
 
     Protect us from strict mode, as this isn't an array in quite the
     sense it expects
+    (This is not an issue now that buffer is a word array, but I'm
+    keeping the alias.)
     b = buffer;
 
     Insert character ch into buffer at point i.
@@ -1471,8 +1494,8 @@ languages of play, and is not called in the template.
     if (y > INPUT_BUFFER_LEN) y = INPUT_BUFFER_LEN;
 
     Move the subsequent text along one character:
-    for (y=y+WORDSIZE : y>i : y--) b->y = b->(y-1);
-    b->i = ch;
+    for (y=y+1 : y>i : y--) b-->y = b-->(y-1);
+    b-->i = ch;
 
     And the text is now one character longer:
     if (b-->0 < INPUT_BUFFER_LEN) (b-->0)++;
@@ -1505,11 +1528,11 @@ since, on Glulx, they are the same, these are each the identity function.
 [ VM_DictionaryAddressToNumber w; return w; ];
 [ VM_NumberToDictionaryAddress n; return n; ];
 
-Array gg_tokenbuf -> DICT_WORD_SIZE;
+Array gg_tokenbuf --> DICT_WORD_SIZE;
 
 [ GGWordCompare str1 str2 ix jx;
     for (ix=0 : ix<DICT_WORD_SIZE : ix++) {
-        jx = (str1->ix) - (str2->ix);
+        jx = (str1-->ix) - (str2-->ix);
         if (jx ~= 0) return jx;
     }
     return 0;
@@ -1658,6 +1681,10 @@ including discarded characters.) The character set stored here is ZSCII,
 not Unicode.
 

+

Glulx_PrintAnyToArrayUni does the same again, but the output is sent to a +word array in memory. The stored characters are Unicode code points. +

+

Glulx_ChangeAnyToCString calls Glulx_PrintAnyToArray on a particular array, then amends the result to make it a C-style string — that is, a sequence of byte-sized characters which are null terminated. The character @@ -1736,6 +1763,28 @@ set stored here is once again ZSCII, not Unicode. return len; ]; +[ Glulx_PrintAnyToArrayUni _vararg_count arr arrlen str oldstr len; + @copy sp arr; + @copy sp arrlen; + _vararg_count = _vararg_count - 2; + + oldstr = glk_stream_get_current(); + str = glk_stream_open_memory_uni(arr, arrlen, 1, 0); + if (str == 0) return 0; + + glk_stream_set_current(str); + + @call Glulx_PrintAnything _vararg_count 0; + + glk_stream_set_current(oldstr); + @copy $ffffffff sp; + @copy str sp; + @glk $0044 2 0; stream_close + @copy sp len; + @copy sp 0; + return len; +]; + Constant GG_ANYTOSTRING_LEN 66; Array AnyToStrArr -> GG_ANYTOSTRING_LEN+1; diff --git a/docs/BasicInformKit/S-lst.html b/docs/BasicInformKit/S-lst.html index ba551947a..58c6f1986 100644 --- a/docs/BasicInformKit/S-lst.html +++ b/docs/BasicInformKit/S-lst.html @@ -272,7 +272,7 @@ use the "listing contents of..." activity in any circumstances. if (i<no_items-2) print ", "; if (i==no_items-2) { if (format == 1) print ", "; else { - if (KIT_CONFIGURATION_BITMAP & SERIAL_COMMA_TCBIT) { + if (BasicInformKit`SERIAL_COMMA_CFGF) { if (no_items ~= 2) print ","; } LIST_WRITER_INTERNAL_RM('C'); diff --git a/docs/BasicInformKit/S-mth.html b/docs/BasicInformKit/S-mth.html index 0ffe15de5..af1a90e23 100644 --- a/docs/BasicInformKit/S-mth.html +++ b/docs/BasicInformKit/S-mth.html @@ -358,7 +358,7 @@ cases used to check the floating-point extensions to Glulx. expon expnegative count; print "FloatParse <"; -for (ix=0: ix<len: ix++) print (char) buf->ix; +for (ix=0: ix<len: ix++) print (char) buf-->ix; print ">^"; if (len == 0) @@ -371,7 +371,7 @@ cases used to check the floating-point extensions to Glulx. @numtof 10 ten; Sign character (optional) - ch = buf->ix; + ch = buf-->ix; if (ch == '-') { negative = true; ix++; @@ -382,7 +382,7 @@ cases used to check the floating-point extensions to Glulx. Some digits (optional) for (count=0 : ix<len : ix++, count++) { - ch = buf->ix; + ch = buf-->ix; if (ch < '0' || ch > '9') break; val = (ch - '0'); @@ -392,11 +392,11 @@ cases used to check the floating-point extensions to Glulx. } Decimal point and more digits (optional) - if (ix<len && buf->ix == '.') { + if (ix<len && buf-->ix == '.') { ix++; @numtof 1 fracdiv; for ( : ix<len : ix++, count++) { - ch = buf->ix; + ch = buf-->ix; if (ch < '0' || ch > '9') break; val = (ch - '0'); @@ -416,8 +416,8 @@ cases used to check the floating-point extensions to Glulx. @fadd intpart fracpart res; Exponent (optional) - if (ix<len && buf->ix == 'e' or 'E' or ' ' or '*' or 'x' or 'X' or $D7) { - if (buf->ix == 'e' or 'E') { + if (ix<len && buf-->ix == 'e' or 'E' or ' ' or '*' or 'x' or 'X' or $D7) { + if (buf-->ix == 'e' or 'E') { no spaces, just the 'e' ix++; if (ix == len) @@ -425,31 +425,31 @@ cases used to check the floating-point extensions to Glulx. } else { any number of spaces, "*", any number of spaces more, "10^" - while (ix < len && buf->ix == ' ') + while (ix < len && buf-->ix == ' ') ix++; if (ix == len) return FLOAT_NAN; - if (buf->ix ~= '*' or 'x' or 'X' or $D7) + if (buf-->ix ~= '*' or 'x' or 'X' or $D7) return FLOAT_NAN; ix++; - while (ix < len && buf->ix == ' ') + while (ix < len && buf-->ix == ' ') ix++; if (ix == len) return FLOAT_NAN; - if (buf->ix ~= '1') + if (buf-->ix ~= '1') return FLOAT_NAN; ix++; - if (buf->ix ~= '0') + if (buf-->ix ~= '0') return FLOAT_NAN; ix++; - if (buf->ix ~= $5E) + if (buf-->ix ~= $5E) return FLOAT_NAN; ix++; } Sign character (optional) expnegative = false; - ch = buf->ix; + ch = buf-->ix; if (ch == '-') { expnegative = true; ix++; @@ -461,7 +461,7 @@ cases used to check the floating-point extensions to Glulx. expon = 0; Some digits (mandatory) for (count=0 : ix<len : ix++, count++) { - ch = buf->ix; + ch = buf-->ix; if (ch < '0' || ch > '9') break; expon = 10*expon + (ch - '0'); @@ -599,8 +599,8 @@ cases used to check the floating-point extensions to Glulx. } Print the exponent. There are two conventions coded here: the - programmatic ("1.0e+00") and the literary ("1.0 x 10^0"). - if (KIT_CONFIGURATION_BITMAP & PROGRAMMING_EXPONENTS_TCBIT == 0) { + engineering notation ("1.0e+00") and the mathematical ("1.0 x 10^0"). + if (BasicInformKit`PRINT_ENGINEER_EXPS_CFGF == 0) { PrintMultiplicationSign(); @streamchar '1'; @streamchar '0'; diff --git a/docs/BasicInformKit/S-prg.html b/docs/BasicInformKit/S-prg.html index 66a7c1716..eab76a969 100644 --- a/docs/BasicInformKit/S-prg.html +++ b/docs/BasicInformKit/S-prg.html @@ -51,7 +51,7 @@

To manage the line skips which space paragraphs out.

-
+

§1. Paragraph Control. Ah, yes: the paragraph breaking algorithm. In {\it \TeX: The Program}, Donald Knuth writes at section 768: "It's sort of a miracle whenever \halign @@ -196,7 +196,15 @@ of the huge number of circumstances in which paragraphs are printed: so change nothing without very careful testing.

-

§2. State. The current state is stored in a combination of two global variables: +

§2. Tracing. Uncomment this line and rebuild the kit to enable tracing of what the algorithm +below is doing. (This constant should not be used anywhere except in this file, +where #Ifdef on it will have the expected effect: elsewhere, it might not.) +

+ +
+onstant LKTRACE_SPACING;
+
+

§3. State. The current state is stored in a combination of two global variables:

  • (1) say__p, the "say paragraph" flag, which is set if a paragraph break @@ -238,27 +246,25 @@ below.

    -onstant TRACE_I7_SPACING;
    -
     [ ClearParagraphing r;
         say__p = 0; say__pc = 0;
     ];
     
     [ DivideParagraphPoint;
    -    #ifdef TRACE_I7_SPACING; print "[DPP", say__p, say__pc, "]"; #endif;
    +    #ifdef LKTRACE_SPACING; print "[DPP", say__p, say__pc, "]"; #endif;
         if (say__p) {
             new_line; say__p = 0; say__pc = say__pc | PARA_COMPLETED;
             say__pc_save = true;
             if (say__pc & PARA_PROMPTSKIP) say__pc = say__pc - PARA_PROMPTSKIP;
             if (say__pc & PARA_SUPPRESSPROMPTSKIP) say__pc = say__pc - PARA_SUPPRESSPROMPTSKIP;
         }
    -    #ifdef TRACE_I7_SPACING; print "[-->", say__p, say__pc, "]"; #endif;
    +    #ifdef LKTRACE_SPACING; print "[-->", say__p, say__pc, "]"; #endif;
         say__pc = say__pc | PARA_CONTENTEXPECTED;
         say__pc_save = (say__pc & PARA_COMPLETED);
     ];
     
     [ AdjustParagraphPoint;
    -    #ifdef TRACE_I7_SPACING; print "[APP ", say__p, " ", say__pc, " ", say__pc_save, "]^"; #endif;
    +    #ifdef LKTRACE_SPACING; print "[APP ", say__p, " ", say__pc, " ", say__pc_save, "]^"; #endif;
         if (say__pc_save) say__pc = (say__pc | PARA_COMPLETED);
     ];
     
    @@ -280,14 +286,14 @@ below.
     ];
     
     [ RunParagraphOn;
    -    #ifdef TRACE_I7_SPACING; print "[RPO", say__p, say__pc, "]"; #endif;
    +    #ifdef LKTRACE_SPACING; print "[RPO", say__p, say__pc, "]"; #endif;
         say__p = 0;
         say__pc = say__pc | PARA_PROMPTSKIP;
         say__pc = say__pc | PARA_SUPPRESSPROMPTSKIP;
     ];
     
     [ SpecialLookSpacingBreak;
    -    #ifdef TRACE_I7_SPACING; print "[SLS", say__p, say__pc, "]"; #endif;
    +    #ifdef LKTRACE_SPACING; print "[SLS", say__p, say__pc, "]"; #endif;
         say__p = 0;
         say__pc = say__pc | PARA_PROMPTSKIP;
     ];
    @@ -307,7 +313,7 @@ below.
         say__pc = 0;
     ];
     
    -

    §3. Say Number. The global variable say__n is set to the numerical value of any quantity +

    §4. Say Number. The global variable say__n is set to the numerical value of any quantity printed, and this is used for the text substitution "[s]", so that "You have been awake for [turn count] turn[s]." will expand correctly.

    @@ -317,7 +323,7 @@ printed, and this is used for the text substitution "[s]", so that if (say__n ~= 1) print "s"; ];
-

§4. Print English Number. Another traditional name, this: in fact it prints the number as text in +

§5. Print English Number. Another traditional name, this: in fact it prints the number as text in whatever is the current language of play.

@@ -353,7 +359,7 @@ whatever is the current language of play. print (LanguageNumber) n/100, " hundred"; n = n%100; f = 1; } if (n == 0) rfalse; - if (KIT_CONFIGURATION_BITMAP & DIALECT_US_TCBIT) { + if (BasicInformKit`AMERICAN_DIALECT_CFGF) { if (f == 1) print " "; } else { if (f == 1) print " and "; diff --git a/docs/BasicInformKit/S-rlb.html b/docs/BasicInformKit/S-rlb.html index 911204c45..035bddac5 100644 --- a/docs/BasicInformKit/S-rlb.html +++ b/docs/BasicInformKit/S-rlb.html @@ -312,7 +312,7 @@ occur, in so far as memory economy allows this. [ DB_Rule R N blocked; if (R==0) return; print "[Rule ~", (RulePrintingRule) R, "~ "; - #ifdef NUMBERED_RULES; print "(", N, ") "; #endif; + if (BasicInformKit`NUMBERED_RULES_CFGF) print "(", N, ") "; if (blocked == false) "applies.]"; print "does not apply (wrong "; if (blocked == 1) print "scene"; diff --git a/docs/BasicInformKit/S-txt.html b/docs/BasicInformKit/S-txt.html index 85049ce47..3c8382771 100644 --- a/docs/BasicInformKit/S-txt.html +++ b/docs/BasicInformKit/S-txt.html @@ -99,8 +99,9 @@ number of characters, plus one for the null terminator. ];

§3. Character Set. On the Z-machine, we use the 8-bit ZSCII character set, stored in bytes; -on Glulx, we use the opening 16-bit subset of Unicode (which though only a -subset covers almost all letter forms used on Earth), stored in half-words. +on Glulx, we use full 32-bit Unicode, stored in words. (Until May 2023, +16-bit half-words were used, but that restricted the range of Unicode points +so as to omit such essentials as "Smiling Cat Face With Heart-Shaped Eyes".)

The Z-machine does have very partial Unicode support, but not in a way that @@ -110,7 +111,7 @@ OS X, using the Lucida Grande font) can produce many thousands of glyphs. But it is not capable of printing those characters into memory rather than the screen, an essential technique for texts: it can only write each character to a single byte, and it does so in ZSCII. That forces our hand when it comes to -choosing the indexed-text character set. +choosing the character set here. For Unicode, use Glulx.

@@ -118,7 +119,7 @@ choosing the indexed-text character set.
 Constant TEXT_TY_Storage_Flags = BLK_FLAG_MULTIPLE;
 Constant ZSCII_Tables;
 #IFNOT;
-Constant TEXT_TY_Storage_Flags = BLK_FLAG_MULTIPLE + BLK_FLAG_16_BIT;
+Constant TEXT_TY_Storage_Flags = BLK_FLAG_MULTIPLE + BLK_FLAG_WORD;
 Constant Large_Unicode_Tables;
 #ENDIF;
 
@@ -274,6 +275,7 @@ memory as necessary so that we can always avoid overruns entirely.

+Constant TEXT_TY_BufferSize = BasicInformKit`TEXT_BUFFER_SIZE_CFGV + 3;
 Constant TEXT_TY_NoBuffers = 2;
 
 #ifdef TARGET_ZCODE;
diff --git a/docs/BasicInformKit/S-unc.html b/docs/BasicInformKit/S-unc.html
index 1e6b6aea5..3ad1def1a 100644
--- a/docs/BasicInformKit/S-unc.html
+++ b/docs/BasicInformKit/S-unc.html
@@ -65,7 +65,7 @@ MathJax = {
     
 

To tabulate casings in the character set.

-
+

§1. Source. When this section is included, exactly one of the following constants is defined: @@ -73,12 +73,19 @@ defined:

  • (a) ZSCII_Tables, meaning that we will use ZSCII as the character set for characters in text values. -
  • (b) Small_Unicode_Tables, meaning that we will use Unicode but store +
  • (b) Large_Unicode_Tables, meaning that we will use Unicode and store +word-sized characters. +
+

At one time we also supported, but essentially never used, +

+ +
  • (c) Small_Unicode_Tables, meaning that we will use Unicode but store only single-byte characters, so that only the codes 0 to 255 are valid: in effect ISO Latin-1. -
  • (c) Large_Unicode_Tables, meaning that we will use Unicode and store -two-byte characters, so that all of Unicode in the range 0 to 65535 are valid.
+

This has now been removed. +

+

Whichever is defined, we must create two arrays:

@@ -107,7 +114,7 @@ not included in the ranges below is not a letter.

§2. ZSCII Casing Tables.

-#IFDEF ZSCII_Tables;
+#Ifdef TARGET_ZCODE;
 Array CharCasingChart0 -->
     $0061 (  26) (     -32) $009b (   3) (       3) $00a1 (   1)   UNIC_NCT
     $00a4 (   2) (       3) $00a6 (   1)   UNIC_NCT $00a9 (   6) (       6)
@@ -122,28 +129,12 @@ not included in the ranges below is not a letter.
     $00ca (  -3) (      -1) $00d0 (   3) (      -3) $00d4 (  -3) (      -1)
     $00d9 (   2) (      -2) $00dd (   1) (      -1) $0000
 ;
-#ENDIF; ZSCII_Tables
+#Endif; TARGET_ZCODE
 
-

§3. Small Unicode Casing Tables.

+

§3. Large Unicode Casing Tables.

-#IFDEF Small_Unicode_Tables;
-Array CharCasingChart0 -->
-    $0061 (  26) (     -32) $00aa (   1)   UNIC_NCT $00b5 (   1)   UNIC_NCT $00ba (   1)   UNIC_NCT
-    $00df (   1)   UNIC_NCT $00e0 (  23) (     -32) $00f8 (   7) (     -32) $00ff (   1)   UNIC_NCT
-    $0000
-;
-
-Array CharCasingChart1 -->
-    $0041 (  26) (      32) $00c0 (  23) (      32) $00d8 (   7) (      32) $0000
-;
-
-#ENDIF; Small_Unicode_Tables
-
-

§4. Large Unicode Casing Tables.

- -
-#IFDEF Large_Unicode_Tables;
+#Ifdef TARGET_GLULX;
 Array CharCasingChart0 -->
     $0061 (  26) (     -32) $00aa (   1)   UNIC_NCT $00b5 (   1) (     743) $00ba (   1)   UNIC_NCT
     $00df (   1)   UNIC_NCT $00e0 (  23) (     -32) $00f8 (   7) (     -32) $00ff (   1) (     121)
@@ -223,7 +214,7 @@ not included in the ranges below is not a letter.
     $213e (   2)   UNIC_NCT $2145 (   1)   UNIC_NCT $ff21 (  26) (      32) $0000
 ;
 
-#ENDIF; Large_Unicode_Tables
+#Endif; TARGET_GLULX
 
-

§63. Choose Objects. This material, the final body of code in the parser, is an I7 addition. +

§63. Tracing. Uncomment this line and rebuild the kit to enable tracing of what the algorithm +below is doing. (This constant should not be used anywhere except in this file, +where #Ifdef on it will have the expected effect: elsewhere, it might not.) +

+ +
+Constant LKTRACE_CHOOSE_OBJECTS;
+
+

§64. Choose Objects. This material, the final body of code in the parser, is an I7 addition. The I6 parser leaves it to the user to provide a ChooseObjects routine to decide between possibilities when the situation is ambiguous. For I7 use, we provide a ChooseObjects which essentially runs the "does the @@ -4010,8 +4077,6 @@ is defined in the Standard Rules, not here.

-onstant COBJ_DEBUG;
-
 the highest value returned by CheckDPMR (see the Standard Rules)
 Constant HIGHEST_DPMR_SCORE = 4;
 
@@ -4050,12 +4115,12 @@ is defined in the Standard Rules, not here.
     if (cobj_flag == 1) {
         .CodeOne;
         if (parameters > 0) {
-            #ifdef COBJ_DEBUG;
+            #ifdef LKTRACE_CHOOSE_OBJECTS;
             print "[scoring ", (the) obj, " (second)]^";
             #endif;
             return ScoreDabCombo(parser_results-->INP1_PRES, obj);
         } else {
-            #ifdef COBJ_DEBUG;
+            #ifdef LKTRACE_CHOOSE_OBJECTS;
             print "[scoring ", (the) obj, " (first) in ",
                 alt_match_list-->0, " combinations]^";
             #endif;
@@ -4063,7 +4128,7 @@ is defined in the Standard Rules, not here.
             for (i=1: i<=alt_match_list-->0: i++) {
                 spcount = ScoreDabCombo(obj, alt_match_list-->i);
                 if (spcount == HIGHEST_DPMR_SCORE) {
-                    #ifdef COBJ_DEBUG;
+                    #ifdef LKTRACE_CHOOSE_OBJECTS;
                     print "[scored ", spcount, " - best possible]^";
                     #endif;
                     return spcount;
@@ -4075,7 +4140,7 @@ is defined in the Standard Rules, not here.
     }
     if (cobj_flag == 2) {
         .CodeTwo;
-        #ifdef COBJ_DEBUG;
+        #ifdef LKTRACE_CHOOSE_OBJECTS;
         print "[scoring ", (the) obj, " (simple); parameters = ", parameters,
             " aw = ", advance_warning, "]^";
         #endif;
@@ -4092,7 +4157,7 @@ is defined in the Standard Rules, not here.
         return l;
     }
 
-    #ifdef COBJ_DEBUG;
+    #ifdef LKTRACE_CHOOSE_OBJECTS;
     print "[choosing a cobj strategy: ";
     #endif;
     swn = wn;
@@ -4117,7 +4182,7 @@ is defined in the Standard Rules, not here.
             match_length = 0; number_matched = 0; match_from = wn;
             token_filter = 0;
             SearchScope(actor, actors_location, line_tdata-->pcount);
-            #ifdef COBJ_DEBUG;
+            #ifdef LKTRACE_CHOOSE_OBJECTS;
             print number_matched, " possible second nouns]^";
             #endif;
             wn = swn;
@@ -4132,7 +4197,7 @@ is defined in the Standard Rules, not here.
     pcount = spcount;
     wn = swn;
 
-    #ifdef COBJ_DEBUG;
+    #ifdef LKTRACE_CHOOSE_OBJECTS;
     print "nothing interesting]^";
     #endif;
     cobj_flag = 2;
@@ -4147,7 +4212,7 @@ is defined in the Standard Rules, not here.
     else { noun = a; second = b; }
     result = CheckDPMR();
     @pull second; @pull noun; @pull act_requester; @pull action;
-    #ifdef COBJ_DEBUG;
+    #ifdef LKTRACE_CHOOSE_OBJECTS;
     print "[", (the) a, " / ", (the) b, " => ", result, "]^";
     #endif;
     return result;
@@ -4168,13 +4233,13 @@ is defined in the Standard Rules, not here.
     return 2;
 ];
 
-

§64. Default Topic. A default value for the I7 sort-of-kind "topic", which never matches. +

§65. Default Topic. A default value for the I7 sort-of-kind "topic", which never matches.

 [ DefaultTopic; return GPR_FAIL; ];
 
-

§65. Recognition-only-GPR. An I6 general parsing routine to look at words from the position marker +

§66. Recognition-only-GPR. An I6 general parsing routine to look at words from the position marker wn in the player's command to see if they match the contents of the text txt, returning either GPR_PREPOSITION or GPR_FAIL according to whether a match could be made. This is used when the an @@ -4202,7 +4267,7 @@ recognises an existing value: it doesn't parse a new one. return r; ]; [ TEXT_TY_ROGPRI txt - pos len wa wl wpos bdm ch own; + pos len wa wl wpos wach bdm ch own; bdm = true; own = wn; len = BlkValueLBCapacity(txt); for (pos=0: pos<=len: pos++) { @@ -4220,7 +4285,12 @@ recognises an existing value: it doesn't parse a new one. wl = WordLength(wn-1); wpos = 0; } - if (wa->wpos ~= ch or TEXT_TY_RevCase(ch)) return GPR_FAIL; + #Ifdef TARGET_ZCODE; + wach = wa->wpos; + #Ifnot; TARGET_GLULX + wach = wa-->wpos; + #Endif; TARGET_ + if (wach ~= ch or TEXT_TY_RevCase(ch)) return GPR_FAIL; wpos++; } } @@ -4228,7 +4298,7 @@ recognises an existing value: it doesn't parse a new one. return GPR_PREPOSITION; ]; -

§66. RunRoutines. This function may not be very well-named, but the idea is to take a property +

§67. RunRoutines. This function may not be very well-named, but the idea is to take a property of a given object and either to print it (and return true) if it's a string, and call it (and pass along its return value) if it's a routine. If the object does not provide the property, we act on the default value for the @@ -4255,7 +4325,7 @@ and in the Inform 7 world it was a facility never used. return obj.prop(); ]; -

§67. Setting the Player's Command. In effect, the text typed most recently by the player is a sort of +

§68. Setting the Player's Command. In effect, the text typed most recently by the player is a sort of text already, though it isn't in text format, and doesn't live on the heap.

@@ -4264,20 +4334,22 @@ the heap. [ SetPlayersCommand from_txt i len at p cp; cp = from_txt-->0; p = TEXT_TY_Temporarily_Transmute(from_txt); len = TEXT_TY_CharacterLength(from_txt); - if (len > 118) len = 118; + if (len > INPUT_BUFFER_LEN-2) len = INPUT_BUFFER_LEN-2; #ifdef TARGET_ZCODE; buffer->1 = len; at = 2; - #ifnot; - buffer-->0 = len; at = 4; - #endif; for (i=0:i<len:i++) buffer->(i+at) = CharToCase(BlkValueRead(from_txt, i), 0); - for (:at+i<120:i++) buffer->(at+i) = ' '; + for (:at+i<INPUT_BUFFER_LEN:i++) buffer->(at+i) = ' '; + #ifnot; + buffer-->0 = len; at = 1; + for (i=0:i<len:i++) buffer-->(i+at) = CharToCase(BlkValueRead(from_txt, i), 0); + for (:at+i<INPUT_BUFFER_LEN:i++) buffer-->(at+i) = ' '; + #endif; VM_Tokenise(buffer, parse); players_command = 100 + WordCount(); The snippet variable "player's command" TEXT_TY_Untransmute(from_txt, p, cp); ]; -

§68. Multiple Object List. The parser uses one data structure which is really a list: but which can't +

§69. Multiple Object List. The parser uses one data structure which is really a list: but which can't be represented as such because the heap might not exist. This is the multiple object list, which is used to handle commands like TAKE ALL by firing off a sequence of actions with one of the objects taken from entries in turn of diff --git a/docs/CommandParserKit/S-tkn.html b/docs/CommandParserKit/S-tkn.html index f92f19a3b..308e4c6ab 100644 --- a/docs/CommandParserKit/S-tkn.html +++ b/docs/CommandParserKit/S-tkn.html @@ -74,7 +74,7 @@ so that a 16-bit VM can hold the range of integers \(-2^{15} = -32768\) to

-[ DECIMAL_TOKEN wnc wna r n wa wl sign base digit digit_count original_wn group_wn;
+[ DECIMAL_TOKEN wnc wna r n wa wl sign base digit digit_count original_wn group_wn ch;
     wnc = wn; original_wn = wn; group_wn = wn;
     r = DECIMAL_TOKEN_INNER();
     if (r ~= GPR_FAIL) return r;
@@ -85,15 +85,32 @@ so that a 16-bit VM can hold the range of integers \(-2^{15} = -32768\) to
     wa = WordAddress(wn);
     wl = WordLength(wn);
     sign = 1; base = 10; digit_count = 0;
-    if (wa->0 ~= '-' or '$' or '0' or '1' or '2' or '3' or '4'
+    #Ifdef TARGET_ZCODE;
+    ch = wa->0;
+    #Ifnot; TARGET_GLULX
+    ch = wa-->0;
+    #Endif; TARGET_
+    if (ch ~= '-' or '$' or '0' or '1' or '2' or '3' or '4'
         or '5' or '6' or '7' or '8' or '9')
         return GPR_FAIL;
-    if (wa->0 == '-') { sign = -1; wl--; wa++; }
+    if (ch == '-') {
+        sign = -1; wl--;
+        #Ifdef TARGET_ZCODE;
+        wa++;
+        #Ifnot; TARGET_GLULX
+        wa = wa+WORDSIZE;
+        #Endif; TARGET_
+    }
     if (wl == 0) return GPR_FAIL;
     n = 0;
     while (wl > 0) {
-        if (wa->0 >= 'a') digit = wa->0 - 'a' + 10;
-        else digit = wa->0 - '0';
+        #Ifdef TARGET_ZCODE;
+        ch = wa->0;
+        #Ifnot; TARGET_GLULX
+        ch = wa-->0;
+        #Endif; TARGET_
+        if (ch >= 'a') digit = ch - 'a' + 10;
+        else digit = ch - '0';
         digit_count++;
         switch (base) {
             2:  if (digit_count == 17) return GPR_FAIL;
@@ -121,7 +138,12 @@ so that a 16-bit VM can hold the range of integers \(-2^{15} = -32768\) to
         }
         if (digit >= 0 && digit < base) n = base*n + digit;
         else return GPR_FAIL;
-        wl--; wa++;
+        wl--;
+        #Ifdef TARGET_ZCODE;
+        wa++;
+        #Ifnot; TARGET_GLULX
+        wa = wa+WORDSIZE;
+        #Endif; TARGET_
     }
     parsed_number = n*sign; wn++;
     return GPR_NUMBER;
@@ -182,7 +204,7 @@ out not to be.) I don't plan to worry about these cases.)
             There's whitespace between the previous word and this one.
             Whitespace is okay around an asterisk...
             if ((lastchar ~= '*' or 'x' or 'X' or $D7)
-                && (newstart->0 ~= '*' or 'x' or 'X' or $D7)) {
+                && (newstart-->0 ~= '*' or 'x' or 'X' or $D7)) {
                 But around any other character, it's not.
                 Don't include the new word.
                 break;
@@ -190,7 +212,7 @@ out not to be.) I don't plan to worry about these cases.)
         }
         newlen = WordLength(wn);
         for (ix=0 : ix<newlen : ix++) {
-            ch = newstart->ix;
+            ch = newstart-->ix;
             if (~~((ch >= '0' && ch <= '9')
                 || (ch == '-' or '+' or 'E' or 'e' or '.' or 'x' or 'X' or '*' or $D7 or $5E)))
                 break;
@@ -201,16 +223,16 @@ out not to be.) I don't plan to worry about these cases.)
             break;
         }
         Okay, include it.
-        bufend = newstart + newlen;
+        bufend = newstart + newlen*WORDSIZE;
         wn++;
-        lastchar = (bufend-1)->0;
+        lastchar = (bufend-WORDSIZE)-->0;
         lastwasdot = (newlen == 1 && lastchar == '.');
     }
 
     if (wn > firstwd && lastwasdot) {
         Exclude a trailing period.
         wn--;
-        bufend--;
+        bufend = bufend - WORDSIZE;
     }
 
     if (wn == firstwd) {
@@ -218,7 +240,7 @@ out not to be.) I don't plan to worry about these cases.)
         return GPR_FAIL;
     }
 
-    parsed_number = FloatParse(buf, bufend-buf, true);
+    parsed_number = FloatParse(buf, (bufend-buf)/WORDSIZE, true);
     if (parsed_number == FLOAT_NAN)
         return GPR_FAIL;
     return GPR_NUMBER;
diff --git a/docs/EnglishLanguageKit/S-lng.html b/docs/EnglishLanguageKit/S-lng.html
index bcca1429c..8ce1101a1 100644
--- a/docs/EnglishLanguageKit/S-lng.html
+++ b/docs/EnglishLanguageKit/S-lng.html
@@ -51,14 +51,21 @@
     
 

The fundamental definitions needed by the parser and the verb library in order to specify the language of play -- that is, the language used for communications between the story file and the player.

-
+
-

§1. Identification.

+

§1. Initialisation. It used to be optional whether or not to include a function of this name in +a language kit: it's now compulsory, even when (as now) it does nothing. +

+ +
+[ LanguageInitialise; ];
+
+

§2. Identification.

 Constant ENGLISHLANGUAGEKIT = 1;
 
-

§2. Vocabulary.

+

§3. Vocabulary.

 Constant AGAIN1__WD     = 'again';
@@ -112,7 +119,7 @@
 Constant RESTART__WD    = 'restart';
 Constant RESTORE__WD    = 'restore';
 
-

§3. Pronouns.

+

§4. Pronouns.

 Array LanguagePronouns table
@@ -128,7 +135,7 @@
     'her'     $$010000000000                    NULL
     'them'    $$000111000111                    NULL;
 
-

§4. Descriptors.

+

§5. Descriptors.

 Array LanguageDescriptors table
@@ -156,7 +163,7 @@
     'lighted' $$111111111111    LIGHTED_PK      NULL
     'unlit'   $$111111111111    UNLIGHTED_PK    NULL;
 
-

§5. Numbers.

+

§6. Numbers.

 Array LanguageNumbers table
@@ -169,7 +176,7 @@
     'twenty-nine' 29 'thirty' 30
 ;
 
-

§6. Time.

+

§7. Time.

 [ LanguageTimeOfDay hours mins i;
@@ -180,19 +187,29 @@
     if ((hours/12) > 0) print " pm"; else print " am";
 ];
 
-

§7. Directions.

+

§8. Directions.

 [ LanguageDirection d;
     print (name) d;
 ];
 
-

§8. Translation.

+

§9. Translation. These are all opportunities to meddle with the normal (Anglo-centric) running +of things, which we will decline. +

+ +

Until April 2023, it was optional for a kit to provide LanguageRefers and +LanguagePrintShortName, but this is now compulsory. +

 [ LanguageToInformese; ];
+
+[ LanguageRefers x y; return -1; ];
+
+[ LanguagePrintShortName obj; rfalse; ];
 
-

§9. Articles.

+

§10. Articles.

 Constant LanguageAnimateGender   = male;
@@ -202,9 +219,15 @@
                                            0 = starting with a consonant
                                            1 = starting with a vowel
 
-[ LanguageContraction text;
-    if (text->0 == 'a' or 'e' or 'i' or 'o' or 'u'
-                or 'A' or 'E' or 'I' or 'O' or 'U') return 1;
+[ LanguageContraction text
+    ch;
+    #Ifdef TARGET_ZCODE;
+    ch = text->0;
+    #Ifnot; TARGET_GLULX
+    ch = text-->0;
+    #Endif; TARGET_
+    if (ch == 'a' or 'e' or 'i' or 'o' or 'u'
+           or 'A' or 'E' or 'I' or 'O' or 'U') return 1;
     return 0;
 ];
 
@@ -222,7 +245,7 @@
 
 Array LanguageGNAsToArticles --> 0 0 0 1 1 1 0 0 0 1 1 1;
 
-

§10. Commands. LanguageVerbLikesAdverb is called by PrintCommand when printing an UPTO_PE +

§11. Commands. LanguageVerbLikesAdverb is called by PrintCommand when printing an UPTO_PE error or an inference message. Words which are intransitive verbs, i.e., which require a direction name as an adverb ("walk west"), not a noun ("I only understood you as far as wanting to touch the ground"), should @@ -262,7 +285,7 @@ adjective in a name rfalse; ];

-

§11. Stubs. To reduce the need for conditional compilation, we provide these stub +

§12. Stubs. To reduce the need for conditional compilation, we provide these stub routines:

diff --git a/docs/WorldModelKit/S-act.html b/docs/WorldModelKit/S-act.html index 4a3ff6a5b..6d36e0d21 100644 --- a/docs/WorldModelKit/S-act.html +++ b/docs/WorldModelKit/S-act.html @@ -875,9 +875,15 @@ a whole action might produce "Henry taking the grapefruit".) print "~"; for (a=cf:d<cw:d++,a++) { wn = a; b = WordAddress(a); c = WordLength(a); + #Ifdef TARGET_ZCODE; for (i=b:i<b+c:i++) { print (char) 0->i; } + #Ifnot; TARGET_GLULX + for (i=0:i<c:i++) { + print (char) b-->i; + } + #Endif; TARGET_ if (d<cw-1) print " "; } print "~"; diff --git a/docs/WorldModelKit/S-lst.html b/docs/WorldModelKit/S-lst.html index 766c7863f..9249609b2 100644 --- a/docs/WorldModelKit/S-lst.html +++ b/docs/WorldModelKit/S-lst.html @@ -65,7 +65,7 @@ MathJax = {

A flexible object-lister taking care of plurals, inventory information, various formats and so on.

-
+

§1. Specification. The list-writer is called by one of the following function calls:

@@ -370,10 +370,16 @@ is non-zero then the iterator is required to disqualify any entry whose Constant ADVANCE_ITF = 1; Constant COALESCE_ITF = 2; Constant START_ITF = 3; - -Constant DBLW; ! Uncomment this to provide debugging information at run-time -

§8. Marked List Iterator. Here the raw list is provided by the MarkedObjectArray, which is convenient +

§8. Tracing. Uncomment this line and rebuild the kit to enable tracing of what the algorithm +below is doing. (This constant should not be used anywhere except in this file, +where #Ifdef on it will have the expected effect: elsewhere, it might not.) +

+ +
+Constant LKTRACE_LIST_WRITER;
+
+

§9. Marked List Iterator. Here the raw list is provided by the MarkedObjectArray, which is convenient for coalescing, but not so helpful for translating the obj parameter into the \(i\) such that it is \(x_i\). We simply search from the beginning to do this, which combined with other code using the iterator makes for some @@ -408,7 +414,7 @@ very rapid anyway (because the player can only read very slowly). return nothing; ]; -

§9. Concealment. This is the definition of concealment used by the list-writer, and means that, +

§10. Concealment. This is the definition of concealment used by the list-writer, and means that, for example, the "deciding the concealed possessions" activity is taken into account.

@@ -421,7 +427,28 @@ account. rfalse; ]; -

§10. Coalesce Marked List. The return value is the new first entry in the raw list. +

§11. Having Evident Content +This is true when something has at least one unconcealed thing in it. +It's false when something is truly empty or when all the things in +it are concealed or undescribed, and is used to ensure that output +is consistent in both those cases. The player shouldn't count for +these purposes, but since the player is undescribed, they're excluded +anyway. +

+ +
+[ ObviouslyOccupied o x;
+  if (~~((o ofclass K5_container) || (o ofclass K6_supporter))) rfalse;
+  if (o has container && o hasnt open && o hasnt transparent) rfalse; opaque closed container's status can never be obvious
+  x = child(o);
+  while (x) {
+    if ((x hasnt concealed) && (~~TestConcealment(o, x))) rtrue;
+    x = sibling(x);
+  }
+  rfalse;
+];
+
+

§12. Coalesce Marked List. The return value is the new first entry in the raw list.

@@ -451,7 +478,7 @@ account.
     return MarkedObjectArray-->0;
 ];
 
-

§11. Object Tree Iterator. Here the raw list is the list of all children of a given parent: since the +

§13. Object Tree Iterator. Here the raw list is the list of all children of a given parent: since the argument obj is required to be a member of the raw list, we can use parent(obj) to find it. Now seeking and advancing are fast, but coalescing is slower. @@ -478,12 +505,12 @@ is slower. } ]; -

§12. Coalesce Object Tree. Again, the return value is the new first entry in the raw list. +

§14. Coalesce Object Tree. Again, the return value is the new first entry in the raw list.

 [ ObjectTreeCoalesce obj memb lt later;
-    #Ifdef DBLW; print "^^Sorting out: "; DiagnoseSortList(obj); #Endif;
+    #Ifdef LKTRACE_LIST_WRITER; print "^^Sorting out: "; DiagnoseSortList(obj); #Endif;
     .StartAgain;
     memb = obj;
     while (memb ~= nothing) {
@@ -505,7 +532,7 @@ is slower.
             if (LT_Compare(later.list_together, lt) == 0) {
                 Yes, they do: so we perform a regrouping of the list and start again:
                 obj = GroupChildren(parent(obj), lt);
-                #Ifdef DBLW; print "^^Sorted to: "; DiagnoseSortList(obj); #Endif;
+                #Ifdef LKTRACE_LIST_WRITER; print "^^Sorted to: "; DiagnoseSortList(obj); #Endif;
                 jump StartAgain;
             }
         }
@@ -514,7 +541,7 @@ is slower.
     return obj;
 ];
 
-

§13. GroupChildren. The following runs through the child-objects of par in the I6 object tree, +

§15. GroupChildren. The following runs through the child-objects of par in the I6 object tree, and moves those having a given list_property property value together, to become the eldest children. It preserves the ordering in between those objects, and also in between those not having that property value. @@ -537,13 +564,13 @@ objects which in all other circumstances never have children in the tree. return child(par); ]; -#Ifdef DBLW; +#Ifdef LKTRACE_LIST_WRITER; [ DiagnoseSortList obj memb; for (memb=obj: memb~=nothing: memb=sibling(memb)) print memb, " --> "; new_line; ]; #Endif; -

§14. WriteListFrom. And here we go at last. Or at any rate we initialise the quartet of global +

§16. WriteListFrom. And here we go at last. Or at any rate we initialise the quartet of global variables detailing the current list-writing process, and begin.

@@ -579,7 +606,7 @@ variables detailing the current list-writing process, and begin. @pull c_margin; @pull c_depth; @pull c_style; @pull c_iterator; ]; -

§15. Standard Contents Listing Rule. The default for the listing contents activity is to call this rule in its +

§17. Standard Contents Listing Rule. The default for the listing contents activity is to call this rule in its "for" stage: note that this suppresses the use of the activity, to avoid an infinite regress. The activity is used only for the default ObjectTreeIterator, so there is no need to specify which is used. @@ -590,7 +617,7 @@ an infinite regress. The activity is used only for the default WriteListFrom(child(parameter_value), c_style, c_depth, true); ]; -

§16. Partitioning. Given qualifying objects \(x_1, ..., x_j\), we partition them into classes of +

§18. Partitioning. Given qualifying objects \(x_1, ..., x_j\), we partition them into classes of the equivalence relation \(x_i\sim x_j\) if and only

@@ -611,7 +638,7 @@ objects in this class.

-#Ifdef DBLW;
+#Ifdef LKTRACE_LIST_WRITER;
 Global DBLW_no_classes; Global DBLW_no_objs;
 [ DebugPartition partition_class_sizes partition_classes first depth i k o;
     print "[Length of list is ", DBLW_no_objs, " with ", k, " plural.]^";
@@ -626,7 +653,7 @@ objects in this class.
 ];
 #Endif;
 
-

§17. Partition List. The following creates the partition_classes and partition_class_sizes +

§19. Partition List. The following creates the partition_classes and partition_class_sizes accordingly. We return \(n\), the number of classes.

@@ -649,14 +676,14 @@ accordingly. We return \(n\), the number of classes. if (n < 255) n++; } n--; - #Ifdef DBLW; + #Ifdef LKTRACE_LIST_WRITER; DBLW_no_classes = n; DBLW_no_objs = no_objs; DebugPartition(partition_class_sizes, partition_classes, first, depth); #Endif; return n; ]; -

§18. Equivalence Relation. The above algorithm will fail unless ListEqual is indeed reflexive, symmetric +

§20. Equivalence Relation. The above algorithm will fail unless ListEqual is indeed reflexive, symmetric and transitive, which ultimately depends on the care with which Identical is implemented, which in turn hangs on the parse_noun properties compiled by Inform. But this seems to be sound. @@ -664,21 +691,16 @@ by Inform. But this seems to be sound.

 [ ListEqual o1 o2;
-    if ((o1.plural == 0) || (o2.plural == 0)) rfalse;
-    if (child(o1) ~= 0 && WillRecurs(o1) ~= 0) rfalse;
-    if (child(o2) ~= 0 && WillRecurs(o2) ~= 0) rfalse;
-    if (c_style & (FULLINV_BIT + PARTINV_BIT) ~= 0) {
-        if ((o1 hasnt worn && o2 has worn) || (o2 hasnt worn && o1 has worn)) rfalse;
-        if ((o1 hasnt light && o2 has light) || (o2 hasnt light && o1 has light)) rfalse;
-        if (o1 has container) {
-            if (o2 hasnt container) rfalse;
-            if ((o1 has open && o2 hasnt open) || (o2 has open && o1 hasnt open))
-                rfalse;
-        }
-        else if (o2 has container)
-            rfalse;
-    }
-    return Identical(o1, o2);
+  if (o1.KD_Count ~= o2.KD_Count) rfalse;
+  if ((o1.plural == 0) || (o2.plural == 0)) rfalse;
+  if (ObviouslyOccupied(o1) && WillRecurs(o1)) rfalse;
+  if (ObviouslyOccupied(o2) && WillRecurs(o2)) rfalse;
+  if (c_style & (FULLINV_BIT + PARTINV_BIT) ~= 0) {
+    if ((o1 hasnt worn && o2 has worn) || (o2 hasnt worn && o1 has worn)) rfalse;
+    if ((o1 hasnt light && o2 has light) || (o2 hasnt light && o1 has light)) rfalse;
+    if ((o1 has open && o2 hasnt open) || (o2 has open && o1 hasnt open)) rfalse;
+  }
+  return Identical(o1, o2);
 ];
 
 [ WillRecurs o;
@@ -688,7 +710,7 @@ by Inform. But this seems to be sound.
     rfalse;
 ];
 
-

§19. Grouping. A "group" is a maximally-sized run of one or more adjacent partition +

§21. Grouping. A "group" is a maximally-sized run of one or more adjacent partition classes in the list whose first members have a common value of list_together which is a routine or string, and which is not equal to lt_value, the current grouping value. (As we see below, it's by setting @@ -762,7 +784,7 @@ in the above sense. current_lt = lt; } } - #Ifdef DBLW; print "[There are ", no_groups, " groups.]^"; #Endif; + #Ifdef LKTRACE_LIST_WRITER; print "[There are ", no_groups, " groups.]^"; #Endif; return no_groups; ]; @@ -780,7 +802,7 @@ in the above sense. return BlkValueCompare(lt1, lt2); ]; -

§20. Write List Recursively. The big one: WriteListR is the heart of the list-writer. +

§22. Write List Recursively. The big one: WriteListR is the heart of the list-writer.

@@ -824,7 +846,7 @@ in the above sense.
             if (memb==0) { print "*** Error in list-writer ***^"; return; }
         }
 
-        #Ifdef DBLW;
+        #Ifdef LKTRACE_LIST_WRITER;
         DebugPartition(partition_class_sizes, partition_classes, o, depth);
         print "^[Class ", cl, " of ", no_classes, ": first object ", memb,
             " (", memb.list_together, "); groups_to_do ", groups_to_do, ",
@@ -866,7 +888,7 @@ in the above sense.
         groups_to_do--;
         if (c_style & ENGLISH_BIT ~= 0) {
             if (groups_to_do == 1) {
-                if (KIT_CONFIGURATION_BITMAP & SERIAL_COMMA_TCBIT) {
+                if (BasicInformKit`SERIAL_COMMA_CFGF) {
                     if (cl > 1) print ",";
                 }
                 LIST_WRITER_INTERNAL_RM('C');
@@ -879,7 +901,7 @@ in the above sense.
     FreeStack(partition_classes);
 ]; end of WriteListR
 
-

§21. Write Multiple Class Group. The text of a single group which contains more than one partition class. +

§23. Write Multiple Class Group. The text of a single group which contains more than one partition class. We carry out the "grouping together" activity, so that the user can add text fore and aft — this is how groups of objects such as "X, Y and Z" can be fluffed up to "the letters X, Y and Z from a Scrabble set" — @@ -923,10 +945,10 @@ below, and {\it that} is where they are printed. @push lt_value; @push listing_together; @push listing_size; lt_value = memb.list_together; listing_together = memb; - #Ifdef DBLW; print "^^DOWN lt_value = ", lt_value, " listing_together = ", memb, "^^"; + #Ifdef LKTRACE_LIST_WRITER; print "^^DOWN lt_value = ", lt_value, " listing_together = ", memb, "^^"; @push DBLW_no_classes; @push DBLW_no_objs; #Endif; WriteListR(memb, depth, false); - #Ifdef DBLW; print "^^UP^^"; @pull DBLW_no_objs; @pull DBLW_no_classes; #Endif; + #Ifdef LKTRACE_LIST_WRITER; print "^^UP^^"; @pull DBLW_no_objs; @pull DBLW_no_classes; #Endif; @pull listing_size; @pull listing_together; @pull lt_value; c_margin--; @@ -952,7 +974,7 @@ below, and {\it that} is where they are printed. c_style = q; ]; -

§22. Write Single Class Group. The text of a single group which contains exactly one partition class. +

§24. Write Single Class Group. The text of a single group which contains exactly one partition class. Because of the way the multiple-class case recurses, every class ends up in this routine sooner or later; this is the place where the actual name of an object is printed, at long last. @@ -990,7 +1012,7 @@ name of an object is printed, at long last. c_style = q; ]; -

§23. Write After Entry. Each entry can be followed by supplementary, usually parenthetical, information: +

§25. Write After Entry. Each entry can be followed by supplementary, usually parenthetical, information: exactly what, depends on the style. The extreme case is when the style, and the object, call for recursion to list the object-tree contents: this is achieved by calling WriteListR, using the ObjectTreeIterator (whatever @@ -1037,7 +1059,7 @@ the iterator used at the top level) and increasing the depth by 1. if (o has container) { if (o has openable) { if (parenth_flag) { - if (KIT_CONFIGURATION_BITMAP & SERIAL_COMMA_TCBIT) + if (BasicInformKit`SERIAL_COMMA_CFGF) print ","; LIST_WRITER_INTERNAL_RM('C'); } else LIST_WRITER_INTERNAL_RM('A', o); @@ -1117,7 +1139,7 @@ the iterator used at the top level) and increasing the depth by 1. } ]; -

§24. Internal Rule. This rule does nothing in itself; it exists as a placeholder for the +

§26. Internal Rule. This rule does nothing in itself; it exists as a placeholder for the response texts used by the list-writer.

diff --git a/docs/WorldModelKit/S-mpr.html b/docs/WorldModelKit/S-mpr.html index 61c902eca..c594dd499 100644 --- a/docs/WorldModelKit/S-mpr.html +++ b/docs/WorldModelKit/S-mpr.html @@ -65,7 +65,7 @@ MathJax = {

Testing and changing the fundamental spatial relations.

-
+

§1. Map Route-Finding. The general problem we have to solve here is: given \(x, y\in R\), where \(R\) is the set of rooms and we write \(x\sim y\) if there is a map connection from @@ -116,15 +116,17 @@ due to a disagreement between extensions — "fast" wins.

-#ifndef FAST_ROUTE_FINDING;
-#ifndef SLOW_ROUTE_FINDING;
-#ifdef TARGET_GLULX;
-Constant FAST_ROUTE_FINDING;
-#ifnot;
-Constant SLOW_ROUTE_FINDING;
-#endif;
-#endif;
-#endif;
+[ UseFastRouteFinding;
+    if (WorldModelKit`ROUTE_FINDING_CFGV == 0) {
+        #ifdef TARGET_ZCODE;
+        rfalse;
+        #ifnot;
+        rtrue;
+        #endif;
+    }
+    if (WorldModelKit`ROUTE_FINDING_CFGV == 1) rtrue;
+    rfalse;
+];
 

§2. Cache Control. We provide code to enable our route-finding algorithms to cache their partial results from one usage to the next (though at present only the "fast" @@ -187,19 +189,35 @@ by enumerating them in the property oyi++; } if (map_has_changed) { - #ifdef FAST_ROUTE_FINDING; ComputeFWMatrix(filter, use_doors); #endif; + if (UseFastRouteFinding()) ComputeFWMatrix(filter, use_doors); map_has_changed = false; last_filter = filter; last_use_doors = use_doors; } - #ifdef FAST_ROUTE_FINDING; - if (count) return FastCountRouteTo(from, to, filter, use_doors); - return FastRouteTo(from, to, filter, use_doors); - #ifnot; - if (count) return SlowCountRouteTo(from, to, filter, use_doors); - return SlowRouteTo(from, to, filter, use_doors); - #endif; + if (UseFastRouteFinding()) { + if (count) return FastCountRouteTo(from, to, filter, use_doors); + return FastRouteTo(from, to, filter, use_doors); + } else { + if (count) return SlowCountRouteTo(from, to, filter, use_doors); + return SlowRouteTo(from, to, filter, use_doors); + } ]; -

§3. Fast Route-Finding. The following is a form of Floyd's adaptation of Warshall's algorithm for +

§3. When this code became part of WorldModelKit, and thus needed to be linked +at the Inter level rather than mixed in as raw I6 code as in the pre-2020 days, +the mechanism for selecting the route-finding algorithm needed to change. +Previously, if the constant FAST_ROUTE_FINDING was defined, the matrix +FW_Matrix and its functions would be compiled, and otherwise the functions +with names beginning Slow... would be compiled. +

+ +

To avoid having to make two different linkable binaries of WorldModelKit, +one in which fast route finding is used and one in which it isn't, we now +instead compile the functions either way (they are not large) and the Inform +compiler defines the constant FWMATRIX_SIZE to be 2 for slow route-finding +(wasting only a negligible number of words for an unused array) and \(R^2\), +where \(R\) is the number of rooms, for fast route-finding. +

+ +

§4. Fast Route-Finding. The following is a form of Floyd's adaptation of Warshall's algorithm for finding the transitive closure of a directed graph.

@@ -248,8 +266,7 @@ cache is useful for all future routes whatever their endpoints.

-#ifdef FAST_ROUTE_FINDING;
-Array FWMatrix --> NUM_ROOMS*NUM_ROOMS;
+Array FWMatrix --> FWMATRIX_SIZE;
 
 [ FastRouteTo from to filter use_doors diri i dir oy;
     if (from == to) return nothing;
@@ -318,9 +335,8 @@ cache is useful for all future routes whatever their endpoints.
                 }
         }
 ];
-#ENDIF;
 
-

§4. Slow Route-Finding. The alternative algorithm, used when only \(O(n)\) memory is available, +

§5. Slow Route-Finding. The alternative algorithm, used when only \(O(n)\) memory is available, computes only some of the shortest paths leading to \(R_y\), and is not cached — both because the storage is likely to be reused often by other searches and because there is little gain from doing so, given that a subsequent search @@ -371,7 +387,6 @@ the direction of the shortest path from there to \(R_y\).

-#ifndef FAST_ROUTE_FINDING;
 [ SlowRouteTo from to filter use_doors  obj dir in_direction progressed sl through_door;
     if (from == nothing) return nothing;
     if (to == nothing) return nothing;
@@ -436,7 +451,6 @@ the direction of the shortest path from there to \(R_y\).
     }
     return -1;
 ];
-#ENDIF;