Annotation of OpenXM_contrib/gnuplot/scanner.c, Revision 1.1.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>