mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-27 12:16:59 +00:00
9c92bd1b81
svn-id: r49373
840 lines
23 KiB
Plaintext
840 lines
23 KiB
Plaintext
%{
|
|
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* $URL$
|
|
* $Id$
|
|
*
|
|
*/
|
|
|
|
#include "sci/engine/state.h"
|
|
|
|
|
|
// Bison generates an empty switch statement that gives a warning in MSVC.
|
|
// This disables that warning.
|
|
#ifdef _MSC_VER
|
|
#pragma warning(disable:4065)
|
|
#endif
|
|
|
|
|
|
namespace Sci {
|
|
|
|
#define SAID_BRANCH_NULL 0
|
|
|
|
#define MAX_SAID_TOKENS 128
|
|
|
|
// Maximum number of words to be expected in a parsed sentence
|
|
#define AUGMENT_MAX_WORDS 64
|
|
|
|
|
|
#define ANYWORD 0xfff
|
|
|
|
#define WORD_TYPE_BASE 0x141
|
|
#define WORD_TYPE_REF 0x144
|
|
#define WORD_TYPE_SYNTACTIC_SUGAR 0x145
|
|
|
|
#define AUGMENT_SENTENCE_PART_BRACKETS 0x152
|
|
|
|
// Minor numbers
|
|
#define AUGMENT_SENTENCE_MINOR_MATCH_PHRASE 0x14c
|
|
#define AUGMENT_SENTENCE_MINOR_MATCH_WORD 0x153
|
|
#define AUGMENT_SENTENCE_MINOR_RECURSE 0x144
|
|
#define AUGMENT_SENTENCE_MINOR_PARENTHESES 0x14f
|
|
|
|
|
|
#undef YYDEBUG /*1*/
|
|
//#define SAID_DEBUG*/
|
|
//#define SCI_DEBUG_PARSE_TREE_AUGMENTATION // uncomment to debug parse tree augmentation
|
|
|
|
|
|
#ifdef SCI_DEBUG_PARSE_TREE_AUGMENTATION
|
|
#define scidprintf printf
|
|
#else
|
|
void print_nothing(...) { }
|
|
#define scidprintf print_nothing
|
|
#endif
|
|
|
|
|
|
static char *said_parse_error;
|
|
|
|
static int said_token;
|
|
static int said_tokens_nr;
|
|
static int said_tokens[MAX_SAID_TOKENS];
|
|
static int said_blessed; // increminated by said_top_branch
|
|
|
|
static int said_tree_pos; // Set to 0 if we're out of space
|
|
#define SAID_TREE_START 4; // Reserve space for the 4 top nodes
|
|
|
|
#define VALUE_IGNORE -424242
|
|
|
|
static parse_tree_node_t said_tree[VOCAB_TREE_NODES];
|
|
|
|
typedef int wgroup_t;
|
|
typedef int tree_t;
|
|
typedef int said_spec_t;
|
|
|
|
static tree_t said_aug_branch(int, int, tree_t, tree_t);
|
|
static tree_t said_attach_branch(tree_t, tree_t);
|
|
/*
|
|
static tree_t said_wgroup_branch(wgroup_t);
|
|
*/
|
|
static said_spec_t said_top_branch(tree_t);
|
|
static tree_t said_paren(tree_t, tree_t);
|
|
static tree_t said_value(int, tree_t);
|
|
static tree_t said_terminal(int);
|
|
|
|
static int yylex();
|
|
|
|
static int yyerror(const char *s) {
|
|
said_parse_error = strdup(s);
|
|
return 1; /* Abort */
|
|
}
|
|
|
|
%}
|
|
|
|
%token WGROUP /* Word group */
|
|
%token YY_COMMA /* 0xf0 */
|
|
%token YY_AMP /* 0xf1 */
|
|
%token YY_SLASH /* 0xf2 */
|
|
%token YY_PARENO /* 0xf3 */
|
|
%token YY_PARENC /* 0xf4 */
|
|
%token YY_BRACKETSO /* 0xf5 */
|
|
%token YY_BRACKETSC /* 0xf6 */
|
|
%token YY_HASH /* 0xf7 */
|
|
%token YY_LT /* 0xf8 */
|
|
%token YY_GT /* 0xf9 */
|
|
%token YY_BRACKETSO_LT /* special token used to imitate LR(2) behaviour */
|
|
%token YY_BRACKETSO_SLASH /* special token used to imitate LR(2) behaviour */
|
|
%token YY_LT_BRACKETSO /* special token used to imitate LR(2) behaviour */
|
|
%token YY_LT_PARENO /* special token used to imitate LR(2) behaviour */
|
|
|
|
%%
|
|
|
|
saidspec : leftspec optcont
|
|
{ $$ = said_top_branch(said_attach_branch($1, $2)); }
|
|
| leftspec midspec optcont
|
|
{ $$ = said_top_branch(said_attach_branch($1, said_attach_branch($2, $3))); }
|
|
| leftspec midspec rightspec optcont
|
|
{ $$ = said_top_branch(said_attach_branch($1, said_attach_branch($2, said_attach_branch($3, $4)))); }
|
|
;
|
|
|
|
|
|
optcont : /* empty */
|
|
{ $$ = SAID_BRANCH_NULL; }
|
|
| YY_GT
|
|
{ $$ = said_paren(said_value(0x14b, said_value(0xf900, said_terminal(0xf900))), SAID_BRANCH_NULL); }
|
|
;
|
|
|
|
|
|
|
|
leftspec : /* empty */
|
|
{ $$ = SAID_BRANCH_NULL; }
|
|
| expr
|
|
{ $$ = said_paren(said_value(0x141, said_value(0x149, $1)), SAID_BRANCH_NULL); }
|
|
;
|
|
|
|
|
|
|
|
midspec : YY_SLASH expr
|
|
{ $$ = said_aug_branch(0x142, 0x14a, $2, SAID_BRANCH_NULL); }
|
|
| YY_BRACKETSO_SLASH YY_SLASH expr YY_BRACKETSC
|
|
{ $$ = said_aug_branch(0x152, 0x142, said_aug_branch(0x142, 0x14a, $3, SAID_BRANCH_NULL), SAID_BRANCH_NULL); }
|
|
| YY_SLASH
|
|
{ $$ = SAID_BRANCH_NULL; }
|
|
;
|
|
|
|
|
|
|
|
rightspec : YY_SLASH expr
|
|
{ $$ = said_aug_branch(0x143, 0x14a, $2, SAID_BRANCH_NULL); }
|
|
| YY_BRACKETSO_SLASH YY_SLASH expr YY_BRACKETSC
|
|
{ $$ = said_aug_branch(0x152, 0x143, said_aug_branch(0x143, 0x14a, $3, SAID_BRANCH_NULL), SAID_BRANCH_NULL); }
|
|
| YY_SLASH
|
|
{ $$ = SAID_BRANCH_NULL; }
|
|
;
|
|
|
|
|
|
word : WGROUP
|
|
{ $$ = said_paren(said_value(0x141, said_value(0x153, said_terminal($1))), SAID_BRANCH_NULL); }
|
|
;
|
|
|
|
|
|
cwordset : wordset
|
|
{ $$ = said_aug_branch(0x141, 0x14f, $1, SAID_BRANCH_NULL); }
|
|
| YY_BRACKETSO wordset YY_BRACKETSC
|
|
{ $$ = said_aug_branch(0x141, 0x14f, said_aug_branch(0x152, 0x14c, said_aug_branch(0x141, 0x14f, $2, SAID_BRANCH_NULL), SAID_BRANCH_NULL), SAID_BRANCH_NULL); }
|
|
;
|
|
|
|
|
|
wordset : word
|
|
{ $$ = $1; }
|
|
| YY_PARENO expr YY_PARENC
|
|
{ $$ = said_aug_branch(0x141, 0x14c, $2, SAID_BRANCH_NULL); }
|
|
| wordset YY_COMMA wordset
|
|
{ $$ = said_attach_branch($1, $3); }
|
|
| wordset YY_BRACKETSO_LT wordrefset YY_BRACKETSC
|
|
{ $$ = said_attach_branch($1, $3); }
|
|
| wordset YY_COMMA YY_BRACKETSO wordset YY_BRACKETSC
|
|
{ $$ = said_attach_branch($1, $3); }
|
|
;
|
|
|
|
|
|
expr : cwordset cwordrefset
|
|
{ $$ = said_attach_branch($1, $2); }
|
|
| cwordset
|
|
{ $$ = $1; }
|
|
| cwordrefset
|
|
{ $$ = $1; }
|
|
;
|
|
|
|
|
|
cwordrefset : wordrefset
|
|
{ $$ = $1; }
|
|
| YY_BRACKETSO_LT wordrefset YY_BRACKETSC
|
|
{ $$ = said_aug_branch(0x152, 0x144, $2, SAID_BRANCH_NULL); }
|
|
| wordrefset YY_BRACKETSO_LT wordrefset YY_BRACKETSC
|
|
{ $$ = said_attach_branch($1, said_aug_branch(0x152, 0x144, $3, SAID_BRANCH_NULL)); }
|
|
;
|
|
|
|
|
|
wordrefset : YY_LT word recref
|
|
{ $$ = said_aug_branch(0x144, 0x14f, $2, $3); }
|
|
| YY_LT_PARENO YY_PARENO expr YY_PARENC
|
|
{ $$ = said_aug_branch(0x144, 0x14f, said_aug_branch(0x141, 0x144, $2, SAID_BRANCH_NULL), SAID_BRANCH_NULL); }
|
|
| YY_LT wordset
|
|
{ $$ = said_aug_branch(0x144, 0x14f, $2, SAID_BRANCH_NULL); }
|
|
| YY_LT_BRACKETSO YY_BRACKETSO wordset YY_BRACKETSC
|
|
{ $$ = said_aug_branch(0x152, 0x144, said_aug_branch(0x144, 0x14f, $3, SAID_BRANCH_NULL), SAID_BRANCH_NULL); }
|
|
;
|
|
|
|
|
|
recref : YY_LT wordset recref
|
|
{ $$ = said_aug_branch(0x141, 0x144, said_aug_branch(0x144, 0x14f, $2, SAID_BRANCH_NULL), $3); }
|
|
| YY_LT wordset
|
|
{ $$ = said_aug_branch(0x141, 0x144, said_aug_branch(0x144, 0x14f, $2, SAID_BRANCH_NULL), SAID_BRANCH_NULL); }
|
|
| YY_LT_PARENO YY_PARENO expr YY_PARENC
|
|
{ $$ = said_aug_branch(0x141, 0x14c, $2, SAID_BRANCH_NULL); }
|
|
;
|
|
|
|
%%
|
|
|
|
int parse_yy_token_lookup[] = {YY_COMMA, YY_AMP, YY_SLASH, YY_PARENO, YY_PARENC, YY_BRACKETSO, YY_BRACKETSC, YY_HASH, YY_LT, YY_GT};
|
|
|
|
static int yylex() {
|
|
int retval = said_tokens[said_token++];
|
|
|
|
if (retval < SAID_LONG(SAID_FIRST)) {
|
|
yylval = retval;
|
|
retval = WGROUP;
|
|
} else {
|
|
retval >>= 8;
|
|
|
|
if (retval == SAID_TERM)
|
|
retval = 0;
|
|
else {
|
|
assert(retval >= SAID_FIRST);
|
|
retval = parse_yy_token_lookup[retval - SAID_FIRST];
|
|
if (retval == YY_BRACKETSO) {
|
|
if ((said_tokens[said_token] >> 8) == SAID_LT)
|
|
retval = YY_BRACKETSO_LT;
|
|
else
|
|
if ((said_tokens[said_token] >> 8) == SAID_SLASH)
|
|
retval = YY_BRACKETSO_SLASH;
|
|
} else if (retval == YY_LT && (said_tokens[said_token] >> 8) == SAID_BRACKO) {
|
|
retval = YY_LT_BRACKETSO;
|
|
} else if (retval == YY_LT && (said_tokens[said_token] >> 8) == SAID_PARENO) {
|
|
retval = YY_LT_PARENO;
|
|
}
|
|
}
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
static int said_next_node() {
|
|
return ((said_tree_pos == 0) || (said_tree_pos >= VOCAB_TREE_NODES)) ? said_tree_pos = 0 : said_tree_pos++;
|
|
}
|
|
|
|
#define SAID_NEXT_NODE said_next_node()
|
|
|
|
static int said_leaf_node(tree_t pos, int value) {
|
|
said_tree[pos].type = kParseTreeLeafNode;
|
|
|
|
if (value != VALUE_IGNORE)
|
|
said_tree[pos].content.value = value;
|
|
|
|
return pos;
|
|
}
|
|
|
|
static int said_branch_node(tree_t pos, int left, int right) {
|
|
said_tree[pos].type = kParseTreeBranchNode;
|
|
|
|
if (left != VALUE_IGNORE)
|
|
said_tree[pos].content.branches[0] = left;
|
|
|
|
if (right != VALUE_IGNORE)
|
|
said_tree[pos].content.branches[1] = right;
|
|
|
|
return pos;
|
|
}
|
|
|
|
static tree_t said_paren(tree_t t1, tree_t t2) {
|
|
if (t1)
|
|
return said_branch_node(SAID_NEXT_NODE, t1, t2);
|
|
else
|
|
return t2;
|
|
}
|
|
|
|
static tree_t said_value(int val, tree_t t) {
|
|
return said_branch_node(SAID_NEXT_NODE, said_leaf_node(SAID_NEXT_NODE, val), t);
|
|
|
|
}
|
|
|
|
static tree_t said_terminal(int val) {
|
|
return said_leaf_node(SAID_NEXT_NODE, val);
|
|
}
|
|
|
|
static tree_t said_aug_branch(int n1, int n2, tree_t t1, tree_t t2) {
|
|
int retval;
|
|
|
|
retval = said_branch_node(SAID_NEXT_NODE,
|
|
said_branch_node(SAID_NEXT_NODE,
|
|
said_leaf_node(SAID_NEXT_NODE, n1),
|
|
said_branch_node(SAID_NEXT_NODE,
|
|
said_leaf_node(SAID_NEXT_NODE, n2),
|
|
t1)
|
|
),
|
|
t2);
|
|
|
|
#ifdef SAID_DEBUG
|
|
fprintf(stderr, "AUG(0x%x, 0x%x, [%04x], [%04x]) = [%04x]\n", n1, n2, t1, t2, retval);
|
|
#endif
|
|
|
|
return retval;
|
|
}
|
|
|
|
static tree_t said_attach_branch(tree_t base, tree_t attacheant) {
|
|
#ifdef SAID_DEBUG
|
|
fprintf(stderr, "ATT2([%04x], [%04x]) = [%04x]\n", base, attacheant, base);
|
|
#endif
|
|
|
|
if (!attacheant)
|
|
return base;
|
|
if (!base)
|
|
return attacheant;
|
|
|
|
if (!base)
|
|
return 0; // Happens if we're out of space
|
|
|
|
said_branch_node(base, VALUE_IGNORE, attacheant);
|
|
|
|
return base;
|
|
}
|
|
|
|
static said_spec_t said_top_branch(tree_t first) {
|
|
#ifdef SAID_DEBUG
|
|
fprintf(stderr, "TOP([%04x])\n", first);
|
|
#endif
|
|
said_branch_node(0, 1, 2);
|
|
said_leaf_node(1, 0x141); // Magic number #1
|
|
said_branch_node(2, 3, first);
|
|
said_leaf_node(3, 0x13f); // Magic number #2
|
|
|
|
++said_blessed;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int said_parse_spec(byte *spec) {
|
|
int nextitem;
|
|
|
|
said_parse_error = NULL;
|
|
said_token = 0;
|
|
said_tokens_nr = 0;
|
|
said_blessed = 0;
|
|
|
|
said_tree_pos = SAID_TREE_START;
|
|
|
|
do {
|
|
nextitem = *spec++;
|
|
if (nextitem < SAID_FIRST)
|
|
said_tokens[said_tokens_nr++] = nextitem << 8 | *spec++;
|
|
else
|
|
said_tokens[said_tokens_nr++] = SAID_LONG(nextitem);
|
|
|
|
} while ((nextitem != SAID_TERM) && (said_tokens_nr < MAX_SAID_TOKENS));
|
|
|
|
if (nextitem == SAID_TERM)
|
|
yyparse();
|
|
else {
|
|
warning("SAID spec is too long");
|
|
return 1;
|
|
}
|
|
|
|
if (said_parse_error) {
|
|
warning("Error while parsing SAID spec: %s", said_parse_error);
|
|
free(said_parse_error);
|
|
return 1;
|
|
}
|
|
|
|
if (said_tree_pos == 0) {
|
|
warning("Out of tree space while parsing SAID spec");
|
|
return 1;
|
|
}
|
|
|
|
if (said_blessed != 1) {
|
|
warning("Found multiple top branches");
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**********************/
|
|
/**** Augmentation ****/
|
|
/**********************/
|
|
|
|
// primitive functions
|
|
|
|
#define AUG_READ_BRANCH(a, br, p) \
|
|
if (tree[p].type != kParseTreeBranchNode) \
|
|
return 0; \
|
|
a = tree[p].content.branches[br];
|
|
|
|
#define AUG_READ_VALUE(a, p) \
|
|
if (tree[p].type != kParseTreeLeafNode) \
|
|
return 0; \
|
|
a = tree[p].content.value;
|
|
|
|
#define AUG_ASSERT(i) \
|
|
if (!i) return 0;
|
|
|
|
static int aug_get_next_sibling(parse_tree_node_t *tree, int pos, int *first, int *second) {
|
|
// Returns the next sibling relative to the specified position in 'tree',
|
|
// sets *first and *second to its augment node values, returns the new position
|
|
// or 0 if there was no next sibling
|
|
int seek, valpos;
|
|
|
|
AUG_READ_BRANCH(pos, 1, pos);
|
|
AUG_ASSERT(pos);
|
|
AUG_READ_BRANCH(seek, 0, pos);
|
|
AUG_ASSERT(seek);
|
|
|
|
// Now retrieve first value
|
|
AUG_READ_BRANCH(valpos, 0, seek);
|
|
AUG_ASSERT(valpos);
|
|
AUG_READ_VALUE(*first, valpos);
|
|
|
|
// Get second value
|
|
AUG_READ_BRANCH(seek, 1, seek);
|
|
AUG_ASSERT(seek);
|
|
AUG_READ_BRANCH(valpos, 0, seek);
|
|
AUG_ASSERT(valpos);
|
|
AUG_READ_VALUE(*second, valpos);
|
|
|
|
return pos;
|
|
}
|
|
|
|
static int aug_get_wgroup(parse_tree_node_t *tree, int pos) {
|
|
// Returns 0 if pos in tree is not the root of a 3-element list, otherwise
|
|
// it returns the last element (which, in practice, is the word group
|
|
int val;
|
|
|
|
AUG_READ_BRANCH(pos, 0, pos);
|
|
AUG_ASSERT(pos);
|
|
AUG_READ_BRANCH(pos, 1, pos);
|
|
AUG_ASSERT(pos);
|
|
AUG_READ_BRANCH(pos, 1, pos);
|
|
AUG_ASSERT(pos);
|
|
AUG_READ_VALUE(val, pos);
|
|
|
|
return val;
|
|
}
|
|
|
|
static int aug_get_base_node(parse_tree_node_t *tree) {
|
|
int startpos = 0;
|
|
AUG_READ_BRANCH(startpos, 1, startpos);
|
|
|
|
return startpos;
|
|
}
|
|
|
|
// semi-primitive functions
|
|
|
|
static int aug_get_first_child(parse_tree_node_t *tree, int pos, int *first, int *second) {
|
|
// like aug_get_next_sibling, except that it recurses into the tree and
|
|
// finds the first child (usually *not* Ayanami Rei) of the current branch
|
|
// rather than its next sibling.
|
|
AUG_READ_BRANCH(pos, 0, pos);
|
|
AUG_ASSERT(pos);
|
|
AUG_READ_BRANCH(pos, 1, pos);
|
|
AUG_ASSERT(pos);
|
|
|
|
return aug_get_next_sibling(tree, pos, first, second);
|
|
}
|
|
|
|
static void aug_find_words_recursively(parse_tree_node_t *tree, int startpos, int *base_words, int *base_words_nr,
|
|
int *ref_words, int *ref_words_nr, int maxwords, int refbranch) {
|
|
// Finds and lists all base (141) and reference (144) words */
|
|
int major, minor;
|
|
int word;
|
|
int pos = aug_get_first_child(tree, startpos, &major, &minor);
|
|
|
|
//if (major == WORD_TYPE_REF)
|
|
// refbranch = 1;
|
|
|
|
while (pos) {
|
|
if ((word = aug_get_wgroup(tree, pos))) { // found a word
|
|
if (!refbranch && major == WORD_TYPE_BASE) {
|
|
if ((*base_words_nr) == maxwords) {
|
|
warning("Out of regular words");
|
|
return; // return gracefully
|
|
}
|
|
|
|
base_words[*base_words_nr] = word; // register word
|
|
++(*base_words_nr);
|
|
|
|
}
|
|
if (major == WORD_TYPE_REF || refbranch) {
|
|
if ((*ref_words_nr) == maxwords) {
|
|
warning("Out of reference words");
|
|
return; // return gracefully
|
|
}
|
|
|
|
ref_words[*ref_words_nr] = word; // register word
|
|
++(*ref_words_nr);
|
|
|
|
}
|
|
if (major != WORD_TYPE_SYNTACTIC_SUGAR && major != WORD_TYPE_BASE && major != WORD_TYPE_REF)
|
|
warning("aug_find_words_recursively(): Unknown word type %03x", major);
|
|
|
|
} else // Did NOT find a word group: Attempt to recurse
|
|
aug_find_words_recursively(tree, pos, base_words, base_words_nr,
|
|
ref_words, ref_words_nr, maxwords, refbranch || major == WORD_TYPE_REF);
|
|
|
|
pos = aug_get_next_sibling(tree, pos, &major, &minor);
|
|
}
|
|
}
|
|
|
|
|
|
static void aug_find_words(parse_tree_node_t *tree, int startpos, int *base_words, int *base_words_nr,
|
|
int *ref_words, int *ref_words_nr, int maxwords) {
|
|
// initializing wrapper for aug_find_words_recursively()
|
|
*base_words_nr = 0;
|
|
*ref_words_nr = 0;
|
|
|
|
aug_find_words_recursively(tree, startpos, base_words, base_words_nr, ref_words, ref_words_nr, maxwords, 0);
|
|
}
|
|
|
|
|
|
static int aug_contains_word(int *list, int length, int word) {
|
|
int i;
|
|
|
|
if (word == ANYWORD)
|
|
return (length);
|
|
|
|
for (i = 0; i < length; i++)
|
|
if (list[i] == word)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int augment_sentence_expression(parse_tree_node_t *saidt, int augment_pos, parse_tree_node_t *parset,
|
|
int parse_branch, int major, int minor, int *base_words, int base_words_nr,
|
|
int *ref_words, int ref_words_nr);
|
|
|
|
static int augment_match_expression_p(parse_tree_node_t *saidt, int augment_pos, parse_tree_node_t *parset,
|
|
int parse_basepos, int major, int minor,
|
|
int *base_words, int base_words_nr, int *ref_words, int ref_words_nr) {
|
|
int cmajor, cminor, cpos;
|
|
cpos = aug_get_first_child(saidt, augment_pos, &cmajor, &cminor);
|
|
if (!cpos) {
|
|
warning("augment_match_expression_p(): Empty condition");
|
|
return 1;
|
|
}
|
|
|
|
scidprintf("Attempting to match (%03x %03x (%03x %03x\n", major, minor, cmajor, cminor);
|
|
|
|
if ((major == WORD_TYPE_BASE) && (minor == AUGMENT_SENTENCE_MINOR_RECURSE))
|
|
return augment_match_expression_p(saidt, cpos, parset, parse_basepos, cmajor, cminor,
|
|
base_words, base_words_nr, ref_words, ref_words_nr);
|
|
|
|
switch (major) {
|
|
|
|
case WORD_TYPE_BASE:
|
|
while (cpos) {
|
|
if (cminor == AUGMENT_SENTENCE_MINOR_MATCH_WORD) {
|
|
int word = aug_get_wgroup(saidt, cpos);
|
|
scidprintf("Looking for word %03x\n", word);
|
|
|
|
if (aug_contains_word(base_words, base_words_nr, word))
|
|
return 1;
|
|
} else if (cminor == AUGMENT_SENTENCE_MINOR_MATCH_PHRASE) {
|
|
if (augment_sentence_expression(saidt, cpos, parset, parse_basepos, cmajor, cminor,
|
|
base_words, base_words_nr, ref_words, ref_words_nr))
|
|
return 1;
|
|
} else if (cminor == AUGMENT_SENTENCE_MINOR_PARENTHESES) {
|
|
int gc_major, gc_minor;
|
|
int gchild = aug_get_first_child(saidt, cpos, &gc_major, &gc_minor);
|
|
|
|
while (gchild) {
|
|
if (augment_match_expression_p(saidt, cpos, parset, parse_basepos, major,
|
|
minor, base_words, base_words_nr,
|
|
ref_words, ref_words_nr))
|
|
return 1;
|
|
gchild = aug_get_next_sibling(saidt, gchild, &gc_major, &gc_minor);
|
|
}
|
|
} else
|
|
warning("augment_match_expression_p(): Unknown type 141 minor number %3x", cminor);
|
|
|
|
cpos = aug_get_next_sibling(saidt, cpos, &cmajor, &cminor);
|
|
|
|
}
|
|
break;
|
|
|
|
case WORD_TYPE_REF:
|
|
while (cpos) {
|
|
if (cminor == AUGMENT_SENTENCE_MINOR_MATCH_WORD) {
|
|
int word = aug_get_wgroup(saidt, cpos);
|
|
scidprintf("Looking for refword %03x\n", word);
|
|
|
|
if (aug_contains_word(ref_words, ref_words_nr, word))
|
|
return 1;
|
|
} else if (cminor == AUGMENT_SENTENCE_MINOR_MATCH_PHRASE) {
|
|
if (augment_match_expression_p(saidt, cpos, parset, parse_basepos, cmajor, cminor,
|
|
base_words, base_words_nr, ref_words, ref_words_nr))
|
|
return 1;
|
|
} else if (cminor == AUGMENT_SENTENCE_MINOR_PARENTHESES) {
|
|
int gc_major, gc_minor;
|
|
int gchild = aug_get_first_child(saidt, cpos, &gc_major, &gc_minor);
|
|
|
|
while (gchild) {
|
|
if (augment_match_expression_p(saidt, cpos, parset, parse_basepos, major,
|
|
minor, base_words, base_words_nr,
|
|
ref_words, ref_words_nr))
|
|
return 1;
|
|
gchild = aug_get_next_sibling(saidt, gchild, &gc_major, &gc_minor);
|
|
}
|
|
} else
|
|
warning("augment_match_expression_p(): Unknown type 144 minor number %3x", cminor);
|
|
|
|
cpos = aug_get_next_sibling(saidt, cpos, &cmajor, &cminor);
|
|
|
|
}
|
|
break;
|
|
|
|
case AUGMENT_SENTENCE_PART_BRACKETS:
|
|
if (augment_match_expression_p(saidt, cpos, parset, parse_basepos, cmajor, cminor,
|
|
base_words, base_words_nr, ref_words, ref_words_nr))
|
|
return 1;
|
|
|
|
scidprintf("Didn't match subexpression; checking sub-bracked predicate %03x\n", cmajor);
|
|
|
|
switch (cmajor) {
|
|
case WORD_TYPE_BASE:
|
|
if (!base_words_nr)
|
|
return 1;
|
|
break;
|
|
|
|
case WORD_TYPE_REF:
|
|
if (!ref_words_nr)
|
|
return 1;
|
|
break;
|
|
|
|
default:
|
|
warning("augment_match_expression_p(): (subp1) Unkonwn sub-bracket predicate %03x", cmajor);
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
warning("augment_match_expression_p(): Unknown predicate %03x", major);
|
|
|
|
}
|
|
|
|
scidprintf("augment_match_expression_p(): Generic failure\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int augment_sentence_expression(parse_tree_node_t *saidt, int augment_pos, parse_tree_node_t *parset,
|
|
int parse_branch, int major, int minor, int *base_words, int base_words_nr,
|
|
int *ref_words, int ref_words_nr) {
|
|
int check_major, check_minor;
|
|
int check_pos = aug_get_first_child(saidt, augment_pos, &check_major, &check_minor);
|
|
do {
|
|
if (!(augment_match_expression_p(saidt, check_pos, parset, parse_branch, check_major, check_minor,
|
|
base_words, base_words_nr, ref_words, ref_words_nr)))
|
|
return 0;
|
|
} while ((check_pos = aug_get_next_sibling(saidt, check_pos, &check_major, &check_minor)));
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int augment_sentence_part(parse_tree_node_t *saidt, int augment_pos, parse_tree_node_t *parset, int parse_basepos, int major, int minor) {
|
|
int pmajor, pminor;
|
|
int parse_branch = parse_basepos;
|
|
int optional = 0;
|
|
int foundwords = 0;
|
|
|
|
scidprintf("Augmenting (%03x %03x\n", major, minor);
|
|
|
|
if (major == AUGMENT_SENTENCE_PART_BRACKETS) { // '[/ foo]' is true if '/foo' or if there
|
|
// exists no x for which '/x' is true
|
|
if ((augment_pos = aug_get_first_child(saidt, augment_pos, &major, &minor))) {
|
|
scidprintf("Optional part: Now augmenting (%03x %03x\n", major, minor);
|
|
optional = 1;
|
|
} else {
|
|
scidprintf("Matched empty optional expression\n");
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if ((major < 0x141) || (major > 0x143)) {
|
|
scidprintf("augment_sentence_part(): Unexpected sentence part major number %03x\n", major);
|
|
return 0;
|
|
}
|
|
|
|
while ((parse_branch = aug_get_next_sibling(parset, parse_branch, &pmajor, &pminor))) {
|
|
if (pmajor == major) { // found matching sentence part
|
|
int success;
|
|
int base_words_nr;
|
|
int ref_words_nr;
|
|
int base_words[AUGMENT_MAX_WORDS];
|
|
int ref_words[AUGMENT_MAX_WORDS];
|
|
#ifdef SCI_DEBUG_PARSE_TREE_AUGMENTATION
|
|
int i;
|
|
#endif
|
|
|
|
scidprintf("Found match with pminor = %03x\n", pminor);
|
|
aug_find_words(parset, parse_branch, base_words, &base_words_nr, ref_words, &ref_words_nr, AUGMENT_MAX_WORDS);
|
|
foundwords |= (ref_words_nr | base_words_nr);
|
|
#ifdef SCI_DEBUG_PARSE_TREE_AUGMENTATION
|
|
printf("%d base words:", base_words_nr);
|
|
for (i = 0; i < base_words_nr; i++)
|
|
printf(" %03x", base_words[i]);
|
|
printf("\n%d reference words:", ref_words_nr);
|
|
for (i = 0; i < ref_words_nr; i++)
|
|
printf(" %03x", ref_words[i]);
|
|
printf("\n");
|
|
#endif
|
|
|
|
success = augment_sentence_expression(saidt, augment_pos, parset, parse_basepos, major, minor,
|
|
base_words, base_words_nr, ref_words, ref_words_nr);
|
|
|
|
if (success) {
|
|
scidprintf("SUCCESS on augmenting (%03x %03x\n", major, minor);
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (optional && (foundwords == 0)) {
|
|
scidprintf("Found no words and optional branch => SUCCESS on augmenting (%03x %03x\n", major, minor);
|
|
return 1;
|
|
}
|
|
scidprintf("FAILURE on augmenting (%03x %03x\n", major, minor);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int augment_parse_nodes(parse_tree_node_t *parset, parse_tree_node_t *saidt) {
|
|
int augment_basepos = 0;
|
|
int parse_basepos;
|
|
int major, minor;
|
|
int dontclaim = 0;
|
|
|
|
parse_basepos = aug_get_base_node(parset);
|
|
if (!parse_basepos) {
|
|
warning("augment_parse_nodes(): Parse tree is corrupt");
|
|
return 0;
|
|
}
|
|
|
|
augment_basepos = aug_get_base_node(saidt);
|
|
if (!augment_basepos) {
|
|
warning("augment_parse_nodes(): Said tree is corrupt");
|
|
return 0;
|
|
}
|
|
|
|
while ((augment_basepos = aug_get_next_sibling(saidt, augment_basepos, &major, &minor))) {
|
|
if ((major == 0x14b) && (minor == SAID_LONG(SAID_GT)))
|
|
dontclaim = 1; // special case
|
|
else // normal sentence part
|
|
if (!(augment_sentence_part(saidt, augment_basepos, parset, parse_basepos, major, minor))) {
|
|
scidprintf("Returning failure\n");
|
|
return 0; // fail
|
|
}
|
|
}
|
|
|
|
scidprintf("Returning success with dontclaim=%d\n", dontclaim);
|
|
|
|
if (dontclaim)
|
|
return SAID_PARTIAL_MATCH;
|
|
else
|
|
return 1; // full match
|
|
}
|
|
|
|
|
|
/*******************/
|
|
/**** Main code ****/
|
|
/*******************/
|
|
|
|
int said(EngineState *s, byte *spec, bool verbose) {
|
|
int retval;
|
|
Vocabulary *voc = g_sci->getVocabulary();
|
|
|
|
parse_tree_node_t *parse_tree_ptr = voc->_parserNodes;
|
|
|
|
if (voc->parserIsValid) {
|
|
if (said_parse_spec(spec)) {
|
|
printf("Offending spec was: ");
|
|
voc->decipherSaidBlock(spec);
|
|
return SAID_NO_MATCH;
|
|
}
|
|
|
|
if (verbose)
|
|
vocab_dump_parse_tree("Said-tree", said_tree); // Nothing better to do yet
|
|
retval = augment_parse_nodes(parse_tree_ptr, &(said_tree[0]));
|
|
|
|
if (!retval)
|
|
return SAID_NO_MATCH;
|
|
else if (retval != SAID_PARTIAL_MATCH)
|
|
return SAID_FULL_MATCH;
|
|
else
|
|
return SAID_PARTIAL_MATCH;
|
|
}
|
|
|
|
return SAID_NO_MATCH;
|
|
}
|
|
|
|
|
|
#ifdef SAID_DEBUG_PROGRAM
|
|
int main (int argc, char *argv) {
|
|
byte block[] = {0x01, 0x00, 0xf8, 0xf5, 0x02, 0x01, 0xf6, 0xf2, 0x02, 0x01, 0xf2, 0x01, 0x03, 0xff};
|
|
EngineState s;
|
|
|
|
s.parser_valid = 1;
|
|
said(&s, block);
|
|
}
|
|
#endif
|
|
|
|
} // End of namespace Sci
|