Conditional I6 compilation of Include (-....-) phrases in Ver 10

I want to include certain I6 parser routines using Include (-...-) replacing "SomeParserRoutine" so that I can tinker with them, but some run into a problem because they reference I6 variables, arrays or routines that seem to be created only in the final stages of Inter compilation to I6 and therefore fail the Inter pipeline ‘shorten-wiring’ stage.

e.g.

"Include (- [ DoScopeActionAndRecurse ... -) replacing "DoScopeActionAndRecurse".
Include (-
[ DoScopeActionAndRecurse domain nosearch context i ad n obj next_obj;
	DoScopeAction(domain);
	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) == 0)))) {
				DoScopeActionAndRecurse(obj, nosearch, context);
			}
			(obj = next_obj);
		}
	}
	if ((_final_propertyexists(OBJECT_TY, domain, A_component_child))) {
		(obj = (domain.component_child));
		while (obj) {
			(next_obj = (obj.component_sibling));
			if ((((domain == actor)) || ((TestConcealment(domain, obj) == 0)))) {
				DoScopeActionAndRecurse(obj, 0, context);
			}
			(obj = next_obj);
		}
	}
	(ad = (_final_propertyarray(OBJECT_TY, domain, A_add_to_scope)));
	if ((ad ~= 0)) {
		(i = (metaclass((ad-->(0))) == Object));
		if (i) {
			(ats_flag = (2 + context));
			RunRoutines(domain, A_add_to_scope);
			(ats_flag = 0);
		} else {
			(n = (_final_propertylength(OBJECT_TY, domain, A_add_to_scope)));
			for ((i = 0):((WORDSIZE*i) < n):(i)++) {
				if ((ad-->(i))) {
					DoScopeActionAndRecurse((ad-->(i)), 0, context);
				}
			}
		}
	}
];
-) replacing "DoScopeActionAndRecurse".

results in

Problem. Something went wrong late in compilation, when working through the ‘pipeline’ of code-generation steps. (This should not normally happen unless your source text is making use of ‘(-’ and ‘-)’ and getting that wrong, or unless you are experimenting with non-standard pipelines.) The pipeline looks like so:

view earlier steps
  1. read ← *memory

  2. parse-insertions

  3. resolve-conditional-compilation

  4. compile-splats

  5. load-binary-kits

  6. make-synoptic-module

  1. shorten-wiring

Problem: unable to find definitions for the following name(s): _final_propertyexists, A_component_child, _final_propertyarray, A_add_to_scope, _final_propertylength

view later steps
  1. detect-indirect-calls

  2. make-identifiers-unique

  3. reconcile-verbs

  4. eliminate-redundant-labels

  5. eliminate-redundant-operations

  6. optionally-generate text →

  7. generate

  8. index

Because of this problem, the source could not be translated into a working game. (Correct the source text to remove the difficulty and click on Go once again.)

Now, it’s possible to get past this block by subterfuge, i.e. by writing another I6 inclusion that defines the problem names as dummy variables, arrays and routines:

view including dummy definitions
Include (-
#ifndef _final_propertyexists;
[ _final_propertyexists; ];  !###Delete
#endif;
#ifndef A_component_child;
Array A_component_child --> 1;  !###Delete
#endif;
#ifndef  _final_propertyarray;
[ _final_propertyarray;];  !###Delete
#endif;
#ifndef A_add_to_scope;
Array A_add_to_scope --> 1;  !###Delete
#endif;
#ifndef _final_propertylength;
[ _final_propertylength; ];  !###Delete
#endif;
-).

and this will now compile to an I6 ‘auto.inf’ source file, but the problem now is that the I7->Inter->I6 compilation steps strip out the #ifndef and #endif statements, so that these variables, arrays and routines are now defined twice in the I6 source- causing the I6 compiler to bail with errors:

view generated errors

C:\Program Files\Inform\Compilers\inform6
-wSDGk +include_path=…\Source,.\ auto.inf output.ulx
Inform 6.41 for Win32 (22nd July 2022)
auto.inf(4159): Error: “A_component_child” is a name already in use and may not be used as a new array name (Array “A_component_child” was defined at line 4091)
> Array A_component_child
auto.inf(4159): Error: Expected ‘;’ but found Array
> Array
auto.inf(4160): Error: “A_add_to_scope” is a name already in use and may not be used as a new array name (Array “A_add_to_scope” was defined at line 4088)
> Array A_add_to_scope
auto.inf(4160): Error: Expected ‘;’ but found Array
> Array
auto.inf(80622): Error: “_final_propertyexists” is a name already in use and may not be used as a routine name (Routine “_final_propertyexists” was defined at line 6194)
> [ _final_propertyexists

This isn’t a problem for global variables- I6 doesn’t seem to mind these being defined twice- but it clearly can be for arrays and routines (I’m not sure why only one of the three routines here generates an error- perhaps the compiler gives up in disgust after finding the first one?)

At present I’m manually commenting out the duplicate definitions in ‘auto.inf’ and running the I6 compiler on the edited source from the command line, but is there a less troublesome approach?

1 Like

It looks like you’re using post-compilation code as the basis for your inclusion. Can you pull the version of the routine from the template file instead?

(The template files are still there in 10.1.2, just moved – see Inter/CommandParserKit/Sections/Parser.i6t for the DoScopeAndRecurse() routine’s definition. When I use that definition as the basis of the replacement, it compiles OK for me.)

2 Likes

Duh! I am a twit!

As you say,

Include (- <kit version of DoScopeActionAndRecurse> -)

compiles happily into the post-Inter version I was trying to include :upside_down_face:

Although, going back to the original question- do you know of a way to include I6 conditional compilation statements into the target I6 source file from Ver 10 of I7?

If by conditional compilation you mean by #ifdef, no, I don’t think we can. (We used to be able to with Erik Temple’s clever inline debugging tactic but no more.)

Yes, I saw that, tried it… :upside_down_face:

One could put the I6 into a kit and then with some build script finagling maintain two precompiled copies of the kit, one with the flag and one without, kept in different nests. Then, when compiling I7 (on the command-line), specify the -nest of the one you want. (Obviously, this would literally get exponentially more complicated if there were more than one flag you wanted to be able to vary.)

Probably needs the “partly implemented” Annotations for kit linking to be a viable approach when replacing existing routines.

1 Like

I think maybe I’m just not understanding your question. It looks like the compiler is OK with use if #ifdef and the like so long as it doesn’t span across I6 inclusions. As I understood it, the errors that you were getting were caused by the conflict with the automatic renaming of variables happening in the I6->Inter->I6 translation, not from the use of #ifdef itself. (Is that off-base?)

Are you trying to retain an #ifdef in the second iteration of the I6 version of the code? I would think that the target would be the first iteration of I6 (pre-Inter).

Exactly that- although with your help the immediate need for it has receded. As you say, #ifdef works fine for the pre-Inter iteration.

Well, it’s a bit more than renaming of variables- the I6 → Inter → I6 compilation replaces some longstanding I6 idioms:

object.#property becomes _final_propertylength(OBJECT_TY, object, property_metadata_array)
object.&property becomes _final_propertyarray(OBJECT_TY, object, property_metadata_array)
object provides property becomes _final_propertyexists(OBJECT_TY, object, property_metadata_array)

where property metadata arrays are compiled from Inter to have forms such as

Array A_component_child --> [ 1; subterfuge_41; 0; "component_child"; K0_kind; K1_room; K2_thing; K9_region; K3_direction; NULL; ];

where A_component_child -->1 (subterfuge_41) is an alias for the actual property/attribute (component_child), A_component_child -->0 and A_component_child -->2 are respectively flags for (i) whether this is compiled as an attribute (2) or property (1); (ii) is an either-or property/attribute (always true for attributes), A_component_child-->3 “component_child” is its ‘printed name’ and the following elements are a list of the kinds/objects (if any) restricted to providing said property.

object properties and attributes now generally being accessed from Inter-compiled I6 via these newly-minted arrays and functions rather than directly via the object.property / object has attribute idioms.