|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T i
Length: 15883 (0x3e0b) Types: TextFile Names: »iscan.c«
└─⟦a05ed705a⟧ Bits:30007078 DKUUG GNU 2/12/89 └─⟦ff23ba0e6⟧ »./ghostscript-1.3.tar.Z« └─⟦a24a58cd3⟧ └─⟦this⟧ »iscan.c«
/* Copyright (C) 1989 Aladdin Enterprises. All rights reserved. Distributed by Free Software Foundation, Inc. This file is part of Ghostscript. Ghostscript is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to anyone for the consequences of using it or for whether it serves any particular purpose or works at all, unless he says so in writing. Refer to the Ghostscript General Public License for full details. Everyone is granted permission to copy, modify and redistribute Ghostscript, but only under the conditions described in the Ghostscript General Public License. A copy of this license is supposed to have been given to you along with Ghostscript so you can know your rights and responsibilities. It should be in a file named COPYING. Among other things, the copyright notice and this notice must be preserved on all copies. */ /* iscan.c */ /* Token scanner for GhostScript interpreter */ #include <stdio.h> /* for stream.h */ #include <ctype.h> #include "ghost.h" #include "alloc.h" #include "dict.h" /* for //name lookup */ #include "errors.h" #include "store.h" #include "stream.h" /* Array packing flag */ int array_packing; /* Forward references */ private int scan_hex_string(P3(stream *, ref *, byte *(*)())), scan_int(P4(register stream *, int, ulong *, double *)), scan_name(P3(stream *, int, ref *)), scan_string(P4(stream *, int, ref *, byte *(*)())); /* Import the dictionary stack for //name lookup */ extern ref *dsp; /* Static constants */ private ref left_bracket; private ref right_bracket; /* An array for fast scanning of names and hex strings. */ /* Indexed by character code (including EOFC), it contains: */ /* 0 - 15 for valid hex digits, */ /* ctype_name for other characters valid in names, */ /* ctype_space for whitespace characters, */ /* ctype_eof for end-of-file, and */ /* ctype_other for everything else. */ private char scan_char_array[257]; char *scan_char_decoder = &scan_char_array[1]; /* account for EOFC */ #define ctype_name 0x10 #define ctype_space 0x11 #define ctype_other 0x12 #define ctype_eof 0x13 /* Type definition for alloc_shrink and alloc_shrink_copy */ typedef byte *(*alloc_end_proc)(P4(byte *, uint, uint, char *)); /* A structure for dynamically growable objects */ typedef struct dynamic_area_s { byte *base; byte *next; uint size; byte *limit; } dynamic_area; /* Begin a dynamic object */ /* Note that alloc_dynamic may return 0: the invoker of dynamic_begin */ /* must test the value against 0. */ #define dynamic_begin(pda, dsize)\ ((pda)->limit =\ ((pda)->base = alloc_dynamic((pda)->size = (dsize), "scanner")) +\ (dsize),\ (pda)->next = (pda)->base) /* Grow a dynamic object */ private int dynamic_grow(register dynamic_area *pda) { uint size = pda->size; uint pos = pda->next - pda->base; size = (size >= (uint)(-1) >> 1 ? (uint)(-1) : size << 1); pda->base = alloc_grow(pda->base, pda->size, size, "scanner"); if ( pda->base == 0 ) return 0; pda->limit = pda->base + (pda->size = size); pda->next = pda->base + pos; return 1; } /* Get rid of an unwanted dynamic object */ #define dynamic_free(pda)\ alloc_free((char *)((pda)->base), (pda)->size, "scanner") /* Initialize the scanner. */ void scan_init() { /* Precompute left and right bracket tokens */ { name_ref("[", 1, &left_bracket, 0); r_set_attrs(&left_bracket, a_executable); name_ref("]", 1, &right_bracket, 0); r_set_attrs(&right_bracket, a_executable); } /* Initialize decoder array */ { int i; static char hex_chars[] = "0123456789ABCDEFabcdef"; static char stop_chars[] = "()<>[]{}/%"; char *p; scan_char_decoder[-1] = ctype_eof; for ( i = 0; i < 256; i++ ) scan_char_decoder[i] = (isspace(i) ? ctype_space : ctype_name); for ( i = 0; i < 16+6; i++ ) scan_char_decoder[hex_chars[i]] = (i >= 16 ? i - 6 : i); for ( p = stop_chars; *p; ) scan_char_decoder[*p++] = ctype_other; scan_char_decoder[26] = ctype_space; /* ^Z */ } array_packing = 0; } /* Read a token from a stream. */ /* Return 1 for end-of-stream, 0 if a token was read, */ /* or a (negative) error code. */ /* fromString indicates reading from a string vs. a file, */ /* because \ escapes are not recognized in the former case. */ /* (See the footnote on p. 23 of the PostScript manual.) */ int scan_token(register stream *s, int from_string, ref *pref) { ref *myref = pref; dynamic_area da; int pstack = 0; /* offset from da.base */ alloc_end_proc alend = alloc_shrink; int retcode = 0; register int c; int c1; top: c = sgetc(s); #ifdef DEBUG if ( gs_debug['s'] ) printf((c >= 32 && c <= 126 ? "`%c'" : "`%03o'"), c); #endif switch ( c ) { case ' ': case '\t': case '\n': case '\r': case 26: /* ^Z */ goto top; case '[': *myref = left_bracket; break; case ']': *myref = right_bracket; break; case '<': retcode = scan_hex_string(s, myref, alend); break; case '(': retcode = scan_string(s, from_string, myref, alend); break; case '{': if ( pstack == 0 ) { myref = (ref *)dynamic_begin(&da, 20 * sizeof(ref)); if ( myref == 0 ) return e_VMerror; } if ( da.limit - (byte *)myref < 2 * sizeof(ref) ) { da.next = (byte *)myref; if ( !dynamic_grow(&da) ) return e_VMerror; myref = (ref *)da.next; } myref->size = pstack; myref++; pstack = (byte *)myref - da.base; alend = alloc_shrink_copy; goto top; case '>': case ')': retcode = e_syntaxerror; break; case '}': if ( pstack == 0 ) { retcode = e_syntaxerror; break; } { ref *ref0 = (ref *)(da.base + pstack); uint size = myref - ref0; ref *aref = (ref *)alloc(size * sizeof(ref), "scanner"); if ( aref == 0 ) return e_VMerror; memcpy(aref, ref0, size * sizeof(ref)); myref = ref0 - 1; pstack = myref->size; if ( pstack == 0 ) { myref = pref; alloc_free((char *)da.base, da.size, "scanner"); } if ( array_packing ) make_tasv(myref, t_packedarray, a_executable + a_read + a_execute, size, refs, aref); else make_tasv(myref, t_array, a_executable + a_all, size, refs, aref); } break; case '/': { int lookup; c = sgetc(s); if ( c == '/' ) { lookup = 1; c = sgetc(s); } else lookup = 0; retcode = scan_name(s, c, myref); if ( retcode >= 0 && lookup && r_type(myref) == t_name ) /* might be a number */ { /* Look up the name now. */ ref *pvalue = dict_search(myref, dsp); if ( pvalue == 0 ) retcode = e_undefined; else store(myref, *pvalue); } } break; case '%': do { c = sgetc(s); } while ( c != '\n' && c != '\r' && c != EOFC ); if ( c == '\r' && (c1 = sgetc(s)) != '\n' && c1 != EOFC ) sputback(s); if ( c != EOFC ) goto top; case EOFC: retcode = (pstack != 0 ? e_syntaxerror : 1); break; /* Add enough cases to force the compiler to generate */ /* a dispatch rather than a comparison loop. */ /* What a nuisance! */ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': default: retcode = scan_name(s, c, myref); if ( r_type(myref) == t_name ) /* might be a number */ r_set_attrs(myref, a_executable); } /* If we are the top level, return the object, otherwise keep going */ if ( pstack == 0 || retcode < 0 ) return retcode; if ( da.limit - (byte *)myref < 2 * sizeof(ref) ) { da.next = (byte *)myref; if ( !dynamic_grow(&da) ) return e_VMerror; /* out of room */ myref = (ref *)da.next; } myref++; goto top; } /* The internal scanning procedures return 0 on success, */ /* or a (negative) error code on failure. */ /* Internal procedure to scan a name. */ private int scan_name(register stream *s, register int c, ref *pref) { dynamic_area da; register byte *ptr; register char *decoder = scan_char_decoder; int try_number; int code; /* See if this name might be a number */ skip: switch ( decoder[c] ) { case ctype_space: c = sgetc(s); goto skip; case ctype_name: try_number = (c == '+' || c == '-' || c == '.'); break; case ctype_other: switch ( c ) { case '[': /* only special as first character */ *pref = left_bracket; r_clear_attrs(pref, a_executable); return 0; case ']': /* ditto */ *pref = right_bracket; r_clear_attrs(pref, a_executable); return 0; default: return e_syntaxerror; } case ctype_eof: /* eof following / */ return e_syntaxerror; default: try_number = isdigit(c); } ptr = dynamic_begin(&da, 40); if ( ptr == 0 ) return e_VMerror; while ( 1 ) { if ( ptr == da.limit ) { da.next = ptr; if ( !dynamic_grow(&da) ) return e_VMerror; ptr = da.next; } *ptr++ = c; c = sgetc(s); switch ( decoder[c] ) { case ctype_other: sputback(s); case ctype_space: /* Check for \r\n */ if ( c == '\r' && (c = sgetc(s)) != '\n' && c != EOFC ) sputback(s); case ctype_eof: goto nx; } } nx: /* Check for a number */ if ( try_number ) { stream nst; stream *ns = &nst; sread_string(ns, da.base, (uint)(ptr - da.base)); code = scan_number(ns, pref); if ( code != e_syntaxerror ) { dynamic_free(&da); return code; /* might be e_limitcheck */ } } code = name_ref(da.base, (uint)(ptr - da.base), pref, 1); dynamic_free(&da); return code; } /* Procedure to scan a number. This is also called by cvi and cvr. */ int scan_number(register stream *s, ref *pref) { int sign = 0; ulong ival; double dval; int code; register int c; switch ( c = sgetc(s) ) { case '+': sign = 1; c = sgetc(s); break; case '-': sign = -1; c = sgetc(s); break; } if ( !isdigit(c) ) { if ( c != '.' ) return e_syntaxerror; c = sgetc(s); if ( !isdigit(c) ) return e_syntaxerror; goto ff; } sputback(s); if ( (code = scan_int(s, 10, &ival, &dval)) != 0 ) { if ( code < 0 ) return code; /* e_syntaxerror */ /* Code == 1, i.e., the integer overflowed. */ switch ( c = sgetc(s) ) { default: return e_syntaxerror; /* not terminated properly */ case '.': c = sgetc(s); goto ff; case EOFC: /* return a float */ make_real(pref, (float)(sign < 0 ? -dval : dval)); return 0; } } switch ( c = sgetc(s) ) { default: return e_syntaxerror; /* not terminated properly */ case '.': dval = ival; c = sgetc(s); goto ff; case '#': if ( sign || ival < 2 || ival > 36 ) return e_syntaxerror; code = scan_int(s, (int)ival, &ival, NULL); if ( code ) return code; if ( sgetc(s) != EOFC ) return e_syntaxerror; case EOFC: ; } /* Return an integer */ make_int(pref, (sign < 0 ? -ival : ival)); return 0; /* Handle a real. We just saw the decimal point. */ ff: { int exp10 = 0; double epow; while ( isdigit(c) ) { dval = dval * 10 + (c - '0'); c = sgetc(s); exp10--; } if ( c == 'e' || c == 'E' ) { /* Check for a following exponent. */ int esign = 0; ulong eexp; switch ( c = sgetc(s) ) { case '+': break; case '-': esign = 1; break; default: sputback(s); } code = scan_int(s, 10, &eexp, NULL); if ( code < 0 ) return code; if ( code > 0 || eexp > 999 ) return e_limitcheck; /* semi-arbitrary */ if ( esign ) exp10 -= (int)eexp; else exp10 += (int)eexp; c = sgetc(s); } if ( c != EOFC ) return e_syntaxerror; /* Compute dval * 10^exp10. */ /* The following doesn't produce very accurate results, */ /* but it's simple and will do for now. */ if ( exp10 >= 0 ) epow = 10.0; else exp10 = -exp10, epow = 0.1; while ( exp10 ) { if ( exp10 & 1 ) dval *= epow; exp10 >>= 1; epow *= epow; } make_real(pref, (float)(sign < 0 ? -dval : dval)); } return 0; } /* Internal subroutine to scan an integer. */ /* Return 0, e_limitcheck, or e_syntaxerror. */ /* (The only syntax error is no digits encountered.) */ /* If pdval == NULL, return e_limitcheck if the integer won't fit; */ /* if pdval != NULL, return 1 and store a double value in *pdval. */ /* Put back the terminating character. */ private int scan_int(register stream *s, int radix, ulong *pval, double *pdval) { ulong ival = 0; double dval; ulong imax = (ulong)(-1) / radix; int irem = (ulong)(-1) % radix; register int c; while ( 1 ) { c = sgetc(s); if ( isdigit(c) ? (c -= '0') >= radix : isalpha(c) ? (c = toupper(c) - ('A' - 10)) >= radix : 1 ) { if ( c != EOFC ) sputback(s); *pval = ival; return 0; } if ( ival >= imax && (ival > imax || c > irem) ) break; /* overflow */ ival = ival * radix + c; } /* Integer overflowed. Accumulate the result as a double. */ if ( pdval == NULL ) return e_limitcheck; dval = (double)ival * radix + c; while ( 1 ) { c = sgetc(s); if ( isdigit(c) ? (c -= '0') >= radix : isalpha(c) ? (c = toupper(c) - ('A' - 10)) >= radix : 1 ) { if ( c != EOFC ) sputback(s); *pdval = dval; return 1; } dval = dval * radix + c; } } /* Make a string */ private int mk_string(ref *pref, dynamic_area *pda, alloc_end_proc alend) { uint size = pda->next - pda->base; byte *body = (*alend)(pda->base, pda->size, size, "scanner(string)"); if ( body == 0 ) return e_VMerror; make_tasv(pref, t_string, a_all, size, bytes, body); return 0; } /* Internal procedure to scan a string. */ private int scan_string(register stream *s, int from_string, ref *pref, alloc_end_proc alend) { dynamic_area da; register int c; register byte *ptr = dynamic_begin(&da, 100); int plevel = 0; if ( ptr == 0 ) return e_VMerror; top: while ( 1 ) { c = sgetc(s); if ( c == EOFC ) return e_syntaxerror; else if ( c == '(' ) plevel++; else if ( c == ')' ) { if ( --plevel < 0 ) break; } else if ( c == '\\' && !from_string ) { c = sgetc(s); switch ( c ) { case 'n': c = '\n'; break; case 'r': c = '\r'; break; case 't': c = '\t'; break; case 'b': c = '\b'; break; case 'f': c = '\f'; break; case '\n': goto top; /* ignore */ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': { int d = sgetc(s); c -= '0'; if ( d >= '0' && d <= '7' ) { c = (c << 3) + d - '0'; d = sgetc(s); if ( d >= '0' && d <= '7' ) { c = (c << 3) + d - '0'; break; } } if ( d == EOFC ) return e_syntaxerror; sputback(s); } break; default: ; /* ignore the \ */ } } if ( ptr == da.limit ) { da.next = ptr; if ( !dynamic_grow(&da) ) return e_VMerror; ptr = da.next; } *ptr++ = c; } da.next = ptr; return mk_string(pref, &da, alend); } /* Internal procedure to scan a hex string. */ private int scan_hex_string(stream *s, ref *pref, alloc_end_proc alend) { dynamic_area da; int c1, c2, val1, val2; byte *ptr = dynamic_begin(&da, 40); if ( ptr == 0 ) return e_VMerror; l1: do { c1 = sgetc(s); if ( (val1 = scan_char_decoder[c1]) < 0x10 ) { do { c2 = sgetc(s); if ( (val2 = scan_char_decoder[c2]) < 0x10 ) { if ( ptr == da.limit ) { da.next = ptr; if ( !dynamic_grow(&da) ) return e_VMerror; ptr = da.next; } *ptr++ = (val1 << 4) + val2; goto l1; } } while ( val2 == ctype_space ); if ( c2 != '>' ) return e_syntaxerror; if ( ptr == da.limit ) { da.next = ptr; if ( !dynamic_grow(&da) ) return e_VMerror; ptr = da.next; } *ptr++ = val1 << 4; /* no 2nd char */ goto lx; } } while ( val1 == ctype_space ); if ( c1 != '>' ) return e_syntaxerror; lx: da.next = ptr; return mk_string(pref, &da, alend); }