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

Annotation of OpenXM_contrib/gnuplot/scanner.c, Revision 1.1.1.2

1.1       maekawa     1: #ifndef lint
1.1.1.2 ! maekawa     2: static char *RCSid = "$Id: scanner.c,v 1.10 1998/11/04 14:49:57 lhecking Exp $";
1.1       maekawa     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>