diff --git a/docs/core-module/1-wtc.html b/docs/core-module/1-wtc.html
index f53d670a7..ea0f2d3e2 100644
--- a/docs/core-module/1-wtc.html
+++ b/docs/core-module/1-wtc.html
@@ -213,7 +213,7 @@ rough stages. Twenty is plenty.
return inform7_task -> project -> as_copy -> edition ;
}
-parse_node_tree * Task::syntax_tree ( void ) {
+parse_node_tree * Task::syntax_tree ( void ) {
return latest_syntax_tree ;
}
diff --git a/docs/core-module/10-aots.html b/docs/core-module/10-aots.html
index 30f50ad63..fb65e6a26 100644
--- a/docs/core-module/10-aots.html
+++ b/docs/core-module/10-aots.html
@@ -330,7 +330,7 @@ context.
preform_lookahead_mode = plm ;
Write the newly discovered specification to the cache for future use 13.2 ;
- VerifyTree::verify_structure ( spec );
+ VerifyTree::verify_structure_from ( spec );
return spec ;
}
diff --git a/docs/core-module/10-varc.html b/docs/core-module/10-varc.html
index 111e86cf2..4bf11387b 100644
--- a/docs/core-module/10-varc.html
+++ b/docs/core-module/10-varc.html
@@ -424,7 +424,7 @@ object.
one -> next_alternative = NULL ;
parse_node * new_poss = ExParser::Subtrees::to_specification ( SV_not_SN , W , one , B );
if (!( Node::is ( new_poss , UNKNOWN_NT )))
- amb = Node::add_possible_reading ( amb , new_poss , W );
+ amb = SyntaxTree::add_reading ( amb , new_poss , W );
}
if ( amb == NULL ) amb = Specifications::new_UNKNOWN ( W );
return amb ;
@@ -437,7 +437,7 @@ object.
hmm -> down -> next_alternative = NULL ;
parse_node * new_poss = ExParser::Subtrees::to_specification ( SV_not_SN , W , A , hmm );
if (!( Node::is ( new_poss , UNKNOWN_NT )))
- amb = Node::add_possible_reading ( amb , new_poss , W );
+ amb = SyntaxTree::add_reading ( amb , new_poss , W );
}
if ( amb == NULL ) amb = Specifications::new_UNKNOWN ( W );
return amb ;
diff --git a/docs/core-module/14-cn.html b/docs/core-module/14-cn.html
index d709487d5..7410ea154 100644
--- a/docs/core-module/14-cn.html
+++ b/docs/core-module/14-cn.html
@@ -270,7 +270,7 @@ created condition:
reading -> next_alternative = NULL ;
reading = Conditions::attach_historic_requirement ( reading , tp );
if ( Node::is ( reading , UNKNOWN_NT ) == FALSE )
- amb = Node::add_possible_reading ( amb ,
+ amb = SyntaxTree::add_reading ( amb ,
reading , Node::get_text ( cond ));
}
return amb ;
diff --git a/docs/core-module/14-ds2.html b/docs/core-module/14-ds2.html
index 1fec8fbca..61e1cf23f 100644
--- a/docs/core-module/14-ds2.html
+++ b/docs/core-module/14-ds2.html
@@ -4331,6 +4331,36 @@ at run time.
}
}
+
+
+define AMBIGUITY_JOIN_SYNTAX_CALLBACK Dash::ambiguity_join
+
+
+parse_node * Dash::ambiguity_join ( parse_node * existing , parse_node * reading ) {
+ if (( ParseTreeUsage::is_phrasal ( reading )) &&
+ ( Node::get_type ( reading ) == Node::get_type ( existing ))) {
+ Dash::add_pr_inv ( existing , reading );
+ return existing ;
+ }
+ return NULL ;
+}
+
+void Dash::add_pr_inv ( parse_node * E , parse_node * reading ) {
+ for ( parse_node * N = reading -> down -> down , * next_N = ( N )?( N -> next_alternative ): NULL ; N ;
+ N = next_N , next_N = ( N )?( N -> next_alternative ): NULL )
+ Dash::add_single_pr_inv ( E , N );
+}
+
+void Dash::add_single_pr_inv ( parse_node * E , parse_node * N ) {
+ E = E -> down -> down ;
+ if ( Invocations::eq ( E , N )) return ;
+ while (( E ) && ( E -> next_alternative )) {
+ E = E -> next_alternative ;
+ if ( Invocations::eq ( E , N )) return ;
+ }
+ E -> next_alternative = N ; N -> next_alternative = NULL ;
+}
+
diff --git a/docs/core-module/25-cp.html b/docs/core-module/25-cp.html
index 7d31ed1be..e4c113e17 100644
--- a/docs/core-module/25-cp.html
+++ b/docs/core-module/25-cp.html
@@ -160,9 +160,9 @@ should always be supplied for "To..." phrases, but left null for rules.
current_sentence = ph -> declaration_node ;
if ( Phrases::Context::compile_test_head ( ph , acl ) == FALSE ) {
if ( ph -> declaration_node ) {
- VerifyTree::verify_structure ( ph -> declaration_node );
+ VerifyTree::verify_structure_from ( ph -> declaration_node );
Routines::Compile::code_block_outer (1, ph -> declaration_node -> down );
- VerifyTree::verify_structure ( ph -> declaration_node );
+ VerifyTree::verify_structure_from ( ph -> declaration_node );
}
current_sentence = ph -> declaration_node ;
Phrases::Context::compile_test_tail ( ph , acl );
diff --git a/docs/core-module/25-in.html b/docs/core-module/25-in.html
index e7ae61e9d..6cf1fd6b0 100644
--- a/docs/core-module/25-in.html
+++ b/docs/core-module/25-in.html
@@ -649,7 +649,7 @@ Inform prioritises phrases.
-int Invocations::eq ( parse_node * inv1 , parse_node * inv2 ) {
+int Invocations::eq ( parse_node * inv1 , parse_node * inv2 ) {
if (( inv1 ) && ( inv2 == NULL )) return FALSE ;
if (( inv1 == NULL ) && ( inv2 )) return FALSE ;
if ( inv1 == NULL ) return TRUE ;
@@ -682,7 +682,7 @@ in a list:
-void Invocations::log_list ( parse_node * invl ) {
+void Invocations::log_list ( parse_node * invl ) {
parse_node * inv ;
LOG ( "Invocation list (%d):\n" , Invocations::length_of_list ( invl ));
int n = 0 ;
diff --git a/docs/core-module/6-nv.html b/docs/core-module/6-nv.html
index c01582c56..9b4e0799e 100644
--- a/docs/core-module/6-nv.html
+++ b/docs/core-module/6-nv.html
@@ -1408,6 +1408,16 @@ usages to the debugging log.
}
}
+
+
+define TRACING_LINGUISTICS_CALLBACK NewVerbs::trace_parsing
+
+
+int NewVerbs::trace_parsing ( void ) {
+ if ( SyntaxTree::is_trace_set ( Task::syntax_tree ())) return TRUE ;
+ return FALSE ;
+}
+
diff --git a/docs/core-module/7-ns.html b/docs/core-module/7-ns.html
index 75e17405c..c000dc3b4 100644
--- a/docs/core-module/7-ns.html
+++ b/docs/core-module/7-ns.html
@@ -176,8 +176,8 @@ in quick succession, the second run-through does nothing.)
}
void Sentences::VPs::visit ( parse_node * p ) {
if ( Node::get_type ( p ) == TRACE_NT ) {
- trace_sentences = 1 - trace_sentences ;
- Log::tracing_on ( trace_sentences , I "Diagramming" );
+ SyntaxTree::toggle_trace ( Task::syntax_tree ());
+ Log::tracing_on ( SyntaxTree::is_trace_set ( Task::syntax_tree ()), I "Diagramming" );
}
if (( Node::get_type ( p ) == SENTENCE_NT ) &&
( Annotations::read_int ( p , sentence_unparsed_ANNOT ))) {
@@ -443,7 +443,7 @@ action declarations continue with usually extensive further text:
Annotations::write_int ( VP_PN , verb_id_ANNOT , ASSERT_VB );
SyntaxTree::graft ( Task::syntax_tree (), VP_PN , nss_tree_head );
- if ( trace_sentences ) {
+ if ( SyntaxTree::is_trace_set ( Task::syntax_tree ())) {
LOG ( "$T\n" , nss_tree_head ); STREAM_FLUSH ( DL );
}
* X = 0 ;
diff --git a/docs/core-module/7-oaf.html b/docs/core-module/7-oaf.html
index d952291e7..c2201ea54 100644
--- a/docs/core-module/7-oaf.html
+++ b/docs/core-module/7-oaf.html
@@ -131,7 +131,7 @@ not be treated as a possessive, and expunge them.
}
void Sentences::Rearrangement::tidy_up_ofs_and_froms ( void ) {
- VerifyTree::verify_integrity ( Task::syntax_tree ()-> root_node , FALSE );
+ VerifyTree::verify_integrity ( Task::syntax_tree ());
SyntaxTree::traverse_wfirst ( Task::syntax_tree (), Sentences::Rearrangement::traverse_for_property_names );
SyntaxTree::traverse ( Task::syntax_tree (), Sentences::Rearrangement::traverse_for_nonbreaking_ofs );
}
diff --git a/docs/core-module/7-ptu.html b/docs/core-module/7-ptu.html
index 283d50dfe..be2f6bcd7 100644
--- a/docs/core-module/7-ptu.html
+++ b/docs/core-module/7-ptu.html
@@ -212,28 +212,28 @@ also makes it easier for us to manipulate the results.
void ParseTreeUsage::write_parentage_permissions ( void ) {
- parentage_allowed [ L2_NCAT ][ L3_NCAT ] = TRUE ;
- parentage_allowed [ L3_NCAT ][ L3_NCAT ] = TRUE ;
- parentage_allowed [ L2_NCAT ][ L4_NCAT ] = TRUE ;
- parentage_allowed [ L4_NCAT ][ L4_NCAT ] = TRUE ;
- parentage_allowed [ L4_NCAT ][ UNKNOWN_NCAT ] = TRUE ;
+ NodeType::allow_parentage_for_categories ( L2_NCAT , L3_NCAT );
+ NodeType::allow_parentage_for_categories ( L3_NCAT , L3_NCAT );
+ NodeType::allow_parentage_for_categories ( L2_NCAT , L4_NCAT );
+ NodeType::allow_parentage_for_categories ( L4_NCAT , L4_NCAT );
+ NodeType::allow_parentage_for_categories ( L4_NCAT , UNKNOWN_NCAT );
- parentage_allowed [ L4_NCAT ][ LVALUE_NCAT ] = TRUE ;
- parentage_allowed [ L4_NCAT ][ RVALUE_NCAT ] = TRUE ;
- parentage_allowed [ L4_NCAT ][ COND_NCAT ] = TRUE ;
+ NodeType::allow_parentage_for_categories ( L4_NCAT , LVALUE_NCAT );
+ NodeType::allow_parentage_for_categories ( L4_NCAT , RVALUE_NCAT );
+ NodeType::allow_parentage_for_categories ( L4_NCAT , COND_NCAT );
- parentage_allowed [ LVALUE_NCAT ][ UNKNOWN_NCAT ] = TRUE ;
- parentage_allowed [ RVALUE_NCAT ][ UNKNOWN_NCAT ] = TRUE ;
- parentage_allowed [ COND_NCAT ][ UNKNOWN_NCAT ] = TRUE ;
- parentage_allowed [ LVALUE_NCAT ][ LVALUE_NCAT ] = TRUE ;
- parentage_allowed [ RVALUE_NCAT ][ LVALUE_NCAT ] = TRUE ;
- parentage_allowed [ COND_NCAT ][ LVALUE_NCAT ] = TRUE ;
- parentage_allowed [ LVALUE_NCAT ][ RVALUE_NCAT ] = TRUE ;
- parentage_allowed [ RVALUE_NCAT ][ RVALUE_NCAT ] = TRUE ;
- parentage_allowed [ COND_NCAT ][ RVALUE_NCAT ] = TRUE ;
- parentage_allowed [ LVALUE_NCAT ][ COND_NCAT ] = TRUE ;
- parentage_allowed [ RVALUE_NCAT ][ COND_NCAT ] = TRUE ;
- parentage_allowed [ COND_NCAT ][ COND_NCAT ] = TRUE ;
+ NodeType::allow_parentage_for_categories ( LVALUE_NCAT , UNKNOWN_NCAT );
+ NodeType::allow_parentage_for_categories ( RVALUE_NCAT , UNKNOWN_NCAT );
+ NodeType::allow_parentage_for_categories ( COND_NCAT , UNKNOWN_NCAT );
+ NodeType::allow_parentage_for_categories ( LVALUE_NCAT , LVALUE_NCAT );
+ NodeType::allow_parentage_for_categories ( RVALUE_NCAT , LVALUE_NCAT );
+ NodeType::allow_parentage_for_categories ( COND_NCAT , LVALUE_NCAT );
+ NodeType::allow_parentage_for_categories ( LVALUE_NCAT , RVALUE_NCAT );
+ NodeType::allow_parentage_for_categories ( RVALUE_NCAT , RVALUE_NCAT );
+ NodeType::allow_parentage_for_categories ( COND_NCAT , RVALUE_NCAT );
+ NodeType::allow_parentage_for_categories ( LVALUE_NCAT , COND_NCAT );
+ NodeType::allow_parentage_for_categories ( RVALUE_NCAT , COND_NCAT );
+ NodeType::allow_parentage_for_categories ( COND_NCAT , COND_NCAT );
}
@@ -406,7 +406,7 @@ also makes it easier for us to manipulate the results.
define IMMUTABLE_NODE ParseTreeUsage::immutable
-define SENTENCE_NODE_SYNTAX_CALLBACK ParseTreeUsage::second_level
+define IS_SENTENCE_NODE_SYNTAX_CALLBACK ParseTreeUsage::second_level
int ParseTreeUsage::second_level ( node_type_t t ) {
@@ -456,7 +456,7 @@ also makes it easier for us to manipulate the results.
return FALSE ;
}
-int ParseTreeUsage::is_phrasal ( parse_node * pn ) {
+int ParseTreeUsage::is_phrasal ( parse_node * pn ) {
if ( NodeType::has_flag ( Node::get_type ( pn ), PHRASAL_NFLAG )) return TRUE ;
return FALSE ;
}
@@ -470,7 +470,7 @@ be such that their head nodes each pass this test:
int ParseTreeUsage::allow_in_assertions ( parse_node * p ) {
- VerifyTree::verify_structure ( p );
+ VerifyTree::verify_structure_from ( p );
if ( NodeType::has_flag ( Node::get_type ( p ), ASSERT_NFLAG )) return TRUE ;
return FALSE ;
}
@@ -565,7 +565,8 @@ be such that their head nodes each pass this test:
void ParseTreeUsage::verify ( void ) {
- VerifyTree::verify_node ( Task::syntax_tree ());
+ VerifyTree::verify_integrity ( Task::syntax_tree ());
+ VerifyTree::verify_structure ( Task::syntax_tree ());
}
diff --git a/docs/core-module/9-tbath.html b/docs/core-module/9-tbath.html
index 01c200ca3..b3a4cc6fe 100644
--- a/docs/core-module/9-tbath.html
+++ b/docs/core-module/9-tbath.html
@@ -289,7 +289,7 @@ the massive
This code is used in §7.3.1.2 .
@@ -724,6 +727,18 @@ the exactly equivalent idea of the hat being worn by Darcy.
}
+
+
+
+int VerbPhrases::tracing ( void ) {
+ # ifdef TRACING_LINGUISTICS_CALLBACK
+ return TRACING_LINGUISTICS_CALLBACK ();
+ # endif
+ # ifndef TRACING_LINGUISTICS_CALLBACK
+ return FALSE ;
+ # endif
+}
+
diff --git a/docs/linguistics-test/1-pc.html b/docs/linguistics-test/1-pc.html
index 05bd4cc16..3b774f7ac 100644
--- a/docs/linguistics-test/1-pc.html
+++ b/docs/linguistics-test/1-pc.html
@@ -60,8 +60,6 @@
SyntaxModule::start ();
LinguisticsModule::start ();
- Unit::start_diagrams ();
-
CommandLine::declare_heading ( L "linguistics-test: a tool for testing the linguistics module\n" );
CommandLine::declare_switch ( TEST_DIAGRAMS_CLSW , L "test-diagrams" , 2 ,
@@ -79,7 +77,7 @@
void Main::respond ( int id , int val , text_stream * arg , void * state ) {
switch ( id ) {
- case TEST_DIAGRAMS_CLSW: Main::load ( I "Syntax.preform" ); Unit::test_diagrams ( arg ); break ;
+ case TEST_DIAGRAMS_CLSW: Main::load ( I "Syntax.preform" ); Unit::test_diagrams ( arg ); break ;
}
}
diff --git a/docs/linguistics-test/1-ut.html b/docs/linguistics-test/1-ut.html
index 14f7476eb..411547322 100644
--- a/docs/linguistics-test/1-ut.html
+++ b/docs/linguistics-test/1-ut.html
@@ -52,7 +52,7 @@ function togglePopup(material_id) {
How we shall test it.
-
+
@@ -75,24 +75,33 @@ function togglePopup(material_id) {
return TRUE ;
}
-
+
<dividing-sentence> ::=
- chapter ... | ==> 1
- section ... ==> 2
+ chapter ... | ==> 1
+ section ... ==> 2
<structural-sentence> ::=
- ... ==> TRUE; return FAIL_NONTERMINAL;
+ ... ==> TRUE; return FAIL_NONTERMINAL;
<language-modifying-sentence> ::=
- ... ==> TRUE; return FAIL_NONTERMINAL;
+ ... ==> TRUE; return FAIL_NONTERMINAL;
-<unexceptional-sentence> ::=
- <sentence> ==> Report any error 3.1
+<comma-divisible-sentence> ::=
+ ... ==> TRUE; return FAIL_NONTERMINAL;
This is Preform grammar , not regular C code.
-
+
+
+<unexceptional-sentence> ::=
+ <sentence> ==> Report any error 4.1
+
+This is Preform grammar , not regular C code.
+
@@ -101,25 +110,21 @@ function togglePopup(material_id) {
Errors::nowhere ( "two certainties" );
* XP = VP_PN ;
-
-
+
+
<stock> ::=
verb <cardinal-number> ... ==> R[1]; *XP = Conjugation::conjugate(WordAssemblages::from_wording(FW[1]), English_language);
This is Preform grammar , not regular C code.
-
+
int my_first_verb = TRUE ;
-void Unit::start_diagrams ( void ) {
- trace_sentences = TRUE ;
-}
-
parse_node_tree * syntax_tree = NULL ;
-void Unit::test_diagrams ( text_stream * arg ) {
+void Unit::test_diagrams ( text_stream * arg ) {
Streams::enable_debugging ( STDOUT );
filename * F = Filenames::from_text ( arg );
feed_t FD = Feeds::begin ();
@@ -133,14 +138,15 @@ function togglePopup(material_id) {
text_stream * save_DL = DL ;
DL = STDOUT ;
Streams::enable_debugging ( DL );
- SyntaxTree::traverse ( syntax_tree , Unit::diagram );
- Node::log_tree ( DL , syntax_tree -> root_node );
+ SyntaxTree::clear_trace ( syntax_tree );
+ SyntaxTree::traverse ( syntax_tree , Unit::diagram );
+ Node::log_tree ( DL , syntax_tree -> root_node );
DL = save_DL ;
}
void Unit::diagram ( parse_node * p ) {
- if ( Node::get_type ( p ) == SENTENCE_NT ) {
- wording W = Node::get_text ( p );
+ if ( Node::get_type ( p ) == SENTENCE_NT ) {
+ wording W = Node::get_text ( p );
if ( <stock> ( W )) {
verb_conjugation * vc = <<rp>> ;
int cop = FALSE ;
diff --git a/docs/problems-test/1-pc.html b/docs/problems-test/1-pc.html
index 1c1546f1e..cce19256d 100644
--- a/docs/problems-test/1-pc.html
+++ b/docs/problems-test/1-pc.html
@@ -73,7 +73,7 @@
void Main::respond ( int id , int val , text_stream * arg , void * state ) {
switch ( id ) {
- case TEST_PROBLEMS_CLSW: Main::load ( I "Syntax.preform" ); Unit::test_problems ( arg ); break ;
+ case TEST_PROBLEMS_CLSW: Main::load ( I "Syntax.preform" ); Unit::test_problems ( arg ); break ;
}
}
diff --git a/docs/problems-test/1-ut.html b/docs/problems-test/1-ut.html
index 7b75fc68c..665715c1e 100644
--- a/docs/problems-test/1-ut.html
+++ b/docs/problems-test/1-ut.html
@@ -52,28 +52,40 @@ function togglePopup(material_id) {
How we shall test it.
-
+
-
-parse_node_tree * syntax_tree = NULL ;
+
+parse_node_tree * syntax_tree = NULL ;
+
+
+
<dividing-sentence> ::=
- chapter ... | ==> 1
- section ... ==> 2
+ chapter ... | ==> 1
+ section ... ==> 2
<structural-sentence> ::=
- ... ==> TRUE; return FAIL_NONTERMINAL;
+ ... ==> TRUE; return FAIL_NONTERMINAL;
<language-modifying-sentence> ::=
- ... ==> TRUE; return FAIL_NONTERMINAL;
+ ... ==> TRUE; return FAIL_NONTERMINAL;
-<scan-individual-phrase> ::=
- ... banana ... ==> Issue PM_UnexpectedFruit problem 1.1 ;
+<comma-divisible-sentence> ::=
+ ... ==> TRUE; return FAIL_NONTERMINAL;
This is Preform grammar , not regular C code.
-
+
+
+<scan-individual-phrase> ::=
+ ... banana ... ==> Issue PM_UnexpectedFruit problem 3.1 ;
+
+This is Preform grammar , not regular C code.
+
@@ -84,8 +96,8 @@ function togglePopup(material_id) {
"will be ruined." );
Problems::issue_problem_end ();
-
-
+
+
void Unit::test_problems ( text_stream * arg ) {
@@ -98,12 +110,12 @@ function togglePopup(material_id) {
PRINT ( "Read %d words\n" , Wordings::length ( W ));
Sentences::break ( syntax_tree , W );
- SyntaxTree::traverse ( syntax_tree , Unit::scan_tree );
+ SyntaxTree::traverse ( syntax_tree , Unit::scan_tree );
}
void Unit::scan_tree ( parse_node * p ) {
- if ( Node::get_type ( p ) == SENTENCE_NT ) {
- wording W = Node::get_text ( p );
+ if ( Node::get_type ( p ) == SENTENCE_NT ) {
+ wording W = Node::get_text ( p );
<scan-individual-phrase> ( W );
}
}
diff --git a/docs/supervisor-module/2-ce.html b/docs/supervisor-module/2-ce.html
index 495f73d6f..b2e73bd38 100644
--- a/docs/supervisor-module/2-ce.html
+++ b/docs/supervisor-module/2-ce.html
@@ -111,7 +111,7 @@ fields are blank.
-copy_error * CopyErrors::new ( int cat , int subcat ) {
+copy_error * CopyErrors::new ( int cat , int subcat ) {
copy_error * CE = CREATE ( copy_error );
CE -> copy = NULL ;
CE -> error_category = cat ;
@@ -171,7 +171,7 @@ we also offer these functions to tack extra details on:
CE -> details_work2 = w2 ;
}
-void CopyErrors::supply_node ( copy_error * CE , parse_node * n ) {
+void CopyErrors::supply_node ( copy_error * CE , parse_node * n ) {
CE -> details_node = n ;
}
diff --git a/docs/supervisor-module/2-cps.html b/docs/supervisor-module/2-cps.html
index 27bb9dc97..ecec7e3f1 100644
--- a/docs/supervisor-module/2-cps.html
+++ b/docs/supervisor-module/2-cps.html
@@ -144,7 +144,7 @@ for later reporting. These are stored in a list.
-void Copies::attach_error ( inbuild_copy * C , copy_error * CE ) {
+void Copies::attach_error ( inbuild_copy * C , copy_error * CE ) {
if ( C == NULL ) internal_error ( "no copy to attach to" );
CopyErrors::supply_attached_copy ( CE , C );
ADD_TO_LINKED_LIST ( CE , copy_error , C -> errors_reading_source_text );
diff --git a/docs/supervisor-module/4-em.html b/docs/supervisor-module/4-em.html
index 7b88fe828..6e3959363 100644
--- a/docs/supervisor-module/4-em.html
+++ b/docs/supervisor-module/4-em.html
@@ -113,7 +113,7 @@ which stores data about extensions used by the Inform compiler.
-inform_extension * ExtensionManager::from_copy ( inbuild_copy * C ) {
+inform_extension * ExtensionManager::from_copy ( inbuild_copy * C ) {
if (( C ) && ( C -> edition -> work -> genre == extension_genre )) {
return RETRIEVE_POINTER_inform_extension ( C -> metadata );
}
diff --git a/docs/supervisor-module/6-inc.html b/docs/supervisor-module/6-inc.html
index a027ffc41..df25f6df5 100644
--- a/docs/supervisor-module/6-inc.html
+++ b/docs/supervisor-module/6-inc.html
@@ -415,7 +415,7 @@ use an extension which is marked as not working on the current VM.
-void Inclusions::check_begins_here ( parse_node * PN , inform_extension * E ) {
+void Inclusions::check_begins_here ( parse_node * PN , inform_extension * E ) {
inbuild_copy * S = inclusions_errors_to ;
inclusions_errors_to = E -> as_copy ;
<begins-here-sentence-subject> ( Node::get_text ( PN ));
@@ -431,7 +431,7 @@ the "begins here".
<the-prefix-for-extensions> ::=
the ...
-void Inclusions::check_ends_here ( parse_node * PN , inform_extension * E ) {
+void Inclusions::check_ends_here ( parse_node * PN , inform_extension * E ) {
inbuild_copy * S = inclusions_errors_to ;
inclusions_errors_to = E -> as_copy ;
wording W = Node::get_text ( PN );
diff --git a/docs/supervisor-module/6-st.html b/docs/supervisor-module/6-st.html
index f5555cd8d..2da64a6e3 100644
--- a/docs/supervisor-module/6-st.html
+++ b/docs/supervisor-module/6-st.html
@@ -219,7 +219,7 @@ finished loading the bulk in, it calls:
not for inbuild , which isn't in the inventions business.
-define SENTENCE_ANNOTATION_SYNTAX_CALLBACK SourceText::annotate_new_sentence
+define NEW_NONSTRUCTURAL_SENTENCE_SYNTAX_CALLBACK SourceText::annotate_new_sentence
void SourceText::annotate_new_sentence ( parse_node * new ) {
@@ -360,7 +360,27 @@ never accidentally match in the main source text.
include (- ... ==> 0; sfsm->nt = INFORM6CODE_NT;
This is Preform grammar , not regular C code.
-
+
+
+ Instead of going north, try entering the cage
+
+
+
+<comma-divisible-sentence> ::=
+ instead of ... |
+ every turn *** |
+ before ... |
+ after ... |
+ when ...
+
+This is Preform grammar , not regular C code.
+This is Preform grammar , not regular C code.
-
-define BEGIN_OR_END_HERE_SYNTAX_CALLBACK SourceText::new_beginend
+define BEGIN_OR_END_HERE_SYNTAX_CALLBACK SourceText::new_beginend
void SourceText::new_beginend ( parse_node * pn , inbuild_copy * C ) {
@@ -386,7 +406,7 @@ of an extension.
if ( Node::get_type ( pn ) == ENDHERE_NT ) Inclusions::check_ends_here ( pn , E );
}
-
@@ -397,7 +417,7 @@ of an extension.
stack into the new world of kits), so we issue a syntax error.
-define LANGUAGE_ELEMENT_SYNTAX_CALLBACK SourceText::new_language
+define LANGUAGE_ELEMENT_SYNTAX_CALLBACK SourceText::new_language
void SourceText::new_language ( wording W ) {
diff --git a/docs/syntax-module/1-sm.html b/docs/syntax-module/1-sm.html
index c42986daf..4683f65f3 100644
--- a/docs/syntax-module/1-sm.html
+++ b/docs/syntax-module/1-sm.html
@@ -84,19 +84,19 @@ all we need do is set up some debugging log facilities.
void SyntaxModule::start ( void ) {
NodeType::make_parentage_allowed_table ();
- NodeType::metadata_setup ();
+ NodeType::metadata_setup ();
Annotations::make_annotation_allowed_table ();
- Writers::register_logger ( 'm' , Node::log_tree ); /* |$ m | = log syntax tree from node */
- Writers::register_logger_I ( 'N' , NodeType::log ); /* |$ N | = log individual node type */
- Writers::register_logger ( 'P' , Node::log_node ); /* |$ P | = log individual parse node */
- Writers::register_logger ( 'T' , Node::log_subtree ); /* |$ T | = log tree under node */
+ Writers::register_logger ( 'm' , Node::log_tree ); /* |$ m | = log syntax tree from node */
+ Writers::register_logger_I ( 'N' , NodeType::log ); /* |$ N | = log individual node type */
+ Writers::register_logger ( 'P' , Node::log_node ); /* |$ P | = log individual parse node */
+ Writers::register_logger ( 'T' , Node::log_subtree ); /* |$ T | = log tree under node */
}
void SyntaxModule::end ( void ) {
}
+
diff --git a/docs/syntax-module/2-na.html b/docs/syntax-module/2-na.html
index fddf47d99..4db57bcd0 100644
--- a/docs/syntax-module/2-na.html
+++ b/docs/syntax-module/2-na.html
@@ -104,7 +104,7 @@ is unannotated.
-void Annotations::clear ( parse_node * PN ) {
+void Annotations::clear ( parse_node * PN ) {
PN -> annotations = NULL ;
}
@@ -128,7 +128,7 @@ other for reading pointers to objects.
-int Annotations::read_int ( parse_node * PN , int id ) {
+int Annotations::read_int ( parse_node * PN , int id ) {
parse_node_annotation * pna ;
if ( PN )
for ( pna = PN -> annotations ; pna ; pna = pna -> next_annotation )
@@ -154,7 +154,7 @@ one (on the same node) overwrites it, but this is not an error.
-void Annotations::write_int ( parse_node * PN , int id , int v ) {
+void Annotations::write_int ( parse_node * PN , int id , int v ) {
parse_node_annotation * newpna , * pna , * final = NULL ;
if ( PN == NULL ) internal_error ( "annotated null PN" );
for ( pna = PN -> annotations ; pna ; pna = pna -> next_annotation ) {
@@ -224,7 +224,7 @@ wants to.
-void Annotations::copy ( parse_node * to , parse_node * from ) {
+void Annotations::copy ( parse_node * to , parse_node * from ) {
to -> annotations = NULL ;
for ( parse_node_annotation * pna = from -> annotations , * latest = NULL ;
pna ; pna = pna -> next_annotation ) {
@@ -284,7 +284,7 @@ expected also to call the following:
}
void Annotations::allow_for_category ( int cat , int annot ) {
LOOP_OVER_ENUMERATED_NTS ( t )
- if ( NodeType::category ( t ) == cat )
+ if ( NodeType::category ( t ) == cat )
Annotations::allow ( t , annot );
}
@@ -306,8 +306,8 @@ is rarely used by Inform, but is needed when a node changes its type.
-void Annotations::clear_invalid ( parse_node * pn ) {
- node_type_t nt = Node::get_type ( pn );
+void Annotations::clear_invalid ( parse_node * pn ) {
+ node_type_t nt = Node::get_type ( pn );
while (( pn -> annotations ) &&
(!( Annotations::is_allowed ( nt , pn -> annotations -> annotation_id ))))
pn -> annotations = pn -> annotations -> next_annotation ;
diff --git a/docs/syntax-module/2-nt.html b/docs/syntax-module/2-nt.html
index 05012c79a..42b6673a1 100644
--- a/docs/syntax-module/2-nt.html
+++ b/docs/syntax-module/2-nt.html
@@ -1,7 +1,7 @@
- Node Tyoes
+ Node Types
@@ -61,12 +61,12 @@ function togglePopup(material_id) {
-
+
+
Each node in a syntax tree has a type, which informs whether it can have child nodes, and what in general terms it means.
-
+
-int NodeType::is_enumerated ( node_type_t t ) {
+int NodeType::is_enumerated ( node_type_t t ) {
if (( t >= ENUMERATED_NT_BASE ) &&
( t < ENUMERATED_NT_BASE + NO_DEFINED_NT_VALUES )) return TRUE ;
return FALSE ;
@@ -132,19 +132,34 @@ to be children of which others, thus enforcing this hierarchy.
for ( int i = 0 ; i < NO_DEFINED_NCAT_VALUES ; i ++)
for ( int j = 0 ; j < NO_DEFINED_NCAT_VALUES ; j ++)
parentage_allowed [ i ][ j ] = FALSE ;
- parentage_allowed [ L1_NCAT ][ L1_NCAT ] = TRUE ;
+ NodeType::allow_parentage_for_categories ( L1_NCAT , L1_NCAT );
# ifdef PARENTAGE_PERMISSIONS_SYNTAX_CALLBACK
PARENTAGE_PERMISSIONS_SYNTAX_CALLBACK ();
# endif
+ # ifdef MORE_PARENTAGE_PERMISSIONS_SYNTAX_CALLBACK
+ MORE_PARENTAGE_PERMISSIONS_SYNTAX_CALLBACK ();
+ # endif
+ # ifdef EVEN_MORE_PARENTAGE_PERMISSIONS_SYNTAX_CALLBACK
+ EVEN_MORE_PARENTAGE_PERMISSIONS_SYNTAX_CALLBACK ();
+ # endif
}
-
+
+
+void NodeType::allow_parentage_for_categories ( int A , int B ) {
+ parentage_allowed [ A ][ B ] = TRUE ;
+}
+
+
define DONT_VISIT_NFLAG 0x00000001
define TABBED_NFLAG 0x00000002
-
-
-void NodeType::log ( OUTPUT_STREAM , int it ) {
+void NodeType::log ( OUTPUT_STREAM , int it ) {
node_type_t t = ( node_type_t ) it ;
- node_type_metadata * metadata = NodeType::get_metadata ( t );
+ node_type_metadata * metadata = NodeType::get_metadata ( t );
if ( metadata ) WRITE ( "%S" , metadata -> node_type_name );
else {
# ifdef LOG_UNENUMERATED_NODE_TYPES_SYNTAX_CALLBACK
@@ -185,10 +200,10 @@ enumerated, we allow a callback function (if provided) to do the job for us.
}
}
-
+
-void NodeType::new ( node_type_t identity , text_stream * node_type_name , int min_children ,
+void NodeType::new ( node_type_t identity , text_stream * node_type_name , int min_children ,
int max_children , int category , int node_flags ) {
if ( NodeType::is_enumerated ( identity ) == FALSE ) internal_error ( "set bad metadata" );
node_type_metadata * ptnt =
@@ -201,46 +216,46 @@ enumerated, we allow a callback function (if provided) to do the job for us.
ptnt -> node_flags = node_flags ;
}
-
+
-int NodeType::category ( node_type_t t ) {
- node_type_metadata * metadata = NodeType::get_metadata ( t );
+int NodeType::category ( node_type_t t ) {
+ node_type_metadata * metadata = NodeType::get_metadata ( t );
if ( metadata ) return metadata -> category ;
return INVALID_NCAT ;
}
-int NodeType::is_top_level ( node_type_t t ) {
- if ( NodeType::category ( t ) == L1_NCAT ) return TRUE ;
+int NodeType::is_top_level ( node_type_t t ) {
+ if ( NodeType::category ( t ) == L1_NCAT ) return TRUE ;
return FALSE ;
}
-int NodeType::has_flag ( node_type_t t , int f ) {
- node_type_metadata * metadata = NodeType::get_metadata ( t );
+int NodeType::has_flag ( node_type_t t , int f ) {
+ node_type_metadata * metadata = NodeType::get_metadata ( t );
if (( metadata ) && (( metadata -> node_flags ) & f )) return TRUE ;
return FALSE ;
}
text_stream * NodeType::get_name ( node_type_t t ) {
- node_type_metadata * metadata = NodeType::get_metadata ( t );
+ node_type_metadata * metadata = NodeType::get_metadata ( t );
if ( metadata == NULL ) return I "?" ;
return metadata -> node_type_name ;
}
-
-int NodeType::is_sentence ( node_type_t t ) {
- # ifdef SENTENCE_NODE_SYNTAX_CALLBACK
- return SENTENCE_NODE_SYNTAX_CALLBACK ( t );
+int NodeType::is_sentence ( node_type_t t ) {
+ # ifdef IS_SENTENCE_NODE_SYNTAX_CALLBACK
+ return IS_SENTENCE_NODE_SYNTAX_CALLBACK ( t );
# endif
- # ifndef SENTENCE_NODE_SYNTAX_CALLBACK
+ # ifndef IS_SENTENCE_NODE_SYNTAX_CALLBACK
return FALSE ;
# endif
}
-
@@ -256,18 +271,18 @@ do this. All a bit clumsy, but it works.
enum UNKNOWN_NT
-void NodeType::metadata_setup ( void ) {
- NodeType::new ( INVALID_NT , I "(INVALID_NT)" , 0 , INFTY , INVALID_NCAT , 0 );
+void NodeType::metadata_setup ( void ) {
+ NodeType::new ( INVALID_NT , I "(INVALID_NT)" , 0 , INFTY , INVALID_NCAT , 0 );
- NodeType::new ( ROOT_NT , I "ROOT_NT" , 0 , INFTY , L1_NCAT , DONT_VISIT_NFLAG );
- NodeType::new ( INCLUSION_NT , I "INCLUSION_NT" , 0 , INFTY , L1_NCAT , DONT_VISIT_NFLAG );
- NodeType::new ( HEADING_NT , I "HEADING_NT" , 0 , INFTY , L1_NCAT , 0 );
- NodeType::new ( INCLUDE_NT , I "INCLUDE_NT" , 0 , 0 , L2_NCAT , 0 );
- NodeType::new ( BEGINHERE_NT , I "BEGINHERE_NT" , 0 , 0 , L2_NCAT , 0 );
- NodeType::new ( ENDHERE_NT , I "ENDHERE_NT" , 0 , 0 , L2_NCAT , 0 );
- NodeType::new ( SENTENCE_NT , I "SENTENCE_NT" , 0 , INFTY , L2_NCAT , 0 );
- NodeType::new ( AMBIGUITY_NT , I "AMBIGUITY_NT" , 0 , INFTY , L1_NCAT , 0 );
- NodeType::new ( UNKNOWN_NT , I "UNKNOWN_NT" , 0 , INFTY , UNKNOWN_NCAT , 0 );
+ NodeType::new ( ROOT_NT , I "ROOT_NT" , 0 , INFTY , L1_NCAT , DONT_VISIT_NFLAG );
+ NodeType::new ( INCLUSION_NT , I "INCLUSION_NT" , 0 , INFTY , L1_NCAT , DONT_VISIT_NFLAG );
+ NodeType::new ( HEADING_NT , I "HEADING_NT" , 0 , INFTY , L1_NCAT , 0 );
+ NodeType::new ( INCLUDE_NT , I "INCLUDE_NT" , 0 , 0 , L2_NCAT , 0 );
+ NodeType::new ( BEGINHERE_NT , I "BEGINHERE_NT" , 0 , 0 , L2_NCAT , 0 );
+ NodeType::new ( ENDHERE_NT , I "ENDHERE_NT" , 0 , 0 , L2_NCAT , 0 );
+ NodeType::new ( SENTENCE_NT , I "SENTENCE_NT" , 0 , INFTY , L2_NCAT , 0 );
+ NodeType::new ( AMBIGUITY_NT , I "AMBIGUITY_NT" , 0 , INFTY , L1_NCAT , 0 );
+ NodeType::new ( UNKNOWN_NT , I "UNKNOWN_NT" , 0 , INFTY , UNKNOWN_NCAT , 0 );
# ifdef NODE_METADATA_SETUP_SYNTAX_CALLBACK
NODE_METADATA_SETUP_SYNTAX_CALLBACK ();
@@ -280,15 +295,15 @@ do this. All a bit clumsy, but it works.
# endif
}
-
-int NodeType::parentage_allowed ( node_type_t t_parent , node_type_t t_child ) {
- node_type_metadata * metadata_parent = NodeType::get_metadata ( t_parent );
+int NodeType::parentage_allowed ( node_type_t t_parent , node_type_t t_child ) {
+ node_type_metadata * metadata_parent = NodeType::get_metadata ( t_parent );
if ( metadata_parent == NULL ) return FALSE ;
- node_type_metadata * metadata_child = NodeType::get_metadata ( t_child );
+ node_type_metadata * metadata_child = NodeType::get_metadata ( t_child );
if ( metadata_child == NULL ) return FALSE ;
int cat_child = metadata_child -> category ;
diff --git a/docs/syntax-module/2-pn.html b/docs/syntax-module/2-pn.html
index 2d600c4f6..96d04712c 100644
--- a/docs/syntax-module/2-pn.html
+++ b/docs/syntax-module/2-pn.html
@@ -78,9 +78,9 @@ MathJax = {
-To represent atomic pieces of meaning; or, less pretentiously, to provide the nodes of which syntax trees are made up.
+Syntax trees are made of single nodes, each representing one way to understand a given piece of text.
-
+
@@ -88,87 +88,78 @@ MathJax = {
typedef struct parse_node {
struct wording text_parsed ;
-
node_type_t node_type ;
struct parse_node_annotation * annotations ; Node Annotations
struct parse_node * down ;
struct parse_node * next ;
-
- int score ;
struct parse_node * next_alternative ;
- int log_time ;
+ int score ;
+ int last_seen_on_traverse ;
CLASS_DEFINITION
} parse_node ;
The structure parse_node is accessed in 2/st, 2/na, 2/tv and here.
-
+
-int trace_sentences = FALSE ;
-
-
-
-
-parse_node * Node::new ( node_type_t t ) {
+parse_node * Node::new ( node_type_t t ) {
parse_node * pn = CREATE ( parse_node );
pn -> node_type = t ;
- Node::set_text ( pn , EMPTY_WORDING );
+ Node::set_text ( pn , EMPTY_WORDING );
Annotations::clear ( pn );
pn -> down = NULL ; pn -> next = NULL ; pn -> next_alternative = NULL ;
- pn -> log_time = 0 ;
- Node::set_score ( pn , 0 );
+ pn -> last_seen_on_traverse = 0 ;
+ Node::set_score ( pn , 0 );
return pn ;
}
-
-parse_node * Node::new_with_words ( node_type_t code_number , wording W ) {
- parse_node * pn = Node::new ( code_number );
- Node::set_text ( pn , W );
+parse_node * Node::new_with_words ( node_type_t code_number , wording W ) {
+ parse_node * pn = Node::new ( code_number );
+ Node::set_text ( pn , W );
return pn ;
}
-
-wording Node::get_text ( parse_node * pn ) {
+wording Node::get_text ( parse_node * pn ) {
if ( pn == NULL ) return EMPTY_WORDING ;
return pn -> text_parsed ;
}
-void Node::set_text ( parse_node * pn , wording W ) {
+void Node::set_text ( parse_node * pn , wording W ) {
if ( pn == NULL ) internal_error ( "tried to set words for null node" );
pn -> text_parsed = W ;
}
-
-node_type_t Node::get_type ( parse_node * pn ) {
+node_type_t Node::get_type ( parse_node * pn ) {
if ( pn == NULL ) return INVALID_NT ;
return pn -> node_type ;
}
-int Node::is ( parse_node * pn , node_type_t t ) {
+int Node::is ( parse_node * pn , node_type_t t ) {
if (( pn ) && ( pn -> node_type == t )) return TRUE ;
return FALSE ;
}
-
-void Node::set_type ( parse_node * pn , node_type_t nt ) {
+void Node::set_type ( parse_node * pn , node_type_t nt ) {
# ifdef IMMUTABLE_NODE
node_type_t from = pn -> node_type ;
if ( IMMUTABLE_NODE ( from )) {
@@ -185,14 +176,14 @@ annotations no longer relevant to the node's new identity.
Annotations::clear ( pn );
}
-
-int Node::get_score ( parse_node * pn ) { return pn -> score ; }
-void Node::set_score ( parse_node * pn , int s ) { pn -> score = s ; }
+int Node::get_score ( parse_node * pn ) { return pn -> score ; }
+void Node::set_score ( parse_node * pn , int s ) { pn -> score = s ; }
-
-void Node::copy ( parse_node * to , parse_node * from ) {
+void Node::copy ( parse_node * to , parse_node * from ) {
COPY ( to , from , parse_node );
Annotations::copy ( to , from );
}
parse_node * Node::duplicate ( parse_node * p ) {
- parse_node * dup = Node::new ( INVALID_NT );
- Node::copy ( dup , p );
+ parse_node * dup = Node::new ( INVALID_NT );
+ Node::copy ( dup , p );
return dup ;
}
-
@@ -220,34 +211,34 @@ deep copy which duplicates not only the node, but also its annotation list.
parse_node * next_link = to -> next ;
parse_node * alt_link = to -> next_alternative ;
parse_node * down_link = to -> down ;
- Node::copy ( to , from );
+ Node::copy ( to , from );
to -> next = next_link ;
to -> next_alternative = alt_link ;
to -> down = down_link ;
}
-
void Node::copy_subtree ( parse_node * from , parse_node * to , int level ) {
if (( from == NULL ) || ( to == NULL )) internal_error ( "Null deep copy" );
- Node::copy ( to , from );
+ Node::copy ( to , from );
if ( from -> down ) {
- to -> down = Node::new ( INVALID_NT );
- Node::copy_subtree ( from -> down , to -> down , level +1);
+ to -> down = Node::new ( INVALID_NT );
+ Node::copy_subtree ( from -> down , to -> down , level +1);
}
if (( level >0) && ( from -> next )) {
- to -> next = Node::new ( INVALID_NT );
- Node::copy_subtree ( from -> next , to -> next , level );
+ to -> next = Node::new ( INVALID_NT );
+ Node::copy_subtree ( from -> next , to -> next , level );
}
if (( level >0) && ( from -> next_alternative )) {
- to -> next_alternative = Node::new ( INVALID_NT );
- Node::copy_subtree ( from -> next_alternative , to -> next_alternative , level );
+ to -> next_alternative = Node::new ( INVALID_NT );
+ Node::copy_subtree ( from -> next_alternative , to -> next_alternative , level );
}
}
-
+
int Node::no_children ( parse_node * pn ) {
@@ -256,7 +247,7 @@ deep copy which duplicates not only the node, but also its annotation list.
return c ;
}
-
-
int Node::left_edge_of ( parse_node * PN ) {
parse_node * child ;
- int l = Wordings::first_wn ( Node::get_text ( PN )), lc ;
+ int l = Wordings::first_wn ( Node::get_text ( PN )), lc ;
for ( child = PN -> down ; child ; child = child -> next ) {
- lc = Node::left_edge_of ( child );
+ lc = Node::left_edge_of ( child );
if (( lc >= 0 ) && (( l == -1) || ( lc < l ))) l = lc ;
}
return l ;
}
-
int Node::right_edge_of ( parse_node * PN ) {
parse_node * child ;
- int r = Wordings::last_wn ( Node::get_text ( PN )), rc ;
- if ( Wordings::first_wn ( Node::get_text ( PN )) < 0 ) r = -1;
+ int r = Wordings::last_wn ( Node::get_text ( PN )), rc ;
+ if ( Wordings::first_wn ( Node::get_text ( PN )) < 0 ) r = -1;
for ( child = PN -> down ; child ; child = child -> next ) {
- rc = Node::right_edge_of ( child );
+ rc = Node::right_edge_of ( child );
if (( rc >= 0 ) && (( r == -1) || ( rc > r ))) r = rc ;
}
return r ;
}
-
@@ -326,12 +317,10 @@ logging is a diagnostic tool, we want it to work even when Inform is sick.
-int pn_log_token = 0 ;
-
void Node::log_tree ( OUTPUT_STREAM , void * vpn ) {
parse_node * pn = ( parse_node *) vpn ;
if ( pn == NULL ) { WRITE ( "<null-meaning-list>\n" ); return ; }
- Node::log_subtree_recursively ( OUT , pn , 0 , 0 , 1 , ++ pn_log_token );
+ Node::log_subtree_recursively ( OUT , pn , 0 , 0 , 1 , SyntaxTree::new_traverse_token ());
}
void Node::log_subtree ( OUTPUT_STREAM , void * vpn ) {
@@ -340,50 +329,52 @@ logging is a diagnostic tool, we want it to work even when Inform is sick.
WRITE ( "$P\n" , pn );
if ( pn -> down ) {
LOG_INDENT ;
- Node::log_subtree_recursively ( OUT , pn -> down , 0 , 0 , 1 , ++ pn_log_token );
+ Node::log_subtree_recursively ( OUT , pn -> down , 0 , 0 , 1 , ++ pn_log_token );
LOG_OUTDENT ;
}
}
-
-void Node::log_subtree_recursively ( OUTPUT_STREAM , parse_node * pn , int num , int of , int gen , int ltime ) {
+void Node::log_subtree_recursively ( OUTPUT_STREAM , parse_node * pn , int num ,
+ int of , int gen , int traverse_token ) {
while ( pn ) {
- if ( pn -> log_time == ltime ) {
- WRITE ( "*** Not a tree: %W ***\n" , Node::get_text ( pn )); return ;
+ if ( pn -> last_seen_on_traverse == traverse_token ) {
+ WRITE ( "*** Not a tree: %W ***\n" , Node::get_text ( pn )); return ;
}
- pn -> log_time = ltime ;
- Calculate num and of such that this is [num/of] if they aren't already supplied 17.1 ;
+ pn -> last_seen_on_traverse = traverse_token ;
+ Calculate num and of such that this is [num/of] if they aren't already supplied 16.1 ;
if ( pn == NULL ) { WRITE ( "<null-parse-node>\n" ); return ; }
if ( of > 1 ) {
WRITE ( "[%d/%d] " , num , of );
- if ( Node::get_score ( pn ) != 0 ) WRITE ( "(score %d) " , Node::get_score ( pn ));
+ if ( Node::get_score ( pn ) != 0 ) WRITE ( "(score %d) " , Node::get_score ( pn ));
}
WRITE ( "$P\n" , pn );
if ( pn -> down ) {
LOG_INDENT ;
- Node::log_subtree_recursively ( OUT , pn -> down , 0 , 0 , gen +1, ltime );
+ Node::log_subtree_recursively ( OUT , pn -> down , 0 , 0 , gen +1, traverse_token );
LOG_OUTDENT ;
}
- if ( pn -> next_alternative ) Node::log_subtree_recursively ( OUT , pn -> next_alternative , num +1, of , gen +1, ltime );
+ if ( pn -> next_alternative ) Node::log_subtree_recursively ( OUT ,
+ pn -> next_alternative , num +1, of , gen +1, traverse_token );
pn = pn -> next ; num = 0 ; of = 0 ; gen ++;
}
}
-
-
@@ -393,8 +384,8 @@ so that this code won't be used again on the same horizontal list of possibiliti
num = 1 ;
}
-This code is used in §17 .
-This code is used in §16 .
+
@@ -406,13 +397,14 @@ text in the debugging log.
# ifdef PARSE_TREE_LOGGER
PARSE_TREE_LOGGER ( OUT , pn );
# else
- NodeType::log ( OUT , ( int ) pn -> node_type );
- if ( Wordings::nonempty ( Node::get_text ( pn ))) WRITE ( "'%W'" , Node::get_text ( pn ));
+ NodeType::log ( OUT , ( int ) pn -> node_type );
+ if ( Wordings::nonempty ( Node::get_text ( pn ))) WRITE ( "'%W'" , Node::get_text ( pn ));
# ifdef LINGUISTICS_MODULE
Diagrams::log_node ( OUT , pn );
# endif
switch ( pn -> node_type ) {
- case HEADING_NT: WRITE ( " (level %d)" , Annotations::read_int ( pn , heading_level_ANNOT )); break ;
+ case HEADING_NT: WRITE ( " (level %d)" , Annotations::read_int ( pn ,
+ heading_level_ANNOT )); break ;
}
# endif
int a = 0 ;
@@ -420,7 +412,7 @@ text in the debugging log.
if ( a > 0 ) WRITE ( "/%d" , a );
}
-
@@ -431,63 +423,6 @@ text in the debugging log.
LOG ( "\n" );
}
-
-
-
-parse_node * Node::add_possible_reading ( parse_node * existing , parse_node * reading , wording W ) {
- if ( existing == NULL ) return reading ;
-# ifdef CORE_MODULE
- if ( Node::is ( reading , UNKNOWN_NT )) return existing ;
-# endif
- if ( Node::is ( reading , AMBIGUITY_NT )) reading = reading -> down ;
-
- if ( Node::is ( existing , AMBIGUITY_NT )) {
- # ifdef CORE_MODULE
- if ( ParseTreeUsage::is_phrasal ( reading ))
- for ( parse_node * E = existing -> down ; E ; E = E -> next_alternative )
- if ( Node::get_type ( reading ) == Node::get_type ( E )) {
- Node::add_pr_inv ( E , reading );
- return existing ;
- }
- # endif
- parse_node * L = existing -> down ;
- while (( L ) && ( L -> next_alternative )) L = L -> next_alternative ;
- L -> next_alternative = reading ;
- return existing ;
- }
-
- # ifdef CORE_MODULE
- if (( ParseTreeUsage::is_phrasal ( reading )) &&
- ( Node::get_type ( reading ) == Node::get_type ( existing ))) {
- Node::add_pr_inv ( existing , reading );
- return existing ;
- }
- # endif
-
- parse_node * A = Node::new_with_words ( AMBIGUITY_NT , W );
- A -> down = existing ;
- A -> down -> next_alternative = reading ;
- return A ;
-}
-
-# ifdef CORE_MODULE
-void Node::add_pr_inv ( parse_node * E , parse_node * reading ) {
- for ( parse_node * N = reading -> down -> down , * next_N = ( N )?( N -> next_alternative ): NULL ; N ;
- N = next_N , next_N = ( N )?( N -> next_alternative ): NULL )
- Node::add_single_pr_inv ( E , N );
-}
-
-void Node::add_single_pr_inv ( parse_node * E , parse_node * N ) {
- E = E -> down -> down ;
- if ( Invocations::eq ( E , N )) return ;
- while (( E ) && ( E -> next_alternative )) {
- E = E -> next_alternative ;
- if ( Invocations::eq ( E , N )) return ;
- }
- E -> next_alternative = N ; N -> next_alternative = NULL ;
-}
-# endif
-
diff --git a/docs/syntax-module/2-st.html b/docs/syntax-module/2-st.html
index 7dc148205..8060de29a 100644
--- a/docs/syntax-module/2-st.html
+++ b/docs/syntax-module/2-st.html
@@ -66,7 +66,7 @@ function togglePopup(material_id) {
To parse trees which decompose the meaning of excerpts of text, and which allow annotations to be made at each node.
-
+
-void SyntaxTree::graft_sentence ( parse_node_tree * T , parse_node * new ) {
+void SyntaxTree::graft_sentence ( parse_node_tree * T , parse_node * new ) {
if ( T -> bud_parent_sp == 0 ) internal_error ( "no attachment point" );
- if ( Node::get_type ( new ) == HEADING_NT ) Adjust bud point for a heading 4.1 ;
+ if ( Node::get_type ( new ) == HEADING_NT ) Adjust bud point for a heading 4.1 ;
parse_node * sentence_attachment_point = T -> bud_parent_stack [ T -> bud_parent_sp -1];
SyntaxTree::graft ( T , new , sentence_attachment_point );
- if ( Node::get_type ( new ) == HEADING_NT ) SyntaxTree::push_bud ( T , new );
+ if ( Node::get_type ( new ) == HEADING_NT ) SyntaxTree::push_bud ( T , new );
}
-void VerifyTree::verify_structure_recursively ( parse_node * p , parse_node * parent ) {
- node_type_t t = Node::get_type ( p );
- node_type_metadata * metadata = NodeType::get_metadata ( t );
+int VerifyTree::verify_structure_r ( parse_node * p , parse_node * parent , int ec ) {
+ node_type_t t = Node::get_type ( p );
+ node_type_metadata * metadata = NodeType::get_metadata ( t );
if ( metadata == NULL ) internal_error ( "broken tree should have been reported" );
Check rule (1) of the invariant 4.1 ;
@@ -181,12 +176,13 @@ among its children.
int children_count = 0 ;
for ( parse_node * q = p -> down ; q ; q = q -> next , children_count ++)
- VerifyTree::verify_structure_recursively ( q , p );
+ ec += VerifyTree::verify_structure_r ( q , p , ec );
Check rule (4) of the invariant 4.4 ;
if ( p -> next_alternative )
- VerifyTree::verify_structure_recursively ( p -> next_alternative , parent );
+ ec += VerifyTree::verify_structure_r ( p -> next_alternative , parent , ec );
+ return ec ;
}
if ( t == INVALID_NT ) {
- LOG ( "N%d is $N, which is not allowed except temporarily\n" , p -> allocation_id , t );
+ LOG ( "N%d is $N, which is not allowed except temporarily\n" ,
+ p -> allocation_id , t );
Log this invariant failure 4.1.1
}
@@ -225,10 +222,11 @@ among its children.
- node_type_t t_parent = Node::get_type ( parent );
+ node_type_t t_parent = Node::get_type ( parent );
- if (!( NodeType::parentage_allowed ( t_parent , t ))) {
- LOG ( "N%d is $N: should not be a child of $N\n" , p -> allocation_id , t , t_parent );
+ if (!( NodeType::parentage_allowed ( t_parent , t ))) {
+ LOG ( "N%d is $N: should not be a child of $N\n" ,
+ p -> allocation_id , t , t_parent );
Log this invariant failure 4.1.1
}
@@ -252,13 +250,16 @@ among its children.
}
-
+
+
- if ( Node::is ( parent , ROOT_NT )) LOG ( "Failing subtree:\n$T" , p );
+ if ( Node::is ( parent , ROOT_NT )) LOG ( "Failing subtree:\n$T" , p );
else LOG ( "Failing subtree:\n$T" , parent );
- node_errors ++;
+ ec ++;
This code is used in §4.1 , §4.2 , §4.3 , §4.4 (twice).
diff --git a/docs/syntax-module/3-snt.html b/docs/syntax-module/3-snt.html
index a5b7f8dcd..65e7f853a 100644
--- a/docs/syntax-module/3-snt.html
+++ b/docs/syntax-module/3-snt.html
@@ -104,11 +104,16 @@ in Preform grammar functions.
@ default PROBLEM_REF_SYNTAX_TYPE void
@ default PROJECT_REF_SYNTAX_TYPE void
+enum NO_EXTENSION_POS from 0
+enum BEFORE_BEGINS_EXTENSION_POS
+enum MIDDLE_EXTENSION_POS
+enum AFTER_ENDS_EXTENSION_POS
+enum PAST_CARING_EXTENSION_POS
typedef struct syntax_fsm_state {
source_file * sf ;
- int ext_pos ;
+ int ext_pos ;
int skipping_material_at_level ;
int main_source_start_wn ;
node_type_t nt ;
@@ -140,7 +145,8 @@ one source text start position.
sfsm -> skipping_material_at_level = -1;
sfsm -> ref = ref ;
sfsm -> project_ref = project_ref ;
- if ( is_extension ) sfsm -> ext_pos = 1 ; else sfsm -> ext_pos = 0 ;
+ if ( is_extension ) sfsm -> ext_pos = BEFORE_BEGINS_EXTENSION_POS ;
+ else sfsm -> ext_pos = NO_EXTENSION_POS ;
}
if (( <structural-sentence> ( Wordings::from ( W , sentence_start ))) &&
- ( NodeType::has_flag ( sfsm -> nt , TABBED_NFLAG )))
+ ( NodeType::has_flag ( sfsm -> nt , TABBED_NFLAG )))
sfsm -> inside_table_mode = TRUE ;
else
sfsm -> inside_table_mode = FALSE ;
@@ -449,8 +455,9 @@ or until reaching the end of the text: whichever comes first.
-void Sentences::make_node ( parse_node_tree * T , wording W , int stop_character ) {
- int heading_level = 0 , begins_or_ends = 0 ;
+void Sentences::make_node ( parse_node_tree * T , wording W , int stop_character ) {
+ int heading_level = 0 ;
+ int begins_or_ends = 0 ;
parse_node * new ;
if ( Wordings::empty ( W )) internal_error ( "empty sentence generated" );
@@ -487,8 +494,8 @@ is declared as if it were a super-heading in the text.
if ( Lexer::file_of_origin ( Wordings::first_wn ( W )) != sfsm -> sf ) {
- parse_node * implicit_heading = Node::new ( HEADING_NT );
- Node::set_text ( implicit_heading , W );
+ parse_node * implicit_heading = Node::new ( HEADING_NT );
+ Node::set_text ( implicit_heading , W );
Annotations::write_int ( implicit_heading , sentence_unparsed_ANNOT , FALSE );
Annotations::write_int ( implicit_heading , heading_level_ANNOT , 0 );
SyntaxTree::graft_sentence ( T , implicit_heading );
@@ -504,9 +511,9 @@ is declared as if it were a super-heading in the text.
- if (( sfsm -> ext_pos == 3 ) && ( begins_or_ends == 0 )) {
+ if (( sfsm -> ext_pos == AFTER_ENDS_EXTENSION_POS ) && ( begins_or_ends == 0 )) {
Sentences::syntax_problem ( ExtSpuriouslyContinues_SYNERROR , W , sfsm -> ref , 0 );
- sfsm -> ext_pos = 4 ;
+ sfsm -> ext_pos = PAST_CARING_EXTENSION_POS ;
}
@@ -522,8 +529,8 @@ important), or
An overview of the syntax module's role and abilities.
-
+
+
+
+ How To Include This Module -
+ What to do to make use of the syntax module in a new command-line tool.
+
@@ -90,13 +95,13 @@
- Node Tyoes -
+ Node Types -
Each node in a syntax tree has a type, which informs whether it can have child nodes, and what in general terms it means.
Parse Nodes -
- To represent atomic pieces of meaning; or, less pretentiously, to provide the nodes of which syntax trees are made up.
+ Syntax trees are made of single nodes, each representing one way to understand a given piece of text.
diff --git a/docs/syntax-test/1-ut.html b/docs/syntax-test/1-ut.html
index 51cad352a..d1b924197 100644
--- a/docs/syntax-test/1-ut.html
+++ b/docs/syntax-test/1-ut.html
@@ -52,20 +52,25 @@ function togglePopup(material_id) {
How we shall test it.
-
+
-
+
<dividing-sentence> ::=
- chapter ... | ==> 1
- section ... ==> 2
+ chapter ... | ==> 1
+ section ... ==> 2
<structural-sentence> ::=
- ... ==> TRUE; return FAIL_NONTERMINAL;
+ ... ==> TRUE; return FAIL_NONTERMINAL;
<language-modifying-sentence> ::=
- ... ==> TRUE; return FAIL_NONTERMINAL;
+ ... ==> TRUE; return FAIL_NONTERMINAL;
+
+<comma-divisible-sentence> ::=
+ ... ==> TRUE; return FAIL_NONTERMINAL;
This is Preform grammar , not regular C code.
@@ -86,7 +91,7 @@ function togglePopup(material_id) {
text_stream * save_DL = DL ;
DL = STDOUT ;
Streams::enable_debugging ( DL );
- Node::log_tree ( DL , syntax_tree -> root_node );
+ Node::log_tree ( DL , syntax_tree -> root_node );
DL = save_DL ;
}
diff --git a/docs/words-module/4-prf.html b/docs/words-module/4-prf.html
index 7f67f988f..4f169c43b 100644
--- a/docs/words-module/4-prf.html
+++ b/docs/words-module/4-prf.html
@@ -2021,7 +2021,7 @@ and the pointer result is null.
if ( nt -> multiplicitous ) {
# ifdef CORE_MODULE
added_to_result = QP ;
- acc_result = ( void *) Node::add_possible_reading (( parse_node *) acc_result , QP , W );
+ acc_result = ( void *) SyntaxTree::add_reading (( parse_node *) acc_result , QP , W );
# endif
goto Fail ;
}
diff --git a/inbuild/supervisor-module/Chapter 6/Source Text.w b/inbuild/supervisor-module/Chapter 6/Source Text.w
index d530329a7..57d35a514 100644
--- a/inbuild/supervisor-module/Chapter 6/Source Text.w
+++ b/inbuild/supervisor-module/Chapter 6/Source Text.w
@@ -137,7 +137,7 @@ void SourceText::bulk_of_source_loaded(void) {
@ And here is the callback function. It's only ever needed for //inform7//,
not for //inbuild//, which isn't in the inventions business.
-@d SENTENCE_ANNOTATION_SYNTAX_CALLBACK SourceText::annotate_new_sentence
+@d NEW_NONSTRUCTURAL_SENTENCE_SYNTAX_CALLBACK SourceText::annotate_new_sentence
=
void SourceText::annotate_new_sentence(parse_node *new) {
@@ -249,6 +249,22 @@ never accidentally match in the main source text.
include ... by ... | ==> 0; sfsm->nt = INCLUDE_NT;
include (- ... ==> 0; sfsm->nt = INFORM6CODE_NT;
+@ Rules are ordinarily detected by their colon, which divides the header from the
+rest: colons are not otherwise legal in Inform. But there's an exception. If the
+sentence consists of text matching the following grammar, followed by comma,
+followed by more text, then the comma is read as if it's a colon and the
+sentence becomes a rule. For example:
+
+>> Instead of going north, try entering the cage
+
+=
+ ::=
+ instead of ... |
+ every turn *** |
+ before ... |
+ after ... |
+ when ...
+
@ Properly speaking, despite the definition above, language modifying sentences
are nonstructural. So what are they doing here? The answer is that we need to
read them early on, because they affect the way that they parse all other
diff --git a/inform7/core-module/Chapter 10/Architecture of the S-Parser.w b/inform7/core-module/Chapter 10/Architecture of the S-Parser.w
index 828fe86eb..f82693ccb 100644
--- a/inform7/core-module/Chapter 10/Architecture of the S-Parser.w
+++ b/inform7/core-module/Chapter 10/Architecture of the S-Parser.w
@@ -232,7 +232,7 @@ parse_node *ExParser::parse_with_cache(wording W, int context, nonterminal *nt)
preform_lookahead_mode = plm;
@;
- VerifyTree::verify_structure(spec);
+ VerifyTree::verify_structure_from(spec);
return spec;
}
diff --git a/inform7/core-module/Chapter 10/Verbal and Relative Clauses.w b/inform7/core-module/Chapter 10/Verbal and Relative Clauses.w
index 1649487db..4d044720f 100644
--- a/inform7/core-module/Chapter 10/Verbal and Relative Clauses.w
+++ b/inform7/core-module/Chapter 10/Verbal and Relative Clauses.w
@@ -291,7 +291,7 @@ parse_node *ExParser::Subtrees::to_specification_inner(int SV_not_SN, wording W,
one->next_alternative = NULL;
parse_node *new_poss = ExParser::Subtrees::to_specification(SV_not_SN, W, one, B);
if (!(Node::is(new_poss, UNKNOWN_NT)))
- amb = Node::add_possible_reading(amb, new_poss, W);
+ amb = SyntaxTree::add_reading(amb, new_poss, W);
}
if (amb == NULL) amb = Specifications::new_UNKNOWN(W);
return amb;
@@ -304,7 +304,7 @@ parse_node *ExParser::Subtrees::to_specification_inner(int SV_not_SN, wording W,
hmm->down->next_alternative = NULL;
parse_node *new_poss = ExParser::Subtrees::to_specification(SV_not_SN, W, A, hmm);
if (!(Node::is(new_poss, UNKNOWN_NT)))
- amb = Node::add_possible_reading(amb, new_poss, W);
+ amb = SyntaxTree::add_reading(amb, new_poss, W);
}
if (amb == NULL) amb = Specifications::new_UNKNOWN(W);
return amb;
diff --git a/inform7/core-module/Chapter 14/Conditions.w b/inform7/core-module/Chapter 14/Conditions.w
index 12102e46a..6d90395a9 100644
--- a/inform7/core-module/Chapter 14/Conditions.w
+++ b/inform7/core-module/Chapter 14/Conditions.w
@@ -169,7 +169,7 @@ parse_node *Conditions::attach_historic_requirement(parse_node *cond, time_perio
reading->next_alternative = NULL;
reading = Conditions::attach_historic_requirement(reading, tp);
if (Node::is(reading, UNKNOWN_NT) == FALSE)
- amb = Node::add_possible_reading(amb,
+ amb = SyntaxTree::add_reading(amb,
reading, Node::get_text(cond));
}
return amb;
diff --git a/inform7/core-module/Chapter 14/Dash.w b/inform7/core-module/Chapter 14/Dash.w
index c44c57bf6..6ff37b0dd 100644
--- a/inform7/core-module/Chapter 14/Dash.w
+++ b/inform7/core-module/Chapter 14/Dash.w
@@ -3511,3 +3511,33 @@ void Dash::experiment(wording W, int full) {
LOG("$m\n", test_tree);
}
}
+
+@
+
+@d AMBIGUITY_JOIN_SYNTAX_CALLBACK Dash::ambiguity_join
+
+=
+parse_node *Dash::ambiguity_join(parse_node *existing, parse_node *reading) {
+ if ((ParseTreeUsage::is_phrasal(reading)) &&
+ (Node::get_type(reading) == Node::get_type(existing))) {
+ Dash::add_pr_inv(existing, reading);
+ return existing;
+ }
+ return NULL;
+}
+
+void Dash::add_pr_inv(parse_node *E, parse_node *reading) {
+ for (parse_node *N = reading->down->down, *next_N = (N)?(N->next_alternative):NULL; N;
+ N = next_N, next_N = (N)?(N->next_alternative):NULL)
+ Dash::add_single_pr_inv(E, N);
+}
+
+void Dash::add_single_pr_inv(parse_node *E, parse_node *N) {
+ E = E->down->down;
+ if (Invocations::eq(E, N)) return;
+ while ((E) && (E->next_alternative)) {
+ E = E->next_alternative;
+ if (Invocations::eq(E, N)) return;
+ }
+ E->next_alternative = N; N->next_alternative = NULL;
+}
diff --git a/inform7/core-module/Chapter 25/Compile Phrases.w b/inform7/core-module/Chapter 25/Compile Phrases.w
index dea1dd88b..99bd15f6e 100644
--- a/inform7/core-module/Chapter 25/Compile Phrases.w
+++ b/inform7/core-module/Chapter 25/Compile Phrases.w
@@ -79,9 +79,9 @@ void Routines::Compile::routine(phrase *ph,
current_sentence = ph->declaration_node;
if (Phrases::Context::compile_test_head(ph, acl) == FALSE) {
if (ph->declaration_node) {
- VerifyTree::verify_structure(ph->declaration_node);
+ VerifyTree::verify_structure_from(ph->declaration_node);
Routines::Compile::code_block_outer(1, ph->declaration_node->down);
- VerifyTree::verify_structure(ph->declaration_node);
+ VerifyTree::verify_structure_from(ph->declaration_node);
}
current_sentence = ph->declaration_node;
Phrases::Context::compile_test_tail(ph, acl);
diff --git a/inform7/core-module/Chapter 6/New Verbs.w b/inform7/core-module/Chapter 6/New Verbs.w
index b56d861a8..45098b647 100644
--- a/inform7/core-module/Chapter 6/New Verbs.w
+++ b/inform7/core-module/Chapter 6/New Verbs.w
@@ -1202,3 +1202,12 @@ void NewVerbs::tabulate_meaning(OUTPUT_STREAM, lexicon_entry *lex) {
}
}
+@
+
+@d TRACING_LINGUISTICS_CALLBACK NewVerbs::trace_parsing
+
+=
+int NewVerbs::trace_parsing(void) {
+ if (SyntaxTree::is_trace_set(Task::syntax_tree())) return TRUE;
+ return FALSE;
+}
diff --git a/inform7/core-module/Chapter 7/Nonstructural Sentences.w b/inform7/core-module/Chapter 7/Nonstructural Sentences.w
index ec48d8025..5173f54d6 100644
--- a/inform7/core-module/Chapter 7/Nonstructural Sentences.w
+++ b/inform7/core-module/Chapter 7/Nonstructural Sentences.w
@@ -98,8 +98,8 @@ void Sentences::VPs::traverse(void) {
}
void Sentences::VPs::visit(parse_node *p) {
if (Node::get_type(p) == TRACE_NT) {
- trace_sentences = 1 - trace_sentences;
- Log::tracing_on(trace_sentences, I"Diagramming");
+ SyntaxTree::toggle_trace(Task::syntax_tree());
+ Log::tracing_on(SyntaxTree::is_trace_set(Task::syntax_tree()), I"Diagramming");
}
if ((Node::get_type(p) == SENTENCE_NT) &&
(Annotations::read_int(p, sentence_unparsed_ANNOT))) {
@@ -331,7 +331,7 @@ action declarations continue with usually extensive further text:
Annotations::write_int(VP_PN, verb_id_ANNOT, ASSERT_VB);
SyntaxTree::graft(Task::syntax_tree(), VP_PN, nss_tree_head);
- if (trace_sentences) {
+ if (SyntaxTree::is_trace_set(Task::syntax_tree())) {
LOG("$T\n", nss_tree_head); STREAM_FLUSH(DL);
}
*X = 0;
diff --git a/inform7/core-module/Chapter 7/Of and From.w b/inform7/core-module/Chapter 7/Of and From.w
index 957fe6204..8df2c04f8 100644
--- a/inform7/core-module/Chapter 7/Of and From.w
+++ b/inform7/core-module/Chapter 7/Of and From.w
@@ -61,7 +61,7 @@ void Sentences::Rearrangement::further_material(void) {
}
void Sentences::Rearrangement::tidy_up_ofs_and_froms(void) {
- VerifyTree::verify_integrity(Task::syntax_tree()->root_node, FALSE);
+ VerifyTree::verify_integrity(Task::syntax_tree());
SyntaxTree::traverse_wfirst(Task::syntax_tree(), Sentences::Rearrangement::traverse_for_property_names);
SyntaxTree::traverse(Task::syntax_tree(), Sentences::Rearrangement::traverse_for_nonbreaking_ofs);
}
diff --git a/inform7/core-module/Chapter 7/Parse Tree Usage.w b/inform7/core-module/Chapter 7/Parse Tree Usage.w
index bcd9c9805..ba6be102d 100644
--- a/inform7/core-module/Chapter 7/Parse Tree Usage.w
+++ b/inform7/core-module/Chapter 7/Parse Tree Usage.w
@@ -146,28 +146,28 @@ void ParseTreeUsage::md(void) {
=
void ParseTreeUsage::write_parentage_permissions(void) {
- parentage_allowed[L2_NCAT][L3_NCAT] = TRUE;
- parentage_allowed[L3_NCAT][L3_NCAT] = TRUE;
- parentage_allowed[L2_NCAT][L4_NCAT] = TRUE;
- parentage_allowed[L4_NCAT][L4_NCAT] = TRUE;
- parentage_allowed[L4_NCAT][UNKNOWN_NCAT] = TRUE;
+ NodeType::allow_parentage_for_categories(L2_NCAT, L3_NCAT);
+ NodeType::allow_parentage_for_categories(L3_NCAT, L3_NCAT);
+ NodeType::allow_parentage_for_categories(L2_NCAT, L4_NCAT);
+ NodeType::allow_parentage_for_categories(L4_NCAT, L4_NCAT);
+ NodeType::allow_parentage_for_categories(L4_NCAT, UNKNOWN_NCAT);
- parentage_allowed[L4_NCAT][LVALUE_NCAT] = TRUE;
- parentage_allowed[L4_NCAT][RVALUE_NCAT] = TRUE;
- parentage_allowed[L4_NCAT][COND_NCAT] = TRUE;
+ NodeType::allow_parentage_for_categories(L4_NCAT, LVALUE_NCAT);
+ NodeType::allow_parentage_for_categories(L4_NCAT, RVALUE_NCAT);
+ NodeType::allow_parentage_for_categories(L4_NCAT, COND_NCAT);
- parentage_allowed[LVALUE_NCAT][UNKNOWN_NCAT] = TRUE;
- parentage_allowed[RVALUE_NCAT][UNKNOWN_NCAT] = TRUE;
- parentage_allowed[COND_NCAT][UNKNOWN_NCAT] = TRUE;
- parentage_allowed[LVALUE_NCAT][LVALUE_NCAT] = TRUE;
- parentage_allowed[RVALUE_NCAT][LVALUE_NCAT] = TRUE;
- parentage_allowed[COND_NCAT][LVALUE_NCAT] = TRUE;
- parentage_allowed[LVALUE_NCAT][RVALUE_NCAT] = TRUE;
- parentage_allowed[RVALUE_NCAT][RVALUE_NCAT] = TRUE;
- parentage_allowed[COND_NCAT][RVALUE_NCAT] = TRUE;
- parentage_allowed[LVALUE_NCAT][COND_NCAT] = TRUE;
- parentage_allowed[RVALUE_NCAT][COND_NCAT] = TRUE;
- parentage_allowed[COND_NCAT][COND_NCAT] = TRUE;
+ NodeType::allow_parentage_for_categories(LVALUE_NCAT, UNKNOWN_NCAT);
+ NodeType::allow_parentage_for_categories(RVALUE_NCAT, UNKNOWN_NCAT);
+ NodeType::allow_parentage_for_categories(COND_NCAT, UNKNOWN_NCAT);
+ NodeType::allow_parentage_for_categories(LVALUE_NCAT, LVALUE_NCAT);
+ NodeType::allow_parentage_for_categories(RVALUE_NCAT, LVALUE_NCAT);
+ NodeType::allow_parentage_for_categories(COND_NCAT, LVALUE_NCAT);
+ NodeType::allow_parentage_for_categories(LVALUE_NCAT, RVALUE_NCAT);
+ NodeType::allow_parentage_for_categories(RVALUE_NCAT, RVALUE_NCAT);
+ NodeType::allow_parentage_for_categories(COND_NCAT, RVALUE_NCAT);
+ NodeType::allow_parentage_for_categories(LVALUE_NCAT, COND_NCAT);
+ NodeType::allow_parentage_for_categories(RVALUE_NCAT, COND_NCAT);
+ NodeType::allow_parentage_for_categories(COND_NCAT, COND_NCAT);
}
@
@@ -339,7 +339,7 @@ int ParseTreeUsage::parentage_exceptions(node_type_t t_parent, int cat_parent,
@ Further classification:
@d IMMUTABLE_NODE ParseTreeUsage::immutable
-@d SENTENCE_NODE_SYNTAX_CALLBACK ParseTreeUsage::second_level
+@d IS_SENTENCE_NODE_SYNTAX_CALLBACK ParseTreeUsage::second_level
=
int ParseTreeUsage::second_level(node_type_t t) {
@@ -403,7 +403,7 @@ be such that their head nodes each pass this test:
=
int ParseTreeUsage::allow_in_assertions(parse_node *p) {
- VerifyTree::verify_structure(p);
+ VerifyTree::verify_structure_from(p);
if (NodeType::has_flag(Node::get_type(p), ASSERT_NFLAG)) return TRUE;
return FALSE;
}
@@ -487,7 +487,8 @@ void ParseTreeUsage::log_node(OUTPUT_STREAM, parse_node *pn) {
@ =
void ParseTreeUsage::verify(void) {
- VerifyTree::verify_node(Task::syntax_tree());
+ VerifyTree::verify_integrity(Task::syntax_tree());
+ VerifyTree::verify_structure(Task::syntax_tree());
}
@
diff --git a/inform7/core-module/Chapter 9/To Be and To Have.w b/inform7/core-module/Chapter 9/To Be and To Have.w
index d8d97812b..d9fd30704 100644
--- a/inform7/core-module/Chapter 9/To Be and To Have.w
+++ b/inform7/core-module/Chapter 9/To Be and To Have.w
@@ -192,7 +192,7 @@ void Assertions::Copular::make_assertion(parse_node *px, parse_node *py) {
if (Assertions::Creator::consult_the_creator(px, py) == FALSE) return;
}
- if (trace_sentences) LOG("$T", current_sentence);
+ if (SyntaxTree::is_trace_set(Task::syntax_tree())) LOG("$T", current_sentence);
if ((Node::get_text(px))) {
if (traverse == 1) Assertions::Copular::make_existential_assertion(py);
px = py;
diff --git a/inform7/core-module/Chapter 9/Traverse for Assertions.w b/inform7/core-module/Chapter 9/Traverse for Assertions.w
index 6d74f1f48..644f6a4f8 100644
--- a/inform7/core-module/Chapter 9/Traverse for Assertions.w
+++ b/inform7/core-module/Chapter 9/Traverse for Assertions.w
@@ -110,7 +110,7 @@ void Assertions::Traverse::traverse2(void) {
void Assertions::Traverse::traverse(int pass) {
Assertions::Traverse::new_discussion(); /* clear memory of what the subject and object of discussion are */
traverse = pass;
- trace_sentences = FALSE;
+ SyntaxTree::clear_trace(Task::syntax_tree());
if (sentence_handlers_initialised == FALSE) @;
@@ -200,7 +200,7 @@ handlers until right at the end of the program. The routine which does so,
}
@ =
- if ((trace_sentences) && (Node::get_type(p) != TRACE_NT))
+ if ((SyntaxTree::is_trace_set(Task::syntax_tree())) && (Node::get_type(p) != TRACE_NT))
LOG("\n[%W]\n", Node::get_text(p));
@;
@@ -248,9 +248,9 @@ void Assertions::Traverse::switch_sentence_trace(parse_node *PN) {
"so I'll note it down in the Telemetry file (if you're keeping one.)");
telemetry_recording = tr;
} else {
- trace_sentences = 1 - trace_sentences;
- if (traverse == 1) Log::tracing_on(trace_sentences, I"Pass 1");
- else Log::tracing_on(trace_sentences, I"Pass 2");
+ SyntaxTree::toggle_trace(Task::syntax_tree());
+ if (traverse == 1) Log::tracing_on(SyntaxTree::is_trace_set(Task::syntax_tree()), I"Pass 1");
+ else Log::tracing_on(SyntaxTree::is_trace_set(Task::syntax_tree()), I"Pass 2");
}
}
diff --git a/inform7/linguistics-module/Chapter 5/Verb Phrases.w b/inform7/linguistics-module/Chapter 5/Verb Phrases.w
index 3d6751e98..f921a256f 100644
--- a/inform7/linguistics-module/Chapter 5/Verb Phrases.w
+++ b/inform7/linguistics-module/Chapter 5/Verb Phrases.w
@@ -101,9 +101,9 @@ verbs were added to the grammar. Still, it was a pity.
=
internal {
- if (trace_sentences) { LOG("Parsing the sentence: %W\n", W); LOG_INDENT; }
+ if (VerbPhrases::tracing()) { LOG("Parsing the sentence: %W\n", W); LOG_INDENT; }
int rv = VerbPhrases::seek(W, X, XP, 0);
- if (trace_sentences) {
+ if (VerbPhrases::tracing()) {
LOG_OUTDENT;
if (rv) {
LOG("Passed\n"); LOG_INDENT;
@@ -137,7 +137,7 @@ which word positions might be the beginning of verb phrases.
int VerbPhrases::seek(wording W, int *X, void **XP, int existential_OP_edge) {
int viable[VIABILITY_MAP_SIZE];
@;
- if (trace_sentences) @;
+ if (VerbPhrases::tracing()) @;
@;
return FALSE;
}
@@ -330,7 +330,7 @@ certainty are removed from these.
}
certainty = pre_certainty;
if (certainty == UNKNOWN_CE) certainty = post_certainty;
- if (trace_sentences) LOG("Found usage, pass %d tier %d: (%W) $w (%W)\n",
+ if (VerbPhrases::tracing()) LOG("Found usage, pass %d tier %d: (%W) $w (%W)\n",
pass, tier->priority, ISW, vi, IOW);
@ If the verb form is, say, "place in ... with ...", and we have detected the
@@ -352,7 +352,8 @@ who is in the Dining Room" (note the additional "is"), it would.
if (existential_OP_edge > 0) { /* i.e., if we are looking for "(S which) verbs (O)" */
if ((SW)) { /* there is indeed a "which" at the end of |SW| */
SW = GET_RW(, 1); /* so trim it off */
- if (trace_sentences) LOG("Trimmed to: (%W) $w (%W)\n", SW, vi, OW);
+ if (VerbPhrases::tracing())
+ LOG("Trimmed to: (%W) $w (%W)\n", SW, vi, OW);
}
}
@@ -396,7 +397,7 @@ who is in the Dining Room" (note the additional "is"), it would.
usage_succeeds = TRUE;
}
if (usage_succeeds == FALSE) {
- if (trace_sentences) LOG("$w + $p + $p : failed for lack of $p\n",
+ if (VerbPhrases::tracing()) LOG("$w + $p + $p : failed for lack of $p\n",
vi, prep, second_prep, prep);
continue;
}
@@ -419,7 +420,7 @@ who is in the Dining Room" (note the additional "is"), it would.
usage_succeeds = TRUE;
}
if (usage_succeeds == FALSE) {
- if (trace_sentences) LOG("$w + $p + $p : failed for lack of $p\n",
+ if (VerbPhrases::tracing()) LOG("$w + $p + $p : failed for lack of $p\n",
vi, prep, second_prep, second_prep);
continue;
}
@@ -450,10 +451,12 @@ representing the verb.
VP_PN = VerbPhrases::accept(vf, VP_PN, SW, OW, O2W);
if (VP_PN) {
*XP = VP_PN;
- if (trace_sentences) LOG("Accepted as $w + $p + $p\n", vi, prep, second_prep);
+ if (VerbPhrases::tracing())
+ LOG("Accepted as $w + $p + $p\n", vi, prep, second_prep);
return TRUE;
} else {
- if (trace_sentences) LOG("Rejected as $w + $p + $p\n", vi, prep, second_prep);
+ if (VerbPhrases::tracing())
+ LOG("Rejected as $w + $p + $p\n", vi, prep, second_prep);
}
@ This routine completes the sentence diagram by adding further nodes to
@@ -547,3 +550,15 @@ the exactly equivalent idea of the hat being worn by Darcy.
V->next->next = NounPhrases::PN_rel(
Node::get_text(V), VerbMeanings::reverse_VMT(meaning), STANDARD_RELN, O_PN);
}
+
+@
+
+=
+int VerbPhrases::tracing(void) {
+ #ifdef TRACING_LINGUISTICS_CALLBACK
+ return TRACING_LINGUISTICS_CALLBACK();
+ #endif
+ #ifndef TRACING_LINGUISTICS_CALLBACK
+ return FALSE;
+ #endif
+}
diff --git a/inform7/linguistics-test/Chapter 1/Program Control.w b/inform7/linguistics-test/Chapter 1/Program Control.w
index 4b2bffe62..ab4ef4c28 100644
--- a/inform7/linguistics-test/Chapter 1/Program Control.w
+++ b/inform7/linguistics-test/Chapter 1/Program Control.w
@@ -19,8 +19,6 @@ int main(int argc, char **argv) {
SyntaxModule::start();
LinguisticsModule::start();
- Unit::start_diagrams();
-
CommandLine::declare_heading(L"linguistics-test: a tool for testing the linguistics module\n");
CommandLine::declare_switch(TEST_DIAGRAMS_CLSW, L"test-diagrams", 2,
diff --git a/inform7/linguistics-test/Chapter 1/Unit Tests.w b/inform7/linguistics-test/Chapter 1/Unit Tests.w
index ee1274a40..c50dcbb6c 100644
--- a/inform7/linguistics-test/Chapter 1/Unit Tests.w
+++ b/inform7/linguistics-test/Chapter 1/Unit Tests.w
@@ -23,19 +23,27 @@ int Unit::allow_generally(verb_conjugation *vc, int tense, int sense, int person
return TRUE;
}
-@h
+@h Minimal Preform grammar.
+Only || can ever match, since the others are wired to match
+any text but then fail.
=
::=
- chapter ... | ==> 1
- section ... ==> 2
+ chapter ... | ==> 1
+ section ... ==> 2
::=
- ... ==> TRUE; return FAIL_NONTERMINAL;
+ ... ==> TRUE; return FAIL_NONTERMINAL;
::=
- ... ==> TRUE; return FAIL_NONTERMINAL;
+ ... ==> TRUE; return FAIL_NONTERMINAL;
+ ::=
+ ... ==> TRUE; return FAIL_NONTERMINAL;
+
+@
+
+=
::=
==> @
@@ -54,10 +62,6 @@ int Unit::allow_generally(verb_conjugation *vc, int tense, int sense, int person
=
int my_first_verb = TRUE;
-void Unit::start_diagrams(void) {
- trace_sentences = TRUE;
-}
-
parse_node_tree *syntax_tree = NULL;
void Unit::test_diagrams(text_stream *arg) {
Streams::enable_debugging(STDOUT);
@@ -73,6 +77,7 @@ void Unit::test_diagrams(text_stream *arg) {
text_stream *save_DL = DL;
DL = STDOUT;
Streams::enable_debugging(DL);
+ SyntaxTree::clear_trace(syntax_tree);
SyntaxTree::traverse(syntax_tree, Unit::diagram);
Node::log_tree(DL, syntax_tree->root_node);
DL = save_DL;
diff --git a/inform7/problems-test/Chapter 1/Unit Tests.w b/inform7/problems-test/Chapter 1/Unit Tests.w
index 490b7af8e..ddf0a4359 100644
--- a/inform7/problems-test/Chapter 1/Unit Tests.w
+++ b/inform7/problems-test/Chapter 1/Unit Tests.w
@@ -7,16 +7,25 @@ How we shall test it.
=
parse_node_tree *syntax_tree = NULL;
+@h Minimal Preform grammar.
+Only || can ever match, since the others are wired to match
+any text but then fail.
+
+=
::=
- chapter ... | ==> 1
- section ... ==> 2
+ chapter ... | ==> 1
+ section ... ==> 2
::=
- ... ==> TRUE; return FAIL_NONTERMINAL;
+ ... ==> TRUE; return FAIL_NONTERMINAL;
::=
- ... ==> TRUE; return FAIL_NONTERMINAL;
+ ... ==> TRUE; return FAIL_NONTERMINAL;
+ ::=
+ ... ==> TRUE; return FAIL_NONTERMINAL;
+
+@ =
::=
... banana ... ==> @;
diff --git a/shared/syntax-module/Chapter 2/Node Tyoes.w b/shared/syntax-module/Chapter 2/Node Tyoes.w
index f54d5ed22..05cb80ecb 100644
--- a/shared/syntax-module/Chapter 2/Node Tyoes.w
+++ b/shared/syntax-module/Chapter 2/Node Tyoes.w
@@ -1,4 +1,4 @@
-[NodeType::] Node Tyoes.
+[NodeType::] Node Types.
Each node in a syntax tree has a type, which informs whether it can have
child nodes, and what in general terms it means.
@@ -67,10 +67,24 @@ void NodeType::make_parentage_allowed_table(void) {
for (int i = 0; i < NO_DEFINED_NCAT_VALUES; i++)
for (int j = 0; j < NO_DEFINED_NCAT_VALUES; j++)
parentage_allowed[i][j] = FALSE;
- parentage_allowed[L1_NCAT][L1_NCAT] = TRUE;
+ NodeType::allow_parentage_for_categories(L1_NCAT, L1_NCAT);
#ifdef PARENTAGE_PERMISSIONS_SYNTAX_CALLBACK
PARENTAGE_PERMISSIONS_SYNTAX_CALLBACK();
#endif
+ #ifdef MORE_PARENTAGE_PERMISSIONS_SYNTAX_CALLBACK
+ MORE_PARENTAGE_PERMISSIONS_SYNTAX_CALLBACK();
+ #endif
+ #ifdef EVEN_MORE_PARENTAGE_PERMISSIONS_SYNTAX_CALLBACK
+ EVEN_MORE_PARENTAGE_PERMISSIONS_SYNTAX_CALLBACK();
+ #endif
+}
+
+@ The callback function |PARENTAGE_PERMISSIONS_SYNTAX_CALLBACK| should
+call this as needed to fill in more permissions:
+
+=
+void NodeType::allow_parentage_for_categories(int A, int B) {
+ parentage_allowed[A][B] = TRUE;
}
@ The bitmap of node flags currently contains only two:
@@ -164,10 +178,10 @@ text_stream *NodeType::get_name(node_type_t t) {
=
int NodeType::is_sentence(node_type_t t) {
- #ifdef SENTENCE_NODE_SYNTAX_CALLBACK
- return SENTENCE_NODE_SYNTAX_CALLBACK(t);
+ #ifdef IS_SENTENCE_NODE_SYNTAX_CALLBACK
+ return IS_SENTENCE_NODE_SYNTAX_CALLBACK(t);
#endif
- #ifndef SENTENCE_NODE_SYNTAX_CALLBACK
+ #ifndef IS_SENTENCE_NODE_SYNTAX_CALLBACK
return FALSE;
#endif
}
diff --git a/shared/syntax-module/Chapter 2/Parse Nodes.w b/shared/syntax-module/Chapter 2/Parse Nodes.w
index c4de5300f..55a7fab12 100644
--- a/shared/syntax-module/Chapter 2/Parse Nodes.w
+++ b/shared/syntax-module/Chapter 2/Parse Nodes.w
@@ -1,7 +1,7 @@
[Node::] Parse Nodes.
-To represent atomic pieces of meaning; or, less pretentiously, to provide
-the nodes of which syntax trees are made up.
+Syntax trees are made of single nodes, each representing one way to understand
+a given piece of text.
@h Nodes themselves.
Each node is an instance of this:
@@ -9,26 +9,18 @@ Each node is an instance of this:
=
typedef struct parse_node {
struct wording text_parsed; /* the text being interpreted by this node */
-
node_type_t node_type; /* what the node basically represents */
struct parse_node_annotation *annotations; /* see //Node Annotations// */
struct parse_node *down; /* pointers within the current interpretation */
struct parse_node *next;
-
- int score; /* used to choose most likely interpretation */
struct parse_node *next_alternative; /* fork to alternative interpretation */
- int log_time; /* used purely as a defensive measure when writing debugging log */
+ int score; /* scratch storage for choosing between interpretations */
+ int last_seen_on_traverse; /* scratch storage for detecting accidental loops */
CLASS_DEFINITION
} parse_node;
-@ Various modules conventionally use this global setting to toggle debugging
-log output:
-
-=
-int trace_sentences = FALSE;
-
@h Creation.
=
@@ -38,7 +30,7 @@ parse_node *Node::new(node_type_t t) {
Node::set_text(pn, EMPTY_WORDING);
Annotations::clear(pn);
pn->down = NULL; pn->next = NULL; pn->next_alternative = NULL;
- pn->log_time = 0;
+ pn->last_seen_on_traverse = 0;
Node::set_score(pn, 0);
return pn;
}
@@ -236,12 +228,10 @@ that we're logging a badly-formed tree; this should never happen, but since
logging is a diagnostic tool, we want it to work even when Inform is sick.
=
-int pn_log_token = 0;
-
void Node::log_tree(OUTPUT_STREAM, void *vpn) {
parse_node *pn = (parse_node *) vpn;
if (pn == NULL) { WRITE("\n"); return; }
- Node::log_subtree_recursively(OUT, pn, 0, 0, 1, ++pn_log_token);
+ Node::log_subtree_recursively(OUT, pn, 0, 0, 1, SyntaxTree::new_traverse_token());
}
void Node::log_subtree(OUTPUT_STREAM, void *vpn) {
@@ -260,12 +250,13 @@ to pursue |next| links, since otherwise a source text with more than 100,000
sentences or so will exceed the typical stack size Inform has to run in.
=
-void Node::log_subtree_recursively(OUTPUT_STREAM, parse_node *pn, int num, int of, int gen, int ltime) {
+void Node::log_subtree_recursively(OUTPUT_STREAM, parse_node *pn, int num,
+ int of, int gen, int traverse_token) {
while (pn) {
- if (pn->log_time == ltime) {
+ if (pn->last_seen_on_traverse == traverse_token) {
WRITE("*** Not a tree: %W ***\n", Node::get_text(pn)); return;
}
- pn->log_time = ltime;
+ pn->last_seen_on_traverse = traverse_token;
@;
if (pn == NULL) { WRITE("\n"); return; }
@@ -276,10 +267,11 @@ void Node::log_subtree_recursively(OUTPUT_STREAM, parse_node *pn, int num, int o
WRITE("$P\n", pn);
if (pn->down) {
LOG_INDENT;
- Node::log_subtree_recursively(OUT, pn->down, 0, 0, gen+1, ltime);
+ Node::log_subtree_recursively(OUT, pn->down, 0, 0, gen+1, traverse_token);
LOG_OUTDENT;
}
- if (pn->next_alternative) Node::log_subtree_recursively(OUT, pn->next_alternative, num+1, of, gen+1, ltime);
+ if (pn->next_alternative) Node::log_subtree_recursively(OUT,
+ pn->next_alternative, num+1, of, gen+1, traverse_token);
pn = pn->next; num = 0; of = 0; gen++;
}
@@ -315,7 +307,8 @@ void Node::log_node(OUTPUT_STREAM, void *vpn) {
Diagrams::log_node(OUT, pn);
#endif
switch(pn->node_type) {
- case HEADING_NT: WRITE(" (level %d)", Annotations::read_int(pn, heading_level_ANNOT)); break;
+ case HEADING_NT: WRITE(" (level %d)", Annotations::read_int(pn,
+ heading_level_ANNOT)); break;
}
#endif
int a = 0;
@@ -332,60 +325,3 @@ void Node::log_with_annotations(parse_node *pn) {
LOG("-%d", pna->annotation_id);
LOG("\n");
}
-
-@h Ambiguity subtrees.
-
-=
-parse_node *Node::add_possible_reading(parse_node *existing, parse_node *reading, wording W) {
- if (existing == NULL) return reading;
-#ifdef CORE_MODULE
- if (Node::is(reading, UNKNOWN_NT)) return existing;
-#endif
- if (Node::is(reading, AMBIGUITY_NT)) reading = reading->down;
-
- if (Node::is(existing, AMBIGUITY_NT)) {
- #ifdef CORE_MODULE
- if (ParseTreeUsage::is_phrasal(reading))
- for (parse_node *E = existing->down; E; E = E->next_alternative)
- if (Node::get_type(reading) == Node::get_type(E)) {
- Node::add_pr_inv(E, reading);
- return existing;
- }
- #endif
- parse_node *L = existing->down;
- while ((L) && (L->next_alternative)) L = L->next_alternative;
- L->next_alternative = reading;
- return existing;
- }
-
- #ifdef CORE_MODULE
- if ((ParseTreeUsage::is_phrasal(reading)) &&
- (Node::get_type(reading) == Node::get_type(existing))) {
- Node::add_pr_inv(existing, reading);
- return existing;
- }
- #endif
-
- parse_node *A = Node::new_with_words(AMBIGUITY_NT, W);
- A->down = existing;
- A->down->next_alternative = reading;
- return A;
-}
-
-#ifdef CORE_MODULE
-void Node::add_pr_inv(parse_node *E, parse_node *reading) {
- for (parse_node *N = reading->down->down, *next_N = (N)?(N->next_alternative):NULL; N;
- N = next_N, next_N = (N)?(N->next_alternative):NULL)
- Node::add_single_pr_inv(E, N);
-}
-
-void Node::add_single_pr_inv(parse_node *E, parse_node *N) {
- E = E->down->down;
- if (Invocations::eq(E, N)) return;
- while ((E) && (E->next_alternative)) {
- E = E->next_alternative;
- if (Invocations::eq(E, N)) return;
- }
- E->next_alternative = N; N->next_alternative = NULL;
-}
-#endif
diff --git a/shared/syntax-module/Chapter 2/Syntax Trees.w b/shared/syntax-module/Chapter 2/Syntax Trees.w
index e131fa2a5..07a31d359 100644
--- a/shared/syntax-module/Chapter 2/Syntax Trees.w
+++ b/shared/syntax-module/Chapter 2/Syntax Trees.w
@@ -30,6 +30,7 @@ typedef struct parse_node_tree {
struct parse_node *bud_parent_stack[MAX_BUD_STACK_SIZE];
struct parse_node *last_sentence; /* cached position in tree */
int allow_last_sentence_cacheing;
+ int trace_sentences;
HEADING_TREE_SYNTAX_TYPE *headings;
CLASS_DEFINITION
} parse_node_tree;
@@ -40,6 +41,7 @@ parse_node_tree *SyntaxTree::new(void) {
T->bud_parent_sp = 0;
T->last_sentence = NULL;
T->allow_last_sentence_cacheing = FALSE;
+ T->trace_sentences = FALSE;
SyntaxTree::push_bud(T, T->root_node);
#ifdef NEW_HEADING_TREE_SYNTAX_CALLBACK
T->headings = NEW_HEADING_TREE_SYNTAX_CALLBACK(T);
@@ -440,3 +442,96 @@ void SyntaxTree::traverse_wfirst_from(parse_node *pn, void (*visitor)(parse_node
}
current_sentence = SCS;
}
+
+@h Cautious traverses.
+When logging or verifying the tree, we cannot use the carefree functions
+above: the tree might be malformed. As a way to detect cycles, we call for
+a new "traverse token" -- just a unique integer value -- and mark all nodes
+visited with that value.
+
+=
+int pn_log_token = 0;
+
+int SyntaxTree::new_traverse_token(void) {
+ return ++pn_log_token;
+}
+
+@h Toggling log output.
+Various modules conventionally use this global setting to toggle debugging
+log output:
+
+=
+int SyntaxTree::is_trace_set(parse_node_tree *T) {
+ return T->trace_sentences;
+}
+
+void SyntaxTree::set_trace(parse_node_tree *T) {
+ T->trace_sentences = TRUE;
+}
+
+void SyntaxTree::clear_trace(parse_node_tree *T) {
+ T->trace_sentences = FALSE;
+}
+
+void SyntaxTree::toggle_trace(parse_node_tree *T) {
+ T->trace_sentences = (T->trace_sentences)?FALSE:TRUE;
+}
+
+@h Ambiguity subtrees.
+The following function adds a new |reading| to an |existing| interpretation
+of some wording |W|, and return the node now representing. For example,
+suppose the text "orange" can be read as a noun for fruit, a noun for colour,
+or an adjective, resulting in nodes |fruit_node| and |colour_node| and |adj_node|.
+Then:
+(a) |SyntaxTree::add_reading(NULL, fruit_node, W)| returns |noun_node|,
+(b) but |SyntaxTree::add_reading(fruit_node, colour_node, W)| returns this subtree:
+= (text)
+ AMBIGUITY_NT A
+ fruit_node
+ colour_node
+=
+(c) and |SyntaxTree::add_reading(A, adj_node, W)| returns the subtree:
+= (text)
+ AMBIGUITY_NT A
+ fruit_node
+ colour_node
+ adj_node
+=
+Thus it accumulates possible readings of a given text.
+
+A complication is that the following callback function is offered the chance
+to amend this process in individual cases; it's called whenever |reading|
+is about to become one of the alternatives to some existing |E|. If it returns
+a non-null node, that's the answer, and otherwise we carry on as normal.
+
+(//inform7// uses this to handle ambiguous phrase invocations to be sorted
+out in type-checking: see //core: Dash//.)
+
+=
+parse_node *SyntaxTree::add_reading(parse_node *existing, parse_node *reading, wording W) {
+ if (existing == NULL) return reading;
+ if (Node::is(reading, UNKNOWN_NT)) return existing;
+ if (Node::is(reading, AMBIGUITY_NT)) reading = reading->down;
+ if (Node::is(existing, AMBIGUITY_NT)) {
+ #ifdef AMBIGUITY_JOIN_SYNTAX_CALLBACK
+ for (parse_node *E = existing->down; E; E = E->next_alternative) {
+ parse_node *pn = AMBIGUITY_JOIN_SYNTAX_CALLBACK(E, reading);
+ if (pn) return pn;
+ }
+ #endif
+ parse_node *L = existing->down;
+ while ((L) && (L->next_alternative)) L = L->next_alternative;
+ L->next_alternative = reading;
+ return existing;
+ }
+
+ #ifdef AMBIGUITY_JOIN_SYNTAX_CALLBACK
+ parse_node *pn = AMBIGUITY_JOIN_SYNTAX_CALLBACK(existing, reading);
+ if (pn) return pn;
+ #endif
+
+ parse_node *A = Node::new_with_words(AMBIGUITY_NT, W);
+ A->down = existing;
+ A->down->next_alternative = reading;
+ return A;
+}
diff --git a/shared/syntax-module/Chapter 2/Tree Verification.w b/shared/syntax-module/Chapter 2/Tree Verification.w
index 3eb16592d..548d92f24 100644
--- a/shared/syntax-module/Chapter 2/Tree Verification.w
+++ b/shared/syntax-module/Chapter 2/Tree Verification.w
@@ -5,6 +5,8 @@ Inform contains bugs of a kind which lead to malformed syntax trees: that
should never happen even if the source text being compiled is a dumpster fire.
@h Verify integrity.
+We can perform two different checks.
+
The first duty of a tree is to contain no loops, and the following checks
that (rejecting even undirected loops). In addition, it checks that each
node has an enumerated node type, rather than a meaning code.
@@ -12,33 +14,30 @@ node has an enumerated node type, rather than a meaning code.
=
int tree_stats_size = 0, tree_stats_depth = 0, tree_stats_width = 0;
-void VerifyTree::verify_integrity(parse_node *p, int worth_logging) {
+void VerifyTree::verify_integrity(parse_node_tree *T) {
tree_stats_size = 0; tree_stats_depth = 0; tree_stats_width = 1;
- VerifyTree::verify_tree_integrity_recursively(p->down, p, "down", 0, ++pn_log_token);
+ VerifyTree::verify_integrity_below(T->root_node);
+}
+
+void VerifyTree::verify_integrity_below(parse_node *p) {
+ VerifyTree::verify_integrity_r(p->down, p, "down", 0,
+ SyntaxTree::new_traverse_token());
}
@ The verification traverse is a very cautious manoeuvre: we step through
-the tree, testing each branch with our outstretched foot in case it might
-be illusory or broken. At the first sign of trouble we panic.
+the tree, testing each branch with our outstretched foot. At the first sign
+of trouble we panic.
=
-void VerifyTree::verify_tree_integrity_recursively(parse_node *p,
- parse_node *from, char *way, int depth, int ltime) {
- int width;
- pointer_sized_int probably_an_address = (pointer_sized_int) p;
- depth++; if (depth > tree_stats_depth) tree_stats_depth = depth;
- for (width = 0; p; p = p->next, width++) {
- if ((probably_an_address == 0) || (probably_an_address == -1)) {
- LOG("Link %s broken from:\n$P", way, from);
- Errors::set_internal_handler(NULL);
- internal_error("Link broken in parse tree");
- }
- if (p->log_time == ltime) {
+void VerifyTree::verify_integrity_r(parse_node *p,
+ parse_node *from, char *way, int depth, int traverse_token) {
+ for (int width = 0; p; p = p->next, width++) {
+ if (p->last_seen_on_traverse == traverse_token) {
LOG("Cycle found in parse tree, found %s from:\n$P", way, from);
Errors::set_internal_handler(NULL);
internal_error("Cycle found in parse tree");
}
- p->log_time = ltime;
+ p->last_seen_on_traverse = traverse_token;
node_type_t t = Node::get_type(p);
if (NodeType::is_enumerated(t)) tree_stats_size++;
else {
@@ -47,50 +46,45 @@ void VerifyTree::verify_tree_integrity_recursively(parse_node *p,
internal_error("Link broken in parse tree");
}
if (p->next_alternative)
- VerifyTree::verify_tree_integrity_recursively(p->next_alternative, p, "alt", depth, ltime);
+ VerifyTree::verify_integrity_r(p->next_alternative,
+ p, "alt", depth, traverse_token);
if (p->down)
- VerifyTree::verify_tree_integrity_recursively(p->down, p, "down", depth, ltime);
+ VerifyTree::verify_integrity_r(p->down,
+ p, "down", depth+1, traverse_token);
+ if (width > tree_stats_width) tree_stats_width = width;
}
- if (width > tree_stats_width) tree_stats_width = width;
+ if (depth > tree_stats_depth) tree_stats_depth = depth;
}
@h Verify structure.
The parse tree is a complicated structure, arbitrarily wide and deep, and
containing many different node types, each subject to its own rules of usage.
-(For instance, a |SENTENCE_NT| node cannot legally be beneath a
-|PROPER_NOUN_NT| one.) This is both good and bad: bad because complexity is
-always the enemy of program correctness, good because it gives us an
-independent opportunity to test a great deal of what earlier code has done.
-If, given every test case, we always construct a well-formed tree, we must be
-doing something right.
+In this second check, we ensure that nodes have acceptable parentage and
+annotations -- that is, parentage and annotations which fall within the
+permissions set up when their node types were created.
-The collection of rules like this which the tree must satisfy is called its
-"invariant", and is expressed by the code below. Note that this is
-verification, not an attempt to correct matters. If any test fails, Inform
-will stop with an internal error. (If there are multiple failures, we
-itemise them to the debugging log, and only produce a single internal error
-at the end.)
+If any test fails, Inform will stop with an internal error. (If there are
+multiple failures, we itemise them to the debugging log, and only produce
+a single internal error at the end.)
We protect ourselves by first checking that the tree is intact as a
structure: once we know the tree is safe to climb over, we can wander
-about counting children with impunity.
+about counting branches with impunity.
=
-void VerifyTree::verify_node(parse_node_tree *T) {
+void VerifyTree::verify_structure(parse_node_tree *T) {
if (T->root_node == NULL) {
Errors::set_internal_handler(NULL);
internal_error("Root of parse tree NULL");
}
- VerifyTree::verify_structure(T->root_node);
+ VerifyTree::verify_structure_from(T->root_node);
}
-int node_errors = 0;
-void VerifyTree::verify_structure(parse_node *p) {
- VerifyTree::verify_integrity(p, FALSE);
- node_errors = 0;
- VerifyTree::verify_structure_recursively(p, NULL);
- if (node_errors > 0) {
- LOG("[Verification failed: %d node errors]\n", node_errors);
+void VerifyTree::verify_structure_from(parse_node *p) {
+ VerifyTree::verify_integrity_below(p);
+ int errors_found = VerifyTree::verify_structure_r(p, NULL, 0);
+ if (errors_found > 0) {
+ LOG("[Verification failed: %d node errors]\n", errors_found);
Errors::set_internal_handler(NULL);
internal_error("Parse tree broken");
}
@@ -102,7 +96,7 @@ parse node and (ii) either |p| is the tree root, in which case |parent| is
among its children.
=
-void VerifyTree::verify_structure_recursively(parse_node *p, parse_node *parent) {
+int VerifyTree::verify_structure_r(parse_node *p, parse_node *parent, int ec) {
node_type_t t = Node::get_type(p);
node_type_metadata *metadata = NodeType::get_metadata(t);
if (metadata == NULL) internal_error("broken tree should have been reported");
@@ -113,19 +107,21 @@ void VerifyTree::verify_structure_recursively(parse_node *p, parse_node *parent)
int children_count = 0;
for (parse_node *q=p->down; q; q=q->next, children_count++)
- VerifyTree::verify_structure_recursively(q, p);
+ ec += VerifyTree::verify_structure_r(q, p, ec);
@;
if (p->next_alternative)
- VerifyTree::verify_structure_recursively(p->next_alternative, parent);
+ ec += VerifyTree::verify_structure_r(p->next_alternative, parent, ec);
+ return ec;
}
@ Rule (1): no INVALID nodes.
@ =
if (t == INVALID_NT) {
- LOG("N%d is $N, which is not allowed except temporarily\n", p->allocation_id, t);
+ LOG("N%d is $N, which is not allowed except temporarily\n",
+ p->allocation_id, t);
@
}
@@ -146,7 +142,8 @@ void VerifyTree::verify_structure_recursively(parse_node *p, parse_node *parent)
node_type_t t_parent = Node::get_type(parent);
if (!(NodeType::parentage_allowed(t_parent, t))) {
- LOG("N%d is $N: should not be a child of $N\n", p->allocation_id, t, t_parent);
+ LOG("N%d is $N: should not be a child of $N\n",
+ p->allocation_id, t, t_parent);
@
}
@@ -164,7 +161,9 @@ void VerifyTree::verify_structure_recursively(parse_node *p, parse_node *parent)
@
}
+@ (Logging the root node produces an absolutely enormous output.)
+
@ =
if (Node::is(parent, ROOT_NT)) LOG("Failing subtree:\n$T", p);
else LOG("Failing subtree:\n$T", parent);
- node_errors++;
+ ec++;
diff --git a/shared/syntax-module/Chapter 3/Sentences.w b/shared/syntax-module/Chapter 3/Sentences.w
index 2792c4496..63ffce6d5 100644
--- a/shared/syntax-module/Chapter 3/Sentences.w
+++ b/shared/syntax-module/Chapter 3/Sentences.w
@@ -33,10 +33,16 @@ in Preform grammar functions.
@default PROBLEM_REF_SYNTAX_TYPE void
@default PROJECT_REF_SYNTAX_TYPE void
+@e NO_EXTENSION_POS from 0
+@e BEFORE_BEGINS_EXTENSION_POS
+@e MIDDLE_EXTENSION_POS
+@e AFTER_ENDS_EXTENSION_POS
+@e PAST_CARING_EXTENSION_POS
+
=
typedef struct syntax_fsm_state {
source_file *sf; /* reading from this source file */
- int ext_pos; /* 0: not extension; 1: before "begins here"; 2: before "ends here"; 3: after */
+ int ext_pos; /* one of the |*_EXTENSION_POS| values: where we are in an extension */
int skipping_material_at_level;
int main_source_start_wn;
node_type_t nt;
@@ -66,7 +72,8 @@ void Sentences::reset(syntax_fsm_state *sfsm, int is_extension,
sfsm->skipping_material_at_level = -1;
sfsm->ref = ref;
sfsm->project_ref = project_ref;
- if (is_extension) sfsm->ext_pos = 1; else sfsm->ext_pos = 0;
+ if (is_extension) sfsm->ext_pos = BEFORE_BEGINS_EXTENSION_POS;
+ else sfsm->ext_pos = NO_EXTENSION_POS;
}
@ These are the syntax errors we will generate.
@@ -311,7 +318,8 @@ or until reaching the end of the text: whichever comes first.
=
void Sentences::make_node(parse_node_tree *T, wording W, int stop_character) {
- int heading_level = 0, begins_or_ends = 0;
+ int heading_level = 0;
+ int begins_or_ends = 0; /* 1 for "begins here", -1 for "ends here" */
parse_node *new;
if (Wordings::empty(W)) internal_error("empty sentence generated");
@@ -357,9 +365,9 @@ is declared as if it were a super-heading in the text.
sfsm->sf = Lexer::file_of_origin(Wordings::first_wn(W));
@ =
- if ((sfsm->ext_pos == 3) && (begins_or_ends == 0)) {
+ if ((sfsm->ext_pos == AFTER_ENDS_EXTENSION_POS) && (begins_or_ends == 0)) {
Sentences::syntax_problem(ExtSpuriouslyContinues_SYNERROR, W, sfsm->ref, 0);
- sfsm->ext_pos = 4; /* to avoid multiply issuing this */
+ sfsm->ext_pos = PAST_CARING_EXTENSION_POS; /* to avoid multiply issuing this */
}
@ The client must define a Preform nonterminal called ||
@@ -370,8 +378,8 @@ important), or |-1| to mean that the sentence begins an extension, or
@ =
if ((W)) {
switch (<>) {
- case -1: if (sfsm->ext_pos > 0) begins_or_ends = 1; break;
- case -2: if (sfsm->ext_pos > 0) begins_or_ends = -1; break;
+ case -1: if (sfsm->ext_pos != NO_EXTENSION_POS) begins_or_ends = 1; break;
+ case -2: if (sfsm->ext_pos != NO_EXTENSION_POS) begins_or_ends = -1; break;
default: heading_level = <>; break;
}
}
@@ -403,7 +411,8 @@ newlines automatically added at the end of the feed of any source file.
if (Lexer::break_before(Wordings::last_wn(W)+1) != '\n') {
int k;
for (k = Wordings::last_wn(W)+1;
- (k<=Wordings::last_wn(W)+8) && (kref, k);
}
@@ -427,9 +436,10 @@ from an extension, we need to make sure we saw both beginning and end:
@ =
switch (sfsm->ext_pos) {
- case 1: Sentences::syntax_problem(ExtNoBeginsHere_SYNERROR, W, sfsm->ref, 0); break;
- case 2: Sentences::syntax_problem(ExtNoEndsHere_SYNERROR, W, sfsm->ref, 0); break;
- case 3: break;
+ case BEFORE_BEGINS_EXTENSION_POS:
+ Sentences::syntax_problem(ExtNoBeginsHere_SYNERROR, W, sfsm->ref, 0); break;
+ case MIDDLE_EXTENSION_POS:
+ Sentences::syntax_problem(ExtNoEndsHere_SYNERROR, W, sfsm->ref, 0); break;
}
@h Unskipped material which is not a heading.
@@ -482,7 +492,7 @@ sentences and options-file sentences may have been read already.)
@;
if (sfsm->inside_rule_mode)
- @
+ @
else if (stop_character == ';') {
Sentences::syntax_problem(UnexpectedSemicolon_SYNERROR, W, sfsm->ref, 0);
stop_character = '.';
@@ -509,26 +519,10 @@ sentences and options-file sentences may have been read already.)
/* none of that happened, so we have a SENTENCE node for certain */
Annotations::write_int(new, sentence_unparsed_ANNOT, TRUE);
- #ifdef SENTENCE_ANNOTATION_SYNTAX_CALLBACK
- SENTENCE_ANNOTATION_SYNTAX_CALLBACK(new);
+ #ifdef NEW_NONSTRUCTURAL_SENTENCE_SYNTAX_CALLBACK
+ NEW_NONSTRUCTURAL_SENTENCE_SYNTAX_CALLBACK(new);
#endif
-@ Rules are ordinarily detected by their colon, which divides the header from the
-rest: colons are not otherwise legal in Inform. But there's an exception. If the
-sentence consists of text matching the following grammar, followed by comma,
-followed by more text, then the comma is read as if it's a colon and the
-sentence becomes a rule. For example:
-
->> Instead of going north, try entering the cage
-
-=
- ::=
- instead of ... |
- every turn *** |
- before ... |
- after ... |
- when ...
-
@ We make an exception to the exception for the serial comma used in a list of
alternatives: thus the comma in "Aeschylus, Sophocles, or Euripides" does
not trigger this rule. We need this exception because such lists of
@@ -639,7 +633,7 @@ instead of a semicolon. We may lament this, but it is so.)
@ Subsequent commands are divided by semicolons, and any failure of a
semicolon to appear indicates an end of the rule.
-@ =
+@ =
#ifdef list_node_type
Node::set_type(new, list_entry_node_type);
#endif
diff --git a/shared/syntax-module/Contents.w b/shared/syntax-module/Contents.w
index 1c2038d83..e3e1a3013 100644
--- a/shared/syntax-module/Contents.w
+++ b/shared/syntax-module/Contents.w
@@ -6,6 +6,7 @@ Licence: Artistic License 2.0
Preliminaries
What This Module Does
+ How To Include This Module
Chapter 1: Setting Up
"Loading this module."
diff --git a/shared/syntax-module/Preliminaries/How To Include This Module.w b/shared/syntax-module/Preliminaries/How To Include This Module.w
new file mode 100644
index 000000000..661ce2400
--- /dev/null
+++ b/shared/syntax-module/Preliminaries/How To Include This Module.w
@@ -0,0 +1,113 @@
+How To Include This Module.
+
+What to do to make use of the syntax module in a new command-line tool.
+
+@h Status.
+The syntax module provided as one of the "shared" Inform modules, which means
+that it was built with a view to potential incorporation in multiple tools.
+It can be found, for example, in //inform7//, //inbuild// and //syntax-test//,
+among others. //syntax-test// may be useful as a minimal example of a tool
+using //syntax//.
+
+By convention, the modules considered as "shared" have no dependencies on
+other modules except for //foundation// and other "shared" modules.
+
+A tool can import //syntax// only if it also imports //foundation// and
+//words//.
+
+@h Importing the module.
+We'll use the term "parent" to mean the tool which is importing //syntax//,
+that is, which will include its code and be able to use it. As with any
+imported module,
+(*) The contents page of the parent's web must identify and locate the
+module:
+= (text as Inweb)
+Import: somepath/syntax
+=
+(*) The parent must call |SyntaxModule::start()| just after it starts up, and
+|SyntaxModule::end()| just before it shuts down. (But just after, and just
+before, the corresponding calls to //foundation//.)
+
+But in addition, the parent of //syntax// must define some Preform grammar:
+
+(*) || to recognise sentences modifying the
+language which is currently being parsed;
+(*) || to recognise structurally important sentences;
+(*) || to recognise sentences which divide up the text,
+normally headings;
+(*) || to recognise sentences where a comma plays
+a role normally expected to be played by a colon.
+
+Though compulsory, these don't need to do much: see //syntax-test: Unit Tests//.
+
+@h Using callbacks.
+Shared modules like this one are tweaked in behaviour by defining "callback
+functions". This means that the parent might provide a function of its own
+which would answer a question put to it by the module, or take some action
+on behalf of the module: it's a callback in the sense that the parent is
+normally calling the module, but then the module calls the parent back to
+ask for data or action.
+
+The parent must indicate which function to use by defining a constant with
+a specific name as being equal to that function's name. A fictional example
+would be
+= (text as Inweb)
+ @d EXPRESS_SURPRISE_SYNTAX_CALLBACK Emotions::gosh
+
+ =
+ void Emotions::gosh(text_stream *OUT) {
+ WRITE("Good gracious!\n");
+ }
+=
+The syntax module has many callbacks, but they are all optional. The following
+alphabetical list has references to fuller explanations:
+
+(*) |AMBIGUITY_JOIN_SYNTAX_CALLBACK| can divert ambiguous readings and prevent
+them from being added to a syntax tree: see //SyntaxTree::add_reading//.
+
+(*) |ANNOTATION_COPY_SYNTAX_CALLBACK| can perform deep rather than shallow
+copies of node annotations when these are essential: see //Annotations::copy//.
+
+(*) |ANNOTATION_PERMISSIONS_SYNTAX_CALLBACK|, |MORE_ANNOTATION_PERMISSIONS_SYNTAX_CALLBACK|
+and |EVEN_MORE_ANNOTATION_PERMISSIONS_SYNTAX_CALLBACK| gives permission for nodes
+of given types to have annotations with given IDs, and effectively provides a
+way to create custom annotations: see //Annotations::make_annotation_allowed_table//.
+
+(*) |BEGIN_OR_END_HERE_SYNTAX_CALLBACK| is called when a new extension beginning
+or ending sentence is found in the source text being broken into sentences:
+see //Sentences::make_node//.
+
+(*) |LANGUAGE_ELEMENT_SYNTAX_CALLBACK| is called when a sentence is found matching
+the nonterminal ||: see //Sentences::make_node//.
+
+(*) |LOG_UNENUMERATED_NODE_TYPES_SYNTAX_CALLBACK| is called to log a node type
+not recognised as one of the enumerated |*_NT| values: see //NodeType::log//.
+
+(*) |NEW_HEADING_SYNTAX_CALLBACK| is called when a new heading sentence is found
+in the source text being broken into sentences: see //Sentences::make_node//.
+
+(*) |NEW_HEADING_TREE_SYNTAX_CALLBACK| is called when a new syntax tree is being
+created, and needs to be given a matching tree of headings: see //SyntaxTree::new//.
+
+(*) |NODE_METADATA_SETUP_SYNTAX_CALLBACK|, |MORE_NODE_METADATA_SETUP_SYNTAX_CALLBACK|
+and |EVEN_MORE_NODE_METADATA_SETUP_SYNTAX_CALLBACK| adds new syntax tree node
+types: see //NodeType::metadata_setup//.
+
+(*) |PARENTAGE_EXCEPTIONS_SYNTAX_CALLBACK| allows exceptions to the rules about
+which nodes in a syntax tree can be parents of which other nodes: see
+//NodeType::parentage_allowed//.
+
+(*) |PARENTAGE_PERMISSIONS_SYNTAX_CALLBACK|, |MORE_PARENTAGE_PERMISSIONS_SYNTAX_CALLBACK|
+and |EVEN_MORE_PARENTAGE_PERMISSIONS_SYNTAX_CALLBACK| adds permissions for nodes
+to be parents of each other: see //NodeType::make_parentage_allowed_table//.
+
+(*) |PROBLEM_SYNTAX_CALLBACK| is called when a syntax error is found, and can
+prevent this from being issued to the terminal as an error message: see
+//Sentences::syntax_problem//.
+
+(*) |NEW_NONSTRUCTURAL_SENTENCE_SYNTAX_CALLBACK| is called when a new, regular
+sentence is found in the source text being broken into sentences: see
+//Sentences::make_node//.
+
+(*) |IS_SENTENCE_NODE_SYNTAX_CALLBACK| is asked whether a given node represents
+a regular sentence or not: see //NodeType::is_sentence//.
diff --git a/shared/syntax-module/Preliminaries/What This Module Does.w b/shared/syntax-module/Preliminaries/What This Module Does.w
index 33b673b4f..57c37240a 100644
--- a/shared/syntax-module/Preliminaries/What This Module Does.w
+++ b/shared/syntax-module/Preliminaries/What This Module Does.w
@@ -31,18 +31,7 @@ source text compiled by //inform7// is just one syntax tree. When //supervisor//
manages extensions, it may generate one //parse_node_tree// object for each
extension whose text it reads. Still -- there are few trees.
-But there are many nodes. Syntax trees are made up of //parse_node// structures.
-While these are in principle individual nodes, they effectively represent
-subtrees, because they carry with them links to the nodes below. A //parse_node//
-object can therefore equally represent "orange", "the orange envelope", or
-"now the card is in the orange envelope".
-
-Meaning is an ambiguous thing, and so the tree needs to be capable of
-representing multiple interpretations of the same wording. So nodes have not
-only |next| and |down| links to other nodes, but also |next_alternative| links,
-which -- if used -- fork the syntax tree into different possible readings.
-
-@ The main trunk of the tree can be grown in any sequence: call //SyntaxTree::push_bud//
+@ The trunk of the tree can be grown in any sequence: call //SyntaxTree::push_bud//
to begin "budding" from a particular branch, and //SyntaxTree::pop_bud// to go back
to where you were. These are also used automatically to ensure that sentences
arriving at //SyntaxTree::graft_sentence// are grafted under the headings to
@@ -67,5 +56,55 @@ But it is also possible to graft smaller (not-whole-sentence) cuttings onto
each other using //SyntaxTree::graft//, which doesn't involve the bud stack
at all.
+@ Meaning is an ambiguous thing, and so the tree needs to be capable of
+representing multiple interpretations of the same wording. So nodes have not
+only |next| and |down| links to other nodes, but also |next_alternative| links,
+which -- if used -- fork the syntax tree into different possible readings.
+
+These are not added to the tree by grafting: that's only done for definite
+meanings. Instead, multiple ambiguous readings mostly lie beneath |AMBIGUITY_NT|
+nodes -- see //SyntaxTree::add_reading//. For example, we might have:
+= (text)
+ sun is orange
+ sun
+ AMBIGUITY
+ orange (read as being a fruit)
+ orange (read as being a colour)
+=
+
@ An extensive suite of functions is provided to make it easy to traverse
a syntax tree, calling a visitor function on each node: see //SyntaxTree::traverse//.
+
+@h Nodes.
+Syntax trees are made up of //parse_node// structures. While these are in
+principle individual nodes, they effectively represent subtrees, because they
+carry with them links to the nodes below. A //parse_node// object can
+therefore equally represent "orange", "the orange envelope", or "now the card
+is in the orange envelope".
+
+Each node carries three essential pieces of information with it:
+(1) The text giving rise to it (say, "Section Five - Fruit").
+(2) A node type ID, which in broad terms says what kind of reference is being
+made (say, |HEADING_NT|). The possible node types are stored in the C type
+|node_type_t|, which corresponds to some metadata in a //node_type_metadata//
+object: see //Node::get_type// and //NodeType::get_metadata//.
+(3) A list of optional annotations, which are either integer or object-valued,
+and which give specifics about the meaning (say, the level number in the
+hierarchy of headings). See //Node Annotations//.
+
+@h Fussy, defensive, pedantry.
+Safe to say that Inform includes bugs: the more defensive coding we can do,
+the better. That means not only extensive logging (see //Node::log_tree//)
+but also strict verification tests on every tree made (see //Tree Verification//).
+(a) The only nodes allowed to exist are those for node types declared
+by //NodeType::new//: more generally, see //Node Types// on metadata associated
+with these.
+(b) A node of type |A| can only be a child of a node of type |B| if
+//NodeType::parentage_allowed// says so, and this is (mostly) a matter
+of calling //NodeType::allow_parentage_for_categories// -- parentage depends
+not on the type per se, but on the category of the type, which groups types
+together.
+(c) A node of type |A| can only have an annotation with ID |I| if
+//Annotations::is_allowed// says so. To declare an annotation legal,
+call |Annotations::allow(A, I)|, or |Annotations::allow_for_category(C, I)|
+for the category |C| of |A|.
diff --git a/shared/syntax-test/Chapter 1/Unit Tests.w b/shared/syntax-test/Chapter 1/Unit Tests.w
index 49c22fb1c..1ab2100a0 100644
--- a/shared/syntax-test/Chapter 1/Unit Tests.w
+++ b/shared/syntax-test/Chapter 1/Unit Tests.w
@@ -2,18 +2,23 @@
How we shall test it.
-@h
+@h Minimal Preform grammar.
+Only || can ever match, since the others are wired to match
+any text but then fail.
=
::=
- chapter ... | ==> 1
- section ... ==> 2
+ chapter ... | ==> 1
+ section ... ==> 2
::=
- ... ==> TRUE; return FAIL_NONTERMINAL;
+ ... ==> TRUE; return FAIL_NONTERMINAL;
::=
- ... ==> TRUE; return FAIL_NONTERMINAL;
+ ... ==> TRUE; return FAIL_NONTERMINAL;
+
+ ::=
+ ... ==> TRUE; return FAIL_NONTERMINAL;
@h Syntax tree.
diff --git a/shared/words-module/Chapter 4/Preform.w b/shared/words-module/Chapter 4/Preform.w
index d168cf109..56264ad72 100644
--- a/shared/words-module/Chapter 4/Preform.w
+++ b/shared/words-module/Chapter 4/Preform.w
@@ -1746,7 +1746,7 @@ and the pointer result is null.
if (nt->multiplicitous) {
#ifdef CORE_MODULE
added_to_result = QP;
- acc_result = (void *) Node::add_possible_reading((parse_node *) acc_result, QP, W);
+ acc_result = (void *) SyntaxTree::add_reading((parse_node *) acc_result, QP, W);
#endif
goto Fail;
}