I don’t think that “[any person]
” is necessary, just “[person]
” seems sufficient. The line in the generated parse_name()
routine is restructured as:
w = ParseTokenStopped(ROUTINE_FILTER_TT, Noun_Filter_5);
with Noun_Filter_5()
defined as:
[ Noun_Filter_5
x ! saved value of noun
;
x=noun;
return ((noun ofclass K8_person));
];
The routine DoScopeAction()
doesn’t seem to do anything when the context is ROUTINE_FILTER_TT
, so the cycle is broken.
If using “[any person]
” then the corresponding line in parse_name()
becomes:
w = ParseTokenStopped(SCOPE_TT, Scope_Filter_5);
with Scope_Filter_5()
defined as:
[ Scope_Filter_5
obj ! object loop variable
o2 ! saved value of noun
;
switch (scope_stage) {
1: rfalse;
2: obj=noun;
objectloop(noun ofclass Object && (((noun ofclass K8_person) && (noun ofclass K8_person)))) {
o2 = noun; noun = obj;
suppress_scope_loops = true; PlaceInScope(o2, true); suppress_scope_loops = false;
noun = o2;
}
noun=obj;
3: nextbest_etype = NOTINCONTEXT_PE; return -1;
}
];
Although the call to PlaceInScope()
in turn calls DoScopeAction()
, in this case it seems like DoScopeAction()
wouldn’t invoke MatchTextAgainstObject()
because the context is SCOPE_TT
, breaking the cycle.
So, if you want to override scope, you can use “[any person]
” in your grammar lines, and if you want typical scope rules to apply then you can use “[person]
”. I think that “[somebody]
” might offer some advantage for “talkable” things (if you are tinkering with that) because of the way CREATURE_TOKEN
is handled at certain points, something will have to be done to stop the infinite recursion.
As far as what can be done about the root issue… I’m not sure. Every call to NounDomain()
(and there are several sprinkled throughout the parser) can result in the recursion loop due to that routine’s call of SearchScope()
. Some possibilities that have occurred to me:
- Change the compiler’s construction of
.parse_name()
routines to use w = ParseTokenStopped(ROUTINE_FILTER_TT, Noun_Filter_N);
where the Noun_Filter_N()
routine is based on CreatureTest()
. Given the comparison cases above, this seems like it might be the best option, but it will require I7 compiler modification.
- Limit the allowable nesting for
ParseToken()
via a check of the existing parsetoken_nesting
global. This doesn’t actually solve the root problem because it makes it impossible for the “[somebody]
” token to match anything. It also probably imposes undesirable limits for those interested in extreme parsing stunts.
- Add token context to
DoScopeAction()
so that it can skip past things that fail CreatureTest()
when the context is CREATURE_TOKEN
. This prevents the backdrop.parse_name()
routine from being called by itself and solves the OP’s example issue, but it might not be enough on its own to prevent this type of issue in other contexts.
The 6M62 Include
statements needed to implement the last option are:
Limited Fix
Include (-
! ==== ==== ==== ==== ==== ==== ==== ==== ==== ====
! Parser.i6t: DoScopeActionAndRecurse (modified)
! ==== ==== ==== ==== ==== ==== ==== ==== ==== ====
[ DoScopeActionAndRecurse domain nosearch context i ad n obj next_obj;
DoScopeAction(domain, context); ! MODIFIED
! (a)
if ((domain ~= nosearch) &&
((domain ofclass K1_room or K8_person) || (IsSeeThrough(domain) == 1))) {
obj = child(domain);
while (obj) {
next_obj = sibling(obj);
if ((domain == actor) || (TestConcealment(domain, obj) == false)) {
DoScopeActionAndRecurse(obj, nosearch, context);
}
obj = next_obj;
}
}
! (b)
if (domain provides component_child) {
obj = domain.component_child;
while (obj) {
next_obj = obj.component_sibling;
if ((domain == actor) || (TestConcealment(domain, obj) == false)) {
DoScopeActionAndRecurse(obj, 0, context);
}
obj = next_obj;
}
}
! (c)
ad = domain.&add_to_scope;
if (ad ~= 0) {
! Test if the property value is not an object.
#Ifdef TARGET_ZCODE;
i = (UnsignedCompare(ad-->0, top_object) > 0);
#Ifnot; ! TARGET_GLULX
i = (((ad-->0)->0) ~= $70);
#Endif; ! TARGET_
if (i) {
ats_flag = 2+context;
RunRoutines(domain, add_to_scope);
ats_flag = 0;
}
else {
n = domain.#add_to_scope;
for (i=0 : (WORDSIZE*i)<n : i++)
if (ad-->i) {
DoScopeActionAndRecurse(ad-->i, 0, context);
}
}
}
];
-) instead of "DoScopeActionAndRecurse" in "Parser.i6t".
Include (-
! ==== ==== ==== ==== ==== ==== ==== ==== ==== ====
! Parser.i6t: DoScopeAction (modified)
! ==== ==== ==== ==== ==== ==== ==== ==== ==== ====
[ DoScopeAction item context; ! MODIFIED
#Ifdef DEBUG;
if (parser_trace >= 6)
print "[DSA on ", (the) item, " with reason = ", scope_reason,
" p1 = ", parser_one, " p2 = ", parser_two, "]^";
#Endif; ! DEBUG
@push parser_one; @push scope_reason;
switch(scope_reason) {
TESTSCOPE_REASON: if (item == parser_one) parser_two = 1;
LOOPOVERSCOPE_REASON: if (parser_one ofclass Routine) indirect(parser_one, item);
PARSING_REASON, TALKING_REASON:
! BEGIN MODIFICATION
if (context == CREATURE_TOKEN && CreatureTest(item) == false) {
! print "<DSA bailout!>^";
return false;
}
! END MODIFICATION
MatchTextAgainstObject(item, context); ! MODIFIED
}
@pull scope_reason; @pull parser_one;
];
-) instead of "DoScopeAction" in "Parser.i6t".
They need to be modified a bit for 10.1 because the syntax for inclusions has changed.