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 }