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

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