home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / g / gs252src.zip / GS252 / ISCAN.C < prev    next >
C/C++ Source or Header  |  1992-09-03  |  26KB  |  881 lines

  1. /* Copyright (C) 1989, 1992 Aladdin Enterprises.  All rights reserved.
  2.    Distributed by Free Software Foundation, Inc.
  3.  
  4. This file is part of Ghostscript.
  5.  
  6. Ghostscript is distributed in the hope that it will be useful, but
  7. WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
  8. to anyone for the consequences of using it or for whether it serves any
  9. particular purpose or works at all, unless he says so in writing.  Refer
  10. to the Ghostscript General Public License for full details.
  11.  
  12. Everyone is granted permission to copy, modify and redistribute
  13. Ghostscript, but only under the conditions described in the Ghostscript
  14. General Public License.  A copy of this license is supposed to have been
  15. given to you along with Ghostscript so you can know your rights and
  16. responsibilities.  It should be in a file named COPYING.  Among other
  17. things, the copyright notice and this notice must be preserved on all
  18. copies.  */
  19.  
  20. /* iscan.c */
  21. /* Token scanner for Ghostscript interpreter */
  22. #include <ctype.h>
  23. #include "memory_.h"
  24. #include "ghost.h"
  25. #include "alloc.h"
  26. #include "dict.h"            /* for //name lookup */
  27. #include "dstack.h"            /* ditto */
  28. #include "errors.h"
  29. #include "iutil.h"
  30. #include "name.h"
  31. #include "ostack.h"            /* for accumulating proc bodies */
  32. #include "packed.h"
  33. #include "store.h"
  34. #include "stream.h"
  35. #include "scanchar.h"
  36.  
  37. /* Array packing flag */
  38. ref array_packing;            /* t_boolean */
  39. /* Binary object format flag. This will never be set non-zero */
  40. /* unless the binary token feature is enabled. */
  41. ref binary_object_format;        /* t_integer */
  42. #define recognize_btokens() (binary_object_format.value.intval != 0)
  43.  
  44. /* Procedure for binary tokens.  Set at initialization if the binary token */
  45. /* option is included; only called if recognize_btokens() is true. */
  46. /* Returns 0 on success, <0 on failure. */
  47. int (*scan_btoken_proc)(P3(stream *, ref *, int)) = NULL;
  48.  
  49. /*
  50.  * Level 2 includes some changes in the scanner:
  51.  *    - \ is always recognized in strings, regardless of the data source;
  52.  *    - << and >> are legal tokens;
  53.  *    - <~ introduces an ASCII-85 encoded string (terminated by ~>)
  54.  *        (not implemented yet);
  55.  *    - Character codes above 127 introduce binary objects.
  56.  * We explicitly enable or disable these changes here.
  57.  */
  58. int scan_enable_level2 = 1;
  59.  
  60. /* Forward references */
  61. private    int    scan_hex_string(P2(stream *, ref *)),
  62.         scan_int(P6(const byte **, const byte *, int, int,
  63.                 long *, double *)),
  64.         scan_number(P3(const byte *, const byte *, ref *)),
  65.         scan_string(P3(stream *, int, ref *));
  66.  
  67. /* Define the character scanning table (see scanchar.h). */
  68. byte scan_char_array[258];
  69.  
  70. /* A structure for dynamically growable objects */
  71. typedef struct dynamic_area_s {
  72.     byte *base;
  73.     byte *next;
  74.     uint num_elts;
  75.     uint elt_size;
  76.     int is_dynamic;            /* false if using fixed buffer */
  77.     byte *limit;
  78. } dynamic_area;
  79. typedef dynamic_area _ss *da_ptr;
  80.  
  81. /* Begin a dynamic object. */
  82. /* dynamic_begin returns the value of alloc, which may be 0: */
  83. /* the invoker of dynamic_begin must test the value against 0. */
  84. #define dynamic_begin(pda, dnum, desize)\
  85.     ((pda)->base = (byte *)alloc((pda)->num_elts = (dnum),\
  86.                      (pda)->elt_size = (desize), "scanner"),\
  87.      (pda)->limit = (pda)->base + (dnum) * (desize),\
  88.      (pda)->is_dynamic = 1,\
  89.      (pda)->next = (pda)->base)
  90.  
  91. /* Free a dynamic object. */
  92. private void
  93. dynamic_free(da_ptr pda)
  94. {    if ( pda->is_dynamic )
  95.         alloc_free((char *)(pda->base), pda->num_elts, pda->elt_size,
  96.                "scanner");
  97. }
  98.  
  99. /* Grow a dynamic object. */
  100. /* If the allocation fails, free the old contents, and return NULL; */
  101. /* otherwise, return the new `next' pointer. */
  102. private byte *
  103. dynamic_grow(register da_ptr pda, byte *next)
  104. {    if ( next != pda->limit ) return next;
  105.     pda->next = next;
  106.        {    uint num = pda->num_elts;
  107.         uint old_size = num * pda->elt_size;
  108.         uint pos = pda->next - pda->base;
  109.         uint new_size = (old_size < 10 ? 20 :
  110.                  old_size >= (max_uint >> 1) ? max_uint :
  111.                  old_size << 1);
  112.         uint new_num = new_size / pda->elt_size;
  113.         if ( pda->is_dynamic )
  114.            {    byte *base = alloc_grow(pda->base, num, new_num, pda->elt_size, "scanner");
  115.             if ( base == 0 )
  116.                {    dynamic_free(pda);
  117.                 return NULL;
  118.                }
  119.             pda->base = base;
  120.             pda->num_elts = new_num;
  121.             pda->limit = pda->base + new_size;
  122.            }
  123.         else
  124.            {    byte *base = pda->base;
  125.             if ( !dynamic_begin(pda, new_num, pda->elt_size) ) return NULL;
  126.             memcpy(pda->base, base, old_size);
  127.             pda->is_dynamic = 1;
  128.            }
  129.         pda->next = pda->base + pos;
  130.        }
  131.     return pda->next;
  132. }
  133.  
  134. /* Initialize the scanner. */
  135. void
  136. scan_init()
  137. {    /* Initialize decoder array */
  138.     register byte _ds *decoder = scan_char_decoder;
  139.     static const char _ds *stop_chars = "()<>[]{}/%";
  140.     static const char _ds *space_chars = " \f\t\n\r";
  141.     decoder[ERRC] = ctype_eof;    /* ****** FIX THIS? ****** */
  142.     decoder[EOFC] = ctype_eof;
  143.     memset(decoder, ctype_name, 256);
  144.     memset(decoder + 128, ctype_btoken, 32);
  145.        {    register const char _ds *p;
  146.         for ( p = space_chars; *p; p++ )
  147.           decoder[*p] = ctype_space;
  148.         decoder[char_NULL] = decoder[char_VT] =
  149.           decoder[char_DOS_EOF] = ctype_space;
  150.         for ( p = stop_chars; *p; p++ )
  151.           decoder[*p] = ctype_other;
  152.        }
  153.        {    register int i;
  154.         for ( i = 0; i < 10; i++ )
  155.           decoder['0' + i] = i;
  156.         for ( i = 0; i < max_radix - 10; i++ )
  157.           decoder['A' + i] = decoder['a' + i] = i + 10;
  158.        }
  159.     /* Other initialization */
  160.     make_false(&array_packing);
  161.     make_int(&binary_object_format, 0);
  162. }
  163.  
  164. /*
  165.  * Read a token from a stream.
  166.  * Return 1 for end-of-stream, 0 if a token was read,
  167.  * or a (negative) error code.
  168.  * If the token required a terminating character (i.e., was a name or
  169.  * number) and the next character was whitespace, read and discard
  170.  * that character: see the description of the 'token' operator on
  171.  * p. 232 of the Red Book (First Edition).
  172.  * from_string indicates reading from a string vs. a file,
  173.  * because \ escapes are not recognized in the former case.
  174.  * (See the footnote on p. 23 of the Red Book.)
  175.  */
  176. int
  177. scan_token(register stream *s, int from_string, ref *pref)
  178. {    ref *myref = pref;
  179.     dynamic_area proc_da;    /* (not actually dynamic) */
  180.     int pstack = 0;        /* offset from proc_da.base */
  181.     int retcode = 0;
  182.     register int c;
  183.     s_declare_inline(s, sptr, endptr);
  184. #define sreturn(code) { s_end_inline(s, sptr, endptr); return(code); }
  185.     int name_type;        /* number of /'s preceding */
  186.     int try_number;
  187.     byte s1[2];
  188.     register byte _ds *decoder = scan_char_decoder;
  189.     /* Only old P*stScr*pt interpreters use from_string.... */
  190.     from_string &= !scan_enable_level2;
  191.     s_begin_inline(s, sptr, endptr);
  192. top:    c = sgetc_inline(s, sptr, endptr);
  193. #ifdef DEBUG
  194. if ( gs_debug['s'] )
  195.     fprintf(gs_debug_out, (c >= 32 && c <= 126 ? "`%c'" : "`%03o'"), c);
  196. #endif
  197.     switch ( c )
  198.        {
  199.     case ' ': case '\f': case '\t': case '\n': case '\r':
  200.     case char_NULL: case char_VT: case char_DOS_EOF:
  201.         goto top;
  202.     case '[':
  203.     case ']':
  204.         s1[0] = (byte)c;
  205.         name_ref(s1, 1, myref, 1);
  206.         r_set_attrs(myref, a_executable);
  207.         break;
  208.     case '<':
  209.         if ( scan_enable_level2 )
  210.            {    c = sgetc_inline(s, sptr, endptr);
  211.             if ( char_is_data(c) ) sputback_inline(s, sptr, endptr);
  212.             switch ( c )
  213.                {
  214.             case '<':
  215.                 name_type = try_number = 0;
  216.                 goto try_funny_name;
  217.             /****** Check for <~ here ******/
  218.                }
  219.            }
  220.         s_end_inline(s, sptr, endptr);
  221.         retcode = scan_hex_string(s, myref);
  222.         s_begin_inline(s, sptr, endptr);
  223.         break;
  224.     case '(':
  225.         s_end_inline(s, sptr, endptr);
  226.         retcode = scan_string(s, from_string, myref);
  227.         s_begin_inline(s, sptr, endptr);
  228.         break;
  229.     case '{':
  230.         if ( pstack == 0 )
  231.            {    /* Use the operand stack to accumulate procedures. */
  232.             myref = osp + 1;
  233.             proc_da.base = (byte *)myref;
  234.             proc_da.limit = (byte *)(ostop + 1);
  235.             proc_da.is_dynamic = 0;
  236.             proc_da.elt_size = sizeof(ref);
  237.             proc_da.num_elts = ostop - osp;
  238.            }
  239.         if ( proc_da.limit - (byte *)myref < 2 * sizeof(ref) )
  240.           sreturn(e_limitcheck); /* ****** SHOULD GROW OSTACK ****** */
  241.         r_set_size(myref, pstack);
  242.         myref++;
  243.         pstack = (byte *)myref - proc_da.base;
  244.         goto top;
  245.     case '>':
  246.         if ( scan_enable_level2 )
  247.            {    name_type = try_number = 0;
  248.             goto try_funny_name;
  249.            }
  250.         /* falls through */
  251.     case ')':
  252.         retcode = e_syntaxerror;
  253.         break;
  254.     case '}':
  255.         if ( pstack == 0 )
  256.            {    retcode = e_syntaxerror;
  257.             break;    
  258.            }
  259.            {    ref *ref0 = (ref *)(proc_da.base + pstack);
  260.             uint size = myref - ref0;
  261.             ref *aref;
  262.             myref = ref0 - 1;
  263.             pstack = r_size(myref);
  264.             if ( pstack == 0 ) myref = pref;
  265.             if ( array_packing.value.index )
  266.                {    retcode = make_packed_array(ref0, size, myref,
  267.                                 "scanner(packed)");
  268.                 if ( retcode < 0 ) sreturn(retcode);
  269.                 r_set_attrs(myref, a_executable);
  270.                }
  271.             else
  272.               {    aref = alloc_refs(size, "scanner(proc)");
  273.                 if ( aref == 0 ) sreturn(e_VMerror);
  274.                 refcpy_to_new(aref, ref0, size);
  275.                 make_tasv_new(myref, t_array, a_executable + a_all, size, refs, aref);
  276.               }
  277.            }
  278.         break;
  279.     case '/':
  280.         c = sgetc_inline(s, sptr, endptr);
  281.         if ( c == '/' )
  282.            {    name_type = 2;
  283.             c = sgetc_inline(s, sptr, endptr);
  284.            }
  285.         else
  286.             name_type = 1;
  287.         try_number = 0;
  288.         switch ( decoder[c] )
  289.            {
  290.         case ctype_name:
  291.         default:
  292.             goto do_name;
  293.         case ctype_btoken:
  294.             if ( !recognize_btokens() ) goto do_name;
  295.             /* otherwise, an empty name */
  296.             sputback_inline(s, sptr, endptr);
  297.         case ctype_eof:
  298.             /* Empty name: bizarre but legitimate. */
  299.             name_ref((byte *)0, 0, myref, 1);
  300.             goto have_name;
  301.         case ctype_other:
  302.             switch ( c )
  303.                {
  304.             case '[':    /* only special as first character */
  305.             case ']':    /* ditto */
  306.                 s1[0] = (byte)c;
  307.                 name_ref(s1, 1, myref, 1);
  308.                 goto have_name;
  309.             case '<':    /* legal in Level 2 */
  310.             case '>':
  311.                 if ( scan_enable_level2 ) goto try_funny_name;
  312.             default:
  313.                 /* Empty name: bizarre but legitimate. */
  314.                 name_ref((byte *)0, 0, myref, 1);
  315.                 sputback_inline(s, sptr, endptr);
  316.                 goto have_name;
  317.                }
  318.         case ctype_space:
  319.             /* Empty name: bizarre but legitimate. */
  320.             name_ref((byte *)0, 0, myref, 1);
  321.             /* Check for \r\n */
  322.             if ( c == '\r' && (c = sgetc_inline(s, sptr, endptr)) != '\n' && char_is_data(c) )
  323.                 sputback_inline(s, sptr, endptr);
  324.             goto have_name;
  325.            }
  326.         /* NOTREACHED */
  327.     case '%':
  328.        {    for ( ; ; )
  329.           switch ( sgetc_inline(s, sptr, endptr) )
  330.            {
  331.         case '\r':
  332.             if ( (c = sgetc_inline(s, sptr, endptr)) != '\n' && char_is_data(c) )
  333.                 sputback_inline(s, sptr, endptr);
  334.             /* falls through */
  335.         case '\n': case '\f':
  336.             goto top;
  337.         case EOFC:
  338.             goto ceof;
  339.         case ERRC:
  340.             goto cerr;
  341.            }
  342. ceof:        ;
  343.        }    /* falls through */
  344.     case EOFC:
  345.         retcode = (pstack != 0 ? e_syntaxerror : 1);
  346.         break;
  347.     case ERRC:
  348. cerr:        retcode = e_ioerror;
  349.         break;
  350.  
  351.     /* Check for a Level 2 funny name (<< or >>). */
  352.     /* c is '<' or '>'. */
  353. try_funny_name:
  354.        {    int c1 = sgetc_inline(s, sptr, endptr);
  355.         if ( c1 == c )
  356.            {    s1[0] = s1[1] = c;
  357.             retcode = name_ref(s1, 2, myref, 1);
  358.             goto have_name;
  359.            }
  360.         if ( char_is_data(c1) ) sputback_inline(s, sptr, endptr);
  361.        }    retcode = e_syntaxerror;
  362.         break;
  363.  
  364.     /* Handle separately the names that might be a number */
  365.     case '0': case '1': case '2': case '3': case '4':
  366.     case '5': case '6': case '7': case '8': case '9':
  367.     case '.': case '+': case '-':
  368.         name_type = 0;
  369.         try_number = 1;
  370.         goto do_name;
  371.  
  372.     /* Check for a binary object */
  373. #define case4(c) case c: case c+1: case c+2: case c+3
  374.     case4(128): case4(132): case4(136): case4(140):
  375.     case4(144): case4(148): case4(152): case4(156):
  376. #undef case4
  377.         if ( recognize_btokens() )
  378.            {    s_end_inline(s, sptr, endptr);
  379.             retcode = (*scan_btoken_proc)(s, myref, c);
  380.             s_begin_inline(s, sptr, endptr);
  381.             break;
  382.            }
  383.     /* Not a binary object, fall through. */
  384.  
  385.     /* The default is a name. */
  386.     default:
  387.     /* Populate the switch with enough cases to force */
  388.     /* simple compilers to use a dispatch rather than tests. */
  389.     case '!': case '"': case '$': case '&': case '\'':
  390.     case '*': case ',': case '=': case ':': case ';': case '?': case '@':
  391.     case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
  392.     case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M':
  393.     case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S':
  394.     case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z':
  395.     case '\\': case '^': case '_': case '`':
  396.     case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
  397.     case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm':
  398.     case 'n': case 'o': case 'p': case 'q': case 'r': case 's':
  399.     case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z':
  400.     case '|': case '~':
  401.         /* Common code for scanning a name. */
  402.         /* try_number and name_type are already set. */
  403.         /* We know c has ctype_name (or maybe ctype_btoken) */
  404.         /* or is a digit. */
  405.         name_type = 0;
  406.         try_number = 0;
  407. do_name:
  408.        {    dynamic_area da;
  409.         int max_name_ctype =
  410.             (recognize_btokens() ? ctype_name : ctype_btoken);
  411.         /* Try to scan entirely within the stream buffer. */
  412.         /* We stop 1 character early, so we don't switch buffers */
  413.         /* looking ahead if the name is terminated by \r\n. */
  414.         byte *ptr = sptr;
  415.         byte *endp1 = endptr - 1;
  416.         da.base = sptr;
  417.         da.is_dynamic = 0;
  418.         do
  419.            {    if ( sptr >= endp1 )    /* stop 1 early! */
  420.                {    s_end_inline(s, sptr, endptr);
  421.                 /* Initialize the dynamic area. */
  422.                 /* We have to do this before the next */
  423.                 /* sgetc, which will overwrite the buffer. */
  424.                 da.limit = ++sptr;
  425.                 da.num_elts = sptr - da.base;
  426.                 da.elt_size = 1;
  427.                 ptr = dynamic_grow(&da, da.limit);
  428.                 if ( !ptr ) sreturn(e_VMerror);
  429.                 s_begin_inline(s, sptr, endptr);
  430.                 goto dyn_name;
  431.                }
  432.             c = *++sptr;
  433.            }
  434.         while ( decoder[c] <= max_name_ctype );    /* digit or name */
  435.         /* Name ended within the buffer. */
  436.         ptr = sptr;
  437.         goto nx;
  438.         /* Name overran buffer. */
  439. dyn_name:    while ( decoder[c = sgetc_inline(s, sptr, endptr)] <= max_name_ctype )
  440.           {    if ( ptr == da.limit )
  441.                {    ptr = dynamic_grow(&da, ptr);
  442.                 if ( !ptr ) sreturn(e_VMerror);
  443.                }
  444.             *ptr++ = c;
  445.            }
  446. nx:        switch ( decoder[c] )
  447.           {
  448.           case ctype_btoken:
  449.           case ctype_other:
  450.             sputback_inline(s, sptr, endptr);
  451.             break;
  452.           case ctype_space:
  453.             /* Check for \r\n */
  454.             if ( c == '\r' && (c = sgetc_inline(s, sptr, endptr)) != '\n' && char_is_data(c) )
  455.                 sputback_inline(s, sptr, endptr);
  456.           case ctype_eof: ;
  457.           }
  458.         /* Check for a number */
  459.         if ( try_number )
  460.            {    retcode = scan_number(da.base, ptr, myref);
  461.             if ( retcode != e_syntaxerror )
  462.                {    dynamic_free(&da);
  463.                 if ( name_type == 2 ) sreturn(e_syntaxerror);
  464.                 break;    /* might be e_limitcheck */
  465.                }
  466.            }
  467.         retcode = name_ref(da.base, (uint)(ptr - da.base), myref, 1);
  468.         dynamic_free(&da);
  469.        }
  470.         /* Done scanning.  Check for preceding /'s. */
  471. have_name:    if ( retcode < 0 ) sreturn(retcode);
  472.         switch ( name_type )
  473.            {
  474.         case 0:            /* ordinary executable name */
  475.             if ( r_has_type(myref, t_name) )    /* i.e., not a number */
  476.               r_set_attrs(myref, a_executable);
  477.         case 1:            /* quoted name */
  478.             break;
  479.         case 2:            /* immediate lookup */
  480.            {    ref *pvalue;
  481.             if ( !r_has_type(myref, t_name) )
  482.                 sreturn(e_undefined);
  483.             if ( (pvalue = dict_find_name(myref)) == 0 )
  484.                 sreturn(e_undefined);
  485.             ref_assign_new(myref, pvalue);
  486.            }
  487.            }
  488.        }
  489.     /* If we are at the top level, return the object, */
  490.     /* otherwise keep going. */
  491.     if ( pstack == 0 || retcode < 0 )
  492.       sreturn(retcode);
  493.     if ( proc_da.limit - (byte *)myref < 2 * sizeof(ref) )
  494.       sreturn(e_limitcheck); /* ****** SHOULD GROW OSTACK ****** */
  495.     myref++;
  496.     goto top;
  497. }
  498.  
  499. /* The internal scanning procedures return 0 on success, */
  500. /* or a (negative) error code on failure. */
  501.  
  502. /* Scan a number for cvi or cvr. */
  503. /* The first argument is a t_string.  This is just like scan_number, */
  504. /* but allows leading or trailing whitespace. */
  505. int
  506. scan_number_only(const ref *psref, ref *pnref)
  507. {    const byte *str = psref->value.const_bytes;
  508.     const byte *end = str + r_size(psref);
  509.     if ( !r_has_attr(psref, a_read) ) return e_invalidaccess;
  510.     while ( str < end && scan_char_decoder[*str] == ctype_space )
  511.       str++;
  512.     while ( str < end && scan_char_decoder[end[-1]] == ctype_space )
  513.       end--;
  514.     return scan_number(str, end, pnref);
  515. }
  516.  
  517. /* Note that the number scanning procedures use a byte ** and a byte * */
  518. /* rather than a stream.  (It makes quite a difference in performance.) */
  519. #define ngetc(sp) (sp < end ? *sp++ : EOFC)
  520. #define nputback(sp) (--sp)
  521. #define nreturn(v) return (*pstr = sp, v)
  522.  
  523. /* Procedure to scan a number. */
  524. private int
  525. scan_number(const byte *str, const byte *end, ref *pref)
  526. {    /* Powers of 10 up to 6 can be represented accurately as */
  527.     /* a single-precision float. */
  528. #define num_powers_10 6
  529.     static float powers_10[num_powers_10+1] =
  530.        {    1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6    };
  531.     static double neg_powers_10[num_powers_10+1] =
  532.        {    1e0, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6    };
  533.     const byte *sp = str;        /* can't be register because of & */
  534.     int sign = 0;
  535.     long ival;
  536.     double dval;
  537.     int exp10 = 0;
  538.     int code;
  539.     register int c;
  540.     switch ( c = ngetc(sp) )
  541.        {
  542.     case '+': sign = 1; c = ngetc(sp); break;
  543.     case '-': sign = -1; c = ngetc(sp); break;
  544.        }
  545.     if ( !isdigit(c) )
  546.        {    if ( c != '.' ) return(e_syntaxerror);
  547.         c = ngetc(sp);
  548.         if ( !isdigit(c) ) return(e_syntaxerror);
  549.         ival = 0;
  550.         goto fi;
  551.        }
  552.     nputback(sp);
  553.     if ( (code = scan_int(&sp, end, 10, 0, &ival, &dval)) != 0 )
  554.        {    if ( code < 0 ) return(code);    /* e_syntaxerror */
  555.         /* Code == 1, i.e., the integer overflowed. */
  556.         switch ( c = ngetc(sp) )
  557.            {
  558.         default:
  559.             return(e_syntaxerror); /* not terminated properly */
  560.         case '.':
  561.             c = ngetc(sp); goto fd;
  562.         case 'e': case 'E':
  563.             goto fsd;
  564.         case EOFC:        /* return a float */
  565.             make_real_new(pref, (float)(sign < 0 ? -dval : dval));
  566.             return 0;
  567.         case ERRC:
  568.             return e_ioerror;
  569.            }
  570.        }
  571.     switch ( c = ngetc(sp) )
  572.        {
  573.     case EOFC:
  574.         break;
  575.     case ERRC:
  576.         return e_ioerror;
  577.     case '.':
  578.         c = ngetc(sp); goto fi;
  579.     default:
  580.         return(e_syntaxerror);    /* not terminated properly */
  581.     case 'e': case 'E':
  582.         goto fsi;
  583.     case '#':
  584.         if ( sign || ival < min_radix || ival > max_radix )
  585.             return(e_syntaxerror);
  586.         code = scan_int(&sp, end, (int)ival, 1, &ival, NULL);
  587.         if ( code ) return(code);
  588.         switch ( ngetc(sp) )
  589.            {
  590.             case EOFC:
  591.                 break;
  592.             case ERRC:
  593.                 return(e_ioerror);
  594.             default:
  595.                 return(e_syntaxerror);
  596.            }
  597.        }
  598.     /* Return an integer */
  599.     make_int_new(pref, (sign < 0 ? -ival : ival));
  600.     return(0);
  601.     /* Handle a real.  We just saw the decimal point. */
  602.     /* Enter here if we are still accumulating an integer in ival. */
  603. fi:    while ( isdigit(c) )
  604.        {    /* Check for overflowing ival */
  605.         if ( ival >= (max_ulong >> 1) / 10 - 1 )
  606.            {    dval = ival;
  607.             goto fd;
  608.            }
  609.         ival = ival * 10 + (c - '0');
  610.         c = ngetc(sp);
  611.         exp10--;
  612.        }
  613. fsi:    if ( sign < 0 ) ival = -ival;
  614.     /* Take a shortcut for the common case */
  615.     if ( !(c == 'e' || c == 'E' || exp10 < -num_powers_10) )
  616.        {    /* Check for trailing garbage */
  617.         if ( c != EOFC ) return(e_syntaxerror);
  618.         make_real_new(pref, (float)(ival * neg_powers_10[-exp10]));
  619.         return(0);
  620.        }
  621.     dval = ival;
  622.     goto fe;
  623.     /* Now we are accumulating a double in dval. */
  624. fd:    while ( isdigit(c) )
  625.        {    dval = dval * 10 + (c - '0');
  626.         c = ngetc(sp);
  627.         exp10--;
  628.        }
  629. fsd:    if ( sign < 0 ) dval = -dval;
  630. fe:    /* dval contains the value, negated if necessary */
  631.     if ( c == 'e' || c == 'E' )
  632.        {    /* Check for a following exponent. */
  633.         int esign = 0;
  634.         long eexp;
  635.         switch ( c = ngetc(sp) )
  636.            {
  637.         case '+': break;
  638.         case '-': esign = 1; break;
  639.         default: nputback(sp);
  640.            }
  641.         code = scan_int(&sp, end, 10, 0, &eexp, NULL);
  642.         if ( code < 0 ) return(code);
  643.         if ( code > 0 || eexp > 999 )
  644.             return(e_limitcheck);    /* semi-arbitrary */
  645.         if ( esign )
  646.             exp10 -= (int)eexp;
  647.         else
  648.             exp10 += (int)eexp;
  649.         c = ngetc(sp);
  650.        }
  651.     if ( c != EOFC ) return(c == ERRC ? e_ioerror : e_syntaxerror);
  652.     /* Compute dval * 10^exp10. */
  653.     if ( exp10 > 0 )
  654.        {    while ( exp10 > num_powers_10 )
  655.             dval *= powers_10[num_powers_10],
  656.             exp10 -= num_powers_10;
  657.         if ( exp10 > 0 )
  658.             dval *= powers_10[exp10];
  659.        }
  660.     else if ( exp10 < 0 )
  661.        {    while ( exp10 < -num_powers_10 )
  662.             dval /= powers_10[num_powers_10],
  663.             exp10 += num_powers_10;
  664.         if ( exp10 < 0 )
  665.             dval /= powers_10[-exp10];
  666.        }
  667.     make_real_new(pref, (float)dval);
  668.     return(0);
  669. }
  670. /* Internal subroutine to scan an integer. */
  671. /* Return 0, e_limitcheck, or e_syntaxerror. */
  672. /* (The only syntax error is no digits encountered.) */
  673. /* Put back the terminating character. */
  674. /* If nosign is true, the integer is scanned as unsigned; */
  675. /* overflowing a ulong returns e_limitcheck.  If nosign is false, */
  676. /* the integer is scanned as signed; if the integer won't fit in a long, */
  677. /* then: */
  678. /*   if pdval == NULL, return e_limitcheck; */
  679. /*   if pdval != NULL, return 1 and store a double value in *pdval. */
  680. private int
  681. scan_int(const byte **pstr, const byte *end, int radix, int nosign,
  682.   long *pval, double *pdval)
  683. {    register const byte *sp = *pstr;
  684.     uint ival = 0, imax, irem;
  685. #if arch_ints_are_short
  686.     ulong lval, lmax;
  687.     uint lrem;
  688. #else
  689. #  define lval ival            /* for overflowing into double */
  690. #endif
  691.     double dval;
  692.     register int c, d;
  693.     register byte _ds *decoder = scan_char_decoder;
  694.     /* Avoid the long divisions when radix = 10 */
  695. #define set_max(vmax, vrem, big)\
  696.   if ( radix == 10 )    vmax = (big) / 10, vrem = (big) % 10;\
  697.   else            vmax = (big) / radix, vrem = (big) % radix
  698.     set_max(imax, irem, max_uint);
  699. #define convert_digit_fails(c, d)\
  700.   (d = decoder[c]) >= radix
  701.     while ( 1 )
  702.        {    c = ngetc(sp);
  703.         if ( convert_digit_fails(c, d) )
  704.            {    if ( char_is_data(c) ) nputback(sp);
  705.             if ( (int)ival < 0 && !nosign )
  706.                {    d = ival % radix;
  707.                 ival /= radix;
  708.                 break;
  709.                }
  710.             *pval = ival;
  711.             nreturn(0);
  712.            }
  713.         if ( ival >= imax && (ival > imax || d > irem) )
  714.             break;        /* overflow */
  715.         ival = ival * radix + d;
  716.        }
  717. #if arch_ints_are_short
  718.     /* Short integer overflowed.  Accumulate in a long. */
  719.     lval = (ulong)ival * radix + d;
  720.     set_max(lmax, lrem, max_ulong);
  721.     while ( 1 )
  722.        {    c = ngetc(sp);
  723.         if ( convert_digit_fails(c, d) )
  724.            {    if ( char_is_data(c) ) nputback(sp);
  725.             if ( (long)lval < 0 && !nosign )
  726.                {    d = lval % radix;
  727.                 lval /= radix;
  728.                 break;
  729.                }
  730.             *pval = lval;
  731.             nreturn(0);
  732.            }
  733.         if ( lval >= lmax && (lval > lmax || d > lrem) )
  734.             break;        /* overflow */
  735.         lval = lval * radix + d;
  736.        }
  737. #endif
  738.     /* Integer overflowed.  Accumulate the result as a double. */
  739.     if ( pdval == NULL ) nreturn(e_limitcheck);
  740.     dval = (double)lval * radix + d;
  741.     while ( 1 )
  742.        {    c = ngetc(sp);
  743.         if ( convert_digit_fails(c, d) )
  744.            {    if ( char_is_data(c) ) nputback(sp);
  745.             *pdval = dval;
  746.             nreturn(1);
  747.            }
  748.         dval = dval * radix + d;
  749.        }
  750.     /* Control doesn't get here */
  751. }
  752.  
  753. /* Make a string.  If the allocation fails, release any dynamic storage. */
  754. private int
  755. mk_string(ref *pref, da_ptr pda, byte *next)
  756. {    uint size = (pda->next = next) - pda->base;
  757.     byte *body = alloc_shrink(pda->base, pda->num_elts, size, 1, "scanner(string)");
  758.     if ( body == 0 )
  759.        {    dynamic_free(pda);
  760.         return e_VMerror;
  761.        }
  762.     make_tasv_new(pref, t_string, a_all, size, bytes, body);
  763.     return 0;
  764. }
  765.  
  766. /* Internal procedure to scan a string. */
  767. private int
  768. scan_string(register stream *s, int from_string, ref *pref)
  769. {    dynamic_area da;
  770.     register int c;
  771.     register byte *ptr = dynamic_begin(&da, 100, 1);
  772.     int plevel = 0;
  773.     if ( ptr == 0 ) return e_VMerror;
  774. top:    while ( 1 )
  775.        {    switch ( (c = sgetc(s)) )
  776.            {
  777.         case EOFC:
  778.             dynamic_free(&da);
  779.             return e_syntaxerror;
  780.         case ERRC:
  781.             dynamic_free(&da);
  782.             return e_ioerror;
  783.         case '\\':
  784.             if ( from_string ) break;
  785.             switch ( (c = sgetc(s)) )
  786.                {
  787.             case 'n': c = '\n'; break;
  788.             case 'r': c = '\r'; break;
  789.             case 't': c = '\t'; break;
  790.             case 'b': c = '\b'; break;
  791.             case 'f': c = '\f'; break;
  792.             case '\r':    /* ignore, check for following \n */
  793.                 c = sgetc(s);
  794.                 if ( c != '\n' && char_is_data(c) )
  795.                     sputback(s);
  796.                 goto top;
  797.             case '\n': goto top;    /* ignore */
  798.             case '0': case '1': case '2': case '3':
  799.             case '4': case '5': case '6': case '7':
  800.                {    int d = sgetc(s);
  801.                 c -= '0';
  802.                 if ( d >= '0' && d <= '7' )
  803.                    {    c = (c << 3) + d - '0';
  804.                     d = sgetc(s);
  805.                     if ( d >= '0' && d <= '7' )
  806.                        {    c = (c << 3) + d - '0';
  807.                         break;
  808.                        }
  809.                    }
  810.                 if ( char_is_signal(d) )
  811.                    {    dynamic_free(&da);
  812.                     return (d == ERRC ? e_ioerror : e_syntaxerror);
  813.                    }
  814.                 sputback(s);
  815.                }
  816.                 break;
  817.             default: ;    /* ignore the \ */
  818.                }
  819.             break;
  820.         case '(':
  821.             plevel++; break;
  822.         case ')':
  823.             if ( --plevel < 0 ) goto out; break;
  824.         case '\r':        /* convert to \n */
  825.             c = sgetc(s);
  826.             if ( c != '\n' && char_is_data(c) )
  827.                 sputback(s);
  828.             c = '\n';
  829.            }
  830.         if ( ptr == da.limit )
  831.            {    ptr = dynamic_grow(&da, ptr);
  832.             if ( !ptr ) return e_VMerror;
  833.            }
  834.         *ptr++ = c;
  835.        }
  836. out:    return mk_string(pref, &da, ptr);
  837. }
  838.  
  839. /* Internal procedure to scan a hex string. */
  840. private int
  841. scan_hex_string(stream *s, ref *pref)
  842. {    dynamic_area da;
  843.     int c1, c2, val1, val2;
  844.     byte *ptr = dynamic_begin(&da, 100, 1);
  845.     register const byte _ds *decoder = scan_char_decoder;
  846.     if ( ptr == 0 ) return e_VMerror;
  847. l1:    do
  848.        {    c1 = sgetc(s);
  849.         if ( (val1 = decoder[c1]) < 0x10 )
  850.            {    do
  851.                {    c2 = sgetc(s);
  852.                 if ( (val2 = decoder[c2]) < 0x10 )
  853.                    {    if ( ptr == da.limit )
  854.                        {    ptr = dynamic_grow(&da, ptr);
  855.                         if ( !ptr ) return e_VMerror;
  856.                        }
  857.                     *ptr++ = (val1 << 4) + val2;
  858.                     goto l1;
  859.                    }
  860.                }
  861.             while ( val2 == ctype_space );
  862.             if ( c2 != '>' )
  863.                {    dynamic_free(&da);
  864.                 return e_syntaxerror;
  865.                }
  866.             if ( ptr == da.limit )
  867.                {    ptr = dynamic_grow(&da, ptr);
  868.                 if ( !ptr ) return e_VMerror;
  869.                }
  870.             *ptr++ = val1 << 4;    /* no 2nd char */
  871.             goto lx;
  872.            }
  873.        }
  874.     while ( val1 == ctype_space );
  875.     if ( c1 != '>' )
  876.        {    dynamic_free(&da);
  877.         return e_syntaxerror;
  878.        }
  879. lx:    return mk_string(pref, &da, ptr);
  880. }
  881.