Rename: nlg → elp (Engram Language Protocol)
This commit is contained in:
+198
-138
@@ -1,20 +1,25 @@
|
||||
// grammar.el - Context-free grammar for English.
|
||||
// grammar.el - Grammar engine: syntactic structure, word order, phrase assembly.
|
||||
//
|
||||
// Grammar rules are stored as lists: [id, lhs, rhs_part0, rhs_part1, ...]
|
||||
// Tree nodes are stored as lists: [label, word, child0, child1, ...]
|
||||
// where child slots are also lists (nested tree nodes).
|
||||
// Language-specific word order and question strategy are driven by the language
|
||||
// profile, not hardcoded. The slot map format (GramSpec) is universal; a "lang"
|
||||
// key carries the ISO 639-1 code so every downstream function can resolve the
|
||||
// active profile.
|
||||
//
|
||||
// This module provides:
|
||||
// - A catalog of English grammar rules (S, NP, VP, PP)
|
||||
// - A generator that fills a rule skeleton with semantic slots
|
||||
// GramSpec slot keys:
|
||||
// intent - "assert" | "question" | "command"
|
||||
// agent - subject referent string
|
||||
// predicate - verb base form
|
||||
// patient - object noun phrase (optional)
|
||||
// location - prepositional phrase (optional)
|
||||
// tense - "present" | "past" | "future"
|
||||
// aspect - "simple" | "progressive" | "perfect"
|
||||
// lang - ISO 639-1 code (default "en")
|
||||
// verb_surf - conjugated verb surface form (computed)
|
||||
// aux_surf - auxiliary surface form (computed)
|
||||
//
|
||||
// Slots are passed as a flat string map encoded as a list:
|
||||
// ["key1", "val1", "key2", "val2", ...]
|
||||
//
|
||||
// Depends on: nothing (standalone)
|
||||
// Depends on: language-profile
|
||||
|
||||
// ── Slot map helpers ──────────────────────────────────────────────────────────
|
||||
// Slot maps are [String] lists: [key, val, key, val, ...]
|
||||
|
||||
fn slots_get(slots: [String], key: String) -> String {
|
||||
let n: Int = native_list_len(slots)
|
||||
@@ -90,22 +95,6 @@ fn make_slots5(k0: String, v0: String, k1: String, v1: String, k2: String, v2: S
|
||||
}
|
||||
|
||||
// ── Grammar rule catalog ──────────────────────────────────────────────────────
|
||||
//
|
||||
// Rules:
|
||||
// S-DECL S -> NP VP declarative sentence
|
||||
// S-QUEST S -> Aux NP VP yes/no question
|
||||
// S-IMP S -> VP imperative
|
||||
// NP-DET-N NP -> Det N the cat
|
||||
// NP-DET-ADJ-N NP -> Det Adj N the big cat
|
||||
// NP-PRON NP -> Pron she/he/they
|
||||
// NP-N NP -> N proper noun / bare noun
|
||||
// VP-V VP -> V intransitive
|
||||
// VP-V-NP VP -> V NP transitive
|
||||
// VP-V-PP VP -> V PP locative
|
||||
// VP-V-NP-PP VP -> V NP PP ditransitive+pp
|
||||
// VP-AUX-V VP -> Aux V modal
|
||||
// VP-AUX-V-NP VP -> Aux V NP modal transitive
|
||||
// PP-P-NP PP -> P NP prepositional phrase
|
||||
|
||||
fn rule_id(rule: [String]) -> String {
|
||||
return native_list_get(rule, 0)
|
||||
@@ -153,27 +142,20 @@ fn make_rule4(id: String, lhs: String, r0: String, r1: String, r2: String, r3: S
|
||||
fn build_rules() -> [[String]] {
|
||||
let rules: [[String]] = native_list_empty()
|
||||
|
||||
// Sentence rules
|
||||
let rules = native_list_append(rules, make_rule2("S-DECL", "S", "NP", "VP"))
|
||||
let rules = native_list_append(rules, make_rule3("S-QUEST", "S", "Aux", "NP", "VP"))
|
||||
let rules = native_list_append(rules, make_rule("S-IMP", "S", "VP"))
|
||||
|
||||
// NP rules
|
||||
let rules = native_list_append(rules, make_rule2("NP-DET-N", "NP", "Det", "N"))
|
||||
let rules = native_list_append(rules, make_rule3("NP-DET-ADJ-N","NP","Det", "Adj", "N"))
|
||||
let rules = native_list_append(rules, make_rule("NP-PRON", "NP", "Pron"))
|
||||
let rules = native_list_append(rules, make_rule("NP-N", "NP", "N"))
|
||||
|
||||
// VP rules
|
||||
let rules = native_list_append(rules, make_rule("VP-V", "VP", "V"))
|
||||
let rules = native_list_append(rules, make_rule2("VP-V-NP", "VP", "V", "NP"))
|
||||
let rules = native_list_append(rules, make_rule2("VP-V-PP", "VP", "V", "PP"))
|
||||
let rules = native_list_append(rules, make_rule3("VP-V-NP-PP", "VP", "V", "NP", "PP"))
|
||||
let rules = native_list_append(rules, make_rule2("VP-AUX-V", "VP", "Aux", "V"))
|
||||
let rules = native_list_append(rules, make_rule3("VP-AUX-V-NP","VP", "Aux", "V", "NP"))
|
||||
|
||||
// PP rules
|
||||
let rules = native_list_append(rules, make_rule2("PP-P-NP", "PP", "P", "NP"))
|
||||
let rules = native_list_append(rules, make_rule2("S-DECL", "S", "NP", "VP"))
|
||||
let rules = native_list_append(rules, make_rule3("S-QUEST", "S", "Aux", "NP", "VP"))
|
||||
let rules = native_list_append(rules, make_rule("S-IMP", "S", "VP"))
|
||||
let rules = native_list_append(rules, make_rule2("NP-DET-N", "NP", "Det", "N"))
|
||||
let rules = native_list_append(rules, make_rule3("NP-DET-ADJ-N","NP", "Det", "Adj", "N"))
|
||||
let rules = native_list_append(rules, make_rule("NP-PRON", "NP", "Pron"))
|
||||
let rules = native_list_append(rules, make_rule("NP-N", "NP", "N"))
|
||||
let rules = native_list_append(rules, make_rule("VP-V", "VP", "V"))
|
||||
let rules = native_list_append(rules, make_rule2("VP-V-NP", "VP", "V", "NP"))
|
||||
let rules = native_list_append(rules, make_rule2("VP-V-PP", "VP", "V", "PP"))
|
||||
let rules = native_list_append(rules, make_rule3("VP-V-NP-PP", "VP", "V", "NP", "PP"))
|
||||
let rules = native_list_append(rules, make_rule2("VP-AUX-V", "VP", "Aux", "V"))
|
||||
let rules = native_list_append(rules, make_rule3("VP-AUX-V-NP", "VP", "Aux", "V", "NP"))
|
||||
let rules = native_list_append(rules, make_rule2("PP-P-NP", "PP", "P", "NP"))
|
||||
|
||||
return rules
|
||||
}
|
||||
@@ -199,13 +181,6 @@ fn find_rule(rule_id_str: String) -> [String] {
|
||||
}
|
||||
|
||||
// ── Tree node construction ────────────────────────────────────────────────────
|
||||
// A tree node is a [String]: [label, word, num_children, c0_size, c0..., c1_size, c1..., ...]
|
||||
// Since El lists only hold one element type, we serialize tree nodes as
|
||||
// flattened string lists using a simple s-expression encoding.
|
||||
//
|
||||
// Format: "(LABEL WORD CHILD1 CHILD2 ...)"
|
||||
// Leaf node: "(LABEL WORD)"
|
||||
// Non-terminal: "(LABEL _ CHILD1 CHILD2)"
|
||||
|
||||
fn make_leaf(label: String, word: String) -> String {
|
||||
return "(" + label + " " + word + ")"
|
||||
@@ -227,18 +202,15 @@ fn make_node4(label: String, child0: String, child1: String, child2: String, chi
|
||||
return "(" + label + " _ " + child0 + " " + child1 + " " + child2 + " " + child3 + ")"
|
||||
}
|
||||
|
||||
// ── Tree rendering: extract the terminal words in order ───────────────────────
|
||||
//
|
||||
// Walk the s-expression and collect all leaf words.
|
||||
// ── Tree rendering ────────────────────────────────────────────────────────────
|
||||
|
||||
fn nlg_is_ws(c: String) -> Bool {
|
||||
if str_eq(c, " ") { return true }
|
||||
if str_eq(c, " ") { return true }
|
||||
if str_eq(c, "\t") { return true }
|
||||
if str_eq(c, "\n") { return true }
|
||||
return false
|
||||
}
|
||||
|
||||
// Scan forward past whitespace; return new position.
|
||||
fn skip_ws(s: String, pos: Int) -> Int {
|
||||
let n: Int = str_len(s)
|
||||
let i: Int = pos
|
||||
@@ -258,7 +230,6 @@ fn skip_ws(s: String, pos: Int) -> Int {
|
||||
return i
|
||||
}
|
||||
|
||||
// Scan a token (non-whitespace, non-paren run); return [token_string, end_pos].
|
||||
fn scan_token(s: String, start: Int) -> [String] {
|
||||
let n: Int = str_len(s)
|
||||
let i: Int = start
|
||||
@@ -290,21 +261,11 @@ fn scan_token(s: String, start: Int) -> [String] {
|
||||
return result
|
||||
}
|
||||
|
||||
// Collect terminal words from a tree s-expression.
|
||||
// Words are the second token in each "(LABEL WORD)" pair where WORD != "_".
|
||||
// render a tree to a flat string by collecting leaf words.
|
||||
// We walk the s-expression character by character.
|
||||
|
||||
fn render_tree(tree: String) -> String {
|
||||
let words: [String] = native_list_empty()
|
||||
let n: Int = str_len(tree)
|
||||
let i: Int = 0
|
||||
// Track depth: after opening paren, the first non-_ token at depth 1
|
||||
// that is followed by a closing paren (or more tokens) is a leaf word.
|
||||
// Strategy: extract all tokens, skip labels (first after '(') and '_'.
|
||||
// All other tokens that aren't '(' or ')' are leaf words.
|
||||
let prev_was_open: Bool = false
|
||||
let is_first_after_open: Bool = false
|
||||
while i < n {
|
||||
let c: String = str_slice(tree, i, i + 1)
|
||||
if str_eq(c, "(") {
|
||||
@@ -318,17 +279,13 @@ fn render_tree(tree: String) -> String {
|
||||
if nlg_is_ws(c) {
|
||||
let i = i + 1
|
||||
} else {
|
||||
// Start of a token
|
||||
let tok_info: [String] = scan_token(tree, i)
|
||||
let tok: String = native_list_get(tok_info, 0)
|
||||
let new_i: Int = str_to_int(native_list_get(tok_info, 1))
|
||||
let i = new_i
|
||||
// If this is the first token after '(' it is a label - skip
|
||||
if prev_was_open {
|
||||
let prev_was_open = false
|
||||
// skip label
|
||||
} else {
|
||||
// It's a word or '_' placeholder
|
||||
if !str_eq(tok, "_") {
|
||||
let words = native_list_append(words, tok)
|
||||
}
|
||||
@@ -340,61 +297,129 @@ fn render_tree(tree: String) -> String {
|
||||
return str_join(words, " ")
|
||||
}
|
||||
|
||||
// ── Tree generator ────────────────────────────────────────────────────────────
|
||||
//
|
||||
// generate_tree(rule_id, slots) -> tree s-expression string
|
||||
// slots: a [String] list of [key, val, key, val, ...] pairs
|
||||
//
|
||||
// Known slot keys:
|
||||
// "agent" - NP subject (pronoun or noun phrase string)
|
||||
// "predicate" - verb base form
|
||||
// "patient" - NP object (noun phrase string, optional)
|
||||
// "location" - PP location (e.g. "in the park")
|
||||
// "tense" - "present" | "past" | "future"
|
||||
// "aspect" - "simple" | "progressive" | "perfect"
|
||||
// "det" - determiner for subject NP
|
||||
// "aux" - auxiliary for questions
|
||||
// "verb_surf" - pre-conjugated verb surface form
|
||||
// "aux_surf" - pre-conjugated auxiliary surface form
|
||||
// ── Word-order engine ─────────────────────────────────────────────────────────
|
||||
|
||||
fn generate_tree(rule_id_str: String, slots: [String]) -> String {
|
||||
let rule: [String] = find_rule(rule_id_str)
|
||||
let n: Int = native_list_len(rule)
|
||||
if n == 0 {
|
||||
return make_leaf("ERR", "unknown-rule")
|
||||
}
|
||||
|
||||
let lhs: String = native_list_get(rule, 1)
|
||||
let rhs_n: Int = n - 2
|
||||
|
||||
// ── S rules ───────────────────────────────────────────────────────────────
|
||||
if str_eq(rule_id_str, "S-DECL") {
|
||||
let agent: String = slots_get(slots, "agent")
|
||||
let np_tree: String = build_np(agent, slots)
|
||||
let vp_tree: String = build_vp_from_slots(slots)
|
||||
return make_node2("S", np_tree, vp_tree)
|
||||
}
|
||||
|
||||
if str_eq(rule_id_str, "S-QUEST") {
|
||||
let agent: String = slots_get(slots, "agent")
|
||||
let np_tree: String = build_np(agent, slots)
|
||||
let vp_tree: String = build_vp_body(slots)
|
||||
let aux_surf: String = slots_get(slots, "aux_surf")
|
||||
return make_node3("S", make_leaf("Aux", aux_surf), np_tree, vp_tree)
|
||||
}
|
||||
|
||||
if str_eq(rule_id_str, "S-IMP") {
|
||||
let vp_tree: String = build_vp_from_slots(slots)
|
||||
return make_node1("S", vp_tree)
|
||||
}
|
||||
|
||||
return make_leaf(lhs, "?")
|
||||
// gram_word_order: returns the word order string from a profile.
|
||||
fn gram_word_order(profile: [String]) -> String {
|
||||
return lang_word_order(profile)
|
||||
}
|
||||
|
||||
// Build an NP tree from a referent string.
|
||||
// If the referent is a pronoun (I, you, he, she, it, we, they, me, him, her, us, them),
|
||||
// use NP-PRON. If it looks like "the X" or "a X", parse accordingly.
|
||||
// Otherwise treat as a proper noun.
|
||||
// gram_order_constituents: order Subject, Verb, Object tokens according to the
|
||||
// language profile's word_order.
|
||||
//
|
||||
// subj, verb, obj: surface strings (may be empty).
|
||||
// Returns a space-joined string in the correct order.
|
||||
//
|
||||
// Supported orders: SVO, SOV, VSO, VOS, OVS, OSV, free (defaults to SVO).
|
||||
|
||||
fn gram_order_constituents(subj: String, verb: String, obj: String, profile: [String]) -> String {
|
||||
let order: String = gram_word_order(profile)
|
||||
let parts: [String] = native_list_empty()
|
||||
|
||||
if str_eq(order, "SVO") {
|
||||
if !str_eq(subj, "") { let parts = native_list_append(parts, subj) }
|
||||
if !str_eq(verb, "") { let parts = native_list_append(parts, verb) }
|
||||
if !str_eq(obj, "") { let parts = native_list_append(parts, obj) }
|
||||
return str_join(parts, " ")
|
||||
}
|
||||
|
||||
if str_eq(order, "SOV") {
|
||||
if !str_eq(subj, "") { let parts = native_list_append(parts, subj) }
|
||||
if !str_eq(obj, "") { let parts = native_list_append(parts, obj) }
|
||||
if !str_eq(verb, "") { let parts = native_list_append(parts, verb) }
|
||||
return str_join(parts, " ")
|
||||
}
|
||||
|
||||
if str_eq(order, "VSO") {
|
||||
if !str_eq(verb, "") { let parts = native_list_append(parts, verb) }
|
||||
if !str_eq(subj, "") { let parts = native_list_append(parts, subj) }
|
||||
if !str_eq(obj, "") { let parts = native_list_append(parts, obj) }
|
||||
return str_join(parts, " ")
|
||||
}
|
||||
|
||||
if str_eq(order, "VOS") {
|
||||
if !str_eq(verb, "") { let parts = native_list_append(parts, verb) }
|
||||
if !str_eq(obj, "") { let parts = native_list_append(parts, obj) }
|
||||
if !str_eq(subj, "") { let parts = native_list_append(parts, subj) }
|
||||
return str_join(parts, " ")
|
||||
}
|
||||
|
||||
if str_eq(order, "OVS") {
|
||||
if !str_eq(obj, "") { let parts = native_list_append(parts, obj) }
|
||||
if !str_eq(verb, "") { let parts = native_list_append(parts, verb) }
|
||||
if !str_eq(subj, "") { let parts = native_list_append(parts, subj) }
|
||||
return str_join(parts, " ")
|
||||
}
|
||||
|
||||
if str_eq(order, "OSV") {
|
||||
if !str_eq(obj, "") { let parts = native_list_append(parts, obj) }
|
||||
if !str_eq(subj, "") { let parts = native_list_append(parts, subj) }
|
||||
if !str_eq(verb, "") { let parts = native_list_append(parts, verb) }
|
||||
return str_join(parts, " ")
|
||||
}
|
||||
|
||||
// "free" and unknown: use SVO as the neutral citation order.
|
||||
if !str_eq(subj, "") { let parts = native_list_append(parts, subj) }
|
||||
if !str_eq(verb, "") { let parts = native_list_append(parts, verb) }
|
||||
if !str_eq(obj, "") { let parts = native_list_append(parts, obj) }
|
||||
return str_join(parts, " ")
|
||||
}
|
||||
|
||||
// gram_build_vp: construct a verb phrase surface string.
|
||||
//
|
||||
// verb: main verb surface form.
|
||||
// aux: auxiliary surface form (empty if none).
|
||||
// profile: language profile.
|
||||
//
|
||||
// In SVO/VSO/VOS languages the auxiliary precedes the main verb.
|
||||
// In SOV languages the verb cluster appears at the end; we keep aux before V
|
||||
// as a reasonable default for the auxiliary-final constructions in those languages.
|
||||
|
||||
fn gram_build_vp(verb: String, aux: String, profile: [String]) -> String {
|
||||
if str_eq(aux, "") {
|
||||
return verb
|
||||
}
|
||||
return aux + " " + verb
|
||||
}
|
||||
|
||||
// gram_question_strategy: returns the question formation strategy for a language.
|
||||
//
|
||||
// "do-support" - English: "Do you see?" — do-auxiliary inserted, verb stays base
|
||||
// "particle" - Japanese: sentence-final か appended
|
||||
// "intonation" - Mandarin, Spanish: rising intonation only, word order unchanged
|
||||
// "inversion" - French, German: subject-verb inversion
|
||||
|
||||
fn gram_question_strategy(profile: [String]) -> String {
|
||||
let code: String = lang_get(profile, "code")
|
||||
if str_eq(code, "en") { return "do-support" }
|
||||
if str_eq(code, "ja") { return "particle" }
|
||||
if str_eq(code, "zh") { return "intonation" }
|
||||
if str_eq(code, "es") { return "intonation" }
|
||||
if str_eq(code, "fr") { return "inversion" }
|
||||
if str_eq(code, "de") { return "inversion" }
|
||||
if str_eq(code, "ar") { return "intonation" }
|
||||
if str_eq(code, "hi") { return "particle" }
|
||||
if str_eq(code, "ru") { return "intonation" }
|
||||
if str_eq(code, "fi") { return "particle" }
|
||||
if str_eq(code, "sw") { return "intonation" }
|
||||
if str_eq(code, "la") { return "intonation" } // Latin: word order marks Q (VSO or -ne suffix)
|
||||
if str_eq(code, "he") { return "intonation" } // Modern Hebrew: rising intonation
|
||||
if str_eq(code, "grc") { return "intonation" } // Ancient Greek: ἆρα particle or intonation
|
||||
if str_eq(code, "ang") { return "intonation" } // Old English: hwæþer particle or intonation
|
||||
if str_eq(code, "sa") { return "intonation" } // Sanskrit: kim particle or intonation
|
||||
if str_eq(code, "got") { return "intonation" } // Gothic: ibai particle or intonation
|
||||
if str_eq(code, "non") { return "intonation" } // Old Norse: hvárr particle or intonation
|
||||
if str_eq(code, "enm") { return "do-support" } // Middle English: do-support emerging
|
||||
if str_eq(code, "pi") { return "intonation" } // Pali: kim particle or intonation
|
||||
// Unknown: default to intonation (safest — never wrong, just flat)
|
||||
return "intonation"
|
||||
}
|
||||
|
||||
// ── NP and PP assembly ────────────────────────────────────────────────────────
|
||||
//
|
||||
// These functions are profile-aware but the logic is the same across languages
|
||||
// because we work with pre-assembled strings (Engram vocabulary supplies
|
||||
// language-specific forms before these functions see them).
|
||||
|
||||
fn is_pronoun(word: String) -> Bool {
|
||||
if str_eq(word, "I") { return true }
|
||||
@@ -412,43 +437,42 @@ fn is_pronoun(word: String) -> Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// build_np: assemble a noun phrase tree from a referent string.
|
||||
// profile parameter reserved for future case-marking / article agreement.
|
||||
fn build_np(referent: String, slots: [String]) -> String {
|
||||
if is_pronoun(referent) {
|
||||
return make_node1("NP", make_leaf("Pron", referent))
|
||||
}
|
||||
// Try to parse "DET NOUN" or "DET ADJ NOUN" from the referent string
|
||||
let parts: [String] = str_split(referent, " ")
|
||||
let np: Int = native_list_len(parts)
|
||||
if np == 1 {
|
||||
// Single word - proper noun or bare noun
|
||||
return make_node1("NP", make_leaf("N", referent))
|
||||
}
|
||||
if np == 2 {
|
||||
// DET NOUN
|
||||
let det: String = native_list_get(parts, 0)
|
||||
let det: String = native_list_get(parts, 0)
|
||||
let noun: String = native_list_get(parts, 1)
|
||||
return make_node2("NP", make_leaf("Det", det), make_leaf("N", noun))
|
||||
}
|
||||
if np == 3 {
|
||||
// DET ADJ NOUN
|
||||
let det: String = native_list_get(parts, 0)
|
||||
let adj: String = native_list_get(parts, 1)
|
||||
let det: String = native_list_get(parts, 0)
|
||||
let adj: String = native_list_get(parts, 1)
|
||||
let noun: String = native_list_get(parts, 2)
|
||||
return make_node3("NP", make_leaf("Det", det), make_leaf("Adj", adj), make_leaf("N", noun))
|
||||
}
|
||||
// Fallback: treat the whole thing as a name
|
||||
return make_node1("NP", make_leaf("N", referent))
|
||||
}
|
||||
|
||||
// build_pp: assemble a prepositional phrase tree from a "PREP NP" string.
|
||||
// For postpositional languages (ja, hi, ko) the slot value is expected to be
|
||||
// already pre-assembled with the postposition in the correct position by the
|
||||
// caller (vocabulary lookup from Engram supplies the right surface form).
|
||||
fn build_pp(loc: String) -> String {
|
||||
// loc is expected as "PREP NP" e.g. "in the park"
|
||||
let parts: [String] = str_split(loc, " ")
|
||||
let n: Int = native_list_len(parts)
|
||||
if n < 2 {
|
||||
return make_leaf("PP", loc)
|
||||
}
|
||||
let prep: String = native_list_get(parts, 0)
|
||||
// Rest is the NP
|
||||
let np_parts: [String] = native_list_empty()
|
||||
let i: Int = 1
|
||||
while i < n {
|
||||
@@ -460,6 +484,8 @@ fn build_pp(loc: String) -> String {
|
||||
return make_node2("PP", make_leaf("P", prep), np_tree)
|
||||
}
|
||||
|
||||
// ── VP tree construction ──────────────────────────────────────────────────────
|
||||
|
||||
fn build_vp_body(slots: [String]) -> String {
|
||||
let verb_surf: String = slots_get(slots, "verb_surf")
|
||||
let patient: String = slots_get(slots, "patient")
|
||||
@@ -493,3 +519,37 @@ fn build_vp_from_slots(slots: [String]) -> String {
|
||||
}
|
||||
return build_vp_body(slots)
|
||||
}
|
||||
|
||||
// ── Tree generator ────────────────────────────────────────────────────────────
|
||||
|
||||
fn generate_tree(rule_id_str: String, slots: [String]) -> String {
|
||||
let rule: [String] = find_rule(rule_id_str)
|
||||
let n: Int = native_list_len(rule)
|
||||
if n == 0 {
|
||||
return make_leaf("ERR", "unknown-rule")
|
||||
}
|
||||
|
||||
let lhs: String = native_list_get(rule, 1)
|
||||
|
||||
if str_eq(rule_id_str, "S-DECL") {
|
||||
let agent: String = slots_get(slots, "agent")
|
||||
let np_tree: String = build_np(agent, slots)
|
||||
let vp_tree: String = build_vp_from_slots(slots)
|
||||
return make_node2("S", np_tree, vp_tree)
|
||||
}
|
||||
|
||||
if str_eq(rule_id_str, "S-QUEST") {
|
||||
let agent: String = slots_get(slots, "agent")
|
||||
let np_tree: String = build_np(agent, slots)
|
||||
let vp_tree: String = build_vp_body(slots)
|
||||
let aux_surf: String = slots_get(slots, "aux_surf")
|
||||
return make_node3("S", make_leaf("Aux", aux_surf), np_tree, vp_tree)
|
||||
}
|
||||
|
||||
if str_eq(rule_id_str, "S-IMP") {
|
||||
let vp_tree: String = build_vp_from_slots(slots)
|
||||
return make_node1("S", vp_tree)
|
||||
}
|
||||
|
||||
return make_leaf(lhs, "?")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user