- Home
- Inform7 Modules
- if
- Chapter 5: Command Grammar
- Grammar Types
Some grammar text specifies one or more values, and we need to keep track of their kind(s). Here we manage the data structure doing this.
typedef struct grammar_type {
int no_resulting_values; number of resulting values: 0, 1 or 2; or -1
struct parse_node *first_type; and their types
struct parse_node *second_type;
int first_multiplicity; lines only: allow a multiple object here?
int second_multiplicity; lines only: allow a multiple object here?
} grammar_type;
The structure grammar_type is private to this section.
grammar_type PL::Parsing::Tokens::Types::new(int supports_return_type) { grammar_type gty; gty.first_type = NULL; gty.second_type = NULL; gty.first_multiplicity = FALSE; gty.second_multiplicity = FALSE; if (supports_return_type) gty.no_resulting_values = 0; else gty.no_resulting_values = -1; return gty; }
§3. The multiplication by 10 here is explained in the discussion of GSB tallying during GL sorting in "Grammar Lines". Do not amend it without changing that discussion.
int PL::Parsing::Tokens::Types::add_type(grammar_type *gty, parse_node *spec, int multiple_flag, int score) { switch((gty->no_resulting_values)++) { case 0: gty->first_type = spec; gty->first_multiplicity = multiple_flag; return 10*score; case 1: gty->second_type = spec; gty->second_multiplicity = multiple_flag; return score; case 2: Problems::Issue::sentence_problem(Task::syntax_tree(), _p_(PM_ThreeValuedLine), "there can be at most two varying parts to a line of grammar", "so 'put [something] in [a container]' is allowed but 'put " "[something] in [something] beside [a door]' is not."); } return 0; } int PL::Parsing::Tokens::Types::has_return_type(grammar_type *gty) { if (gty->no_resulting_values == -1) return FALSE; return TRUE; } int PL::Parsing::Tokens::Types::get_no_resulting_values(grammar_type *gty) { return gty->no_resulting_values; } parse_node *PL::Parsing::Tokens::Types::get_single_type(grammar_type *gty) { switch(gty->no_resulting_values) { case 0: return NULL; case 1: return gty->first_type; default: internal_error("gty improperly typed"); } return NULL; } void PL::Parsing::Tokens::Types::set_single_type(grammar_type *gty, parse_node *spec) { if (spec == NULL) gty->no_resulting_values = 0; else { gty->no_resulting_values = 1; gty->first_type = spec; } } void PL::Parsing::Tokens::Types::compile_to_string(grammar_type *gty) { Specifications::Compiler::emit_as_val(K_value, gty->first_type); } kind *PL::Parsing::Tokens::Types::get_data_type_as_token(grammar_type *gty) { if (gty->no_resulting_values > 0) { if ((ParseTree::is(gty->first_type, CONSTANT_NT)) || (Specifications::is_description(gty->first_type))) return Specifications::to_kind(gty->first_type); } return NULL; }
§4. The behaviour of this sorting routine is documented in the discussion of GL sorting in "Grammar Lines". Do not amend it without changing that discussion.
int PL::Parsing::Tokens::Types::must_precede(grammar_type *gty1, grammar_type *gty2) { int cs; if ((gty1->no_resulting_values) < (gty2->no_resulting_values)) return TRUE; if ((gty1->no_resulting_values) > (gty2->no_resulting_values)) return FALSE; if (gty1->no_resulting_values == 0) return NOT_APPLICABLE; cs = Specifications::compare_specificity(gty1->first_type, gty2->first_type, NULL); if (cs == 1) return TRUE; if (cs == -1) return FALSE; if ((gty1->first_multiplicity) && (gty2->first_multiplicity == FALSE)) return FALSE; if ((gty1->first_multiplicity == FALSE) && (gty2->first_multiplicity)) return TRUE; if (gty1->no_resulting_values == 1) return NOT_APPLICABLE; cs = Specifications::compare_specificity(gty1->second_type, gty2->second_type, NULL); if (cs == 1) return TRUE; if (cs == -1) return FALSE; if ((gty1->second_multiplicity) && (gty2->second_multiplicity == FALSE)) return FALSE; if ((gty1->second_multiplicity == FALSE) && (gty2->second_multiplicity)) return TRUE; return NOT_APPLICABLE; }