00001 %{
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 #include <plang/term.h>
00022 #include <plang/context.h>
00023 #include <stdio.h>
00024 #include <string.h>
00025 #include <stdarg.h>
00026 #include <stdlib.h>
00027 #include <errno.h>
00028 #include "parser.h"
00029 #include "term-priv.h"
00030 #include "parser-priv.h"
00031 #include "context-priv.h"
00032 
00033 extern int yylex(YYSTYPE *lval, YYLTYPE *loc, p_context *context, yyscan_t yyscanner);
00034 extern p_input_stream *p_term_get_extra(yyscan_t yyscanner);
00035 extern p_term *p_term_lex_create_variable
00036     (p_context *context, p_input_stream *stream, const char *name);
00037 extern unsigned int p_term_lex_variable_count
00038     (p_input_stream *stream, p_term *var);
00039 
00040 #define input_stream (p_term_get_extra(yyscanner))
00041 
00042 static void yyerror(YYLTYPE *loc, p_context *context, yyscan_t yyscanner, const char *msg)
00043 {
00044     p_input_stream *stream = p_term_get_extra(yyscanner);
00045     if (stream->filename)
00046         fprintf(stderr, "%s:%d: %s\n", stream->filename, loc->first_line, msg);
00047     else
00048         fprintf(stderr, "%d: %s\n", loc->first_line, msg);
00049     ++(stream->error_count);
00050 }
00051 
00052 static void yyerror_printf(YYLTYPE *loc, p_context *context, p_input_stream *stream, const char *format, ...)
00053 {
00054     va_list va;
00055     va_start(va, format);
00056     if (stream && stream->filename)
00057         fprintf(stderr, "%s:%d: ", stream->filename, loc->first_line);
00058     else if (stream)
00059         fprintf(stderr, "%d: ", loc->first_line);
00060     vfprintf(stderr, format, va);
00061     putc('\n', stderr);
00062     if (stream)
00063         ++(stream->error_count);
00064     va_end(va);
00065 }
00066 
00067 
00068 
00069 
00070 #define YYMALLOC    GC_MALLOC
00071 #define YYFREE      GC_FREE
00072 
00073 
00074 static p_term *make_unary_term(p_context *context, const char *name, p_term *term)
00075 {
00076     p_term *result = p_term_create_functor
00077         (context, p_term_create_atom(context, (name)), 1);
00078     p_term_bind_functor_arg(result, 0, (term));
00079     return result;
00080 }
00081 #define unary_term(name,term)   make_unary_term(context, (name), (term))
00082 
00083 
00084 static p_term *make_binary_term(p_context *context, const char *name, p_term *term1, p_term *term2)
00085 {
00086     p_term *result = p_term_create_functor
00087         (context, p_term_create_atom(context, (name)), 2);
00088     p_term_bind_functor_arg(result, 0, (term1));
00089     p_term_bind_functor_arg(result, 1, (term2));
00090     return result;
00091 }
00092 #define binary_term(name,term1,term2) make_binary_term(context, (name), (term1), (term2))
00093 
00094 
00095 static p_term *make_ternary_term(p_context *context, const char *name, p_term *term1, p_term *term2, p_term *term3)
00096 {
00097     p_term *result = p_term_create_functor
00098         (context, p_term_create_atom(context, (name)), 3);
00099     p_term_bind_functor_arg(result, 0, (term1));
00100     p_term_bind_functor_arg(result, 1, (term2));
00101     p_term_bind_functor_arg(result, 2, (term3));
00102     return result;
00103 }
00104 #define ternary_term(name,term1,term2,term3) make_ternary_term(context, (name), (term1), (term2), (term3))
00105 
00106 
00107 
00108 #define append_r_list(dest, src, new_term, oper) \
00109     do { \
00110         p_term *term; \
00111         if (src.r_hole) { \
00112             term = p_term_create_functor \
00113                 (context, p_term_create_atom(context, oper), 2); \
00114             p_term_bind_functor_arg(term, 0, src.r_tail); \
00115             p_term_bind_functor_arg(src.r_hole, 1, term); \
00116             dest.r_head = src.r_head; \
00117             dest.r_hole = term; \
00118             dest.r_tail = new_term; \
00119         } else { \
00120             term = p_term_create_functor \
00121                 (context, p_term_create_atom(context, oper), 2); \
00122             p_term_bind_functor_arg(term, 0, src.r_tail); \
00123             dest.r_head = term; \
00124             dest.r_hole = term; \
00125             dest.r_tail = new_term; \
00126         } \
00127     } while (0)
00128 #define finalize_r_list(list) \
00129     (list.r_hole ? \
00130         (p_term_bind_functor_arg(list.r_hole, 1, list.r_tail), \
00131          list.r_head) : list.r_tail)
00132 #define create_r_list(list,term) \
00133     do { \
00134         list.r_head = 0; \
00135         list.r_hole = 0; \
00136         list.r_tail = term; \
00137     } while (0)
00138 
00139 
00140 #define append_list(dest,src,term) \
00141     do { \
00142         dest.l_head = src.l_head; \
00143         dest.l_tail = p_term_create_list(context, term, 0); \
00144         p_term_set_tail(src.l_tail, dest.l_tail); \
00145     } while (0)
00146 #define append_lists(dest,src1,src2) \
00147     do { \
00148         if (src1.l_head && src2.l_head) { \
00149             dest.l_head = src1.l_head; \
00150             dest.l_tail = src2.l_tail; \
00151             p_term_set_tail(src1.l_tail, src2.l_head); \
00152         } else if (src1.l_head) { \
00153             dest.l_head = src1.l_head; \
00154             dest.l_tail = src1.l_tail; \
00155         } else if (src2.l_head) { \
00156             dest.l_head = src2.l_head; \
00157             dest.l_tail = src2.l_tail; \
00158         } else { \
00159             dest.l_head = 0; \
00160             dest.l_tail = 0; \
00161         } \
00162     } while (0)
00163 #define create_list(list,term) \
00164     do { \
00165         list.l_head = p_term_create_list(context, term, 0); \
00166         list.l_tail = list.l_head; \
00167     } while (0)
00168 #define create_empty_list(list) \
00169     do { \
00170         list.l_head = 0; \
00171         list.l_tail = 0; \
00172     } while (0)
00173 #define finalize_list(list) \
00174     ((list).l_head ? \
00175         (p_term_set_tail((list).l_tail, p_term_nil_atom(context)), \
00176          (list).l_head) : p_term_nil_atom(context))
00177 #define finalize_list_tail(list,tail) \
00178     (p_term_set_tail((list).l_tail, (tail)), (list).l_head)
00179 
00180 
00181 
00182 static p_term *make_class_declaration
00183     (p_context *context, p_term *name, p_term *parent,
00184      p_term *vars, p_term *clauses)
00185 {
00186     p_term *term;
00187     term = p_term_create_functor
00188         (context, p_term_create_atom(context, "new_class"), 4);
00189     p_term_bind_functor_arg(term, 0, name);
00190     p_term_bind_functor_arg(term, 1, parent);
00191     p_term_bind_functor_arg(term, 2, vars);
00192     p_term_bind_functor_arg(term, 3, clauses);
00193     return make_unary_term(context, "?-", term);
00194 }
00195 
00196 
00197 #define clear_variables()   (input_stream->num_variables = 0)
00198 
00199 
00200 static p_term *add_debug_line
00201     (p_context *context, p_input_stream *stream,
00202      YYLTYPE *loc, p_term *term)
00203 {
00204     p_term *line;
00205     if (!context->debug)
00206         return term;
00207     if (!stream->filename_string) {
00208         stream->filename_string =
00209             p_term_create_string(context, stream->filename);
00210     }
00211     line = p_term_create_functor(context, context->line_atom, 3);
00212     p_term_bind_functor_arg(line, 0, stream->filename_string);
00213     p_term_bind_functor_arg
00214         (line, 1, p_term_create_integer(context, loc->first_line));
00215     p_term_bind_functor_arg(line, 2, term);
00216     return line;
00217 }
00218 #define add_debug(loc, term) \
00219     (add_debug_line(context, input_stream, &(loc), term))
00220 
00221 static char *p_concat_strings
00222     (const char *str1, size_t len1, const char *str2, size_t len2,
00223      const char *str3, size_t len3, const char *str4, size_t len4)
00224 {
00225     char *str = (char *)malloc(len1 + len2 + len3 + len4 + 1);
00226     if (len1 > 0)
00227         memcpy(str, str1, len1);
00228     if (len2 > 0)
00229         memcpy(str + len1, str2, len2);
00230     if (len3 > 0)
00231         memcpy(str + len1 + len2, str3, len3);
00232     if (len4 > 0)
00233         memcpy(str + len1 + len2 + len3, str4, len4);
00234     str[len1 + len2 + len3 + len4] = '\0';
00235     return str;
00236 }
00237 
00238 static int p_context_consult_file_in_path
00239     (p_context *context, const char *pathname, const char *name,
00240      int has_extn, p_input_stream *stream)
00241 {
00242     int error;
00243     char *path;
00244     size_t len = strlen(pathname);
00245     const char *sep = 0;
00246     size_t sep_len = 0;
00247 #if defined(P_WIN32)
00248     if (len > 0 && pathname[len - 1] != '/' && pathname[len - 1] != '\\') {
00249         sep = "\\";
00250         sep_len = 1;
00251     }
00252 #else
00253     if (len > 0 && pathname[len - 1] != '/') {
00254         sep = "/";
00255         sep_len = 1;
00256     }
00257 #endif
00258     if (has_extn) {
00259         path = p_concat_strings
00260             (pathname, strlen(pathname), sep, sep_len,
00261              name, strlen(name), 0, 0);
00262     } else {
00263         path = p_concat_strings
00264             (pathname, strlen(pathname), sep, sep_len,
00265              name, strlen(name), ".lp", 3);
00266     }
00267     error = p_context_consult_file(context, path, P_CONSULT_ONCE);
00268     if (error == 0) {
00269         
00270         free(path);
00271         return 1;
00272     } else if (error == EINVAL) {
00273         
00274         if (stream)
00275             ++(stream->error_count);
00276         free(path);
00277         return 0;
00278     }
00279     free(path);
00280     return -1;
00281 }
00282 
00283 static int p_context_import
00284     (YYLTYPE *loc, p_context *context, p_input_stream *stream,
00285      const char *name)
00286 {
00287     const char *parent_filename;
00288     size_t len, len2;
00289     int has_extn, has_dir, is_root, error;
00290     char *path;
00291     int result;
00292 
00293     
00294     parent_filename = (stream ? stream->filename : 0);
00295     len = parent_filename ? strlen(parent_filename) : 0;
00296     while (len > 0) {
00297 #if defined(P_WIN32)
00298         if (parent_filename[len - 1] == '/' ||
00299                 parent_filename[len - 1] == '\\')
00300             break;
00301 #else
00302         if (parent_filename[len - 1] == '/')
00303             break;
00304 #endif
00305         --len;
00306     }
00307     if (!len) {
00308 #if defined(P_WIN32)
00309         parent_filename = ".\\";
00310 #else
00311         parent_filename = "./";
00312 #endif
00313         len = 2;
00314     }
00315 
00316     
00317 
00318     len2 = strlen(name);
00319     if (!len2) {
00320         yyerror_printf(loc, context, stream, "empty import name");
00321         return 0;
00322     }
00323     has_extn = 0;
00324     while (len2 > 0) {
00325 #if defined(P_WIN32)
00326         if (name[len2 - 1] == '/' || name[len2 - 1] == '\\')
00327             break;
00328 #else
00329         if (name[len2 - 1] == '/')
00330             break;
00331 #endif
00332         if (name[len2 - 1] == '.')
00333             has_extn = 1;
00334         --len2;
00335     }
00336     has_dir = (len2 > 0);
00337 
00338     
00339     is_root = 0;
00340     if (name[0] == '/') {
00341         is_root = 1;
00342 #if defined(P_WIN32)
00343     } else if (name[0] == '\\') {
00344         is_root = 1;
00345     } else if (((name[0] >= 'a' && name[0] <= 'z') ||
00346                 (name[0] >= 'A' && name[0] <= 'Z'))) {
00347         if (name[1] == ':' && (name[2] == '/' || name[2] == '\\'))
00348             is_root = 1;
00349 #endif
00350     }
00351 
00352     
00353     if (is_root) {
00354         if (has_extn)
00355             path = p_concat_strings(name, strlen(name), 0, 0, 0, 0, 0, 0);
00356         else
00357             path = p_concat_strings(name, strlen(name), ".lp", 3, 0, 0, 0, 0);
00358     } else {
00359         if (has_extn) {
00360             path = p_concat_strings
00361                 (parent_filename, len, name, strlen(name), 0, 0, 0, 0);
00362         } else {
00363             path = p_concat_strings
00364                 (parent_filename, len, name, strlen(name), ".lp", 3, 0, 0);
00365         }
00366     }
00367     error = p_context_consult_file(context, path, P_CONSULT_ONCE);
00368     if (error == 0) {
00369         
00370         free(path);
00371         return 1;
00372     } else if (error == EINVAL) {
00373         
00374         if (stream)
00375             ++(stream->error_count);
00376         free(path);
00377         return 0;
00378     }
00379     free(path);
00380 
00381     
00382     if (!has_dir) {
00383         size_t index;
00384         for (index = 0; index < context->user_imports.num_paths; ++index) {
00385             result = p_context_consult_file_in_path
00386                 (context, context->user_imports.paths[index],
00387                  name, has_extn, stream);
00388             if (result >= 0)
00389                 return result;
00390         }
00391         for (index = 0; index < context->system_imports.num_paths; ++index) {
00392             result = p_context_consult_file_in_path
00393                 (context, context->system_imports.paths[index],
00394                  name, has_extn, stream);
00395             if (result >= 0)
00396                 return result;
00397         }
00398     }
00399 
00400     
00401     return -1;
00402 }
00403 
00404 int p_context_builtin_import(p_context *context, const char *name)
00405 {
00406     return p_context_import(0, context, 0, name);
00407 }
00408 
00409 
00410 static p_term *create_clause_head
00411     (p_context *context, p_input_stream *stream,
00412      p_term *member_name, p_term **args, size_t num_args,
00413      int is_static)
00414 {
00415     size_t index;
00416     p_term *head = p_term_create_functor
00417         (context, p_term_create_member_name
00418             (context, stream->class_name, member_name),
00419          (int)(num_args + (is_static ? 0 : 1)));
00420     if (is_static) {
00421         for (index = 0; index < num_args; ++index)
00422             p_term_bind_functor_arg(head, index, args[index]);
00423     } else {
00424         p_term *self = p_term_lex_create_variable
00425             (context, stream, "Self");
00426         p_term_bind_functor_arg(head, 0, self);
00427         for (index = 0; index < num_args; ++index)
00428             p_term_bind_functor_arg(head, index + 1, args[index]);
00429     }
00430     if (args)
00431         GC_FREE(args);
00432     return head;
00433 }
00434 
00435 %}
00436 
00437 
00438 %name-prefix="p_term_"
00439 %pure-parser
00440 %error-verbose
00441 %locations
00442 %parse-param {p_context *context}
00443 %parse-param {yyscan_t yyscanner}
00444 %lex-param {p_context *context}
00445 %lex-param {yyscan_t yyscanner}
00446 
00447 
00448 %union {
00449     p_term *term;
00450     struct {
00451         p_term *l_head;
00452         p_term *l_tail;
00453     } list;
00454     struct {
00455         p_term **args;
00456         size_t num_args;
00457         size_t max_args;
00458     } arg_list;
00459     struct {
00460         p_term *r_head;
00461         p_term *r_tail;
00462         p_term *r_hole;
00463     } r_list;
00464     struct {
00465         p_term *vars;
00466         p_term *clauses;
00467         int has_constructor;
00468     } class_body;
00469     struct {
00470         struct {
00471             p_term *l_head;
00472             p_term *l_tail;
00473         } vars;
00474         struct {
00475             p_term *l_head;
00476             p_term *l_tail;
00477         } clauses;
00478         int has_constructor;
00479     } member_list;
00480     struct {
00481         p_term *object;
00482         p_term *name;
00483         int auto_create;
00484     } member_ref;
00485     struct {
00486         p_term *name;
00487         p_term *kind;
00488         p_term *head;
00489         p_term *body;
00490         int has_constructor;
00491     } clause;
00492     struct {
00493         p_term *l_head;
00494         p_term *l_tail;
00495         int is_default;
00496     } case_labels;
00497     struct {
00498         p_term *l_head;
00499         p_term *l_tail;
00500         p_term *default_case;
00501         int is_default;
00502     } switch_case;
00503     struct {
00504         p_term *case_list;
00505         p_term *default_case;
00506     } switch_body;
00507 }
00508 
00509 
00510 %token K_ATOM           "an atom"
00511 %token K_INTEGER        "an integer"
00512 %token K_REAL           "a floating-point number"
00513 %token K_STRING         "a string"
00514 %token K_VARIABLE       "a variable"
00515 %token K_COLON_DASH     "`:-'"
00516 %token K_QUEST_DASH     "`?-'"
00517 %token K_TEST_GOAL      "`??--'"
00518 %token K_READ_TERM      "`??-'"
00519 %token K_ARROW          "`->'"
00520 %token K_DARROW         "`-->'"
00521 %token K_DOT_TERMINATOR "`.'"
00522 %token K_OR             "`||'"
00523 %token K_AND            "`&&'"
00524 %token K_NOT            "`\\+'"
00525 %token K_NE             "`!='"
00526 %token K_TERM_EQ        "`=='"
00527 %token K_TERM_NE        "`!=='"
00528 %token K_TERM_LT        "`@<'"
00529 %token K_TERM_LE        "`@<='"
00530 %token K_TERM_GT        "`@>'"
00531 %token K_TERM_GE        "`@>='"
00532 %token K_UNIV           "`=..'"
00533 %token K_NUM_EQ         "`=:='"
00534 %token K_NUM_NE         "`=!='"
00535 %token K_NUM_LT         "`<'"
00536 %token K_NUM_LE         "`<='"
00537 %token K_NUM_GT         "`>'"
00538 %token K_NUM_GE         "`>='"
00539 %token K_NUM_GETS       "`::='"
00540 %token K_NUM_BT_GETS    "`::=='"
00541 %token K_BITWISE_AND    "`/\\'"
00542 %token K_BITWISE_OR     "`\\/'"
00543 %token K_BITWISE_NOT    "`\\'"
00544 %token K_SHIFT_LEFT     "`<<'"
00545 %token K_SHIFT_RIGHT    "`>>'"
00546 %token K_USHIFT_RIGHT    "`>>>'"
00547 %token K_EXP            "`**'"
00548 %token K_DOT_DOT        "`..'"
00549 %token K_GETS           "`:='"
00550 %token K_BT_GETS        "`:=='"
00551 %token K_IMPLIES        "`=>'"
00552 %token K_EQUIV          "`<=>'"
00553 %token K_ABSTRACT       "`abstract'"
00554 %token K_CASE           "`case'"
00555 %token K_CATCH          "`catch'"
00556 %token K_CLASS          "`class'"
00557 %token K_DEFAULT        "`default'"
00558 %token K_DO             "`do'"
00559 %token K_ELSE           "`else'"
00560 %token K_FOR            "`for'"
00561 %token K_IF             "`if'"
00562 %token K_IN             "`in'"
00563 %token K_IS             "`is'"
00564 %token K_MOD            "`mod'"
00565 %token K_NEW            "`new'"
00566 %token K_REM            "`rem'"
00567 %token K_STATIC         "`static'"
00568 %token K_SWITCH         "`switch'"
00569 %token K_TRY            "`try'"
00570 %token K_WHILE          "`while'"
00571 %token K_VAR            "`var'"
00572 
00573 
00574 %type <term>        K_ATOM K_INTEGER K_REAL K_STRING K_VARIABLE
00575 
00576 %type <term>        declaration directive goal clause callable_term
00577 %type <term>        class_declaration atom opt_parent member_name
00578 
00579 %type <term>        term not_term compare_term additive_term
00580 %type <term>        multiplicative_term power_term unary_term
00581 %type <term>        primary_term condition if_term argument_term
00582 %type <term>        new_term member_var bracketed_term head_argument_term
00583 %type <term>        implies_term or_term
00584 %type <term>        argument_implies_term argument_or_term
00585 
00586 %type <term>        statement if_statement compound_statement
00587 %type <term>        loop_statement unbind_vars try_statement
00588 %type <term>        catch_clause switch_statement clause_body
00589 %type <term>        confidence
00590 
00591 %type <term>        dcg_clause dcg_body dcg_unary_term
00592 %type <term>        dcg_primitive_term
00593 
00594 %type <case_labels> case_label case_labels
00595 %type <switch_case> switch_cases switch_case
00596 %type <switch_body> switch_body
00597 
00598 %type <list>        list_members declaration_list
00599 %type <list>        member_vars unbind_var_list catch_clauses
00600 
00601 %type <arg_list>    arguments
00602 %type <r_list>      statements and_term argument_and_term dcg_term
00603 %type <class_body>  class_body
00604 %type <member_list> class_members class_member
00605 %type <member_ref>  member_reference
00606 %type <clause>      member_clause member_clause_head
00607 %type <clause>      regular_member_clause_head
00608 
00609 
00610 
00611 
00612 %expect 3
00613 
00614 %start file
00615 %%
00616 
00617 file
00618     : declaration_list      {
00619             input_stream->declarations = finalize_list($1);
00620         }
00621     | K_READ_TERM term K_DOT_TERMINATOR {
00622             input_stream->declarations =
00623                 p_term_create_list
00624                     (context, unary_term("\?\?-", $2),
00625                      context->nil_atom);
00626         }
00627     | 
00628     ;
00629 
00630 declaration_list
00631     : declaration_list declaration  {
00632             p_term *decl = add_debug(@2, $2);
00633             append_list($$, $1, decl);
00634             clear_variables();
00635         }
00636     | declaration   {
00637             p_term *decl = add_debug(@1, $1);
00638             create_list($$, decl);
00639             clear_variables();
00640         }
00641     ;
00642 
00643 declaration
00644     : clause                    { $$ = $1; }
00645     | directive                 { $$ = $1; }
00646     | goal                      { $$ = $1; }
00647     | class_declaration         { $$ = $1; }
00648     | dcg_clause                { $$ = $1; }
00649     | error K_DOT_TERMINATOR    {
00650             
00651             $$ = unary_term("?-", context->true_atom);
00652         }
00653     ;
00654 
00655 directive
00656     : K_COLON_DASH callable_term K_DOT_TERMINATOR   {
00657             if (p_term_type($2) == P_TERM_FUNCTOR &&
00658                     p_term_arg_count($2) == 1 &&
00659                     p_term_functor($2) ==
00660                         p_term_create_atom(context, "initialization")) {
00661                 
00662                 $$ = unary_term("?-", add_debug(@2, p_term_arg($2, 0)));
00663             } else if (p_term_type($2) == P_TERM_FUNCTOR &&
00664                        p_term_arg_count($2) == 1 &&
00665                        p_term_functor($2) ==
00666                        p_term_create_atom(context, "import")) {
00667                 
00668                 p_term *name = p_term_deref(p_term_arg($2, 0));
00669                 if (!name || (name->header.type != P_TERM_ATOM &&
00670                               name->header.type != P_TERM_STRING)) {
00671                     yyerror_printf
00672                         (&(@2), context, input_stream,
00673                          "import name is not an atom or string");
00674                 } else {
00675                     int result = p_context_import
00676                         (&(@2), context, input_stream,
00677                          p_term_name(name));
00678                     if (result < 0) {
00679                         yyerror_printf
00680                             (&(@2), context, input_stream,
00681                              "cannot locate import `%s'", name);
00682                     }
00683                 }
00684                 $$ = unary_term(":-", $2);
00685             } else {
00686                 
00687                 if (p_goal_call_from_parser(context, add_debug(@2, $2))
00688                         != P_RESULT_TRUE) {
00689                     ++(input_stream->error_count);
00690                 }
00691                 $$ = unary_term(":-", $2);
00692             }
00693         }
00694     ;
00695 
00696 goal
00697     : K_QUEST_DASH term K_DOT_TERMINATOR    {
00698             $$ = unary_term("?-", add_debug(@2, $2));
00699         }
00700     | K_QUEST_DASH compound_statement       {
00701             $$ = unary_term("?-", add_debug(@2, $2));
00702         }
00703     | K_TEST_GOAL term K_DOT_TERMINATOR     {
00704             
00705 
00706             $$ = unary_term("\?\?--", $2);
00707         }
00708     | K_TEST_GOAL compound_statement        {
00709             $$ = unary_term("\?\?--", $2);
00710         }
00711     ;
00712 
00713 clause
00714     : callable_term clause_body     { $$ = binary_term(":-", $1, $2); }
00715     ;
00716 
00717 clause_body
00718     : K_DOT_TERMINATOR              { $$ = context->true_atom; }
00719     | compound_statement            { $$ = $1; }
00720     | K_SHIFT_LEFT confidence K_SHIFT_RIGHT K_DOT_TERMINATOR {
00721             $$ = unary_term("$$fuzzy", $2);
00722         }
00723     | K_SHIFT_LEFT confidence K_SHIFT_RIGHT compound_statement {
00724             $$ = binary_term(",", unary_term("$$fuzzy", $2), $4);
00725         }
00726     ;
00727 
00728 confidence
00729     : K_INTEGER                     { $$ = $1; }
00730     | K_REAL                        { $$ = $1; }
00731     ;
00732 
00733 callable_term
00734     : atom                          { $$ = $1; }
00735     | atom '(' ')'                  { $$ = $1; }
00736     | atom '(' arguments ')'   {
00737             if ($1 == context->dot_atom && $3.num_args == 2) {
00738                 yyerror_printf
00739                     (&(@1), context, input_stream,
00740                      "(.)/2 cannot be used as a predicate name");
00741             }
00742             $$ = p_term_create_functor_with_args
00743                 (context, $1, $3.args, (int)($3.num_args));
00744             GC_FREE($3.args);
00745         }
00746     ;
00747 
00748 
00749 atom
00750     : K_ATOM        { $$ = $1; }
00751     | K_VAR         { $$ = p_term_create_atom(context, "var"); }
00752     | K_CATCH       { $$ = p_term_create_atom(context, "catch"); }
00753     | K_CLASS       { $$ = p_term_create_atom(context, "class"); }
00754     | K_STATIC      { $$ = p_term_create_atom(context, "static"); }
00755     | K_ABSTRACT    { $$ = p_term_create_atom(context, "abstract"); }
00756     ;
00757 
00758 arguments
00759     : arguments ',' head_argument_term   {
00760             $$ = $1;
00761             if ($$.num_args > $$.max_args) {
00762                 $$.max_args *= 2;
00763                 $$.args = GC_REALLOC($$.args, sizeof(p_term *) * $$.max_args);
00764             }
00765             $$.args[($$.num_args)++] = $3;
00766         }
00767     | head_argument_term {
00768             $$.args = GC_MALLOC(sizeof(p_term *) * 4);
00769             $$.args[0] = $1;
00770             $$.num_args = 1;
00771             $$.max_args = 4;
00772         }
00773     ;
00774 
00775 head_argument_term
00776     : K_IN argument_term        { $$ = unary_term("in", $2); }
00777     | argument_term             { $$ = $1; }
00778     ;
00779 
00780 bracketed_term
00781     : term                      { $$ = $1; }
00782     | term K_COLON_DASH term    { $$ = binary_term(":-", $1, $3); }
00783     | term K_DARROW term        { $$ = binary_term("-->", $1, $3); }
00784     | K_COLON_DASH term         { $$ = unary_term(":-", $2); }
00785     | K_QUEST_DASH term         { $$ = unary_term("?-", $2); }
00786     ;
00787 
00788 term
00789     : term K_EQUIV implies_term { $$ = binary_term("<=>", $1, $3); }
00790     | implies_term              { $$ = $1; }
00791     ;
00792 
00793 implies_term
00794     : implies_term K_IMPLIES or_term  {
00795             $$ = binary_term("=>", $1, $3);
00796         }
00797     | or_term                   { $$ = $1; }
00798     ;
00799 
00800 or_term
00801     : or_term K_OR if_term      { $$ = binary_term("||", $1, $3); }
00802     | if_term                   { $$ = $1; }
00803     ;
00804 
00805 if_term
00806     : and_term K_ARROW if_term  {
00807             $$ = binary_term("->", finalize_r_list($1), $3);
00808         }
00809     | and_term                  { $$ = finalize_r_list($1); }
00810     ;
00811 
00812 and_term
00813     : and_term K_AND not_term   { append_r_list($$, $1, $3, "&&"); }
00814     | and_term ',' not_term     { append_r_list($$, $1, $3, ","); }
00815     | not_term                  { create_r_list($$, $1); }
00816     ;
00817 
00818 argument_term
00819     : argument_term K_EQUIV argument_implies_term {
00820             $$ = binary_term("<=>", $1, $3);
00821         }
00822     | argument_implies_term     { $$ = $1; }
00823     ;
00824 
00825 argument_implies_term
00826     : argument_implies_term K_IMPLIES argument_or_term {
00827             $$ = binary_term("=>", $1, $3);
00828         }
00829     | argument_or_term          { $$ = $1; }
00830     ;
00831 
00832 argument_or_term
00833     : argument_or_term K_OR argument_and_term {
00834             $$ = binary_term("||", $1, finalize_r_list($3));
00835         }
00836     | argument_and_term         { $$ = finalize_r_list($1); }
00837     ;
00838 
00839 argument_and_term
00840     : argument_and_term K_AND not_term { append_r_list($$, $1, $3, "&&"); }
00841     | not_term                  { create_r_list($$, $1); }
00842     ;
00843 
00844 not_term
00845     : K_NOT not_term            { $$ = unary_term("!", $2); }
00846     | '!' not_term              { $$ = unary_term("!", $2); }
00847     | compare_term              { $$ = $1; }
00848     ;
00849 
00850 compare_term
00851     : additive_term '=' additive_term   {
00852             $$ = binary_term("=", $1, $3);
00853         }
00854     | additive_term K_NE additive_term  {
00855             $$ = binary_term("!=", $1, $3);
00856         }
00857     | additive_term K_TERM_EQ additive_term {
00858             $$ = binary_term("==", $1, $3);
00859         }
00860     | additive_term K_TERM_NE additive_term {
00861             $$ = binary_term("!==", $1, $3);
00862         }
00863     | additive_term K_TERM_LT additive_term {
00864             $$ = binary_term("@<", $1, $3);
00865         }
00866     | additive_term K_TERM_LE additive_term {
00867             $$ = binary_term("@<=", $1, $3);
00868         }
00869     | additive_term K_TERM_GT additive_term {
00870             $$ = binary_term("@>", $1, $3);
00871         }
00872     | additive_term K_TERM_GE additive_term {
00873             $$ = binary_term("@>=", $1, $3);
00874         }
00875     | additive_term K_UNIV additive_term {
00876             $$ = binary_term("=..", $1, $3);
00877         }
00878     | additive_term K_IS additive_term {
00879             $$ = binary_term("is", $1, $3);
00880         }
00881     | additive_term K_NUM_EQ additive_term {
00882             $$ = binary_term("=:=", $1, $3);
00883         }
00884     | additive_term K_NUM_NE additive_term {
00885             $$ = binary_term("=!=", $1, $3);
00886         }
00887     | additive_term K_NUM_LT additive_term {
00888             $$ = binary_term("<", $1, $3);
00889         }
00890     | additive_term K_NUM_LE additive_term {
00891             $$ = binary_term("<=", $1, $3);
00892         }
00893     | additive_term K_NUM_GT additive_term {
00894             $$ = binary_term(">", $1, $3);
00895         }
00896     | additive_term K_NUM_GE additive_term {
00897             $$ = binary_term(">=", $1, $3);
00898         }
00899     | additive_term K_IN additive_term {
00900             $$ = binary_term("in", $1, $3);
00901         }
00902     | additive_term K_GETS additive_term {
00903             $$ = binary_term(":=", $1, $3);
00904         }
00905     | additive_term K_BT_GETS additive_term {
00906             $$ = binary_term(":==", $1, $3);
00907         }
00908     | additive_term K_NUM_GETS additive_term {
00909             $$ = binary_term("::=", $1, $3);
00910         }
00911     | additive_term K_NUM_BT_GETS additive_term {
00912             $$ = binary_term("::==", $1, $3);
00913         }
00914     | additive_term     { $$ = $1; }
00915     ;
00916 
00917 additive_term
00918     : additive_term '+' multiplicative_term {
00919             $$ = binary_term("+", $1, $3);
00920         }
00921     | additive_term '-' multiplicative_term {
00922             $$ = binary_term("-", $1, $3);
00923         }
00924     | additive_term K_BITWISE_AND multiplicative_term {
00925             $$ = binary_term("/\\", $1, $3);
00926         }
00927     | additive_term K_BITWISE_OR multiplicative_term {
00928             $$ = binary_term("\\/", $1, $3);
00929         }
00930     | multiplicative_term   { $$ = $1; }
00931     ;
00932 
00933 multiplicative_term
00934     : multiplicative_term '*' power_term {
00935             $$ = binary_term("*", $1, $3);
00936         }
00937     | multiplicative_term '/' power_term {
00938             $$ = binary_term("/", $1, $3);
00939         }
00940     | multiplicative_term '%' power_term {
00941             $$ = binary_term("%", $1, $3);
00942         }
00943     | multiplicative_term K_MOD power_term {
00944             $$ = binary_term("mod", $1, $3);
00945         }
00946     | multiplicative_term K_REM power_term {
00947             $$ = binary_term("rem", $1, $3);
00948         }
00949     | multiplicative_term K_SHIFT_LEFT power_term {
00950             $$ = binary_term("<<", $1, $3);
00951         }
00952     | multiplicative_term K_SHIFT_RIGHT power_term {
00953             $$ = binary_term(">>", $1, $3);
00954         }
00955     | multiplicative_term K_USHIFT_RIGHT power_term {
00956             $$ = binary_term(">>>", $1, $3);
00957         }
00958     | power_term    { $$ = $1; }
00959     ;
00960 
00961 power_term
00962     : unary_term K_EXP unary_term {
00963             $$ = binary_term("**", $1, $3);
00964         }
00965     | unary_term '^' power_term {
00966             $$ = binary_term("^", $1, $3);
00967         }
00968     | unary_term    { $$ = $1; }
00969     ;
00970 
00971 unary_term
00972     : '-' unary_term                { $$ = unary_term("-", $2); }
00973     | K_BITWISE_NOT unary_term      { $$ = unary_term("~", $2); }
00974     | '~' unary_term                { $$ = unary_term("~", $2); }
00975     | primary_term                  { $$ = $1; }
00976     ;
00977 
00978 primary_term
00979     : atom                      { $$ = $1; }
00980     | K_INTEGER                 { $$ = $1; }
00981     | K_REAL                    { $$ = $1; }
00982     | K_STRING                  { $$ = $1; }
00983     | K_VARIABLE                { $$ = $1; }
00984     | '!'    {
00985             $$ = p_term_create_atom(context, "!");
00986         }
00987     | atom '(' arguments ')'  {
00988             if ($1 == context->dot_atom && $3.num_args == 2) {
00989                 $$ = p_term_create_list
00990                     (context, $3.args[0], $3.args[1]);
00991             } else {
00992                 $$ = p_term_create_functor_with_args
00993                     (context, $1, $3.args, (int)($3.num_args));
00994             }
00995             GC_FREE($3.args);
00996         }
00997     | atom '(' ')'              { $$ = $1; }
00998     | '[' ']'                   { $$ = p_term_nil_atom(context); }
00999     | '[' list_members ']'      { $$ = finalize_list($2); }
01000     | '[' list_members '|' term ']' { $$ = finalize_list_tail($2, $4); }
01001     | '(' bracketed_term ')'    { $$ = $2; }
01002     | member_reference          {
01003             $$ = p_term_create_member_variable
01004                 (context, $1.object, $1.name, $1.auto_create);
01005         }
01006     | member_reference '(' arguments ')'    {
01007             
01008             p_term *term = p_term_create_functor
01009                 (context, p_term_create_atom(context, "$$"),
01010                  (int)($3.num_args + 1));
01011             size_t index;
01012             p_term_bind_functor_arg(term, 0, $1.object);
01013             for (index = 0; index < $3.num_args; ++index) {
01014                 p_term_bind_functor_arg
01015                     (term, (int)(index + 1), $3.args[index]);
01016             }
01017             GC_FREE($3.args);
01018             $$ = p_term_create_functor
01019                 (context, p_term_create_atom
01020                     (context, "$$call_member"), 2);
01021             p_term_bind_functor_arg
01022                 ($$, 0, p_term_create_member_variable
01023                     (context, $1.object, $1.name, $1.auto_create));
01024             p_term_bind_functor_arg($$, 1, term);
01025         }
01026     | member_reference '(' ')'  {
01027             
01028             p_term *term = p_term_create_functor
01029                 (context, p_term_create_atom(context, "$$"), 1);
01030             p_term_bind_functor_arg(term, 0, $1.object);
01031             $$ = p_term_create_functor
01032                 (context, p_term_create_atom
01033                     (context, "$$call_member"), 2);
01034             p_term_bind_functor_arg
01035                 ($$, 0, p_term_create_member_variable
01036                     (context, $1.object, $1.name, $1.auto_create));
01037             p_term_bind_functor_arg($$, 1, term);
01038         }
01039     | new_term                  { $$ = $1; }
01040     ;
01041 
01042 list_members
01043     : list_members ',' argument_term    { append_list($$, $1, $3); }
01044     | argument_term                     { create_list($$, $1); }
01045     ;
01046 
01047 member_reference
01048     : K_VARIABLE '.' atom     {
01049             $$.object = $1;
01050             $$.name = $3;
01051             $$.auto_create = 0;
01052         }
01053     | K_VARIABLE K_DOT_DOT atom   {
01054             $$.object = $1;
01055             $$.name = $3;
01056             $$.auto_create = 1;
01057         }
01058     | member_reference '.' atom   {
01059             $$.object = p_term_create_member_variable
01060                 (context, $1.object, $1.name, $1.auto_create);
01061             $$.name = $3;
01062             $$.auto_create = 0;
01063         }
01064     | member_reference K_DOT_DOT atom {
01065             $$.object = p_term_create_member_variable
01066                 (context, $1.object, $1.name, $1.auto_create);
01067             $$.name = $3;
01068             $$.auto_create = 1;
01069         }
01070     ;
01071 
01072 new_term
01073     : K_NEW atom '(' arguments ')' {
01074             
01075 
01076 
01077             p_term *obj = $4.args[0];
01078             p_term *call_new = p_term_create_functor
01079                 (context, p_term_create_atom(context, "$$new"), 2);
01080             p_term *ctor_name = p_term_create_member_name
01081                 (context, $2, p_term_create_atom(context, "new"));
01082             p_term *call_ctor = p_term_create_functor_with_args
01083                 (context, ctor_name, $4.args, (int)($4.num_args));
01084             GC_FREE($4.args);
01085             p_term_bind_functor_arg(call_new, 0, $2);
01086             p_term_bind_functor_arg(call_new, 1, obj);
01087             $$ = binary_term(",", call_new, call_ctor);
01088         }
01089     ;
01090 
01091 statements
01092     : statements statement  {
01093             p_term *stmt = add_debug(@2, $2);
01094             append_r_list($$, $1, stmt, ",");
01095         }
01096     | statement             {
01097             p_term *stmt = add_debug(@1, $1);
01098             create_r_list($$, stmt);
01099         }
01100     ;
01101 
01102 statement
01103     : argument_term ';'     { $$ = $1; }
01104     | if_statement          { $$ = $1; }
01105     | compound_statement    { $$ = $1; }
01106     | loop_statement        { $$ = $1; }
01107     | try_statement         { $$ = $1; }
01108     | switch_statement      { $$ = $1; }
01109     | ';'       {
01110             $$ = add_debug(@1, context->true_atom);
01111         }
01112     ;
01113 
01114 if_statement
01115     : K_IF condition statement     {
01116             
01117             p_term *if_stmt = p_term_create_functor
01118                 (context, p_term_create_atom(context, "->"), 2);
01119             p_term_bind_functor_arg(if_stmt, 0, $2);
01120             p_term_bind_functor_arg(if_stmt, 1, $3);
01121             $$ = p_term_create_functor
01122                 (context, p_term_create_atom(context, "||"), 2);
01123             p_term_bind_functor_arg($$, 0, if_stmt);
01124             p_term_bind_functor_arg($$, 1, context->true_atom);
01125         }
01126     | K_IF condition statement K_ELSE statement {
01127             
01128             p_term *if_stmt = p_term_create_functor
01129                 (context, p_term_create_atom(context, "->"), 2);
01130             p_term_bind_functor_arg(if_stmt, 0, $2);
01131             p_term_bind_functor_arg(if_stmt, 1, $3);
01132             $$ = p_term_create_functor
01133                 (context, p_term_create_atom(context, "||"), 2);
01134             p_term_bind_functor_arg($$, 0, if_stmt);
01135             p_term_bind_functor_arg($$, 1, $5);
01136         }
01137     ;
01138 
01139 condition
01140     : '(' term ')'          { $$ = $2; }
01141     | '(' error ')'         { $$ = context->fail_atom; }
01142     ;
01143 
01144 compound_statement
01145     : '{' statements '}'    { $$ = finalize_r_list($2); }
01146     | '{' '}'               { $$ = context->true_atom; }
01147     | '{' error '}'         { $$ = context->true_atom; }
01148     ;
01149 
01150 loop_statement
01151     : K_WHILE unbind_vars condition statement   {
01152             if ($2 == p_term_nil_atom(context))
01153                 $$ = binary_term("$$while", $3, $4);
01154             else
01155                 $$ = ternary_term("$$while", $2, $3, $4);
01156         }
01157     | K_DO unbind_vars compound_statement K_WHILE condition ';' {
01158             if ($2 == p_term_nil_atom(context))
01159                 $$ = binary_term("$$do", $3, $5);
01160             else
01161                 $$ = ternary_term("$$do", $2, $3, $5);
01162         }
01163     | K_FOR unbind_vars '(' K_VARIABLE  {
01164             if (p_term_lex_variable_count(input_stream, $4) > 1) {
01165                 
01166 
01167                 yyerror_printf
01168                     (&(@4), context, input_stream,
01169                      "for loop variable `%s' has been referenced previously",
01170                      p_term_name($4));
01171             }
01172         }
01173       K_IN primary_term ')' statement  {
01174             $$ = p_term_create_functor
01175                 (context, p_term_create_atom(context, "$$for"), 4);
01176             p_term_bind_functor_arg($$, 0, $2);
01177             p_term_bind_functor_arg($$, 1, unary_term("$$loopvar", $4));
01178             p_term_bind_functor_arg($$, 2, $7);
01179             p_term_bind_functor_arg($$, 3, $9);
01180         }
01181     ;
01182 
01183 unbind_vars
01184     : '[' unbind_var_list ']'   { $$ = finalize_list($2); }
01185     | '[' ']'                   { $$ = p_term_nil_atom(context); }
01186     |                { $$ = p_term_nil_atom(context); }
01187     ;
01188 
01189 unbind_var_list
01190     : unbind_var_list ',' K_VARIABLE    { append_list($$, $1, $3); }
01191     | K_VARIABLE                        { create_list($$, $1); }
01192     ;
01193 
01194 try_statement
01195     : K_TRY compound_statement catch_clauses    {
01196             $$ = binary_term("$$try", $2, finalize_list($3));
01197         }
01198     ;
01199 
01200 catch_clauses
01201     : catch_clauses catch_clause        { append_list($$, $1, $2); }
01202     | catch_clause                      { create_list($$, $1); }
01203     ;
01204 
01205 catch_clause
01206     : K_CATCH '(' argument_term ')' compound_statement  {
01207             $$ = binary_term("$$catch", $3, $5);
01208         }
01209     ;
01210 
01211 switch_statement
01212     : K_SWITCH '(' argument_term ')' '{' switch_body '}' {
01213             $$ = ternary_term
01214                 ("$$switch", $3, $6.case_list, $6.default_case);
01215         }
01216     ;
01217 
01218 switch_body
01219     : switch_cases      {
01220             $$.case_list = finalize_list($1);
01221             if ($1.default_case)
01222                 $$.default_case = $1.default_case;
01223             else
01224                 $$.default_case = context->fail_atom;
01225         }
01226     |        {
01227             $$.case_list = p_term_nil_atom(context);
01228             $$.default_case = context->fail_atom;
01229         }
01230     ;
01231 
01232 switch_cases
01233     : switch_cases switch_case  {
01234             append_lists($$, $1, $2);
01235             if ($1.is_default) {
01236                 $$.default_case = $1.default_case;
01237                 if ($1.is_default == 2 || $2.is_default == 2) {
01238                     
01239                     $$.is_default = 2;
01240                 } else if ($1.is_default && $2.is_default) {
01241                     yyerror_printf
01242                         (&(@2), context, input_stream,
01243                          "multiple `default' cases in `switch'");
01244                     $$.is_default = 2;
01245                 } else {
01246                     $$.is_default = $1.is_default;
01247                 }
01248             } else if ($2.is_default) {
01249                 $$.default_case = $2.default_case;
01250                 $$.is_default = $2.is_default;
01251             } else {
01252                 $$.default_case = 0;
01253                 $$.is_default = 0;
01254             }
01255         }
01256     | switch_case               { $$ = $1; }
01257     ;
01258 
01259 switch_case
01260     : case_labels statement     {
01261             p_term *case_list = finalize_list($1);
01262             if (case_list != context->nil_atom) {
01263                 p_term *term = p_term_create_functor
01264                     (context, p_term_create_atom(context, "$$case"), 2);
01265                 p_term_bind_functor_arg(term, 0, case_list);
01266                 p_term_bind_functor_arg(term, 1, $2);
01267                 create_list($$, term);
01268             } else {
01269                 create_empty_list($$);
01270             }
01271             if ($1.is_default) {
01272                 $$.default_case = $2;
01273                 $$.is_default = $1.is_default;
01274             } else {
01275                 $$.default_case = 0;
01276                 $$.is_default = 0;
01277             }
01278         }
01279     ;
01280 
01281 case_labels
01282     : case_labels case_label    {
01283                 if ($2.is_default) {
01284                     append_lists($$, $1, $2);
01285                     if ($1.is_default) {
01286                         yyerror_printf
01287                             (&(@2), context, input_stream,
01288                              "multiple `default' cases in `switch'");
01289                         $$.is_default = 2;
01290                     } else {
01291                         $$.is_default = 1;
01292                     }
01293                 } else {
01294                     append_lists($$, $1, $2);
01295                     $$.is_default = $1.is_default;
01296                 }
01297             }
01298     | case_label                { $$ = $1; }
01299     ;
01300 
01301 case_label
01302     : K_CASE argument_term ':'  {
01303             create_list($$, $2);
01304             $$.is_default = 0;
01305         }
01306     | K_DEFAULT ':'             {
01307             create_empty_list($$);
01308             $$.is_default = 1;
01309         }
01310     ;
01311 
01312 class_declaration
01313     : K_CLASS atom      {
01314             input_stream->class_name = $2;
01315         } opt_parent class_body opt_semi    {
01316             p_term *clauses = $5.clauses;
01317             if (!($5.has_constructor)) {
01318                 
01319                 p_term *ctor = create_clause_head
01320                     (context, input_stream,
01321                      p_term_create_atom(context, "new"), 0, 0, 0);
01322                 ctor = binary_term(":-", ctor, context->true_atom);
01323                 ctor = ternary_term
01324                     ("clause",
01325                      p_term_create_atom(context, "new"),
01326                      p_term_create_atom(context, "constructor"),
01327                      ctor);
01328                 ctor = add_debug(@2, ctor);
01329                 clauses = p_term_create_list(context, ctor, clauses);
01330                 clear_variables();
01331             }
01332             $$ = make_class_declaration
01333                 (context, $2, $4, $5.vars, clauses);
01334             input_stream->class_name = 0;
01335         }
01336     ;
01337 
01338 opt_parent
01339     :            { $$ = p_term_nil_atom(context); }
01340     | ':' '[' ']'           { $$ = p_term_nil_atom(context); }
01341     | ':' atom              { $$ = $2; }
01342     ;
01343 
01344 opt_semi
01345     : 
01346     | ';'
01347     ;
01348 
01349 class_body
01350     : '{' class_members '}' {
01351             $$.vars = finalize_list($2.vars);
01352             $$.clauses = finalize_list($2.clauses);
01353             $$.has_constructor = $2.has_constructor;
01354         }
01355     | '{' '}'   {
01356             $$.vars = p_term_nil_atom(context);
01357             $$.clauses = p_term_nil_atom(context);
01358             $$.has_constructor = 0;
01359         }
01360     | '{' error '}' {
01361             $$.vars = p_term_nil_atom(context);
01362             $$.clauses = p_term_nil_atom(context);
01363             $$.has_constructor = 0;
01364         }
01365     ;
01366 
01367 class_members
01368     : class_members class_member    {
01369             append_lists($$.vars, $1.vars, $2.vars);
01370             append_lists($$.clauses, $1.clauses, $2.clauses);
01371             $$.has_constructor =
01372                 ($1.has_constructor || $2.has_constructor);
01373         }
01374     | class_member                  { $$ = $1; }
01375     ;
01376 
01377 class_member
01378     : K_VAR member_vars opt_semi    {
01379             $$.vars.l_head = $2.l_head;
01380             $$.vars.l_tail = $2.l_tail;
01381             create_empty_list($$.clauses);
01382             $$.has_constructor = 0;
01383         }
01384     | member_clause {
01385             p_term *clause = ternary_term
01386                 ("clause", $1.name, $1.kind,
01387                  binary_term(":-", $1.head, $1.body));
01388             clause = add_debug(@1, clause);
01389             create_empty_list($$.vars);
01390             create_list($$.clauses, clause);
01391             $$.has_constructor = $1.has_constructor;
01392             clear_variables();
01393         }
01394     ;
01395 
01396 member_clause
01397     : member_clause_head clause_body    {
01398             $$ = $1;
01399             $$.body = $2;
01400         }
01401     | K_ABSTRACT regular_member_clause_head K_DOT_TERMINATOR {
01402             
01403 
01404             p_term *pred;
01405             p_term *error;
01406             pred = p_term_create_functor
01407                 (context, context->slash_atom, 2);
01408             p_term_bind_functor_arg(pred, 0, p_term_functor($2.head));
01409             p_term_bind_functor_arg
01410                 (pred, 1, p_term_create_integer
01411                     (context, p_term_arg_count($2.head)));
01412             error = binary_term
01413                 ("existence_error",
01414                  p_term_create_atom(context, "member_predicate"), pred);
01415             error = binary_term("error", error, pred);
01416             $$ = $2;
01417             $$.body = unary_term("throw", error);
01418         }
01419     ;
01420 
01421 member_clause_head
01422     : regular_member_clause_head                { $$ = $1; }
01423     | K_STATIC member_name                      {
01424             $$.name = $2;
01425             $$.kind = p_term_create_atom(context, "static");
01426             $$.head = create_clause_head
01427                 (context, input_stream, $2, 0, 0, 1);
01428             $$.body = 0;
01429             $$.has_constructor = 0;
01430         }
01431     | K_STATIC member_name '(' ')'              {
01432             $$.name = $2;
01433             $$.kind = p_term_create_atom(context, "static");
01434             $$.head = create_clause_head
01435                 (context, input_stream, $2, 0, 0, 1);
01436             $$.body = 0;
01437             $$.has_constructor = 0;
01438         }
01439     | K_STATIC member_name '(' arguments ')'    {
01440             $$.name = $2;
01441             $$.kind = p_term_create_atom(context, "static");
01442             $$.head = create_clause_head
01443                 (context, input_stream, $2, $4.args, $4.num_args, 1);
01444             $$.body = 0;
01445             $$.has_constructor = 0;
01446         }
01447     | K_NEW                                     {
01448             $$.name = p_term_create_atom(context, "new");
01449             $$.kind = p_term_create_atom(context, "constructor");
01450             $$.head = create_clause_head
01451                 (context, input_stream,
01452                  p_term_create_atom(context, "new"), 0, 0, 0);
01453             $$.body = 0;
01454             $$.has_constructor = 1;
01455         }
01456     | K_NEW '(' ')'                             {
01457             $$.name = p_term_create_atom(context, "new");
01458             $$.kind = p_term_create_atom(context, "constructor");
01459             $$.head = create_clause_head
01460                 (context, input_stream,
01461                  p_term_create_atom(context, "new"), 0, 0, 0);
01462             $$.body = 0;
01463             $$.has_constructor = 1;
01464         }
01465     | K_NEW '(' arguments ')'                   {
01466             $$.name = p_term_create_atom(context, "new");
01467             $$.kind = p_term_create_atom(context, "constructor");
01468             $$.head = create_clause_head
01469                 (context, input_stream,
01470                  p_term_create_atom(context, "new"),
01471                  $3.args, $3.num_args, 0);
01472             $$.body = 0;
01473             $$.has_constructor = 1;
01474         }
01475     ;
01476 
01477 regular_member_clause_head
01478     : member_name                               {
01479             $$.name = $1;
01480             $$.kind = p_term_create_atom(context, "member");
01481             $$.head = create_clause_head
01482                 (context, input_stream, $1, 0, 0, 0);
01483             $$.body = 0;
01484             $$.has_constructor = 0;
01485         }
01486     | member_name '(' ')'                       {
01487             $$.name = $1;
01488             $$.kind = p_term_create_atom(context, "member");
01489             $$.head = create_clause_head
01490                 (context, input_stream, $1, 0, 0, 0);
01491             $$.body = 0;
01492             $$.has_constructor = 0;
01493         }
01494     | member_name '(' arguments ')'             {
01495             $$.name = $1;
01496             $$.kind = p_term_create_atom(context, "member");
01497             $$.head = create_clause_head
01498                 (context, input_stream, $1, $3.args, $3.num_args, 0);
01499             $$.body = 0;
01500             $$.has_constructor = 0;
01501         }
01502     ;
01503 
01504 member_vars
01505     : member_vars ',' member_var    { append_list($$, $1, $3); }
01506     | member_var                    { create_list($$, $1); }
01507     ;
01508 
01509 member_var
01510     : member_name                   { $$ = add_debug(@1, $1); }
01511     ;
01512 
01513 member_name
01514     : atom          {
01515             if ($1 == context->class_name_atom ||
01516                     $1 == context->prototype_atom) {
01517                 yyerror_printf
01518                     (&(@1), context, input_stream,
01519                      "`%s' is not allowed as a member name",
01520                      p_term_name($1));
01521             }
01522             $$ = $1;
01523         }
01524     ;
01525 
01526 dcg_clause
01527     : callable_term K_DARROW dcg_body K_DOT_TERMINATOR {
01528             $$ = p_term_expand_dcg(context, binary_term("-->", $1, $3));
01529         }
01530     | callable_term K_DARROW dcg_body K_SHIFT_LEFT confidence
01531         K_SHIFT_RIGHT K_DOT_TERMINATOR {
01532             p_term *body = unary_term("{}", unary_term("$$fuzzy", $5));
01533             body = binary_term(",", $3, body);
01534             $$ = p_term_expand_dcg
01535                 (context, binary_term("-->", $1, body));
01536         }
01537     ;
01538 
01539 dcg_body
01540     : dcg_body K_OR dcg_term        {
01541             $$ = binary_term("||", $1, finalize_r_list($3));
01542         }
01543     | dcg_term                      {
01544             $$ = finalize_r_list($1);
01545         }
01546     ;
01547 
01548 dcg_term
01549     : dcg_term ',' dcg_unary_term   { append_r_list($$, $1, $3, ","); }
01550     | dcg_unary_term                { create_r_list($$, $1); }
01551     ;
01552 
01553 dcg_unary_term
01554     : '!' dcg_primitive_term    { $$ = unary_term("!", $2); }
01555     | dcg_primitive_term        { $$ = $1; }
01556     ;
01557 
01558 dcg_primitive_term
01559     : callable_term             { $$ = $1; }
01560     | compound_statement        { $$ = unary_term("{}", $1); }
01561     | '[' ']'                   { $$ = context->nil_atom; }
01562     | '[' list_members ']'      { $$ = finalize_list($2); }
01563     | K_STRING                  { $$ = $1; }
01564     | '(' dcg_body ')'          { $$ = $2; }
01565     | '!'                       { $$ = context->commit_atom; }
01566     ;