From 7ead289afee3e262a3b08ddb6623e4012b1efc5f Mon Sep 17 00:00:00 2001 From: David de Hilster Date: Sun, 13 Sep 2026 11:43:30 -0400 Subject: [PATCH] Let one analyzer run another's passes on a node (4.1.0) callanalyzer(pnode, concept, "name") runs the named analyzer's passes on the subtree under pnode, in the caller's parse tree and KB. callconcept() gives the called analyzer the concept it was handed. The called analyzer is built on first use and stays in the VTRun registry, together with its .dict and .kbb files read into the shared KB and its *full files registered for lazy lookup. On each call its tokenizer passes are skipped, a dicttok pass looks up the subtree's words (lazy files included) via the new DICTTok::applyToSubtree, G() variables start empty, and no per-pass .tree dumps are written. Self-calls and cycles are refused. CG::openFullDict/openFullKBB now clear the lazy-lookup miss cache, so a word missed before a lazy file was registered is looked up in it. NlpDebug::suspend/resume keep the debugger's pause points off inside a called analyzer. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/build-linux.yml | 44 + .github/workflows/build-windows.yml | 43 + .../call-analyzer-callee/kb/user/colors.dict | 3 + .../call-analyzer-callee/kb/user/hier.kb | 756 ++++++++++++++++++ .../kb/user/shades-full.dict | 2 + .../call-analyzer-callee/spec/analyzer.seq | 3 + .../call-analyzer-callee/spec/colors.nlp | 32 + .../tests/call-analyzer-callee/spec/mark.nlp | 11 + .../tests/call-analyzer/input/text.txt | 1 + .../tests/call-analyzer/kb/user/hier.kb | 756 ++++++++++++++++++ .../tests/call-analyzer/spec/analyzer.seq | 4 + .../tests/call-analyzer/spec/call.nlp | 21 + .../tests/call-analyzer/spec/report.nlp | 72 ++ .../tests/call-analyzer/spec/sentence.nlp | 7 + cs/libconsh/cg.cpp | 7 + include/Api/lite/Arun.h | 7 + include/Api/lite/nlpdebug.h | 8 + lite/callana.cpp | 558 +++++++++++++ lite/dicttok.cpp | 54 ++ lite/dicttok.h | 2 + lite/fn.cpp | 4 + lite/fn.h | 2 + lite/func_defs.h | 4 + lite/funcs.h | 3 + lite/nlpdebug.cpp | 18 + nlp/main.cpp | 2 +- 26 files changed, 2423 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/tests/call-analyzer-callee/kb/user/colors.dict create mode 100644 .github/workflows/tests/call-analyzer-callee/kb/user/hier.kb create mode 100644 .github/workflows/tests/call-analyzer-callee/kb/user/shades-full.dict create mode 100644 .github/workflows/tests/call-analyzer-callee/spec/analyzer.seq create mode 100644 .github/workflows/tests/call-analyzer-callee/spec/colors.nlp create mode 100644 .github/workflows/tests/call-analyzer-callee/spec/mark.nlp create mode 100644 .github/workflows/tests/call-analyzer/input/text.txt create mode 100644 .github/workflows/tests/call-analyzer/kb/user/hier.kb create mode 100644 .github/workflows/tests/call-analyzer/spec/analyzer.seq create mode 100644 .github/workflows/tests/call-analyzer/spec/call.nlp create mode 100644 .github/workflows/tests/call-analyzer/spec/report.nlp create mode 100644 .github/workflows/tests/call-analyzer/spec/sentence.nlp create mode 100644 lite/callana.cpp diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index 61d8af4d..34f4c2ca 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -593,6 +593,50 @@ jobs: fi echo "[json] jsonwrite serializes and jsonparse round-trips" + - name: callanalyzer runs another analyzer, loaded once + if: matrix.id != 'docker-ubuntu-20.04' + shell: bash + run: | + set -eo pipefail + # callanalyzer (4.1.0) runs another analyzer's passes on one node of + # this analyzer's parse tree, with this analyzer's KB. The callee + # sits beside the caller, in tests/call-analyzer-callee, and is found + # by name. The tree lines prove it changed only the nodes it was + # given; crimson proves its lazy *full.dict was run on the passed + # text; the load count proves it was built once for two calls. + FIX=.github/workflows/tests/call-analyzer + rm -rf "$FIX/logs" "$FIX/input/text.txt_log" .github/workflows/tests/call-analyzer-callee/logs + mkdir -p "$FIX/logs" + ./bin/nlp -ANA "$FIX" -WORK ./ "$FIX/input/text.txt" 2>&1 | tee "$FIX/logs/run.log" + if [ -f "$FIX/logs/make_ana.log" ]; then cat "$FIX/logs/make_ana.log"; fi + OUT="$FIX/input/text.txt_log/out.txt" + if [ ! -f "$OUT" ]; then + echo "FAIL(callanalyzer): no out.txt -- the analyzer did not build"; exit 1 + fi + got=$(tr -d '\r' < "$OUT") + want=$(printf '%s\n' \ + 'loaded-before:0' \ + 'call:1' \ + 'call:1' \ + 'loaded-after:1' \ + 'mine:caller' \ + 'tree:_sent _color apples* .' \ + 'tree:_sent _color sky* and* _color grass* .' \ + 'tree:Blue' \ + 'concept:sent root:_sent sawcallerG:0 backcall:0 colors:red;' \ + 'concept:sent root:_sent sawcallerG:0 backcall:0 colors:crimson;green;' \ + 'self:0' \ + 'missing:0') + if [ "$got" != "$want" ]; then + echo "FAIL(callanalyzer): out.txt was:"; echo "$got" + echo "wanted:"; echo "$want"; exit 1 + fi + loads=$(grep -c 'callanalyzer: loaded call-analyzer-callee' "$FIX/logs/run.log" || true) + if [ "$loads" != "1" ]; then + echo "FAIL(callanalyzer): the called analyzer was loaded $loads times for two calls"; exit 1 + fi + echo "[callanalyzer] called analyzer ran on the given nodes, loaded once" + - name: Rule-level debug server (Non-20.04) if: matrix.id != 'docker-ubuntu-20.04' shell: bash diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 2b0177e0..fa26fce5 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -522,6 +522,49 @@ jobs: fi echo "[json] jsonwrite serializes and jsonparse round-trips" + - name: callanalyzer runs another analyzer, loaded once + shell: bash + run: | + set -eo pipefail + # callanalyzer (4.1.0) runs another analyzer's passes on one node of + # this analyzer's parse tree, with this analyzer's KB. The callee + # sits beside the caller, in tests/call-analyzer-callee, and is found + # by name. The tree lines prove it changed only the nodes it was + # given; crimson proves its lazy *full.dict was run on the passed + # text; the load count proves it was built once for two calls. + FIX=.github/workflows/tests/call-analyzer + rm -rf "$FIX/logs" "$FIX/input/text.txt_log" .github/workflows/tests/call-analyzer-callee/logs + mkdir -p "$FIX/logs" + ./bin/Release/nlp.exe -ANA "$FIX" -WORK ./ "$FIX/input/text.txt" 2>&1 | tee "$FIX/logs/run.log" + if [ -f "$FIX/logs/make_ana.log" ]; then cat "$FIX/logs/make_ana.log"; fi + OUT="$FIX/input/text.txt_log/out.txt" + if [ ! -f "$OUT" ]; then + echo "FAIL(callanalyzer): no out.txt -- the analyzer did not build"; exit 1 + fi + got=$(tr -d '\r' < "$OUT") + want=$(printf '%s\n' \ + 'loaded-before:0' \ + 'call:1' \ + 'call:1' \ + 'loaded-after:1' \ + 'mine:caller' \ + 'tree:_sent _color apples* .' \ + 'tree:_sent _color sky* and* _color grass* .' \ + 'tree:Blue' \ + 'concept:sent root:_sent sawcallerG:0 backcall:0 colors:red;' \ + 'concept:sent root:_sent sawcallerG:0 backcall:0 colors:crimson;green;' \ + 'self:0' \ + 'missing:0') + if [ "$got" != "$want" ]; then + echo "FAIL(callanalyzer): out.txt was:"; echo "$got" + echo "wanted:"; echo "$want"; exit 1 + fi + loads=$(grep -c 'callanalyzer: loaded call-analyzer-callee' "$FIX/logs/run.log" || true) + if [ "$loads" != "1" ]; then + echo "FAIL(callanalyzer): the called analyzer was loaded $loads times for two calls"; exit 1 + fi + echo "[callanalyzer] called analyzer ran on the given nodes, loaded once" + - name: Rule-level debug server shell: bash run: | diff --git a/.github/workflows/tests/call-analyzer-callee/kb/user/colors.dict b/.github/workflows/tests/call-analyzer-callee/kb/user/colors.dict new file mode 100644 index 00000000..86f7af49 --- /dev/null +++ b/.github/workflows/tests/call-analyzer-callee/kb/user/colors.dict @@ -0,0 +1,3 @@ +blue color=yes +green color=yes +red color=yes diff --git a/.github/workflows/tests/call-analyzer-callee/kb/user/hier.kb b/.github/workflows/tests/call-analyzer-callee/kb/user/hier.kb new file mode 100644 index 00000000..9d513bf1 --- /dev/null +++ b/.github/workflows/tests/call-analyzer-callee/kb/user/hier.kb @@ -0,0 +1,756 @@ +add empty +add root +add hier "concept" "gram" +add hier "concept" "sys" +add hier "concept" "sys" "attrs" +add hier "concept" "sys" "attrs" "proxy" +add hier "concept" "sys" "attrs" "proxy" "atom" +add hier "concept" "sys" "attrs" "pproxy" +add hier "concept" "sys" "attrs" "pproxy" "phrase" +add hier "concept" "sys" "attrs" "common" +add hier "concept" "sys" "attrs" "common" "var" +add hier "concept" "sys" "attrs" "rule_elt" +add hier "concept" "sys" "vals" +add hier "concept" "sys" "vals" "boolean" +add hier "concept" "sys" "vals" "boolean" "false" +add hier "concept" "sys" "vals" "boolean" "true" +add hier "concept" "sys" "nlp" +add hier "concept" "sys" "nlp" "wht" +add hier "concept" "sys" "nlp" "punct" +add hier "concept" "sys" "nlp" "ctrl" +add hier "concept" "sys" "nlp" "lex" +add hier "concept" "sys" "nlp" "lex" "slot" +add hier "concept" "sys" "nlp" "lex" "slot" "cases" +add hier "concept" "sys" "mean" +add hier "concept" "sys" "mean" "slot" +add hier "concept" "sys" "mean" "slot" "case" +add hier "concept" "sys" "mean" "slot" "case" "cap" +add hier "concept" "sys" "mean" "slot" "case" "allcap" +add hier "concept" "sys" "mean" "slot" "case" "mixed" +add hier "concept" "sys" "mean" "slot" "mixed" +add hier "concept" "sys" "dict" +add hier "concept" "sys" "dict" "a" +add hier "concept" "sys" "dict" "a" "A" +add hier "concept" "sys" "dict" "a" "A" "A" +add hier "concept" "sys" "dict" "a" "A" "Aa" +add hier "concept" "sys" "dict" "a" "A" "Ab" +add hier "concept" "sys" "dict" "a" "A" "Ac" +add hier "concept" "sys" "dict" "a" "A" "Ad" +add hier "concept" "sys" "dict" "a" "A" "Ae" +add hier "concept" "sys" "dict" "a" "A" "Af" +add hier "concept" "sys" "dict" "a" "A" "Ag" +add hier "concept" "sys" "dict" "a" "A" "Ah" +add hier "concept" "sys" "dict" "a" "A" "Ai" +add hier "concept" "sys" "dict" "a" "A" "Aj" +add hier "concept" "sys" "dict" "a" "A" "Ak" +add hier "concept" "sys" "dict" "a" "A" "Al" +add hier "concept" "sys" "dict" "a" "A" "Am" +add hier "concept" "sys" "dict" "a" "A" "An" +add hier "concept" "sys" "dict" "a" "A" "Ap" +add hier "concept" "sys" "dict" "a" "A" "Aq" +add hier "concept" "sys" "dict" "a" "A" "Ar" +add hier "concept" "sys" "dict" "a" "A" "As" +add hier "concept" "sys" "dict" "a" "A" "At" +add hier "concept" "sys" "dict" "a" "A" "Au" +add hier "concept" "sys" "dict" "a" "A" "Av" +add hier "concept" "sys" "dict" "a" "A" "Aw" +add hier "concept" "sys" "dict" "a" "A" "Ax" +add hier "concept" "sys" "dict" "a" "A" "Ay" +add hier "concept" "sys" "dict" "a" "A" "Az" +add hier "concept" "sys" "dict" "a" "B" +add hier "concept" "sys" "dict" "a" "B" "B" +add hier "concept" "sys" "dict" "a" "B" "Ba" +add hier "concept" "sys" "dict" "a" "B" "Be" +add hier "concept" "sys" "dict" "a" "B" "Bi" +add hier "concept" "sys" "dict" "a" "B" "Bl" +add hier "concept" "sys" "dict" "a" "B" "Bo" +add hier "concept" "sys" "dict" "a" "B" "Br" +add hier "concept" "sys" "dict" "a" "B" "Bu" +add hier "concept" "sys" "dict" "a" "B" "By" +add hier "concept" "sys" "dict" "a" "C" +add hier "concept" "sys" "dict" "a" "C" "C" +add hier "concept" "sys" "dict" "a" "C" "Ca" +add hier "concept" "sys" "dict" "a" "C" "Ce" +add hier "concept" "sys" "dict" "a" "C" "Ch" +add hier "concept" "sys" "dict" "a" "C" "Ci" +add hier "concept" "sys" "dict" "a" "C" "Cl" +add hier "concept" "sys" "dict" "a" "C" "Co" +add hier "concept" "sys" "dict" "a" "C" "Cr" +add hier "concept" "sys" "dict" "a" "C" "Cu" +add hier "concept" "sys" "dict" "a" "C" "Cy" +add hier "concept" "sys" "dict" "a" "D" +add hier "concept" "sys" "dict" "a" "D" "D" +add hier "concept" "sys" "dict" "a" "D" "Da" +add hier "concept" "sys" "dict" "a" "D" "De" +add hier "concept" "sys" "dict" "a" "D" "Di" +add hier "concept" "sys" "dict" "a" "D" "Do" +add hier "concept" "sys" "dict" "a" "D" "Dr" +add hier "concept" "sys" "dict" "a" "D" "Du" +add hier "concept" "sys" "dict" "a" "D" "Dy" +add hier "concept" "sys" "dict" "a" "E" +add hier "concept" "sys" "dict" "a" "E" "E" +add hier "concept" "sys" "dict" "a" "E" "Ea" +add hier "concept" "sys" "dict" "a" "E" "Eb" +add hier "concept" "sys" "dict" "a" "E" "Ed" +add hier "concept" "sys" "dict" "a" "E" "Ee" +add hier "concept" "sys" "dict" "a" "E" "Ef" +add hier "concept" "sys" "dict" "a" "E" "Eg" +add hier "concept" "sys" "dict" "a" "E" "Eh" +add hier "concept" "sys" "dict" "a" "E" "Ei" +add hier "concept" "sys" "dict" "a" "E" "Ej" +add hier "concept" "sys" "dict" "a" "E" "El" +add hier "concept" "sys" "dict" "a" "E" "Em" +add hier "concept" "sys" "dict" "a" "E" "En" +add hier "concept" "sys" "dict" "a" "E" "Eo" +add hier "concept" "sys" "dict" "a" "E" "Ep" +add hier "concept" "sys" "dict" "a" "E" "Eq" +add hier "concept" "sys" "dict" "a" "E" "Er" +add hier "concept" "sys" "dict" "a" "E" "Es" +add hier "concept" "sys" "dict" "a" "E" "Et" +add hier "concept" "sys" "dict" "a" "E" "Eu" +add hier "concept" "sys" "dict" "a" "E" "Ev" +add hier "concept" "sys" "dict" "a" "E" "Ew" +add hier "concept" "sys" "dict" "a" "E" "Ex" +add hier "concept" "sys" "dict" "a" "E" "Ey" +add hier "concept" "sys" "dict" "a" "E" "Ez" +add hier "concept" "sys" "dict" "a" "F" +add hier "concept" "sys" "dict" "a" "F" "F" +add hier "concept" "sys" "dict" "a" "F" "Fa" +add hier "concept" "sys" "dict" "a" "F" "Fe" +add hier "concept" "sys" "dict" "a" "F" "Fi" +add hier "concept" "sys" "dict" "a" "F" "Fl" +add hier "concept" "sys" "dict" "a" "F" "Fo" +add hier "concept" "sys" "dict" "a" "F" "Fr" +add hier "concept" "sys" "dict" "a" "F" "Fu" +add hier "concept" "sys" "dict" "a" "F" "Fy" +add hier "concept" "sys" "dict" "a" "G" +add hier "concept" "sys" "dict" "a" "G" "G" +add hier "concept" "sys" "dict" "a" "G" "Ga" +add hier "concept" "sys" "dict" "a" "G" "Ge" +add hier "concept" "sys" "dict" "a" "G" "Gh" +add hier "concept" "sys" "dict" "a" "G" "Gi" +add hier "concept" "sys" "dict" "a" "G" "Gl" +add hier "concept" "sys" "dict" "a" "G" "Gn" +add hier "concept" "sys" "dict" "a" "G" "Go" +add hier "concept" "sys" "dict" "a" "G" "Gr" +add hier "concept" "sys" "dict" "a" "G" "Gu" +add hier "concept" "sys" "dict" "a" "G" "Gy" +add hier "concept" "sys" "dict" "a" "H" +add hier "concept" "sys" "dict" "a" "H" "H" +add hier "concept" "sys" "dict" "a" "H" "Ha" +add hier "concept" "sys" "dict" "a" "H" "He" +add hier "concept" "sys" "dict" "a" "H" "Hi" +add hier "concept" "sys" "dict" "a" "H" "Ho" +add hier "concept" "sys" "dict" "a" "H" "Hu" +add hier "concept" "sys" "dict" "a" "H" "Hy" +add hier "concept" "sys" "dict" "a" "I" +add hier "concept" "sys" "dict" "a" "I" "I" +add hier "concept" "sys" "dict" "a" "I" "Ia" +add hier "concept" "sys" "dict" "a" "I" "Ib" +add hier "concept" "sys" "dict" "a" "I" "Ic" +add hier "concept" "sys" "dict" "a" "I" "Id" +add hier "concept" "sys" "dict" "a" "I" "Ig" +add hier "concept" "sys" "dict" "a" "I" "Il" +add hier "concept" "sys" "dict" "a" "I" "Im" +add hier "concept" "sys" "dict" "a" "I" "In" +add hier "concept" "sys" "dict" "a" "I" "Io" +add hier "concept" "sys" "dict" "a" "I" "Ir" +add hier "concept" "sys" "dict" "a" "I" "Is" +add hier "concept" "sys" "dict" "a" "I" "It" +add hier "concept" "sys" "dict" "a" "J" +add hier "concept" "sys" "dict" "a" "J" "J" +add hier "concept" "sys" "dict" "a" "J" "Ja" +add hier "concept" "sys" "dict" "a" "J" "Je" +add hier "concept" "sys" "dict" "a" "J" "Ji" +add hier "concept" "sys" "dict" "a" "J" "Jo" +add hier "concept" "sys" "dict" "a" "J" "Ju" +add hier "concept" "sys" "dict" "a" "K" +add hier "concept" "sys" "dict" "a" "K" "K" +add hier "concept" "sys" "dict" "a" "K" "Ka" +add hier "concept" "sys" "dict" "a" "K" "Ke" +add hier "concept" "sys" "dict" "a" "K" "Kh" +add hier "concept" "sys" "dict" "a" "K" "Ki" +add hier "concept" "sys" "dict" "a" "K" "Kl" +add hier "concept" "sys" "dict" "a" "K" "Kn" +add hier "concept" "sys" "dict" "a" "K" "Ko" +add hier "concept" "sys" "dict" "a" "K" "Kr" +add hier "concept" "sys" "dict" "a" "K" "Ku" +add hier "concept" "sys" "dict" "a" "L" +add hier "concept" "sys" "dict" "a" "L" "L" +add hier "concept" "sys" "dict" "a" "L" "La" +add hier "concept" "sys" "dict" "a" "L" "Le" +add hier "concept" "sys" "dict" "a" "L" "Li" +add hier "concept" "sys" "dict" "a" "L" "Ll" +add hier "concept" "sys" "dict" "a" "L" "Lo" +add hier "concept" "sys" "dict" "a" "L" "Lu" +add hier "concept" "sys" "dict" "a" "L" "Ly" +add hier "concept" "sys" "dict" "a" "M" +add hier "concept" "sys" "dict" "a" "M" "M" +add hier "concept" "sys" "dict" "a" "M" "Ma" +add hier "concept" "sys" "dict" "a" "M" "Me" +add hier "concept" "sys" "dict" "a" "M" "Mi" +add hier "concept" "sys" "dict" "a" "M" "Mn" +add hier "concept" "sys" "dict" "a" "M" "Mo" +add hier "concept" "sys" "dict" "a" "M" "Mu" +add hier "concept" "sys" "dict" "a" "M" "My" +add hier "concept" "sys" "dict" "a" "N" +add hier "concept" "sys" "dict" "a" "N" "N" +add hier "concept" "sys" "dict" "a" "N" "Na" +add hier "concept" "sys" "dict" "a" "N" "Ne" +add hier "concept" "sys" "dict" "a" "N" "Ni" +add hier "concept" "sys" "dict" "a" "N" "No" +add hier "concept" "sys" "dict" "a" "N" "Nu" +add hier "concept" "sys" "dict" "a" "N" "Ny" +add hier "concept" "sys" "dict" "a" "O" +add hier "concept" "sys" "dict" "a" "O" "O" +add hier "concept" "sys" "dict" "a" "O" "Oa" +add hier "concept" "sys" "dict" "a" "O" "Ob" +add hier "concept" "sys" "dict" "a" "O" "Oc" +add hier "concept" "sys" "dict" "a" "O" "Od" +add hier "concept" "sys" "dict" "a" "O" "Oe" +add hier "concept" "sys" "dict" "a" "O" "Of" +add hier "concept" "sys" "dict" "a" "O" "Og" +add hier "concept" "sys" "dict" "a" "O" "Oh" +add hier "concept" "sys" "dict" "a" "O" "Oi" +add hier "concept" "sys" "dict" "a" "O" "Ok" +add hier "concept" "sys" "dict" "a" "O" "On" +add hier "concept" "sys" "dict" "a" "O" "Oo" +add hier "concept" "sys" "dict" "a" "O" "Op" +add hier "concept" "sys" "dict" "a" "O" "Oq" +add hier "concept" "sys" "dict" "a" "O" "Or" +add hier "concept" "sys" "dict" "a" "O" "Os" +add hier "concept" "sys" "dict" "a" "O" "Ot" +add hier "concept" "sys" "dict" "a" "O" "Ou" +add hier "concept" "sys" "dict" "a" "O" "Ov" +add hier "concept" "sys" "dict" "a" "O" "Ow" +add hier "concept" "sys" "dict" "a" "O" "Ox" +add hier "concept" "sys" "dict" "a" "O" "Oy" +add hier "concept" "sys" "dict" "a" "O" "Oz" +add hier "concept" "sys" "dict" "a" "P" +add hier "concept" "sys" "dict" "a" "P" "P" +add hier "concept" "sys" "dict" "a" "P" "Pa" +add hier "concept" "sys" "dict" "a" "P" "Pe" +add hier "concept" "sys" "dict" "a" "P" "Ph" +add hier "concept" "sys" "dict" "a" "P" "Pi" +add hier "concept" "sys" "dict" "a" "P" "Pl" +add hier "concept" "sys" "dict" "a" "P" "Pn" +add hier "concept" "sys" "dict" "a" "P" "Po" +add hier "concept" "sys" "dict" "a" "P" "Pr" +add hier "concept" "sys" "dict" "a" "P" "Pt" +add hier "concept" "sys" "dict" "a" "P" "Pu" +add hier "concept" "sys" "dict" "a" "P" "Py" +add hier "concept" "sys" "dict" "a" "Q" +add hier "concept" "sys" "dict" "a" "Q" "Q" +add hier "concept" "sys" "dict" "a" "Q" "Qa" +add hier "concept" "sys" "dict" "a" "Q" "Qu" +add hier "concept" "sys" "dict" "a" "R" +add hier "concept" "sys" "dict" "a" "R" "R" +add hier "concept" "sys" "dict" "a" "R" "Ra" +add hier "concept" "sys" "dict" "a" "R" "Re" +add hier "concept" "sys" "dict" "a" "R" "Rh" +add hier "concept" "sys" "dict" "a" "R" "Ri" +add hier "concept" "sys" "dict" "a" "R" "Ro" +add hier "concept" "sys" "dict" "a" "R" "Ru" +add hier "concept" "sys" "dict" "a" "R" "Ry" +add hier "concept" "sys" "dict" "a" "S" +add hier "concept" "sys" "dict" "a" "S" "S" +add hier "concept" "sys" "dict" "a" "S" "Sa" +add hier "concept" "sys" "dict" "a" "S" "Sc" +add hier "concept" "sys" "dict" "a" "S" "Se" +add hier "concept" "sys" "dict" "a" "S" "Sf" +add hier "concept" "sys" "dict" "a" "S" "Sh" +add hier "concept" "sys" "dict" "a" "S" "Si" +add hier "concept" "sys" "dict" "a" "S" "Sk" +add hier "concept" "sys" "dict" "a" "S" "Sl" +add hier "concept" "sys" "dict" "a" "S" "Sm" +add hier "concept" "sys" "dict" "a" "S" "Sn" +add hier "concept" "sys" "dict" "a" "S" "So" +add hier "concept" "sys" "dict" "a" "S" "Sp" +add hier "concept" "sys" "dict" "a" "S" "Sq" +add hier "concept" "sys" "dict" "a" "S" "St" +add hier "concept" "sys" "dict" "a" "S" "Su" +add hier "concept" "sys" "dict" "a" "S" "Sw" +add hier "concept" "sys" "dict" "a" "S" "Sy" +add hier "concept" "sys" "dict" "a" "T" +add hier "concept" "sys" "dict" "a" "T" "T" +add hier "concept" "sys" "dict" "a" "T" "Ta" +add hier "concept" "sys" "dict" "a" "T" "Te" +add hier "concept" "sys" "dict" "a" "T" "Th" +add hier "concept" "sys" "dict" "a" "T" "Ti" +add hier "concept" "sys" "dict" "a" "T" "To" +add hier "concept" "sys" "dict" "a" "T" "Tr" +add hier "concept" "sys" "dict" "a" "T" "Tu" +add hier "concept" "sys" "dict" "a" "T" "Tw" +add hier "concept" "sys" "dict" "a" "T" "Ty" +add hier "concept" "sys" "dict" "a" "U" +add hier "concept" "sys" "dict" "a" "U" "U" +add hier "concept" "sys" "dict" "a" "U" "Ua" +add hier "concept" "sys" "dict" "a" "U" "Un" +add hier "concept" "sys" "dict" "a" "U" "Up" +add hier "concept" "sys" "dict" "a" "U" "Ur" +add hier "concept" "sys" "dict" "a" "V" +add hier "concept" "sys" "dict" "a" "V" "V" +add hier "concept" "sys" "dict" "a" "V" "Va" +add hier "concept" "sys" "dict" "a" "V" "Ve" +add hier "concept" "sys" "dict" "a" "V" "Vi" +add hier "concept" "sys" "dict" "a" "V" "Vo" +add hier "concept" "sys" "dict" "a" "V" "Vu" +add hier "concept" "sys" "dict" "a" "W" +add hier "concept" "sys" "dict" "a" "W" "W" +add hier "concept" "sys" "dict" "a" "W" "Wa" +add hier "concept" "sys" "dict" "a" "W" "We" +add hier "concept" "sys" "dict" "a" "W" "Wh" +add hier "concept" "sys" "dict" "a" "W" "Wi" +add hier "concept" "sys" "dict" "a" "W" "Wo" +add hier "concept" "sys" "dict" "a" "W" "Wr" +add hier "concept" "sys" "dict" "a" "W" "Wu" +add hier "concept" "sys" "dict" "a" "X" +add hier "concept" "sys" "dict" "a" "X" "X" +add hier "concept" "sys" "dict" "a" "X" "Xa" +add hier "concept" "sys" "dict" "a" "X" "Xe" +add hier "concept" "sys" "dict" "a" "X" "Xi" +add hier "concept" "sys" "dict" "a" "X" "Xo" +add hier "concept" "sys" "dict" "a" "X" "Xu" +add hier "concept" "sys" "dict" "a" "X" "Xy" +add hier "concept" "sys" "dict" "a" "Y" +add hier "concept" "sys" "dict" "a" "Y" "Y" +add hier "concept" "sys" "dict" "a" "Y" "Ya" +add hier "concept" "sys" "dict" "a" "Y" "Ye" +add hier "concept" "sys" "dict" "a" "Y" "Yi" +add hier "concept" "sys" "dict" "a" "Y" "Yo" +add hier "concept" "sys" "dict" "a" "Y" "Yu" +add hier "concept" "sys" "dict" "a" "Z" +add hier "concept" "sys" "dict" "a" "Z" "Z" +add hier "concept" "sys" "dict" "a" "Z" "Za" +add hier "concept" "sys" "dict" "a" "Z" "Ze" +add hier "concept" "sys" "dict" "a" "Z" "Zi" +add hier "concept" "sys" "dict" "a" "Z" "Zo" +add hier "concept" "sys" "dict" "a" "Z" "Zu" +add hier "concept" "sys" "dict" "a" "Z" "Zy" +add hier "concept" "sys" "dict" "a" "a" +add hier "concept" "sys" "dict" "a" "a" "a" +add hier "concept" "sys" "dict" "a" "a" "aa" +add hier "concept" "sys" "dict" "a" "a" "ab" +add hier "concept" "sys" "dict" "a" "a" "ac" +add hier "concept" "sys" "dict" "a" "a" "ad" +add hier "concept" "sys" "dict" "a" "a" "ae" +add hier "concept" "sys" "dict" "a" "a" "af" +add hier "concept" "sys" "dict" "a" "a" "ag" +add hier "concept" "sys" "dict" "a" "a" "ah" +add hier "concept" "sys" "dict" "a" "a" "ai" +add hier "concept" "sys" "dict" "a" "a" "aj" +add hier "concept" "sys" "dict" "a" "a" "ak" +add hier "concept" "sys" "dict" "a" "a" "al" +add hier "concept" "sys" "dict" "a" "a" "am" +add hier "concept" "sys" "dict" "a" "a" "an" +add hier "concept" "sys" "dict" "a" "a" "ap" +add hier "concept" "sys" "dict" "a" "a" "aq" +add hier "concept" "sys" "dict" "a" "a" "ar" +add hier "concept" "sys" "dict" "a" "a" "as" +add hier "concept" "sys" "dict" "a" "a" "at" +add hier "concept" "sys" "dict" "a" "a" "au" +add hier "concept" "sys" "dict" "a" "a" "av" +add hier "concept" "sys" "dict" "a" "a" "aw" +add hier "concept" "sys" "dict" "a" "a" "ax" +add hier "concept" "sys" "dict" "a" "a" "ay" +add hier "concept" "sys" "dict" "a" "a" "az" +add hier "concept" "sys" "dict" "a" "b" +add hier "concept" "sys" "dict" "a" "b" "b" +add hier "concept" "sys" "dict" "a" "b" "ba" +add hier "concept" "sys" "dict" "a" "b" "be" +add hier "concept" "sys" "dict" "a" "b" "bi" +add hier "concept" "sys" "dict" "a" "b" "bl" +add hier "concept" "sys" "dict" "a" "b" "bo" +add hier "concept" "sys" "dict" "a" "b" "br" +add hier "concept" "sys" "dict" "a" "b" "bu" +add hier "concept" "sys" "dict" "a" "b" "by" +add hier "concept" "sys" "dict" "a" "c" +add hier "concept" "sys" "dict" "a" "c" "c" +add hier "concept" "sys" "dict" "a" "c" "ca" +add hier "concept" "sys" "dict" "a" "c" "ce" +add hier "concept" "sys" "dict" "a" "c" "ch" +add hier "concept" "sys" "dict" "a" "c" "ci" +add hier "concept" "sys" "dict" "a" "c" "cl" +add hier "concept" "sys" "dict" "a" "c" "co" +add hier "concept" "sys" "dict" "a" "c" "cr" +add hier "concept" "sys" "dict" "a" "c" "cu" +add hier "concept" "sys" "dict" "a" "c" "cy" +add hier "concept" "sys" "dict" "a" "d" +add hier "concept" "sys" "dict" "a" "d" "d" +add hier "concept" "sys" "dict" "a" "d" "da" +add hier "concept" "sys" "dict" "a" "d" "de" +add hier "concept" "sys" "dict" "a" "d" "di" +add hier "concept" "sys" "dict" "a" "d" "do" +add hier "concept" "sys" "dict" "a" "d" "dr" +add hier "concept" "sys" "dict" "a" "d" "du" +add hier "concept" "sys" "dict" "a" "d" "dy" +add hier "concept" "sys" "dict" "a" "e" +add hier "concept" "sys" "dict" "a" "e" "e" +add hier "concept" "sys" "dict" "a" "e" "ea" +add hier "concept" "sys" "dict" "a" "e" "eb" +add hier "concept" "sys" "dict" "a" "e" "ed" +add hier "concept" "sys" "dict" "a" "e" "ee" +add hier "concept" "sys" "dict" "a" "e" "ef" +add hier "concept" "sys" "dict" "a" "e" "eg" +add hier "concept" "sys" "dict" "a" "e" "eh" +add hier "concept" "sys" "dict" "a" "e" "ei" +add hier "concept" "sys" "dict" "a" "e" "ej" +add hier "concept" "sys" "dict" "a" "e" "el" +add hier "concept" "sys" "dict" "a" "e" "em" +add hier "concept" "sys" "dict" "a" "e" "en" +add hier "concept" "sys" "dict" "a" "e" "eo" +add hier "concept" "sys" "dict" "a" "e" "ep" +add hier "concept" "sys" "dict" "a" "e" "eq" +add hier "concept" "sys" "dict" "a" "e" "er" +add hier "concept" "sys" "dict" "a" "e" "es" +add hier "concept" "sys" "dict" "a" "e" "et" +add hier "concept" "sys" "dict" "a" "e" "eu" +add hier "concept" "sys" "dict" "a" "e" "ev" +add hier "concept" "sys" "dict" "a" "e" "ew" +add hier "concept" "sys" "dict" "a" "e" "ex" +add hier "concept" "sys" "dict" "a" "e" "ey" +add hier "concept" "sys" "dict" "a" "e" "ez" +add hier "concept" "sys" "dict" "a" "f" +add hier "concept" "sys" "dict" "a" "f" "f" +add hier "concept" "sys" "dict" "a" "f" "fa" +add hier "concept" "sys" "dict" "a" "f" "fe" +add hier "concept" "sys" "dict" "a" "f" "fi" +add hier "concept" "sys" "dict" "a" "f" "fl" +add hier "concept" "sys" "dict" "a" "f" "fo" +add hier "concept" "sys" "dict" "a" "f" "fr" +add hier "concept" "sys" "dict" "a" "f" "fu" +add hier "concept" "sys" "dict" "a" "f" "fy" +add hier "concept" "sys" "dict" "a" "g" +add hier "concept" "sys" "dict" "a" "g" "g" +add hier "concept" "sys" "dict" "a" "g" "ga" +add hier "concept" "sys" "dict" "a" "g" "ge" +add hier "concept" "sys" "dict" "a" "g" "gh" +add hier "concept" "sys" "dict" "a" "g" "gi" +add hier "concept" "sys" "dict" "a" "g" "gl" +add hier "concept" "sys" "dict" "a" "g" "gn" +add hier "concept" "sys" "dict" "a" "g" "go" +add hier "concept" "sys" "dict" "a" "g" "gr" +add hier "concept" "sys" "dict" "a" "g" "gu" +add hier "concept" "sys" "dict" "a" "g" "gy" +add hier "concept" "sys" "dict" "a" "h" +add hier "concept" "sys" "dict" "a" "h" "h" +add hier "concept" "sys" "dict" "a" "h" "ha" +add hier "concept" "sys" "dict" "a" "h" "he" +add hier "concept" "sys" "dict" "a" "h" "hi" +add hier "concept" "sys" "dict" "a" "h" "ho" +add hier "concept" "sys" "dict" "a" "h" "hu" +add hier "concept" "sys" "dict" "a" "h" "hy" +add hier "concept" "sys" "dict" "a" "i" +add hier "concept" "sys" "dict" "a" "i" "i" +add hier "concept" "sys" "dict" "a" "i" "ia" +add hier "concept" "sys" "dict" "a" "i" "ib" +add hier "concept" "sys" "dict" "a" "i" "ic" +add hier "concept" "sys" "dict" "a" "i" "id" +add hier "concept" "sys" "dict" "a" "i" "ig" +add hier "concept" "sys" "dict" "a" "i" "il" +add hier "concept" "sys" "dict" "a" "i" "im" +add hier "concept" "sys" "dict" "a" "i" "in" +add hier "concept" "sys" "dict" "a" "i" "io" +add hier "concept" "sys" "dict" "a" "i" "ir" +add hier "concept" "sys" "dict" "a" "i" "is" +add hier "concept" "sys" "dict" "a" "i" "it" +add hier "concept" "sys" "dict" "a" "j" +add hier "concept" "sys" "dict" "a" "j" "j" +add hier "concept" "sys" "dict" "a" "j" "ja" +add hier "concept" "sys" "dict" "a" "j" "je" +add hier "concept" "sys" "dict" "a" "j" "ji" +add hier "concept" "sys" "dict" "a" "j" "jo" +add hier "concept" "sys" "dict" "a" "j" "ju" +add hier "concept" "sys" "dict" "a" "k" +add hier "concept" "sys" "dict" "a" "k" "k" +add hier "concept" "sys" "dict" "a" "k" "ka" +add hier "concept" "sys" "dict" "a" "k" "ke" +add hier "concept" "sys" "dict" "a" "k" "kh" +add hier "concept" "sys" "dict" "a" "k" "ki" +add hier "concept" "sys" "dict" "a" "k" "kl" +add hier "concept" "sys" "dict" "a" "k" "kn" +add hier "concept" "sys" "dict" "a" "k" "ko" +add hier "concept" "sys" "dict" "a" "k" "kr" +add hier "concept" "sys" "dict" "a" "k" "ku" +add hier "concept" "sys" "dict" "a" "l" +add hier "concept" "sys" "dict" "a" "l" "l" +add hier "concept" "sys" "dict" "a" "l" "la" +add hier "concept" "sys" "dict" "a" "l" "le" +add hier "concept" "sys" "dict" "a" "l" "li" +add hier "concept" "sys" "dict" "a" "l" "ll" +add hier "concept" "sys" "dict" "a" "l" "lo" +add hier "concept" "sys" "dict" "a" "l" "lu" +add hier "concept" "sys" "dict" "a" "l" "ly" +add hier "concept" "sys" "dict" "a" "m" +add hier "concept" "sys" "dict" "a" "m" "m" +add hier "concept" "sys" "dict" "a" "m" "ma" +add hier "concept" "sys" "dict" "a" "m" "me" +add hier "concept" "sys" "dict" "a" "m" "mi" +add hier "concept" "sys" "dict" "a" "m" "mn" +add hier "concept" "sys" "dict" "a" "m" "mo" +add hier "concept" "sys" "dict" "a" "m" "mu" +add hier "concept" "sys" "dict" "a" "m" "my" +add hier "concept" "sys" "dict" "a" "n" +add hier "concept" "sys" "dict" "a" "n" "n" +add hier "concept" "sys" "dict" "a" "n" "na" +add hier "concept" "sys" "dict" "a" "n" "ne" +add hier "concept" "sys" "dict" "a" "n" "ni" +add hier "concept" "sys" "dict" "a" "n" "no" +add hier "concept" "sys" "dict" "a" "n" "nu" +add hier "concept" "sys" "dict" "a" "n" "ny" +add hier "concept" "sys" "dict" "a" "o" +add hier "concept" "sys" "dict" "a" "o" "o" +add hier "concept" "sys" "dict" "a" "o" "oa" +add hier "concept" "sys" "dict" "a" "o" "ob" +add hier "concept" "sys" "dict" "a" "o" "oc" +add hier "concept" "sys" "dict" "a" "o" "od" +add hier "concept" "sys" "dict" "a" "o" "oe" +add hier "concept" "sys" "dict" "a" "o" "of" +add hier "concept" "sys" "dict" "a" "o" "og" +add hier "concept" "sys" "dict" "a" "o" "oh" +add hier "concept" "sys" "dict" "a" "o" "oi" +add hier "concept" "sys" "dict" "a" "o" "ok" +add hier "concept" "sys" "dict" "a" "o" "on" +add hier "concept" "sys" "dict" "a" "o" "oo" +add hier "concept" "sys" "dict" "a" "o" "op" +add hier "concept" "sys" "dict" "a" "o" "oq" +add hier "concept" "sys" "dict" "a" "o" "or" +add hier "concept" "sys" "dict" "a" "o" "os" +add hier "concept" "sys" "dict" "a" "o" "ot" +add hier "concept" "sys" "dict" "a" "o" "ou" +add hier "concept" "sys" "dict" "a" "o" "ov" +add hier "concept" "sys" "dict" "a" "o" "ow" +add hier "concept" "sys" "dict" "a" "o" "ox" +add hier "concept" "sys" "dict" "a" "o" "oy" +add hier "concept" "sys" "dict" "a" "o" "oz" +add hier "concept" "sys" "dict" "a" "p" +add hier "concept" "sys" "dict" "a" "p" "p" +add hier "concept" "sys" "dict" "a" "p" "pa" +add hier "concept" "sys" "dict" "a" "p" "pe" +add hier "concept" "sys" "dict" "a" "p" "ph" +add hier "concept" "sys" "dict" "a" "p" "pi" +add hier "concept" "sys" "dict" "a" "p" "pl" +add hier "concept" "sys" "dict" "a" "p" "pn" +add hier "concept" "sys" "dict" "a" "p" "po" +add hier "concept" "sys" "dict" "a" "p" "pr" +add hier "concept" "sys" "dict" "a" "p" "pt" +add hier "concept" "sys" "dict" "a" "p" "pu" +add hier "concept" "sys" "dict" "a" "p" "py" +add hier "concept" "sys" "dict" "a" "q" +add hier "concept" "sys" "dict" "a" "q" "q" +add hier "concept" "sys" "dict" "a" "q" "qa" +add hier "concept" "sys" "dict" "a" "q" "qu" +add hier "concept" "sys" "dict" "a" "r" +add hier "concept" "sys" "dict" "a" "r" "r" +add hier "concept" "sys" "dict" "a" "r" "ra" +add hier "concept" "sys" "dict" "a" "r" "re" +add hier "concept" "sys" "dict" "a" "r" "rh" +add hier "concept" "sys" "dict" "a" "r" "ri" +add hier "concept" "sys" "dict" "a" "r" "ro" +add hier "concept" "sys" "dict" "a" "r" "ru" +add hier "concept" "sys" "dict" "a" "r" "ry" +add hier "concept" "sys" "dict" "a" "s" +add hier "concept" "sys" "dict" "a" "s" "s" +add hier "concept" "sys" "dict" "a" "s" "sa" +add hier "concept" "sys" "dict" "a" "s" "sc" +add hier "concept" "sys" "dict" "a" "s" "se" +add hier "concept" "sys" "dict" "a" "s" "sf" +add hier "concept" "sys" "dict" "a" "s" "sh" +add hier "concept" "sys" "dict" "a" "s" "si" +add hier "concept" "sys" "dict" "a" "s" "sk" +add hier "concept" "sys" "dict" "a" "s" "sl" +add hier "concept" "sys" "dict" "a" "s" "sm" +add hier "concept" "sys" "dict" "a" "s" "sn" +add hier "concept" "sys" "dict" "a" "s" "so" +add hier "concept" "sys" "dict" "a" "s" "sp" +add hier "concept" "sys" "dict" "a" "s" "sq" +add hier "concept" "sys" "dict" "a" "s" "st" +add hier "concept" "sys" "dict" "a" "s" "su" +add hier "concept" "sys" "dict" "a" "s" "sw" +add hier "concept" "sys" "dict" "a" "s" "sy" +add hier "concept" "sys" "dict" "a" "t" +add hier "concept" "sys" "dict" "a" "t" "t" +add hier "concept" "sys" "dict" "a" "t" "ta" +add hier "concept" "sys" "dict" "a" "t" "te" +add hier "concept" "sys" "dict" "a" "t" "th" +add hier "concept" "sys" "dict" "a" "t" "ti" +add hier "concept" "sys" "dict" "a" "t" "to" +add hier "concept" "sys" "dict" "a" "t" "tr" +add hier "concept" "sys" "dict" "a" "t" "tu" +add hier "concept" "sys" "dict" "a" "t" "tw" +add hier "concept" "sys" "dict" "a" "t" "ty" +add hier "concept" "sys" "dict" "a" "u" +add hier "concept" "sys" "dict" "a" "u" "u" +add hier "concept" "sys" "dict" "a" "u" "ua" +add hier "concept" "sys" "dict" "a" "u" "un" +add hier "concept" "sys" "dict" "a" "u" "up" +add hier "concept" "sys" "dict" "a" "u" "ur" +add hier "concept" "sys" "dict" "a" "v" +add hier "concept" "sys" "dict" "a" "v" "v" +add hier "concept" "sys" "dict" "a" "v" "va" +add hier "concept" "sys" "dict" "a" "v" "ve" +add hier "concept" "sys" "dict" "a" "v" "vi" +add hier "concept" "sys" "dict" "a" "v" "vo" +add hier "concept" "sys" "dict" "a" "v" "vu" +add hier "concept" "sys" "dict" "a" "w" +add hier "concept" "sys" "dict" "a" "w" "w" +add hier "concept" "sys" "dict" "a" "w" "wa" +add hier "concept" "sys" "dict" "a" "w" "we" +add hier "concept" "sys" "dict" "a" "w" "wh" +add hier "concept" "sys" "dict" "a" "w" "wi" +add hier "concept" "sys" "dict" "a" "w" "wo" +add hier "concept" "sys" "dict" "a" "w" "wr" +add hier "concept" "sys" "dict" "a" "w" "wu" +add hier "concept" "sys" "dict" "a" "x" +add hier "concept" "sys" "dict" "a" "x" "x" +add hier "concept" "sys" "dict" "a" "x" "xa" +add hier "concept" "sys" "dict" "a" "x" "xe" +add hier "concept" "sys" "dict" "a" "x" "xi" +add hier "concept" "sys" "dict" "a" "x" "xo" +add hier "concept" "sys" "dict" "a" "x" "xu" +add hier "concept" "sys" "dict" "a" "x" "xy" +add hier "concept" "sys" "dict" "a" "y" +add hier "concept" "sys" "dict" "a" "y" "y" +add hier "concept" "sys" "dict" "a" "y" "ya" +add hier "concept" "sys" "dict" "a" "y" "ye" +add hier "concept" "sys" "dict" "a" "y" "yi" +add hier "concept" "sys" "dict" "a" "y" "yo" +add hier "concept" "sys" "dict" "a" "y" "yu" +add hier "concept" "sys" "dict" "a" "z" +add hier "concept" "sys" "dict" "a" "z" "z" +add hier "concept" "sys" "dict" "a" "z" "za" +add hier "concept" "sys" "dict" "a" "z" "ze" +add hier "concept" "sys" "dict" "a" "z" "zi" +add hier "concept" "sys" "dict" "a" "z" "zo" +add hier "concept" "sys" "dict" "a" "z" "zu" +add hier "concept" "sys" "dict" "a" "z" "zy" +add hier "concept" "sys" "dict" "0" +add hier "concept" "sys" "dict" "0" "0" +add hier "concept" "sys" "dict" "0" "0" "0" +add hier "concept" "sys" "dict" "0" "0" "00" +add hier "concept" "sys" "dict" "0" "0" "01" +add hier "concept" "sys" "dict" "0" "0" "02" +add hier "concept" "sys" "dict" "0" "0" "03" +add hier "concept" "sys" "dict" "0" "0" "04" +add hier "concept" "sys" "dict" "0" "0" "05" +add hier "concept" "sys" "dict" "0" "0" "06" +add hier "concept" "sys" "dict" "0" "0" "07" +add hier "concept" "sys" "dict" "0" "0" "08" +add hier "concept" "sys" "dict" "0" "0" "09" +add hier "concept" "sys" "dict" "0" "1" +add hier "concept" "sys" "dict" "0" "1" "1" +add hier "concept" "sys" "dict" "0" "1" "10" +add hier "concept" "sys" "dict" "0" "1" "11" +add hier "concept" "sys" "dict" "0" "1" "12" +add hier "concept" "sys" "dict" "0" "1" "13" +add hier "concept" "sys" "dict" "0" "1" "14" +add hier "concept" "sys" "dict" "0" "1" "15" +add hier "concept" "sys" "dict" "0" "1" "16" +add hier "concept" "sys" "dict" "0" "1" "17" +add hier "concept" "sys" "dict" "0" "1" "18" +add hier "concept" "sys" "dict" "0" "1" "19" +add hier "concept" "sys" "dict" "0" "2" +add hier "concept" "sys" "dict" "0" "2" "2" +add hier "concept" "sys" "dict" "0" "2" "20" +add hier "concept" "sys" "dict" "0" "2" "21" +add hier "concept" "sys" "dict" "0" "2" "22" +add hier "concept" "sys" "dict" "0" "2" "23" +add hier "concept" "sys" "dict" "0" "2" "24" +add hier "concept" "sys" "dict" "0" "2" "25" +add hier "concept" "sys" "dict" "0" "2" "26" +add hier "concept" "sys" "dict" "0" "2" "27" +add hier "concept" "sys" "dict" "0" "2" "28" +add hier "concept" "sys" "dict" "0" "2" "29" +add hier "concept" "sys" "dict" "0" "3" +add hier "concept" "sys" "dict" "0" "3" "3" +add hier "concept" "sys" "dict" "0" "3" "30" +add hier "concept" "sys" "dict" "0" "3" "31" +add hier "concept" "sys" "dict" "0" "3" "32" +add hier "concept" "sys" "dict" "0" "3" "33" +add hier "concept" "sys" "dict" "0" "3" "34" +add hier "concept" "sys" "dict" "0" "3" "35" +add hier "concept" "sys" "dict" "0" "3" "36" +add hier "concept" "sys" "dict" "0" "3" "37" +add hier "concept" "sys" "dict" "0" "3" "38" +add hier "concept" "sys" "dict" "0" "3" "39" +add hier "concept" "sys" "dict" "0" "4" +add hier "concept" "sys" "dict" "0" "4" "4" +add hier "concept" "sys" "dict" "0" "4" "40" +add hier "concept" "sys" "dict" "0" "4" "41" +add hier "concept" "sys" "dict" "0" "4" "42" +add hier "concept" "sys" "dict" "0" "4" "43" +add hier "concept" "sys" "dict" "0" "4" "44" +add hier "concept" "sys" "dict" "0" "4" "45" +add hier "concept" "sys" "dict" "0" "4" "46" +add hier "concept" "sys" "dict" "0" "4" "47" +add hier "concept" "sys" "dict" "0" "4" "48" +add hier "concept" "sys" "dict" "0" "4" "49" +add hier "concept" "sys" "dict" "0" "5" +add hier "concept" "sys" "dict" "0" "5" "5" +add hier "concept" "sys" "dict" "0" "5" "50" +add hier "concept" "sys" "dict" "0" "5" "51" +add hier "concept" "sys" "dict" "0" "5" "52" +add hier "concept" "sys" "dict" "0" "5" "53" +add hier "concept" "sys" "dict" "0" "5" "54" +add hier "concept" "sys" "dict" "0" "5" "55" +add hier "concept" "sys" "dict" "0" "5" "56" +add hier "concept" "sys" "dict" "0" "5" "57" +add hier "concept" "sys" "dict" "0" "5" "58" +add hier "concept" "sys" "dict" "0" "5" "59" +add hier "concept" "sys" "dict" "0" "6" +add hier "concept" "sys" "dict" "0" "6" "6" +add hier "concept" "sys" "dict" "0" "6" "60" +add hier "concept" "sys" "dict" "0" "6" "61" +add hier "concept" "sys" "dict" "0" "6" "62" +add hier "concept" "sys" "dict" "0" "6" "63" +add hier "concept" "sys" "dict" "0" "6" "64" +add hier "concept" "sys" "dict" "0" "6" "65" +add hier "concept" "sys" "dict" "0" "6" "66" +add hier "concept" "sys" "dict" "0" "6" "67" +add hier "concept" "sys" "dict" "0" "6" "68" +add hier "concept" "sys" "dict" "0" "6" "69" +add hier "concept" "sys" "dict" "0" "7" +add hier "concept" "sys" "dict" "0" "7" "7" +add hier "concept" "sys" "dict" "0" "7" "70" +add hier "concept" "sys" "dict" "0" "7" "71" +add hier "concept" "sys" "dict" "0" "7" "72" +add hier "concept" "sys" "dict" "0" "7" "73" +add hier "concept" "sys" "dict" "0" "7" "74" +add hier "concept" "sys" "dict" "0" "7" "75" +add hier "concept" "sys" "dict" "0" "7" "76" +add hier "concept" "sys" "dict" "0" "7" "77" +add hier "concept" "sys" "dict" "0" "7" "78" +add hier "concept" "sys" "dict" "0" "7" "79" +add hier "concept" "sys" "dict" "0" "8" +add hier "concept" "sys" "dict" "0" "8" "8" +add hier "concept" "sys" "dict" "0" "8" "80" +add hier "concept" "sys" "dict" "0" "8" "81" +add hier "concept" "sys" "dict" "0" "8" "82" +add hier "concept" "sys" "dict" "0" "8" "83" +add hier "concept" "sys" "dict" "0" "8" "84" +add hier "concept" "sys" "dict" "0" "8" "85" +add hier "concept" "sys" "dict" "0" "8" "86" +add hier "concept" "sys" "dict" "0" "8" "87" +add hier "concept" "sys" "dict" "0" "8" "88" +add hier "concept" "sys" "dict" "0" "8" "89" +add hier "concept" "sys" "dict" "0" "9" +add hier "concept" "sys" "dict" "0" "9" "9" +add hier "concept" "sys" "dict" "0" "9" "90" +add hier "concept" "sys" "dict" "0" "9" "91" +add hier "concept" "sys" "dict" "0" "9" "92" +add hier "concept" "sys" "dict" "0" "9" "93" +add hier "concept" "sys" "dict" "0" "9" "94" +add hier "concept" "sys" "dict" "0" "9" "95" +add hier "concept" "sys" "dict" "0" "9" "96" +add hier "concept" "sys" "dict" "0" "9" "97" +add hier "concept" "sys" "dict" "0" "9" "98" +add hier "concept" "sys" "dict" "0" "9" "99" +add hier "concept" "sys" "dict" "A" +add hier "concept" "sys" "dict" "wht" +add hier "concept" "sys" "dict" "pnct" +add hier "concept" "sys" "dict" "ctrl" +add hier "concept" "sys" "dict" "emoji" +add hier "concept" "sys" "dict" "unknown" + +quit + diff --git a/.github/workflows/tests/call-analyzer-callee/kb/user/shades-full.dict b/.github/workflows/tests/call-analyzer-callee/kb/user/shades-full.dict new file mode 100644 index 00000000..da6a951f --- /dev/null +++ b/.github/workflows/tests/call-analyzer-callee/kb/user/shades-full.dict @@ -0,0 +1,2 @@ +crimson color=yes +scarlet color=yes diff --git a/.github/workflows/tests/call-analyzer-callee/spec/analyzer.seq b/.github/workflows/tests/call-analyzer-callee/spec/analyzer.seq new file mode 100644 index 00000000..93f027a7 --- /dev/null +++ b/.github/workflows/tests/call-analyzer-callee/spec/analyzer.seq @@ -0,0 +1,3 @@ +dicttok nil # when called: look up the given node's words, lazy files included +nlp colors # turn color words into _color nodes and record them +nlp mark # mark every other word it was given diff --git a/.github/workflows/tests/call-analyzer-callee/spec/colors.nlp b/.github/workflows/tests/call-analyzer-callee/spec/colors.nlp new file mode 100644 index 00000000..a48595f2 --- /dev/null +++ b/.github/workflows/tests/call-analyzer-callee/spec/colors.nlp @@ -0,0 +1,32 @@ +############################################### +# FILE: colors.nlp +# SUBJ: The analyzer tests/call-analyzer calls. Works on the node it is +# given and records the colors it finds in callconcept(). +# NOTE: Not run on its own by CI. +############################################### + +@CODE +L("out") = callconcept(); +addstrval(L("out"),"root",pnname(pnroot())); + +# The caller's G() variables are not visible here. +if (G("mine")) + addnumval(L("out"),"sawcallerG",1); +else + addnumval(L("out"),"sawcallerG",0); +G("mine") = "callee"; + +# The analyzer that called this one is still running, so this is refused. +addnumval(L("out"),"backcall",callanalyzer(pnroot(),L("out"),"call-analyzer")); +@@CODE + +@CHECK +if (!N("color",1)) + fail(); + +@POST +addstrval(callconcept(),"color",strtolower(N("$text",1))); +single(); + +@RULES +_color <- _xALPHA @@ diff --git a/.github/workflows/tests/call-analyzer-callee/spec/mark.nlp b/.github/workflows/tests/call-analyzer-callee/spec/mark.nlp new file mode 100644 index 00000000..18d3079c --- /dev/null +++ b/.github/workflows/tests/call-analyzer-callee/spec/mark.nlp @@ -0,0 +1,11 @@ +############################################### +# FILE: mark.nlp +# SUBJ: Mark every word left, so the caller can see which nodes this +# analyzer reached. +############################################### + +@POST +N("callee",1) = 1; + +@RULES +_xNIL <- _xALPHA @@ diff --git a/.github/workflows/tests/call-analyzer/input/text.txt b/.github/workflows/tests/call-analyzer/input/text.txt new file mode 100644 index 00000000..7ac21f14 --- /dev/null +++ b/.github/workflows/tests/call-analyzer/input/text.txt @@ -0,0 +1 @@ +Red apples. Crimson sky and green grass. Blue diff --git a/.github/workflows/tests/call-analyzer/kb/user/hier.kb b/.github/workflows/tests/call-analyzer/kb/user/hier.kb new file mode 100644 index 00000000..9d513bf1 --- /dev/null +++ b/.github/workflows/tests/call-analyzer/kb/user/hier.kb @@ -0,0 +1,756 @@ +add empty +add root +add hier "concept" "gram" +add hier "concept" "sys" +add hier "concept" "sys" "attrs" +add hier "concept" "sys" "attrs" "proxy" +add hier "concept" "sys" "attrs" "proxy" "atom" +add hier "concept" "sys" "attrs" "pproxy" +add hier "concept" "sys" "attrs" "pproxy" "phrase" +add hier "concept" "sys" "attrs" "common" +add hier "concept" "sys" "attrs" "common" "var" +add hier "concept" "sys" "attrs" "rule_elt" +add hier "concept" "sys" "vals" +add hier "concept" "sys" "vals" "boolean" +add hier "concept" "sys" "vals" "boolean" "false" +add hier "concept" "sys" "vals" "boolean" "true" +add hier "concept" "sys" "nlp" +add hier "concept" "sys" "nlp" "wht" +add hier "concept" "sys" "nlp" "punct" +add hier "concept" "sys" "nlp" "ctrl" +add hier "concept" "sys" "nlp" "lex" +add hier "concept" "sys" "nlp" "lex" "slot" +add hier "concept" "sys" "nlp" "lex" "slot" "cases" +add hier "concept" "sys" "mean" +add hier "concept" "sys" "mean" "slot" +add hier "concept" "sys" "mean" "slot" "case" +add hier "concept" "sys" "mean" "slot" "case" "cap" +add hier "concept" "sys" "mean" "slot" "case" "allcap" +add hier "concept" "sys" "mean" "slot" "case" "mixed" +add hier "concept" "sys" "mean" "slot" "mixed" +add hier "concept" "sys" "dict" +add hier "concept" "sys" "dict" "a" +add hier "concept" "sys" "dict" "a" "A" +add hier "concept" "sys" "dict" "a" "A" "A" +add hier "concept" "sys" "dict" "a" "A" "Aa" +add hier "concept" "sys" "dict" "a" "A" "Ab" +add hier "concept" "sys" "dict" "a" "A" "Ac" +add hier "concept" "sys" "dict" "a" "A" "Ad" +add hier "concept" "sys" "dict" "a" "A" "Ae" +add hier "concept" "sys" "dict" "a" "A" "Af" +add hier "concept" "sys" "dict" "a" "A" "Ag" +add hier "concept" "sys" "dict" "a" "A" "Ah" +add hier "concept" "sys" "dict" "a" "A" "Ai" +add hier "concept" "sys" "dict" "a" "A" "Aj" +add hier "concept" "sys" "dict" "a" "A" "Ak" +add hier "concept" "sys" "dict" "a" "A" "Al" +add hier "concept" "sys" "dict" "a" "A" "Am" +add hier "concept" "sys" "dict" "a" "A" "An" +add hier "concept" "sys" "dict" "a" "A" "Ap" +add hier "concept" "sys" "dict" "a" "A" "Aq" +add hier "concept" "sys" "dict" "a" "A" "Ar" +add hier "concept" "sys" "dict" "a" "A" "As" +add hier "concept" "sys" "dict" "a" "A" "At" +add hier "concept" "sys" "dict" "a" "A" "Au" +add hier "concept" "sys" "dict" "a" "A" "Av" +add hier "concept" "sys" "dict" "a" "A" "Aw" +add hier "concept" "sys" "dict" "a" "A" "Ax" +add hier "concept" "sys" "dict" "a" "A" "Ay" +add hier "concept" "sys" "dict" "a" "A" "Az" +add hier "concept" "sys" "dict" "a" "B" +add hier "concept" "sys" "dict" "a" "B" "B" +add hier "concept" "sys" "dict" "a" "B" "Ba" +add hier "concept" "sys" "dict" "a" "B" "Be" +add hier "concept" "sys" "dict" "a" "B" "Bi" +add hier "concept" "sys" "dict" "a" "B" "Bl" +add hier "concept" "sys" "dict" "a" "B" "Bo" +add hier "concept" "sys" "dict" "a" "B" "Br" +add hier "concept" "sys" "dict" "a" "B" "Bu" +add hier "concept" "sys" "dict" "a" "B" "By" +add hier "concept" "sys" "dict" "a" "C" +add hier "concept" "sys" "dict" "a" "C" "C" +add hier "concept" "sys" "dict" "a" "C" "Ca" +add hier "concept" "sys" "dict" "a" "C" "Ce" +add hier "concept" "sys" "dict" "a" "C" "Ch" +add hier "concept" "sys" "dict" "a" "C" "Ci" +add hier "concept" "sys" "dict" "a" "C" "Cl" +add hier "concept" "sys" "dict" "a" "C" "Co" +add hier "concept" "sys" "dict" "a" "C" "Cr" +add hier "concept" "sys" "dict" "a" "C" "Cu" +add hier "concept" "sys" "dict" "a" "C" "Cy" +add hier "concept" "sys" "dict" "a" "D" +add hier "concept" "sys" "dict" "a" "D" "D" +add hier "concept" "sys" "dict" "a" "D" "Da" +add hier "concept" "sys" "dict" "a" "D" "De" +add hier "concept" "sys" "dict" "a" "D" "Di" +add hier "concept" "sys" "dict" "a" "D" "Do" +add hier "concept" "sys" "dict" "a" "D" "Dr" +add hier "concept" "sys" "dict" "a" "D" "Du" +add hier "concept" "sys" "dict" "a" "D" "Dy" +add hier "concept" "sys" "dict" "a" "E" +add hier "concept" "sys" "dict" "a" "E" "E" +add hier "concept" "sys" "dict" "a" "E" "Ea" +add hier "concept" "sys" "dict" "a" "E" "Eb" +add hier "concept" "sys" "dict" "a" "E" "Ed" +add hier "concept" "sys" "dict" "a" "E" "Ee" +add hier "concept" "sys" "dict" "a" "E" "Ef" +add hier "concept" "sys" "dict" "a" "E" "Eg" +add hier "concept" "sys" "dict" "a" "E" "Eh" +add hier "concept" "sys" "dict" "a" "E" "Ei" +add hier "concept" "sys" "dict" "a" "E" "Ej" +add hier "concept" "sys" "dict" "a" "E" "El" +add hier "concept" "sys" "dict" "a" "E" "Em" +add hier "concept" "sys" "dict" "a" "E" "En" +add hier "concept" "sys" "dict" "a" "E" "Eo" +add hier "concept" "sys" "dict" "a" "E" "Ep" +add hier "concept" "sys" "dict" "a" "E" "Eq" +add hier "concept" "sys" "dict" "a" "E" "Er" +add hier "concept" "sys" "dict" "a" "E" "Es" +add hier "concept" "sys" "dict" "a" "E" "Et" +add hier "concept" "sys" "dict" "a" "E" "Eu" +add hier "concept" "sys" "dict" "a" "E" "Ev" +add hier "concept" "sys" "dict" "a" "E" "Ew" +add hier "concept" "sys" "dict" "a" "E" "Ex" +add hier "concept" "sys" "dict" "a" "E" "Ey" +add hier "concept" "sys" "dict" "a" "E" "Ez" +add hier "concept" "sys" "dict" "a" "F" +add hier "concept" "sys" "dict" "a" "F" "F" +add hier "concept" "sys" "dict" "a" "F" "Fa" +add hier "concept" "sys" "dict" "a" "F" "Fe" +add hier "concept" "sys" "dict" "a" "F" "Fi" +add hier "concept" "sys" "dict" "a" "F" "Fl" +add hier "concept" "sys" "dict" "a" "F" "Fo" +add hier "concept" "sys" "dict" "a" "F" "Fr" +add hier "concept" "sys" "dict" "a" "F" "Fu" +add hier "concept" "sys" "dict" "a" "F" "Fy" +add hier "concept" "sys" "dict" "a" "G" +add hier "concept" "sys" "dict" "a" "G" "G" +add hier "concept" "sys" "dict" "a" "G" "Ga" +add hier "concept" "sys" "dict" "a" "G" "Ge" +add hier "concept" "sys" "dict" "a" "G" "Gh" +add hier "concept" "sys" "dict" "a" "G" "Gi" +add hier "concept" "sys" "dict" "a" "G" "Gl" +add hier "concept" "sys" "dict" "a" "G" "Gn" +add hier "concept" "sys" "dict" "a" "G" "Go" +add hier "concept" "sys" "dict" "a" "G" "Gr" +add hier "concept" "sys" "dict" "a" "G" "Gu" +add hier "concept" "sys" "dict" "a" "G" "Gy" +add hier "concept" "sys" "dict" "a" "H" +add hier "concept" "sys" "dict" "a" "H" "H" +add hier "concept" "sys" "dict" "a" "H" "Ha" +add hier "concept" "sys" "dict" "a" "H" "He" +add hier "concept" "sys" "dict" "a" "H" "Hi" +add hier "concept" "sys" "dict" "a" "H" "Ho" +add hier "concept" "sys" "dict" "a" "H" "Hu" +add hier "concept" "sys" "dict" "a" "H" "Hy" +add hier "concept" "sys" "dict" "a" "I" +add hier "concept" "sys" "dict" "a" "I" "I" +add hier "concept" "sys" "dict" "a" "I" "Ia" +add hier "concept" "sys" "dict" "a" "I" "Ib" +add hier "concept" "sys" "dict" "a" "I" "Ic" +add hier "concept" "sys" "dict" "a" "I" "Id" +add hier "concept" "sys" "dict" "a" "I" "Ig" +add hier "concept" "sys" "dict" "a" "I" "Il" +add hier "concept" "sys" "dict" "a" "I" "Im" +add hier "concept" "sys" "dict" "a" "I" "In" +add hier "concept" "sys" "dict" "a" "I" "Io" +add hier "concept" "sys" "dict" "a" "I" "Ir" +add hier "concept" "sys" "dict" "a" "I" "Is" +add hier "concept" "sys" "dict" "a" "I" "It" +add hier "concept" "sys" "dict" "a" "J" +add hier "concept" "sys" "dict" "a" "J" "J" +add hier "concept" "sys" "dict" "a" "J" "Ja" +add hier "concept" "sys" "dict" "a" "J" "Je" +add hier "concept" "sys" "dict" "a" "J" "Ji" +add hier "concept" "sys" "dict" "a" "J" "Jo" +add hier "concept" "sys" "dict" "a" "J" "Ju" +add hier "concept" "sys" "dict" "a" "K" +add hier "concept" "sys" "dict" "a" "K" "K" +add hier "concept" "sys" "dict" "a" "K" "Ka" +add hier "concept" "sys" "dict" "a" "K" "Ke" +add hier "concept" "sys" "dict" "a" "K" "Kh" +add hier "concept" "sys" "dict" "a" "K" "Ki" +add hier "concept" "sys" "dict" "a" "K" "Kl" +add hier "concept" "sys" "dict" "a" "K" "Kn" +add hier "concept" "sys" "dict" "a" "K" "Ko" +add hier "concept" "sys" "dict" "a" "K" "Kr" +add hier "concept" "sys" "dict" "a" "K" "Ku" +add hier "concept" "sys" "dict" "a" "L" +add hier "concept" "sys" "dict" "a" "L" "L" +add hier "concept" "sys" "dict" "a" "L" "La" +add hier "concept" "sys" "dict" "a" "L" "Le" +add hier "concept" "sys" "dict" "a" "L" "Li" +add hier "concept" "sys" "dict" "a" "L" "Ll" +add hier "concept" "sys" "dict" "a" "L" "Lo" +add hier "concept" "sys" "dict" "a" "L" "Lu" +add hier "concept" "sys" "dict" "a" "L" "Ly" +add hier "concept" "sys" "dict" "a" "M" +add hier "concept" "sys" "dict" "a" "M" "M" +add hier "concept" "sys" "dict" "a" "M" "Ma" +add hier "concept" "sys" "dict" "a" "M" "Me" +add hier "concept" "sys" "dict" "a" "M" "Mi" +add hier "concept" "sys" "dict" "a" "M" "Mn" +add hier "concept" "sys" "dict" "a" "M" "Mo" +add hier "concept" "sys" "dict" "a" "M" "Mu" +add hier "concept" "sys" "dict" "a" "M" "My" +add hier "concept" "sys" "dict" "a" "N" +add hier "concept" "sys" "dict" "a" "N" "N" +add hier "concept" "sys" "dict" "a" "N" "Na" +add hier "concept" "sys" "dict" "a" "N" "Ne" +add hier "concept" "sys" "dict" "a" "N" "Ni" +add hier "concept" "sys" "dict" "a" "N" "No" +add hier "concept" "sys" "dict" "a" "N" "Nu" +add hier "concept" "sys" "dict" "a" "N" "Ny" +add hier "concept" "sys" "dict" "a" "O" +add hier "concept" "sys" "dict" "a" "O" "O" +add hier "concept" "sys" "dict" "a" "O" "Oa" +add hier "concept" "sys" "dict" "a" "O" "Ob" +add hier "concept" "sys" "dict" "a" "O" "Oc" +add hier "concept" "sys" "dict" "a" "O" "Od" +add hier "concept" "sys" "dict" "a" "O" "Oe" +add hier "concept" "sys" "dict" "a" "O" "Of" +add hier "concept" "sys" "dict" "a" "O" "Og" +add hier "concept" "sys" "dict" "a" "O" "Oh" +add hier "concept" "sys" "dict" "a" "O" "Oi" +add hier "concept" "sys" "dict" "a" "O" "Ok" +add hier "concept" "sys" "dict" "a" "O" "On" +add hier "concept" "sys" "dict" "a" "O" "Oo" +add hier "concept" "sys" "dict" "a" "O" "Op" +add hier "concept" "sys" "dict" "a" "O" "Oq" +add hier "concept" "sys" "dict" "a" "O" "Or" +add hier "concept" "sys" "dict" "a" "O" "Os" +add hier "concept" "sys" "dict" "a" "O" "Ot" +add hier "concept" "sys" "dict" "a" "O" "Ou" +add hier "concept" "sys" "dict" "a" "O" "Ov" +add hier "concept" "sys" "dict" "a" "O" "Ow" +add hier "concept" "sys" "dict" "a" "O" "Ox" +add hier "concept" "sys" "dict" "a" "O" "Oy" +add hier "concept" "sys" "dict" "a" "O" "Oz" +add hier "concept" "sys" "dict" "a" "P" +add hier "concept" "sys" "dict" "a" "P" "P" +add hier "concept" "sys" "dict" "a" "P" "Pa" +add hier "concept" "sys" "dict" "a" "P" "Pe" +add hier "concept" "sys" "dict" "a" "P" "Ph" +add hier "concept" "sys" "dict" "a" "P" "Pi" +add hier "concept" "sys" "dict" "a" "P" "Pl" +add hier "concept" "sys" "dict" "a" "P" "Pn" +add hier "concept" "sys" "dict" "a" "P" "Po" +add hier "concept" "sys" "dict" "a" "P" "Pr" +add hier "concept" "sys" "dict" "a" "P" "Pt" +add hier "concept" "sys" "dict" "a" "P" "Pu" +add hier "concept" "sys" "dict" "a" "P" "Py" +add hier "concept" "sys" "dict" "a" "Q" +add hier "concept" "sys" "dict" "a" "Q" "Q" +add hier "concept" "sys" "dict" "a" "Q" "Qa" +add hier "concept" "sys" "dict" "a" "Q" "Qu" +add hier "concept" "sys" "dict" "a" "R" +add hier "concept" "sys" "dict" "a" "R" "R" +add hier "concept" "sys" "dict" "a" "R" "Ra" +add hier "concept" "sys" "dict" "a" "R" "Re" +add hier "concept" "sys" "dict" "a" "R" "Rh" +add hier "concept" "sys" "dict" "a" "R" "Ri" +add hier "concept" "sys" "dict" "a" "R" "Ro" +add hier "concept" "sys" "dict" "a" "R" "Ru" +add hier "concept" "sys" "dict" "a" "R" "Ry" +add hier "concept" "sys" "dict" "a" "S" +add hier "concept" "sys" "dict" "a" "S" "S" +add hier "concept" "sys" "dict" "a" "S" "Sa" +add hier "concept" "sys" "dict" "a" "S" "Sc" +add hier "concept" "sys" "dict" "a" "S" "Se" +add hier "concept" "sys" "dict" "a" "S" "Sf" +add hier "concept" "sys" "dict" "a" "S" "Sh" +add hier "concept" "sys" "dict" "a" "S" "Si" +add hier "concept" "sys" "dict" "a" "S" "Sk" +add hier "concept" "sys" "dict" "a" "S" "Sl" +add hier "concept" "sys" "dict" "a" "S" "Sm" +add hier "concept" "sys" "dict" "a" "S" "Sn" +add hier "concept" "sys" "dict" "a" "S" "So" +add hier "concept" "sys" "dict" "a" "S" "Sp" +add hier "concept" "sys" "dict" "a" "S" "Sq" +add hier "concept" "sys" "dict" "a" "S" "St" +add hier "concept" "sys" "dict" "a" "S" "Su" +add hier "concept" "sys" "dict" "a" "S" "Sw" +add hier "concept" "sys" "dict" "a" "S" "Sy" +add hier "concept" "sys" "dict" "a" "T" +add hier "concept" "sys" "dict" "a" "T" "T" +add hier "concept" "sys" "dict" "a" "T" "Ta" +add hier "concept" "sys" "dict" "a" "T" "Te" +add hier "concept" "sys" "dict" "a" "T" "Th" +add hier "concept" "sys" "dict" "a" "T" "Ti" +add hier "concept" "sys" "dict" "a" "T" "To" +add hier "concept" "sys" "dict" "a" "T" "Tr" +add hier "concept" "sys" "dict" "a" "T" "Tu" +add hier "concept" "sys" "dict" "a" "T" "Tw" +add hier "concept" "sys" "dict" "a" "T" "Ty" +add hier "concept" "sys" "dict" "a" "U" +add hier "concept" "sys" "dict" "a" "U" "U" +add hier "concept" "sys" "dict" "a" "U" "Ua" +add hier "concept" "sys" "dict" "a" "U" "Un" +add hier "concept" "sys" "dict" "a" "U" "Up" +add hier "concept" "sys" "dict" "a" "U" "Ur" +add hier "concept" "sys" "dict" "a" "V" +add hier "concept" "sys" "dict" "a" "V" "V" +add hier "concept" "sys" "dict" "a" "V" "Va" +add hier "concept" "sys" "dict" "a" "V" "Ve" +add hier "concept" "sys" "dict" "a" "V" "Vi" +add hier "concept" "sys" "dict" "a" "V" "Vo" +add hier "concept" "sys" "dict" "a" "V" "Vu" +add hier "concept" "sys" "dict" "a" "W" +add hier "concept" "sys" "dict" "a" "W" "W" +add hier "concept" "sys" "dict" "a" "W" "Wa" +add hier "concept" "sys" "dict" "a" "W" "We" +add hier "concept" "sys" "dict" "a" "W" "Wh" +add hier "concept" "sys" "dict" "a" "W" "Wi" +add hier "concept" "sys" "dict" "a" "W" "Wo" +add hier "concept" "sys" "dict" "a" "W" "Wr" +add hier "concept" "sys" "dict" "a" "W" "Wu" +add hier "concept" "sys" "dict" "a" "X" +add hier "concept" "sys" "dict" "a" "X" "X" +add hier "concept" "sys" "dict" "a" "X" "Xa" +add hier "concept" "sys" "dict" "a" "X" "Xe" +add hier "concept" "sys" "dict" "a" "X" "Xi" +add hier "concept" "sys" "dict" "a" "X" "Xo" +add hier "concept" "sys" "dict" "a" "X" "Xu" +add hier "concept" "sys" "dict" "a" "X" "Xy" +add hier "concept" "sys" "dict" "a" "Y" +add hier "concept" "sys" "dict" "a" "Y" "Y" +add hier "concept" "sys" "dict" "a" "Y" "Ya" +add hier "concept" "sys" "dict" "a" "Y" "Ye" +add hier "concept" "sys" "dict" "a" "Y" "Yi" +add hier "concept" "sys" "dict" "a" "Y" "Yo" +add hier "concept" "sys" "dict" "a" "Y" "Yu" +add hier "concept" "sys" "dict" "a" "Z" +add hier "concept" "sys" "dict" "a" "Z" "Z" +add hier "concept" "sys" "dict" "a" "Z" "Za" +add hier "concept" "sys" "dict" "a" "Z" "Ze" +add hier "concept" "sys" "dict" "a" "Z" "Zi" +add hier "concept" "sys" "dict" "a" "Z" "Zo" +add hier "concept" "sys" "dict" "a" "Z" "Zu" +add hier "concept" "sys" "dict" "a" "Z" "Zy" +add hier "concept" "sys" "dict" "a" "a" +add hier "concept" "sys" "dict" "a" "a" "a" +add hier "concept" "sys" "dict" "a" "a" "aa" +add hier "concept" "sys" "dict" "a" "a" "ab" +add hier "concept" "sys" "dict" "a" "a" "ac" +add hier "concept" "sys" "dict" "a" "a" "ad" +add hier "concept" "sys" "dict" "a" "a" "ae" +add hier "concept" "sys" "dict" "a" "a" "af" +add hier "concept" "sys" "dict" "a" "a" "ag" +add hier "concept" "sys" "dict" "a" "a" "ah" +add hier "concept" "sys" "dict" "a" "a" "ai" +add hier "concept" "sys" "dict" "a" "a" "aj" +add hier "concept" "sys" "dict" "a" "a" "ak" +add hier "concept" "sys" "dict" "a" "a" "al" +add hier "concept" "sys" "dict" "a" "a" "am" +add hier "concept" "sys" "dict" "a" "a" "an" +add hier "concept" "sys" "dict" "a" "a" "ap" +add hier "concept" "sys" "dict" "a" "a" "aq" +add hier "concept" "sys" "dict" "a" "a" "ar" +add hier "concept" "sys" "dict" "a" "a" "as" +add hier "concept" "sys" "dict" "a" "a" "at" +add hier "concept" "sys" "dict" "a" "a" "au" +add hier "concept" "sys" "dict" "a" "a" "av" +add hier "concept" "sys" "dict" "a" "a" "aw" +add hier "concept" "sys" "dict" "a" "a" "ax" +add hier "concept" "sys" "dict" "a" "a" "ay" +add hier "concept" "sys" "dict" "a" "a" "az" +add hier "concept" "sys" "dict" "a" "b" +add hier "concept" "sys" "dict" "a" "b" "b" +add hier "concept" "sys" "dict" "a" "b" "ba" +add hier "concept" "sys" "dict" "a" "b" "be" +add hier "concept" "sys" "dict" "a" "b" "bi" +add hier "concept" "sys" "dict" "a" "b" "bl" +add hier "concept" "sys" "dict" "a" "b" "bo" +add hier "concept" "sys" "dict" "a" "b" "br" +add hier "concept" "sys" "dict" "a" "b" "bu" +add hier "concept" "sys" "dict" "a" "b" "by" +add hier "concept" "sys" "dict" "a" "c" +add hier "concept" "sys" "dict" "a" "c" "c" +add hier "concept" "sys" "dict" "a" "c" "ca" +add hier "concept" "sys" "dict" "a" "c" "ce" +add hier "concept" "sys" "dict" "a" "c" "ch" +add hier "concept" "sys" "dict" "a" "c" "ci" +add hier "concept" "sys" "dict" "a" "c" "cl" +add hier "concept" "sys" "dict" "a" "c" "co" +add hier "concept" "sys" "dict" "a" "c" "cr" +add hier "concept" "sys" "dict" "a" "c" "cu" +add hier "concept" "sys" "dict" "a" "c" "cy" +add hier "concept" "sys" "dict" "a" "d" +add hier "concept" "sys" "dict" "a" "d" "d" +add hier "concept" "sys" "dict" "a" "d" "da" +add hier "concept" "sys" "dict" "a" "d" "de" +add hier "concept" "sys" "dict" "a" "d" "di" +add hier "concept" "sys" "dict" "a" "d" "do" +add hier "concept" "sys" "dict" "a" "d" "dr" +add hier "concept" "sys" "dict" "a" "d" "du" +add hier "concept" "sys" "dict" "a" "d" "dy" +add hier "concept" "sys" "dict" "a" "e" +add hier "concept" "sys" "dict" "a" "e" "e" +add hier "concept" "sys" "dict" "a" "e" "ea" +add hier "concept" "sys" "dict" "a" "e" "eb" +add hier "concept" "sys" "dict" "a" "e" "ed" +add hier "concept" "sys" "dict" "a" "e" "ee" +add hier "concept" "sys" "dict" "a" "e" "ef" +add hier "concept" "sys" "dict" "a" "e" "eg" +add hier "concept" "sys" "dict" "a" "e" "eh" +add hier "concept" "sys" "dict" "a" "e" "ei" +add hier "concept" "sys" "dict" "a" "e" "ej" +add hier "concept" "sys" "dict" "a" "e" "el" +add hier "concept" "sys" "dict" "a" "e" "em" +add hier "concept" "sys" "dict" "a" "e" "en" +add hier "concept" "sys" "dict" "a" "e" "eo" +add hier "concept" "sys" "dict" "a" "e" "ep" +add hier "concept" "sys" "dict" "a" "e" "eq" +add hier "concept" "sys" "dict" "a" "e" "er" +add hier "concept" "sys" "dict" "a" "e" "es" +add hier "concept" "sys" "dict" "a" "e" "et" +add hier "concept" "sys" "dict" "a" "e" "eu" +add hier "concept" "sys" "dict" "a" "e" "ev" +add hier "concept" "sys" "dict" "a" "e" "ew" +add hier "concept" "sys" "dict" "a" "e" "ex" +add hier "concept" "sys" "dict" "a" "e" "ey" +add hier "concept" "sys" "dict" "a" "e" "ez" +add hier "concept" "sys" "dict" "a" "f" +add hier "concept" "sys" "dict" "a" "f" "f" +add hier "concept" "sys" "dict" "a" "f" "fa" +add hier "concept" "sys" "dict" "a" "f" "fe" +add hier "concept" "sys" "dict" "a" "f" "fi" +add hier "concept" "sys" "dict" "a" "f" "fl" +add hier "concept" "sys" "dict" "a" "f" "fo" +add hier "concept" "sys" "dict" "a" "f" "fr" +add hier "concept" "sys" "dict" "a" "f" "fu" +add hier "concept" "sys" "dict" "a" "f" "fy" +add hier "concept" "sys" "dict" "a" "g" +add hier "concept" "sys" "dict" "a" "g" "g" +add hier "concept" "sys" "dict" "a" "g" "ga" +add hier "concept" "sys" "dict" "a" "g" "ge" +add hier "concept" "sys" "dict" "a" "g" "gh" +add hier "concept" "sys" "dict" "a" "g" "gi" +add hier "concept" "sys" "dict" "a" "g" "gl" +add hier "concept" "sys" "dict" "a" "g" "gn" +add hier "concept" "sys" "dict" "a" "g" "go" +add hier "concept" "sys" "dict" "a" "g" "gr" +add hier "concept" "sys" "dict" "a" "g" "gu" +add hier "concept" "sys" "dict" "a" "g" "gy" +add hier "concept" "sys" "dict" "a" "h" +add hier "concept" "sys" "dict" "a" "h" "h" +add hier "concept" "sys" "dict" "a" "h" "ha" +add hier "concept" "sys" "dict" "a" "h" "he" +add hier "concept" "sys" "dict" "a" "h" "hi" +add hier "concept" "sys" "dict" "a" "h" "ho" +add hier "concept" "sys" "dict" "a" "h" "hu" +add hier "concept" "sys" "dict" "a" "h" "hy" +add hier "concept" "sys" "dict" "a" "i" +add hier "concept" "sys" "dict" "a" "i" "i" +add hier "concept" "sys" "dict" "a" "i" "ia" +add hier "concept" "sys" "dict" "a" "i" "ib" +add hier "concept" "sys" "dict" "a" "i" "ic" +add hier "concept" "sys" "dict" "a" "i" "id" +add hier "concept" "sys" "dict" "a" "i" "ig" +add hier "concept" "sys" "dict" "a" "i" "il" +add hier "concept" "sys" "dict" "a" "i" "im" +add hier "concept" "sys" "dict" "a" "i" "in" +add hier "concept" "sys" "dict" "a" "i" "io" +add hier "concept" "sys" "dict" "a" "i" "ir" +add hier "concept" "sys" "dict" "a" "i" "is" +add hier "concept" "sys" "dict" "a" "i" "it" +add hier "concept" "sys" "dict" "a" "j" +add hier "concept" "sys" "dict" "a" "j" "j" +add hier "concept" "sys" "dict" "a" "j" "ja" +add hier "concept" "sys" "dict" "a" "j" "je" +add hier "concept" "sys" "dict" "a" "j" "ji" +add hier "concept" "sys" "dict" "a" "j" "jo" +add hier "concept" "sys" "dict" "a" "j" "ju" +add hier "concept" "sys" "dict" "a" "k" +add hier "concept" "sys" "dict" "a" "k" "k" +add hier "concept" "sys" "dict" "a" "k" "ka" +add hier "concept" "sys" "dict" "a" "k" "ke" +add hier "concept" "sys" "dict" "a" "k" "kh" +add hier "concept" "sys" "dict" "a" "k" "ki" +add hier "concept" "sys" "dict" "a" "k" "kl" +add hier "concept" "sys" "dict" "a" "k" "kn" +add hier "concept" "sys" "dict" "a" "k" "ko" +add hier "concept" "sys" "dict" "a" "k" "kr" +add hier "concept" "sys" "dict" "a" "k" "ku" +add hier "concept" "sys" "dict" "a" "l" +add hier "concept" "sys" "dict" "a" "l" "l" +add hier "concept" "sys" "dict" "a" "l" "la" +add hier "concept" "sys" "dict" "a" "l" "le" +add hier "concept" "sys" "dict" "a" "l" "li" +add hier "concept" "sys" "dict" "a" "l" "ll" +add hier "concept" "sys" "dict" "a" "l" "lo" +add hier "concept" "sys" "dict" "a" "l" "lu" +add hier "concept" "sys" "dict" "a" "l" "ly" +add hier "concept" "sys" "dict" "a" "m" +add hier "concept" "sys" "dict" "a" "m" "m" +add hier "concept" "sys" "dict" "a" "m" "ma" +add hier "concept" "sys" "dict" "a" "m" "me" +add hier "concept" "sys" "dict" "a" "m" "mi" +add hier "concept" "sys" "dict" "a" "m" "mn" +add hier "concept" "sys" "dict" "a" "m" "mo" +add hier "concept" "sys" "dict" "a" "m" "mu" +add hier "concept" "sys" "dict" "a" "m" "my" +add hier "concept" "sys" "dict" "a" "n" +add hier "concept" "sys" "dict" "a" "n" "n" +add hier "concept" "sys" "dict" "a" "n" "na" +add hier "concept" "sys" "dict" "a" "n" "ne" +add hier "concept" "sys" "dict" "a" "n" "ni" +add hier "concept" "sys" "dict" "a" "n" "no" +add hier "concept" "sys" "dict" "a" "n" "nu" +add hier "concept" "sys" "dict" "a" "n" "ny" +add hier "concept" "sys" "dict" "a" "o" +add hier "concept" "sys" "dict" "a" "o" "o" +add hier "concept" "sys" "dict" "a" "o" "oa" +add hier "concept" "sys" "dict" "a" "o" "ob" +add hier "concept" "sys" "dict" "a" "o" "oc" +add hier "concept" "sys" "dict" "a" "o" "od" +add hier "concept" "sys" "dict" "a" "o" "oe" +add hier "concept" "sys" "dict" "a" "o" "of" +add hier "concept" "sys" "dict" "a" "o" "og" +add hier "concept" "sys" "dict" "a" "o" "oh" +add hier "concept" "sys" "dict" "a" "o" "oi" +add hier "concept" "sys" "dict" "a" "o" "ok" +add hier "concept" "sys" "dict" "a" "o" "on" +add hier "concept" "sys" "dict" "a" "o" "oo" +add hier "concept" "sys" "dict" "a" "o" "op" +add hier "concept" "sys" "dict" "a" "o" "oq" +add hier "concept" "sys" "dict" "a" "o" "or" +add hier "concept" "sys" "dict" "a" "o" "os" +add hier "concept" "sys" "dict" "a" "o" "ot" +add hier "concept" "sys" "dict" "a" "o" "ou" +add hier "concept" "sys" "dict" "a" "o" "ov" +add hier "concept" "sys" "dict" "a" "o" "ow" +add hier "concept" "sys" "dict" "a" "o" "ox" +add hier "concept" "sys" "dict" "a" "o" "oy" +add hier "concept" "sys" "dict" "a" "o" "oz" +add hier "concept" "sys" "dict" "a" "p" +add hier "concept" "sys" "dict" "a" "p" "p" +add hier "concept" "sys" "dict" "a" "p" "pa" +add hier "concept" "sys" "dict" "a" "p" "pe" +add hier "concept" "sys" "dict" "a" "p" "ph" +add hier "concept" "sys" "dict" "a" "p" "pi" +add hier "concept" "sys" "dict" "a" "p" "pl" +add hier "concept" "sys" "dict" "a" "p" "pn" +add hier "concept" "sys" "dict" "a" "p" "po" +add hier "concept" "sys" "dict" "a" "p" "pr" +add hier "concept" "sys" "dict" "a" "p" "pt" +add hier "concept" "sys" "dict" "a" "p" "pu" +add hier "concept" "sys" "dict" "a" "p" "py" +add hier "concept" "sys" "dict" "a" "q" +add hier "concept" "sys" "dict" "a" "q" "q" +add hier "concept" "sys" "dict" "a" "q" "qa" +add hier "concept" "sys" "dict" "a" "q" "qu" +add hier "concept" "sys" "dict" "a" "r" +add hier "concept" "sys" "dict" "a" "r" "r" +add hier "concept" "sys" "dict" "a" "r" "ra" +add hier "concept" "sys" "dict" "a" "r" "re" +add hier "concept" "sys" "dict" "a" "r" "rh" +add hier "concept" "sys" "dict" "a" "r" "ri" +add hier "concept" "sys" "dict" "a" "r" "ro" +add hier "concept" "sys" "dict" "a" "r" "ru" +add hier "concept" "sys" "dict" "a" "r" "ry" +add hier "concept" "sys" "dict" "a" "s" +add hier "concept" "sys" "dict" "a" "s" "s" +add hier "concept" "sys" "dict" "a" "s" "sa" +add hier "concept" "sys" "dict" "a" "s" "sc" +add hier "concept" "sys" "dict" "a" "s" "se" +add hier "concept" "sys" "dict" "a" "s" "sf" +add hier "concept" "sys" "dict" "a" "s" "sh" +add hier "concept" "sys" "dict" "a" "s" "si" +add hier "concept" "sys" "dict" "a" "s" "sk" +add hier "concept" "sys" "dict" "a" "s" "sl" +add hier "concept" "sys" "dict" "a" "s" "sm" +add hier "concept" "sys" "dict" "a" "s" "sn" +add hier "concept" "sys" "dict" "a" "s" "so" +add hier "concept" "sys" "dict" "a" "s" "sp" +add hier "concept" "sys" "dict" "a" "s" "sq" +add hier "concept" "sys" "dict" "a" "s" "st" +add hier "concept" "sys" "dict" "a" "s" "su" +add hier "concept" "sys" "dict" "a" "s" "sw" +add hier "concept" "sys" "dict" "a" "s" "sy" +add hier "concept" "sys" "dict" "a" "t" +add hier "concept" "sys" "dict" "a" "t" "t" +add hier "concept" "sys" "dict" "a" "t" "ta" +add hier "concept" "sys" "dict" "a" "t" "te" +add hier "concept" "sys" "dict" "a" "t" "th" +add hier "concept" "sys" "dict" "a" "t" "ti" +add hier "concept" "sys" "dict" "a" "t" "to" +add hier "concept" "sys" "dict" "a" "t" "tr" +add hier "concept" "sys" "dict" "a" "t" "tu" +add hier "concept" "sys" "dict" "a" "t" "tw" +add hier "concept" "sys" "dict" "a" "t" "ty" +add hier "concept" "sys" "dict" "a" "u" +add hier "concept" "sys" "dict" "a" "u" "u" +add hier "concept" "sys" "dict" "a" "u" "ua" +add hier "concept" "sys" "dict" "a" "u" "un" +add hier "concept" "sys" "dict" "a" "u" "up" +add hier "concept" "sys" "dict" "a" "u" "ur" +add hier "concept" "sys" "dict" "a" "v" +add hier "concept" "sys" "dict" "a" "v" "v" +add hier "concept" "sys" "dict" "a" "v" "va" +add hier "concept" "sys" "dict" "a" "v" "ve" +add hier "concept" "sys" "dict" "a" "v" "vi" +add hier "concept" "sys" "dict" "a" "v" "vo" +add hier "concept" "sys" "dict" "a" "v" "vu" +add hier "concept" "sys" "dict" "a" "w" +add hier "concept" "sys" "dict" "a" "w" "w" +add hier "concept" "sys" "dict" "a" "w" "wa" +add hier "concept" "sys" "dict" "a" "w" "we" +add hier "concept" "sys" "dict" "a" "w" "wh" +add hier "concept" "sys" "dict" "a" "w" "wi" +add hier "concept" "sys" "dict" "a" "w" "wo" +add hier "concept" "sys" "dict" "a" "w" "wr" +add hier "concept" "sys" "dict" "a" "w" "wu" +add hier "concept" "sys" "dict" "a" "x" +add hier "concept" "sys" "dict" "a" "x" "x" +add hier "concept" "sys" "dict" "a" "x" "xa" +add hier "concept" "sys" "dict" "a" "x" "xe" +add hier "concept" "sys" "dict" "a" "x" "xi" +add hier "concept" "sys" "dict" "a" "x" "xo" +add hier "concept" "sys" "dict" "a" "x" "xu" +add hier "concept" "sys" "dict" "a" "x" "xy" +add hier "concept" "sys" "dict" "a" "y" +add hier "concept" "sys" "dict" "a" "y" "y" +add hier "concept" "sys" "dict" "a" "y" "ya" +add hier "concept" "sys" "dict" "a" "y" "ye" +add hier "concept" "sys" "dict" "a" "y" "yi" +add hier "concept" "sys" "dict" "a" "y" "yo" +add hier "concept" "sys" "dict" "a" "y" "yu" +add hier "concept" "sys" "dict" "a" "z" +add hier "concept" "sys" "dict" "a" "z" "z" +add hier "concept" "sys" "dict" "a" "z" "za" +add hier "concept" "sys" "dict" "a" "z" "ze" +add hier "concept" "sys" "dict" "a" "z" "zi" +add hier "concept" "sys" "dict" "a" "z" "zo" +add hier "concept" "sys" "dict" "a" "z" "zu" +add hier "concept" "sys" "dict" "a" "z" "zy" +add hier "concept" "sys" "dict" "0" +add hier "concept" "sys" "dict" "0" "0" +add hier "concept" "sys" "dict" "0" "0" "0" +add hier "concept" "sys" "dict" "0" "0" "00" +add hier "concept" "sys" "dict" "0" "0" "01" +add hier "concept" "sys" "dict" "0" "0" "02" +add hier "concept" "sys" "dict" "0" "0" "03" +add hier "concept" "sys" "dict" "0" "0" "04" +add hier "concept" "sys" "dict" "0" "0" "05" +add hier "concept" "sys" "dict" "0" "0" "06" +add hier "concept" "sys" "dict" "0" "0" "07" +add hier "concept" "sys" "dict" "0" "0" "08" +add hier "concept" "sys" "dict" "0" "0" "09" +add hier "concept" "sys" "dict" "0" "1" +add hier "concept" "sys" "dict" "0" "1" "1" +add hier "concept" "sys" "dict" "0" "1" "10" +add hier "concept" "sys" "dict" "0" "1" "11" +add hier "concept" "sys" "dict" "0" "1" "12" +add hier "concept" "sys" "dict" "0" "1" "13" +add hier "concept" "sys" "dict" "0" "1" "14" +add hier "concept" "sys" "dict" "0" "1" "15" +add hier "concept" "sys" "dict" "0" "1" "16" +add hier "concept" "sys" "dict" "0" "1" "17" +add hier "concept" "sys" "dict" "0" "1" "18" +add hier "concept" "sys" "dict" "0" "1" "19" +add hier "concept" "sys" "dict" "0" "2" +add hier "concept" "sys" "dict" "0" "2" "2" +add hier "concept" "sys" "dict" "0" "2" "20" +add hier "concept" "sys" "dict" "0" "2" "21" +add hier "concept" "sys" "dict" "0" "2" "22" +add hier "concept" "sys" "dict" "0" "2" "23" +add hier "concept" "sys" "dict" "0" "2" "24" +add hier "concept" "sys" "dict" "0" "2" "25" +add hier "concept" "sys" "dict" "0" "2" "26" +add hier "concept" "sys" "dict" "0" "2" "27" +add hier "concept" "sys" "dict" "0" "2" "28" +add hier "concept" "sys" "dict" "0" "2" "29" +add hier "concept" "sys" "dict" "0" "3" +add hier "concept" "sys" "dict" "0" "3" "3" +add hier "concept" "sys" "dict" "0" "3" "30" +add hier "concept" "sys" "dict" "0" "3" "31" +add hier "concept" "sys" "dict" "0" "3" "32" +add hier "concept" "sys" "dict" "0" "3" "33" +add hier "concept" "sys" "dict" "0" "3" "34" +add hier "concept" "sys" "dict" "0" "3" "35" +add hier "concept" "sys" "dict" "0" "3" "36" +add hier "concept" "sys" "dict" "0" "3" "37" +add hier "concept" "sys" "dict" "0" "3" "38" +add hier "concept" "sys" "dict" "0" "3" "39" +add hier "concept" "sys" "dict" "0" "4" +add hier "concept" "sys" "dict" "0" "4" "4" +add hier "concept" "sys" "dict" "0" "4" "40" +add hier "concept" "sys" "dict" "0" "4" "41" +add hier "concept" "sys" "dict" "0" "4" "42" +add hier "concept" "sys" "dict" "0" "4" "43" +add hier "concept" "sys" "dict" "0" "4" "44" +add hier "concept" "sys" "dict" "0" "4" "45" +add hier "concept" "sys" "dict" "0" "4" "46" +add hier "concept" "sys" "dict" "0" "4" "47" +add hier "concept" "sys" "dict" "0" "4" "48" +add hier "concept" "sys" "dict" "0" "4" "49" +add hier "concept" "sys" "dict" "0" "5" +add hier "concept" "sys" "dict" "0" "5" "5" +add hier "concept" "sys" "dict" "0" "5" "50" +add hier "concept" "sys" "dict" "0" "5" "51" +add hier "concept" "sys" "dict" "0" "5" "52" +add hier "concept" "sys" "dict" "0" "5" "53" +add hier "concept" "sys" "dict" "0" "5" "54" +add hier "concept" "sys" "dict" "0" "5" "55" +add hier "concept" "sys" "dict" "0" "5" "56" +add hier "concept" "sys" "dict" "0" "5" "57" +add hier "concept" "sys" "dict" "0" "5" "58" +add hier "concept" "sys" "dict" "0" "5" "59" +add hier "concept" "sys" "dict" "0" "6" +add hier "concept" "sys" "dict" "0" "6" "6" +add hier "concept" "sys" "dict" "0" "6" "60" +add hier "concept" "sys" "dict" "0" "6" "61" +add hier "concept" "sys" "dict" "0" "6" "62" +add hier "concept" "sys" "dict" "0" "6" "63" +add hier "concept" "sys" "dict" "0" "6" "64" +add hier "concept" "sys" "dict" "0" "6" "65" +add hier "concept" "sys" "dict" "0" "6" "66" +add hier "concept" "sys" "dict" "0" "6" "67" +add hier "concept" "sys" "dict" "0" "6" "68" +add hier "concept" "sys" "dict" "0" "6" "69" +add hier "concept" "sys" "dict" "0" "7" +add hier "concept" "sys" "dict" "0" "7" "7" +add hier "concept" "sys" "dict" "0" "7" "70" +add hier "concept" "sys" "dict" "0" "7" "71" +add hier "concept" "sys" "dict" "0" "7" "72" +add hier "concept" "sys" "dict" "0" "7" "73" +add hier "concept" "sys" "dict" "0" "7" "74" +add hier "concept" "sys" "dict" "0" "7" "75" +add hier "concept" "sys" "dict" "0" "7" "76" +add hier "concept" "sys" "dict" "0" "7" "77" +add hier "concept" "sys" "dict" "0" "7" "78" +add hier "concept" "sys" "dict" "0" "7" "79" +add hier "concept" "sys" "dict" "0" "8" +add hier "concept" "sys" "dict" "0" "8" "8" +add hier "concept" "sys" "dict" "0" "8" "80" +add hier "concept" "sys" "dict" "0" "8" "81" +add hier "concept" "sys" "dict" "0" "8" "82" +add hier "concept" "sys" "dict" "0" "8" "83" +add hier "concept" "sys" "dict" "0" "8" "84" +add hier "concept" "sys" "dict" "0" "8" "85" +add hier "concept" "sys" "dict" "0" "8" "86" +add hier "concept" "sys" "dict" "0" "8" "87" +add hier "concept" "sys" "dict" "0" "8" "88" +add hier "concept" "sys" "dict" "0" "8" "89" +add hier "concept" "sys" "dict" "0" "9" +add hier "concept" "sys" "dict" "0" "9" "9" +add hier "concept" "sys" "dict" "0" "9" "90" +add hier "concept" "sys" "dict" "0" "9" "91" +add hier "concept" "sys" "dict" "0" "9" "92" +add hier "concept" "sys" "dict" "0" "9" "93" +add hier "concept" "sys" "dict" "0" "9" "94" +add hier "concept" "sys" "dict" "0" "9" "95" +add hier "concept" "sys" "dict" "0" "9" "96" +add hier "concept" "sys" "dict" "0" "9" "97" +add hier "concept" "sys" "dict" "0" "9" "98" +add hier "concept" "sys" "dict" "0" "9" "99" +add hier "concept" "sys" "dict" "A" +add hier "concept" "sys" "dict" "wht" +add hier "concept" "sys" "dict" "pnct" +add hier "concept" "sys" "dict" "ctrl" +add hier "concept" "sys" "dict" "emoji" +add hier "concept" "sys" "dict" "unknown" + +quit + diff --git a/.github/workflows/tests/call-analyzer/spec/analyzer.seq b/.github/workflows/tests/call-analyzer/spec/analyzer.seq new file mode 100644 index 00000000..31421e8a --- /dev/null +++ b/.github/workflows/tests/call-analyzer/spec/analyzer.seq @@ -0,0 +1,4 @@ +dicttokz nil # tokenize; this analyzer has no dictionary of its own +nlp sentence # group each sentence +nlp call # hand each sentence node to call-analyzer-callee +nlp report # print the shared tree and KB afterward diff --git a/.github/workflows/tests/call-analyzer/spec/call.nlp b/.github/workflows/tests/call-analyzer/spec/call.nlp new file mode 100644 index 00000000..aad9c39a --- /dev/null +++ b/.github/workflows/tests/call-analyzer/spec/call.nlp @@ -0,0 +1,21 @@ +############################################### +# FILE: call.nlp +# SUBJ: Regression for callanalyzer: hand each sentence node to +# another analyzer, which works on that part of this tree and +# puts what it finds in the given concept of this KB. +# NOTE: The called analyzer lives beside this one, in +# tests/call-analyzer-callee, and is found by name. +############################################### + +@CODE +G("results") = makeconcept(findroot(),"results"); +G("mine") = "caller"; +"out.txt" << "loaded-before:" << str(findana("call-analyzer-callee")) << "\n"; +@@CODE + +@POST +L("s") = makeconcept(G("results"),"sent"); +"out.txt" << "call:" << str(callanalyzer(N(1),L("s"),"call-analyzer-callee")) << "\n"; + +@RULES +_xNIL <- _sent @@ diff --git a/.github/workflows/tests/call-analyzer/spec/report.nlp b/.github/workflows/tests/call-analyzer/spec/report.nlp new file mode 100644 index 00000000..87c2cf62 --- /dev/null +++ b/.github/workflows/tests/call-analyzer/spec/report.nlp @@ -0,0 +1,72 @@ +############################################### +# FILE: report.nlp +# SUBJ: Print what callanalyzer did to the shared tree and KB. +# NOTE: What each line proves: +# loaded-* the called analyzer was loaded by the first call +# mine its G() variables are its own +# tree it changed only the sentence nodes it was given: +# colors became _color nodes and * marks each word +# it visited; the top-level "Blue" is untouched +# _color red/green come from its regular dictionary, loaded +# into the shared KB; crimson only from its lazy +# shades-full.dict, looked up on the passed text +# concept it wrote into this KB's concept directly, saw the +# given node as its root, and could not call back +# self an analyzer cannot call itself +# missing an unknown analyzer is an error, not a crash +# +# Expected out.txt: +# loaded-before:0 +# call:1 +# call:1 +# loaded-after:1 +# mine:caller +# tree:_sent _color apples* . +# tree:_sent _color sky* and* _color grass* . +# tree:Blue +# concept:sent root:_sent sawcallerG:0 backcall:0 colors:red; +# concept:sent root:_sent sawcallerG:0 backcall:0 colors:crimson;green; +# self:0 +# missing:0 +############################################### + +@CODE +"out.txt" << "loaded-after:" << str(findana("call-analyzer-callee")) << "\n"; +"out.txt" << "mine:" << G("mine") << "\n"; + +L("n") = pndown(pnroot()); +while (L("n")) { + "out.txt" << "tree:" << pnname(L("n")); + if (pnvar(L("n"),"callee")) + "out.txt" << "*"; + L("c") = pndown(L("n")); + while (L("c")) { + "out.txt" << " " << pnname(L("c")); + if (pnvar(L("c"),"callee")) + "out.txt" << "*"; + L("c") = pnnext(L("c")); + } + "out.txt" << "\n"; + L("n") = pnnext(L("n")); +} + +L("s") = down(G("results")); +while (L("s")) { + "out.txt" + << "concept:" << conceptname(L("s")) + << " root:" << strval(L("s"),"root") + << " sawcallerG:" << str(numval(L("s"),"sawcallerG")) + << " backcall:" << str(numval(L("s"),"backcall")) + << " colors:"; + L("v") = attrvals(findattr(L("s"),"color")); + while (L("v")) { + "out.txt" << getstrval(L("v")) << ";"; + L("v") = nextval(L("v")); + } + "out.txt" << "\n"; + L("s") = next(L("s")); +} + +"out.txt" << "self:" << str(callanalyzer(pnroot(),G("results"),"call-analyzer")) << "\n"; +"out.txt" << "missing:" << str(callanalyzer(pnroot(),G("results"),"no-such-analyzer")) << "\n"; +@@CODE diff --git a/.github/workflows/tests/call-analyzer/spec/sentence.nlp b/.github/workflows/tests/call-analyzer/spec/sentence.nlp new file mode 100644 index 00000000..613c02e2 --- /dev/null +++ b/.github/workflows/tests/call-analyzer/spec/sentence.nlp @@ -0,0 +1,7 @@ +############################################### +# FILE: sentence.nlp +# SUBJ: Group each sentence, so the next pass has a node to hand over. +############################################### + +@RULES +_sent <- _xALPHA _xWILD [star fails=(\.)] \. @@ diff --git a/cs/libconsh/cg.cpp b/cs/libconsh/cg.cpp index 696afa5c..9bbe5620 100644 --- a/cs/libconsh/cg.cpp +++ b/cs/libconsh/cg.cpp @@ -4597,6 +4597,10 @@ bool CG::openFullKBB(const std::string &file) std::_t_cerr << _T("[Lazy-loading words from ") << file << _T(" under \"") << rootName << _T("\"]") << std::endl; + + // A word missed before this file was open may be in it. Only matters when + // files are added mid-run, as callanalyzer() does. // 09/13/26 DD. + fullMissCache_.clear(); return true; } @@ -4625,6 +4629,9 @@ bool CG::openFullDict(const std::string &file) } std::_t_cerr << _T("[Lazy-loading words from ") << file << _T("]") << std::endl; + + // See openFullKBB. // 09/13/26 DD. + fullMissCache_.clear(); return true; } diff --git a/include/Api/lite/Arun.h b/include/Api/lite/Arun.h index 0d1c8e13..33020072 100644 --- a/include/Api/lite/Arun.h +++ b/include/Api/lite/Arun.h @@ -1737,6 +1737,13 @@ class LITE_API Arun static bool findana(Nlppp*,RFASem*); // 05/29/03 AM. static bool findana(Nlppp*,long long); // 07/11/03 AM. + // In callana.cpp. // 09/13/26 DD. + static long long callanalyzer(Nlppp*,NODE*,RFASem*,_TCHAR*); + static long long callanalyzer(Nlppp*,NODE*,RFASem*,RFASem*); + static long long callanalyzer(Nlppp*,RFASem*,RFASem*,_TCHAR*); + static long long callanalyzer(Nlppp*,RFASem*,RFASem*,RFASem*); + static RFASem *callconcept(Nlppp*); + static bool inputrangetofile(Nlppp*,long long,long long,std::_t_ostream*); // 05/29/03 AM. static bool inputrangetofile(Nlppp*,long long,long long,RFASem*); static bool inputrangetofile(Nlppp*,long long,RFASem*,std::_t_ostream*); diff --git a/include/Api/lite/nlpdebug.h b/include/Api/lite/nlpdebug.h index 4cc0e257..064cb493 100644 --- a/include/Api/lite/nlpdebug.h +++ b/include/Api/lite/nlpdebug.h @@ -76,6 +76,14 @@ class LITE_API NlpDebug static void arm(); static void disarm(); + // Hold the pause points off while the engine runs something other than the + // analyzer being debugged, including across the arm() of a nested analysis. + // callanalyzer() needs this: the called analyzer's pass numbers and lines + // would otherwise be reported against the caller's files. Calls nest. + // suspend() returns whether the points were armed, for the matching resume(). + static bool suspend(); + static void resume(bool wasArmed); + // True once a client is attached. Read directly by the inline hooks below; // public so they can stay inline. static bool active_; diff --git a/lite/callana.cpp b/lite/callana.cpp new file mode 100644 index 00000000..fd531da8 --- /dev/null +++ b/lite/callana.cpp @@ -0,0 +1,558 @@ +/******************************************************************************* +Copyright (c) 2026 by Text Analysis International, Inc. +All rights reserved. +*******************************************************************************/ +// callana.cpp +// +// callanalyzer() and callconcept(): one analyzer's passes run inside another's. +// +// WHAT IT DOES. callanalyzer(pnode, concept, "name") runs the passes of the +// named analyzer inside the analysis already in progress. The called analyzer +// gets no text or tree of its own. Its passes work on the subtree under pnode +// in the caller's parse tree, and on the caller's KB, where callconcept() gives +// them the concept they were handed to put things in. Whatever they change is +// there for the caller as soon as the call returns. +// +// WHAT IS LOADED ONCE. The first call builds the analyzer's passes (its rules +// and @DECL functions) and reads its kb/user .kbb and .dict files into the +// caller's KB. Its lazily loaded *full.kbb and *full.dict files are registered +// with that KB. The analyzer then stays in the VTRun registry, so no later call +// reads anything again. Its .kb files are not read: they are a whole saved KB, +// hierarchy and all, and reading one into a KB that already has a hierarchy +// adds its attribute values a second time. +// +// WHAT RUNS ON EACH CALL. The passes, in order, on the subtree, with these +// differences from running on a text of its own: +// - tokenizer passes are skipped, because the tree already exists; +// - a dicttok or dicttokz pass looks up the subtree's words instead, +// including in the lazy *full files, which only load a word once it is +// seen; +// - G() variables start empty and are discarded afterwards; +// - G("$apppath") is the called analyzer's folder; +// - no per-pass .tree dumps, which are named by pass number and would +// overwrite the caller's. +// +// WHAT IS REFUSED. An analyzer cannot call itself, directly or around a cycle +// (A calls B calls A). Its passes are a single set of objects, and they hold +// state while they run. + +#include "StdAfx.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "machine.h" +#include "lite/lite.h" +#include "lite/global.h" +#include "u_out.h" +#include "consh/libconsh.h" +#include "consh/cg.h" +#include "htab.h" +#include "kb.h" +#include "prim/libprim.h" +#include "lite/mach.h" +#include "dlist.h" +#include "node.h" +#include "tree.h" +#include "lite/Auser.h" +#include "lite/iarg.h" +#include "inline.h" +#include "str.h" +#include "chars.h" +#include "io.h" +#include "pn.h" +#include "ana.h" +#include "parse.h" +#include "Eana.h" +#include "lite/nlp.h" +#include "lite/nlppp.h" +#include "rfasem.h" +#include "arg.h" +#include "ipair.h" +#include "seqn.h" +#include "algo.h" +#include "dicttok.h" +#include "lite/vtrun.h" +#include "lite/nlpdebug.h" +#include "lite/Arun.h" +#include "fn.h" + +// What callconcept() returns when the analyzer is not being called: somewhere +// to put results while developing it on its own. +static _TCHAR STANDALONE_CONCEPT[] = _T("callanalyzer"); + +// One callanalyzer() in progress. +struct Call + { + Ana *caller; // The analyzer that made the call. + Ana *callee; // The analyzer whose passes are running. + CONCEPT *con; // What callconcept() returns to them. + }; + +// Calls in progress, outermost first. +static std::vector calls; + +// Each loaded analyzer paired with a KB its files have been read into. +static std::set > loadedInto; + +// Paths handed to the analyzers loaded here. The engine passes these around as +// bare pointers, so keep them for the life of the process rather than rely on +// every holder having made a copy. A list, so the strings never move. +static std::list anaPaths; + +static bool callError(Parse *parse, const std::string &msg) +{ +_stprintf(Errbuf, _T("[callanalyzer: %.*s]"), (int)(MAXSTR - 20), msg.c_str()); +parse->errOut(true); +return false; +} + +static bool isAbsolute(const std::string &path) +{ +if (path.empty()) + return false; +if (path[0] == '/' || path[0] == '\\') + return true; +return path.size() > 1 && path[1] == ':'; +} + +static std::string trimSlashes(std::string path) +{ +while (path.size() > 1 && (path.back() == '/' || path.back() == '\\')) + path.pop_back(); +return path; +} + +static std::string baseName(const std::string &path) +{ +size_t slash = path.find_last_of("/\\"); +return slash == std::string::npos ? path : path.substr(slash + 1); +} + +static std::string dirName(const std::string &path) +{ +size_t slash = path.find_last_of("/\\"); +return slash == std::string::npos ? std::string(".") : path.substr(0, slash); +} + +static _TCHAR *keepPath(const std::string &path) +{ +anaPaths.push_back(path); +return (_TCHAR *) anaPaths.back().c_str(); +} + +// Passes that build the parse tree from the text. +static bool isTokenizer(_TCHAR *algo) +{ +return algo + && (!strcmp_i(algo, _T("tokenize")) + || !strcmp_i(algo, _T("tok")) + || !strcmp_i(algo, _T("token")) + || !strcmp_i(algo, _T("cmltokenize")) + || !strcmp_i(algo, _T("cmltok")) + || !strcmp_i(algo, _T("chartok")) + || !strcmp_i(algo, _T("lines")) + || !strcmp_i(algo, _T("line"))); +} + +static bool isDictTok(_TCHAR *algo) +{ +return algo + && (!strcmp_i(algo, _T("dicttok")) + || !strcmp_i(algo, _T("dicttokz"))); +} + +/******************************************** +* FN: FINDCALLEE +* SUBJ: Find the named analyzer, building its passes on first use. +* NOTE: A name already in the registry is used as is -- that is what +* makes the second call free. Otherwise an absolute path names +* the analyzer folder, and anything else is looked for beside the +* calling analyzer's folder, which is how analyzers sit in a +* VisualText workspace. +********************************************/ + +static NLP *findCallee(Parse *parse, const std::string &given) +{ +VTRun *vtrun = parse->getNLP()->getVTRun(); + +std::string path = trimSlashes(given); +std::string name = baseName(path); +NLP *nlp = vtrun->findAna((_TCHAR *) name.c_str()); +if (nlp) + return nlp; + +std::string anadir = isAbsolute(path) + ? path + : dirName(trimSlashes(parse->getAppdir())) + DIR_STR + path; +std::string seqfile = anadir + DIR_STR + "spec" + DIR_STR + "analyzer.seq"; +if (!std::ifstream(seqfile.c_str()).good()) + { + callError(parse, "No analyzer named " + given + ": there is no " + seqfile + "."); + return 0; + } + +_TCHAR *dir = keepPath(anadir); +bool silent = parse->getEana()->getFsilent(); +clock_t start = clock(); + +// The same steps as NLP_ENGINE::init, which cannot be used from inside a run: +// it resets the engine's notion of the current analyzer. The analyzer gets a +// KB object because an NLP expects one, but it is never read -- its passes run +// on the caller's KB. +nlp = vtrun->makeNLP(dir, (_TCHAR *) name.c_str(), false, silent, false); +if (!nlp) + { + callError(parse, "Couldn't create analyzer " + name + "."); + return 0; + } +if (!vtrun->makeCG(dir, false, nlp, true)) + { + vtrun->rmAna(nlp); + vtrun->deleteNLP(nlp); + callError(parse, "Couldn't make a knowledge base object for " + name + "."); + return 0; + } +if (!nlp->make_analyzer(keepPath(seqfile), dir, false, silent, 0, false, false)) + { + vtrun->rmAna(nlp); + vtrun->deleteNLP(nlp); + callError(parse, "Couldn't build analyzer " + name + ". See its logs" + + DIR_STR + "make_ana.log."); + return 0; + } + +if (!silent) + std::_t_cerr << _T("[callanalyzer: loaded ") << name.c_str() << _T(": ") + << (double)(clock() - start) / CLOCKS_PER_SEC << _T(" sec]") << std::endl; +return nlp; +} + +// The called analyzer's kb/user files of one kind, as CG::openKBB and +// CG::openDict choose them: a consolidated all. if there is one, else +// every file with that extension. +static std::vector kbFiles( + const std::filesystem::path &kbdir, const std::string &ext) +{ +std::vector files; +std::error_code ec; +std::filesystem::path all = kbdir / ("all" + ext); +if (std::filesystem::exists(all, ec)) + { + files.push_back(all); + return files; + } +for (const auto &entry : std::filesystem::directory_iterator(kbdir, ec)) + if (entry.path().extension().string() == ext) + files.push_back(entry.path()); +std::sort(files.begin(), files.end()); +return files; +} + +// Read the called analyzer's dictionaries and kbb files into the KB it is +// run with, once for each such KB. Lazy *full files are registered, not read. +static void loadKnowledge(NLP *callee, Ana *ana, CG *cg) +{ +if (!loadedInto.insert(std::make_pair(callee, cg)).second) + return; + +std::error_code ec; +std::filesystem::path kbdir = std::filesystem::path(ana->getAppdir()) / "kb" / "user"; +if (!std::filesystem::is_directory(kbdir, ec)) + return; + +// kbb files first, as CG::readKB reads them, so dictionaries can pair with them. +std::vector kbbs = kbFiles(kbdir, ".kbb"); +std::vector dicts = kbFiles(kbdir, ".dict"); +for (const auto &file : kbbs) + { + if (cg->stemEndsWithFull(file.stem().string())) + cg->openFullKBB(file.string()); + else + cg->readKBB(file.string()); + } +for (const auto &file : dicts) + { + if (cg->stemEndsWithFull(file.stem().string())) + cg->openFullDict(file.string()); + else + cg->readDict(file.string(), kbbs); + } +} + +// Run a loaded analyzer's passes on the subtree under node. +static bool runCallee(Parse *parse, NLP *callee, Node *node, CONCEPT *con) +{ +Ana *ana = (Ana *) callee->getAna(); +if (!ana || !ana->getSeq()) + return callError(parse, std::string(callee->getName()) + " has no passes."); + +Ana *caller = parse->getAna(); +CG *cg = caller->getCG(); +loadKnowledge(callee, ana, cg); + +// Passes find the KB, and their @DECL functions, through the Ana the parse is +// running, so the called analyzer's Ana is put in and pointed at this KB. +CG *ownCG = ana->getCG(); +ana->setCG(cg); + +TREE *tree = parse->getTree(); +Delt *seq = parse->getSeq(); +long currpass = parse->getCurrpass(); +long rulepass = parse->getRulepass(); +Dlist *vars = parse->getVars(); +std::string appdir = parse->getAppdir(); + +Tree subtree(node); // Does not own the nodes. +parse->setTree(&subtree); +parse->setAna(ana); +parse->setVars(0); +parse->setAppdir(ana->getAppdir()); + +Call call = { caller, ana, con }; +calls.push_back(call); + +bool ok = true; +long num = 0; +for (Delt *step = ana->getSeq(); step && ok; step = step->Right()) + { + ++num; + Seqn *pass = step->getData(); + Algo *algo = pass->getAlgo(); + _TCHAR *algoname = pass->getAlgoname(); + if (!pass->getActive() || !algo || isTokenizer(algoname)) + continue; + + // What Parse::stepExecute and iniPass set, minus the dump files. + parse->setSeq(step); + parse->setCurrpass(num); + parse->setRulepass(num); + if (isDictTok(algoname)) + ((DICTTok *) algo)->applyToSubtree(parse, node); + else + ok = algo->Execute(parse, pass); + } + +calls.pop_back(); + +if (parse->getVars()) + Dlist::DeleteDlistAndData(parse->getVars()); +parse->setVars(vars); +parse->setAppdir((_TCHAR *) appdir.c_str()); +parse->setAna(caller); +parse->setTree(tree); +parse->setSeq(seq); +parse->setCurrpass(currpass); +parse->setRulepass(rulepass); +ana->setCG(ownCG); + +if (!ok) + return callError(parse, std::string("A pass of ") + callee->getName() + " failed."); +return true; +} + +static bool callAnalyzer(Parse *parse, Node *node, CONCEPT *con, _TCHAR *given) +{ +if (!node || !con) + return callError(parse, "Given no parse node or no concept."); +if (!given || !*given) + return callError(parse, "Given no analyzer name."); + +// Nothing the called analyzer does -- building from its rule files, or running +// its passes -- is the analyzer being debugged. Its pass numbers and lines +// would be reported against the caller's files. +bool wasArmed = NlpDebug::suspend(); + +bool ok = false; +NLP *callee = findCallee(parse, given); +if (callee) + { + Ana *ana = (Ana *) callee->getAna(); + bool running = (ana == parse->getAna()); + for (const Call &call : calls) + if (call.caller == ana || call.callee == ana) + running = true; + if (running) + callError(parse, std::string(callee->getName()) + " is already running." + + " An analyzer cannot call itself, directly or through another analyzer."); + else + ok = runCallee(parse, callee, node, con); + } + +NlpDebug::resume(wasArmed); +return ok; +} + +static CONCEPT *callConcept(Parse *parse) +{ +if (!calls.empty()) + return calls.back().con; +CG *cg = parse->getAna()->getCG(); +CONCEPT *root = cg->findRoot(); +return root ? cg->getConcept(root, STANDALONE_CONCEPT) : 0; +} + + +/******************************************** +* FN: FNCALLANALYZER +* CR: 09/13/26 DD. +* SUBJ: Run another analyzer's passes on part of this parse tree. +* RET: True if ok, else false. +* UP - 1 if the analyzer ran, else 0. +* FORMS: callanalyzer(pnode, concept, analyzer_str) +* NOTE: The analyzer works on the subtree under pnode and on this KB, +* and callconcept() gives it the concept. It is loaded on first use +* and stays loaded. +********************************************/ + +bool Fn::fnCallanalyzer( + Delt *args, + Nlppp *nlppp, + /*UP*/ + RFASem* &sem + ) +{ +sem = 0; +Parse *parse = nlppp->parse_; + +RFASem *node_sem = 0; +RFASem *con_sem = 0; +_TCHAR *name = 0; + +if (!Arg::sem1(_T("callanalyzer"),nlppp,(DELTS*&)args,node_sem)) + return false; +if (!Arg::sem1(_T("callanalyzer"),nlppp,(DELTS*&)args,con_sem)) + return false; +if (!Arg::str1(_T("callanalyzer"),(DELTS*&)args,name)) + return false; +if (!Arg::done((DELTS*)args,_T("callanalyzer"),parse)) + return false; + +Node *node = (node_sem && node_sem->getType() == RSNODE) + ? node_sem->getNode() : 0; +CONCEPT *con = (con_sem && con_sem->getType() == RS_KBCONCEPT) + ? con_sem->getKBconcept() : 0; + +sem = new RFASem(callAnalyzer(parse, node, con, name) ? 1LL : 0LL); +return true; +} + + +/******************************************** +* FN: FNCALLCONCEPT +* CR: 09/13/26 DD. +* SUBJ: The concept an analyzer was handed by callanalyzer(). +* RET: True if ok, else false. +* UP - the concept. +* FORMS: callconcept() +* NOTE: Run on its own, the analyzer gets the concept "callanalyzer" +* under the KB root instead, so it can be developed without a +* caller. +********************************************/ + +bool Fn::fnCallconcept( + Delt *args, + Nlppp *nlppp, + /*UP*/ + RFASem* &sem + ) +{ +sem = 0; +Parse *parse = nlppp->parse_; +if (!Arg::done((DELTS*)args,_T("callconcept"),parse)) + return false; + +CONCEPT *con = callConcept(parse); +if (con) + sem = new RFASem(con, RS_KBCONCEPT, parse->getAna()->getCG()); +return true; +} + + +/******************************************** +* FN: CALLANALYZER +* CR: 09/13/26 DD. +* SUBJ: Compiled-analyzer form of callanalyzer(). +********************************************/ + +long long Arun::callanalyzer( + Nlppp *nlppp, + NODE *node, + RFASem *con_sem, + _TCHAR *name + ) +{ +CONCEPT *con = 0; +if (con_sem) + { + if (con_sem->getType() == RS_KBCONCEPT) + con = con_sem->getKBconcept(); + delete con_sem; + } +return callAnalyzer(nlppp->parse_, (Node *) node, con, name) ? 1 : 0; +} + +// VARIANT. +long long Arun::callanalyzer( + Nlppp *nlppp, + NODE *node, + RFASem *con_sem, + RFASem *name_sem + ) +{ +_TCHAR *name = name_sem ? sem_to_str(name_sem) : 0; +long long ok = callanalyzer(nlppp, node, con_sem, name); +if (name_sem) + delete name_sem; +return ok; +} + +// VARIANT. +long long Arun::callanalyzer( + Nlppp *nlppp, + RFASem *node_sem, + RFASem *con_sem, + _TCHAR *name + ) +{ +NODE *node = node_sem ? node_sem->sem_to_node() : 0; +if (node_sem) + delete node_sem; +return callanalyzer(nlppp, node, con_sem, name); +} + +// VARIANT. +long long Arun::callanalyzer( + Nlppp *nlppp, + RFASem *node_sem, + RFASem *con_sem, + RFASem *name_sem + ) +{ +NODE *node = node_sem ? node_sem->sem_to_node() : 0; +if (node_sem) + delete node_sem; +return callanalyzer(nlppp, node, con_sem, name_sem); +} + + +/******************************************** +* FN: CALLCONCEPT +* CR: 09/13/26 DD. +* SUBJ: Compiled-analyzer form of callconcept(). +********************************************/ + +RFASem *Arun::callconcept( + Nlppp *nlppp + ) +{ +Parse *parse = nlppp->parse_; +CONCEPT *con = callConcept(parse); +return con ? new RFASem(con, RS_KBCONCEPT, parse->getAna()->getCG()) : 0; +} diff --git a/lite/dicttok.cpp b/lite/dicttok.cpp index d0419395..59eddf67 100644 --- a/lite/dicttok.cpp +++ b/lite/dicttok.cpp @@ -336,6 +336,60 @@ bool DICTTok::ApplyDictFiles() { return true; } +/******************************************** +* FN: APPLYTOSUBTREE +* CR: 09/13/26 DD. +* SUBJ: Run this pass's dictionary step on part of an existing tree. +* NOTE: For an analyzer run by callanalyzer(), which works on a node of +* its caller's tree and must not rebuild it. Every token under top +* is looked up -- lazily loaded *full dictionaries included -- and +* given its dictionary attributes, then multi-word dictionary +* phrases are matched among top's children. +********************************************/ + +bool DICTTok::applyToSubtree(Parse *parse, Node *top) +{ +if (!parse || !top) + return false; + +parse_ = parse; +cg_ = parse->getAna()->getCG(); +htab_ = parse->htab_; +Tree subtree(top); // Does not own the nodes. +tree_ = &subtree; +root_ = top; + +lookupTokens(top->Down()); +ApplyDictFiles(); + +tree_ = 0; +root_ = 0; +return true; +} + +// Give every token in a list of nodes, and beneath them, its dictionary +// attributes. +void DICTTok::lookupTokens(Node *node) +{ +_TCHAR buf[PATHSIZ]; +for (; node; node = node->Right()) + { + Pn *pn = node->getData(); + if (pn->getType() == PNNODE) + { + lookupTokens(node->Down()); + continue; + } + _TCHAR *name = pn->getName(); + if (pn->getType() == PNWHITE || !name || !*name) + continue; + CONCEPT *con = cg_->findWordConcept(name); + if (!con) + con = cg_->findWordConcept(str_to_lower(name, buf)); + findAttrs(node, con, name, false); + } +} + Node* DICTTok::MatchLongest(CONCEPT *con, Node *parentN, CONCEPT **end, int &length, int level) { _TCHAR conName[MAXSTR]; CONCEPT *next = con; diff --git a/lite/dicttok.h b/lite/dicttok.h index b31a650d..af65862a 100644 --- a/lite/dicttok.h +++ b/lite/dicttok.h @@ -51,6 +51,8 @@ class DICTTok : public Algo bool Execute(Parse *, Seqn *); // Perform the tokenization. bool Tokenize(Parse *); // Perform the tokenization. bool ApplyDictFiles(); + bool applyToSubtree(Parse *, Node *); // For callanalyzer(). // 09/13/26 DD. + void lookupTokens(Node *); // 09/13/26 DD. Node* MatchLongest(CONCEPT *con, Node *parentN, CONCEPT **end, int &length, int level); bool copyAttrsToSuggested(Pn *pn, Node *suggestedPn, Node *endNode); bool checkCase(_TCHAR *name, Node *node, bool &lower, bool &cap, bool &upper); diff --git a/lite/fn.cpp b/lite/fn.cpp index 5564cf94..0cd49dbb 100644 --- a/lite/fn.cpp +++ b/lite/fn.cpp @@ -455,6 +455,10 @@ switch (fnid) // 12/21/01 AM. return fnJsonwrite(args,nlppp,/*UP*/sem); // 08/04/26 DD. case FNjsonparse: return fnJsonparse(args,nlppp,/*UP*/sem); // 08/04/26 DD. + case FNcallanalyzer: // In callana.cpp. + return fnCallanalyzer(args,nlppp,/*UP*/sem); // 09/13/26 DD. + case FNcallconcept: // In callana.cpp. + return fnCallconcept(args,nlppp,/*UP*/sem); // 09/13/26 DD. case FNlogten: return fnLogten(args,nlppp,/*UP*/sem); // 04/29/04 AM. case FNrandomint: diff --git a/lite/fn.h b/lite/fn.h index 9839cff0..1b320151 100644 --- a/lite/fn.h +++ b/lite/fn.h @@ -979,6 +979,8 @@ static bool fnStruniquechars( static bool fnPush(Delt*,Nlppp*,RFASem*&); // 08/03/26 DD. static bool fnJsonwrite(Delt*,Nlppp*,RFASem*&); // 08/04/26 DD. static bool fnJsonparse(Delt*,Nlppp*,RFASem*&); // 08/04/26 DD. + static bool fnCallanalyzer(Delt*,Nlppp*,RFASem*&); // 09/13/26 DD. + static bool fnCallconcept(Delt*,Nlppp*,RFASem*&); // 09/13/26 DD. static bool fnStriscaps(Delt*,Nlppp*,RFASem*&); static bool fnStrisupper(Delt*,Nlppp*,RFASem*&); // 11/20/01 AM. static bool fnStrislower(Delt*,Nlppp*,RFASem*&); // 11/20/01 AM. diff --git a/lite/func_defs.h b/lite/func_defs.h index 6f25784f..312e620c 100644 --- a/lite/func_defs.h +++ b/lite/func_defs.h @@ -397,6 +397,10 @@ enum funcDef FNjsonwrite, FNjsonparse, + // Analyzer functions. // 09/13/26 DD. + FNcallanalyzer, + FNcallconcept, + FNXXYYZZ }; #endif diff --git a/lite/funcs.h b/lite/funcs.h index 5edeed2b..abd5cbf4 100644 --- a/lite/funcs.h +++ b/lite/funcs.h @@ -386,6 +386,9 @@ _T("push"), // JSON functions. // 08/04/26 DD. _T("jsonwrite"), _T("jsonparse"), +// Analyzer functions. // 09/13/26 DD. +_T("callanalyzer"), +_T("callconcept"), 0 }; #endif // NLP_LITE_FUNCS_H diff --git a/lite/nlpdebug.cpp b/lite/nlpdebug.cpp index 538d5263..b6f93a99 100644 --- a/lite/nlpdebug.cpp +++ b/lite/nlpdebug.cpp @@ -1124,8 +1124,12 @@ void NlpDebug::ruleFailed_(Nlppp *nlppp) stopAndServe(NLPDEBUG_RULE_FAILED); } +// How many suspend() calls are in effect. arm() does nothing while nonzero. +static int g_suspended = 0; + void NlpDebug::arm() { + if (g_suspended) return; g_armed = true; } @@ -1134,6 +1138,20 @@ void NlpDebug::disarm() g_armed = false; } +bool NlpDebug::suspend() +{ + bool wasArmed = g_armed; + ++g_suspended; + g_armed = false; + return wasArmed; +} + +void NlpDebug::resume(bool wasArmed) +{ + if (g_suspended > 0 && --g_suspended == 0) + g_armed = wasArmed; +} + void NlpDebug::statement_(Nlppp *nlppp, long line) { if (!g_armed) return; diff --git a/nlp/main.cpp b/nlp/main.cpp index 403d4c8a..615bbac4 100644 --- a/nlp/main.cpp +++ b/nlp/main.cpp @@ -15,7 +15,7 @@ All rights reserved. #include "lite/nlp_engine.h" #include "version.h" -#define NLP_ENGINE_VERSION "4.0.0" +#define NLP_ENGINE_VERSION "4.1.0" bool cmdReadArgs(int, _TCHAR *argv[], _TCHAR *&, _TCHAR *&, _TCHAR *&, _TCHAR *&, bool &, bool &, bool &, bool &, bool &, bool &, int &); void cmdHelpargs(_TCHAR *);