00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 #include "term-priv.h"
00021 #include "context-priv.h"
00022 
00024 struct p_term_expand_info
00025 {
00026     p_term *or_atom;
00027     p_term *compound_atom;
00028     p_term *unify_atom;
00029     p_term *not_atom;
00030 };
00033 static p_term *p_term_expand_head
00034     (p_context *context, p_term *term, p_term *in_var, p_term *out_var)
00035 {
00036     p_term *new_term;
00037     if (term->header.type == P_TERM_ATOM) {
00038         new_term = p_term_create_functor(context, term, 2);
00039         p_term_bind_functor_arg(new_term, 0, in_var);
00040         p_term_bind_functor_arg(new_term, 1, out_var);
00041     } else {
00042         unsigned int index;
00043         new_term = p_term_create_functor
00044             (context, term->functor.functor_name,
00045              p_term_arg_count(term) + 2);
00046         for (index = 0; index < term->header.size; ++index) {
00047             p_term_bind_functor_arg
00048                 (new_term, (int)index, term->functor.arg[index]);
00049         }
00050         p_term_bind_functor_arg(new_term, term->header.size, in_var);
00051         p_term_bind_functor_arg(new_term, term->header.size + 1, out_var);
00052     }
00053     return new_term;
00054 }
00055 
00056 P_INLINE p_term *p_term_create_binary
00057     (p_context *context, p_term *name, p_term *term1, p_term *term2)
00058 {
00059     p_term *term = p_term_create_functor(context, name, 2);
00060     p_term_bind_functor_arg(term, 0, term1);
00061     p_term_bind_functor_arg(term, 1, term2);
00062     return term;
00063 }
00064 
00065 static p_term *p_term_expand_body
00066     (p_context *context, p_term *term, p_term *in_var,
00067      p_term *out_var, struct p_term_expand_info *info, int *first)
00068 {
00069     p_term *list;
00070     p_term *left;
00071     p_term *right;
00072     p_term *middle_var;
00073     term = p_term_deref(term);
00074     if (!term)
00075         return term;
00076     switch (term->header.type) {
00077     case P_TERM_ATOM:
00078         if (term == context->nil_atom) {
00079             
00080 
00081 
00082 
00083             if (*first) {
00084                 p_term_unify
00085                     (context, in_var, out_var, P_BIND_NO_RECORD);
00086                 return context->true_atom;
00087             } else {
00088                 return p_term_create_binary
00089                     (context, info->unify_atom, in_var, out_var);
00090             }
00091         } else if (term == context->commit_atom) {
00092             
00093 
00094             *first = 0;
00095             right = p_term_create_binary
00096                 (context, info->unify_atom, in_var, out_var);
00097             return p_term_create_binary
00098                 (context, context->comma_atom, term, right);
00099         } else {
00100             
00101             *first = 0;
00102             return p_term_expand_head(context, term, in_var, out_var);
00103         }
00104     case P_TERM_FUNCTOR:
00105         if (term->functor.functor_name == info->or_atom &&
00106                 term->header.size == 2) {
00107             
00108             *first = 0;
00109             left = p_term_expand_body
00110                 (context, term->functor.arg[0], in_var,
00111                  out_var, info, first);
00112             right = p_term_expand_body
00113                 (context, term->functor.arg[1], in_var,
00114                  out_var, info, first);
00115             return p_term_create_binary
00116                 (context, info->or_atom, left, right);
00117         } else if (term->functor.functor_name == context->comma_atom &&
00118                    term->header.size == 2) {
00119             
00120             middle_var = p_term_create_variable(context);
00121             left = p_term_expand_body
00122                 (context, term->functor.arg[0], in_var,
00123                  middle_var, info, first);
00124             right = p_term_expand_body
00125                 (context, term->functor.arg[1], middle_var,
00126                  out_var, info, first);
00127             if (left == context->true_atom)
00128                 return right;
00129             else if (right == context->true_atom)
00130                 return left;
00131             return p_term_create_binary
00132                 (context, context->comma_atom, left, right);
00133         } else if (term->functor.functor_name == info->not_atom &&
00134                    term->header.size == 1) {
00135             
00136 
00137             *first = 0;
00138             middle_var = p_term_create_variable(context);
00139             term = p_term_expand_body
00140                 (context, term->functor.arg[0], in_var,
00141                  middle_var, info, first);
00142             left = p_term_create_functor(context, info->not_atom, 1);
00143             p_term_bind_functor_arg(left, 0, term);
00144             right = p_term_create_binary
00145                 (context, info->unify_atom, in_var, out_var);
00146             return p_term_create_binary
00147                 (context, context->comma_atom, left, right);
00148         } else if (term->functor.functor_name == info->compound_atom &&
00149                    term->header.size == 1) {
00150             
00151             *first = 0;
00152             right = p_term_create_binary
00153                 (context, info->unify_atom, in_var, out_var);
00154             term = p_term_deref(term->functor.arg[0]);
00155             if (term == context->true_atom)
00156                 return right;
00157             return p_term_create_binary
00158                 (context, context->comma_atom, term, right);
00159         }
00160         *first = 0;
00161         return p_term_expand_head(context, term, in_var, out_var);
00162     case P_TERM_LIST:
00163         
00164         list = p_term_create_list(context, term->list.head, 0);
00165         left = p_term_deref(term->list.tail);
00166         right = list;
00167         while (left && left->header.type == P_TERM_LIST) {
00168             middle_var = p_term_create_list
00169                 (context, left->list.head, 0);
00170             p_term_set_tail(right, middle_var);
00171             right = middle_var;
00172             left = p_term_deref(left->list.tail);
00173         }
00174         p_term_set_tail(right, out_var);
00175         if (*first) {
00176             
00177 
00178 
00179             p_term_unify(context, in_var, list, P_BIND_NO_RECORD);
00180             return context->true_atom;
00181         } else {
00182             return p_term_create_binary
00183                 (context, info->unify_atom, in_var, list);
00184         }
00185         break;
00186     case P_TERM_STRING:
00187         
00188         if (*first) {
00189             list = p_term_create_list(context, term, out_var);
00190             p_term_unify(context, in_var, list, P_BIND_NO_RECORD);
00191             return context->true_atom;
00192         } else {
00193             list = p_term_create_list(context, term, out_var);
00194             return p_term_create_binary
00195                 (context, info->unify_atom, in_var, list);
00196         }
00197         break;
00198     default: break;
00199     }
00200     return term;
00201 }
00202 
00212 p_term *p_term_expand_dcg(p_context *context, p_term *term)
00213 {
00214     struct p_term_expand_info info;
00215     p_term *head;
00216     p_term *body;
00217     p_term *clause;
00218     p_term *in_var;
00219     p_term *out_var;
00220     int first = 1;
00221 
00222     
00223     info.or_atom = p_term_create_atom(context, "||");
00224     info.compound_atom = p_term_create_atom(context, "{}");
00225     info.unify_atom = p_term_create_atom(context, "=");
00226     info.not_atom = p_term_create_atom(context, "!");
00227 
00228     
00229     term = p_term_deref(term);
00230     if (!term || term->header.type != P_TERM_FUNCTOR ||
00231             term->header.size != 2 ||
00232             term->functor.functor_name !=
00233                     p_term_create_atom(context, "-->"))
00234         return 0;
00235     head = p_term_deref(term->functor.arg[0]);
00236     if (!head || (head->header.type != P_TERM_FUNCTOR &&
00237                   head->header.type != P_TERM_ATOM))
00238         return 0;
00239 
00240     
00241     in_var = p_term_create_variable(context);
00242     out_var = p_term_create_variable(context);
00243     head = p_term_expand_head(context, head, in_var, out_var);
00244 
00245     
00246     body = p_term_expand_body
00247         (context, term->functor.arg[1], in_var, out_var, &info, &first);
00248 
00249     
00250     clause = p_term_create_functor(context, context->clause_atom, 2);
00251     p_term_bind_functor_arg(clause, 0, head);
00252     p_term_bind_functor_arg(clause, 1, body);
00253     return clause;
00254 }