[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.3

1.1       maekawa     1: #ifndef lint
1.1.1.3 ! ohara       2: static char *RCSid = "$Id: scanner.c,v 1.10.2.3 2002/03/11 16:10:09 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[]));
1.1.1.3 ! ohara      40: static void substitute __PROTO((char **, int *, int));
1.1       maekawa    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[].
1.1.1.3 ! ohara      77:  *   The total number of tokens found is returned as the function
        !            78:  *   value.  Scanning will stop when '\0' is found in expression[], or
        !            79:  *   when token[] is full.  extend_input_line() is called to extend
        !            80:  *   expression array if needed.
1.1       maekawa    81:  *
                     82:  *       Scanning is performed by following rules:
                     83:  *
                     84:  *      Current char    token should contain
                     85:  *     -------------    -----------------------
                     86:  *      1.  alpha,_     all following alpha-numerics
                     87:  *      2.  digit       0 or more following digits, 0 or 1 decimal point,
                     88:  *                              0 or more digits, 0 or 1 'e' or 'E',
                     89:  *                              0 or more digits.
                     90:  *      3.  ^,+,-,/     only current char
                     91:  *          %,~,(,)
                     92:  *          [,],;,:,
                     93:  *          ?,comma
                     94:  *          $           for using patch (div)
                     95:  *      4.  &,|,=,*     current char; also next if next is same
                     96:  *      5.  !,<,>       current char; also next if next is =
                     97:  *      6.  ", '        all chars up until matching quote
                     98:  *      7.  #           this token cuts off scanning of the line (DFK).
1.1.1.3 ! ohara      99:  *      8.  `           (command substitution: all characters through the
        !           100:  *                      matching backtic are replaced by the output of
        !           101:  *                      the contained command, then scanning is restarted.)
1.1       maekawa   102:  *
                    103:  *                      white space between tokens is ignored
                    104:  */
1.1.1.3 ! ohara     105: int
        !           106: scanner(expressionp, expressionlenp)
        !           107: char **expressionp;
        !           108: int *expressionlenp;
1.1       maekawa   109: {
                    110:     register int current;      /* index of current char in expression[] */
1.1.1.3 ! ohara     111:     char *expression = *expressionp;
1.1       maekawa   112:     register int quote;
                    113:     char brace;
                    114:
                    115:     for (current = t_num = 0; expression[current] != NUL; current++) {
                    116:       again:
                    117:        if (t_num + 1 >= token_table_size) {
                    118:            /* leave space for dummy end token */
                    119:            extend_token_table();
                    120:        }
                    121:        if (isspace((int) expression[current]))
                    122:            continue;           /* skip the whitespace */
                    123:        token[t_num].start_index = current;
                    124:        token[t_num].length = 1;
                    125:        token[t_num].is_token = TRUE;   /* to start with... */
                    126:
                    127:        if (expression[current] == '`') {
1.1.1.3 ! ohara     128:            substitute(expressionp, expressionlenp, current);
        !           129:            expression = *expressionp; /* expression might have moved */
1.1       maekawa   130:            goto again;
                    131:        }
                    132:        /* allow _ to be the first character of an identifier */
                    133:        if (isalpha((int) expression[current]) || expression[current] == '_') {
                    134:            SCAN_IDENTIFIER;
                    135:        } else if (isdigit((int) expression[current]) || expression[current] == '.') {
                    136:            token[t_num].is_token = FALSE;
                    137:            token[t_num].length = get_num(&expression[current]);
                    138:            current += (token[t_num].length - 1);
                    139:        } else if (expression[current] == LBRACE) {
                    140:            token[t_num].is_token = FALSE;
                    141:            token[t_num].l_val.type = CMPLX;
                    142: #ifdef __PUREC__
                    143:            {
                    144:                char l[80];
                    145:                if ((sscanf(&expression[++current], "%lf,%lf%[ }]s",
                    146:                            &token[t_num].l_val.v.cmplx_val.real,
                    147:                            &token[t_num].l_val.v.cmplx_val.imag,
                    148:                            &l) != 3) || (!strchr(l, RBRACE)))
                    149:                    int_error("invalid complex constant", t_num);
                    150:            }
                    151: #else
                    152:            if ((sscanf(&expression[++current], "%lf , %lf %c",
                    153:                        &token[t_num].l_val.v.cmplx_val.real,
                    154:                        &token[t_num].l_val.v.cmplx_val.imag,
                    155:                        &brace) != 3) || (brace != RBRACE))
                    156:                int_error("invalid complex constant", t_num);
                    157: #endif
                    158:            token[t_num].length += 2;
                    159:            while (expression[++current] != RBRACE) {
                    160:                token[t_num].length++;
                    161:                if (expression[current] == NUL) /* { for vi % */
                    162:                    int_error("no matching '}'", t_num);
                    163:            }
                    164:        } else if (expression[current] == '\'' || expression[current] == '\"') {
                    165:            token[t_num].length++;
                    166:            quote = expression[current];
                    167:            while (expression[++current] != quote) {
                    168:                if (!expression[current]) {
                    169:                    expression[current] = quote;
                    170:                    expression[current + 1] = NUL;
                    171:                    break;
                    172:                } else if (expression[current] == '\\'
                    173:                           && expression[current + 1]) {
                    174:                    current++;
                    175:                    token[t_num].length += 2;
1.1.1.3 ! ohara     176:                } else if (quote == '\"' && expression[current] == '`') {
        !           177:                    substitute(expressionp, expressionlenp, current);
        !           178:                    expression = *expressionp; /* it might have moved */
        !           179:                    current--;
1.1       maekawa   180:                } else
                    181:                    token[t_num].length++;
                    182:            }
                    183:        } else
                    184:            switch (expression[current]) {
                    185:            case '#':           /* DFK: add comments to gnuplot */
                    186:                goto endline;   /* ignore the rest of the line */
                    187:            case '^':
                    188:            case '+':
                    189:            case '-':
                    190:            case '/':
                    191:            case '%':
                    192:            case '~':
                    193:            case '(':
                    194:            case ')':
                    195:            case '[':
                    196:            case ']':
                    197:            case ';':
                    198:            case ':':
                    199:            case '?':
                    200:            case ',':
                    201:            case '$':           /* div */
                    202:                break;
                    203:            case '&':
                    204:            case '|':
                    205:            case '=':
                    206:            case '*':
                    207:                if (expression[current] == expression[current + 1])
                    208:                    APPEND_TOKEN;
                    209:                break;
                    210:            case '!':
                    211:            case '<':
                    212:            case '>':
                    213:                if (expression[current + 1] == '=')
                    214:                    APPEND_TOKEN;
                    215:                break;
                    216:            default:
                    217:                int_error("invalid character", t_num);
                    218:            }
                    219:        ++t_num;                /* next token if not white space */
                    220:     }
                    221:
                    222:   endline:                     /* comments jump here to ignore line */
                    223:
                    224: /* Now kludge an extra token which points to '\0' at end of expression[].
                    225:    This is useful so printerror() looks nice even if we've fallen off the
                    226:    line. */
                    227:
                    228:     token[t_num].start_index = current;
                    229:     token[t_num].length = 0;
                    230:     /* print 3+4  then print 3+  is accepted without
                    231:      * this, since string is ignored if it is not
                    232:      * a token
                    233:      */
                    234:     token[t_num].is_token = TRUE;
                    235:     return (t_num);
                    236: }
                    237:
                    238:
                    239: static int get_num(str)
                    240: char str[];
                    241: {
                    242:     register int count = 0;
                    243:     register long lval;
                    244:
                    245:     token[t_num].is_token = FALSE;
                    246:     token[t_num].l_val.type = INTGR;   /* assume unless . or E found */
                    247:     while (isdigit((int) str[count]))
                    248:        count++;
                    249:     if (str[count] == '.') {
                    250:        token[t_num].l_val.type = CMPLX;
                    251:        /* swallow up digits until non-digit */
                    252:        while (isdigit((int) str[++count]))
                    253:            ;
                    254:        /* now str[count] is other than a digit */
                    255:     }
                    256:     if (str[count] == 'e' || str[count] == 'E') {
                    257:        token[t_num].l_val.type = CMPLX;
                    258: /* modified if statement to allow + sign in exponent
                    259:    rjl 26 July 1988 */
                    260:        count++;
                    261:        if (str[count] == '-' || str[count] == '+')
                    262:            count++;
                    263:        if (!isdigit((int) str[count])) {
                    264:            token[t_num].start_index += count;
                    265:            int_error("expecting exponent", t_num);
                    266:        }
                    267:        while (isdigit((int) str[++count]));
                    268:     }
                    269:     if (token[t_num].l_val.type == INTGR) {
                    270:        lval = atol(str);
                    271:        if ((token[t_num].l_val.v.int_val = lval) != lval)
                    272:            int_error("integer overflow; change to floating point", t_num);
                    273:     } else {
                    274:        token[t_num].l_val.v.cmplx_val.imag = 0.0;
                    275:        token[t_num].l_val.v.cmplx_val.real = atof(str);
                    276:     }
                    277:     return (count);
                    278: }
                    279:
                    280: #if defined(VMS) || defined(PIPES) || (defined(ATARI) || defined(MTOS)) && defined(__PUREC__)
                    281:
                    282: /* A macro to reduce clutter ... */
                    283: # ifdef AMIGA_AC_5
                    284: #  define CLOSE_FILE_OR_PIPE ((void) close(fd))
                    285: # elif (defined(ATARI) || defined(MTOS)) && defined(__PUREC__)
                    286: #  define CLOSE_FILE_OR_PIPE ((void) fclose(f); (void) unlink(atari_tmpfile))
                    287: # else /* Rest of the world */
                    288: #  define CLOSE_FILE_OR_PIPE ((void) pclose(f))
                    289: # endif
                    290:
1.1.1.3 ! ohara     291: /* substitute output from ` `
        !           292:  * *strp points to the input string.  (*strp)[current] is expected to
        !           293:  * be the initial back tic.  Characters through the following back tic
        !           294:  * are replaced by the output of the command.  extend_input_line()
        !           295: * is called to extend *strp array if needed.
        !           296:  */
        !           297: static void substitute(strp, str_lenp, current)
        !           298:     char **strp;
        !           299:     int *str_lenp;
        !           300:     int current;
1.1       maekawa   301: {
                    302:     register char *last;
1.1.1.3 ! ohara     303:     register int c;
1.1       maekawa   304:     register FILE *f;
                    305: # ifdef AMIGA_AC_5
                    306:     int fd;
                    307: # elif (defined(ATARI) || defined(MTOS)) && defined(__PUREC__)
                    308:     char *atari_tmpfile;
                    309: # endif /* !AMIGA_AC_5 */
1.1.1.3 ! ohara     310:     char *str, *pgm, *rest = NULL;
        !           311:     int pgm_len, rest_len;
1.1       maekawa   312:
                    313: # ifdef VMS
                    314:     int chan, one = 1;
1.1.1.3 ! ohara     315:     struct dsc$descriptor_s pgmdsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};
1.1       maekawa   316:     static $DESCRIPTOR(lognamedsc, MAILBOX);
                    317: # endif /* VMS */
                    318:
                    319:     /* forgive missing closing backquote at end of line */
1.1.1.3 ! ohara     320:     str = *strp + current;
1.1       maekawa   321:     last = str;
                    322:     while (*++last) {
1.1.1.3 ! ohara     323:        if (*last == '`')
1.1       maekawa   324:            break;
1.1.1.3 ! ohara     325:     }
        !           326:     pgm_len = last - str;
        !           327:     pgm = gp_alloc(pgm_len, "command string");
        !           328:     safe_strncpy(pgm, str + 1, pgm_len); /* omit ` to leave room for NUL */
        !           329:
        !           330:     /* save rest of line, if any */
        !           331:     if (*last) {
        !           332:        last++;                 /* advance past ` */
        !           333:        rest_len = strlen(last) + 1;
        !           334:        if (rest_len > 1) {
        !           335:            rest = gp_alloc(rest_len, "input line copy");
        !           336:            strcpy(rest, last);
1.1       maekawa   337:        }
                    338:     }
                    339:
                    340: # ifdef VMS
1.1.1.3 ! ohara     341:     pgmdsc.dsc$a_pointer = pgm;
        !           342:     pgmdsc.dsc$w_length = pgm_len;
1.1       maekawa   343:     if (!((vaxc$errno = sys$crembx(0, &chan, 0, 0, 0, 0, &lognamedsc)) & 1))
                    344:        os_error("sys$crembx failed", NO_CARET);
                    345:
                    346:     if (!((vaxc$errno = lib$spawn(&pgmdsc, 0, &lognamedsc, &one)) & 1))
                    347:        os_error("lib$spawn failed", NO_CARET);
                    348:
                    349:     if ((f = fopen(MAILBOX, "r")) == NULL)
                    350:        os_error("mailbox open failed", NO_CARET);
                    351: # elif (defined(ATARI) || defined(MTOS)) && defined(__PUREC__)
                    352:     if (system(NULL) == 0)
                    353:        os_error("no command shell", NO_CARET);
                    354:     atari_tmpfile = tmpnam(NULL);
1.1.1.3 ! ohara     355:     gp_realloc(pgm, pgm_len + 5 + strlen(atari_tmpfile), "command string");
        !           356:     strcat(pgm, " >> ");
        !           357:     strcat(pgm, atari_tmpfile);
        !           358:     system(pgm);
1.1       maekawa   359:     if ((f = fopen(atari_tmpfile, "r")) == NULL)
                    360: # elif defined(AMIGA_AC_5)
                    361:     if ((fd = open(pgm, "O_RDONLY")) == -1)
                    362: # else /* everyone else */
                    363:     if ((f = popen(pgm, "r")) == NULL)
                    364:        os_error("popen failed", NO_CARET);
                    365: # endif /* !VMS */
                    366:
1.1.1.3 ! ohara     367:     free(pgm);
        !           368:
        !           369:     /* now replace ` ` with output */
        !           370:     while (1) {
        !           371: # if defined(AMIGA_AC_5)
        !           372:        char ch;
        !           373:        if (read(fd, &ch, 1) != 1)
        !           374:            break;
        !           375:        c = ch;
        !           376: # else
        !           377:        if ((c = getc(f)) == EOF)
        !           378:            break;
        !           379: # endif /* !AMIGA_AC_5 */
        !           380:        /* newlines become blanks */
        !           381:        (*strp)[current++] = ((c == '\n') ? ' ' : c);
        !           382:        if (current == *str_lenp)
        !           383:            extend_input_line();
1.1       maekawa   384:     }
1.1.1.3 ! ohara     385:     (*strp)[current] = 0;
1.1       maekawa   386:
                    387:     CLOSE_FILE_OR_PIPE;
                    388:
                    389:     /* tack on rest of line to output */
1.1.1.3 ! ohara     390:     if (rest) {
        !           391:        while (current + rest_len > *str_lenp)
        !           392:            extend_input_line();
        !           393:        strcpy(*strp+current, rest);
        !           394:        free(rest);
        !           395:     }
        !           396:
1.1       maekawa   397:     screen_ok = FALSE;
                    398: }
                    399:
                    400: #else /* VMS || PIPES || ATARI && PUREC */
                    401:
1.1.1.3 ! ohara     402: static void substitute(strp, str_lenp, current)
        !           403: char **strp;
        !           404: int *str_lenp;
        !           405: int current;
1.1       maekawa   406: {
                    407:     char line[100];
                    408:
                    409:     sprintf(line, "substitution not supported by %s", OS);
                    410:     int_error(line, t_num);
                    411: }
                    412:
                    413: #endif /* unix || VMS || PIPES || ATARI && PUREC */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>