home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume8 / gnuplot1.10A / part04 / scanner.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-09-09  |  6.9 KB  |  283 lines

  1. /*
  2.  *
  3.  *    G N U P L O T  --  scanner.c
  4.  *
  5.  *  Copyright (C) 1986, 1987  Colin Kelley, Thomas Williams
  6.  *
  7.  *  You may use this code as you wish if credit is given and this message
  8.  *  is retained.
  9.  *
  10.  *  Please e-mail any useful additions to vu-vlsi!plot so they may be
  11.  *  included in later releases.
  12.  *
  13.  *  This file should be edited with 4-column tabs!  (:set ts=4 sw=4 in vi)
  14.  */
  15.  
  16. #include <stdio.h>
  17. #include <ctype.h>
  18. #include "plot.h"
  19.  
  20. extern BOOLEAN screen_ok;
  21.  
  22. #ifdef vms
  23.  
  24. #include stdio
  25. #include descrip
  26. #include errno
  27.  
  28. #define MAILBOX "PLOT$MAILBOX"
  29. #define pclose(f) fclose(f)
  30.  
  31. #endif /* vms */
  32.  
  33.  
  34. #define isident(c) (isalnum(c) || (c) == '_')
  35.  
  36. #ifndef STDOUT
  37. #define STDOUT 1
  38. #endif
  39.  
  40. #define LBRACE '{'
  41. #define RBRACE '}'
  42.  
  43. #define APPEND_TOKEN {token[t_num].length++; current++;}
  44.  
  45. #define SCAN_IDENTIFIER while (isident(expression[current + 1]))\
  46.                 APPEND_TOKEN
  47.  
  48. extern struct lexical_unit token[MAX_TOKENS];
  49.  
  50. static int t_num;    /* number of token I'm working on */
  51.  
  52. char *strcat(), *strcpy(), *strncpy();
  53.  
  54. /*
  55.  * scanner() breaks expression[] into lexical units, storing them in token[].
  56.  *   The total number of tokens found is returned as the function value.
  57.  *   Scanning will stop when '\0' is found in expression[], or when token[]
  58.  *     is full.
  59.  *
  60.  *     Scanning is performed by following rules:
  61.  *
  62.  *        Current char    token should contain
  63.  *     -------------    -----------------------
  64.  *        1.  alpha        all following alpha-numerics
  65.  *        2.  digit        0 or more following digits, 0 or 1 decimal point,
  66.  *                          0 or more digits, 0 or 1 'e' or 'E',
  67.  *                          0 or more digits.
  68.  *        3.  ^,+,-,/        only current char
  69.  *            %,~,(,)
  70.  *            [,],;,:,
  71.  *            ?,comma
  72.  *        4.  &,|,=,*        current char; also next if next is same
  73.  *        5.  !,<,>        current char; also next if next is =
  74.  *        6.  ", '        all chars up until matching quote
  75.  *
  76.  *        white space between tokens is ignored
  77.  */
  78. scanner(expression)
  79. char expression[];
  80. {
  81. register int current;    /* index of current char in expression[] */
  82. register int quote;
  83. char brace;
  84.  
  85.     for (current = t_num = 0;
  86.         t_num < MAX_TOKENS && expression[current] != '\0';
  87.         current++) {
  88. again:
  89.         if (isspace(expression[current]))
  90.             continue;                        /* skip the whitespace */
  91.         token[t_num].start_index = current;
  92.         token[t_num].length = 1;
  93.         token[t_num].is_token = TRUE;    /* to start with...*/
  94.  
  95.         if (expression[current] == '`') {
  96.             substitute(&expression[current],MAX_LINE_LEN - current);
  97.             goto again;
  98.         }
  99.         if (isalpha(expression[current])) {
  100.             SCAN_IDENTIFIER;
  101.         } else if (isdigit(expression[current]) || expression[current] == '.'){
  102.             token[t_num].is_token = FALSE;
  103.             token[t_num].length = get_num(&expression[current]);
  104.             current += (token[t_num].length - 1);
  105.         } else if (expression[current] == LBRACE) {
  106.             token[t_num].is_token = FALSE;
  107.             token[t_num].l_val.type = CMPLX;
  108.             if ((sscanf(&expression[++current],"%lf , %lf %c",
  109.                 &token[t_num].l_val.v.cmplx_val.real,
  110.                 &token[t_num].l_val.v.cmplx_val.imag,
  111.                 &brace) != 3) || (brace != RBRACE))
  112.                     int_error("invalid complex constant",t_num);
  113.             token[t_num].length += 2;
  114.             while (expression[++current] != RBRACE) {
  115.                 token[t_num].length++;
  116.                 if (expression[current] == '\0')            /* { for vi % */
  117.                     int_error("no matching '}'", t_num);
  118.             }
  119.         } else if (expression[current] == '\'' || expression[current] == '\"'){
  120.             token[t_num].length++;
  121.             quote = expression[current];
  122.             while (expression[++current] != quote) {
  123.                 if (!expression[current]) {
  124.                     expression[current] = quote;
  125.                     expression[current+1] = '\0';
  126.                     break;
  127.                 } else
  128.                     token[t_num].length++;
  129.             }
  130.         } else switch (expression[current]) {
  131.             case '^':
  132.             case '+':
  133.             case '-':
  134.             case '/':
  135.             case '%':
  136.             case '~':
  137.             case '(':
  138.             case ')':
  139.             case '[':
  140.             case ']':
  141.             case ';':
  142.             case ':':
  143.             case '?':
  144.             case ',':
  145.                 break;
  146.             case '&':
  147.             case '|':
  148.             case '=':
  149.             case '*':
  150.                 if (expression[current] == expression[current + 1])
  151.                     APPEND_TOKEN;
  152.                 break;
  153.             case '!':
  154.             case '<':
  155.             case '>':
  156.                 if (expression[current + 1] == '=')
  157.                     APPEND_TOKEN;
  158.                 break;
  159.             default:
  160.                 int_error("invalid character",t_num);
  161.             }
  162.         ++t_num;    /* next token if not white space */
  163.     }
  164.  
  165. /* Now kludge an extra token which points to '\0' at end of expression[].
  166.    This is useful so printerror() looks nice even if we've fallen off the
  167.    line. */
  168.  
  169.         token[t_num].start_index = current;
  170.         token[t_num].length = 0;
  171.     return(t_num);
  172. }
  173.  
  174.  
  175. get_num(str)
  176. char str[];
  177. {
  178. double atof();
  179. register int count = 0;
  180. long atol();
  181. register long lval;
  182.  
  183.     token[t_num].is_token = FALSE;
  184.     token[t_num].l_val.type = INT;        /* assume unless . or E found */
  185.     while (isdigit(str[count]))
  186.         count++;
  187.     if (str[count] == '.') {
  188.         token[t_num].l_val.type = CMPLX;
  189.         while (isdigit(str[++count]))    /* swallow up digits until non-digit */
  190.             ;
  191.         /* now str[count] is other than a digit */
  192.     }
  193.     if (str[count] == 'e' || str[count] == 'E') {
  194.         token[t_num].l_val.type = CMPLX;
  195.         if (str[++count] == '-')
  196.             count++;
  197.         if (!isdigit(str[count])) {
  198.             token[t_num].start_index += count;
  199.             int_error("expecting exponent",t_num);
  200.         }
  201.         while (isdigit(str[++count]))
  202.             ;
  203.     }
  204.     if (token[t_num].l_val.type == INT) {
  205.          lval = atol(str);
  206.         if ((token[t_num].l_val.v.int_val = lval) != lval)
  207.             int_error("integer overflow; change to floating point",t_num);
  208.     } else {
  209.         token[t_num].l_val.v.cmplx_val.imag = 0.0;
  210.         token[t_num].l_val.v.cmplx_val.real = atof(str);
  211.     }
  212.     return(count);
  213. }
  214.  
  215.  
  216. #ifdef MSDOS
  217.  
  218. substitute()
  219. {
  220.     int_error("substitution not supported by MS-DOS!",t_num);
  221. }
  222.  
  223. #else /* MSDOS */
  224.  
  225. substitute(str,max)            /* substitute output from ` ` */
  226. char *str;
  227. int max;
  228. {
  229. register char *last;
  230. register int i,c;
  231. register FILE *f;
  232. FILE *popen();
  233. static char pgm[MAX_LINE_LEN+1],output[MAX_LINE_LEN+1];
  234.  
  235. #ifdef vms
  236. int chan;
  237. static $DESCRIPTOR(pgmdsc,pgm);
  238. static $DESCRIPTOR(lognamedsc,MAILBOX);
  239. #endif /* vms */
  240.  
  241.     i = 0;
  242.     last = str;
  243.     while (*(++last) != '`') {
  244.         if (*last == '\0')
  245.             int_error("unmatched `",t_num);
  246.         pgm[i++] = *last;
  247.     }
  248.     pgm[i] = '\0';        /* end with null */
  249.     max -= strlen(last);    /* max is now the max length of output sub. */
  250.   
  251. #ifdef vms
  252.       pgmdsc.dsc$w_length = i;
  253.        if (!((vaxc$errno = sys$crembx(0,&chan,0,0,0,0,&lognamedsc)) & 1))
  254.            os_error("sys$crembx failed",NO_CARET);
  255.    
  256.        if (!((vaxc$errno = lib$spawn(&pgmdsc,0,&lognamedsc,&1)) & 1))
  257.            os_error("lib$spawn failed",NO_CARET);
  258.    
  259.        if ((f = fopen(MAILBOX,"r")) == NULL)
  260.            os_error("mailbox open failed",NO_CARET);
  261. #else /* vms */
  262.       if ((f = popen(pgm,"r")) == NULL)
  263.           os_error("popen failed",NO_CARET);
  264. #endif /* vms */
  265.  
  266.     i = 0;
  267.     while ((c = getc(f)) != EOF) {
  268.         output[i++] = ((c == '\n') ? ' ' : c);    /* newlines become blanks*/
  269.         if (i == max) {
  270.             (void) pclose(f);
  271.             int_error("substitution overflow", t_num);
  272.         }
  273.     }
  274.     (void) pclose(f);
  275.     if (i + strlen(last) > max)
  276.         int_error("substitution overflowed rest of line", t_num);
  277.     (void) strncpy(output+i,last+1,MAX_LINE_LEN-i);
  278.                                     /* tack on rest of line to output */
  279.     (void) strcpy(str,output);                /* now replace ` ` with output */
  280.     screen_ok = FALSE;
  281. }
  282. #endif /* MS-DOS */
  283.