libicl_depr.c

来自「SRI international 发布的OAA框架软件」· C语言 代码 · 共 1,035 行 · 第 1/3 页

C
1,035
字号
 * purpose: See if a variable can be resolved using existing variable bindings
 * inputs:
 *   - char *var: will return value if one can be found in var_bindings
 *   - char *var_bindings[]:
 *	        A list stored with var/value in l[N]/l[N+1]
 * remarks: 
 *   quits program!
 ****************************************************************************/
void icl_stderef(char **var,
                 struct dyn_array var_bindings)
{
  int done = 0;
  int pos;

  do {
    pos = icl_member_strlist(*var, var_bindings, 2, 0);
    if (pos >= 0) {
      icl_stFree(*var);
      *var = strdup(var_bindings.item[pos+1]);
    }
    else done = 1;
  } while (!done);
}


/****************************************************************************
 * name:    icl_stderef_term
 * purpose: replace all variables in a term by their bindings
 * inputs:
 *   - char *t, t2: terms to match (unify)
 *   - char ***vars: a string list where variable bindings will be stored
 *	    during unification.  If vars is NULL, no var bindings are kept,
 *	    acting as a simple match instead of a true unify.
 * remarks: 
 *    - Returns the stringlist of vars/bindings which must be deallocated
 *      when finished (free_dyn_list).
 ****************************************************************************/
void icl_stderef_term(char *term,
                      char **answer,
                      struct dyn_array vars)
{
  /* Dynamically allocated vars */
  char *fun1 = NULL;
  char *args1 = NULL;
  char *elt1 = NULL;

  /* These vars do not need to be deallocated, as they 
     are not dynamically allocated */
  char *p1;
  char openp[2], closep[2];

  icl_stFunctorArgs(term, &fun1, &args1);
  icl_stTrim(fun1);

  icl_stderef(&fun1,vars);

  if (icl_stIsList(fun1) && (strcmp(fun1,"[]") != 0)) {
    args1 = strdup(fun1);
    icl_stListToTerms(args1);
    strcpy(openp, "[");
    strcpy(closep, "]");
  }
  else
    if (icl_stIsGroup(fun1)) {
      args1 = strdup(fun1);
      icl_stGroupToTerms(args1);
      strcpy(openp, "[");
      strcpy(closep, "]");
      openp[0] = fun1[0];
      closep[0] = fun1[strlen(fun1)-1];
    }
    else {
      icl_stAppend(answer, fun1);
      strcpy(openp, "(");
      strcpy(closep, ")");
    }
  p1 = args1;
  if (*args1) {
    icl_stAppend(answer, openp);
    while ((strcmp(p1, "") != 0)) {
      icl_stHeadTailPtr(p1, &elt1, &p1);
      icl_stderef_term(elt1,answer,vars);
      if (*p1)
        icl_stAppend(answer, ",");
      icl_stFree(elt1);
    }
    icl_stAppend(answer, closep);
  }

  icl_stFree(fun1);
  icl_stFree(args1);
  icl_stFree(elt1);
}

/****************************************************************************
 * name:    icl_stmatch_terms
 * purpose: Returns true if Term1 matches Term2, saving variable bindings
 *          as it goes (if requested)
 * inputs:
 *   - char *t, t2: terms to match (unify)
 *   - dyn_array *vars: a string list where variable bindings will be stored
 *	    during unification.  If vars is NULL, no var bindings are kept,
 *	    acting as a simple match instead of a true unify.
 * remarks: 
 *    - Returns the stringlist of vars/bindings which must be deallocated
 *      when finished (free_dyn_list).
 ****************************************************************************/
static
int icl_stmatch_terms(char *t1,
                      char *t2,
                      struct dyn_array *vars)
{
  /* Dynamically allocated vars */
  char *fun1 = NULL;
  char *fun2 = NULL;
  char *args1 = NULL;
  char *args2 = NULL;
  char *elt1 = NULL;
  char *elt2 = NULL;

  /* These vars do not need to be deallocated, as they 
     are not dynamically allocated */
  char *p1, *p2;

  int result = TRUE;

  icl_stFunctorArgs(t1, &fun1, &args1);
  icl_stFunctorArgs(t2, &fun2, &args2);

  icl_stTrim(fun1);
  icl_stTrim(fun2);

  if (vars) {
    icl_stderef(&fun1,*vars);
    icl_stderef(&fun2,*vars);
  }

  if (icl_stIsVar(fun1)) {
    /* Anonymous variable "_" never gets bound */
    if (vars)
      /* && (strcmp(fun1,"_") != 0) && (strcmp(fun1, fun2) != 0))*/
      icl_stbind_var(fun1, fun2, vars);
    goto done;
  } else
    if (icl_stIsVar(fun2)) {
      /* Anonymous variable "_" never gets bound */
      if (vars)
	/* && (strcmp(fun2,"_") != 0) && (strcmp(fun1, fun2) != 0))*/
        icl_stbind_var(fun2, fun1, vars);
      goto done;
    } else {

      /* If both are [A,B,C] style lists, remove brackets
	 and start unifying args.  functors are set to "." */
      /* Works the same for (A,B,C) and {A,B,C}.  */
      if ((icl_stIsGroup(fun1) || icl_stIsList(fun1)) && 
	  (icl_stIsGroup(fun2) || icl_stIsList(fun2)) &&
	  (*fun1 == *fun2)) {
        args1 = strdup(fun1);
        args2 = strdup(fun2);
        icl_stGroupToTerms(args1);
        icl_stGroupToTerms(args2);
        icl_stFree(fun1);
        icl_stFree(fun2);
        fun1 = strdup(".");
        fun2 = strdup(".");
      }

      icl_stRemoveQuotes(fun1);
      icl_stRemoveQuotes(fun2);
      if (strcmp(fun1, fun2) == 0) {   /* same functor */

        p1 = args1;
        p2 = args2;
        while ((strcmp(p1, "") != 0) && (strcmp(p2, "") != 0)) {
          icl_stHeadTailPtr(p1, &elt1, &p1);
          icl_stHeadTailPtr(p2, &elt2, &p2);
          if (!icl_stmatch_terms(elt1, elt2, vars)) {
            result = FALSE;
            goto done;
          }
	       
          icl_stFree(elt1);
          icl_stFree(elt2);
        }
        if ((*p1 != 0) || (*p2 != 0)) {
          result = FALSE;
          goto done;
        }
      }
      else {
        result = FALSE;
        goto done;
      }
    }

 done:
  icl_stFree(fun1);
  icl_stFree(fun2);
  icl_stFree(args1);
  icl_stFree(args2);
  icl_stFree(elt1);
  icl_stFree(elt2);

  return result; 
   
}



/****************************************************************************
 * name:    icl_stUnify
 * purpose: Perform true unification and return resulting term
 * returns: if the two terms unify, returns true and answer will contain 
 *	    the unified term. Otherwise returns false (answer not changed)
 * remarks: 
 *   - If unification is successful, answer will be created in a new
 *     space which should be icl_stFree'd when done using.
 *   - answer may be NULL, in which case the resulting term is not returned
 *     but unify will still return true or false
 *   - unify() only works for simple prolog structures.  The following do
 *     NOT work:
 *        o Expressions using operators,  eg: A = 2, A -> B | C.
 ****************************************************************************/
EXPORT_MSCPP
int EXPORT_BORLAND icl_stUnify(char *term1,
                               char *term2,
                               char **answer)
{
  struct dyn_array da;
  int result;

  icl_init_dyn_array(&da);

  result = icl_stmatch_terms(term1, term2, &da);
  if (result && answer)
    icl_stderef_term(term1, answer, da);

  icl_free_dyn_list(&da);
  return result;
}


/****************************************************************************
 * name:    icl_stListToTerms
 * purpose: Converts an incoming prolog list [elt1, elt2, elt3] form) into
 *          a list of terms, on which we can use list_len, NthElt, etc.
 *          i.e. a comma-separated list "elt1, elt2, etl3".
 *          Basically, just removes the brackets...
 * inputs/outputs:
 *   - char *s: a list in prolog canonical syntax
 * remarks:
 *   icl_stListToTerms overwrites old value with the new because the new value
 *   is guaranteed to be shorter.
 ****************************************************************************/
EXPORT_MSCPP
void EXPORT_BORLAND 
icl_stListToTerms(char *s)
{
  int err = 0;
 
  if (s && (*s) && (*s == '['))
    strcpy(s, &s[1]);
  else err = 1;
  if (s && (*s) && (s[strlen(s)-1] == ']'))
    s[strlen(s)-1] = '\0';
  else err = 1;
 
  /*
    if (err) printf("Error in icl_stListToTerms() -- invalid list:\n  '%s'\n",s);
  */
}

/****************************************************************************
 * name:    icl_stHeadTailPtr
 * purpose: takes a comma-separated list of elements and returns a copy of 
 *	    the first element and a pointer to the rest of the list.
 * inputs:
 *   - char *terms: a list of terms
 * outputs:
 *   - char     *aterm: the first term in the list
 *   - char *restterms: the rest of the terms
 * remarks:
 *   - Terms may be nested arbitrarily deep (eg. a(b(c(d,1)), X).
 *   - aterm will return a new copy of the first argument, which should
 *     be free'd when finished using.  restterms will return a pointer
 *     into terms, which should NOT BE free'd.
 *   - Term can correctly parse expression with embedded arguments using
 *     Japanese JIS7 format.  JIS7 is the Japanese encoding standard chosen
 *     for use with the OAA.  Three reasons for this choice:  1) it's the
 *     most popular standard on UNIX machines.  2) 7-bit encoding should
 *     be TCP/IP and modem friendly.  3) it's easy to parse: JIS7 embeds
 *     Japanese characters in a quotation-like wrapper, using ESC$B for the
 *     opening marker and ESC(B for the closing.
 * returns: 
 *     TRUE if a term was read, FALSE if a complete term could not be read.
 *     In the latter case, aterm and restterms returns "" as well.
 ****************************************************************************/
EXPORT_MSCPP
int EXPORT_BORLAND 
icl_stHeadTailPtr(char *terms,
                  char **aterm,
                  char **restterms)
{
  int i;
  int n, len;
  int done = FALSE;
  int inquotes = FALSE;
  int inJIS7 = FALSE;
  int parens = 0;
  int seen_something = FALSE;

  *aterm = NULL;
  *restterms = NULL;

  len = strlen(terms);

  i = -1;
  while ((i < len-1) && !done) {
    i++;

    /* Check for JIS7 Japanese Encoding markers */
    if ((terms[i] == 27) && (terms[i+1] == '$') && (terms[i+2] == 'B'))
      inJIS7 = TRUE;
    else
      if ((terms[i] == 27) && (terms[i+1] == '(') && (terms[i+2] == 'B'))
        inJIS7 = FALSE;
	
    /* If we are not looking at Japanese characters, try to parse the 
       input. */
    if (!inJIS7)
      switch (terms[i]) {
      case '(':
      case '[':
      case '{':
        if (!inquotes)
          parens = parens + 1;
        break;
      case ')':
      case ']':
      case '}':
        if (!inquotes) {
          parens = parens - 1;
          if ((parens == 0) && (!icl_stIsOperatorChar(terms[i+1])))
            done = TRUE;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?