mirror of
https://github.com/ganelson/inform.git
synced 2024-07-09 02:24:21 +03:00
255 lines
11 KiB
OpenEdge ABL
255 lines
11 KiB
OpenEdge ABL
Textual Inter.
|
|
|
|
A specification of the inter language, as written out in text file form.
|
|
|
|
@h Textual, Binary, Memory.
|
|
Inter code has three representations: as a binary file, as a textual file,
|
|
and in memory -- a sort of cross-referenced form of binary. For speed, the
|
|
Inform compiler generates memory inter directly, and code-generates from
|
|
that, so that the inter is normally never written out to disc. When Inter
|
|
performs a conversion, it loads (say) textual inter into memory inter, then
|
|
writes that out as binary inter.
|
|
|
|
The following specification covers the inter language in its textual form:
|
|
a UTF-8 encoded text file which conventionally takes the file extension
|
|
".intert".
|
|
|
|
It should be stressed that inter is designed for inspection -- that is, for
|
|
people to be able to read. It's not intended as a programming language for
|
|
humans to write: the code is verbose and low-level. The idea is that inter
|
|
code will be written by programs (such as Inform), but that this code will
|
|
be possible for humans to check.
|
|
|
|
Like assembly language, inter code is line-based: each line is a "statement".
|
|
Lines can be of arbitrary length. A line beginning with a |#| (in column 1) is
|
|
a comment, and blank lines are ignored.
|
|
|
|
The term "name" below means a string of one or more English upper or lower
|
|
case letters, underscores, or digits, except that it must not begin with
|
|
a digit.
|
|
|
|
As in Python, indentation from the left margin is highly significant, and
|
|
should be in the form of tab characters.
|
|
|
|
Inform follows certain conventions in the inter that it writes, but these
|
|
conventions are not part of the specification, and may change. Any paragraph
|
|
below which begins with "Convention" records the current practice.
|
|
|
|
There are three forms of statement: global statements, data statements, and
|
|
code statements. We will take these in turn.
|
|
|
|
@h Global statements.
|
|
These statements must appear first in the file, and must be unindented.
|
|
There are only four of these:
|
|
|
|
@ |version NUMBER| indicates that the file was written in that version of
|
|
the inter language. At present there has only ever been one version, but
|
|
that may not always be true. A |version| statement number must come before
|
|
anything else, even other global statements; in particular, there cannot be
|
|
two such statements in the same file.
|
|
|
|
Convention. Inform always opens with the statement: |version 1|
|
|
|
|
@ |packagetype NAME| declares that |NAME| is the name of a type of package.
|
|
Packages are the main hierarchical organisation for inter files, as we
|
|
will see below. Each package has a type as well as a name, and the type
|
|
must be one of those declared like this.
|
|
|
|
For example, |packagetype _adjective| creates |_adjective| as a possible type
|
|
for packages in this file.
|
|
|
|
The first two package types must be |_plain| and |_code|, in that order.
|
|
|
|
Convention. All of Inform's package type names begin similarly with an
|
|
underscore, to prevent name clashes. Inform uses package types semantically,
|
|
to show what kind of thing is being defined in the content of a particular
|
|
package. This makes it easier to search a large inter repository for all of
|
|
the adjective defimitions, for example: we just need to look for packages of
|
|
type |_adjective|.
|
|
|
|
@ |pragma TARGET "WHATEVER"| does not change the meaning of the inter file;
|
|
it simply provides pragmatic advice to the eventual compiler of code
|
|
generated from this file. |TARGET| indicates the context for which this
|
|
is intended; at present, the only possible choice is |target_I6|, meaning,
|
|
"if you are compiling me to Inform 6".
|
|
|
|
Convention. Inform uses this to pass on ICL (Inform Command Language)
|
|
commands to Inform 6, such as memory settings or command-line switches.
|
|
For example,
|
|
= (text as Inter)
|
|
pragma target_I6 "$MAX_LABELS=200000"
|
|
=
|
|
(This would be meaningless if we were compiling to some other format.)
|
|
|
|
@ |primitive PRIMITIVE IN -> OUT| defines a new code statement -- if inter
|
|
were an assembly language, these would be the opcodes. For example,
|
|
= (text as Inter)
|
|
primitive !move val val -> void
|
|
=
|
|
defines the primitive |!move| as something which consumes two values and
|
|
produces none. (Further details on this will appear in the section on code
|
|
packages.)
|
|
|
|
@h Package declarations.
|
|
After the global area, an inter file should declare a package called |main|,
|
|
which must have the package type |_plain|.
|
|
|
|
The statement |package NAME TYPE| declares a new package, and the |TYPE|
|
|
must be one of those declared by |packagetype| statements in the global area.
|
|
|
|
The declaration line for a package begins at the level of indentation of
|
|
the package's owner. For |main|, it should be unindented, and this is the
|
|
only package allowed to appear at the top level: all other packages should
|
|
be inside |main| in some way.
|
|
|
|
The contents of the package are then one tab stop in from the declaration. Thus:
|
|
= (text as Inter)
|
|
package main _plain
|
|
...
|
|
package m1_RBLK1 _code
|
|
...
|
|
package m1_RBLK2 _code
|
|
...
|
|
=
|
|
Here, |main| contains two sub-packages, |m1_RBLK1| and |m1_RBLK2|, and
|
|
indentation is used to show which package a statement belongs to.
|
|
|
|
@ After the declaration line, a package definition continues with a set
|
|
of symbols definitions. In effect, this is the symbols table for the
|
|
package written out explicitly. Each definition is a |symbol| line, in
|
|
one of these three forms:
|
|
= (text as Inter)
|
|
symbol private TYPE NAME
|
|
symbol public TYPE NAME
|
|
symbol external TYPE NAME --> SYMBOL
|
|
=
|
|
For example,
|
|
= (text as Inter)
|
|
symbol public misc MEMORY_HEAP_SIZE
|
|
symbol external misc AllowInShowme --> /main/resources/template/AllowInShowme
|
|
=
|
|
|private| means that the meaning and existence of |NAME| are invisible
|
|
from outside the current package; |public| means that other packages are
|
|
allowed to refer to |NAME|; and |external| means that this package is
|
|
making just such a reference, and that |NAME| in this package is equivalent
|
|
to |SYMBOL|, defined elsewhere. It is possible that |SYMBOL| points only to
|
|
another symbol which is also |external|, so that we then have to follow
|
|
another link to find the original non-external definition. However, it is
|
|
a requirement that this process must eventually end. It would be illegal
|
|
to write
|
|
= (text as Inter)
|
|
package main _plain
|
|
package A _plain
|
|
symbol external misc S --> /main/B/T
|
|
package B _plain
|
|
symbol external misc T --> /main/B/S
|
|
=
|
|
The symbol |TYPE| must be one of four possibilities:
|
|
(a) |label|, used to mark execution positions in code packages;
|
|
(b) |package|, meaning that this is the name of a package;
|
|
(c) |packagetype|, meaning that this is a package type;
|
|
(d) |misc|, meaning "anything else" -- most symbols have this type.
|
|
|
|
The run of |symbol| declarations at the top of a module can become quite
|
|
long, since it has to give a complete description of all symbols used inside
|
|
the module, whether they're defined internally or externally. As a
|
|
convenience for people writing test cases by hand, it's in fact optional
|
|
to predeclare a symbol in textual inter provided that this symbol is
|
|
declared earlier in the file than its first use. However, when Inter
|
|
writes out a textual inter file, it always writes the symbols table out
|
|
in full, and never exercises this option.
|
|
|
|
Convention. A conspicuous feature of inter code generated by Inform is that
|
|
many symbols have the form |P_Name|, where |P| is some prefix letter showing
|
|
what sort of thing is referred to: for example, symbols for kinds all begin
|
|
with the prefix |K| (|K_number|, |K_text|, and so on), while variables
|
|
begin with |V|, instances with |I|, properties with |P|, and so on. This
|
|
is all simply a convention used by Inform for clarity and to reduce the
|
|
risk of accidental name clashes; it is not required by inter.
|
|
|
|
@ Where a local symbol is being equated with an external one, the |SYMBOL|
|
|
given is a sort of URL showing the package to look inside. Thus
|
|
= (text as Inter)
|
|
/main/resources/template/AllowInShowme
|
|
=
|
|
means "the symbol |AllowInShowme| in package |template| inside package
|
|
|resources| inside package |main|".
|
|
|
|
@ Optionally, a |private| or |public| symbol can also specify a name it
|
|
wishes to be given when the Inter is translated into some other language
|
|
(i.e., Inform 6 or similar). This is written like so:
|
|
= (text as Inter)
|
|
symbol private TYPE NAME `TRANSLATION`
|
|
=
|
|
So, for example,
|
|
= (text as Inter)
|
|
symbol public misc launcher `launcher_U32`
|
|
=
|
|
Symbols tabulated as |external| cannot be marked in this way, but of course
|
|
the original definition (to which the external link eventually leads) can be.
|
|
For example,
|
|
= (text as Inter)
|
|
package main _plain
|
|
package A _plain
|
|
symbol external misc S --> /main/B/T
|
|
package B _plain
|
|
symbol public misc T `FancyName`
|
|
=
|
|
would result in the names |S| and |T| both being compiled to the name
|
|
|FancyName| in the final code.
|
|
|
|
Convention. Inform mostly makes use of this feature of inter late in code
|
|
generation, essentially to avoid namespace clashes in the final output code,
|
|
but it also needs to use it to implement low-level features of the Inform
|
|
language such as:
|
|
|
|
>> The marked for listing property translates into I6 as "workflag".
|
|
|
|
@h Symbol annotations.
|
|
A useful feature of inter is that short-term or inessential metadata can
|
|
be attached to symbols; inter is flexible abput what this data might mean.
|
|
These annotations can also be represented in text form, which is useful
|
|
for looking at the output from different code-generation stages.
|
|
|
|
Annotations are written on the line where the symbol is created, not where
|
|
it is declared in the symbols table. For example, here is a creation of
|
|
a symbol for a constant:
|
|
= (text as Inter)
|
|
constant WORD_NEXTTOHIGHBIT K_typeless_int = 0x4000
|
|
=
|
|
And here it is with an annotation:
|
|
= (text as Inter)
|
|
constant WORD_NEXTTOHIGHBIT K_typeless_int = 0x4000 __hex
|
|
=
|
|
The annotation, |__hex|, simply means that the natural way to print the
|
|
value of this constant would be hexadecimal; it doesn't change the meaning
|
|
of the program, and this is typical of annotations.
|
|
|
|
All annotations begin with a double underscore, and some can take a number
|
|
or text literal:
|
|
= (text as Inter)
|
|
__binary
|
|
__table_array=1
|
|
__name="matching key"
|
|
=
|
|
There is no built-in set of annotations, and their use does not need to be
|
|
predeclared anywhere: simply writing
|
|
= (text as Inter)
|
|
constant MY_CONSTANT K_typeless_int = 27 __plugh
|
|
=
|
|
would create the annotation |__plugh| as a possibility, if it didn't already
|
|
exist. However, Inform has a conventional set of annotations which it uses
|
|
for symbols with various meanings, and that set will be covered later.
|
|
|
|
@h Splats.
|
|
The special statement |splat "TEXT"| or |splat ANNOTATION "TEXT"| allows
|
|
raw Inform 6 code (or potentially raw code for any language) to be included
|
|
verbatim in inter. Splat is not a respectful term, and nor does it deserve
|
|
one. The annotation can be any of: |IFDEF_PLM|, |IFNDEF_PLM|, |IFNOT_PLM|,
|
|
|ENDIF_PLM|, |IFTRUE_PLM|, |CONSTANT_PLM|, |ARRAY_PLM|, |GLOBAL_PLM|,
|
|
|STUB_PLM|, |ROUTINE_PLM|, |ATTRIBUTE_PLM|, |PROPERTY_PLM|, |VERB_PLM|,
|
|
|FAKEACTION_PLM|, |OBJECT_PLM|, |DEFAULT_PLM|, |MYSTERY_PLM|.
|
|
|
|
Convention. Inform creates no splats, except as needed to convert
|
|
Inform 6 template code into inter, in the code-generator.
|