§1. This section simoly sets up the module in ways expected by foundation, and
+contains no code of interest. The following constant exists only in tools
+which use this module:
+
+
+
defineASSERTIONS_MODULETRUE
+
+
§2. Like all modules, this one must define a start and end function:
+
To keep track of the current object and subject of discussion.
+
+
§1. Inform is deliberately minimal when allowing the use of pronouns which carry
+meanings from one sentence to another. It is unclear exactly how natural
+language does this, and while some theories are more persuasive than others,
+all seem vulnerable to odd cases that they get "wrong". It's therefore
+hard to program a computer to understand "it" so that human users are
+happy with the result.
+
+
+
But we try, just a little, by keeping track of the subject and object
+under discussion. Even this is tricky. Consider:
+
+
+
+
The Pavilion is a room. East is the Cricket Square.
+
+
+
East of where? Clearly of the current subject, the Pavilion (not
+the room kind). On the other hand,
+
+
+
+
On the desk is a pencil. It has description "2B."
+
+
+
"It" here is the pencil, not the desk. To disentangle such things,
+we keep track of two different running references: the current subject and
+the current object. English is an SVO language, so that in assertions of the
+form "X is Y", X is the subject and Y the object. But it will turn out to
+be more complicated than that, because we disregard all references which are
+not to tangible things and kinds.
+
§2. The routine Anaphora::new_discussion is called when we reach a
+heading or other barrier in the source text, to make clear that there has
+been a change of the topic discussed.
+
+
+
Anaphora::change_discussion_topic is called once at the end of
+processing each assertion during each pass.
+
+
+
Note that we are careful to avoid changing the subject with sentences like:
+
+
+
+
East is the Central Plaza.
+
+
+
where this does not have the subject "east", but has instead an implicit
+subject carried over from previous sentences.
+
§3. The slight asymmetry in what follows is partly pragmatic, partly the result
+of subject-verb inversion ("in the bag is the ball" not "the ball is in the
+bag"). We extract a subject from a relationship node on the left, but not on
+the right, and we don't extract an object from one. Consider:
+
+
+
+
A billiards table is in the Gazebo. On it is a trophy cup.
+
+
+
What does "it" mean, and why? A human reader goes for the billiards table at
+once, because it seems more likely as a supporter than the Gazebo, but that's
+not how Inform gets the same answer. It all hangs on "billiards table" being
+the object of the first sentence, not the Gazebo; if we descended the RHS,
+which is RELATIONSHIP_NT -> PROPER_NOUN_NT pointing to the Gazebo, that's the
+conclusion we would have reached.
+
In Inform even verbs are created with natural language sentences, but this process has to start somewhere.
+
+
§1. "Booting" is the traditional computing term for "pulling yourself up by
+your own bootstraps": when a computer switches on it has no program to run,
+but to load in a program would require a program. The circularity is broken
+by having a minimal "boot" program wired into the hardware.
+
+
+
So too with Inform. The opening sentence of the Basic Inform extension, always
+the first sentence read in, is:
+
+
+
+
The verb to mean means the meaning relation.
+
+
+
(See Preamble (in basic_inform).) But this is circular: if we have not yet
+defined "to mean", how can we recognise "means" as the verb, or know what it
+means? We break this circularity by hard-wiring it, as follows.
+
§1.1. "Regular" meanings involve relations between two values: for example, carrying
+and numerical greater-than are both regular meanings, of the verbs "to carry"
+and > respectively.
+
+
+
"Special" meanings are different. The noun phrases need not represent values,
+there need not be two of them, and the meaning can have internal significance
+to the Inform compiler. For example,
+
+
+
+
Black king chess piece translates into Unicode as 9818.
+
+
+
is one of three special meanings of "to translate into". The linguistics
+module decides which if any is meant in a given case by calling the "special
+meaning functions" to see if wants to accept the sentence in question.
+
+
+
§1.2. When the linguistics module looks for a primary verb, it may find
+multiple candidates: consider "fruit flies like a banana", where "flies" and
+"like" are both candidate verbs. We decide by (a) ranking verbs in tiers by
+"priority number", and failing that (b) choosing the leftmost. Priority 0
+verbs are never considered, but otherwise low priority numbers beat higher.
+(See Verb Usages (in linguistics).)
+
+
+
Inform adopts the following convention for the priority of regular meanings:
+
+
+
(a) Regular "to have" has priority 1.
+
(b) Regular "to be" has priority 2.
+
(c) Otherwise, regular verbs in the language of the source text have priority 4.
+
(d) And regular verbs in some other language have priority 5.
+
+
As can be seen below, special meanings have priorities between 1 and 4. Note
+that "to mean" itself has both a special meaning (priority 3) and a regular
+meaning (priority 4). This is why the sentence:
+
+
+
+
The verb to mean means the meaning relation.
+
+
+
is not circular. It uses the special meaning of "mean" (priority 3) to create
+the regular one (4).
+
+
+
§1.3. So, then, here are the core module's special meanings. Just like regular
+meanings, which have names like "containment relation", special meanings have
+names. But as these names are only used in early boot sentences in the
+basic_inform extension, the user never sees them. They are required to
+be a single word, and are hyphenated.
+
§1.4. We need the English infinitive forms of two verbs to get started. In each
+case we use the inflections module to conjugate them — i.e., to generate
+all the other forms, "is", "did not mean" and so on — and then hand them to
+the linguistics module to add to its stock of known verbs. (It starts out
+with none, so these are initially the only two.)
+
+
+
We need to create "to be" first because (a) it is the only copular verb in
+Inform, and there is no way to create a copular verb using Inform source text;
+and (b) because this enables us to conjugate forms of "mean" such as "X is
+meant by" — note the use of "is".
+
§1.6. Those two verbs are now part of our linguistic stock, but do not yet mean
+anything. We need to give the build-in "verb-means" meaning to "to mean":
+
+
+
Give meaning to mean1.6 =
+
+
+
+if ((to_mean == NULL) || (meaning_of_mean == NULL)) internal_error("could not make to mean");
+Verbs::add_form(to_mean, NULL, NULL, VerbMeanings::special(meaning_of_mean), SVO_FS_BIT);
+
§1. Traversing for primary verbs. The story so far: the supervisor module has arranged for the source
+text to be read in by words and has made a rudimentary parse tree for
+it using syntax. Certain "structural" sentences, such as headings, have
+been taken care of, and turned into nodes with types like HEADING_NT.
+
+
+
But the assertions we want to read — such as "The Mona Lisa is in the Louvre",
+or "The plural of major general is majors general" — are all simply
+SENTENCE_NT nodes with no children. The following traverse begins Inform's
+compilation process in earnest: for each such SENTENCE_NT node, it asks
+the linguistics module to identify a primary verb, noun phrases and so
+on, placing them in a subtree.
+
+
+
§2. Textual sentences. "Textual" sentences are not really sentences at all, and are just double-quoted
+text used in isolation — Inform sometimes recognises these as being implicit
+property values, as for the description of a room just created. These sentences
+are necessarily exempt from having a primary verb.
+
§3. Classifying a single sentence. Every SENTENCE_NT node, however it is constructed, therefore ends up here,
+and we ask the linguistics module to "diagram" it.
+
+StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_TwoLikelihoods),
+"this sentence seems to have a likelihood qualification on both "
+"sides of the verb",
+"which is not allowed. 'The black door certainly is usually open' "
+"might possibly be grammatical English in some idioms, but Inform "
+"doesn't like a sentence in this shape because the 'certainly' "
+"on one side of the verb and the 'usually' on the other are "
+"rival indications of certainty.");
+
§3.2. Only special-meaning sentences are allowed in Options files, and not all
+of those.
+
+
+
enumALLOW_IN_OPTIONS_FILE_SMFT
+
+
§3.3. Check that this is allowed, if it occurs in the Options file3.3 =
+
+
+
+if (Wordings::within(Node::get_text(p), options_file_wording)) {
+special_meaning_holder *sm = Node::get_special_meaning(p->down);
+if ((sm == NULL) ||
+ (SpecialMeanings::call(sm, ALLOW_IN_OPTIONS_FILE_SMFT, NULL, NULL) == FALSE)) {
+StandardProblems::unlocated_problem(Task::syntax_tree(),
+_p_(BelievedImpossible), not convenient to test automatically, anyway
+"The options file placed in this installation of Inform's folder "
+"is incorrect, making use of a sentence form which isn't allowed "
+"in that situation. The options file is only allowed to contain "
+"use options, Test ... with..., and Release along with... "
+"instructions.");
+return;
+ }
+ }
+
§3.4. The linguistics module no longer makes sentence diagrams with this defect,
+so the following problem ought now to be impossible to generate. But I'm leaving
+the test here in case of future changes.
+
+
+
Issue problem message if either subject or object contains mismatched brackets3.4 =
+
+
+
+if ((VP_PN->next) && (VP_PN->next->next)) {
+if ((Wordings::mismatched_brackets(Node::get_text(VP_PN->next))) ||
+ (Wordings::mismatched_brackets(Node::get_text(VP_PN->next->next)))) {
+Problems::quote_source(1, current_sentence);
+Problems::quote_wording(2,
+Wordings::one_word(Wordings::last_wn(Node::get_text(VP_PN->next)) + 1));
+Problems::quote_wording(3, Node::get_text(VP_PN->next));
+Problems::quote_wording(4, Node::get_text(VP_PN->next->next));
+StandardProblems::handmade_problem(Task::syntax_tree(), _p_(BelievedImpossible));
+if (Wordings::nonempty(Node::get_text(VP_PN->next->next)))
+Problems::issue_problem_segment(
+"I must be misreading the sentence %1. The verb "
+"looks to me like '%2', but then the brackets don't "
+"match in what I have left: '%3' and '%4'.");
+else
+Problems::issue_problem_segment(
+"I must be misreading the sentence %1. The verb "
+"looks to me like '%2', but then the brackets don't "
+"match in what I have left: '%3'.");
+Problems::issue_problem_end();
+return;
+ }
+ }
+
§3.5. This is a pragmatic sort of problem message. A priori, assertion sentences
+like this might be okay, but in practice they cannot be useful and are far
+more likely to occur as a result of something like:
+
+
+
+
"This is a dining room" East is the Ballroom.
+
+
+
where the lack of a closing full stop in the quoted text means that linguistics
+read this as one single sentence, equating "This is a dining room" East
+with the Ballroom.
+
+
+
Special-meaning sentences are exempt; this is needed because subject phrases
+for "Understand ... as ..." are indeed sometimes multiword clauses the first
+word of which is quoted.
+
+
+
Issue problem message if subject starts with double-quoted literal text3.5 =
+
+
+
+special_meaning_holder *sm = Node::get_special_meaning(VP_PN);
+if ((sm == NULL)
+ && (Wordings::length(Node::get_text(VP_PN->next)) > 1)
+ && (Vocabulary::test_flags(
+Wordings::first_wn(Node::get_text(VP_PN->next)), TEXT_MC+TEXTWITHSUBS_MC))) {
+StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_TextNotClosing),
+"it looks as if perhaps you did not intend that to read as a "
+"single sentence",
+"and possibly the text in quotes was supposed to stand as "
+"as a sentence on its own? (The convention is that if text "
+"ends in a full stop, exclamation or question mark, perhaps "
+"with a close bracket or quotation mark involved as well, then "
+"that punctuation mark also closes the sentence to which the "
+"text belongs: but otherwise the words following the quoted "
+"text are considered part of the same sentence.)");
+return;
+ }
+
§3.6. Here py is a CALLED_NT subtree for "an A called B", which we relabel
+as a PROPERTYCALLED_NT subtree and hang beneath an ALLOWED_NT node;
+or else it's a property or list of properties, as in "carrying capacity 7".
+
+
+
Diagram property callings3.6 =
+
+
+
+parse_node *px = VP_PN->next;
+parse_node *py = VP_PN->next->next->down;
+if (Node::get_type(py) == CALLED_NT) {
+if (Wordings::match(Node::get_text(py->down->next), Node::get_text(py->down))) {
+StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_SuperfluousCalled),
+"'called' should be used only when the name is different from the kind",
+"so this sentence should be simplified. For example, 'A door has a "
+"colour called colour' should be written more simply as 'A door has "
+"a colour'; but 'called' can be used for something like 'A door has "
+"a number called the street number'.");
+return;
+ }
+Node::set_type(py, PROPERTYCALLED_NT);
+if (Node::get_type(py->down) == AND_NT) {
+internal_error("Og yeah?");
+intL = Node::left_edge_of(py->down),
+R = Node::right_edge_of(py->down);
+<np-articled>(Wordings::new(L, R));
+parse_node *pn = <<rp>>;
+pn->next = py->down->next;
+py->down = pn;
+LOG("Thus $T", py);
+ }
+px->next = Node::new(ALLOWED_NT);
+px->next->down = py;
+intprohibited = <prohibited-property-owners>(Node::get_text(px));
+if (!prohibited) {
+<np-articled-list>(Node::get_text(py->down->next));
+py->down->next = <<rp>>;
+ }
+ } else {
+Node::set_type(py, PROPERTY_LIST_NT);
+ }
+
§4. From the earliest beta-testing, the problem message for "I can't find a verb"
+split into cases. Inform is quite sensitive to punctuation errors as between
+comma, paragraph break and semicolon, and this is where that sensitivity begins
+to bite. The grammar below is just a set of heuristics, really: once we enter
+this, a problem message of some kind will certainly result.
+
+StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_RuleWithoutColon),
+"I can't find a verb that I know how to deal with, so can't do anything "
+"with this sentence. It looks as if it might be a rule definition",
+"but if so then it is lacking the necessary colon (or comma). "
+"The punctuation style for rules is 'Rule conditions: do this; "
+"do that; do some more.' Perhaps you used a full stop instead "
+"of the colon?");
+
+StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_IfOutsidePhrase),
+"I can't find a verb that I know how to deal with. This looks like an 'if' "
+"phrase which has slipped its moorings",
+"so I am ignoring it. ('If' phrases, like all other such "
+"instructions, belong inside definitions of rules or phrases - "
+"not as sentences which have no context. Maybe a full stop or a "
+"skipped line was accidentally used instead of semicolon, so that you "
+"inadvertently ended the last rule early?)");
+
+Problems::quote_source(1, current_sentence);
+StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_NoSuchVerbComma));
+Problems::issue_problem_segment(
+"In the sentence %1, I can't find a verb that I know how to deal with. "
+"(I notice there's a comma here, which is sometimes used to abbreviate "
+"rules which would normally be written with a colon - for instance, "
+"'Before taking: say \"You draw breath.\"' can be abbreviated to 'Before "
+"taking, say...' - but that's only allowed for Before, Instead and "
+"After rules. I mention all this in case you meant this sentence "
+"as a rule in some rulebook, but used a comma where there should "
+"have been a colon ':'?)");
+Problems::issue_problem_end();
+
+Problems::quote_source(1, current_sentence);
+StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_NoSuchVerb));
+Problems::issue_problem_segment(
+"In the sentence %1, I can't find a verb that I know how to deal with.");
+Problems::issue_problem_end();
+
+if (Annotations::read_int(current_sentence, verb_problem_issued_ANNOT) == FALSE) {
+Annotations::write_int(current_sentence, verb_problem_issued_ANNOT, TRUE);
+StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_NonPresentTense),
+"assertions about the initial state of play must be given in the "
+"present tense",
+"so 'The cat is in the basket' is fine but not 'The cat has been in "
+"the basket'. Time is presumed to start only when the game begins, so "
+"there is no anterior state which we can speak of.");
+ }
+
§5. The following is needed to handle something like "colour of the box",
+where "colour" is a property name. We must be careful, though, to avoid
+confusion with variable declarations:
+
+
+
+
The interesting var is a description of numbers that varies.
+
+
+
which would otherwise be misread as an attempt to set the "description"
+property of something.
+
To manage the overall process of traversing the parse tree for top-level declarations and assertion sentences.
+
+
§1. The first thing Inform does when compiling source text is to make three
+passes through its top-level definitions: a "pre-pass", in which names of
+things like tables and equations are discovered, and assertion sentences
+are diagrammed; "pass 1", when instance, kinds, properties and so on are
+created; and "pass 2", when property values and relationships are found.
+
§2.2. Here's a tricky timing problem, or rather, here's the fix for it. Assemblies
+are made when the kinds of objects are set, and they're made by inserting
+appropriate sentences. For instance, given the generalisation:
+
+
+
+
Every room contains a vehicle.
+
+
+
we would insert the following sentence into the tree:
+
+
+
+
Ballroom West contains a vehicle.
+
+
+
as soon as we discover that Ballroom West is a room. That works fine if we
+discover this fact during traverses 1 or 2, but sometimes the room-ness of
+a room cannot be established until the world model is constructed. So we
+call the model-maker right now, and prolong pass 2 artificially to pick up
+any additional sentences generated.
+
+
+
Extend the pass to sentences needed when implicit kinds are set2.2 =
+
+voidMajorNodes::visit(parse_node *p, parse_node **last) {
+global_pass_state.assembly_position = current_sentence;
+compilation_unit *cm = CompilationUnits::current();
+CompilationUnits::set_current(p);
+ *last = p;
+Deal with an individual major node3.1;
+CompilationUnits::set_current_to(cm);
+}
+
+
§3.1. Headings cause us to begin a fresh topic of discussion, on a fresh piece of
+paper, as it were: this wipes out any meanings of pronouns like "it" making
+anaphoric references to previous sentences. In other respects, headings are for
+organisation, and are not directly functional in themselves.
+
+
+
Deal with an individual major node3.1 =
+
+
+
+if ((SyntaxTree::is_trace_set(Task::syntax_tree())) && (Node::get_type(p) != TRACE_NT))
+LOG("\n[%W]\n", Node::get_text(p));
+
+switch (Node::get_type(p)) {
+caseROOT_NT:break;
+
+caseHEADING_NT:Anaphora::new_discussion(); break;
+caseBEGINHERE_NT:Anaphora::new_discussion();
+global_pass_state.near_start_of_extension = 1; break;
+caseENDHERE_NT:Anaphora::new_discussion();
+global_pass_state.near_start_of_extension = 0; break;
+
+caseRULE_NT:Pass through a RULE node3.1.1; break;
+caseSENTENCE_NT:Pass through a SENTENCE node3.1.2; break;
+caseTRACE_NT:Pass through a TRACE node3.1.5; break;
+
+caseTABLE_NT:if (global_pass_state.pass == 0) Tables::create_table(p);
+break;
+caseEQUATION_NT:if (global_pass_state.pass == 0) Equations::new_at(p, FALSE);
+break;
+caseINFORM6CODE_NT:
+if (global_pass_state.pass == 2) Config::Inclusions::inform_6_inclusion(p);
+break;
+caseBIBLIOGRAPHIC_NT:
+ #ifdefIF_MODULE
+if (global_pass_state.pass == 2) PL::Bibliographic::bibliographic_data(p);
+ #endif
+break;
+
+caseINVOCATION_LIST_NT:break; for error recovery; shouldn't be here otherwise
+
+default:
+LOG("$T\n", p);
+internal_error("passed through major node of unexpected type");
+ }
+
§3.1.1. This is a little convoluted. The linguistics module turns sentences in
+rule form into a RULE_NT node followed by subsequent INVOCATION_NT nodes,
+and the first call here makes them into a neat subtree. After that, we look
+out for adjectives defined by phrases, and for phrases with names, since
+both will affect how we read sentences in passes 1 and 2.
+
§3.1.2. SENTENCE_NT nodes are by far the most varied and difficult. In the pre-pass,
+we call Classifying::sentence to have them diagrammed, which determines
+whether they have special or regular meanings.
+
§3.1.2.1. Special meanings are handled just by calling the relevant SMF functions
+with one of the following task codes. They don't get the benefit of
+"refinement" (see below) unless they arrange for it themselves.
+
§3.1.2.3. Regular meanings are more subtle: on pass 1, we "refine" them, which means
+identifying unparsed noun phrases. Refiner::refine_coupling
+returns TRUE if it succeeds in this.
+
+
+
After that, there are two cases: existential sentences (such as "there are
+two cases") and all others (such as "regular meaning are more subtle").
+
§3.1.4. A few "invention" sentences only come along later than the pre-pass, which
+means they miss out on being classified at that time. When that happens, the
+syntax module signals us by calling this function:
+
§3.1.5. TRACE_NT nodes result from asterisked sentences; this is a debugging feature of
+Inform. An asterisk on its own toggles logging of work on sentences. An asterisk
+followed by double-quoted text is a note for the telemetry file.
+
+
+
Pass through a TRACE node3.1.5 =
+
+
+
+if (Wordings::length(Node::get_text(p)) > 1) {
+inttr = telemetry_recording;
+telemetry_recording = TRUE;
+Telemetry::write_to_telemetry_file(
+Lexer::word_text(Wordings::last_wn(Node::get_text(p))));
+telemetry_recording = FALSE;
+StandardProblems::sentence_problem(Task::syntax_tree(),
+_p_(PM_TelemetryAccepted),
+"that's a message for the Author, not me",
+"so I'll note it down in the Telemetry file (if you're keeping one.)");
+telemetry_recording = tr;
+ } else {
+SyntaxTree::toggle_trace(Task::syntax_tree());
+text_stream *pass_name = NULL;
+switch (global_pass_state.pass) {
+case0: pass_name = I"Pre-Pass"; break;
+case1: pass_name = I"Pass 1"; break;
+case2: pass_name = I"Pass 2"; break;
+ }
+Log::tracing_on(SyntaxTree::is_trace_set(Task::syntax_tree()), pass_name);
+ }
+
§1. Use options in Inform are akin to #pragma directives for the C family of
+compilers: they are written in the source code of the program being compiled,
+but they're not really part of that program, and are instead instructions to
+the compiler to do something in a different way.1
+
+
+
Use options have natural-language names, and are created with sentences like:
+
+
+
+
Use American dialect translates as (- Constant DIALECT_US; -).
+
+
+
This syntax is now rather odd-looking, but most users never need it: it's used
+mainly in the Basic Inform extension to create the standard set of use options.
+Note the Inform 6 notation used for the Inter code between the (- and -)
+brackets.
+
+
+
1 The design of use options is arguably more muddled, because they do not all
+correspond to compiler features: some affect the behaviour of Inter kits, and
+some can be user-defined entirely.
+ ↩
+
§2. A "... translates as ..." sentence has this special meaning if its SP and
+OP match the following:
+
+StandardProblems::sentence_problem(Task::syntax_tree(),
+_p_(PM_UseTranslatesNotI6),
+"that translates into something which isn't a simple Inter inclusion",
+"placed in '(-' and '-)' markers.");
+ ==> { FALSE, - };
+
+intNewUseOptions::use_translates_as_SMF(inttask, parse_node *V, wording *NPs) {
+wordingSW = (NPs)?(NPs[0]):EMPTY_WORDING;
+wordingOW = (NPs)?(NPs[1]):EMPTY_WORDING;
+switch (task) { "Use American dialect means ..."
+caseACCEPT_SMFT:
+if ((<use-translates-as-sentence-object>(OW)) &&
+ (<use-translates-as-sentence-subject>(SW))) {
+V->next = <<rp>>;
+<np-unparsed>(OW);
+V->next->next = <<rp>>;
+returnTRUE;
+ }
+break;
+casePASS_1_SMFT:
+Create a new use option3.2;
+break;
+ }
+returnFALSE;
+}
+
+
§3.1. Use options correspond to instances of the following:
+
+
+
+typedefstructuse_option {
+structwordingname; word range where name is stored
+structwordingexpansion; definition as given in source
+structparse_node *where_used; where the option is taken in the source
+intoption_used; set if this option has been taken
+intsource_file_scoped; scope is the current source file only?
+intminimum_setting_value; for those which are numeric
+intnotable_option_code; or negative if not notable
+CLASS_DEFINITION
+} use_option;
+
+
The structure use_option is accessed in 3/dbtr, 3/rpr, 4/ass, 4/pk, 6/tc, 6/tbl and here.
§7. We can also meddle with the I6 memory settings which will be used to finish
+compiling the story file. We need this because we have no practical way to
+predict when our code will break I6's limits: the only reasonable way it can
+work is for the user to hit the limit occasionally, and then raise that limit
+by hand with a sentence in the source text.
+
+
+
+typedefstructi6_memory_setting {
+structtext_stream *ICL_identifier; see the DM4 for the I6 memory setting names
+intnumber; e.g., 50000 means "at least 50,000"
+CLASS_DEFINITION
+} i6_memory_setting;
+
+
The structure i6_memory_setting is private to this section.
Special sentences for setting exotic plural forms of nouns.
+
+
§1. Sentences like "the plural of cherub is cherubim" are hardly needed now,
+because the inflections module now contains a full implementation of
+Conway's algorithm. Still, we keep the syntax around, and it may one day be
+useful again for languages other than English.
+
§2. Note that we are saved later grief by not allowing a plural form which
+would be illegal as a new noun: allowing "The plural of thing is ," would not
+end well.
+
§2.1. In general names of things which we need plurals for cannot contain quoted
+text anyway, so the following problem messages are not too gratuitous.
+
+LOOP_THROUGH_WORDING(i, S)
+if (Vocabulary::test_flags(i, TEXT_MC + TEXTWITHSUBS_MC)) {
+StandardProblems::sentence_problem(Task::syntax_tree(),
+_p_(PM_PluralOfQuoted),
+"declares a plural for a phrase containing quoted text",
+"which is forbidden. Sentences like this are supposed to "
+"declare plurals without quotation marks: for instance, "
+"'The plural of attorney general is attorneys general.'");
+returnTRUE;
+ }
+LOOP_THROUGH_WORDING(i, P)
+if (Vocabulary::test_flags(i, TEXT_MC + TEXTWITHSUBS_MC)) {
+StandardProblems::sentence_problem(Task::syntax_tree(),
+_p_(PM_PluralIsQuoted),
+"declares a plural for a phrase using quoted text",
+"which is forbidden. Sentences like this are supposed to "
+"declare plurals without quotation marks: for instance, "
+"'The plural of procurator fiscal is procurators fiscal.'");
+returnTRUE;
+ }
+
§3. Translation into Unicode. The following handles sentences like:
+
+
+
+
leftwards harpoon with barb upwards translates into Unicode as 8636.
+
+
+
The subject "leftwards harpoon with barb upwards" is parsed against the
+Unicode character names known already to make sure that this new translation
+doesn't disagree with an existing one (that is, doesn't translate to a
+different code number).
+
+
+
The sentence "X translates into Y as Z" has this sense provided Y matches:
+
§5. And this parses the noun phrases of such sentences. Note that the numeric
+values has to be given in decimal — I was tempted to allow hexadecimal here,
+but life's too short. Unicode translation sentences are really only
+technicalities needed by the built-in extensions, and those are mechanically
+generated anyway; Inform authors never type them.
+
+StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_UnicodeNonLiteral),
+"a Unicode character name must be translated into a literal decimal "
+"number written out in digits",
+"which this seems not to be.");
+returnFALSE;
+
§6. Translation into Inter. The sentence "X translates into Y as Z" has this sense provided Y matches the
+following. Before the coming of Inter code, the only conceivable compilation
+target was Inform 6, but these now set Inter identifiers, so really the first
+wording is to be preferred.
+
+intTranslations::translates_into_Inter_as_SMF(inttask, parse_node *V, wording *NPs) {
+wordingSW = (NPs)?(NPs[0]):EMPTY_WORDING;
+wordingOW = (NPs)?(NPs[1]):EMPTY_WORDING;
+wordingO2W = (NPs)?(NPs[2]):EMPTY_WORDING;
+switch (task) { "The taking inventory action translates into Inter as "Inv""
+caseACCEPT_SMFT:
+if (<translation-target-i6>(O2W)) {
+<np-articled>(SW);
+V->next = <<rp>>;
+<np-articled>(OW);
+V->next->next = <<rp>>;
+returnTRUE;
+ }
+break;
+casePASS_1_SMFT:
+casePASS_2_SMFT:
+Act on the Inter translation7.2;
+break;
+caseINTER_NAMING_SMFT:
+Act on late naming7.5;
+break;
+ }
+returnFALSE;
+}
+
+
§8. Translations can be made in a number of contexts:
+
+
+
defineINVALID_I6TR -1
+definePROPERTY_I6TR0 "The open property translates into I6 as "open"."
+defineNOUN_I6TR1 "The north object translates into I6 as "n_obj"."
+defineRULE_I6TR2 "The baffling rule translates into I6 as "BAFFLING_R"."
+defineVARIABLE_I6TR3 "The sludge count variable translates into I6 as "sldgc".
+defineACTION_I6TR4 "The taking action translates into I6 as "Take".
+defineGRAMMAR_TOKEN_I6TR5 "The grammar token "[whatever]" translates into I6 as "WHATEVER".
+
+StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_TranslatedUnknownCategory),
+"that isn't one of the things which can be translated to I6",
+"and should be '... variable', '... property', '... object', "
+"'... kind', '... rule', or '... action'. For instance, 'The yourself "
+"object translates into I6 as \"selfobj\".'");
+ ==> { INVALID_I6TR, - };
+
§7.1. The object noun phrase is usually just an I6 identifier in quotation marks,
+but it's also possible to list literal texts (for the benefit of rules).
+Following the optional "with" is an articled list, each entry of which
+will be required to pass <extra-response>.
+
§7.2.1. Ensure that we are translating to a quoted I6 identifier7.2.1 =
+
+
+
+intvalid = TRUE;
+if (<translates-into-i6-sentence-object>(Node::get_text(p2)) == FALSE) valid = FALSE;
+elseresponses_list = <<rp>>;
+if (valid) Dequote it and see if it's valid7.2.1.1;
+if (valid == FALSE) {
+StandardProblems::sentence_problem(Task::syntax_tree(),
+_p_(PM_TranslatedToNonIdentifier),
+"Inform 7 constructions can only translate into quoted I6 identifiers",
+"which must be strings of 1 to 31 characters drawn from 1, 2, ..., 9, "
+"a or A, b or B, ..., z or Z, or underscore '_', except that the "
+"first character is not allowed to be a digit.");
+returnFALSE;
+ }
+
§7.2.2. In some cases, we act on pass 1, but in others pass 2, and in the case of
+NOUN_I6TR, later even than that. There are messy timing issues here.
+
+
+
Take action in pass 1 or 2 where possible7.2.2 =
+
+voidTranslations::plus_responses(parse_node *p, rule *R) {
+if (Node::get_type(p) == AND_NT) {
+Translations::plus_responses(p->down, R);
+Translations::plus_responses(p->down->next, R);
+ } else {
+if (<extra-response>(Node::get_text(p))) {
+intcode = <<r>>;
+response_message *resp = Strings::response_cue(NULL, R,
+code, Node::get_text(p), NULL, TRUE);
+Rules::now_rule_defines_response(R, code, resp);
+ } else {
+StandardProblems::sentence_problem(Task::syntax_tree(),
+_p_(PM_I6ResponsesAwry),
+"additional information about I6 translation of a rule can "
+"only take the form of a list of responses",
+"each quoted and followed by a bracketed letter.");
+ }
+ }
+}
+
+
§7.5. As noted above, NOUN_I6TR renamings happen much later on.
+
+
+
Act on late naming7.5 =
+
+
+
+wordingSP = Node::get_text(V->next);
+wordingOP = Node::get_text(V->next->next);
+intcategory = Annotations::read_int(V, category_of_I6_translation_ANNOT);
+switch(category) {
+caseNOUN_I6TR: {
+wordingW = Wordings::trim_last_word(SP);
+parse_node *res = Lexicon::retrieve(NOUN_MC, W);
+if (res) {
+noun_usage *nu = Nouns::disambiguate(res, FALSE);
+noun *nt = (nu)?(nu->noun_used):NULL;
+if (nt) {
+TEMPORARY_TEXT(i6r)
+WRITE_TO(i6r, "%N", Wordings::first_wn(OP));
+UseNouns::noun_set_I6_representation(nt, i6r);
+DISCARD_TEXT(i6r)
+ }
+ } else {
+StandardProblems::sentence_problem(Task::syntax_tree(),
+_p_(PM_BadObjectTranslation),
+"there is no such object or kind of object",
+"so its name will never be translated into an Inter "
+"identifier in any event.");
+ }
+break;
+ }
+ }
+
§1. The Use sentence. Note that any sentence beginning with the word "Use" is accepted here, which
+is a very wide net: unlike most special meaning sentences, there's no attempt
+to cut down the risk of false positives by screening the noun phrase.
+
§2.2.2. ICL, the "Inform 6 control language", is a set of a pragma-like settings for
+the I6 compiler. Of course, in the age in Inter, those might well be ignored,
+since the compiler next down the chain may no longer be I6.
+
+
+
See //runtime:Use Options at Run Time// for what happens to these.
+
+
+
Set a memory setting2.2.2 =
+
+
+
+intn = <<r>>, w1 = Wordings::first_wn(S);
+TEMPORARY_TEXT(icl_identifier)
+WRITE_TO(icl_identifier, "%+W", Wordings::one_word(w1));
+if (Str::len(icl_identifier) > 63) {
+StandardProblems::sentence_problem(Task::syntax_tree(),
+_p_(PM_BadICLIdentifier),
+"that is too long to be an ICL identifier",
+"so can't be the name of any I6 memory setting.");
+ }
+NewUseOptions::memory_setting(icl_identifier, n);
+DISCARD_TEXT(icl_identifier)
+
§2.2.3. Whereas thus is the standard use option syntax:
+
+
+
Set the option given in this word range2.2.3 =
+
+
+
+intmin_setting = <<r>>;
+wordingOW = GET_RW(<use-setting>, 1);
+use_option *uo = NewUseOptions::parse_uo(OW);
+if (uo) NewUseOptions::set(uo, min_setting,
+Lexer::file_of_origin(Wordings::first_wn(OW)));
+elseif (global_pass_state.pass > 1) {
+LOG("Used: %W\n", S);
+StandardProblems::sentence_problem(Task::syntax_tree(),
+_p_(PM_UnknownUseOption),
+"that isn't a 'Use' option known to me",
+"and needs to be one of the ones listed in the documentation.");
+ }
+
+
+
+
+
+
+
diff --git a/docs/assertions-module/P-wtmd.html b/docs/assertions-module/P-wtmd.html
index 2ee1c8ea3..ea7268bcf 100644
--- a/docs/assertions-module/P-wtmd.html
+++ b/docs/assertions-module/P-wtmd.html
@@ -88,7 +88,7 @@ For more, see §2. Assertions. Top-level declarations are dealt with thus:
-
● The tree is subdivided into //runtime: Compilation Units//. The project's own
+
● The tree is subdivided into Compilation Units (in runtime). The project's own
source text is one unit, as is each extension used.
● A minimal set of kinds, such as "number", verbs, such as "to mean", relations,
such as "meaning", and so on, is created. See in particular Booting Verbs (in assertions).
@@ -133,7 +133,7 @@ hat is indeed spatially on top of the can.
more Linux-aware students to drink.
↩
- Relations -
- What Inform internally calls "binary predicates", the user calls "relations". In this section, we parse definitions of new relations and create the resulting |binary_predicate| objects.
+
+ The Universal Relation -
+ To define the universal relation, which can apply and therefore subsumes all other relations.
In which the stream of words is broken up into sentences and built into a parse tree, recording primary verbs, noun phrases and some sub-clauses; and in which these sentences are collected under a hierarchy of headings, with material intended only for certain target virtual machines included or excluded as need be.
- Headings -
- To keep track of the hierarchy of headings and subheadings found in the source text.
-
-
-
- Rule Subtrees -
- To tidy up |INVOCATION_LIST_NT| nodes into a list of children under the relevant |RULE_NT| node, and so turn each rule definition into a single subtree.
-
-
-
-
-
- Chapter 7: Table Data
+ Chapter 6: Table Data
Inform's preferred data structure for small initialised databases.
Listed-In Relations -
To define the binary predicates corresponding to table columns, and which determine whether a given value is listed in that column.
§1. This section simoly sets up the module in ways expected by foundation, and
contains no code of interest. The following constant exists only in tools
which use this module:
@@ -272,7 +261,7 @@ or other text streams.
COMPILE_WRITER(extension_dictionary_entry *, ExtensionDictionary::log_entry)COMPILE_WRITER(parse_node *, Invocations::log_list)COMPILE_WRITER(parse_node *, Invocations::log)
-COMPILE_WRITER(heading *, Sentences::Headings::log)
+COMPILE_WRITER(heading *, IndexHeadings::log)COMPILE_WRITER(ph_type_data *, Phrases::TypeData::Textual::log)COMPILE_WRITER(inference *, World::Inferences::log)COMPILE_WRITER(i6_schema *, Calculus::Schemas::log)
@@ -307,7 +296,7 @@ or other text streams.
Relations::Universal::start();Relations::Explicit::start();EqualityDetails::start();
-Declare the tree annotations6.10;
+ParseTreeUsage::declare_annotations();}voidCoreModule::end(void) {}
@@ -349,7 +338,7 @@ we need to use the equivalent of traditional
-Writers::register_writer_I('B', &CoreModule::writer);
+Writers::register_writer_I('B', &CoreModule::writer);Writers::register_writer('I', &Instances::writer);Writers::register_writer('L', &LocalVariables::writer);
@@ -453,7 +442,7 @@ we need to use the equivalent of traditional REGISTER_WRITER('d', ExtensionDictionary::log_entry);REGISTER_WRITER('E', Invocations::log_list);REGISTER_WRITER('e', Invocations::log);
-REGISTER_WRITER('H', Sentences::Headings::log);
+REGISTER_WRITER('H', IndexHeadings::log);REGISTER_WRITER('h', Phrases::TypeData::Textual::log);REGISTER_WRITER('I', World::Inferences::log);REGISTER_WRITER('i', Calculus::Schemas::log);
@@ -470,7 +459,7 @@ we need to use the equivalent of traditional REGISTER_WRITER('z', Nouns::log);
voidCoreModule::writer(OUTPUT_STREAM, char *format_string, intwn) {
@@ -483,685 +472,67 @@ we need to use the equivalent of traditional }}
-
§6.8. This module uses syntax, and adds the following annotations to the syntax
-tree; though it's a little like itemising the baubles on a Christmas tree.
+
§8. Built-in relation names. These have to be defined somewhere, and it may as well be here.
-
enumaction_meaning_ANNOTaction_pattern: meaning in parse tree when used as noun
-enumpredicate_ANNOTunary_predicate: which adjective is asserted
-enumcategory_of_I6_translation_ANNOT int: what sort of "translates into I6" sentence this is
-enumclassified_ANNOTint: this sentence has been classified
-enumclears_pronouns_ANNOTint: this sentence erases the current value of "it"
-enumcolon_block_command_ANNOT int: this COMMAND uses the ":" not begin/end syntax
-enumcondition_tense_ANNOTtime_period: for specification nodes
-enumconstant_action_name_ANNOTaction_name: for constant values
-enumconstant_action_pattern_ANNOTaction_pattern: for constant values
-enumconstant_activity_ANNOTactivity: for constant values
-enumconstant_binary_predicate_ANNOTbinary_predicate: for constant values
-enumconstant_constant_phrase_ANNOTconstant_phrase: for constant values
-enumconstant_enumeration_ANNOTint: which one from an enumerated kind
-enumconstant_equation_ANNOTequation: for constant values
-enumconstant_grammar_verb_ANNOTgrammar_verb: for constant values
-enumconstant_instance_ANNOTinstance: for constant values
-enumconstant_local_variable_ANNOTlocal_variable: for constant values
-enumconstant_named_action_pattern_ANNOTnamed_action_pattern: for constant values
-enumconstant_named_rulebook_outcome_ANNOTnamed_rulebook_outcome: for constant values
-enumconstant_nonlocal_variable_ANNOTnonlocal_variable: for constant values
-enumconstant_number_ANNOTint: which integer this is
-enumconstant_property_ANNOTproperty: for constant values
-enumconstant_rule_ANNOTrule: for constant values
-enumconstant_rulebook_ANNOTrulebook: for constant values
-enumconstant_scene_ANNOTscene: for constant values
-enumconstant_table_ANNOTtable: for constant values
-enumconstant_table_column_ANNOTtable_column: for constant values
-enumconstant_text_ANNOTtext_stream: for constant values
-enumconstant_use_option_ANNOTuse_option: for constant values
-enumconstant_verb_form_ANNOTverb_form: for constant values
-enumcontrol_structure_used_ANNOTcontrol_structure_phrase: for CODE BLOCK nodes only
-enumconverted_SN_ANNOTint: marking descriptions
-enumcreation_proposition_ANNOTpcalc_prop: proposition which newly created value satisfies
-enumcreation_site_ANNOTint: whether an instance was created from this node
-enumdefn_language_ANNOTinform_language: what language this definition is in
-enumend_control_structure_used_ANNOTcontrol_structure_phrase: for CODE BLOCK nodes only
-enumepistemological_status_ANNOTint: a bitmap of results from checking an ambiguous reading
-enumevaluation_ANNOTparse_node: result of evaluating the text
-enumexplicit_iname_ANNOTinter_name: is this value explicitly an iname?
-enumexplicit_literal_ANNOTint: my value is an explicit integer or text
-enumexplicit_vh_ANNOTvalue_holster: used for compiling I6-level properties
-enumfrom_text_substitution_ANNOTint: whether this is an implicit say invocation
-enumexplicit_gender_marker_ANNOTint: used by PROPER NOUN nodes for evident genders
-enumgrammar_token_code_ANNOT int: used to identify grammar tokens
-enumgrammar_token_literal_ANNOT int: for grammar tokens which are literal words
-enumgrammar_token_relation_ANNOTbinary_predicate: for relation tokens
-enumgrammar_value_ANNOTparse_node: used as a marker when evaluating Understand grammar
-enumimplicit_in_creation_of_ANNOTinference_subject: for assemblies
-enumimplicitness_count_ANNOT int: keeping track of recursive assemblies
-enumindentation_level_ANNOTint: for routines written with Pythonesque indentation
-enuminterpretation_of_subject_ANNOTinference_subject: subject, during passes
-enumis_phrase_option_ANNOTint: this unparsed text is a phrase option
-enumkind_of_new_variable_ANNOTkind: what if anything is returned
-enumkind_of_value_ANNOTkind: for specification nodes
-enumkind_required_by_context_ANNOTkind: what if anything is expected here
-enumkind_resulting_ANNOTkind: what if anything is returned
-enumkind_variable_declarations_ANNOTkind_variable_declaration: and of these
-enumrule_placement_sense_ANNOTint: are we listing a rule into something, or out of it?
-enumlpe_options_ANNOTint: options set for a literal pattern part
-enummodal_verb_ANNOTverb_conjugation: relevant only for that: e.g., "might"
-enummultiplicity_ANNOTint: e.g., 5 for "five gold rings"
-enumnew_relation_here_ANNOTbinary_predicate: new relation as subject of "relates" sentence
-enumnothing_object_ANNOTint: this represents nothing at run-time
-enumnowhere_ANNOTint: used by the spatial plugin to show this represents "nowhere"
-enumphrase_invoked_ANNOTphrase: the phrase believed to be invoked...
-enumphrase_option_ANNOTint: \(2^i\) where \(i\) is the option number, \(0\leq i<16\)
-enumphrase_options_invoked_ANNOTinvocation_options: details of any options used
-enumproperty_name_used_as_noun_ANNOTint: in ambiguous cases such as "open"
-enumproposition_ANNOTpcalc_prop: for specification nodes
-enumquant_ANNOTquantifier: for quantified excerpts like "three baskets"
-enumquantification_parameter_ANNOTint: e.g., 3 for "three baskets"
-enumrecord_as_self_ANNOTint: record recipient as self when writing this
-enumrefined_ANNOTint: this subtree has had its nouns parsed
-enumresponse_code_ANNOTint: for responses only
-enumresults_from_splitting_ANNOTint: node in a routine's parse tree from comma block notation
-enumrow_amendable_ANNOT int: a candidate row for a table amendment
-enumsave_self_ANNOTint: this invocation must save and preserve self at run-time
-enumsay_adjective_ANNOTadjective: ...or the adjective to be agreed with by "say"
-enumsay_verb_ANNOTverb_conjugation: ...or the verb to be conjugated by "say"
-enumsay_verb_negated_ANNOT relevant only for that
-enumself_object_ANNOTint: this represents self at run-time
-enumslash_class_ANNOT int: used when partitioning grammar tokens
-enumslash_dash_dash_ANNOTint: used when partitioning grammar tokens
-enumssp_closing_segment_wn_ANNOTint: identifier for the last of these, or -1
-enumssp_segment_count_ANNOTint: number of subsequent complex-say phrases in stream
-enumsubject_ANNOTinference_subject: what this node describes
-enumsuppress_newlines_ANNOTint: whether the next say term runs on
-enumtable_cell_unspecified_ANNOT int: used to mark table entries as unset
-enumtense_marker_ANNOTgrammatical_usage: for specification nodes
-enumtext_unescaped_ANNOTint: flag used only for literal texts
-enumtoken_as_parsed_ANNOTparse_node: what if anything is returned
-enumtoken_check_to_do_ANNOTparse_node: what if anything is returned
-enumtoken_to_be_parsed_against_ANNOTparse_node: what if anything is returned
-enumturned_already_ANNOTint: aliasing like "player" to "yourself" performed already
-enumunit_ANNOTcompilation_unit: set only for headings, routines and sentences
-enumunproven_ANNOTint: this invocation needs run-time typechecking
-enumverb_problem_issued_ANNOTint: has a problem message about the primary verb been issued already?
-enumyou_can_ignore_ANNOTint: for assertions now drained of meaning
+
§6.9. So we itemise the pointer-valued annotations below, and the macro expands
-to provide their get and set functions:
+
§9. These are the English names of the built-in relations. The use of hyphenation
+here is a fossil from the times when Inform allowed only single-word relation
+names; but it doesn't seem worth changing, especially as the hyphenated
+relations are almost never needed for anything. All the same, translators into
+other languages may as well drop the hyphens.
diff --git a/docs/core-module/1-cp.html b/docs/core-module/1-cp.html
index 5b0c257f4..fb5eaa9ac 100644
--- a/docs/core-module/1-cp.html
+++ b/docs/core-module/1-cp.html
@@ -177,7 +177,7 @@ bit or the <k-kind> bit set, which as we see above is }
diff --git a/docs/core-module/1-cs.html b/docs/core-module/1-cs.html
index ac95a59c4..ca587a75f 100644
--- a/docs/core-module/1-cs.html
+++ b/docs/core-module/1-cs.html
@@ -244,7 +244,7 @@ the above settings can be changed.)
}
diff --git a/docs/core-module/1-htc.html b/docs/core-module/1-htc.html
index 5aefa1840..bc13eb798 100644
--- a/docs/core-module/1-htc.html
+++ b/docs/core-module/1-htc.html
@@ -196,8 +196,8 @@ will divide according to these units.
Task::advance_stage_to(SUBDIVIDING_CSEQ, I"Dividing source into compilation units", -1);BENCH(CompilationSettings::initialise_gcs)BENCH(Emit::begin);
-BENCH(Sentences::Headings::make_the_tree)
-BENCH(Sentences::Headings::write_as_xml)
+BENCH(NameResolution::make_the_tree)
+BENCH(IndexHeadings::write_as_xml)BENCH(CompilationUnits::determine)
@@ -224,7 +224,7 @@ so on. Those absolute basics are made here.
Task::advance_stage_to(SEMANTIC_ANALYSIS_CSEQ, I"Pre-pass through major nodes", 1);BENCH(MajorNodes::pre_pass)
-BENCH(ParseTreeUsage::verify)
+BENCH(ParseTreeUsage::verify)Task::advance_stage_to(ASSERTIONS_PASS_1_CSEQ, I"First pass through major nodes", 2);BENCH(MajorNodes::pass_1)BENCH(Tables::traverse_to_stock)
@@ -300,7 +300,7 @@ so on. Those absolute basics are made here.
BENCH(Activities::Activity_for_rulebooks_array)BENCH(Activities::Activity_after_rulebooks_array)BENCH(Activities::Activity_atb_rulebooks_array)
-BENCH(Relations::compile_defined_relation_constants)
+BENCH(RTRelations::compile_defined_relation_constants)BENCH(Kinds::RunTime::compile_data_type_support_routines)BENCH(Kinds::RunTime::I7_Kind_Name_routine)BENCH(World::Compile::compile)
@@ -326,7 +326,7 @@ so on. Those absolute basics are made here.
BENCH(PL::Files::arrays)BENCH(Rulebooks::rulebook_var_creators)BENCH(Activities::activity_var_creators)
-BENCH(Relations::IterateRelations)
+BENCH(RTRelations::IterateRelations)BENCH(Phrases::Manager::RulebookNames_array)BENCH(Phrases::Manager::RulePrintingRule_routine)BENCH_IF(parsing_plugin, PL::Parsing::Verbs::prepare)
@@ -335,7 +335,7 @@ so on. Those absolute basics are made here.
BENCH_IF(parsing_plugin, PL::Parsing::Tokens::Values::truth_state)BENCH_IF(parsing_plugin, PL::Parsing::Tokens::Values::time)BENCH_IF(parsing_plugin, PL::Parsing::Tokens::Values::compile_type_gprs)
-BENCH(VerbsAtRunTime::ConjugateVerb)
+BENCH(RTVerbs::ConjugateVerb)BENCH(Adjectives::Meanings::agreements)if (debugging) {
@@ -353,7 +353,7 @@ so on. Those absolute basics are made here.
BENCH(Strings::compile_responses)BENCH(Lists::check)BENCH(Lists::compile)
-BENCH(Relations::compile_defined_relations)
+BENCH(RTRelations::compile_defined_relations)BENCH(Phrases::Manager::compile_as_needed)BENCH(Strings::TextSubstitutions::allow_no_further_text_subs)BENCH_IF(parsing_plugin, PL::Parsing::Tokens::Filters::compile)
@@ -392,7 +392,7 @@ so on. Those absolute basics are made here.
enumaction_meaning_ANNOTaction_pattern: meaning in parse tree when used as noun
+enumpredicate_ANNOTunary_predicate: which adjective is asserted
+enumcategory_of_I6_translation_ANNOT int: what sort of "translates into I6" sentence this is
+enumclassified_ANNOTint: this sentence has been classified
+enumclears_pronouns_ANNOTint: this sentence erases the current value of "it"
+enumcolon_block_command_ANNOT int: this COMMAND uses the ":" not begin/end syntax
+enumcondition_tense_ANNOTtime_period: for specification nodes
+enumconstant_action_name_ANNOTaction_name: for constant values
+enumconstant_action_pattern_ANNOTaction_pattern: for constant values
+enumconstant_activity_ANNOTactivity: for constant values
+enumconstant_binary_predicate_ANNOTbinary_predicate: for constant values
+enumconstant_constant_phrase_ANNOTconstant_phrase: for constant values
+enumconstant_enumeration_ANNOTint: which one from an enumerated kind
+enumconstant_equation_ANNOTequation: for constant values
+enumconstant_grammar_verb_ANNOTgrammar_verb: for constant values
+enumconstant_instance_ANNOTinstance: for constant values
+enumconstant_local_variable_ANNOTlocal_variable: for constant values
+enumconstant_named_action_pattern_ANNOTnamed_action_pattern: for constant values
+enumconstant_named_rulebook_outcome_ANNOTnamed_rulebook_outcome: for constant values
+enumconstant_nonlocal_variable_ANNOTnonlocal_variable: for constant values
+enumconstant_number_ANNOTint: which integer this is
+enumconstant_property_ANNOTproperty: for constant values
+enumconstant_rule_ANNOTrule: for constant values
+enumconstant_rulebook_ANNOTrulebook: for constant values
+enumconstant_scene_ANNOTscene: for constant values
+enumconstant_table_ANNOTtable: for constant values
+enumconstant_table_column_ANNOTtable_column: for constant values
+enumconstant_text_ANNOTtext_stream: for constant values
+enumconstant_use_option_ANNOTuse_option: for constant values
+enumconstant_verb_form_ANNOTverb_form: for constant values
+enumcontrol_structure_used_ANNOTcontrol_structure_phrase: for CODE BLOCK nodes only
+enumconverted_SN_ANNOTint: marking descriptions
+enumcreation_proposition_ANNOTpcalc_prop: proposition which newly created value satisfies
+enumcreation_site_ANNOTint: whether an instance was created from this node
+enumdefn_language_ANNOTinform_language: what language this definition is in
+enumend_control_structure_used_ANNOTcontrol_structure_phrase: for CODE BLOCK nodes only
+enumepistemological_status_ANNOTint: a bitmap of results from checking an ambiguous reading
+enumevaluation_ANNOTparse_node: result of evaluating the text
+enumexplicit_iname_ANNOTinter_name: is this value explicitly an iname?
+enumexplicit_literal_ANNOTint: my value is an explicit integer or text
+enumexplicit_vh_ANNOTvalue_holster: used for compiling I6-level properties
+enumfrom_text_substitution_ANNOTint: whether this is an implicit say invocation
+enumexplicit_gender_marker_ANNOTint: used by PROPER NOUN nodes for evident genders
+enumgrammar_token_code_ANNOT int: used to identify grammar tokens
+enumgrammar_token_literal_ANNOT int: for grammar tokens which are literal words
+enumgrammar_token_relation_ANNOTbinary_predicate: for relation tokens
+enumgrammar_value_ANNOTparse_node: used as a marker when evaluating Understand grammar
+enumimplicit_in_creation_of_ANNOTinference_subject: for assemblies
+enumimplicitness_count_ANNOT int: keeping track of recursive assemblies
+enumindentation_level_ANNOTint: for routines written with Pythonesque indentation
+enuminterpretation_of_subject_ANNOTinference_subject: subject, during passes
+enumis_phrase_option_ANNOTint: this unparsed text is a phrase option
+enumkind_of_new_variable_ANNOTkind: what if anything is returned
+enumkind_of_value_ANNOTkind: for specification nodes
+enumkind_required_by_context_ANNOTkind: what if anything is expected here
+enumkind_resulting_ANNOTkind: what if anything is returned
+enumkind_variable_declarations_ANNOTkind_variable_declaration: and of these
+enumrule_placement_sense_ANNOTint: are we listing a rule into something, or out of it?
+enumlpe_options_ANNOTint: options set for a literal pattern part
+enummodal_verb_ANNOTverb_conjugation: relevant only for that: e.g., "might"
+enummultiplicity_ANNOTint: e.g., 5 for "five gold rings"
+enumnew_relation_here_ANNOTbinary_predicate: new relation as subject of "relates" sentence
+enumnothing_object_ANNOTint: this represents nothing at run-time
+enumnowhere_ANNOTint: used by the spatial plugin to show this represents "nowhere"
+enumphrase_invoked_ANNOTphrase: the phrase believed to be invoked...
+enumphrase_option_ANNOTint: \(2^i\) where \(i\) is the option number, \(0\leq i<16\)
+enumphrase_options_invoked_ANNOTinvocation_options: details of any options used
+enumproperty_name_used_as_noun_ANNOTint: in ambiguous cases such as "open"
+enumproposition_ANNOTpcalc_prop: for specification nodes
+enumquant_ANNOTquantifier: for quantified excerpts like "three baskets"
+enumquantification_parameter_ANNOTint: e.g., 3 for "three baskets"
+enumrecord_as_self_ANNOTint: record recipient as self when writing this
+enumrefined_ANNOTint: this subtree has had its nouns parsed
+enumresponse_code_ANNOTint: for responses only
+enumresults_from_splitting_ANNOTint: node in a routine's parse tree from comma block notation
+enumrow_amendable_ANNOT int: a candidate row for a table amendment
+enumsave_self_ANNOTint: this invocation must save and preserve self at run-time
+enumsay_adjective_ANNOTadjective: ...or the adjective to be agreed with by "say"
+enumsay_verb_ANNOTverb_conjugation: ...or the verb to be conjugated by "say"
+enumsay_verb_negated_ANNOT relevant only for that
+enumself_object_ANNOTint: this represents self at run-time
+enumslash_class_ANNOT int: used when partitioning grammar tokens
+enumslash_dash_dash_ANNOTint: used when partitioning grammar tokens
+enumssp_closing_segment_wn_ANNOTint: identifier for the last of these, or -1
+enumssp_segment_count_ANNOTint: number of subsequent complex-say phrases in stream
+enumsubject_ANNOTinference_subject: what this node describes
+enumsuppress_newlines_ANNOTint: whether the next say term runs on
+enumtable_cell_unspecified_ANNOT int: used to mark table entries as unset
+enumtense_marker_ANNOTgrammatical_usage: for specification nodes
+enumtext_unescaped_ANNOTint: flag used only for literal texts
+enumtoken_as_parsed_ANNOTparse_node: what if anything is returned
+enumtoken_check_to_do_ANNOTparse_node: what if anything is returned
+enumtoken_to_be_parsed_against_ANNOTparse_node: what if anything is returned
+enumturned_already_ANNOTint: aliasing like "player" to "yourself" performed already
+enumunit_ANNOTcompilation_unit: set only for headings, routines and sentences
+enumunproven_ANNOTint: this invocation needs run-time typechecking
+enumverb_problem_issued_ANNOTint: has a problem message about the primary verb been issued already?
+enumyou_can_ignore_ANNOTint: for assertions now drained of meaning
+
enumALLOWED_NT "An animal is allowed to have a description"
+enumEVERY_NT "every container"
+enumACTION_NT "taking something closed"
+enumADJECTIVE_NT "open"
+enumPROPERTYCALLED_NT "A man has a number called age"
+enumCREATED_NT "a vehicle called Sarah Jane's car"
+enumTOKEN_NT Used for tokens in grammar
+enumCODE_BLOCK_NT Holds a block of source material
+enumINVOCATION_LIST_SAY_NT Single thing to be said
+enumINVOCATION_NT Usage of a phrase
+enumVOID_CONTEXT_NT When a void phrase is required
+enumRVALUE_CONTEXT_NT Arguments, in effect
+enumLVALUE_CONTEXT_NT Named storage location
+enumLVALUE_TR_CONTEXT_NT Table reference
+enumSPECIFIC_RVALUE_CONTEXT_NT Argument must be an exact value
+enumMATCHING_RVALUE_CONTEXT_NT Argument must match a description
+enumNEW_LOCAL_CONTEXT_NT Argument which creates a local
+enumLVALUE_LOCAL_CONTEXT_NT Argument which names a local
+enumCONDITION_CONTEXT_NT Used for "now" conditions
+
+
§7. The next specification nodes are the rvalues. These express I6 values —
+numbers, objects, text and so on — but cannot be assigned to, so that in an
+assignment of the form "change L to R" they can be used only as R, not L. This
+is not the same thing as a constant: for instance, "location of the player"
+evaluates differently at different times, but cannot be changed in an
+assignment.
+
+
+
enumCONSTANT_NT "7", "the can't lock a locked door rule", etc.
+enumPHRASE_TO_DECIDE_VALUE_NT "holder of the black box"
+
+
§8. Lvalue nodes represent stored I6 data at run-time, which means that they can
+be assigned to. (The traditional terms "lvalue" and "rvalue" refer to the left
+and right hand side of assignment statements written A = B.) For instance, a
+table entry qualifies as an lvalue because it can be both read and changed. To
+qualify as an lvalue, text must exactly specify the storage location referred
+to: "Table of Corvettes" only indicates a table, not an entry in a table, so
+is merely an rvalue. Similarly, "carrying capacity" (as a property name not
+indicating an owner) is a mere rvalue.
+
+
+
enumLOCAL_VARIABLE_NT "the running total", say
+enumNONLOCAL_VARIABLE_NT "the location"
+enumPROPERTY_VALUE_NT "the carrying capacity of the cedarwood box"
+enumTABLE_ENTRY_NT "tonnage in row X of the Table of Corvettes"
+enumLIST_ENTRY_NT "item 4 in L"
+
+
§9. Condition nodes represent atomic conditions, and also Boolean operations on
+them. It's convenient to represent these operations as nodes in their own right
+rather than as (for example) phrases: this reduces parsing ambiguities, but
+also makes it easier for us to manipulate the results.
+
+
+
enumLOGICAL_NOT_NT "not A"
+enumLOGICAL_TENSE_NT in the past, A
+enumLOGICAL_AND_NT "A and B"
+enumLOGICAL_OR_NT "A or B"
+enumTEST_PROPOSITION_NT if "the cat is on the mat"
+enumTEST_PHRASE_OPTION_NT "giving full details", say
+enumTEST_VALUE_NT when a value is used as a condition
+
diff --git a/docs/imperative-module/3-cs.html b/docs/imperative-module/3-cs.html
index b4a61b8e2..8b00accc4 100644
--- a/docs/imperative-module/3-cs.html
+++ b/docs/imperative-module/3-cs.html
@@ -598,7 +598,7 @@ can be called multiple times in the course of the evening.)
}
diff --git a/docs/imperative-module/3-dptd.html b/docs/imperative-module/3-dptd.html
index fb786775c..2ce9fa322 100644
--- a/docs/imperative-module/3-dptd.html
+++ b/docs/imperative-module/3-dptd.html
@@ -1231,7 +1231,7 @@ in exactly one place: for example,
diff --git a/docs/imperative-module/3-phr.html b/docs/imperative-module/3-phr.html
index cb94e1c51..04cfbca06 100644
--- a/docs/imperative-module/3-phr.html
+++ b/docs/imperative-module/3-phr.html
@@ -593,7 +593,7 @@ response to "requests". All other phrases are compiled just once.
}
diff --git a/docs/imperative-module/3-pi.html b/docs/imperative-module/3-pi.html
index 5e61ca72a..f194d1bf4 100644
--- a/docs/imperative-module/3-pi.html
+++ b/docs/imperative-module/3-pi.html
@@ -343,7 +343,7 @@ above, it may as well go here.
}
diff --git a/docs/imperative-module/3-po.html b/docs/imperative-module/3-po.html
index 6dce05b20..486e9a6fa 100644
--- a/docs/imperative-module/3-po.html
+++ b/docs/imperative-module/3-po.html
@@ -407,7 +407,7 @@ by "and":
To tidy up |INVOCATION_LIST_NT| nodes into a list of children under the relevant |RULE_NT| node, and so turn each rule definition into a single subtree.
§1. Initially, the phrases (INVOCATION_LIST_NT) making up a rule (RULE_NT) are
+simply listed after it in the parse tree, but we want them to become its
+children: this is the only thing the \(A\)-grammar does with rules, which
+otherwise wait until later to be dealt with.
+
+
+
The code in this section accomplishes the regrouping: after it runs, every
+INVOCATION_LIST_NT is a child of the RULE_NT header to which it belongs.
+
+
+
§2. This routine is used whenever new material is added. Whenever it finds a
+childless RULE_NT followed by a sequence of INVOCATION_LIST_NT nodes, it
+joins these in sequence as children of the RULE_NT. Since it always
+acts so as to leave a non-zero number of children, and since it acts only
+on childless nodes, it cannot ever act on the same node twice.
+
+
+
+voidRuleSubtrees::register_recently_lexed_phrases(void) {
+if (problem_count > 0) return; for then the tree is perhaps broken anyway
+SyntaxTree::traverse(Task::syntax_tree(), RuleSubtrees::demote_command_nodes);
+SyntaxTree::traverse(Task::syntax_tree(), RuleSubtrees::detect_loose_command_nodes);
+}
+
+
§3. Command nodes are demoted to be children of routine nodes:
+
+
+
+voidRuleSubtrees::demote_command_nodes(parse_node *p) {
+if ((Node::get_type(p) == RULE_NT) && (p->down == NULL)) {
+parse_node *end_def = p;
+while ((end_def->next) && (Node::get_type(end_def->next) == INVOCATION_LIST_NT))
+end_def = end_def->next;
+if (p == end_def) return; RULE_NT not followed by any INVOCATION_LIST_NTs
+ splice so that p->next to end_def become the children of p:
+p->down = p->next;
+p->next = end_def->next;
+end_def->next = NULL;
+RuleSubtrees::parse_routine_structure(p);
+ }
+}
+
§5. Parsing Routine Structure. There are now two possible syntaxes to express the structural makeup of a
+routine. Traditional I7 syntax for blocks is to place them within begin/end
+markers: the "begin" occurring at the end of the conditional or loop header,
+and the "end if", "end while", etc., as a phrase of its own at the end of
+the block. Newer I7 syntax (March 2008) is to use Python-style colons and
+indentation. Both are allowed, but not in the same routine.
+
+
+
This routine opens with the routine's parse tree consisting of a simple
+linked list of code-point nodes, one for each phrase. We must work out
+which syntax is used, decipher it, and turn the list into a proper tree
+structure in a single unified format.
+
+
+
How much simpler this would all be if we could abolish the old format, but
+it's kept for the benefit of partially sighted users, who find tabbed
+indentation difficult to manage with screen-readers.
+
§5.2. (a.2) Report problems if the two syntaxes are mixed up with each other5.2 =
+
+
+
+if ((uses_colon_syntax) && (mispunctuates_begin_end_syntax)) {
+current_sentence = routine_node;
+Problems::quote_source(1, current_sentence);
+Problems::quote_source(2, mispunctuates_begin_end_syntax);
+StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_BadOldSyntax));
+Problems::issue_problem_segment(
+"The rule or phrase definition %1 seems to use indentation and "
+"colons to group phrases together into 'if', 'repeat' or 'while' "
+"blocks. That's fine, but then this phrase seems to be missing "
+"some punctuation - %2. Perhaps a colon is missing?");
+Problems::issue_problem_end();
+return;
+ }
+
+if ((uses_colon_syntax) && (uses_begin_end_syntax)) {
+current_sentence = routine_node;
+Problems::quote_source(1, current_sentence);
+Problems::quote_source(2, uses_colon_syntax);
+Problems::quote_source(3, uses_begin_end_syntax);
+StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_BothBlockSyntaxes));
+Problems::issue_problem_segment(
+"The rule or phrase definition %1 seems to use both ways of grouping "
+"phrases together into 'if', 'repeat' and 'while' blocks at once. "
+"Inform allows two alternative forms, but they cannot be mixed in "
+"the same definition. %POne way is to end the 'if', 'repeat' or "
+"'while' phrases with a 'begin', and then to match that with an "
+"'end if' or similar. ('Otherwise' or 'otherwise if' clauses are "
+"phrases like any other, and end with semicolons in this case.) "
+"You use this begin/end form here, for instance - %3. %P"
+"The other way is to end with a colon ':' and then indent the "
+"subsequent phrases underneath, using tabs. (Note that any "
+"'otherwise' or 'otherwise if' clauses also have to end with "
+"colons in this case.) You use this indented form here - %2.");
+Problems::issue_problem_end();
+return;
+ }
+
+if ((requires_colon_syntax) && (uses_begin_end_syntax)) {
+current_sentence = routine_node;
+Problems::quote_source(1, current_sentence);
+Problems::quote_source(2, requires_colon_syntax);
+StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_NotInOldSyntax));
+Problems::issue_problem_segment(
+"The construction %2, in the rule or phrase definition %1, "
+"is only allowed if the rule is written in the 'new' format, "
+"that is, with the phrases written one to a line with "
+"indentation showing how they are grouped together, and "
+"with colons indicating the start of such a group.");
+Problems::issue_problem_end();
+return;
+ }
+
§5.3. If we're using Pythonesque notation, then the number of tab stops of
+indentation of a phrase tells us where it belongs in the structure, so
+we mark up the tree with that information.
+
+
+
(b.1) Annotate the parse tree with indentation levels5.3 =
+
§5.4. Note that we are a little cautious about recognising phrases which will
+open blocks, such as "repeat...", because of the dangers of false positives;
+so we look for the "begin" keyword, or the colon. We're less cautious with
+subordinate phrases (such as "otherwise") because we know their wonding
+more certainly, and similarly for "end X" phrases.
+
+
+
(b.2) Annotate the parse tree with control structure usage5.4 =
+
+
+
+for (parse_node *p = routine_node->down; p; p = p->next) {
+control_structure_phrase *csp;
+csp = ControlStructures::detect(Node::get_text(p));
+if (csp) {
+if ((Annotations::read_int(p, colon_block_command_ANNOT)) ||
+ (<phrase-beginning-block>(Node::get_text(p))) ||
+ (csp->subordinate_to)) {
+Node::set_control_structure_used(p, csp);
+if (csp == case_CSP) Trim a switch case to just the case value5.4.1;
+ }
+ }
+csp = ControlStructures::detect_end(Node::get_text(p));
+if (csp) Node::set_end_control_structure_used(p, csp);
+ }
+
+wordingBCW = GET_RW(<phrase-with-comma-notation>, 1); text before the comma
+wordingACW = GET_RW(<phrase-with-comma-notation>, 2); text after the comma
+
+ First trim and annotate the "if ..." part
+Annotations::write_int(p, colon_block_command_ANNOT, TRUE); it previously had no colon...
+Node::set_control_structure_used(p, csp); ...and therefore didn't have its CSP set
+Node::set_text(p, BCW);
+
+ Now make a new node for the "then" part, indenting it one step inward
+parse_node *then_node = Node::new(INVOCATION_LIST_NT);
+Annotations::write_int(then_node, results_from_splitting_ANNOT, TRUE);
+Annotations::write_int(then_node, indentation_level_ANNOT,
+Annotations::read_int(p, indentation_level_ANNOT) + 1);
+Node::set_text(then_node, ACW);
+
+parse_node *last_node_of_if_construction = then_node, *rest_of_routine = p->next;
+
+ Attach the "then" node after the "if" node:
+p->next = then_node;
+
+Deal with an immediately following otherwise node, if there is one5.5.1.1;
+
+if (uses_colon_syntax == FALSE) {
+last_node_of_if_construction->next = RuleSubtrees::end_node(p);
+last_node_of_if_construction->next->next = rest_of_routine;
+ } else {
+last_node_of_if_construction->next = rest_of_routine;
+ }
+
§5.6. If the old-style syntax is used, there are explicit "end if", "end repeat"
+and "end while" nodes in the list already. But if the Pythonesque syntax is
+used then we need to create these nodes and insert them into the list; we
+do these by reading off the structure from the pattern of indentation. It's
+quite a long task, since this pattern may contain errors, which we have to
+report more or less helpfully.
+
+
+
(d) Insert end nodes and check the indentation5.6 =
+
Issue problem message for failing to start flush on the left margin5.6.1 =
+
+
+
+current_sentence = routine_node;
+Problems::quote_source_eliding_begin(1, current_sentence);
+StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_NonflushRule));
+Problems::issue_problem_segment(
+"The phrase or rule definition %1 is written using tab indentations "
+"to show how its phrases are to be grouped together. But in that "
+"case the opening line needs to be on the left margin, not indented.");
+Problems::issue_problem_end();
+suppress_further_problems = TRUE;
+
§5.6.2. Here we set indent to the number of tab-stops in from the margin, or to
+expected_indent if the text does not appear to be at the start of its own
+line in the source (because it runs on from a previous phrase, in
+which case we set the run_on_at flag: except for following on from cases
+in switches with a non-control-structure, which is allowed, because otherwise
+the lines often look silly and short).
+
+
+
Determine actual indentation of this phrase5.6.2 =
+
§5.6.3. We now know the indent level of the line as read, and also the
+expected_indent given the definition so far. If they agree, fine. If they
+don't agree, it isn't necessarily bad news — if each line's indentation were
+a function of the last, there would be no information in it, after all.
+Roughly speaking, when indent is greater than we expect, that must be
+wrong — it means indentation has jumped inward as if to open a new block,
+but blocks are opened explicitly and not by simply raising the indent.
+But when indent is less than we expect, this may simply mean that the
+current block(s) has or have been closed, because blocks are indeed closed
+implicitly just by moving the indentation back in.
+
+
+
Compare actual indentation to what we expect from structure so far5.6.3 =
+
§5.6.3.1. This is a small variation used for an intermediate phrase like "otherwise".
+These are required to be at the same indentation as the line which opened the
+block, rather than being one tab step in from there: in other words they are
+not deemed part of the block itself. They can also occur in "stages", which
+is a way to enforce one intermediate phrase only being allowed after another
+one — for instance, "otherwise if..." is not allowed after an "otherwise"
+within an "if".
+
+
+
Compare actual indentation to what we expect for an intermediate phrase5.6.3.1 =
+
§5.6.4. In colon syntax, blocks are explicitly opened; they are only implicitly
+closed. Here is the opening:
+
+
+
If p is a node representing a phrase beginning a block, and we're in the
+colon syntax, then it is followed by a word which is the colon: thus if p
+reads "if x is 2" then the word following the "2" will be ":".
+
+
+
Insert begin marker and increase expected indentation if a block begins here5.6.4 =
+
§5.6.5. Now for the closing of colon-syntax blocks. We know that blocks must be
+being closed if the indentation has jumped backwards: but it may be that many
+blocks are being closed at once. (It may also be that the indentation has
+gone awry.)
+
+
+
Try closing blocks to bring expected indentation down to match5.6.5 =
+
+
+
+if ((just_opened_block) &&
+ (blo_sp > 0) &&
+ (!(blstack_construct[blo_sp-1]->body_empty_except_for_subordinates)) && (p))
+Issue problem for an empty block5.6.5.2;
+while (indent < expected_indent) {
+parse_node *opening;
+if (blo_sp == 0) {
+Record a misalignment of indentation5.6.3.3;
+indent = expected_indent;
+break;
+ }
+if ((blstack_construct[blo_sp-1]->body_empty_except_for_subordinates) &&
+ (expected_indent - indent == 1)) {
+indent = expected_indent;
+break;
+ }
+expected_indent--;
+if (blstack_construct[blo_sp-1]->indent_subblocks) expected_indent--;
+opening = blstack_opening_phrase[--blo_sp];
+Insert end marker to match the opening of the block phrase5.6.5.1;
+ }
+
§5.6.5.1. An end marker is a phrase like "end if" which matches the "if... begin"
+above it: here we insert such a marker at a place where the source text
+indentation implicitly requires it.
+
+
+
Insert end marker to match the opening of the block phrase5.6.5.1 =
+
§5.6.6. ...and catch it with something of a catch-all message:
+
+
+
Issue problem message for misaligned indentation5.6.6 =
+
+
+
+if (suppress_further_problems == FALSE) {
+LOG("$T\n", routine_node);
+current_sentence = routine_node;
+Problems::quote_source_eliding_begin(1, current_sentence);
+Problems::quote_source_eliding_begin(2, first_misaligned_phrase);
+StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_MisalignedIndentation));
+Problems::issue_problem_segment(
+"The phrase or rule definition %1 is written using the 'colon "
+"and indentation' syntax for its 'if's, 'repeat's and 'while's, "
+"where blocks of phrases grouped together are indented one "
+"tab step inward from the 'if ...:' or similar phrase to which "
+"they belong. But the tabs here seem to be misaligned, and I can't "
+"determine the structure. The first phrase going awry in the "
+"definition seems to be %2, in case that helps. %PThis sometimes "
+"happens even when the code looks about right, to the eye, if rows "
+"of spaces have been used to indent phrases instead of tabs.");
+Problems::Using::diagnose_further();
+Problems::issue_problem_end();
+ }
+
Issue problem message for an excess of indentation5.6.7 =
+
+
+
+if (suppress_further_problems == FALSE) {
+current_sentence = routine_node;
+Problems::quote_source_eliding_begin(1, current_sentence);
+Problems::quote_source_eliding_begin(2, first_overindented_phrase);
+StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_TooMuchIndentation));
+Problems::issue_problem_segment(
+"The phrase or rule definition %1 is written using tab indentations "
+"to show how its phrases are to be grouped together. But the level "
+"of indentation goes far too deep, reaching more than 25 tab stops "
+"from the left margin.");
+Problems::issue_problem_end();
+ }
+
§5.6.8. Issue problem message for run-ons within phrase definition5.6.8 =
+
+
+
+if (suppress_further_problems == FALSE) {
+current_sentence = routine_node;
+Problems::quote_source_eliding_begin(1, current_sentence);
+Problems::quote_source_eliding_begin(2, run_on_at);
+StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_RunOnsInTabbedRoutine));
+Problems::issue_problem_segment(
+"The phrase or rule definition %1 is written using the 'colon "
+"and indentation' syntax for its 'if's, 'repeat's and 'while's, "
+"but that's only allowed if each phrase in the definition "
+"occurs on its own line. So phrases like %2, which follow "
+"directly on from the previous phrase, aren't allowed.");
+Problems::issue_problem_end();
+ }
+
§5.6.5.2. It's a moot point whether the following should be incorrect syntax, but it
+far more often happens as an accident than anything else, and it's hard to
+think of a sensible use.
+
+
+
Issue problem for an empty block5.6.5.2 =
+
+
+
+if (suppress_further_problems == FALSE) {
+LOG("$T\n", routine_node);
+current_sentence = routine_node;
+Problems::quote_source_eliding_begin(1, current_sentence);
+Problems::quote_source_eliding_begin(2, prev);
+Problems::quote_source_eliding_begin(3, p);
+StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_EmptyIndentedBlock));
+Problems::issue_problem_segment(
+"The phrase or rule definition %1 is written using the 'colon "
+"and indentation' syntax for its 'if's, 'repeat's and 'while's, "
+"where blocks of phrases grouped together are indented one "
+"tab step inward from the 'if ...:' or similar phrase to which "
+"they belong. But the phrase %2, which ought to begin a block, "
+"is immediately followed by %3 at the same or a lower indentation, "
+"so the block seems to be empty - this must mean there has been "
+"a mistake in indenting the phrases.");
+Problems::issue_problem_end();
+ }
+
§5.6.3.2.1. Issue problem for non-case in a switch5.6.3.2.1 =
+
+
+
+if (suppress_further_problems == FALSE) {
+current_sentence = routine_node;
+Problems::quote_source_eliding_begin(1, current_sentence);
+Problems::quote_source_eliding_begin(2, p);
+StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_NonCaseInIf));
+Problems::issue_problem_segment(
+"In the phrase or rule definition %1, the phrase %2 came as a "
+"surprise since it was not a case in an 'if X is...' but was "
+"instead some other miscellaneous instruction.");
+Problems::issue_problem_end();
+ }
+
§5.6.3.1.1. Issue problem for an intermediate phrase not matching5.6.3.1.1 =
+
+
+
+if ((indent_misalign == FALSE) && (suppress_further_problems == FALSE)) {
+current_sentence = p;
+if (csp->subordinate_to == if_CSP) {
+LOG("$T\n", routine_node);
+StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_MisalignedOtherwise),
+"this doesn't match a corresponding 'if'",
+"as it must. An 'otherwise' must be vertically underneath the "
+"'if' to which it corresponds, at the same indentation, and "
+"if the 'otherwise' uses a colon to begin a block then the "
+"'if' must do the same.");
+ }
+if (csp->subordinate_to == switch_CSP)
+StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_MisalignedCase),
+"this seems to be misplaced since it is not a case within an "
+"'if X is...'",
+"as it must be. Each case must be placed one tab stop in from "
+"the 'if X is...' to which it belongs, and the instructions "
+"for what to do in that case should be one tab stop further in "
+"still.");
+ }
+
§5.6.3.1.2. Issue problem for an intermediate phrase out of sequence5.6.3.1.2 =
+
+
+
+if ((indent_misalign == FALSE) && (suppress_further_problems == FALSE)) {
+current_sentence = p;
+if ((csp == default_case_CSP) || (csp == case_CSP))
+StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_DefaultCaseNotLast),
+"'otherwise' must be the last clause if an 'if ... is:'",
+"and in particular it has to come after all the '-- V:' "
+"case values supplied.");
+else
+StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_MisarrangedOtherwise),
+"this seems to be misplaced since it is out of sequence within its 'if'",
+"with an 'otherwise if...' coming after the more general 'otherwise' "
+"rather than before. (Note that an 'otherwise' or 'otherwise if' must "
+"be vertically underneath the 'if' to which it corresponds, at the "
+"same indentation.");
+ }
+
§5.7. And after all that work, the routine's parse tree still consists only of a
+linked list of nodes; but at least it now contains the same pattern of nodes
+whichever syntax is used. We finally make a meaningful tree out of it.
+
+
+
(e) Structure the parse tree to match the use of control structures5.7 =
+
+
+
+parse_node *routine_list = routine_node->down;
+parse_node *top_level = Node::new(CODE_BLOCK_NT);
+
+routine_node->down = top_level;
+
+parse_node *attach_owners[MAX_BLOCK_NESTING+1];
+parse_node *attach_points[MAX_BLOCK_NESTING+1];
+control_structure_phrase *attach_csps[MAX_BLOCK_NESTING+1];
+intattach_point_sp = 0;
+
+ push the top level code block onto the stack
+attach_owners[attach_point_sp] = NULL;
+attach_csps[attach_point_sp] = NULL;
+attach_points[attach_point_sp++] = top_level;
+
+parse_node *overflow_point = NULL; if any overflow is found
+for (parse_node *pn = routine_list, *pn_prev = NULL; pn; pn_prev = pn, pn = pn->next) {
+ unstring this node from the old list
+if (pn_prev) pn_prev->next = NULL;
+Attach the node to the routine's growing parse tree5.7.1;
+ }
+if (overflow_point) {
+current_sentence = overflow_point;
+StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_BlockNestingTooDeep),
+"compound phrases have gone too deep",
+"perhaps because many have begun but not been properly ended?");
+ }
+
§5.8. We now have a neatly structured tree, so from here on anything we do will
+need a recursive procedure.
+
+
+
Firstly, the tree is certainly neat, but it can still contain all kinds
+of nonsense: "if" blocks with multiple "otherwise"s, for example. This is
+where we look for such mistakes.
+
§6.1. These used to be much-seen problem messages, until Inform moved to Pythonesque
+structure-by-indentation. Nowadays "end if", "end while" and such are
+automatically inserted into the stream of commands, always in the right place,
+and always passing these checks. But the problem messages are kept for the sake
+of old-format source text, and for refuseniks.
+
+
+
Issue problem for end without begin6.1 =
+
+
+
+StandardProblems::sentence_problem_with_note(Task::syntax_tree(), _p_(PM_EndWithoutBegin),
+"this is an 'end' with no matching 'begin'",
+"which should not happen: every phrase like 'if ... begin;' "
+"should eventually be followed by its bookend 'end if'. "
+"It makes no sense to have an 'end ...' on its own.",
+"Perhaps the problem is actually that you opened several "
+"such begin... end 'blocks' and accidentally closed them "
+"once too many? This is very easily done.");
+
+Problems::quote_source(1, current_sentence);
+Problems::quote_wide_text(2, prior->keyword);
+Problems::quote_source(3, prev_p);
+StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_WrongEnd));
+Problems::issue_problem_segment(
+"You wrote %1, but the end I was expecting next was 'end %2', "
+"finishing the block you began with %3.");
+Problems::issue_problem_end();
+
+StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_BeginWithoutEnd),
+"the definition of the phrase ended with no matching 'end' for "
+"this 'begin'",
+"bearing in mind that every begin must have a matching end, and "
+"that the one most recently begun must be the one first to end. For "
+"instance, 'if ... begin' must have a matching 'end if'.");
+
+if (csp == otherwise_CSP)
+StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_OtherwiseWithoutIf),
+"this is an 'else' or 'otherwise' with no matching 'if' (or 'unless')",
+"which must be wrong.");
+elseif (csp == otherwise_if_CSP)
+StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_OtherwiseIfMisplaced),
+"the 'otherwise if' clause here seems not to be occurring inside "
+"a large 'if'",
+"and seems to be freestanding instead. (Though 'otherwise ...' can "
+"usually be used after simple one-line 'if's to provide an alternative "
+"course of action, 'otherwise if...' is a different matter, and is "
+"used to divide up larger-scale instructions.)");
+else
+StandardProblems::sentence_problem(Task::syntax_tree(), _p_(BelievedImpossible),
+"this clause can't occur outside of a control phrase",
+"which suggests that the structure of this routine is wrong.");
+
§6.5. Choose a problem for the wrong clause6.5 =
+
+
+
+if ((csp == otherwise_CSP) || (csp == otherwise_if_CSP)) {
+Problems::quote_source(1, current_sentence);
+Problems::quote_wide_text(2, context->keyword);
+StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_OtherwiseInNonIf));
+Problems::issue_problem_segment(
+"The %1 here did not make sense inside a "
+"'%2' structure: it's provided for 'if' (or 'unless').");
+Problems::issue_problem_end();
+ } else
+StandardProblems::sentence_problem(Task::syntax_tree(), _p_(BelievedImpossible),
+"this clause is wrong for the phrase containing it",
+"which suggests that the structure of this routine is wrong.");
+
§6.6. Choose a problem for otherwise not occurring last6.6 =
+
+
+
+intdoubled = FALSE, oi = FALSE;
+for (parse_node *p2 = p->next; p2; p2 = p2->next) {
+if (Node::get_control_structure_used(p2) == otherwise_CSP) {
+current_sentence = p2;
+doubled = TRUE;
+ }
+if (Node::get_control_structure_used(p2) == otherwise_if_CSP)
+oi = TRUE;
+ }
+if (doubled)
+StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_DoubleOtherwise),
+"that makes two unconditional 'otherwise' or 'else' clauses "
+"for this 'if'",
+"which is forbidden since 'otherwise' is meant to be a single "
+"(optional) catch-all clause at the end.");
+elseif (oi)
+StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_OtherwiseIfAfterOtherwise),
+"this seems to be misplaced since it is out of sequence within its 'if'",
+"with an 'otherwise if...' coming after the more general 'otherwise' "
+"rather than before. (If there's an 'otherwise' clause, it has to be "
+"the last clause of the 'if'.)");
+else
+StandardProblems::sentence_problem(Task::syntax_tree(), _p_(BelievedImpossible),
+"'otherwise' must be the last clause",
+"but it seems not to be.");
+
§6.7. This shouldn't happen because the switch construct requires Python syntax
+and the structure of that was checked at indentation time, but just in case.
+
+
+
Issue a problem for the default case not occurring last6.7 =
+
+
+
+StandardProblems::sentence_problem(Task::syntax_tree(), _p_(BelievedImpossible),
+"'otherwise' must be the last clause",
+"which must be wrong.");
+
§5.9. The tree is now known to be correctly structured, and there are no possible
+problem messages left to issue. It's therefore safe to begin rearranging it.
+We'll first eliminate one whole construction: "otherwise if whatever: ..."
+can now become "otherwise: if whatever: ...".
+
§5.10. We made a similar manoeuvre above, but for one-line "otherwise do something"
+phrases following one-line "if", not for the wider case of "otherwise if". We
+didn't handle this back then because to do so would have made it impossible
+to issue good problem messages for failures to use "otherwise if" correctly.
+
+
+
+voidRuleSubtrees::purge_otherwise_if(parse_node *block) {
+for (parse_node *p = block->down, *prev_p = NULL; p; prev_p = p, p = p->next) {
+if (Node::get_control_structure_used(p) == otherwise_if_CSP) {
+parse_node *former_contents = p->down;
+parse_node *former_successors = p->next;
+
+ put an otherwise node in the position previously occupied by p
+parse_node *otherwise_node = Node::new(CODE_BLOCK_NT);
+Node::set_control_structure_used(otherwise_node, otherwise_CSP);
+ extract just the word "otherwise"
+Node::set_text(otherwise_node, Wordings::one_word(Wordings::first_wn(Node::get_text(p))));
+if (prev_p) prev_p->next = otherwise_node; elseblock->down = otherwise_node;
+
+ move p to below the otherwise node
+otherwise_node->down = p;
+Node::set_type(p, INVOCATION_LIST_NT);
+Node::set_control_structure_used(p, if_CSP);
+p->next = NULL;
+Node::set_text(p, Wordings::trim_first_word(Node::get_text(p)));
+
+ put the code previously under p under a new code block node under p
+p->down = Node::new(CODE_BLOCK_NT);
+p->down->down = former_contents;
+
+ any further "otherwise if" or "otherwise" nodes after p follow
+p->down->next = former_successors;
+ }
+if (p->down) RuleSubtrees::purge_otherwise_if(p);
+ }
+}
+
+
§5.11. End nodes are now redundant: maybe they got here as explicit "end if" phrases
+in the source text, or maybe they were auto-inserted by the indentation reader,
+but now that the structure is known to be correct they serve no further purpose.
+We remove them.
+
+
+
(h) Remove any end markers as no longer necessary5.11 =
+
§5.15. This all makes a nice tree, but it has the defect that the statements heading
+block-opening phrases (the ifs, whiles, repeats) have child nodes (the blocks
+of code consequent on them). We want them to be leaves for now, so that we
+can append statement-parsing data underneath them later. So we insert blank
+code block nodes to mark these phrases, and transfer the control structure
+annotations to them.
+
+
+
(j) Insert code block nodes so that nodes needing to be parsed are childless5.15 =
+
Issue problem message for comma in a substitution7.1.1.1 =
+
+
+
+Strings::TextSubstitutions::it_is_not_worth_adding();
+StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_TSWithComma),
+"a substitution contains a comma ','",
+"which is against the rules, because 'say' is a special phrase in "
+"which the comma divides items in a list of things to say, and so it "
+"loses its ordinary meanings. Because of this, no text substitution "
+"can contain a comma. "
+"(If you're trying to use a value produced by a phrase with a phrase "
+"option - say 'the best route from A to B, using even locked doors' - "
+"you'll need to put this in a 'let' variable first and then say that, "
+"or else define a better text substitution to do the job for you.)");
+Strings::TextSubstitutions::it_is_worth_adding();
+return;
+
§7.1.1.2. Issue problem message for nested substitution7.1.1.2 =
+
+
+
+Strings::TextSubstitutions::it_is_not_worth_adding();
+if ((p[k+1] == 'u') && (p[k+2] == 'n') && (p[k+3] == 'i') && (p[k+4] == 'c') &&
+ (p[k+5] == 'o') && (p[k+6] == 'd') && (p[k+7] == 'e') && (p[k+8] == ' ')) {
+StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_NestedUSubstitution),
+"the text here contains one substitution '[...]' inside another",
+"which is not allowed. Actually, it looks as if you might have got "
+"into this by typing an exotic character as part of the name of a "
+"text substitution - those get rewritten automatically as '[unicode N]' "
+"for the appropriate Unicode character code number N. Either way - "
+"this isn't allowed.");
+ } else {
+StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_NestedSubstitution),
+"the text here contains one substitution '[...]' inside another",
+"which is not allowed. (If you just wanted a literal open and closed "
+"square bracket, use '[bracket]' and '[close bracket]'.)");
+ }
+Strings::TextSubstitutions::it_is_worth_adding();
+return;
+
§7.1.1.3. Issue problem message for unclosed substitution7.1.1.3 =
+
+
+
+Strings::TextSubstitutions::it_is_not_worth_adding();
+StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_UnclosedSubstitution),
+"the text here uses an open square bracket '[', which opens a substitution "
+"in the text, but doesn't close it again",
+"so that the result is malformed. (If you just wanted a literal open "
+"square bracket, use '[bracket]'.)");
+Strings::TextSubstitutions::it_is_worth_adding();
+return;
+
§7.1.1.4. Issue problem message for unopened substitution7.1.1.4 =
+
+
+
+Strings::TextSubstitutions::it_is_not_worth_adding();
+StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_UnopenedSubstitution),
+"the text here uses a close square bracket ']', which closes a substitution "
+"in the text, but never actually opened it",
+"with a matching '['. (If you just wanted a literal close square bracket, "
+"use '[close bracket]'.)");
+Strings::TextSubstitutions::it_is_worth_adding();
+return;
+
§7.1.1.5. Something devious happens when production (b) of <s-say-phrase> is matched.
+Double-quoted text is literal if it contains no square brackets, but is
+expanded if it includes text substitutions in squares. When (b) matches,
+Inform expands a text such as
+
+
+
+
"Look, [the noun] said."
+
+
+
into:
+
+
+
+
"Look, ", the noun, " said."
+
+
+
and then re-parses the result with the following nonterminal; note that we
+make sure commas are used correctly before handing back to <s-say-phrase>
+to parse the list.
+
+Strings::TextSubstitutions::it_is_not_worth_adding();
+StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_TSWithPunctuation),
+"a substitution contains a '.', ':' or ';'",
+"which suggests that a close square bracket ']' may have gone astray.");
+Strings::TextSubstitutions::it_is_worth_adding();
+
+Strings::TextSubstitutions::it_is_not_worth_adding();
+StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_EmptySubstitution),
+"the text here contains an empty substitution '[]'",
+"which is not allowed. To say nothing - well, say nothing.");
+Strings::TextSubstitutions::it_is_worth_adding();
+
diff --git a/docs/imperative-module/3-tph.html b/docs/imperative-module/3-tph.html
index f6ae85bb9..39ef75f25 100644
--- a/docs/imperative-module/3-tph.html
+++ b/docs/imperative-module/3-tph.html
@@ -403,7 +403,7 @@ is confined to the current Chapter.
}
diff --git a/docs/imperative-module/4-lv.html b/docs/imperative-module/4-lv.html
index f91797b1a..5e95dc71b 100644
--- a/docs/imperative-module/4-lv.html
+++ b/docs/imperative-module/4-lv.html
@@ -148,7 +148,7 @@ marks it as deallocated.
CLASS_DEFINITION} local_variable;
-
The structure local_variable is accessed in 2/dtd, 2/cdp, 3/phr, 3/tph, 3/tp, 4/sf, 5/inv, 5/pi, 5/cii, 5/cp and here.
+
The structure local_variable is accessed in 2/dtd, 2/cdp, 3/rs, 3/phr, 3/tph, 3/tp, 4/sf, 5/inv, 5/pi, 5/cii, 5/cp and here.
§3. A local variable needs to be stored somewhere at run-time. The obvious
correspondence is to put these into I6 local variables, which are, in effect,
CPU registers. We won't need to do much in the way of register-allocation,
diff --git a/docs/imperative-module/5-ci.html b/docs/imperative-module/5-ci.html
index 388f19409..0f289752d 100644
--- a/docs/imperative-module/5-ci.html
+++ b/docs/imperative-module/5-ci.html
@@ -142,7 +142,7 @@ earlier invocation list (in what may be another setting entirely).
LOOP_THROUGH_INVOCATION_LIST(inv, invl) {LOGIF(MATCHING, "C%d: $e\n", pos, inv); pos++;if (Node::get_say_verb(inv)) {
-VerbsAtRunTime::ConjugateVerb_invoke_emit(
+RTVerbs::ConjugateVerb_invoke_emit(Node::get_say_verb(inv),Node::get_modal_verb(inv),Annotations::read_int(inv, say_verb_negated_ANNOT));
@@ -540,7 +540,7 @@ no subsequent lines are looked at.
if (Node::get_say_verb(inv))
-VerbsAtRunTime::ConjugateVerb_invoke_emit(
+RTVerbs::ConjugateVerb_invoke_emit(Node::get_say_verb(inv),Node::get_modal_verb(inv),Annotations::read_int(inv, say_verb_negated_ANNOT));
@@ -561,7 +561,7 @@ no subsequent lines are looked at.
if (Node::get_say_verb(inv))
-VerbsAtRunTime::ConjugateVerb_invoke_emit(
+RTVerbs::ConjugateVerb_invoke_emit(Node::get_say_verb(inv),Node::get_modal_verb(inv),Annotations::read_int(inv, say_verb_negated_ANNOT));
diff --git a/docs/imperative-module/index.html b/docs/imperative-module/index.html
index 91040ee87..e45038632 100644
--- a/docs/imperative-module/index.html
+++ b/docs/imperative-module/index.html
@@ -125,6 +125,11 @@
Introduction to Phrases -
An exposition of the data structures used inside Inform to hold phrases, rules and rulebooks.
+
+
+ Rule Subtrees -
+ To tidy up |INVOCATION_LIST_NT| nodes into a list of children under the relevant |RULE_NT| node, and so turn each rule definition into a single subtree.
+
Construction Sequence -
diff --git a/docs/index-module/2-dr.html b/docs/index-module/2-dr.html
index 34da8c6e9..b7f8898b6 100644
--- a/docs/index-module/2-dr.html
+++ b/docs/index-module/2-dr.html
@@ -331,7 +331,7 @@ following routine.
}}
-voidIndex::DocReferences::link(OUTPUT_STREAM, text_stream *fn) {
+voidIndex::DocReferences::link(OUTPUT_STREAM, text_stream *fn) {Index::DocReferences::link_to_S(OUT, fn, FALSE);}
@@ -472,7 +472,7 @@ and we need to search fairly seldom:
§1. The debugging log. Finally, three ways to describe the run of headings: to the debugging log,
+to the index of the project, and to a freestanding XML file.
+
§3.1.1. We index only headings of level 1 and up — so, not the pseudo-heading or the
+File (0) ones — and which are not within any extensions — so, are in the
+primary source text written by the user.
+
§3.1.2. We skip any objects or kinds without names (i.e., whose creator is null).
+The rest appear in italic type, and without links to source text since this
+in practice strews distractingly many orange berries across the page.
+
+
+
List all the objects and kinds created under the given heading, one tap stop deeper3.1.2 =
+
§4. The XML file. This is provided as a convenience to the application using Inform, which may want
+to have a pull-down menu or similar gadget allowing the user to jump to a given
+heading. This tells the interface where every heading is, thus saving it from
+having to parse the source.
+
+
+
The property list contains a single dictionary, whose keys are the numbers
+0, 1, 2, ..., \(n-1\), where there are \(n\) headings in all. (The pseudo-heading
+is not included.) A special key, the only non-numerical one, called "Application
+Version", contains the Inform build number in its usual form: "4Q34", for instance.
+
+
+
+voidIndexHeadings::write_as_xml(void) {
+text_streamxf_struct; text_stream *xf = &xf_struct;
+filename *F = Task::xml_headings_file();
+if (STREAM_OPEN_TO_FILE(xf, F, UTF8_ENC) == FALSE)
+Problems::fatal_on_file("Can't open headings file", F);
+IndexHeadings::write_headings_as_xml_inner(xf);
+STREAM_CLOSE(xf);
+}
+
+voidIndexHeadings::write_headings_as_xml_inner(OUTPUT_STREAM) {
+heading *h;
+Write DTD indication for XML headings file4.1;
+WRITE("<plist version=\"1.0\"><dict>\n");
+INDENT;
+WRITE("<key>Application Version</key><string>%B (build %B)</string>\n", FALSE, TRUE);
+parse_node_tree *T = Task::syntax_tree();
+LOOP_OVER_LINKED_LIST(h, heading, T->headings->subordinates) {
+WRITE("<key>%d</key><dict>\n", h->allocation_id);
+INDENT;
+Write the dictionary of properties for a single heading4.2;
+OUTDENT;
+WRITE("</dict>\n");
+ }
+OUTDENT;
+WRITE("</dict></plist>\n");
+}
+
§4.2. Note that a level of 0, and a title of --, signifies a File (0) level
+heading: external tools can probably ignore such records. Similarly, it is
+unlikely that they will ever see a record without a "Filename" key —
+this would mean a heading arising from text created internally within Inform,
+which will only happen if someone has done something funny with .i6t files —
+but should this arise then the best recourse is to ignore the heading.
+
+
+
Write the dictionary of properties for a single heading4.2 =
+
diff --git a/docs/index-module/2-li.html b/docs/index-module/2-li.html
index ece7a47d2..14009ad51 100644
--- a/docs/index-module/2-li.html
+++ b/docs/index-module/2-li.html
@@ -617,12 +617,12 @@ of value.
Index::link(OUT, Wordings::first_wn(lex->wording_of_entry));if (lex->part_of_speech == AVERB_LEXE) WRITE(" ... <i>auxiliary verb</i>");elseif (lex->part_of_speech == MVERB_LEXE) WRITE(" ... for saying only");
-elseVerbsAtRunTime::tabulate_meaning(OUT, lex);
+elseRTVerbs::tabulate_meaning(OUT, lex);HTML_CLOSE("p");
-VerbsAtRunTime::tabulate(OUT, lex, IS_TENSE, "present");
-VerbsAtRunTime::tabulate(OUT, lex, WAS_TENSE, "past");
-VerbsAtRunTime::tabulate(OUT, lex, HASBEEN_TENSE, "present perfect");
-VerbsAtRunTime::tabulate(OUT, lex, HADBEEN_TENSE, "past perfect");
+RTVerbs::tabulate(OUT, lex, IS_TENSE, "present");
+RTVerbs::tabulate(OUT, lex, WAS_TENSE, "past");
+RTVerbs::tabulate(OUT, lex, HASBEEN_TENSE, "present perfect");
+RTVerbs::tabulate(OUT, lex, HADBEEN_TENSE, "past perfect");DISCARD_TEXT(entry_text) }}
@@ -651,7 +651,7 @@ be able to print out a table of just those verbs created in that extension.
}
diff --git a/docs/index-module/index.html b/docs/index-module/index.html
index 0cdfea33a..5757a2ec9 100644
--- a/docs/index-module/index.html
+++ b/docs/index-module/index.html
@@ -108,6 +108,11 @@
Index Extensions -
To keep details of the extensions currently loaded, their authors, titles, versions and rubrics, and to index and credit them suitably.
+
+
+ Index Headings -
+ To produce the index contents listing and the XML headings file.
§1. This section simoly sets up the module in ways expected by foundation, and
+
§1. This section simoly sets up the module in ways expected by foundation, and
contains no code of interest. The following constant exists only in tools
which use this module:
defineINFLECTIONS_MODULETRUE
-
§2. This module defines the following classes:
+
§2. This module defines the following classes:
enumlexical_cluster_CLASS
@@ -79,7 +85,7 @@ which use this module:
DECLARE_CLASS(plural_dictionary_entry)DECLARE_CLASS(verb_conjugation)
-
§3. Like all modules, this one must define a start and end function:
+
§3. Like all modules, this one must define a start and end function:
§1. Here we take text such as "UNESCO document" and put an article in front, to
+
§1. Here we take text such as "UNESCO document" and put an article in front, to
get "a UNESCO document" (and not "an UNESCO document": these things are much
trickier than they look).
To inflect adjectives into comparative and superlative forms.
-
§1. In English, the comparative of an adjective can generally be formed by
+
§1. In English, the comparative of an adjective can generally be formed by
suffixing the inflected form with "than"; thus, "big" to "bigger than".
The following does the suffixing:
@@ -69,7 +75,7 @@ The following does the suffixing:
...than
§2. This is essentially a wrapper function for the trie <adjective-to-comparative>.
+
§2. This is essentially a wrapper function for the trie <adjective-to-comparative>.
@@ -96,7 +102,7 @@ The following does the suffixing:
returnPW;}
-
§3. This is essentially a wrapper function for the trie <adjective-to-superlative>.
+
§3. This is essentially a wrapper function for the trie <adjective-to-superlative>.
@@ -119,7 +125,7 @@ The following does the suffixing:
returnPW;}
-
§4. This is essentially a wrapper function for the trie <adjective-to-quiddity>.
+
§4. This is essentially a wrapper function for the trie <adjective-to-quiddity>.
There has to be a better term than "quiddity" for this grammatical concept
(it is some sort of morphological nominalisation) but what I mean is the
property of which the given adjective makes a comparison: for instance,
diff --git a/docs/inflections-module/2-plr.html b/docs/inflections-module/2-plr.html
index 9fcd118f5..718bf520d 100644
--- a/docs/inflections-module/2-plr.html
+++ b/docs/inflections-module/2-plr.html
@@ -40,7 +40,11 @@ function togglePopup(material_id) {
§1. Dictionary. A modest dictionary of plurals is maintained to allow the user to record
+
§1. Dictionary. A modest dictionary of plurals is maintained to allow the user to record
better plurals than the ones we would make ourselves. This assumes that a
plural can be constructed without knowledge of context, but that works in
almost all cases. (Arguably "dwarf" should pluralise to "dwarfs" when
@@ -85,7 +91,7 @@ to be hoped that few works of IF will contain both at once.)
} plural_dictionary_entry;
The structure plural_dictionary_entry is accessed in 3/vc and here.
-
§2. Note that we are entirely allowed to register a new plural for a phrase
+
§2. Note that we are entirely allowed to register a new plural for a phrase
which already has a plural in the dictionary, even for the same language,
which is why we do not trouble to search the existing dictionary here.
@@ -99,7 +105,7 @@ which is why we do not trouble to search the existing dictionary here.
LOGIF(CONSTRUCTED_PLURALS, "[Registering plural of %W as %W]\n", S, P);}
-
§3. Searching the plural dictionary. The following routine can either be called once only — in which case it
+
§3. Searching the plural dictionary. The following routine can either be called once only — in which case it
yields up the best known plural for the phrase — or iteratively, in which
case it serves up all known plurals of the given phrase, starting with the
best (the earliest defined in the text, if any plural for this phrase has
@@ -131,7 +137,7 @@ one not found in the dictionary).
returnNULL;}
-
§3.1. When the dictionary fails us, we use lexical rewriting to construct plurals
+
§3.1. When the dictionary fails us, we use lexical rewriting to construct plurals
of phrases found only in the singular in the source. For instance, if the
designer says that "A wicker basket is a kind of container" then Inform will
need to recognise not only "wicker basket" but also "wicker baskets", a
@@ -163,7 +169,7 @@ it can be rebuilt quickly whenever needed again.
LOGIF(CONSTRUCTED_PLURALS, "[Constructing plural of %W as %W]\n", W, *PW);
§4. The pluralizing trie. The following takes a single word, assumes it to be a noun which meaningfully
+
§4. The pluralizing trie. The following takes a single word, assumes it to be a noun which meaningfully
has a plural, and modifies it to the plural form.
diff --git a/docs/inflections-module/2-pp.html b/docs/inflections-module/2-pp.html
index d1825bfe5..a6c1bd6e9 100644
--- a/docs/inflections-module/2-pp.html
+++ b/docs/inflections-module/2-pp.html
@@ -40,7 +40,11 @@ function togglePopup(material_id) {
§1. Constructing past participles. For example, "turning away" to "turned away".
+
§1. Constructing past participles. For example, "turning away" to "turned away".
@@ -95,7 +101,7 @@ function togglePopup(material_id) {
returnPLW;}
-
§2. The pasturising trie. This is the process of turning a present participle, like "turning", to
+
§2. The pasturising trie. This is the process of turning a present participle, like "turning", to
a past participle, like "turned". Note that it returns NULL if it fails
to recognise the word in question as a present participle; this is needed
above. It expects only a single word.
diff --git a/docs/inflections-module/2-tai.html b/docs/inflections-module/2-tai.html
index 58253b7ed..9ecc53060 100644
--- a/docs/inflections-module/2-tai.html
+++ b/docs/inflections-module/2-tai.html
@@ -40,7 +40,11 @@ function togglePopup(material_id) {
§1. Suffix inflections. The following inflects the ending of the supplied text. It does so by
+
§1. Suffix inflections. The following inflects the ending of the supplied text. It does so by
running the text through an avinue: see Tries and Avinues (in foundation),
which is where the asterisk notation is handled.
§2. The foundation code returns a result which may be null, if no match
+
§2. The foundation code returns a result which may be null, if no match
was found. In that event, we leave the text unchanged, just as if the result
had been 0 — meaning "change nothing".
@@ -96,7 +102,7 @@ had been 0 &mda
returnsuccess;}
-
§2.1. In general the result either has an initial digit, in which case it removes
+
§2.1. In general the result either has an initial digit, in which case it removes
that many terminal letters, or does not, in which case it removes all the
letters (and thus the result text replaces the original entirely).
The special character + after a digit means "duplicate the last character";
@@ -125,7 +131,7 @@ add "ize".
}
§3. General tries. Here we take a word assemblage and apply suffix inflection to the first word
+
§3. General tries. Here we take a word assemblage and apply suffix inflection to the first word
alone, preserving the rest: for example, "make the tea" might become "making
the tea". However, if the result of this inflection contains any + signs,
those once again become word boundaries.
diff --git a/docs/inflections-module/3-dcl.html b/docs/inflections-module/3-dcl.html
index 9c36ac6fe..318342e11 100644
--- a/docs/inflections-module/3-dcl.html
+++ b/docs/inflections-module/3-dcl.html
@@ -54,7 +54,11 @@ MathJax = {
Declensions are sets of inflected variations of a common stem according to grammatical case.
-
§1. The traditional term "declension" refers to the set of inflected forms of a
+
§1. The traditional term "declension" refers to the set of inflected forms of a
word which does not serve as a verb: nouns, adjectives and pronouns all have
"declensions". These forms generally vary according to gender, number and
also "case", which expresses context.
@@ -102,7 +108,7 @@ taken care of by what are less elegantly called } declension;
§9. We have now found the actual declension table NT; if there are \(N\) cases
+
§9. We have now found the actual declension table NT; if there are \(N\) cases
in the language, there will be \(2N\) productions in this table, each of which
consists of a single word giving the rewriting instruction to use.
@@ -375,7 +381,7 @@ consists of a single word giving the rewriting instruction to use.
returnD;}
-
§2. There are six "persons". The sequence corresponds to the defined constants
+
§2. There are six "persons". The sequence corresponds to the defined constants
in the English Language extension, which we assume will be followed by other
languages.
§6. 25 cases sounds like plenty, but some languages are pretty scary this
+
§6. 25 cases sounds like plenty, but some languages are pretty scary this
way: Hungarian has 18. We only require two cases to exist, the nominative
and accusative, which are required to be cases 0 and 1.
@@ -130,7 +136,7 @@ and accusative, which are required to be cases 0 and 1.
defineNOMINATIVE_CASE0defineACCUSATIVE_CASE1
-
§7. There are at least five tenses, the first four of which are used by Inform
+
§7. There are at least five tenses, the first four of which are used by Inform
in English. Some languages can use optional extras; French, for example, uses
tense 5 for the past historic.
@@ -144,7 +150,7 @@ tense 5 for the past historic.
defineCUSTOM1_TENSE5defineCUSTOM2_TENSE6
-
§8. Packed references. The following enables even a 32-bit integer to hold an ID reference in the
+
§8. Packed references. The following enables even a 32-bit integer to hold an ID reference in the
range 0 to 128K, together with any combination of gender, person, number,
voice, case, tense, and sense. This could be optimised further, exploiting
for example that no grammatical concept ever simultaneously has voice and
@@ -161,7 +167,7 @@ values, and at present Preform return values are definelcon_tiint
-
§9. And here's how we pack everything in:
+
§9. And here's how we pack everything in:
@@ -268,7 +274,7 @@ values, and at present Preform return values are }}
-
§10.
+
§10.
intLcon::same_but_for_gender(lcon_tiA, lcon_tiB) {
@@ -306,7 +312,7 @@ values, and at present Preform return values are returnFALSE;}
-
§11. Axes. We can think of a combination of the seven grammatical attributes above as
+
§11. Axes. We can think of a combination of the seven grammatical attributes above as
being like a position in seven-dimensional space, with each being a coordinate
on one of these sevem axes.
@@ -325,7 +331,7 @@ sum of these can represent a set of things we're interested in:
defineTENSE_LCW32defineSENSE_LCW64
-
§12. And desiderata in the following function is exactly that sort of set.
+
§12. And desiderata in the following function is exactly that sort of set.
@@ -337,7 +343,7 @@ sum of these can represent a set of things we're interested in:
}}
-
§13. The parameter axis in the following must, on the other hand, be a pure power
+
§13. The parameter axis in the following must, on the other hand, be a pure power
of 2, that is, it must be a single *_LCW value.
@@ -383,7 +389,7 @@ of 2, that is, it must be a single return0;}
-
§14. Writing sets. Suppose we have a list of lcon_ti constants and want to print out their
+
§14. Writing sets. Suppose we have a list of lcon_ti constants and want to print out their
grammatical attributes. If we do that in the obvious way, by calling
Lcon::write on each of the constants in turn, we tend to get a list
of tiresome length. We want to abbreviate so that, e.g.,
@@ -408,7 +414,7 @@ code is really only needed for printing tidy debugging and test logs, so
it's probably not worth any further effort.
-
§15. To avoid the C extension for variable-length arrays, and to avoid memory
+
§15. To avoid the C extension for variable-length arrays, and to avoid memory
allocation, we're simply going to make our working arrays quite large. But
this is fine — the function is for printing, so it's not used much.
@@ -417,7 +423,7 @@ this is fine — the function is for printing, so it's not used much.
NO_KNOWN_GENDERS*NO_KNOWN_PERSONS*NO_KNOWN_NUMBERS*NO_KNOWN_VOICES*NO_KNOWN_SENSES*MAX_GRAMMATICAL_CASES*NO_KNOWN_TENSES
-
§16. We are going to aggregate items in the list into numbered cuboids. The
+
§16. We are going to aggregate items in the list into numbered cuboids. The
strategy is simple: start with the first item; make the largest-volume cuboid
inside our set which contains that item; then take the next item not already
included, and continue.
@@ -434,7 +440,7 @@ included, and continue.
}}
-
§16.1. Note that there is always at least one cuboid containing the item \(i\) —
+
§16.1. Note that there is always at least one cuboid containing the item \(i\) —
the \(1\times 1\times 1\times 1\times 1\times 1\times 1\) cuboid containing
just that one point. So the following certainly finds something. The
elongated_sides value accumulates the set of axis directions in which
@@ -452,7 +458,7 @@ the cuboid is longer than 1.
Write the resulting cuboid out16.1.2;
§16.1.1. So now we are at item \(i\). We repeatedly do the following: try to expand
+
§16.1.1. So now we are at item \(i\). We repeatedly do the following: try to expand
the cuboid into each of the seven axis directions, then choose the one
which expands it the most. We stop when no further expansion is possible.
@@ -480,7 +486,7 @@ which expands it the most. We stop when no further expansion is possible.
} while (max_elongation > 0);
§16.1.1.1. We start with the current cuboid. The enlarged array will be the same as
+
§16.1.1.1. We start with the current cuboid. The enlarged array will be the same as
the cuboid_number array except that some additional points x for which
cuboid_number[x] is \(-1\) — i.e., points not yet placed in any cuboid —
will have enlarged[x] set to cuboid — i.e., will be placed in the current
@@ -504,7 +510,7 @@ coordinates are the same as those for \(i\).
if (allow == FALSE) elongation = 0;
§16.1.1.1.1. For example, if \(i = (2, 1, 0, 0, 0, 0, 0)\) and \(d\) is the second axis, then
+
§16.1.1.1.1. For example, if \(i = (2, 1, 0, 0, 0, 0, 0)\) and \(d\) is the second axis, then
one variation would be 1 (the \(d\) coordinate of \(i\) itself) and if, say,
\((2, 7, 0, 0, 0, 0, 0)\) were an unplaced point then 7 would also be a variation.
@@ -521,7 +527,7 @@ one variation would be 1 (the \(d\) coordinate of \(i\) itself) and if, say,
}
§16.1.1.1.2. Now suppose our variation set is indeed \(\lbrace 1, 7\rbrace\), as in the
+
§16.1.1.1.2. Now suppose our variation set is indeed \(\lbrace 1, 7\rbrace\), as in the
above example. The idea is that we will use this set as the new side for the
cuboid. We know that we can vary \(i\) by these values; that's how they were
found. But we must also check that we can vary every other point currently
@@ -550,7 +556,7 @@ in the cuboid in the same way. If we can't, the attempt fails.
}
§16.1.2. And finally, but also not quite trivially, printing out the cuboid. We
+
§16.1.2. And finally, but also not quite trivially, printing out the cuboid. We
handle the elongated sides differently from the unelongated ones, which
are relegated to the Lcon::write call at the end. Note that this prints
nothing if remainder is zero.
diff --git a/docs/inflections-module/3-lc2.html b/docs/inflections-module/3-lc2.html
index 9b46d6152..c767f375c 100644
--- a/docs/inflections-module/3-lc2.html
+++ b/docs/inflections-module/3-lc2.html
@@ -40,7 +40,11 @@ function togglePopup(material_id) {
§1. Cluster. A cluster is a linked list of declensions, annotated with lingistic roles. For
+
§1. Cluster. A cluster is a linked list of declensions, annotated with lingistic roles. For
example, the cluster of forms for the common noun "man" might be:
@@ -99,7 +105,7 @@ which it would be fairly easy to convert our } individual_form;
The structure lexical_cluster is private to this section.
The structure individual_form is private to this section.
-
§2. A cluster begins empty.
+
§2. A cluster begins empty.
@@ -109,7 +115,7 @@ which it would be fairly easy to convert our
returnforms;}
-
§3. The following can add either a single form, or a form and its plural(s):
+
§3. The following can add either a single form, or a form and its plural(s):
@@ -131,7 +137,7 @@ which it would be fairly easy to convert our
returnL;}
-
§3.1. The following makes all possible plurals and registers those too. (Note
+
§3.1. The following makes all possible plurals and registers those too. (Note
that every instance gets a plural form: even something palpably unique, like
"the Koh-i-Noor diamond".) The plural dictionary supports multiple plurals,
so there may be any number of forms registered: for instance, the kind
@@ -156,7 +162,7 @@ so there may be any number of forms registered: for instance, the kind
} while (pde);
§4. The following is more suited to adjectives, or to words which are used
+
§4. The following is more suited to adjectives, or to words which are used
adjectivally, such as past participles in French. This time we generate all
possible gender and number agreements.
§5. Plural fixing. Less elegantly, we can force the plural of a form in a cluster to a given
+
§5. Plural fixing. Less elegantly, we can force the plural of a form in a cluster to a given
fixed text, overwriting it if it's already there. In practice this is done
only when the built-in kinds are being given plural forms; some of these
(those for kind constructors with optional wordings) have a peculiar format,
@@ -250,7 +256,7 @@ and wouldn't pass through the pluralising tries intact.
Clusters::add(cl, W, NULL, NEUTER_GENDER, PLURAL_NUMBER, FALSE);}
-
§6. Searching declensions. These are always quite small, so there's no need for any efficient device
+
§6. Searching declensions. These are always quite small, so there's no need for any efficient device
to search them.
@@ -269,7 +275,7 @@ or plural):
returnEMPTY_WORDING;}
-
§7. The following variant finds the earliest form in the language of play,
+
§7. The following variant finds the earliest form in the language of play,
falling back on English if there's none registered:
@@ -286,7 +292,7 @@ falling back on English if there's none registered:
returnClusters::get_form(cl, plural_flag);}
-
§8. A more specific search, which can optionally test for number and gender.
+
§8. A more specific search, which can optionally test for number and gender.
@@ -305,7 +311,7 @@ falling back on English if there's none registered:
returnin->declined.within_language;}
-
§9. All of which use:
+
§9. All of which use:
diff --git a/docs/inflections-module/3-vc.html b/docs/inflections-module/3-vc.html
index 39d026cf4..4dca46ecb 100644
--- a/docs/inflections-module/3-vc.html
+++ b/docs/inflections-module/3-vc.html
@@ -41,7 +41,11 @@ function togglePopup(material_id) {
§1. We will need to turn a base form of a verb — in English, this is always the
+
§1. We will need to turn a base form of a verb — in English, this is always the
infinitive — into up to 123 variants; we manage this with quite an extensive
data structure. There will typically only be a few dozen fully conjugated
verbs in any source text, though, so the memory cost isn't too extreme. For
@@ -104,7 +110,7 @@ English it looks wasteful, since so many forms are the same, but for French
} verb_tabulation;
The structure verb_conjugation is accessed in 2/plr and here.
The structure verb_tabulation is private to this section.
-
§2. Finding. Most of the time, conjugations can be identified by their infinitives:
+
§2. Finding. Most of the time, conjugations can be identified by their infinitives:
@@ -116,7 +122,7 @@ English it looks wasteful, since so many forms are the same, but for French
returnNULL;}
-
§3. But in fact multiple conjugations can be given with the same infinitive...
+
§3. But in fact multiple conjugations can be given with the same infinitive...
@@ -129,7 +135,7 @@ English it looks wasteful, since so many forms are the same, but for French
returnNULL;}
-
§4. ...and those may or may not be identical, so a more detailed test is:
+
§4. ...and those may or may not be identical, so a more detailed test is:
@@ -158,7 +164,7 @@ English it looks wasteful, since so many forms are the same, but for French
returnFALSE;}
-
§5. The following prints out a tidy form of a verb conjugation table:
+
§5. The following prints out a tidy form of a verb conjugation table:
@@ -195,7 +201,7 @@ English it looks wasteful, since so many forms are the same, but for French
&(vc->tabulations[PASSIVE_VOICE].to_be_auxiliary));}
-
§6. Making conjugations. The following will make more sense if read alongside the examples in "English
+
§6. Making conjugations. The following will make more sense if read alongside the examples in "English
Inflections", which explains the format in full.
§6.2. This feature is provided so that English verb definitions can override the
+
§6.2. This feature is provided so that English verb definitions can override the
usual grammatical rules, which enables us to create new irregular verbs.
For example, Inform will by default make the past participle "blended" out
of the verb "to blend", but a definition like
@@ -266,7 +272,7 @@ anybody else try this one on.)
verb_forms[k] = overrides[k];
§6.3.2. A tabulation is a sort of program laying out what to put in which slots,
+
§6.3.2. A tabulation is a sort of program laying out what to put in which slots,
active or passive. Each production is a step in this program, and it consists
of a "selector" followed by a "line". For example, the production:
@@ -340,7 +346,7 @@ rest. (The selector is always just a single token.)
}
§6.3.2.1.3. The selector tells us which tense(s), sense(s) and voice(s) to apply the
+
§6.3.2.1.3. The selector tells us which tense(s), sense(s) and voice(s) to apply the
line to; a3, for example, means active voice, tense 3, in both positive
and negative senses.
§7. This routine is really an interloper from core. It provides the run-time
+
§7. This routine is really an interloper from core. It provides the run-time
values representing verbs in story files compiled by Inform.
@@ -429,7 +435,7 @@ values representing verbs in story files compiled by Inform.
vc->vc_iname = Hierarchy::make_iname_in(MODAL_CONJUGATION_FN_HL, R); } else {package_request *R =
-VerbsAtRunTime::package(vc->vc_conjugates, vc->where_vc_created);
+RTVerbs::package(vc->vc_conjugates, vc->where_vc_created);TEMPORARY_TEXT(ANT)WRITE_TO(ANT, "to %A", &(vc->infinitive));Hierarchy::markup(R, VERB_NAME_HMD, ANT);
@@ -441,7 +447,7 @@ values representing verbs in story files compiled by Inform.
}#endif
-
§8. Follow instructions. That completes the top level of the routine, but it depended on two major
+
§8. Follow instructions. That completes the top level of the routine, but it depended on two major
sub-steps: a preliminary pass called Conjugation::follow_instructions and
a routine to deal with the final results called Conjugation::merge.
@@ -474,7 +480,7 @@ participles and then chooses the tabulation returntabulation_nt;}
-
§8.1. Pattern match on the base text to decide which conjugation to use8.1 =
+
§8.1. Pattern match on the base text to decide which conjugation to use8.1 =
@@ -493,7 +499,7 @@ participles and then chooses the tabulation }
§8.1.1. Each production in this language's <verb-conjugation-instructions> grammar
+
§8.1.1. Each production in this language's <verb-conjugation-instructions> grammar
consists of a (possibly empty) pattern to match, followed by the name of a
nonterminal to use as the conjugation if it matches. For example, in
@@ -540,7 +546,7 @@ infinitive" form is set to the part matched by "malformed line");
§8.2. In a conjugation, productions have two possible forms: either just a single
+
§8.2. In a conjugation, productions have two possible forms: either just a single
nonterminal, which usually identifies the tabulation, or a number followed by some
tokens.
§8.2.1. So here we check the more interesting case. The number identifies which
+
§8.2.1. So here we check the more interesting case. The number identifies which
verb form to set, and the token which follows it provides the content. For
example:
§9. Merge verb material. Now the final main step. row points to a list of ptokens containing text,
+
§9. Merge verb material. Now the final main step. row points to a list of ptokens containing text,
and we have to copy that text into a word assemblage and return it.
§9.1. To take the easiest case first. If we read a word like trailing, we simply
+
§9.1. To take the easiest case first. If we read a word like trailing, we simply
add it. But note that Conjugation::expand_with_endings has other tricks up its sleeve,
and might expand 3+ed to "trailed".
§9.2. If we read a nonterminal name, such as <fr-vivre-present>, then this must
+
§9.2. If we read a nonterminal name, such as <fr-vivre-present>, then this must
be a grammar with six productions, giving the text to use for the six different
persons. We consult person and extract the relevant text. For example, if
person is 3, we extract "vivons". Note that this material is itself read
@@ -728,7 +734,7 @@ make use of the same fancy features we're allowing here.
}
§9.4. And now the lift takes place. We might at this point have verb_form_to_lift
+
§9.4. And now the lift takes place. We might at this point have verb_form_to_lift
set, in which case we should lift a verb form, or we might not, in which case
we should lift an ordinary usage, such as third-person singular in a particular
tense. A lift can optionally change tense or sense: for example,
@@ -804,7 +810,7 @@ make use of the numbered verb forms if we want it to.
}
§10. Whenever we read a single word, it passes through the following. A word
+
§10. Whenever we read a single word, it passes through the following. A word
like "fish" will pass through unchanged; a number like "7" will convert
to verb form 7 in the current verb (for example, 2 becomes the present
participle); a plus sign joins two pieces together; and a tilde is a tie,
@@ -857,7 +863,7 @@ joining but with a space. Thus returnWordAssemblages::lit_1(ve);}
-
§11. The final step in merging verb material is to pass the result through the
+
§11. The final step in merging verb material is to pass the result through the
following, which attends to contractions. (Most of the time it does nothing.)
For example, suppose we have:
@@ -923,7 +929,7 @@ we see a -'returnwa;}
-
§11.1. We contract if the following word starts with a (possibly accented) vowel,
+
§11.1. We contract if the following word starts with a (possibly accented) vowel,
and we construe "y" (but not "h" or "w") as a vowel.
@@ -938,7 +944,7 @@ and we construe "y" (but not "h" or "w") as a vowel.
contract_this = TRUE;
§18. This is for testing English only; it helps with the test suite cases derived
+
§18. This is for testing English only; it helps with the test suite cases derived
from our dictionary of 14,000 or so present and past participles.
@@ -1061,7 +1067,7 @@ from our dictionary of 14,000 or so present and past participles.
&(vc->infinitive), &(vc->present_participle), &(vc->past_participle));}
-
§19. As noted above, these nonterminals have no parsing function, and are used only
+
§19. As noted above, these nonterminals have no parsing function, and are used only
as markers in verb conjugations.
diff --git a/docs/inflections-module/4-dl.html b/docs/inflections-module/4-dl.html
index e38047601..5a3b86c78 100644
--- a/docs/inflections-module/4-dl.html
+++ b/docs/inflections-module/4-dl.html
@@ -40,7 +40,11 @@ function togglePopup(material_id) {
§1. Noun inflections. The following trie looks at the start of a word, which we assume to be a
+
§1. Noun inflections. The following trie looks at the start of a word, which we assume to be a
noun, and decides whether to use the indefinite article "a" or "an".
This is much more complicated than simply looking for a vowel as the first
letter, as people often think until they try a few cases.
@@ -78,7 +84,7 @@ dictionary and the "Official Scrabble Wordlist".
<en-trie-indef-c>
§5. Plural inflections. The following takes a single word, assumes it to be a noun which meaningfully
+
§5. Plural inflections. The following takes a single word, assumes it to be a noun which meaningfully
has a plural, and modifies it to the plural form. ("Golf" is a noun which
doesn't sensibly have a plural; the algorithm here would return "golves".)
@@ -267,7 +273,7 @@ of a sibilant plus "o" suffix to include an "e", so that Conway produces
...<en-trie-plural-append-s>
§6. See Conway's table A.2. The following nouns, mostly names of kinds of animal,
+
§6. See Conway's table A.2. The following nouns, mostly names of kinds of animal,
have the same plural as singular form: for example, chamois, salmon, goldfish.
@@ -325,7 +331,7 @@ have the same plural as singular form: for example, chamois, salmon, goldfish.
pincers0
§9. Step 5. Now we reach a batch of irregular but fairly general inflected
+
§9. Step 5. Now we reach a batch of irregular but fairly general inflected
endings; for example, protozoon to protozoa, or metamorphosis to metamorphoses.
Note that we differ from Conway in pluralizing blouse as blouses, not blice.
@@ -395,7 +401,7 @@ Note that we differ from Conway in pluralizing blouse as blouses, not blice.
*xis3xes
§11. Step 11a. (We're not implementing Conway's steps in sequence: see below.)
+
§11. Step 11a. (We're not implementing Conway's steps in sequence: see below.)
These -o endings are mostly loan words from Romance languages whose original
inflections are assimilated.
@@ -468,7 +474,7 @@ inflections are assimilated.
tempotempos
§14. Verb inflections. "Le verbe est l'âme d'une langue" (attributed to Georges Duhamel). And the
+
§14. Verb inflections. "Le verbe est l'âme d'une langue" (attributed to Georges Duhamel). And the
care of the soul is, of course, complicated. For example, the source text can
say something like this:
@@ -599,7 +605,7 @@ of the possibilities we need to make, and write a trie to handle each one.
is, how the different word forms map onto the possible tenses, persons,
numbers, and so on.
-
§15. This gives us a certain amount of choice. What exactly is "too irregular"?
+
§15. This gives us a certain amount of choice. What exactly is "too irregular"?
In French, are all -er, -ir, and -re verbs "regular"? (Consider "aller",
for example.) In English, it's possible to say that there are seven or so
classes of verbs, all regular by their own standards; but most people say
@@ -634,7 +640,7 @@ example, to set has just three distinct forms — to set, he sets, he set, h
had set, setting.
-
§16. Form types are numbered from 0 up to, potentially, a constant
+
§16. Form types are numbered from 0 up to, potentially, a constant
called MAX_FORM_TYPES. (This is so large that there shouldn't ever be need
for more.) Form type 0 is always the original text, and is used as the basis
from which the others are generated. For English verbs Inform always sets form
@@ -661,7 +667,7 @@ each language. English needs two: the present (5) and past (6) forms.
defineADJOINT_INFINITIVE_FORM_TYPE4defineMAX_FORM_TYPES123
-
§17. We're now ready to write the <verb-conjugation-instructions>. This is
+
§17. We're now ready to write the <verb-conjugation-instructions>. This is
a block which looks at the infinitive of the verb and decides which of
several conjugations should be used. Badly irregular verbs get
conjugations of their own, and others are grouped together. In French,
@@ -687,7 +693,7 @@ least one line, and the best way to ensure that is to finish up with
-
§18. The instructions for English are quite concise, except for the presence
+
§18. The instructions for English are quite concise, except for the presence
of the awkward contracted informal forms of verbs. (These aren't used in
Inform assertion sentences, but are needed for text substitutions.)
@@ -721,7 +727,7 @@ Inform assertion sentences, but are needed for text substitutions.)
...<regular-verb-conjugation>
§19. We will start with two auxiliary verbs, that is, verbs used to construct
+
§19. We will start with two auxiliary verbs, that is, verbs used to construct
forms of other verbs. The first is "to have"; as we'll see, English uses
this to construct perfect tenses:
@@ -784,7 +790,7 @@ for "[have]".
<to-have-tabulation>
§20. Tabulations give instructions for how to construct 120 possible versions
+
§20. Tabulations give instructions for how to construct 120 possible versions
of the verb. These are divided up first into active and passive "voices":
@@ -923,7 +929,7 @@ are used for the six persons.
a2-hadnot
§21. And this is an example of splitting into cases for the six persons,
+
§21. And this is an example of splitting into cases for the six persons,
1PS, 2PS, 3PS, 1PP, 2PP, 3PP. I have, you have, he has, we have, you have,
they have. (This is more excitingly varied in other languages, of course.)
@@ -933,7 +939,7 @@ they have. (This is more excitingly varied in other languages, of course.)
have|have|has|have|have|have
§22. Next we have "to do", which is like "to have" in being fairly regular,
+
§22. Next we have "to do", which is like "to have" in being fairly regular,
as irregular verbs go. But we treat this as a special case because, again,
we're going to need as an auxiliary verb when forming negatives ("Peter
does not wear the hat" — note the "does not"). But this time we give
@@ -999,7 +1005,7 @@ may have to revisit this for languages other than English.)
do|do|does|do|do|do
§23. Regular English verbs, then, look like so. We will, for the first time,
+
§23. Regular English verbs, then, look like so. We will, for the first time,
make heavy use of our numbered verb forms: for example, for the verb
"to take", they would be "take" (1), "taking" (2), "taken" (3),
"takes" (5) and "took" (6). We start with the infinitive ("take")
@@ -1031,7 +1037,7 @@ to "grabs onto", "grabbing onto" and so on.
<regular-verb-tabulation>
§24. Here we see our auxiliary verbs in use. For the negated present tense,
+
§24. Here we see our auxiliary verbs in use. For the negated present tense,
"Peter does not carry the ball"; for the negated past tense, "Peter did
not carry the ball" — in both cases, this is "to do" plus the infinitive
"take". For the perfect tenses, "to have" plus the past participle —
@@ -1055,7 +1061,7 @@ a bequest".)
p*3by
§25. This looks odd, but what it says is that the present tense of a regular
+
§25. This looks odd, but what it says is that the present tense of a regular
English verb is always the infinitive (I take, you take, we take, and so on)
except for third person singular (he takes), which is different. (It's usually
what the plural of the infinitive would be if the infinitive were a noun,
@@ -1067,7 +1073,7 @@ as we'll see.)
1|1|5|1|1|1
§27. Except for tense formation (Peter "will" take the ball), the most common
+
§27. Except for tense formation (Peter "will" take the ball), the most common
modal verb which can be used in Inform source text is "can". For example:
@@ -1132,7 +1138,7 @@ to elide, so we always pronounce it that way and the spelling now follows.
a5-willnotbeableto++1
§28. Inform has only a simple understanding of what "can" means, so it doesn't
+
§28. Inform has only a simple understanding of what "can" means, so it doesn't
allow the source text to use "can" in combination with arbitrary verbs.
Instead, each legal combination has to be declared explicitly:
§29. The following handles the other English modal verbs ("might", "should"
+
§29. The following handles the other English modal verbs ("might", "should"
and so on) surprisingly easily. The notation ++1 means that the verb
being modified should appear in verb form 1, and so on: for example,
"might not lead" as "might not" plus form 1 of "to lead", i.e., "lead".
@@ -1200,7 +1206,7 @@ being modified should appear in verb form 1, and so on: for example,
a5-4not++1
§30. That completes our basic kit of verbs nicely. What's left is used only
+
§30. That completes our basic kit of verbs nicely. What's left is used only
for generating text at run-time — for printing adaptive messages, that is;
none of these oddball exceptional cases is otherwise used as a verb in
Inform source text. None of them has any meaning to Inform.
@@ -1262,7 +1268,7 @@ dialects — and we aren't even going to try to cope with that.
wasn't|weren't|wasn't|weren't|weren't|weren't
§32. Now we come to "aren't", a negated form of "to be", but where the
+
§32. Now we come to "aren't", a negated form of "to be", but where the
contraction occurs between the verb and the "not" rather than between
the subject and the verb.
@@ -1351,7 +1357,7 @@ that option here.)
haven'tbeen|haven'tbeen|hasn'tbeen|haven'tbeen|haven'tbeen|haven'tbeen
§35. We have special tries just to list the forms of the cases we will
+
§35. We have special tries just to list the forms of the cases we will
deal with. Tries can do fancy things (see below), but here they act just as
a look-up table: for example, "won't" has present "won't", past
"wouldn't" and future "won't".
@@ -1450,7 +1456,7 @@ signs can be used if we absolutely have to introduce spaces.
shouldn'tshouldn't
§36. That's the end of the conjugations — the easy part, it turns out. We now
+
§36. That's the end of the conjugations — the easy part, it turns out. We now
need to create the four tries to make verb forms out of the infinitive:
the present participle, the past participle, the third-person singular
present tense, and the past tense.
@@ -1493,7 +1499,7 @@ no easy way to tell. Consider deter to deterring (stress on second syllable
of deter), but meter to metering (stress on first syllable of meter).
-
§37. The following algorithm is due to Toby Nelson, who produced it from a
+
§37. The following algorithm is due to Toby Nelson, who produced it from a
dictionary of 14,689 English verbs, some of them quite obscure (to torpefy,
anyone? to spuilzie? to cachinnate?). It's essentially a more detailed
version of Greenbaum's rules above.
@@ -1508,7 +1514,7 @@ version of Greenbaum's rules above.
...<en-trie-regular-c-present-participle>
§38. First of all there are some irregular cases — some for the usual suspects,
+
§38. First of all there are some irregular cases — some for the usual suspects,
but others for oddball verbs where English breaks the normal phonetic rules
for the sake of clarity. For example, the participle of "singe" ought to
be "singing", but in fact we write "singeing", purely to make it different
@@ -1704,7 +1710,7 @@ from the act of producing a song.
undersaye1ing
§42. Next the past participle. As noted above, for most verbs this is the same
+
§42. Next the past participle. As noted above, for most verbs this is the same
as the past (e.g., he agreed and it was agreed); but there's a list of
exceptions for Anglo-Saxon survivals (e.g., he chose and it was chosen).
The exceptional cases were derived from Wikipedia's catalogue of irregular
@@ -1958,7 +1964,7 @@ removed.
writewritten
§43. That's the mandatory participles sorted out; so now we move on to the two
+
§43. That's the mandatory participles sorted out; so now we move on to the two
additional verb forms used by English. First, the present form: a curiosity
of English is that this is almost always formed as if it were the plural of the
infinitive — thus "touch" becomes "touches". There are just a handful
@@ -1976,7 +1982,7 @@ of exceptions to this.
dodoes
§44. Second, the past. This is harder. Once again we have a catalogue of
+
§44. Second, the past. This is harder. Once again we have a catalogue of
Anglo-Saxon past forms (e.g., he chose, not he chooses); and after those
are out of the way, the rules are the same as for the present participle,
except for adding -ed instead of -ing. The tricky part, again, is spotting
@@ -2609,7 +2615,7 @@ when to double the consonant, which again depends on stress.
*0ed
§47. Grading of adjectives is more interesting. These spelling rules are taken
+
§47. Grading of adjectives is more interesting. These spelling rules are taken
from the Oxford English Grammar at 4.24, "Gradability and comparison".
Something we can't easily implement is that a final vowel plus consonant
doesn't result in doubling the consonant (in the way that "big" becomes
@@ -3171,7 +3177,7 @@ rare in English adjectives.
*0est
§48. To the best of my knowledge there's no technical term for "the noun which
+
§48. To the best of my knowledge there's no technical term for "the noun which
is formed from an adjective to refer to the quality it measures", so the
Inform source code calls this the "quiddity". English permits several
competing forms of these to be constructed, depending on the adjective's
@@ -3191,7 +3197,7 @@ sometimes less elegant, but never means the wrong thing.
*0ness
§49. English has almost no noun cases at all, with the only exceptions being
+
§49. English has almost no noun cases at all, with the only exceptions being
Anglo-Saxon pronouns (thus we distinguish "they" and "them" as nominative
and accusative, for example); and pronouns we handle separately in any
case. We won't bother to distinguish gender:
@@ -3205,7 +3211,7 @@ case. We won't bother to distinguish gender:
*<en-noun-declension-group><en-noun-declension-tables>
§1. Status. The inflections module is provided as one of the "services" suite of modules,
+
§1. Status. The inflections module is provided as one of the "services" suite of modules,
which means that it was built with a view to potential incorporation in
multiple tools. It can be found, for example, in inform7 and
inflections-test.
@@ -74,7 +80,7 @@ other modules except for words and syntax.
-
§2. Importing the module. We'll use the term "parent" to mean the tool which is importing inflections,
+
§2. Importing the module. We'll use the term "parent" to mean the tool which is importing inflections,
that is, which will include its code and be able to use it. As with any
imported module,
@@ -89,7 +95,7 @@ module:
InflectionsModule::end() just before it shuts down. (But just after, and just
before, the corresponding calls to foundation.)
-
§3. This module has no callback functions to modify its behaviour.
+
§3. This module has no callback functions to modify its behaviour.