C:/Users/Dennis/src/lang/bertrand/BERTRAND/bertrand/primitive.c

Go to the documentation of this file.
00001 /*************************************************************
00002  *
00003  * Primitives
00004  *
00005  * Types and their supertypes:
00006  *
00007  *      positive -> nonzero -> constant
00008  *
00009  *      literal
00010  *
00011  *      false
00012  *      true
00013  *
00014  * Primitive constants (not accessible to the programmer):
00015  *
00016  *      str_prim -> literal
00017  *
00018  *      pnum_prim -> positive           (positive constants)
00019  *      znum_prim -> constant           (the constant zero)
00020  *      nnum_prim -> nonzero            (negative constants)
00021  *
00022  *      undeclared_prim         (variable not declared, prints as "'?")
00023  *      untyped_prim            (variable declared via a rule with no type)
00024  *
00025  *
00026  * Types for variables:
00027  *
00028  * A local variable is initially of type undeclared_prim.
00029  * If it labels a redex for a typed rule, the variable becomes
00030  * of that type.  for an untyped rule, it becomes of type untyped_prim.
00031  * If the local variable is not a label, or what it labels is never
00032  * reduced, then that variable stays undeclared (which the user
00033  * can see as type '?, and treat as an error).
00034  *
00035  * A parameter variable with a guard is of the type of the guard.
00036  * If no guard, then it is of type untyped_prim.
00037  * Parameters are NEVER of type undeclared_prim.
00038  *
00039  *
00040  * TO ADD YOUR OWN PRIMITIVES:
00041  *
00042  * Add the definition for your primitive operator at the end of the
00043  * routine primitive_init(), and then add the code for your primitive
00044  * at the end of the big switch statement in primitive_execute().
00045  * Your primitive operator should be nullary, even if it takes
00046  * arguments, and you should then define a regular rule that invokes
00047  * your primitive operator, and ensures that the correct arguments are
00048  * supplied.  Your primitive will be invoked immediately when this
00049  * rule is matched.  Your primitive should leave a numeric value in
00050  * answer->value, and the correct operator will be deduced, or else it
00051  * should set answer->op to be the correct operator.  If you have
00052  * problems doing this, look at how the other primitives are done,
00053  * or, failing all else, write to me for help.
00054  *
00055  *************************************************************/
00056 
00057 #include "def.h"
00058 #include <math.h>
00059 
00060 /* from graphics.c */
00061 extern int graphics;
00062 void graphics_init();
00063 void draw_line();
00064 void draw_string();
00065 
00066 OP *pnum_prim;          /* a particular positive numeric constant */
00067 OP *nnum_prim;          /* a particular negative numeric constant */
00068 OP *znum_prim;          /* the numeric constant zero */
00069 OP *str_prim;           /* a particular string constant */
00070 OP *undeclared_prim;    /* not declared yet ('?) */
00071 OP *untyped_prim;       /* declared, but untyped */
00072 
00073 OP *positive_type;      /* numeric constants greater than zero */
00074 OP *nonzero_type;       /* numeric constants not equal to zero */
00075 OP *constant_type;      /* any numeric constant */
00076 OP *literal_type;       /* string constants */
00077 /* true and false would not need to be primitives operators, except */
00078 /* that the relational primitives need to return them. */
00079 OP *true_op;            /* boolean true operator */
00080 OP *false_op;           /* boolean false operator */
00081 
00082 /*************************************************************
00083  *
00084  * Set up all the primitive operators and types.
00085  *
00086  *************************************************************/
00087 /* linked lists to put operators and types -- from ops.c */
00088 extern OP *single_op;   /* list of single-character operators */
00089 extern OP *double_op;   /* list of double-character operators */
00090 extern OP *name_op;     /* list of alphanumeric operators */
00091 extern OP *type_op;     /* list of types */
00092 
00093 /* used for a type or operator with no supertype */
00094 #define NOSUPER (OP *) NULL
00095 
00096 void
00097 primitive_init()
00098 {
00099 OP *primitive();                /* from util.c */
00100 
00101 /* primitive types and operators */
00102 constant_type = primitive("constant", OP_NAME, NOSUPER, &type_op, 0);
00103 nonzero_type = primitive("nonzero", OP_NAME, constant_type, &type_op, 0);
00104 positive_type = primitive("positive", OP_NAME, nonzero_type, &type_op, 0);
00105 literal_type = primitive("literal", OP_NAME, NOSUPER, &type_op, 0);
00106 true_op = primitive("true", NULLARY, NOSUPER, &name_op, 0);
00107 false_op = primitive("false", NULLARY, NOSUPER, &name_op, 0);
00108 
00109 pnum_prim = primitive("positive constants", OP_NUM, positive_type, NULL, 0);
00110 znum_prim = primitive("zero", OP_NUM, constant_type, NULL, 0);
00111 nnum_prim = primitive("negative constants", OP_NUM, nonzero_type, NULL, 0);
00112 str_prim = primitive("string constant", OP_STR, literal_type, NULL, 0);
00113 undeclared_prim = primitive("?", OP_NAME, NOSUPER, NULL, 0);
00114 untyped_prim = primitive("", OP_NAME, NOSUPER, NULL, 0);
00115 
00116 /* machine primitives, to execute. */
00117 /* All primitives are NULLARY, despite the fact that they take arguments. */
00118 /* Note typical usage in bops. */
00119 primitive("bind_primitive", NULLARY, NOSUPER, &name_op, 1);
00120 
00121 primitive("addition_primitive", NULLARY, NOSUPER, &name_op, 16);
00122 primitive("subtraction_primitive", NULLARY, NOSUPER, &name_op, 17);
00123 primitive("multiplication_primitive", NULLARY, NOSUPER, &name_op, 18);
00124 primitive("division_primitive", NULLARY, NOSUPER, &name_op, 19);
00125 primitive("equality_primitive", NULLARY, NOSUPER, &name_op, 20);
00126 primitive("lessthan_primitive", NULLARY, NOSUPER, &name_op, 21);
00127 primitive("lessorequal_primitive", NULLARY, NOSUPER, &name_op, 22);
00128 primitive("power_primitive", NULLARY, NOSUPER, &name_op, 23);
00129 primitive("sin_primitive", NULLARY, NOSUPER, &name_op, 24);
00130 primitive("cos_primitive", NULLARY, NOSUPER, &name_op, 25);
00131 primitive("tan_primitive", NULLARY, NOSUPER, &name_op, 26);
00132 primitive("atan_primitive", NULLARY, NOSUPER, &name_op, 27);
00133 primitive("round_primitive", NULLARY, NOSUPER, &name_op, 28);
00134 primitive("floor_primitive", NULLARY, NOSUPER, &name_op, 29);
00135 primitive("lexcompare_primitive", NULLARY, NOSUPER, &name_op, 30);
00136 primitive("trace_primitive", NULLARY, NOSUPER, &name_op, 31);
00137 
00138 primitive("line_primitive", NULLARY, NOSUPER, &name_op, 40);
00139 primitive("string_primitive", NULLARY, NOSUPER, &name_op, 41);
00140 
00141 /* USER DEFINED PRIMITIVES GO HERE */
00142 /* You might want to number your primitives starting with 64 */
00143 
00144 /* End of user defined primitives */
00145 }
00146 
00147 /*************************************************************
00148  *
00149  *  Routines to execute machine primitives
00150  *
00151  *  These primitives make assumptions about their arguments,
00152  *  which are enforced in "bops".
00153  *  Changes to bops are at the user's peril!
00154  *
00155  * After the primitive executes, the expression ex will be freed.
00156  * Therefore, any parts of it that are used in the answer must be
00157  * copied.
00158  *
00159  *************************************************************/
00160 
00161 NODE *
00162 primitive_execute(which, ex)
00163 short which;
00164 NODE *ex;
00165 {
00166 NODE *node_new();       /* from expr.c */
00167 char *arity_name();     /* from ops.c */
00168 NODE *expr_copy();      /* from expr.c */
00169 int name_compare();     /* from names.c */
00170 
00171 /* Should be set if a variable gets bound. */
00172 /* Causes all bound variables to be replaced by their value */
00173 extern int bondage;     /* from match.c */
00174 
00175 register TERM_NODE *tn = (TERM_NODE *) ex;
00176 register NODE *answer = node_new();
00177 double value;           /* numeric result */
00178 OP *bresult;            /* boolean result */
00179 
00180 answer->op = (OP *) NULL;
00181 ((TERM_NODE *)answer)->label = (NAME_NODE *) NULL;
00182 ((TERM_NODE *)answer)->right = (NODE *) NULL;
00183 ((TERM_NODE *)answer)->left = (NODE *) NULL;
00184 
00185 switch(which) {
00186  case 1:                /* bind */
00187     answer->op = true_op;
00188     if (tn->left->op->arity != OP_NAME) {
00189         fprintf(stderr, "operator: %s, arity %s\n", tn->left->op->pname,
00190             arity_name(tn->left->op->arity));
00191         error("attempt to bind a value to something other than a name");
00192         }
00193     if (((NAME_NODE *)(tn->left))->value) {
00194         fprintf(stderr, "variable: %s\n", ((NAME_NODE *)(tn->left))->pval);
00195         error("attempt to bind a value to an already bound variable");
00196         }
00197     ((NAME_NODE *)(tn->left))->value = expr_copy(tn->right);
00198     bondage = TRUE;     /* need to replace bound variable */
00199     break;
00200  case 16:               /* addition */
00201     ((NUM_NODE *)answer)->value = ((NUM_NODE *)(tn->left))->value +
00202         ((NUM_NODE *)(tn->right))->value;
00203     break;
00204  case 17:               /* subtraction */
00205     ((NUM_NODE *)answer)->value = ((NUM_NODE *)(tn->left))->value -
00206         ((NUM_NODE *)(tn->right))->value;
00207     break;
00208  case 18:               /* multiplication */
00209     ((NUM_NODE *)answer)->value = ((NUM_NODE *)tn->left)->value *
00210         ((NUM_NODE *)tn->right)->value;
00211     break;
00212  case 19:               /* division */
00213     ((NUM_NODE *)answer)->value = ((NUM_NODE *)tn->left)->value /
00214         ((NUM_NODE *)tn->right)->value;
00215     break;
00216  case 20:               /* numeric equality */
00217     answer->op = (((NUM_NODE *)tn->left)->value ==
00218         ((NUM_NODE *)tn->right)->value) ? true_op : false_op ;
00219     break;
00220  case 21:               /* numeric less than */
00221     answer->op = (((NUM_NODE *)tn->left)->value <
00222         ((NUM_NODE *)tn->right)->value) ? true_op : false_op ;
00223     break;
00224  case 22:               /* numeric less or equal */
00225     answer->op = (((NUM_NODE *)tn->left)->value <=
00226         ((NUM_NODE *)tn->right)->value) ? true_op : false_op ;
00227     break;
00228  case 23:               /* raise to power */
00229     ((NUM_NODE *)answer)->value = pow(((NUM_NODE *)tn->left)->value,
00230         ((NUM_NODE *)tn->right)->value);
00231     break;
00232  case 24:               /* sine */
00233     ((NUM_NODE *)answer)->value = sin(((NUM_NODE *)tn->right)->value);
00234     break;
00235  case 25:               /* cosine */
00236     ((NUM_NODE *)answer)->value = cos(((NUM_NODE *)tn->right)->value);
00237     break;
00238  case 26:               /* tangent */
00239     ((NUM_NODE *)answer)->value = tan(((NUM_NODE *)tn->right)->value);
00240     break;
00241  case 27:               /* arc tangent */
00242     ((NUM_NODE *)answer)->value = atan(((NUM_NODE *)tn->right)->value);
00243     break;
00244  case 28:               /* round to integer */
00245     ((NUM_NODE *)answer)->value = rint(((NUM_NODE *)tn->right)->value);
00246     break;
00247  case 29:               /* floor */
00248     ((NUM_NODE *)answer)->value = floor(((NUM_NODE *)tn->right)->value);
00249     break;
00250  case 30:               /* lexical comparison of variable names */
00251     ((NUM_NODE *)answer)->value = (double) name_compare(
00252         (NAME_NODE *)(tn->left), (NAME_NODE *)(tn->right));
00253     break;
00254  case 31:               /* trace */
00255     ((NUM_NODE *)answer)->value = verbose;
00256     verbose = (((NUM_NODE *)tn->right)->value);
00257     break;
00258  case 40:               /* draw a line */
00259     answer->op = true_op;
00260     draw_line(
00261      ((NUM_NODE *)((TERM_NODE *)((TERM_NODE *)tn->left)->left)->left)->value,
00262      ((NUM_NODE *)((TERM_NODE *)((TERM_NODE *)tn->left)->left)->right)->value,
00263      ((NUM_NODE *)((TERM_NODE *)((TERM_NODE *)tn->left)->right)->left)->value,
00264      ((NUM_NODE *)((TERM_NODE *)((TERM_NODE *)tn->left)->right)->right)->value);
00265     break;
00266  case 41:               /* draw a string centered at a location */
00267     answer->op = true_op;
00268     draw_string(
00269      ((STR_NODE *)((TERM_NODE *)tn->left)->left)->value,
00270      ((NUM_NODE *)((TERM_NODE *)((TERM_NODE *)tn->left)->right)->left)->value,
00271      ((NUM_NODE *)((TERM_NODE *)((TERM_NODE *)tn->left)->right)->right)->value);
00272     break;
00273 
00274 /* USER DEFINED PRIMITIVES GO HERE */
00275 
00276 /* End of user defined primitives */
00277 
00278  default:
00279     fprintf(stderr, "operator: %s (#%d)\n", ex->op->pname, ex->op->eval);
00280     error("invalid builtin function");
00281     }
00282 
00283 /* at this point, the operator of a boolean answer is true or false */
00284 /* the operator of a numeric answer depends on the sign of the answer */
00285 /* If a answer->op has not been assigned, assume that the answer is */
00286 /* a number, and set answer->op depending upon its sign. */
00287 if (NULL == answer->op) {       /* if null, then must be numeric */
00288     if (((NUM_NODE *)answer)->value == 0.0) answer->op = znum_prim;
00289     else answer->op = (((NUM_NODE *)answer)->value > 0.0) ?
00290         pnum_prim : nnum_prim ;
00291     }
00292 
00293 return answer;
00294 }

Generated on Fri Jan 25 09:58:43 2008 for Bertrand by  doxygen 1.5.4