Annotation of OpenXM_contrib/gnuplot/scanner.c, Revision 1.1
1.1 ! maekawa 1: #ifndef lint
! 2: static char *RCSid = "$Id: scanner.c,v 1.56 1998/06/18 14:55:16 ddenholm Exp $";
! 3: #endif
! 4:
! 5: /* GNUPLOT - scanner.c */
! 6:
! 7: /*[
! 8: * Copyright 1986 - 1993, 1998 Thomas Williams, Colin Kelley
! 9: *
! 10: * Permission to use, copy, and distribute this software and its
! 11: * documentation for any purpose with or without fee is hereby granted,
! 12: * provided that the above copyright notice appear in all copies and
! 13: * that both that copyright notice and this permission notice appear
! 14: * in supporting documentation.
! 15: *
! 16: * Permission to modify the software is granted, but not the right to
! 17: * distribute the complete modified source code. Modifications are to
! 18: * be distributed as patches to the released version. Permission to
! 19: * distribute binaries produced by compiling modified sources is granted,
! 20: * provided you
! 21: * 1. distribute the corresponding source modifications from the
! 22: * released version in the form of a patch file along with the binaries,
! 23: * 2. add special version identification to distinguish your version
! 24: * in addition to the base release version number,
! 25: * 3. provide your name and address as the primary contact for the
! 26: * support of your modified version, and
! 27: * 4. retain our contact information in regard to use of the base
! 28: * software.
! 29: * Permission to distribute the released version of the source code along
! 30: * with corresponding source modifications in the form of a patch file is
! 31: * granted with same provisions 2 through 4 for binary distributions.
! 32: *
! 33: * This software is provided "as is" without express or implied warranty
! 34: * to the extent permitted by applicable law.
! 35: ]*/
! 36:
! 37: #include "plot.h"
! 38:
! 39: static int get_num __PROTO((char str[]));
! 40: static void substitute __PROTO((char *str, int max));
! 41:
! 42: #ifdef AMIGA_AC_5
! 43: #define O_RDONLY 0
! 44: int open(const char *_name, int _mode,...);
! 45: int close(int);
! 46: #endif /* AMIGA_AC_5 */
! 47:
! 48: #ifdef VMS
! 49: #include <descrip.h>
! 50: #define MAILBOX "PLOT$MAILBOX"
! 51: #define pclose(f) fclose(f)
! 52: #ifdef __DECC
! 53: #include <lib$routines.h> /* avoid some IMPLICITFNC warnings */
! 54: #include <starlet.h>
! 55: #endif /* __DECC */
! 56: #endif /* VMS */
! 57:
! 58:
! 59: #define isident(c) (isalnum(c) || (c) == '_')
! 60:
! 61: #ifndef STDOUT
! 62: #define STDOUT 1
! 63: #endif
! 64:
! 65: #define LBRACE '{'
! 66: #define RBRACE '}'
! 67:
! 68: #define APPEND_TOKEN {token[t_num].length++; current++;}
! 69:
! 70: #define SCAN_IDENTIFIER while (isident((int)expression[current + 1]))\
! 71: APPEND_TOKEN
! 72:
! 73: static int t_num; /* number of token I'm working on */
! 74:
! 75: /*
! 76: * scanner() breaks expression[] into lexical units, storing them in token[].
! 77: * The total number of tokens found is returned as the function value.
! 78: * Scanning will stop when '\0' is found in expression[], or when token[]
! 79: * is full.
! 80: *
! 81: * Scanning is performed by following rules:
! 82: *
! 83: * Current char token should contain
! 84: * ------------- -----------------------
! 85: * 1. alpha,_ all following alpha-numerics
! 86: * 2. digit 0 or more following digits, 0 or 1 decimal point,
! 87: * 0 or more digits, 0 or 1 'e' or 'E',
! 88: * 0 or more digits.
! 89: * 3. ^,+,-,/ only current char
! 90: * %,~,(,)
! 91: * [,],;,:,
! 92: * ?,comma
! 93: * $ for using patch (div)
! 94: * 4. &,|,=,* current char; also next if next is same
! 95: * 5. !,<,> current char; also next if next is =
! 96: * 6. ", ' all chars up until matching quote
! 97: * 7. # this token cuts off scanning of the line (DFK).
! 98: *
! 99: * white space between tokens is ignored
! 100: */
! 101: int scanner(expression)
! 102: char expression[];
! 103: {
! 104: register int current; /* index of current char in expression[] */
! 105: register int quote;
! 106: char brace;
! 107:
! 108: for (current = t_num = 0; expression[current] != NUL; current++) {
! 109: again:
! 110: if (t_num + 1 >= token_table_size) {
! 111: /* leave space for dummy end token */
! 112: extend_token_table();
! 113: }
! 114: if (isspace((int) expression[current]))
! 115: continue; /* skip the whitespace */
! 116: token[t_num].start_index = current;
! 117: token[t_num].length = 1;
! 118: token[t_num].is_token = TRUE; /* to start with... */
! 119:
! 120: if (expression[current] == '`') {
! 121: substitute(&expression[current], MAX_LINE_LEN - current);
! 122: goto again;
! 123: }
! 124: /* allow _ to be the first character of an identifier */
! 125: if (isalpha((int) expression[current]) || expression[current] == '_') {
! 126: SCAN_IDENTIFIER;
! 127: } else if (isdigit((int) expression[current]) || expression[current] == '.') {
! 128: token[t_num].is_token = FALSE;
! 129: token[t_num].length = get_num(&expression[current]);
! 130: current += (token[t_num].length - 1);
! 131: } else if (expression[current] == LBRACE) {
! 132: token[t_num].is_token = FALSE;
! 133: token[t_num].l_val.type = CMPLX;
! 134: #ifdef __PUREC__
! 135: {
! 136: char l[80];
! 137: if ((sscanf(&expression[++current], "%lf,%lf%[ }]s",
! 138: &token[t_num].l_val.v.cmplx_val.real,
! 139: &token[t_num].l_val.v.cmplx_val.imag,
! 140: &l) != 3) || (!strchr(l, RBRACE)))
! 141: int_error("invalid complex constant", t_num);
! 142: }
! 143: #else
! 144: if ((sscanf(&expression[++current], "%lf , %lf %c",
! 145: &token[t_num].l_val.v.cmplx_val.real,
! 146: &token[t_num].l_val.v.cmplx_val.imag,
! 147: &brace) != 3) || (brace != RBRACE))
! 148: int_error("invalid complex constant", t_num);
! 149: #endif
! 150: token[t_num].length += 2;
! 151: while (expression[++current] != RBRACE) {
! 152: token[t_num].length++;
! 153: if (expression[current] == NUL) /* { for vi % */
! 154: int_error("no matching '}'", t_num);
! 155: }
! 156: } else if (expression[current] == '\'' || expression[current] == '\"') {
! 157: token[t_num].length++;
! 158: quote = expression[current];
! 159: while (expression[++current] != quote) {
! 160: if (!expression[current]) {
! 161: expression[current] = quote;
! 162: expression[current + 1] = NUL;
! 163: break;
! 164: } else if (expression[current] == '\\'
! 165: && expression[current + 1]) {
! 166: current++;
! 167: token[t_num].length += 2;
! 168: } else
! 169: token[t_num].length++;
! 170: }
! 171: } else
! 172: switch (expression[current]) {
! 173: case '#': /* DFK: add comments to gnuplot */
! 174: goto endline; /* ignore the rest of the line */
! 175: case '^':
! 176: case '+':
! 177: case '-':
! 178: case '/':
! 179: case '%':
! 180: case '~':
! 181: case '(':
! 182: case ')':
! 183: case '[':
! 184: case ']':
! 185: case ';':
! 186: case ':':
! 187: case '?':
! 188: case ',':
! 189: case '$': /* div */
! 190: break;
! 191: case '&':
! 192: case '|':
! 193: case '=':
! 194: case '*':
! 195: if (expression[current] == expression[current + 1])
! 196: APPEND_TOKEN;
! 197: break;
! 198: case '!':
! 199: case '<':
! 200: case '>':
! 201: if (expression[current + 1] == '=')
! 202: APPEND_TOKEN;
! 203: break;
! 204: default:
! 205: int_error("invalid character", t_num);
! 206: }
! 207: ++t_num; /* next token if not white space */
! 208: }
! 209:
! 210: endline: /* comments jump here to ignore line */
! 211:
! 212: /* Now kludge an extra token which points to '\0' at end of expression[].
! 213: This is useful so printerror() looks nice even if we've fallen off the
! 214: line. */
! 215:
! 216: token[t_num].start_index = current;
! 217: token[t_num].length = 0;
! 218: /* print 3+4 then print 3+ is accepted without
! 219: * this, since string is ignored if it is not
! 220: * a token
! 221: */
! 222: token[t_num].is_token = TRUE;
! 223: return (t_num);
! 224: }
! 225:
! 226:
! 227: static int get_num(str)
! 228: char str[];
! 229: {
! 230: register int count = 0;
! 231: register long lval;
! 232:
! 233: token[t_num].is_token = FALSE;
! 234: token[t_num].l_val.type = INTGR; /* assume unless . or E found */
! 235: while (isdigit((int) str[count]))
! 236: count++;
! 237: if (str[count] == '.') {
! 238: token[t_num].l_val.type = CMPLX;
! 239: /* swallow up digits until non-digit */
! 240: while (isdigit((int) str[++count]))
! 241: ;
! 242: /* now str[count] is other than a digit */
! 243: }
! 244: if (str[count] == 'e' || str[count] == 'E') {
! 245: token[t_num].l_val.type = CMPLX;
! 246: /* modified if statement to allow + sign in exponent
! 247: rjl 26 July 1988 */
! 248: count++;
! 249: if (str[count] == '-' || str[count] == '+')
! 250: count++;
! 251: if (!isdigit((int) str[count])) {
! 252: token[t_num].start_index += count;
! 253: int_error("expecting exponent", t_num);
! 254: }
! 255: while (isdigit((int) str[++count]));
! 256: }
! 257: if (token[t_num].l_val.type == INTGR) {
! 258: lval = atol(str);
! 259: if ((token[t_num].l_val.v.int_val = lval) != lval)
! 260: int_error("integer overflow; change to floating point", t_num);
! 261: } else {
! 262: token[t_num].l_val.v.cmplx_val.imag = 0.0;
! 263: token[t_num].l_val.v.cmplx_val.real = atof(str);
! 264: }
! 265: return (count);
! 266: }
! 267:
! 268: #if defined(VMS) || defined(PIPES) || (defined(ATARI) || defined(MTOS)) && defined(__PUREC__)
! 269:
! 270: /* this really ought to make use of the dynamic-growth of the
! 271: * input line in 3.6. And it definitely should not have
! 272: * static arrays !
! 273: */
! 274: /* A macro to reduce clutter ... */
! 275: # ifdef AMIGA_AC_5
! 276: # define CLOSE_FILE_OR_PIPE ((void) close(fd))
! 277: # elif (defined(ATARI) || defined(MTOS)) && defined(__PUREC__)
! 278: # define CLOSE_FILE_OR_PIPE ((void) fclose(f); (void) unlink(atari_tmpfile))
! 279: # else /* Rest of the world */
! 280: # define CLOSE_FILE_OR_PIPE ((void) pclose(f))
! 281: # endif
! 282:
! 283: static void substitute(str, max) /* substitute output from ` ` */
! 284: char *str;
! 285: int max;
! 286: {
! 287: register char *last;
! 288: register int i, c;
! 289: register FILE *f;
! 290: # ifdef AMIGA_AC_5
! 291: int fd;
! 292: # elif (defined(ATARI) || defined(MTOS)) && defined(__PUREC__)
! 293: char *atari_tmpfile;
! 294: char *atari_pgm[MAX_LINE_LEN+100];
! 295: # endif /* !AMIGA_AC_5 */
! 296: static char pgm[MAX_LINE_LEN+1], output[MAX_LINE_LEN+1];
! 297:
! 298: # ifdef VMS
! 299: int chan, one = 1;
! 300: static $DESCRIPTOR(pgmdsc, pgm);
! 301: static $DESCRIPTOR(lognamedsc, MAILBOX);
! 302: # endif /* VMS */
! 303:
! 304: /* forgive missing closing backquote at end of line */
! 305: i = 0;
! 306: last = str;
! 307: while (*++last) {
! 308: if (*last == '`') {
! 309: ++last; /* move past it */
! 310: break;
! 311: }
! 312: pgm[i++] = *last;
! 313: }
! 314: pgm[i] = NUL; /* end with null */
! 315: max -= strlen(last); /* max is now the max length of output sub. */
! 316:
! 317: # ifdef VMS
! 318: pgmdsc.dsc$w_length = i;
! 319: if (!((vaxc$errno = sys$crembx(0, &chan, 0, 0, 0, 0, &lognamedsc)) & 1))
! 320: os_error("sys$crembx failed", NO_CARET);
! 321:
! 322: if (!((vaxc$errno = lib$spawn(&pgmdsc, 0, &lognamedsc, &one)) & 1))
! 323: os_error("lib$spawn failed", NO_CARET);
! 324:
! 325: if ((f = fopen(MAILBOX, "r")) == NULL)
! 326: os_error("mailbox open failed", NO_CARET);
! 327: # elif (defined(ATARI) || defined(MTOS)) && defined(__PUREC__)
! 328: if (system(NULL) == 0)
! 329: os_error("no command shell", NO_CARET);
! 330: if ((strlen(atari_tmpfile) + strlen(pgm) + 5) > MAX_LINE_LEN + 100)
! 331: os_error("sorry, command to long", NO_CARET);
! 332: atari_tmpfile = tmpnam(NULL);
! 333: strcpy(atari_pgm, pgm);
! 334: strcat(atari_pgm, " >> ");
! 335: strcat(atari_pgm, atari_tmpfile);
! 336: system(atari_pgm);
! 337: if ((f = fopen(atari_tmpfile, "r")) == NULL)
! 338: # elif defined(AMIGA_AC_5)
! 339: if ((fd = open(pgm, "O_RDONLY")) == -1)
! 340: # else /* everyone else */
! 341: if ((f = popen(pgm, "r")) == NULL)
! 342: os_error("popen failed", NO_CARET);
! 343: # endif /* !VMS */
! 344:
! 345: i = 0;
! 346: while ((c = getc(f)) != EOF) {
! 347: output[i++] = ((c == '\n') ? ' ' : c); /* newlines become blanks */
! 348: if (i == max) {
! 349: CLOSE_FILE_OR_PIPE;
! 350: int_error("substitution overflow", t_num);
! 351: }
! 352: }
! 353:
! 354: CLOSE_FILE_OR_PIPE;
! 355:
! 356: if (i + strlen(last) > max)
! 357: int_error("substitution overflowed rest of line", t_num);
! 358: /* tack on rest of line to output */
! 359: safe_strncpy(output + i, last, MAX_LINE_LEN - i);
! 360: /* now replace ` ` with output */
! 361: safe_strncpy(str, output, max);
! 362: screen_ok = FALSE;
! 363: }
! 364:
! 365: #else /* VMS || PIPES || ATARI && PUREC */
! 366:
! 367: static void substitute(str, max)
! 368: char *str;
! 369: int max;
! 370: {
! 371: char line[100];
! 372:
! 373: sprintf(line, "substitution not supported by %s", OS);
! 374: int_error(line, t_num);
! 375: }
! 376:
! 377: #endif /* unix || VMS || PIPES || ATARI && PUREC */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>