[BACK]Return to interpreter.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / mg

Diff for /src/usr.bin/mg/interpreter.c between version 1.9 and 1.10

version 1.9, 2021/03/08 20:01:43 version 1.10, 2021/03/20 19:39:30
Line 35 
Line 35 
  * 1. multiline parsing - currently only single lines supported.   * 1. multiline parsing - currently only single lines supported.
  * 2. parsing for '(' and ')' throughout whole string and evaluate correctly.   * 2. parsing for '(' and ')' throughout whole string and evaluate correctly.
  * 3. conditional execution.   * 3. conditional execution.
  * 4. define single value variables (define i 0)   * 4. deal with quotes around a string: "x x"
  * 5. deal with quotes around a string: "x x"   * 5. oh so many things....
  * 6. oh so many things....  
  * [...]   * [...]
  * n. implement user definable functions.   * n. implement user definable functions.
  */   */
Line 60 
Line 59 
 static int       isvar(char **, char **, int);  static int       isvar(char **, char **, int);
 static int       foundvar(char *);  static int       foundvar(char *);
 static int       doregex(char *, char *);  static int       doregex(char *, char *);
   static int       parseexp(char *);
   static void      clearexp(void);
   
   struct expentry {
           SLIST_ENTRY(expentry) eentry;
           char    *exp;           /* The string found between paraenthesis. */
           int      par1;          /* Parenthesis at start of string (=1     */
           int      par2;          /* Parenthesis at end of string   )=2     */
           int      expctr;        /* An incremental counter:+1 for each exp */
           int      blkid;         /* Which block are we in?                 */
   };
   SLIST_HEAD(elisthead, expentry) exphead = SLIST_HEAD_INITIALIZER(exphead);
   
 /*  /*
  * Structure for variables during buffer evaluation.   * Structure for variables during buffer evaluation.
  */   */
Line 73 
Line 84 
 SLIST_HEAD(vlisthead, varentry) varhead = SLIST_HEAD_INITIALIZER(varhead);  SLIST_HEAD(vlisthead, varentry) varhead = SLIST_HEAD_INITIALIZER(varhead);
   
 /*  /*
    * Line has a '(' as the first non-white char.
    * Do some very basic parsing of line.
    * Multi-line not supported at the moment, To do.
    */
   int
   foundparen(char *funstr)
   {
           struct expentry *e1 = NULL;
           char            *p, *valp, *endp = NULL, *regs;
           char             expbuf[BUFSIZE], tmpbuf[BUFSIZE];
           int              ret, pctr, fndstart, expctr, blkid, fndchr, fndend;
   
           pctr = fndstart = expctr = fndchr = fndend = 0;
           blkid = 1;
           /*
            * Check for blocks of code with opening and closing ().
            * One block = (cmd p a r a m)
            * Two blocks = (cmd p a r a m s)(hola)
            * Two blocks = (cmd p a r (list a m s))(hola)
            * Only single line at moment, but more for multiline.
            */
           p = funstr;
   
           /*
            * Currently can't do () or (( at the moment,
            * just drop out - stops a segv. TODO.
            */
           regs = "[(]+[\t ]*[)]+";
           if (doregex(regs, funstr))
                   return(dobeep_msg("Empty lists not supported at moment"));
           regs = "[(]+[\t ]*[(]+";
           if (doregex(regs, funstr))
                   return(dobeep_msg("Multiple left parantheses found"));
           /*
            * load expressions into a list called 'expentry', to be processd
            * when all are obtained.
            * Not really live code at the moment. Just part of the process of
            * working out what needs to be done.
            */
           while (*p != '\0') {
                   if (*p == '(') {
                           if (fndstart == 1) {
                                   if (endp == NULL)
                                           *p = '\0';
                                   else
                                           *endp = '\0';
                                   e1->par2 = 1;
                                   if ((e1->exp = strndup(valp, BUFSIZE)) == NULL)
                                           return(dobeep_msg("strndup error"));
                           }
                           if ((e1 = malloc(sizeof(struct expentry))) == NULL)
                                   return (dobeep_msg("malloc Error"));
                           SLIST_INSERT_HEAD(&exphead, e1, eentry);
                           e1->exp = NULL;
                           e1->expctr = ++expctr;
                           e1->blkid = blkid;
                           e1->par1 = 1;
                           fndstart = 1;
                           fndend = 0;
                           fndchr = 0;
                           endp = NULL;
                           pctr++;
                   } else if (*p == ')') {
                           if (endp == NULL)
                                   *p = '\0';
                           else
                                   *endp = '\0';
                           if ((e1->exp = strndup(valp, BUFSIZE)) == NULL)
                                   return(dobeep_msg("strndup error"));
                           fndstart = 0;
                           pctr--;
                   } else if (*p != ' ' && *p != '\t') {
                           if (fndchr == 0) {
                                   valp = p;
                                   fndchr = 1;
                           }
                           fndend = 0;
                           endp = NULL;
                   } else if (fndend == 0 && (*p == ' ' || *p == '\t')) {
                           *p = ' ';
                           fndend = 1;
                           endp = p;
                   } else if (*p == '\t') /* need to check not between "" */
                           *p = ' ';
                   if (pctr == 0)
                           blkid++;
                   p++;
           }
           expbuf[0] = tmpbuf[0] = '\0';
   
           /*
            * Join expressions together for the moment, to progess.
            * This needs to be totally redone and
            * iterate in-to-out, evaluating as we go. Eventually.
            */
           SLIST_FOREACH(e1, &exphead, eentry) {
                   if (strlcpy(tmpbuf, expbuf, sizeof(tmpbuf)) >= sizeof(tmpbuf))
                           return (dobeep_msg("strlcpy error"));
                   expbuf[0] = '\0';
                   if (strlcpy(expbuf, e1->exp, sizeof(expbuf)) >= sizeof(expbuf))
                           return (dobeep_msg("strlcat error"));
                   if (*tmpbuf != '\0')
                           if (strlcat(expbuf, " ", sizeof(expbuf)) >=
                               sizeof(expbuf))
                                   return (dobeep_msg("strlcat error"));
                   if (strlcat(expbuf, tmpbuf, sizeof(expbuf)) >= sizeof(expbuf))
                           return (dobeep_msg("strlcat error"));
   #ifdef MGLOG
                   mglog_misc("exp|%s|\n", e1->exp);
   #endif
           }
           if (pctr != 0) {
                   clearexp();
                   return(dobeep_msg("Opening and closing parentheses error"));
           }
   
           ret = parseexp(expbuf);
           clearexp();
   
           return (ret);
   }
   
   /*
    * At the moment, only paring list defines. Much more to do.
    */
   static int
   parseexp(char *funstr)
   {
           char    *regs;
   
           /* Does the line have a list 'define' like: */
           /* (define alist(list 1 2 3 4)) */
           regs = "^define[ ]+.*[ ]+list[ ]+.*[ ]*";
           if (doregex(regs, funstr))
                   return(foundvar(funstr));
   
           /* Does the line have a incorrect variable 'define' like: */
           /* (define i y z) */
           regs = "^define[ ]+.*[ ]+.*[ ]+.*$";
           if (doregex(regs, funstr))
                   return(dobeep_msg("Invalid use of define."));
   
           /* Does the line have a single variable 'define' like: */
           /* (define i 0) */
           regs = "^define[ ]+.*[ ]+.*$";
           if (doregex(regs, funstr))
                   return(foundvar(funstr));
   
           /* Does the line have an unrecognised 'define' */
           regs = "^define[\t ]+";
           if (doregex(regs, funstr))
                   return(dobeep_msg("Invalid use of define"));
   
           return(multiarg(funstr));
   }
   
   /*
  * Pass a list of arguments to a function.   * Pass a list of arguments to a function.
  */   */
 static int  static int
 multiarg(char *funstr)  multiarg(char *funstr)
 {  {
         PF       funcp;          PF       funcp;
         char     excbuf[BUFSIZE], argbuf[BUFSIZE], *contbuf, tmpbuf[BUFSIZE];          char     excbuf[BUFSIZE], argbuf[BUFSIZE];
         char    *cmdp, *argp, *fendp, *endp, *p, *t, *s = " ";          char     contbuf[BUFSIZE], varbuf[BUFSIZE];
         int      singlecmd = 0, spc, numparams, numspc;          char    *cmdp = NULL, *argp, *fendp = NULL, *endp, *p, *v, *s = " ";
         int      inlist, foundlst = 0, eolst, rpar, sizof, fin;          int      spc, numparams, numspc;
           int      inlist, sizof, fin;
   
         contbuf = NULL;          if (doregex("^[A-Za-z-]+$", funstr))
         endp = strrchr(funstr, ')');                  return(excline(funstr));
         if (endp == NULL) {  
                 ewprintf("No closing parenthesis found");  
                 return(FALSE);  
         }  
         p = endp + 1;  
         if (*p != '\0')  
                 *p = '\0';  
         /* we now know that string starts with '(' and ends with ')' */  
         if (doregex("^[(][\t ]*[)]$", funstr))  
                 return(dobeep_msg("No command found"));  
   
         if (doregex("^[(][\t ]*[A-Za-z-]+[\t ]*[)]$", funstr))          cmdp = funstr;
                 singlecmd = 1;          fendp = strchr(cmdp, ' ');
   
         p = funstr + 1;         /* move past first '(' char.    */  
         cmdp = skipwhite(p);    /* find first char of command.  */  
   
         if (singlecmd) {  
                 /* remove ')', then check for spaces at the end */  
                 cmdp[strlen(cmdp) - 1] = '\0';  
                 if ((fendp = strchr(cmdp, ' ')) != NULL)  
                         *fendp = '\0';  
                 else if ((fendp = strchr(cmdp, '\t')) != NULL)  
                         *fendp = '\0';  
                 return(excline(cmdp));  
         }  
         if ((fendp = strchr(cmdp, ' ')) == NULL)  
                 fendp = strchr(cmdp, '\t');  
   
         *fendp = '\0';          *fendp = '\0';
         /*          /*
          * If no extant mg command found, just return.           * If no extant mg command found, just return.
Line 127 
Line 270 
                 return (dobeep_msgs("Command takes no arguments: ", cmdp));                  return (dobeep_msgs("Command takes no arguments: ", cmdp));
   
         /* now find the first argument */          /* now find the first argument */
         if (fendp)          p = fendp + 1;
                 p = fendp + 1;  
         else  
                 p = "";  
         p = skipwhite(p);          p = skipwhite(p);
   
         if (strlcpy(argbuf, p, sizeof(argbuf)) >= sizeof(argbuf))          if (strlcpy(argbuf, p, sizeof(argbuf)) >= sizeof(argbuf))
                 return (dobeep_msg("strlcpy error"));                  return (dobeep_msg("strlcpy error"));
         argp = argbuf;          argp = argbuf;
         numspc = spc = 1; /* initially fake a space so we find first argument */          numspc = spc = 1; /* initially fake a space so we find first argument */
         inlist = eolst = fin = rpar = 0;          inlist = fin = 0;
   
         for (p = argp; fin == 0; p++) {          for (p = argbuf; *p != '\0'; p++) {
 #ifdef  MGLOG                  if (*(p + 1) == '\0')
                 mglog_execbuf("", excbuf, argbuf, argp, eolst, inlist, cmdp,                          fin = 1;
                     p, contbuf);  
 #endif                  if (*p != ' ') {
                 if (foundlst) {                          if (spc == 1)
                         foundlst = 0;                                  argp = p;
                         p--;    /* otherwise 1st arg is missed from list. */                          spc = 0;
                 }                  }
                 if (*p == ')') {                  if (*p == ' ' || fin) {
                         rpar = 1;  
                         *p = '\0';  
                 }  
                 if (*p == ' ' || *p == '\t' || *p == '\0') {  
                         if (spc == 1)                          if (spc == 1)
                                 continue;                                  continue;
                         if (spc == 0 && (numspc % numparams == 0)) {  
                                 if (*p == '\0')  
                                         eolst = 1;  
                                 else  
                                         eolst = 0;  
                                 *p = '\0';      /* terminate arg string */  
                                 endp = p + 1;  
                                 excbuf[0] = '\0';  
                                 /* Is arg a var? */  
                                 if (!inlist) {  
                                         sizof = sizeof(tmpbuf);  
                                         t = tmpbuf;  
                                         if (isvar(&argp, &t, sizof)) {  
                                                 if ((contbuf = strndup(endp,  
                                                     BUFSIZE)) == NULL)  
                                                         return(FALSE);  
                                                 *p = ' ';  
                                                 (void)(strlcpy(argbuf, tmpbuf,  
                                                     sizof) >= sizof);  
                                                 p = argp = argbuf;  
                                                 spc = 1;  
                                                 foundlst = inlist = 1;  
                                                 continue;  
                                         }  
                                 }  
                                 if (strlcpy(excbuf, cmdp, sizeof(excbuf))  
                                      >= sizeof(excbuf))  
                                         return (dobeep_msg("strlcpy error"));  
                                 if (strlcat(excbuf, s, sizeof(excbuf))  
                                     >= sizeof(excbuf))  
                                         return (dobeep_msg("strlcat error"));  
                                 if (strlcat(excbuf, argp, sizeof(excbuf))  
                                     >= sizeof(excbuf))  
                                         return (dobeep_msg("strlcat error"));  
   
                                 excline(excbuf);                          if (*p == ' ') {
 #ifdef  MGLOG                                  *p = '\0';      /* terminate arg string */
                                 mglog_execbuf("  ", excbuf, argbuf, argp,                          }
                                     eolst, inlist, cmdp, p, contbuf);                          endp = p + 1;
 #endif                          excbuf[0] = '\0';
                                 *p = ' ';       /* so 'for' loop can continue */                          varbuf[0] = '\0';
                                 if (eolst) {                          contbuf[0] = '\0';
                                         if (contbuf != NULL) {                          sizof = sizeof(varbuf);
                                                 (void)strlcpy(argbuf, contbuf,                          v = varbuf;
                                                     sizeof(argbuf));                          if (isvar(&argp, &v, sizof)) {
                                                 free(contbuf);                                  (void)(strlcat(varbuf, " ",
                                                 contbuf = NULL;                                      sizof) >= sizof);
                                                 p = argp = argbuf;  
                                                 foundlst = 1;                                  *p = ' ';
                                                 inlist = 0;  
                                                 if (rpar)                                  (void)(strlcpy(contbuf, endp,
                                                         fin = 1;                                      sizeof(contbuf)) >= sizeof(contbuf));
                                                 continue;  
                                         }                                  (void)(strlcat(varbuf, contbuf,
                                         spc = 1;                                      sizof) >= sizof);
                                         inlist = 0;  
                                   (void)(strlcpy(argbuf, varbuf,
                                       sizof) >= sizof);
   
                                   p = argp = argbuf;
                                   while (*p != ' ') {
                                           if (*p == '\0')
                                                   break;
                                           p++;
                                 }                                  }
                                 if (eolst && rpar)                                  *p = '\0';
                                         fin = 1;                                  spc = 1;
                                   fin = 0;
                         }                          }
                         numspc++;                          if (strlcpy(excbuf, cmdp, sizeof(excbuf))
                               >= sizeof(excbuf))
                                   return (dobeep_msg("strlcpy error"));
                           if (strlcat(excbuf, s, sizeof(excbuf))
                               >= sizeof(excbuf))
                                   return (dobeep_msg("strlcat error"));
                           if (strlcat(excbuf, argp, sizeof(excbuf))
                               >= sizeof(excbuf))
                                   return (dobeep_msg("strlcat error"));
   
                           excline(excbuf);
   
                           if (fin)
                                   break;
   
                           *p = ' ';               /* unterminate arg string */
                         spc = 1;                          spc = 1;
                 } else {  
                         if (spc == 1)  
                                 if ((numparams == 1) ||  
                                     ((numspc + 1) % numparams) == 0)  
                                         argp = p;  
                         spc = 0;  
                 }                  }
         }          }
         return (TRUE);          return (TRUE);
Line 232 
Line 353 
  * Is an item a value or a variable?   * Is an item a value or a variable?
  */   */
 static int  static int
 isvar(char **argp, char **tmpbuf, int sizof)  isvar(char **argp, char **varbuf, int sizof)
 {  {
         struct varentry *v1 = NULL;          struct varentry *v1 = NULL;
   
         if (SLIST_EMPTY(&varhead))          if (SLIST_EMPTY(&varhead))
                 return (FALSE);                  return (FALSE);
 #ifdef  MGLOG  #ifdef  MGLOG
         mglog_isvar(*tmpbuf, *argp, sizof);          mglog_isvar(*varbuf, *argp, sizof);
 #endif  #endif
         SLIST_FOREACH(v1, &varhead, entry) {          SLIST_FOREACH(v1, &varhead, entry) {
                 if (strcmp(*argp, v1->name) == 0) {                  if (strcmp(*argp, v1->name) == 0) {
                         (void)(strlcpy(*tmpbuf, v1->vals, sizof) >= sizof);                          (void)(strlcpy(*varbuf, v1->vals, sizof) >= sizof);
                         return (TRUE);                          return (TRUE);
                 }                  }
         }          }
Line 252 
Line 373 
   
   
 /*  /*
  * The (define string _must_ adhere to the regex in foundparen.   * The define string _must_ adhere to the regex in parsexp().
  * This is not the correct way to do parsing but it does highlight   * This is not the correct way to do parsing but it does highlight
  * the issues.   * the issues.
  */   */
Line 260 
Line 381 
 foundvar(char *defstr)  foundvar(char *defstr)
 {  {
         struct varentry *vt, *v1 = NULL;          struct varentry *vt, *v1 = NULL;
         const char       e[2] = "e", t[2] = "t";          const char       t[2] = "t";
         char            *p, *vnamep, *vendp = NULL, *valp, *o;          char            *p, *vnamep, *vendp = NULL, *valp;
         int              spc, foundlist = 0;          int              spc;
   
         p = defstr + 1;         /* move past first '(' char.    */          p = strstr(defstr, " ");        /* move to first ' ' char.    */
         p = skipwhite(p);       /* find first char of 'define'. */          vnamep = skipwhite(p);          /* find first char of var name. */
         p = strstr(p, e);       /* find first 'e' in 'define'.  */  
         p = strstr(++p, e);     /* find second 'e' in 'define'. */  
         p++;                    /* move past second 'e'.        */  
         vnamep = skipwhite(p);  /* find first char of var name. */  
         vendp = vnamep;          vendp = vnamep;
   
         /* now find the end of the list name */          /* now find the end of the list name */
         while (1) {          while (1) {
                 ++vendp;                  ++vendp;
                 if (*vendp == '(') {                  if (*vendp == ' ')
                         foundlist = 1;  
                         break;                          break;
                 } else if (*vendp == ' ' || *vendp == '\t')  
                         break;  
         }          }
         *vendp = '\0';          *vendp = '\0';
   
         /*          /*
          * Check list name is not an existing function.           * Check list name is not an existing function.
          * Although could this be allowed? Shouldn't context dictate?           * Although could this be allowed? Shouldn't context dictate?
Line 291 
Line 406 
   
         p = ++vendp;          p = ++vendp;
         p = skipwhite(p);          p = skipwhite(p);
         if (foundlist) {  
           if ((*p == 'l') && (*(p + 1) == 'i') && (*(p + 2) == 's')) {
                 p = strstr(p, t);       /* find 't' in 'list'.  */                  p = strstr(p, t);       /* find 't' in 'list'.  */
                 valp = skipwhite(++p);  /* find first value     */                  valp = skipwhite(++p);  /* find first value     */
         } else          } else
Line 319 
Line 435 
         spc = 1;          spc = 1;
         /* now loop through values in list value string while counting them */          /* now loop through values in list value string while counting them */
         for (p = valp; *p != '\0'; p++) {          for (p = valp; *p != '\0'; p++) {
                 if (*p == ' ' || *p == '\t') {                  if (*p != ' ' && *p != '\t') {
                         if (spc == 0)  
                                 vendp = p;  
                         spc = 1;  
                 } else if (*p == ')') {  
                         o = p - 1;  
                         if (*o != ' ' && *o != '\t')  
                                 vendp = p;  
                         break;  
                 } else {  
                         if (spc == 1)                          if (spc == 1)
                                 v1->count++;                                  v1->count++;
                         spc = 0;                          spc = 0;
                 }                  }
         }          }
         if (vendp)  
                 *vendp = '\0';  
   
         if ((v1->vals = strndup(valp, BUFSIZE)) == NULL)          if ((v1->vals = strndup(valp, BUFSIZE)) == NULL)
                 return(dobeep_msg("strndup error"));                  return(dobeep_msg("strndup error"));
   
 #ifdef  MGLOG  #ifdef  MGLOG
         mglog_misc("var:%s\t#items:%d\tvals:%s\n", vnamep, v1->count, v1->vals);          mglog_misc("var:%s\t#items:%d\tvals:|%s|\n", vnamep, v1->count, v1->vals);
 #endif  #endif
   
         return (TRUE);          return (TRUE);
 }  }
   
 /*  /*
  * Finished with evaluation, so clean up any vars.   * Finished with buffer evaluation, so clean up any vars.
    * Perhaps keeps them in mg even after use,...
  */   */
 int  int
 clearvars(void)  clearvars(void)
Line 366 
Line 471 
 }  }
   
 /*  /*
  * Line has a '(' as the first non-white char.   * Finished with block evaluation, so clean up any expressions.
  * Do some very basic parsing of line with '(' as the first character.  
  * Multi-line not supported at the moment, To do.  
  */   */
 int  static void
 foundparen(char *funstr)  clearexp(void)
 {  {
         char    *regs, *p;          struct expentry *e1 = NULL;
         int      pctr;  
   
         pctr = 0;          while (!SLIST_EMPTY(&exphead)) {
                   e1 = SLIST_FIRST(&exphead);
         /*                  SLIST_REMOVE_HEAD(&exphead, eentry);
          * Check for blocks of code with opening and closing ().                  free(e1->exp);
          * One block = (cmd p a r a m)                  free(e1);
          * Two blocks = (cmd p a r a m s)(hola)  
          * Two blocks = (cmd p a r (list a m s))(hola)  
          * Only single line at moment, but more for multiline.  
          */  
         p = funstr;  
         while (*p != '\0') {  
                 if (*p == '(') {  
                         pctr++;  
                 } else if (*p == ')') {  
                         pctr--;  
                 }  
                 p++;  
         }          }
         if (pctr != 0)          return;
                 return(dobeep_msg("Opening and closing parentheses error"));  
   
         /* Does the line have a list 'define' like: */  
         /* (define alist(list 1 2 3 4)) */  
         regs = "^[(][\t ]*define[\t ]+[^\t (]+[\t ]*[(][\t ]*list[\t ]+"\  
                 "[^\t ]+.*[)][\t ]*[)]";  
         if (doregex(regs, funstr))  
                 return(foundvar(funstr));  
   
         /* Does the line have a single variable 'define' like: */  
         /* (define i 0) */  
         regs = "^[(][\t ]*define[\t ]+[^\t (]+[\t ]*[^\t (]+[\t ]*[)]";  
         if (doregex(regs, funstr))  
                 return(foundvar(funstr));  
   
         /* Does the line have an unrecognised 'define' */  
         regs = "^[(][\t ]*define[\t ]+";  
         if (doregex(regs, funstr))  
                 return(dobeep_msg("Invalid use of define"));  
   
         return(multiarg(funstr));  
 }  }
   
 /*  /*
  * Test a string against a regular expression.   * Test a string against a regular expression.
  */   */
 int  static int
 doregex(char *r, char *e)  doregex(char *r, char *e)
 {  {
         regex_t  regex_buff;          regex_t  regex_buff;

Legend:
Removed from v.1.9  
changed lines
  Added in v.1.10