#ifndef lint static char sccsid[] = "@(#)parse_file.h 9.3 88/01/19 Copyright 1987 Sun Micro"; #endif /*- * Parse a PostScript object from a PSFILE * * parse_file.h, Mon Dec 31 09:36:02 1984 * * James Gosling, * Sun Microsystems */ #define MAXIMUM_REASONABLE_BUFFER_SIZE 3000 /* ctype.h should really have this! */ #define isoctdigit(c) ('0' <= (c) && (c)<='7') #define check_buffer(n) \ if (ee->fill+n >= ee->bufsize) { \ if (ee->bufsize) \ ee->static_buffer = (char *) snooprealloc("parse_file.h", ee->static_buffer, ee->bufsize = (ee->fill+n) * 3 / 2); \ else \ ee->static_buffer = (char *) snoopalloc("parse_file.h", ee->bufsize = n+256); \ ee->bufsize -= 3; /* slop */ \ } /* * This is a version of getc that pauses if the buffer is empty and suspends * the process */ #ifdef DEBUG #define Debugging(x) x #else #define Debugging(x) #endif #ifdef undef #ifdef PREVIEW #define pf_getc(e,c) { \ if (--(f)->_cnt>=0) c = *(f)->_ptr++&0377; \ else while (1) { \ ee->restart_state = e; \ ee->event = fileno(f) + 1; \ goto suspend_process; \ CPPCONCAT(read_,e): \ f = es->env.file.file; \ c = _filbuf(f); \ if (c>=0 || !psio_error(f) || errno != EWOULDBLOCK) break; \ f->_flag &= ~_IOERR; \ } \ if (c == '\n') \ repaint = 1; \ } #else #define pf_getc(e,c) { \ if (--(f)->_cnt>=0) c = *(f)->_ptr++&0377; \ else while (1) { \ ee->restart_state = e; \ ee->event = fileno(f) + 1; \ goto suspend_process; \ CPPCONCAT(read_,e): \ f = es->env.file.file; \ c = _filbuf(f); \ if (c>=0 || !psio_error(f) || errno != EWOULDBLOCK) break; \ f->_flag &= ~_IOERR; \ } \ } #endif #endif #define pf_getc0(e,c) \ psio_pgetc(f, c, \ ee->restart_state = e; \ ee->event = psio_fileno(f) + 1; \ goto suspend_process; \ CPPCONCAT(read_,e): \ f = es->env.file.file); #ifdef PREVIEW #define pf_getc(e,c) { \ pf_getc0(e, c); \ if (c == '\n') \ repaint = 1; \ } #else #define pf_getc(e,c) pf_getc0(e,c) #endif #ifdef INDENT struct object parse_file(f) register PSFILE *f; #endif { register c; #ifdef PREVIEW int repaint; extern int usingtty; #endif #ifdef GPROF_HOOKS asm("gP_GetFile:"); #endif restart_parse: ee->ofill = ee->fill; #if QLOGFLAG qlog_chain_check(); #endif while (1) { #ifdef GPROF_HOOKS asm("gP_ParseLoopTop:"); #endif #ifdef PREVIEW if (repaint && usingtty) { repaint = 0; showpage(); } #endif pf_getc(1, c); if (c == '%') { do { pf_getc(2, c); } while (c != '\n' && c != EOF); } else if (!isspace(c) || c >= 0200) break; }; if ((c & 0200) == 0) switch (c) { case '[': case ']': #ifdef GPROF_HOOKS asm("gP_ParseCloseBracket:"); #endif check_buffer(0); ee->static_buffer[ee->fill++] = c; goto its_an_identifier; case '(': { #define depth ee->execee.value.fixed #ifdef GPROF_HOOKS asm("gP_ParseOpenParen:"); #endif depth = 0; while (1) { pf_getc(3, c); if (c == EOF || (c == ')' && --depth < 0)) break; switch (c) { case '(': depth++; break; case BACKSLASH: pf_getc(4, c); switch (c) { case '\n': goto ignore_character; case 'b': c = 010; break; case 'f': c = 014; break; case 'n': c = 012; break; case 'r': c = 015; break; case 't': c = 011; break; default: if (isoctdigit(c)) { register n = c & 7; pf_getc(5, c); if (isoctdigit(c)) { n = (n << 3) + (c & 7); pf_getc(6, c); if (isoctdigit(c)) n = (n << 3) + (c & 7); else psio_ungetc(c, f); } else psio_ungetc(c, f); c = n; } } break; } check_buffer(0); ee->static_buffer[ee->fill++] = c; ignore_character:; } ee->execee = make_string(ee->fill - ee->ofill, ee->static_buffer + ee->ofill); #undef depth } break; case '<': #ifdef GPROF_HOOKS asm("gP_ParseHexOpen:"); #endif while (1) { do { pf_getc(7, c); } while (isspace(c)); if (!isxdigit(c)) break; check_buffer(0); ee->static_buffer[ee->fill] = (c <= '9' ? c - '0' : (c & 037) + 9) << 4; do { pf_getc(8, c); } while (isspace(c)); if (!isxdigit(c)) break; ee->static_buffer[ee->fill++] |= (c <= '9' ? c - '0' : (c & 037) + 9); } ee->execee = make_string(ee->fill - ee->ofill, ee->static_buffer + ee->ofill); break; case '{': #ifdef GPROF_HOOKS asm("gP_ParseOpenBrace:"); #endif check_buffer(sizeof(int) * 3); /* Sparc crapS out on misaligned ints! -deh */ /* 0=>3 1=>2 2=>1 3=>0 */ ee->ofill += (sizeof(int) - 1) - /* align next byte */ (((int) (ee->static_buffer + ee->ofill)) & (sizeof(int) - 1)); /* byte before aligned word */ *(char *) (ee->static_buffer + ee->ofill) = /* push offset */ (ee->ofill - ee->fill); ee->ofill += sizeof(char); /* now we're aligned */ *(int *) (ee->static_buffer + ee->ofill) = ee->arrstart; ee->ofill += sizeof(int); ee->arrstart = ee->fill = ee->ofill; goto restart_parse; case '}': #ifdef GPROF_HOOKS asm("gP_ParseCloseBrace:"); #endif if (ee->arrstart < 0) goto syntax_error; ee->execee = make_growable_object(array_type, ee->static_buffer + ee->arrstart, (ee->fill - ee->arrstart) / sizeof(struct object)); ee->execee.executable = 1; ee->ofill = ee->arrstart - sizeof(int); ee->arrstart = *(int *) (ee->static_buffer + ee->ofill); ee->ofill -= sizeof(char); /* pop offset and restore alignment */ ee->ofill -= *(char *) (ee->static_buffer + ee->ofill); if (ee->fill > MAXIMUM_REASONABLE_BUFFER_SIZE && ee->ofill < MAXIMUM_REASONABLE_BUFFER_SIZE) { ee->bufsize = MAXIMUM_REASONABLE_BUFFER_SIZE; ee->static_buffer = (char *) snooprealloc("parse_file.h", ee->static_buffer, ee->bufsize); } break; case '/': #ifdef GPROF_HOOKS asm("gP_ParseSlash:"); #endif do { check_buffer(0); ee->static_buffer[ee->fill++] = c; pf_getc(9, c); } while (c == '/'); default: #ifdef GPROF_HOOKS asm("gP_ParseDefault:"); #endif if (c > 127) { psio_ungetc(c, f); } else { while (1) { check_buffer(0); ee->static_buffer[ee->fill++] = c; pf_getc(10, c); if (c <= ' ') break; if (delim[c]) { psio_ungetc(c, f); break; } } } #ifdef GPROF_HOOKS asm("gP_ParseCommon:"); #endif if (ee->static_buffer[ee->ofill] <= '9') { register char *sc; register char *limit; register n = 0; register base = 10; register neg = 0; int setbase = 0; int digits = 0; unsigned int maxn = ((unsigned long) (1 << 30)) / 5; int exp1 = 0, dot = 0; sc = ee->static_buffer + ee->ofill; limit = ee->static_buffer + ee->fill; if (*sc == '-') { neg++, sc++; } else if (*sc == '+') sc++; while (sc < limit) { if (*sc == '.') if (dot) goto its_an_identifier; else dot = 1, sc++; else if (*sc == '#') if (setbase || dot || base != 10 || n < 2 || n > 36) goto its_an_identifier; else { base = n; n = 0; setbase++; sc++; maxn = ((unsigned long) (1 << 31)) / base; } else if ((c = translate_digit[*sc]) < base) { sc++; if (n >= maxn) { if (!dot) exp1++; } else { n = n * base + c; exp1 -= dot; digits++; } } else if (*sc == 'e' || *sc == 'E') { int exp2 = 0; int eneg = 0; if (digits == 0 || setbase) goto its_an_identifier; sc++; digits = 0; if (sc >= limit) goto its_an_identifier; if (*sc == '-') eneg++, sc++; else if (*sc == '+') sc++; while (sc < limit && isdigit(*sc)) { exp2 = exp2 * 10 + *sc++ - '0'; digits++; } if (eneg) exp1 -= exp2; else exp1 += exp2; if (sc < limit) goto its_an_identifier; break; } else goto its_an_identifier; } if (digits == 0) goto its_an_identifier; #ifdef GPROF_HOOKS asm("gP_ParseNumber:"); #endif clear_object(&ee->execee); if (exp1 ? digits + exp1 > 4 || exp1 < -4 : n >= (1 << 15)) { int eneg = 0; if (exp1 < 0) eneg = 1, exp1 = -exp1; if (exp1 < 10) { /* two cases for different ranges of * exponents: all in the name of a few * more microseconds */ int fact = 1; while (--exp1 >= 0) fact *= 10; if (eneg) ee->execee.value.real = ((float) n) / ((float) fact); else ee->execee.value.real = ((float) n) * ((float) fact); } else { double fact = 1; while (--exp1 >= 0) fact *= 10; if (eneg) ee->execee.value.real = ((float) n) / fact; else ee->execee.value.real = ((float) n) * fact; } if (neg) ee->execee.value.real = -ee->execee.value.real; ee->execee.type = real_type; } else { ee->execee.type = fixed_type; if (exp1 == 0) ee->execee.value.fixed = fracti(neg ? -n : n); else if (exp1 < 0) { register denom = 10; while (++exp1 < 0) denom *= 10; if (n < (1 << 15)) ee->execee.value.fixed = fracti(neg ? -n : n) / denom; else { register ipart = n / denom; ee->execee.value.fixed = fracti(ipart) + ((n - ipart * denom) << 15) / (denom >> 1); if (neg) ee->execee.value.fixed = -ee->execee.value.fixed; } } else { register fact = 10; while (--exp1 > 0) fact *= 10; ee->execee.value.fixed = fracti((neg ? -n : n) * fact); } } ee->execee.executable = 0; } else its_an_identifier: { register struct body *p; register char *start = ee->static_buffer + ee->ofill; register len = ee->fill - ee->ofill; register hash; register executable = 1; int rlen; #ifdef GPROF_HOOKS asm("gP_ParseIdent:"); #endif while (*start == '/') { executable--; start++; len--; } rlen = len; hash = 0; while (--len >= 0) hash = (hash << 5) - hash + *start++; len = rlen; start -= len; p = hash_table[rlen = /* DEBUG */ (hash & 0x7fffffff) % hash_table_size]; while (p && (p->body.keyword.hash != hash || p->body.keyword.namelen != len || strncmp(start, p->body.keyword.name, len) != 0)) p = p->body.keyword.same_bucket; if (p == 0) p = new_name(hash, start, len); #ifdef GPROF_HOOKS asm("gP_ParseExecutable:"); #endif switch (executable) { case 1: set_executable_typed_bodied_object(&ee->execee, keyword_type, p); if (ee->ofill && ee->autobind && !ee->seeking_token) { register struct dictstack_ent *stackent = ee->dict_top; register hash; hash_object(hash, &ee->execee); while (--stackent >= ee->dictionary_stack) { register struct object *ret = &stackent->body->body.array.objects[ hash_index(hash, stackent->body->body.array.size >> 1)]; while (ret->type != null_type) { if (equal_object(ret, &ee->execee)) { if (ret[1].type == called_operator_type || ret[1].type == operator_type) ee->execee = ret[1]; goto resolved_autobind; } ret -= 2; if (ret < stackent->body->body.array.objects) ret = &stackent->body->body.array.objects[stackent->body->body.array.size - 2]; } } } resolved_autobind: break; case 0: set_typed_bodied_object(&ee->execee, keyword_type, p); break; default: { register struct dictstack_ent *stackent = ee->dict_top; register hash; set_typed_bodied_object(&ee->execee, keyword_type, p); hash_object(hash, &ee->execee); while (--stackent >= ee->dictionary_stack) { register struct object *ret = &stackent->body->body.array.objects[ hash_index(hash, stackent->body->body.array.size >> 1)]; while (ret->type != null_type) { if (equal_object(ret, &ee->execee)) { object_incref(&ret[1]); ee->execee = ret[1]; break; } ret -= 2; if (ret < stackent->body->body.array.objects) ret = &stackent->body->body.array.objects[stackent->body->body.array.size - 2]; } } } } } break; } else { #ifdef GPROF_HOOKS asm("gP_ParseEncoded:"); #endif #ifdef PROCSTASH_HACK #define temp (ee->stash) #else #define temp (object_word0(&ee->execee)) #endif if (c == EOF) { register PSFILE *pff; pff = ee->stdprnt->body.file.outbuf; if (selectable_file(psio_fileno(f), 1)) remove_selectable_file(psio_fileno(f), 1); if (pff && f->file == pff->file) psio_nodropclose(pff); psio_nodropclose(f); goto pop_estack; } #define case4(tag) case tag: case tag+1: case tag+2: case tag+3 #define case16(tag) case4(tag):case4(tag+4):case4(tag+8):case4(tag+12) #define case32(tag) case16(tag):case16(tag+16) switch (c) { /* * An encoded integer: the bottom two bits of the opcode = (the * number of bytes in the integer)-1; the next two bits = the * number of bytes that are to follow the binary point */ case16(enc_int): #ifdef GPROF_HOOKS asm("gP_ParseEncodedInt:"); #endif temp = c; pf_getc(15, c); ee->execee.value.fixed = (char) c; while (temp & 3) { temp--; pf_getc(16, c); ee->execee.value.fixed = (ee->execee.value.fixed << 8) | c; } c = (2 - ((temp >> 2) & 3)) * 8; if (c > 0) ee->execee.value.fixed <<= c; else if (c < 0) ee->execee.value.fixed >>= -c; set_typed_object(&ee->execee, fixed_type); break; case enc_IEEEfloat: #ifdef GPROF_HOOKS asm("gP_ParseEncodedIEEE:"); #endif temp = 4; ee->execee.value.fixed = 0; assert(sizeof(fract) == sizeof(float)); while (--temp >= 0) { pf_getc(24, c); ee->execee.value.fixed = (ee->execee.value.fixed << 8) | c; } #if defined(vax) /* must make this look like a local floating point number * this will be done for all IEEE implementations. Other * floating point forms (like Vax, done here) need to * be explicitly converted from IEEE. */ { /* What IEEE single precision floating point looks like on a Vax */ struct ieee_single { unsigned int mant:23; unsigned int exp:8; unsigned int sign:1; }; /* Vax single precision floating point */ struct vax_single { unsigned int mant1:7; unsigned int exp:8; unsigned int sign:1; unsigned int mant2:16; }; #define VAX_SNG_BIAS 0x81 #define IEEE_SNG_BIAS 0x7f static struct sgl_limits { struct vax_single s; struct ieee_single ieee; } sgl_limits[2] = { {{ 0x7f, 0xff, 0x0, 0xffff }, /* Max Vax */ { 0x0, 0xff, 0x0 }}, /* Max IEEE */ {{ 0x0, 0x0, 0x0, 0x0 }, /* Min Vax */ { 0x0, 0x0, 0x0 }} /* Min IEEE */ }; struct ieee_single is; struct vax_single *vsp; struct sgl_limits *lim; int i; is = *((struct ieee_single *)(&ee->execee.value.fixed)); vsp = (struct vax_single *)(&ee->execee.value.fixed); for (i = 0, lim = sgl_limits; i < sizeof(sgl_limits)/sizeof(struct sgl_limits); i++, lim++) { if ((is.exp == lim->ieee.exp) && (is.mant == lim->ieee.mant)) { *vsp = lim->s; goto floatcvtdone; } } vsp->exp = is.exp - IEEE_SNG_BIAS + VAX_SNG_BIAS; vsp->mant2 = is.mant; vsp->mant1 = (is.mant >> 16); floatcvtdone: vsp->sign = is.sign; } #endif /* vax */ set_typed_object(&ee->execee, real_type); break; case16(enc_short_string): #ifdef GPROF_HOOKS asm("gP_ParseEncodedShStr:"); #endif temp = c & 017; goto read_encoded_string; case4(enc_string): #ifdef GPROF_HOOKS asm("gP_ParseEncodedStr:"); #endif temp = 0; ee->execee.value.fixed = c & 3; do { pf_getc(17, c); temp = (temp << 8) | c; } while (--ee->execee.value.fixed >= 0); read_encoded_string: #ifdef GPROF_HOOKS asm("gP_ReadEncodedStr:"); #endif ee->execee = make_string(temp, 0); { register char *p = body_of(&ee->execee)->body.string.chars; while (ee->execee.value.substring.start < ee->execee.value.substring.length) { psio_pgetc(f, c, ee->restart_state = 18; ee->event = psio_fileno(f) + 1; goto suspend_process; read_18: f = es->env.file.file; p = &body_of(&ee->execee)->body.string.chars [ee->execee.value.substring.start]; ); *p++ = c; ee->execee.value.substring.start++; } } ee->execee.value.substring.start = 0; break; case enc_syscommon2: #ifdef GPROF_HOOKS asm("gP_ParseEncodedSysCom:"); #endif pf_getc(20, c); c += 32; goto do_syscommon; case32(enc_syscommon): c -= enc_syscommon; do_syscommon: ee->execee = syscommon_vec[c]; object_incref(&ee->execee); if (ee->fill = ee->ofill) goto do_add; goto execute_top; case4(enc_lusercommon): #ifdef GPROF_HOOKS asm("gP_ParseEncodedUserCom:"); #endif temp = c - enc_lusercommon; pf_getc(21, c); c = c + (temp << 8) + 32; goto do_usercommon; case32(enc_usercommon): { register struct body *fbod; c -= enc_usercommon; do_usercommon: #ifdef GPROF_HOOKS asm("gP_DoEncodedUserCom:"); #endif fbod = body_of(&es->executed); assert(es->executed.type == file_type); if (c >= fbod->body.file.ntok) clear_object(&ee->execee); else { ee->execee = fbod->body.file.tok[c]; object_incref(&ee->execee); } } if (ee->fill = ee->ofill) goto do_add; goto execute_top; } #undef temp } #ifdef GPROF_HOOKS asm("gP_ParseEnd:"); #endif if (ee->fill = ee->ofill) { do_add: if (ee->seeking_token && ee->fill <= 1) { assert(es->type == file_execution); if (es->executed.type == string_type) { register left = f->cnt; assert(es[-1].type == token_execution); if (psio_eof(f) || psio_error(f)) es[-1].executed.value.substring.length = 0; else { es[-1].executed.value.substring.start += es[-1].executed.value.substring.length - left; es[-1].executed.value.substring.length = left; } } ee->seeking_token = 0; goto pop_estack; } else { check_buffer(sizeof(struct object) - 1); *(struct object *) (ee->static_buffer + ee->fill) = ee->execee; ee->fill += sizeof(struct object); goto restart_parse; } } /* return ee->execee; */ }