[BACK]Return to scanner.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / gnuplot

File: [local] / OpenXM_contrib / gnuplot / Attic / scanner.c (download)

Revision 1.1.1.2 (vendor branch), Sat Jan 22 14:16:00 2000 UTC (24 years, 3 months ago) by maekawa
Branch: GNUPLOT
CVS Tags: maekawa-ipv6, VERSION_3_7_1, RELEASE_20000124, RELEASE_1_2_2, RELEASE_1_2_1, RELEASE_1_1_3, RELEASE_1_1_2
Changes since 1.1.1.1: +1 -1 lines

Import gnuplot 3.7.1

#ifndef lint
static char *RCSid = "$Id: scanner.c,v 1.10 1998/11/04 14:49:57 lhecking Exp $";
#endif

/* GNUPLOT - scanner.c */

/*[
 * Copyright 1986 - 1993, 1998   Thomas Williams, Colin Kelley
 *
 * Permission to use, copy, and distribute this software and its
 * documentation for any purpose with or without fee is hereby granted,
 * provided that the above copyright notice appear in all copies and
 * that both that copyright notice and this permission notice appear
 * in supporting documentation.
 *
 * Permission to modify the software is granted, but not the right to
 * distribute the complete modified source code.  Modifications are to
 * be distributed as patches to the released version.  Permission to
 * distribute binaries produced by compiling modified sources is granted,
 * provided you
 *   1. distribute the corresponding source modifications from the
 *    released version in the form of a patch file along with the binaries,
 *   2. add special version identification to distinguish your version
 *    in addition to the base release version number,
 *   3. provide your name and address as the primary contact for the
 *    support of your modified version, and
 *   4. retain our contact information in regard to use of the base
 *    software.
 * Permission to distribute the released version of the source code along
 * with corresponding source modifications in the form of a patch file is
 * granted with same provisions 2 through 4 for binary distributions.
 *
 * This software is provided "as is" without express or implied warranty
 * to the extent permitted by applicable law.
]*/

#include "plot.h"

static int get_num __PROTO((char str[]));
static void substitute __PROTO((char *str, int max));

#ifdef AMIGA_AC_5
#define O_RDONLY	0
int open(const char *_name, int _mode,...);
int close(int);
#endif /* AMIGA_AC_5 */

#ifdef VMS
#include <descrip.h>
#define MAILBOX "PLOT$MAILBOX"
#define pclose(f) fclose(f)
#ifdef __DECC
#include <lib$routines.h>	/* avoid some IMPLICITFNC warnings */
#include <starlet.h>
#endif /* __DECC */
#endif /* VMS */


#define isident(c) (isalnum(c) || (c) == '_')

#ifndef STDOUT
#define STDOUT 1
#endif

#define LBRACE '{'
#define RBRACE '}'

#define APPEND_TOKEN {token[t_num].length++; current++;}

#define SCAN_IDENTIFIER while (isident((int)expression[current + 1]))\
				APPEND_TOKEN

static int t_num;		/* number of token I'm working on */

/*
 * scanner() breaks expression[] into lexical units, storing them in token[].
 *   The total number of tokens found is returned as the function value.
 *   Scanning will stop when '\0' is found in expression[], or when token[]
 *     is full.
 *
 *       Scanning is performed by following rules:
 *
 *      Current char    token should contain
 *     -------------    -----------------------
 *      1.  alpha,_     all following alpha-numerics
 *      2.  digit       0 or more following digits, 0 or 1 decimal point,
 *                              0 or more digits, 0 or 1 'e' or 'E',
 *                              0 or more digits.
 *      3.  ^,+,-,/     only current char
 *          %,~,(,)
 *          [,],;,:,
 *          ?,comma
 *          $           for using patch (div)
 *      4.  &,|,=,*     current char; also next if next is same
 *      5.  !,<,>       current char; also next if next is =
 *      6.  ", '        all chars up until matching quote
 *      7.  #           this token cuts off scanning of the line (DFK).
 *
 *                      white space between tokens is ignored
 */
int scanner(expression)
char expression[];
{
    register int current;	/* index of current char in expression[] */
    register int quote;
    char brace;

    for (current = t_num = 0; expression[current] != NUL; current++) {
      again:
	if (t_num + 1 >= token_table_size) {
	    /* leave space for dummy end token */
	    extend_token_table();
	}
	if (isspace((int) expression[current]))
	    continue;		/* skip the whitespace */
	token[t_num].start_index = current;
	token[t_num].length = 1;
	token[t_num].is_token = TRUE;	/* to start with... */

	if (expression[current] == '`') {
	    substitute(&expression[current], MAX_LINE_LEN - current);
	    goto again;
	}
	/* allow _ to be the first character of an identifier */
	if (isalpha((int) expression[current]) || expression[current] == '_') {
	    SCAN_IDENTIFIER;
	} else if (isdigit((int) expression[current]) || expression[current] == '.') {
	    token[t_num].is_token = FALSE;
	    token[t_num].length = get_num(&expression[current]);
	    current += (token[t_num].length - 1);
	} else if (expression[current] == LBRACE) {
	    token[t_num].is_token = FALSE;
	    token[t_num].l_val.type = CMPLX;
#ifdef __PUREC__
	    {
		char l[80];
		if ((sscanf(&expression[++current], "%lf,%lf%[ }]s",
			    &token[t_num].l_val.v.cmplx_val.real,
			    &token[t_num].l_val.v.cmplx_val.imag,
			    &l) != 3) || (!strchr(l, RBRACE)))
		    int_error("invalid complex constant", t_num);
	    }
#else
	    if ((sscanf(&expression[++current], "%lf , %lf %c",
			&token[t_num].l_val.v.cmplx_val.real,
			&token[t_num].l_val.v.cmplx_val.imag,
			&brace) != 3) || (brace != RBRACE))
		int_error("invalid complex constant", t_num);
#endif
	    token[t_num].length += 2;
	    while (expression[++current] != RBRACE) {
		token[t_num].length++;
		if (expression[current] == NUL)	/* { for vi % */
		    int_error("no matching '}'", t_num);
	    }
	} else if (expression[current] == '\'' || expression[current] == '\"') {
	    token[t_num].length++;
	    quote = expression[current];
	    while (expression[++current] != quote) {
		if (!expression[current]) {
		    expression[current] = quote;
		    expression[current + 1] = NUL;
		    break;
		} else if (expression[current] == '\\'
			   && expression[current + 1]) {
		    current++;
		    token[t_num].length += 2;
		} else
		    token[t_num].length++;
	    }
	} else
	    switch (expression[current]) {
	    case '#':		/* DFK: add comments to gnuplot */
		goto endline;	/* ignore the rest of the line */
	    case '^':
	    case '+':
	    case '-':
	    case '/':
	    case '%':
	    case '~':
	    case '(':
	    case ')':
	    case '[':
	    case ']':
	    case ';':
	    case ':':
	    case '?':
	    case ',':
	    case '$':		/* div */
		break;
	    case '&':
	    case '|':
	    case '=':
	    case '*':
		if (expression[current] == expression[current + 1])
		    APPEND_TOKEN;
		break;
	    case '!':
	    case '<':
	    case '>':
		if (expression[current + 1] == '=')
		    APPEND_TOKEN;
		break;
	    default:
		int_error("invalid character", t_num);
	    }
	++t_num;		/* next token if not white space */
    }

  endline:			/* comments jump here to ignore line */

/* Now kludge an extra token which points to '\0' at end of expression[].
   This is useful so printerror() looks nice even if we've fallen off the
   line. */

    token[t_num].start_index = current;
    token[t_num].length = 0;
    /* print 3+4  then print 3+  is accepted without
     * this, since string is ignored if it is not
     * a token
     */
    token[t_num].is_token = TRUE;
    return (t_num);
}


static int get_num(str)
char str[];
{
    register int count = 0;
    register long lval;

    token[t_num].is_token = FALSE;
    token[t_num].l_val.type = INTGR;	/* assume unless . or E found */
    while (isdigit((int) str[count]))
	count++;
    if (str[count] == '.') {
	token[t_num].l_val.type = CMPLX;
	/* swallow up digits until non-digit */
	while (isdigit((int) str[++count]))
	    ;
	/* now str[count] is other than a digit */
    }
    if (str[count] == 'e' || str[count] == 'E') {
	token[t_num].l_val.type = CMPLX;
/* modified if statement to allow + sign in exponent
   rjl 26 July 1988 */
	count++;
	if (str[count] == '-' || str[count] == '+')
	    count++;
	if (!isdigit((int) str[count])) {
	    token[t_num].start_index += count;
	    int_error("expecting exponent", t_num);
	}
	while (isdigit((int) str[++count]));
    }
    if (token[t_num].l_val.type == INTGR) {
	lval = atol(str);
	if ((token[t_num].l_val.v.int_val = lval) != lval)
	    int_error("integer overflow; change to floating point", t_num);
    } else {
	token[t_num].l_val.v.cmplx_val.imag = 0.0;
	token[t_num].l_val.v.cmplx_val.real = atof(str);
    }
    return (count);
}

#if defined(VMS) || defined(PIPES) || (defined(ATARI) || defined(MTOS)) && defined(__PUREC__)

/* this really ought to make use of the dynamic-growth of the
 * input line in 3.6.  And it definitely should not have
 * static arrays !
 */
/* A macro to reduce clutter ... */
# ifdef AMIGA_AC_5
#  define CLOSE_FILE_OR_PIPE ((void) close(fd))
# elif (defined(ATARI) || defined(MTOS)) && defined(__PUREC__)
#  define CLOSE_FILE_OR_PIPE ((void) fclose(f); (void) unlink(atari_tmpfile))
# else /* Rest of the world */
#  define CLOSE_FILE_OR_PIPE ((void) pclose(f))
# endif

static void substitute(str, max)	/* substitute output from ` ` */
char *str;
int max;
{
    register char *last;
    register int i, c;
    register FILE *f;
# ifdef AMIGA_AC_5
    int fd;
# elif (defined(ATARI) || defined(MTOS)) && defined(__PUREC__)
    char *atari_tmpfile;
    char *atari_pgm[MAX_LINE_LEN+100];
# endif /* !AMIGA_AC_5 */
    static char pgm[MAX_LINE_LEN+1], output[MAX_LINE_LEN+1];

# ifdef VMS
    int chan, one = 1;
    static $DESCRIPTOR(pgmdsc, pgm);
    static $DESCRIPTOR(lognamedsc, MAILBOX);
# endif /* VMS */

    /* forgive missing closing backquote at end of line */
    i = 0;
    last = str;
    while (*++last) {
	if (*last == '`') {
	    ++last;		/* move past it */
	    break;
	}
	pgm[i++] = *last;
    }
    pgm[i] = NUL;		/* end with null */
    max -= strlen(last);	/* max is now the max length of output sub. */

# ifdef VMS
    pgmdsc.dsc$w_length = i;
    if (!((vaxc$errno = sys$crembx(0, &chan, 0, 0, 0, 0, &lognamedsc)) & 1))
	os_error("sys$crembx failed", NO_CARET);

    if (!((vaxc$errno = lib$spawn(&pgmdsc, 0, &lognamedsc, &one)) & 1))
	os_error("lib$spawn failed", NO_CARET);

    if ((f = fopen(MAILBOX, "r")) == NULL)
	os_error("mailbox open failed", NO_CARET);
# elif (defined(ATARI) || defined(MTOS)) && defined(__PUREC__)
    if (system(NULL) == 0)
	os_error("no command shell", NO_CARET);
    if ((strlen(atari_tmpfile) + strlen(pgm) + 5) > MAX_LINE_LEN + 100)
	os_error("sorry, command to long", NO_CARET);
    atari_tmpfile = tmpnam(NULL);
    strcpy(atari_pgm, pgm);
    strcat(atari_pgm, " >> ");
    strcat(atari_pgm, atari_tmpfile);
    system(atari_pgm);
    if ((f = fopen(atari_tmpfile, "r")) == NULL)
# elif defined(AMIGA_AC_5)
    if ((fd = open(pgm, "O_RDONLY")) == -1)
# else /* everyone else */
    if ((f = popen(pgm, "r")) == NULL)
	os_error("popen failed", NO_CARET);
# endif /* !VMS */

    i = 0;
    while ((c = getc(f)) != EOF) {
	output[i++] = ((c == '\n') ? ' ' : c);	/* newlines become blanks */
	if (i == max) {
	    CLOSE_FILE_OR_PIPE;
	    int_error("substitution overflow", t_num);
	}
    }

    CLOSE_FILE_OR_PIPE;

    if (i + strlen(last) > max)
	int_error("substitution overflowed rest of line", t_num);
    /* tack on rest of line to output */
    safe_strncpy(output + i, last, MAX_LINE_LEN - i);
    /* now replace ` ` with output */
    safe_strncpy(str, output, max);
    screen_ok = FALSE;
}

#else /* VMS || PIPES || ATARI && PUREC */

static void substitute(str, max)
char *str;
int max;
{
    char line[100];

    sprintf(line, "substitution not supported by %s", OS);
    int_error(line, t_num);
}

#endif /* unix || VMS || PIPES || ATARI && PUREC */