home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / library / os2 / remind / src / userfns.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-12  |  11.7 KB  |  401 lines

  1. /***************************************************************/
  2. /*                                                             */
  3. /*  USERFNS.C                                                  */
  4. /*                                                             */
  5. /*  This file contains the routines to support user-defined    */
  6. /*  functions.                                                 */
  7. /*                                                             */
  8. /*  This file is part of REMIND.                               */
  9. /*  Copyright (C) 1992, 1993 by David F. Skoll.                */
  10. /*                                                             */
  11. /***************************************************************/
  12. #include "config.h"
  13. #include <stdio.h>
  14. #ifdef HAVE_STDLIB_H
  15. #include <stdlib.h>
  16. #endif
  17. #ifdef HAVE_MALLOC_H
  18. #include <malloc.h>
  19. #endif
  20. #include <ctype.h>
  21. #include "types.h"
  22. #include "globals.h"
  23. #include "protos.h"
  24. #include "err.h"
  25. #include "expr.h"
  26.  
  27. #define FUNC_HASH_SIZE 32   /* Size of User-defined function hash table */
  28.  
  29. /* Define the data structure used to hold a user-defined function */
  30. typedef struct udf_struct {
  31.    struct udf_struct *next;
  32.    char name[VAR_NAME_LEN+1];
  33.    char *text;
  34.    Var *locals;
  35.    char IsCached;
  36.    char IsActive;
  37.    int nargs;
  38. } UserFunc;
  39.  
  40. /* The hash table */
  41. static UserFunc *FuncHash[FUNC_HASH_SIZE];
  42.  
  43. /* Access to built-in functions */
  44. extern int NumFuncs;
  45. extern Operator Func[];
  46.  
  47. /* We need access to the expression evaluation stack */
  48. extern Value ValStack[];
  49. extern int ValStackPtr;
  50.  
  51. PRIVATE void DestroyUserFunc ARGS ((UserFunc *f));
  52. PRIVATE void FUnset ARGS ((char *name));
  53. PRIVATE void FSet ARGS ((UserFunc *f));
  54. PRIVATE int SetUpLocalVars ARGS ((UserFunc *f));
  55. PRIVATE void DestroyLocalVals ARGS ((UserFunc *f));
  56.  
  57. /***************************************************************/
  58. /*                                                             */
  59. /*  DoFset                                                     */
  60. /*                                                             */
  61. /*  Define a user-defined function - the FSET command.         */
  62. /*                                                             */
  63. /***************************************************************/
  64. #ifdef HAVE_PROTOS
  65. PUBLIC int DoFset(ParsePtr p)
  66. #else
  67. int DoFset(p)
  68. ParsePtr p;
  69. #endif
  70. {
  71.    int r;
  72.    int c;
  73.    UserFunc *func;
  74.    Var *v;
  75.  
  76.    /* Get the function name */
  77.    if ( (r=ParseIdentifier(p, TokBuffer)) ) return r;
  78.    if (*TokBuffer == '$') return E_BAD_ID;
  79.  
  80.    /* Should be followed by '(' */
  81.    c = ParseNonSpaceChar(p, &r, 0);
  82.    if (r) return r;
  83.    if (c != '(') return E_PARSE_ERR;
  84.  
  85.    func = NEW(UserFunc);
  86.    if (!func) return E_NO_MEM;
  87.    StrnCpy(func->name, TokBuffer, VAR_NAME_LEN);
  88.    if (!Hush) {
  89.       if (FindFunc(TokBuffer, Func, NumFuncs)) {
  90.          Eprint("%s: '%s'", ErrMsg[E_REDEF_FUNC],
  91.              TokBuffer);
  92.       }
  93.    }
  94.    func->locals = NULL;
  95.    func->text = NULL;
  96.    func->IsCached = 1;
  97.    func->IsActive = 0;
  98.    func->nargs = 0;
  99.  
  100.    /* Get the local variables - we insert the local variables in REVERSE
  101.       order, but that's OK, because we pop them off the stack in reverse
  102.       order, too, so everything works out just fine. */
  103.  
  104.    c=ParseNonSpaceChar(p, &r, 1);
  105.    if (r) return r;
  106.    if (c == ')') {
  107.       (void) ParseNonSpaceChar(p, &r, 0);
  108.    }
  109.    else {
  110.       while(1) {
  111.      if ( (r=ParseIdentifier(p, TokBuffer)) ) return r;
  112.          if (*TokBuffer == '$') return E_BAD_ID;
  113.      v = NEW(Var);
  114.      func->nargs++;
  115.      v->v.type = ERR_TYPE;
  116.      if (!v) {
  117.         DestroyUserFunc(func);
  118.         return E_NO_MEM;
  119.      }
  120.      StrnCpy(v->name, TokBuffer, VAR_NAME_LEN);
  121.      v->next = func->locals;
  122.      func->locals = v;
  123.      c = ParseNonSpaceChar(p, &r, 0);
  124.      if (c == ')') break;
  125.      else if (c != ',') {
  126.         DestroyUserFunc(func);
  127.         return E_PARSE_ERR;
  128.      }
  129.       }
  130.    }
  131.  
  132.    /* Copy the text over */
  133.    if (p->isnested) {
  134.       Eprint("%s", ErrMsg[E_CANTNEST_FDEF]);
  135.       DestroyUserFunc(func);
  136.       return E_PARSE_ERR;
  137.    }
  138.  
  139.    /* A bit of trickery here - if the definition is already cached,
  140.       no point in copying it. */
  141.    if (CurLine != LineBuffer) {
  142.       func->IsCached = 1;
  143.       func->text = p->pos;
  144.    } else {
  145.       func->IsCached = 0;
  146.       func->text = StrDup(p->pos);
  147.       if (!func->text) {
  148.      DestroyUserFunc(func);
  149.      return E_NO_MEM;
  150.       }
  151.    }
  152.  
  153.    /* If an old definition of this function exists, destroy it */
  154.    FUnset(func->name);
  155.  
  156.    /* Add the function definition */
  157.    FSet(func);
  158.    return OK;
  159. }
  160.  
  161. /***************************************************************/
  162. /*                                                             */
  163. /*  DestroyUserFunc                                            */
  164. /*                                                             */
  165. /*  Free up all the resources used by a user-defined function. */
  166. /*                                                             */
  167. /***************************************************************/
  168. #ifdef HAVE_PROTOS
  169. PRIVATE void DestroyUserFunc(UserFunc *f)
  170. #else
  171. static void DestroyUserFunc(f)
  172. UserFunc *f;
  173. #endif
  174. {
  175.    Var *v, *prev;
  176.  
  177.    /* Free the local variables first */
  178.    v = f->locals;
  179.    while(v) {
  180.       DestroyValue(&(v->v));
  181.       prev = v;
  182.       v = v->next;
  183.       free(prev);
  184.    }
  185.  
  186.    /* Free the function definition */
  187.    if (f->text && !f->IsCached) free(f->text);
  188.  
  189.    /* Free the data structure itself */
  190.    free(f);
  191. }
  192.  
  193. /***************************************************************/
  194. /*                                                             */
  195. /*  FUnset                                                     */
  196. /*                                                             */
  197. /*  Delete the function definition with the given name, if     */
  198. /*  it exists.                                                 */
  199. /*                                                             */
  200. /***************************************************************/
  201. #ifdef HAVE_PROTOS
  202. PRIVATE void FUnset(char *name)
  203. #else
  204. static void FUnset(name)
  205. char *name;
  206. #endif
  207. {
  208.    UserFunc *cur, *prev;
  209.    int h;
  210.  
  211.    h = HashVal(name) % FUNC_HASH_SIZE;
  212.  
  213.    cur = FuncHash[h];
  214.    prev = NULL;
  215.    while(cur) {
  216.       if (! StrinCmp(name, cur->name, VAR_NAME_LEN)) break;
  217.       prev = cur;
  218.       cur = cur->next;
  219.    }
  220.    if (!cur) return;
  221.    if (prev) prev->next = cur->next; else FuncHash[h] = cur->next;
  222.    DestroyUserFunc(cur);
  223. }
  224.  
  225. /***************************************************************/
  226. /*                                                             */
  227. /*  FSet                                                       */
  228. /*                                                             */
  229. /*  Insert a user-defined function into the hash table.        */
  230. /*                                                             */
  231. /***************************************************************/
  232. #ifdef HAVE_PROTOS
  233. PRIVATE void FSet(UserFunc *f)
  234. #else
  235. static void FSet(f)
  236. UserFunc *f;
  237. #endif
  238. {
  239.    int h = HashVal(f->name) % FUNC_HASH_SIZE;
  240.    f->next = FuncHash[h];
  241.    FuncHash[h] = f;
  242. }
  243.  
  244. /***************************************************************/
  245. /*                                                             */
  246. /*  CallUserFunc                                               */
  247. /*                                                             */
  248. /*  Call a user-defined function.                              */
  249. /*                                                             */
  250. /***************************************************************/
  251. #ifdef HAVE_PROTOS
  252. PUBLIC int CallUserFunc(char *name, int nargs)
  253. #else
  254. int CallUserFunc(name, nargs)
  255. char *name;
  256. int nargs;
  257. #endif
  258. {
  259.    UserFunc *f;
  260.    int h = HashVal(name) % FUNC_HASH_SIZE;
  261.    int i;
  262.    char *s;
  263.  
  264.    /* Search for the function */
  265.    f = FuncHash[h];
  266.    while (f && StrinCmp(name, f->name, VAR_NAME_LEN)) f = f->next;
  267.    if (!f) {
  268.       Eprint("%s: '%s'", ErrMsg[E_UNDEF_FUNC], name);
  269.       return E_UNDEF_FUNC;
  270.    }
  271.    /* Debugging stuff */
  272.    if (DebugFlag & DB_PRTEXPR) {
  273.       fprintf(ErrFp, "%s %s(", ErrMsg[E_ENTER_FUN], f->name);
  274.       for (i=0; i<nargs; i++) {
  275.          PrintValue(&ValStack[ValStackPtr - nargs + i], ErrFp);
  276.          if (i<nargs-1) fprintf(ErrFp, ", ");
  277.       }
  278.       fprintf(ErrFp, ")\n");
  279.    }
  280.    /* Detect illegal recursive call */
  281.    if (f->IsActive) {
  282.       if (DebugFlag &DB_PRTEXPR) {
  283.          fprintf(ErrFp, "%s %s() => ", ErrMsg[E_LEAVE_FUN], name);
  284.          fprintf(ErrFp, "%s\n", ErrMsg[E_RECURSIVE]);
  285.       }
  286.       return E_RECURSIVE;
  287.    }
  288.    
  289.    /* Check number of args */
  290.    if (nargs != f->nargs) {
  291.       if (DebugFlag &DB_PRTEXPR) {
  292.          fprintf(ErrFp, "%s %s() => ", ErrMsg[E_LEAVE_FUN], name);
  293.          fprintf(ErrFp, "%s\n",
  294.         ErrMsg[(nargs < f->nargs) ? E_2FEW_ARGS : E_2MANY_ARGS]);
  295.       }
  296.       return (nargs < f->nargs) ? E_2FEW_ARGS : E_2MANY_ARGS;
  297.    }
  298.    /* Found the function - set up a local variable frame */
  299.    h = SetUpLocalVars(f);
  300.    if (h) {
  301.       if (DebugFlag &DB_PRTEXPR) {
  302.          fprintf(ErrFp, "%s %s() => ", ErrMsg[E_LEAVE_FUN], name);
  303.          fprintf(ErrFp, "%s\n", ErrMsg[h]);
  304.       }
  305.       return h;
  306.    }
  307.  
  308.    /* Evaluate the expression */
  309.    f->IsActive = 1;
  310.    s = f->text;
  311.  
  312.    /* Skip the opening bracket, if there's one */
  313.    while (isspace(*s)) s++;
  314.    if (*s == BEG_OF_EXPR) s++;
  315.    h = Evaluate(&s, f->locals);
  316.    f->IsActive = 0;
  317.    DestroyLocalVals(f);
  318.    if (DebugFlag &DB_PRTEXPR) {
  319.       fprintf(ErrFp, "%s %s() => ", ErrMsg[E_LEAVE_FUN], name);
  320.       if (h) fprintf(ErrFp, "%s\n", ErrMsg[h]);
  321.       else {
  322.          PrintValue(&ValStack[ValStackPtr-1], ErrFp);
  323.          fprintf(ErrFp, "\n");
  324.       }
  325.    }
  326.    return h;
  327. }
  328.  
  329. /***************************************************************/
  330. /*                                                             */
  331. /*  SetUpLocalVars                                             */
  332. /*                                                             */
  333. /*  Set up the local variables from the stack frame.           */
  334. /*                                                             */
  335. /***************************************************************/
  336. #ifdef HAVE_PROTOS
  337. PRIVATE int SetUpLocalVars(UserFunc *f)
  338. #else
  339. static int SetUpLocalVars(f)
  340. UserFunc *f;
  341. #endif
  342. {
  343.    int i, r;
  344.    Var *var;
  345.  
  346.    for (i=0, var=f->locals; var && i<f->nargs; var=var->next, i++) {
  347.       if ( (r=PopValStack(&(var->v))) ) {
  348.      DestroyLocalVals(f);
  349.      return r;
  350.       }
  351.    }
  352.    return OK;
  353. }
  354.  
  355. /***************************************************************/
  356. /*                                                             */
  357. /*  DestroyLocalVals                                           */
  358. /*                                                             */
  359. /*  Destroy the values of all local variables after evaluating */
  360. /*  the function.                                              */
  361. /*                                                             */
  362. /***************************************************************/
  363. #ifdef HAVE_PROTOS
  364. PRIVATE void DestroyLocalVals(UserFunc *f)
  365. #else
  366. static void DestroyLocalVals(f)
  367. UserFunc *f;
  368. #endif
  369. {
  370.    Var *v = f->locals;
  371.  
  372.    while(v) {
  373.       DestroyValue(&(v->v));
  374.       v = v->next;
  375.    }
  376. }
  377. /***************************************************************/
  378. /*                                                             */
  379. /*  UserFuncExists                                             */
  380. /*                                                             */
  381. /*  Return the number of arguments accepted by the function if */
  382. /*  it is defined, or -1 if it is not defined.                 */
  383. /*                                                             */
  384. /***************************************************************/
  385. #ifdef HAVE_PROTOS
  386. PUBLIC int UserFuncExists(char *fn)
  387. #else
  388. int UserFuncExists(fn)
  389. char *fn;
  390. #endif
  391. {
  392.    UserFunc *f;
  393.    int h = HashVal(fn) % FUNC_HASH_SIZE;
  394.  
  395.    f = FuncHash[h];
  396.    while (f && StrinCmp(fn, f->name, VAR_NAME_LEN)) f = f->next;
  397.    if (!f) return -1;
  398.    else return f->nargs;
  399. }
  400.  
  401.