1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-07-09 02:24:21 +03:00
inform7/inter/Preliminaries/Chains and Stages.w
2019-03-20 12:51:06 +00:00

177 lines
7.9 KiB
OpenEdge ABL

Chains and Stages.
Sequences of named code-generation stages are called chains.
@h Stages and descriptions.
A processing stage is a step in code generation which acts on a repository
of inter in memory. Some stages change, add to or edit down that code, while
others leave it untouched but output a file based on it.
Each stage can see an entire repository of inter code at a time, and is
not restricted to working through it in sequence. Those which read in or write
out a file also have a filename supplied to them as a parameter, but there
are otherwise no configuration options. It's not possible to tell a stage
to work on one specific function alone, for example.
Stages are named, which are written without spaces, and conventionally use
hyphens: for example, |resolve-conditional-compilation|. Where a filename has
to be supplied, it appears after a colon. Thus |generate-inter:my.intert|
is a valid stage description.
A "chain" is a comma-separated list of stage descriptions, and represents a
sort of program to follow: memory inter is passed through each stage in turn.
The special stage |stop| halts processing of the chain midway. At present
this is only useful for making experimental edits to chain descriptions
to see what just the first half does, without deleting the second half of
the description.
@ There are three ways to use chains. One is from the command line of Inter:
|$ inter/Tangled/inter FILE -inter 'CHAIN'|
The other is to use two experimental features of Inform. This sentence:
>> Use inter chain "STAGES".
replaces the chain normally used for code generation with the one supplied.
(This may very well cause the compiler not to produce viable code, of course.)
Equivalently, a replacement chain can be specified at the Inform 7 command line:
|$ inform7/Tangled/inform7 ... -inter 'CHAIN'|
When using a chain within Inform, one further description syntax is allowed:
the filename |*| means "the filename Inform wants to use for the final
Inform 6 file". This tends to be used for the final stage in the chain, which
is normally |generate-i6:*|.
@h The code-generation stages.
The following are all experimental, and have probably not yet reached their
final form or names. But this briefly describes the stages which currently
exist in the code generator. In the description below, the "repository" is
the reservoir of memory inter code being worked on.
Although one thinks of code generation as a process of turning inter into
Inform 6, in fact it goes both ways, because we also have to read in
the "template" of standing Inform 6 code. The early code generation stages
convert the template from Inform 6 into inter, merging it with the inter
already produced by the front end of the compiler. The later stages then
turn this merged repository into Inform 6 code. (Routines in the template,
therefore, are converted out of Inform 6 and then back into it again. This
sounds inefficient but is surprisingly fast, and enables many optimisations.)
@ |link:T| reads in the I6T template file T, converts it to inter in a very
basic way (creating many splats), and merges it with the repository. Splats
are the unhappiest of inter statements, simply including verbatim snippets
of Inform 6 code.
@ |parse-linked-matter| examines the splats produced by linking and annotates
them by what they seem to want to do. For example,
|splat &"Global nitwit = 2;\n"|
is recognised as an Inform 6 variable declaration, and annotated thus:
|splat GLOBAL &"Global nitwit = 2;\n"|
@ |resolve-conditional-compilation| looks for splats arising from Inform 6
conditional compilation directives such as |#ifdef|, |#ifndef|, |#endif|;
it then detects whether the relevant symbols are defined, or looks at their
values, and deletes sections of code not to be compiled. At the end of this
stage, there are no conditional compilation splats left in the repository.
For example:
|constant MAGIC K_number = 16339|
|splat IFTRUE &"#iftrue MAGIC == 16339;\n"|
|constant WIZARD K_number = 5|
|splat IFNOT &"#ifnot;\n"|
|constant MUGGLE K_number = 0|
|splat ENDIF &"#endif;\n"|
is resolved to:
|constant MAGIC K_number = 16339|
|constant WIZARD K_number = 5|
@ |assimilate| aims to convert all remaining splats in the repository into
higher-level inter statements. For example,
|splat STUB &"#Stub Peach 0;\n"|
|splat ATTRIBUTE &"Attribute marmorial;\n"|
becomes:
|constant Peach K_unchecked_function = Peach_B __assimilated=1|
|property marmorial K_truth_state __assimilated=1 __attribute=1 __either_or=1|
At the end of this stage, there should be no splats left in the repository,
and the linking process is complete.
@ |make-identifiers-unique| looks for symbols marked with the |MAKE_NAME_UNIQUE|
flag (represented in textual form by an asterisk after its name), This flag
means that Inform wants the symbol name to be globally unique in the repository.
For example, if Inform generates the symbol name |fruit*|, it's really telling
the code generator that it eventually wants this to have a name which won't
collide with anything else.
What |make-identifiers-unique| does is to append |_U1|, |_U2|, ... to such
names across the repository. Thus |fruit*| might become |fruit_U176|, and it
is guaranteed that no other symbol has the same name.
This stage is needed because whereas the inter language has namespces, so
that the same name can mean different things in different parts of the
program, Inform 6 (mostly) does not. There cannot be two functions with the
same name in any I6 program, for example.
At the end of this stage, no symbol still has the |MAKE_NAME_UNIQUE| flag.
@ |reconcile-verbs| is a short stage looking for clashes between any verbs (in
the parser interactive fiction sense) which have been assimilated from the
template, and verbs which have been defined in the main source text. For
example, suppose the source creates the command verb "abstract": this would
collide with the command meta-verb "abstract", intended for debugging, which
appears in the template. What this stage does is to detect such problems,
and if it finds one, to prefix the template verb with |!|. Thus we would end
up with two command verbs: |abstract|, with its source text meaning, and
|!abstract|, with its template meaning.
At the end of this stage, all parser verbs have distinct textual forms.
@ |generate-inter:F| writes out the repository as a textual inter file |F|.
(By default, Inform doesn't do this: the inter ordinarily stays in memory
throughout.)
This stage leaves the repository unchanged.
@ |generate-inter-binary:F| writes out the repository as a binary inter
file |F|. (By default, Inform doesn't do this: the inter ordinarily stays in
memory throughout.)
This stage leaves the repository unchanged.
@ |generate-i6:F| translates the repository to an Inform 6 program. This is
normally the final stage in the Inform code generation chain.
This stage leaves the repository unchanged.
@h Diagnostic or non-working stages.
@ |show-dependencies:F| and |log-dependencies| output a dependency graph of
the symbols in the current repository, one to a file, the other to the
debugging log. A dependency means that one can't be compiled without the
other: for example, if a function has a local variable of a given kind, then
the function depends on that kind.
|eliminate-redundant-code| is a stage which removes all material from
the repository which the main routine is not dependent on. This can result
in many template routines being kicked out, and substantially reduces
story file sizes. The stage mostly works, but needs more refinement before
we could safely enable it by default with Inform.
@ |summarise:F| is a very slow diagnostic stage showing the breakdown of the
current repository into packages, writing the output to file |F|. (Slow in
this sense means that it roughly triples compilation time.)
@ |export:F| and |import:F| were part of an experiment to do with caching the
inter generated by the Standard Rules. This eventually worked, but was put on
ice while a better and more systematic solution was found.