home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / unofficial-plug-ins / mathmap / lispreader.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-04-21  |  15.3 KB  |  827 lines

  1. /* $Id: lispreader.c,v 1.1 2000/04/03 02:18:26 schani Exp $ */
  2. /*
  3.  * lispreader.c
  4.  *
  5.  * Copyright (C) 1998-1999 Mark Probst
  6.  *
  7.  * This library is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU Library General Public
  9.  * License as published by the Free Software Foundation; either
  10.  * version 2 of the License, or (at your option) any later version.
  11.  *
  12.  * This library is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  * Library General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU Library General Public
  18.  * License along with this library; if not, write to the
  19.  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  20.  * Boston, MA 02111-1307, USA.
  21.  */
  22.  
  23. #include <assert.h>
  24. #include <ctype.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27.  
  28. #include <lispreader.h>
  29.  
  30. #define TOKEN_ERROR                   -1
  31. #define TOKEN_EOF                     0
  32. #define TOKEN_OPEN_PAREN              1
  33. #define TOKEN_CLOSE_PAREN             2
  34. #define TOKEN_SYMBOL                  3
  35. #define TOKEN_STRING                  4
  36. #define TOKEN_INTEGER                 5
  37. #define TOKEN_PATTERN_OPEN_PAREN      6
  38. #define TOKEN_DOT                     7
  39. #define TOKEN_TRUE                    8
  40. #define TOKEN_FALSE                   9
  41.  
  42. #define MAX_TOKEN_LENGTH           1024
  43.  
  44. static char token_string[MAX_TOKEN_LENGTH + 1] = "";
  45. static int token_length = 0;
  46.  
  47. static lisp_object_t end_marker = { LISP_TYPE_EOF };
  48. static lisp_object_t error_object = { LISP_TYPE_PARSE_ERROR };
  49. static lisp_object_t close_paren_marker = { LISP_TYPE_PARSE_ERROR };
  50. static lisp_object_t dot_marker = { LISP_TYPE_PARSE_ERROR };
  51.  
  52. static void
  53. _token_clear (void)
  54. {
  55.     token_string[0] = '\0';
  56.     token_length = 0;
  57. }
  58.  
  59. static void
  60. _token_append (char c)
  61. {
  62.     assert(token_length < MAX_TOKEN_LENGTH);
  63.  
  64.     token_string[token_length++] = c;
  65.     token_string[token_length] = '\0';
  66. }
  67.  
  68. static int
  69. _next_char (lisp_stream_t *stream)
  70. {
  71.     switch (stream->type)
  72.     {
  73.     case LISP_STREAM_FILE :
  74.         return getc(stream->v.file);
  75.  
  76.     case LISP_STREAM_STRING :
  77.         {
  78.         char c = stream->v.string.buf[stream->v.string.pos];
  79.  
  80.         if (c == 0)
  81.             return EOF;
  82.  
  83.         ++stream->v.string.pos;
  84.  
  85.         return c;
  86.         }
  87.     }
  88.  
  89.     assert(0);
  90.     return EOF;
  91. }
  92.  
  93. static void
  94. _unget_char (char c, lisp_stream_t *stream)
  95. {
  96.     switch (stream->type)
  97.     {
  98.     case LISP_STREAM_FILE :
  99.         ungetc(c, stream->v.file);
  100.         break;
  101.  
  102.     case LISP_STREAM_STRING :
  103.         --stream->v.string.pos;
  104.         break;
  105.  
  106.     default :
  107.         assert(0);
  108.     }
  109. }
  110.  
  111. static int
  112. _scan (lisp_stream_t *stream)
  113. {
  114.     int c;
  115.  
  116.     _token_clear();
  117.  
  118.     do
  119.     {
  120.     c = _next_char(stream);
  121.     if (c == EOF)
  122.         return TOKEN_EOF;
  123.     } while (isspace(c));
  124.  
  125.     switch (c)
  126.     {
  127.     case '(' :
  128.         return TOKEN_OPEN_PAREN;
  129.  
  130.     case ')' :
  131.         return TOKEN_CLOSE_PAREN;
  132.  
  133.     case '"' :
  134.         while (1)
  135.         {
  136.         c = _next_char(stream);
  137.         if (c == EOF)
  138.             return TOKEN_ERROR;
  139.         if (c == '"')
  140.             break;
  141.         if (c == '\\')
  142.         {
  143.             c = _next_char(stream);
  144.  
  145.             switch (c)
  146.             {
  147.             case EOF :
  148.                 return TOKEN_ERROR;
  149.             
  150.             case 'n' :
  151.                 c = '\n';
  152.                 break;
  153.  
  154.             case 't' :
  155.                 c = '\t';
  156.                 break;
  157.             }
  158.         }
  159.  
  160.         _token_append(c);
  161.         }
  162.         return TOKEN_STRING;
  163.  
  164.     case '#' :
  165.         c = _next_char(stream);
  166.         if (c == EOF)
  167.         return TOKEN_ERROR;
  168.  
  169.         switch (c)
  170.         {
  171.         case 't' :
  172.             return TOKEN_TRUE;
  173.  
  174.         case 'f' :
  175.             return TOKEN_FALSE;
  176.  
  177.         case '?' :
  178.             c = _next_char(stream);
  179.             if (c == EOF)
  180.             return TOKEN_ERROR;
  181.  
  182.             if (c == '(')
  183.             return TOKEN_PATTERN_OPEN_PAREN;
  184.             else
  185.             return TOKEN_ERROR;
  186.         }
  187.         return TOKEN_ERROR;
  188.  
  189.     default :
  190.         if (isdigit(c) || c == '-')
  191.         {
  192.         int have_nondigits = 0;
  193.         int have_digits = 0;
  194.  
  195.         do
  196.         {
  197.             if (isdigit(c))
  198.             have_digits = 1;
  199.             _token_append(c);
  200.             c = _next_char(stream);
  201.             if (c != EOF && !isdigit(c) && !isspace(c) && c != '(' && c != ')' && c != '"')
  202.             have_nondigits = 1;
  203.         } while (c != EOF && !isspace(c) && c != '(' && c != ')' && c != '"');
  204.  
  205.         if (c != EOF)
  206.             _unget_char(c, stream);
  207.  
  208.         if (have_nondigits || !have_digits)
  209.             return TOKEN_SYMBOL;
  210.         return TOKEN_INTEGER;
  211.         }
  212.         else
  213.         {
  214.         if (c == '.')
  215.         {
  216.             c = _next_char(stream);
  217.             if (c != EOF && !isspace(c) && c != '(' && c != ')' && c != '"')
  218.             _token_append('.');
  219.             else
  220.             {
  221.             _unget_char(c, stream);
  222.             return TOKEN_DOT;
  223.             }
  224.         }
  225.         do
  226.         {
  227.             _token_append(c);
  228.             c = _next_char(stream);
  229.         } while (c != EOF && !isspace(c) && c != '(' && c != ')' && c != '"');
  230.         if (c != EOF)
  231.             _unget_char(c, stream);
  232.  
  233.         return TOKEN_SYMBOL;
  234.         }
  235.     }
  236.  
  237.     assert(0);
  238.     return TOKEN_ERROR;
  239. }
  240.  
  241. lisp_object_t*
  242. lisp_object_alloc (int type)
  243. {
  244.     lisp_object_t *obj = (lisp_object_t*)malloc(sizeof(lisp_object_t));
  245.  
  246.     obj->type = type;
  247.  
  248.     return obj;
  249. }
  250.  
  251. lisp_stream_t*
  252. lisp_stream_init_file (lisp_stream_t *stream, FILE *file)
  253. {
  254.     stream->type = LISP_STREAM_FILE;
  255.     stream->v.file = file;
  256.  
  257.     return stream;
  258. }
  259.  
  260. lisp_stream_t*
  261. lisp_stream_init_string (lisp_stream_t *stream, char *buf)
  262. {
  263.     stream->type = LISP_STREAM_STRING;
  264.     stream->v.string.buf = buf;
  265.     stream->v.string.pos = 0;
  266.  
  267.     return stream;
  268. }
  269.  
  270. lisp_object_t*
  271. lisp_read (lisp_stream_t *in)
  272. {
  273.     int token = _scan(in);
  274.     lisp_object_t *obj = 0;
  275.  
  276.     if (token == TOKEN_EOF)
  277.     return &end_marker;
  278.  
  279.     switch (token)
  280.     {
  281.     case TOKEN_ERROR :
  282.         return &error_object;
  283.  
  284.     case TOKEN_EOF :
  285.         return &end_marker;
  286.  
  287.     case TOKEN_OPEN_PAREN :
  288.     case TOKEN_PATTERN_OPEN_PAREN :
  289.         {
  290.         lisp_object_t *last = 0, *car;
  291.  
  292.         do
  293.         {
  294.             car = lisp_read(in);
  295.             if (car == &error_object || car == &end_marker)
  296.             {
  297.             lisp_free(obj);
  298.             return &error_object;
  299.             }
  300.             else if (car == &dot_marker)
  301.             {
  302.             if (last == 0)
  303.             {
  304.                 lisp_free(obj);
  305.                 return &error_object;
  306.             }
  307.  
  308.             car = lisp_read(in);
  309.             if (car == &error_object || car == &end_marker)
  310.             {
  311.                 lisp_free(obj);
  312.                 return car;
  313.             }
  314.             else
  315.             {
  316.                 last->v.cons.cdr = car;
  317.  
  318.                 if (_scan(in) != TOKEN_CLOSE_PAREN)
  319.                 {
  320.                 lisp_free(obj);
  321.                 return &error_object;
  322.                 }
  323.  
  324.                 car = &close_paren_marker;
  325.             }
  326.             }
  327.             else if (car != &close_paren_marker)
  328.             {
  329.             if (last == 0)
  330.                 obj = last = lisp_object_alloc(token == TOKEN_OPEN_PAREN
  331.                                ? LISP_TYPE_CONS
  332.                                : LISP_TYPE_PATTERN_CONS);
  333.             else
  334.                 last = last->v.cons.cdr = lisp_object_alloc(LISP_TYPE_CONS);
  335.             last->v.cons.car = car;
  336.             last->v.cons.cdr = 0;
  337.             }
  338.         } while (car != &close_paren_marker);
  339.         }
  340.         return obj;
  341.  
  342.     case TOKEN_CLOSE_PAREN :
  343.         return &close_paren_marker;
  344.  
  345.     case TOKEN_SYMBOL :
  346.         obj = lisp_object_alloc(LISP_TYPE_SYMBOL);
  347.         obj->v.string = strdup(token_string);
  348.         return obj;
  349.  
  350.     case TOKEN_STRING :
  351.         obj = lisp_object_alloc(LISP_TYPE_STRING);
  352.         obj->v.string = strdup(token_string);
  353.         return obj;
  354.  
  355.     case TOKEN_INTEGER :
  356.         obj = lisp_object_alloc(LISP_TYPE_INTEGER);
  357.         obj->v.integer = atoi(token_string);
  358.         return obj;
  359.  
  360.     case TOKEN_DOT :
  361.         return &dot_marker;
  362.  
  363.     case TOKEN_TRUE :
  364.         obj = lisp_object_alloc(LISP_TYPE_BOOLEAN);
  365.         obj->v.integer = 1;
  366.         return obj;
  367.  
  368.     case TOKEN_FALSE :
  369.         obj = lisp_object_alloc(LISP_TYPE_BOOLEAN);
  370.         obj->v.integer = 0;
  371.         return obj;
  372.     }
  373.  
  374.     assert(0);
  375.     return &error_object;
  376. }
  377.  
  378. void
  379. lisp_free (lisp_object_t *obj)
  380. {
  381.     if (obj == 0)
  382.     return;
  383.  
  384.     switch (obj->type)
  385.     {
  386.     case LISP_TYPE_INTERNAL :
  387.     case LISP_TYPE_PARSE_ERROR :
  388.     case LISP_TYPE_EOF :
  389.         return;
  390.  
  391.     case LISP_TYPE_SYMBOL :
  392.     case LISP_TYPE_STRING :
  393.         free(obj->v.string);
  394.         break;
  395.  
  396.     case LISP_TYPE_CONS :
  397.     case LISP_TYPE_PATTERN_CONS :
  398.         lisp_free(obj->v.cons.car);
  399.         lisp_free(obj->v.cons.cdr);
  400.         break;
  401.  
  402.     case LISP_TYPE_PATTERN_VAR :
  403.         lisp_free(obj->v.pattern.sub);
  404.         break;
  405.     }
  406.  
  407.     free(obj);
  408. }
  409.  
  410. lisp_object_t*
  411. lisp_read_from_string (const char *buf)
  412. {
  413.     lisp_stream_t stream;
  414.  
  415.     lisp_stream_init_string(&stream, (char*)buf);
  416.     return lisp_read(&stream);
  417. }
  418.  
  419. static int
  420. _compile_pattern (lisp_object_t **obj, int *index)
  421. {
  422.     if (*obj == 0)
  423.     return 1;
  424.  
  425.     switch (lisp_type(*obj))
  426.     {
  427.     case LISP_TYPE_PATTERN_CONS :
  428.         {
  429.         struct { char *name; int type; } types[] =
  430.                          {
  431.                              { "any", LISP_PATTERN_ANY },
  432.                              { "symbol", LISP_PATTERN_SYMBOL },
  433.                              { "string", LISP_PATTERN_STRING },
  434.                              { "integer", LISP_PATTERN_INTEGER },
  435.                              { "boolean", LISP_PATTERN_BOOLEAN },
  436.                              { "list", LISP_PATTERN_LIST },
  437.                              { "or", LISP_PATTERN_OR },
  438.                              { 0, 0 }
  439.                          };
  440.         char *type_name;
  441.         int type;
  442.         int i;
  443.         lisp_object_t *pattern;
  444.  
  445.         if (lisp_type(lisp_car(*obj)) != LISP_TYPE_SYMBOL)
  446.             return 0;
  447.  
  448.         type_name = lisp_symbol(lisp_car(*obj));
  449.         for (i = 0; types[i].name != 0; ++i)
  450.         {
  451.             if (strcmp(types[i].name, type_name) == 0)
  452.             {
  453.             type = types[i].type;
  454.             break;
  455.             }
  456.         }
  457.  
  458.         if (types[i].name == 0)
  459.             return 0;
  460.  
  461.         if (type != LISP_PATTERN_OR && lisp_cdr(*obj) != 0)
  462.             return 0;
  463.  
  464.         pattern = lisp_object_alloc(LISP_TYPE_PATTERN_VAR);
  465.         pattern->v.pattern.type = type;
  466.         pattern->v.pattern.index = (*index)++;
  467.         pattern->v.pattern.sub = 0;
  468.  
  469.         if (type == LISP_PATTERN_OR)
  470.         {
  471.             lisp_object_t *cdr = lisp_cdr(*obj);
  472.  
  473.             if (!_compile_pattern(&cdr, index))
  474.             {
  475.             lisp_free(pattern);
  476.             return 0;
  477.             }
  478.  
  479.             pattern->v.pattern.sub = cdr;
  480.  
  481.             (*obj)->v.cons.cdr = 0;
  482.         }
  483.  
  484.         lisp_free(*obj);
  485.  
  486.         *obj = pattern;
  487.         }
  488.         break;
  489.  
  490.     case LISP_TYPE_CONS :
  491.         if (!_compile_pattern(&(*obj)->v.cons.car, index))
  492.         return 0;
  493.         if (!_compile_pattern(&(*obj)->v.cons.cdr, index))
  494.         return 0;
  495.         break;
  496.     }
  497.  
  498.     return 1;
  499. }
  500.  
  501. int
  502. lisp_compile_pattern (lisp_object_t **obj, int *num_subs)
  503. {
  504.     int index = 0;
  505.     int result;
  506.  
  507.     result = _compile_pattern(obj, &index);
  508.  
  509.     if (result && num_subs != 0)
  510.     *num_subs = index;
  511.  
  512.     return result;
  513. }
  514.  
  515. static int _match_pattern (lisp_object_t *pattern, lisp_object_t *obj, lisp_object_t **vars);
  516.  
  517. static int
  518. _match_pattern_var (lisp_object_t *pattern, lisp_object_t *obj, lisp_object_t **vars)
  519. {
  520.     assert(lisp_type(pattern) == LISP_TYPE_PATTERN_VAR);
  521.  
  522.     switch (pattern->v.pattern.type)
  523.     {
  524.     case LISP_PATTERN_ANY :
  525.         break;
  526.  
  527.     case LISP_PATTERN_SYMBOL :
  528.         if (obj == 0 || lisp_type(obj) != LISP_TYPE_SYMBOL)
  529.         return 0;
  530.         break;
  531.  
  532.     case LISP_PATTERN_STRING :
  533.         if (obj == 0 || lisp_type(obj) != LISP_TYPE_STRING)
  534.         return 0;
  535.         break;
  536.  
  537.     case LISP_PATTERN_INTEGER :
  538.         if (obj == 0 || lisp_type(obj) != LISP_TYPE_INTEGER)
  539.         return 0;
  540.         break;
  541.  
  542.     case LISP_PATTERN_BOOLEAN :
  543.         if (obj == 0 || lisp_type(obj) != LISP_TYPE_BOOLEAN)
  544.         return 0;
  545.         break;
  546.  
  547.     case LISP_PATTERN_LIST :
  548.         if (obj == 0 || lisp_type(obj) != LISP_TYPE_CONS)
  549.         return 0;
  550.         break;
  551.  
  552.     case LISP_PATTERN_OR :
  553.         {
  554.         lisp_object_t *sub;
  555.         int matched = 0;
  556.  
  557.         for (sub = pattern->v.pattern.sub; sub != 0; sub = lisp_cdr(sub))
  558.         {
  559.             assert(lisp_type(sub) == LISP_TYPE_CONS);
  560.  
  561.             if (_match_pattern(lisp_car(sub), obj, vars))
  562.             matched = 1;
  563.         }
  564.  
  565.         if (!matched)
  566.             return 0;
  567.         }
  568.         break;
  569.  
  570.     default :
  571.         assert(0);
  572.     }
  573.  
  574.     if (vars != 0)
  575.     vars[pattern->v.pattern.index] = obj;
  576.  
  577.     return 1;
  578. }
  579.  
  580. static int
  581. _match_pattern (lisp_object_t *pattern, lisp_object_t *obj, lisp_object_t **vars)
  582. {
  583.     if (pattern == 0)
  584.     return obj == 0;
  585.  
  586.     if (obj == 0)
  587.     return 0;
  588.  
  589.     if (lisp_type(pattern) == LISP_TYPE_PATTERN_VAR)
  590.     return _match_pattern_var(pattern, obj, vars);
  591.  
  592.     if (lisp_type(pattern) != lisp_type(obj))
  593.     return 0;
  594.  
  595.     switch (lisp_type(pattern))
  596.     {
  597.     case LISP_TYPE_SYMBOL :
  598.         return strcmp(lisp_symbol(pattern), lisp_symbol(obj)) == 0;
  599.  
  600.     case LISP_TYPE_STRING :
  601.         return strcmp(lisp_string(pattern), lisp_string(obj)) == 0;
  602.  
  603.     case LISP_TYPE_INTEGER :
  604.         return lisp_integer(pattern) == lisp_integer(obj);
  605.  
  606.     case LISP_TYPE_CONS :
  607.         {
  608.         int result1, result2;
  609.  
  610.         result1 = _match_pattern(lisp_car(pattern), lisp_car(obj), vars);
  611.         result2 = _match_pattern(lisp_cdr(pattern), lisp_cdr(obj), vars);
  612.  
  613.         return result1 && result2;
  614.         }
  615.         break;
  616.  
  617.     default :
  618.         assert(0);
  619.     }
  620.  
  621.     return 0;
  622. }
  623.  
  624. int
  625. lisp_match_pattern (lisp_object_t *pattern, lisp_object_t *obj, lisp_object_t **vars, int num_subs)
  626. {
  627.     int i;
  628.  
  629.     if (vars != 0)
  630.     for (i = 0; i < num_subs; ++i)
  631.         vars[i] = &error_object;
  632.  
  633.     return _match_pattern(pattern, obj, vars);
  634. }
  635.  
  636. int
  637. lisp_match_string (const char *pattern_string, lisp_object_t *obj, lisp_object_t **vars)
  638. {
  639.     lisp_object_t *pattern;
  640.     int result;
  641.     int num_subs;
  642.  
  643.     pattern = lisp_read_from_string(pattern_string);
  644.  
  645.     if (pattern != 0 && (lisp_type(pattern) == LISP_TYPE_EOF
  646.              || lisp_type(pattern) == LISP_TYPE_PARSE_ERROR))
  647.     return 0;
  648.  
  649.     if (!lisp_compile_pattern(&pattern, &num_subs))
  650.     {
  651.     lisp_free(pattern);
  652.     return 0;
  653.     }
  654.  
  655.     result = lisp_match_pattern(pattern, obj, vars, num_subs);
  656.  
  657.     lisp_free(pattern);
  658.  
  659.     return result;
  660. }
  661.  
  662. int
  663. lisp_type (lisp_object_t *obj)
  664. {
  665.     if (obj == 0)
  666.     return LISP_TYPE_NIL;
  667.     return obj->type;
  668. }
  669.  
  670. int
  671. lisp_integer (lisp_object_t *obj)
  672. {
  673.     assert(obj->type == LISP_TYPE_INTEGER);
  674.  
  675.     return obj->v.integer;
  676. }
  677.  
  678. char*
  679. lisp_symbol (lisp_object_t *obj)
  680. {
  681.     assert(obj->type == LISP_TYPE_SYMBOL);
  682.  
  683.     return obj->v.string;
  684. }
  685.  
  686. char*
  687. lisp_string (lisp_object_t *obj)
  688. {
  689.     assert(obj->type == LISP_TYPE_STRING);
  690.  
  691.     return obj->v.string;
  692. }
  693.  
  694. int
  695. lisp_boolean (lisp_object_t *obj)
  696. {
  697.     assert(obj->type == LISP_TYPE_BOOLEAN);
  698.  
  699.     return obj->v.integer;
  700. }
  701.  
  702. lisp_object_t*
  703. lisp_car (lisp_object_t *obj)
  704. {
  705.     assert(obj->type == LISP_TYPE_CONS || obj->type == LISP_TYPE_PATTERN_CONS);
  706.  
  707.     return obj->v.cons.car;
  708. }
  709.  
  710. lisp_object_t*
  711. lisp_cdr (lisp_object_t *obj)
  712. {
  713.     assert(obj->type == LISP_TYPE_CONS || obj->type == LISP_TYPE_PATTERN_CONS);
  714.  
  715.     return obj->v.cons.cdr;
  716. }
  717.  
  718. int
  719. lisp_list_length (lisp_object_t *obj)
  720. {
  721.     int length = 0;
  722.  
  723.     while (obj != 0)
  724.     {
  725.     assert(obj->type == LISP_TYPE_CONS || obj->type == LISP_TYPE_PATTERN_CONS);
  726.  
  727.     ++length;
  728.     obj = obj->v.cons.cdr;
  729.     }
  730.  
  731.     return length;
  732. }
  733.  
  734. lisp_object_t*
  735. lisp_list_nth (lisp_object_t *obj, int index)
  736. {
  737.     while (index > 0)
  738.     {
  739.     assert(obj != 0);
  740.     assert(obj->type == LISP_TYPE_CONS || obj->type == LISP_TYPE_PATTERN_CONS);
  741.  
  742.     --index;
  743.     obj = obj->v.cons.cdr;
  744.     }
  745.  
  746.     assert(obj != 0);
  747.  
  748.     return obj->v.cons.car;
  749. }
  750.  
  751. void
  752. lisp_dump (lisp_object_t *obj, FILE *out)
  753. {
  754.     if (obj == 0)
  755.     {
  756.     fprintf(out, "()");
  757.     return;
  758.     }
  759.  
  760.     switch (lisp_type(obj))
  761.     {
  762.     case LISP_TYPE_EOF :
  763.         fputs("#<eof>", out);
  764.         break;
  765.  
  766.     case LISP_TYPE_PARSE_ERROR :
  767.         fputs("#<error>", out);
  768.         break;
  769.  
  770.     case LISP_TYPE_INTEGER :
  771.         fprintf(out, "%d", lisp_integer(obj));
  772.         break;
  773.  
  774.     case LISP_TYPE_SYMBOL :
  775.         fputs(lisp_symbol(obj), out);
  776.         break;
  777.  
  778.     case LISP_TYPE_STRING :
  779.         {
  780.         char *p;
  781.  
  782.         fputc('"', out);
  783.         for (p = lisp_string(obj); *p != 0; ++p)
  784.         {
  785.             if (*p == '"' || *p == '\\')
  786.             fputc('\\', out);
  787.             fputc(*p, out);
  788.         }
  789.         fputc('"', out);
  790.         }
  791.         break;
  792.  
  793.     case LISP_TYPE_CONS :
  794.     case LISP_TYPE_PATTERN_CONS :
  795.         fputs(lisp_type(obj) == LISP_TYPE_CONS ? "(" : "#?(", out);
  796.         while (obj != 0)
  797.         {
  798.         lisp_dump(lisp_car(obj), out);
  799.         obj = lisp_cdr(obj);
  800.         if (obj != 0)
  801.         {
  802.             if (lisp_type(obj) != LISP_TYPE_CONS
  803.             && lisp_type(obj) != LISP_TYPE_PATTERN_CONS)
  804.             {
  805.             fputs(" . ", out);
  806.             lisp_dump(obj, out);
  807.             break;
  808.             }
  809.             else
  810.             fputc(' ', out);
  811.         }
  812.         }
  813.         fputc(')', out);
  814.         break;
  815.  
  816.     case LISP_TYPE_BOOLEAN :
  817.         if (lisp_boolean(obj))
  818.         fputs("#t", out);
  819.         else
  820.         fputs("#f", out);
  821.         break;
  822.  
  823.     default :
  824.         assert(0);
  825.     }
  826. }
  827.