home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 334_02 / scanner.c < prev    next >
Text File  |  1991-02-05  |  8KB  |  307 lines

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