home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / oct93 / develop / umbscheme.lha / UMBScheme / src / io.c < prev    next >
C/C++ Source or Header  |  1992-08-04  |  14KB  |  723 lines

  1. /* io.c -- UMB Scheme, I/O package.
  2.  
  3. UMB Scheme Interpreter                  $Revision: 2.5 $
  4. Copyright (C) 1988, 1991 William R Campbell
  5.  
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 1, or (at your option)
  9. any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  
  20. UMB Scheme was written by Bill Campbell with help from Karl Berry,
  21. Barbara Dixey, Ira Gerstein, Mary Glaser, Kathy Hargreaves, Bill McCabe,
  22. Long Nguyen, Susan Quina, Jeyashree Sivasubram, Bela Sohoni and Thang Quoc Tran.
  23.  
  24. For additional information about UMB Scheme, contact the author:
  25.  
  26.     Bill Campbell
  27.     Department of Mathematics and Computer Science
  28.     University of Massachusetts at Boston
  29.     Harbor Campus
  30.     Boston, MA 02125
  31.  
  32.     Telephone: 617-287-6449        Internet: bill@cs.umb.edu
  33.  
  34. */
  35.  
  36. #include "portable.h"
  37. #include "eval.h"
  38. #include "object.h"
  39. #include "architecture.h"
  40. #include "steering.h"
  41. #include "primitive.h"
  42. #include "io.h"
  43. #include "number.h"
  44.  
  45. Public FILE *The_Standard_Input, *The_Standard_Output;
  46.  
  47.  
  48. /* A static variable printing keeps track of whether we want to print or not.*/
  49.  
  50. Private Boolean printing = TRUE;
  51.  
  52. Public void Set_Printing(turn_it_on)
  53.     Boolean turn_it_on;
  54. {
  55.     printing = turn_it_on;
  56. }
  57.  
  58. Public Boolean Get_Printing_State()
  59. {
  60.     return printing;
  61. }
  62.  
  63.  
  64. /* The routines that actually print somewhere. |Output| assumes that its 
  65. argument will not have a null. */
  66.  
  67. Public void Output(s)
  68.  
  69.     String s;
  70. {
  71.     fprintf(Get_Port_File(Current_Output_Port), "%s", s);
  72.  
  73.     if ( The_Transcript_Port != Nil )
  74.     { 
  75.         fprintf(Get_Port_File(The_Transcript_Port), "%s", s);
  76.     }
  77. }
  78.  
  79. /* |Output_Char| should perhaps do something about control characters. 
  80. When printing to the terminal, we certainly don't want to send control 
  81. characters, for example. */
  82.  
  83. Public void Output_Char(c)
  84.  
  85.     Character c;
  86. {
  87.     fprintf(Get_Port_File(Current_Output_Port), "%c", c);
  88.  
  89.     if ( The_Transcript_Port != Nil )
  90.     { 
  91.         fprintf(Get_Port_File(The_Transcript_Port), "%c", c);
  92.     }
  93. }
  94.  
  95. Public    Integer    New_Left_Margin( margin )
  96.     
  97.     Integer    margin;
  98. {
  99.     Integer    in_margin = margin;
  100.     Output( "\n" );
  101.     while ( margin-- > 0 )
  102.         Output( " " );
  103.     return( in_margin );
  104. }
  105.  
  106. Public void Print_Type(t)
  107.     Scheme_Type t;
  108. {
  109.     if (Boolean_Type == t) 
  110.     {
  111.         Output( "Boolean" ); 
  112.     }
  113.     if (Eclectic_Type == t) 
  114.     { 
  115.         Output( "Eclectic" ); 
  116.     }
  117.     if (Pair_Type == t) 
  118.     { 
  119.         Output( "Pair" ); 
  120.     }
  121.     if (Empty_List_Type == t) 
  122.     { 
  123.         Output( "Empty_List" ); 
  124.     }
  125.     if (Symbol_Type == t) 
  126.     { 
  127.         Output( "Symbol" ); 
  128.     }
  129.     if (Number_Type == t) 
  130.     { 
  131.         Output( "Number" ); 
  132.     }
  133.     if (Character_Type == t) 
  134.     { 
  135.         Output( "Character" ); 
  136.     }
  137.     if (String_Type == t) 
  138.     { 
  139.         Output( "String" ); 
  140.     }
  141.     if (Vector_Type == t) 
  142.     { 
  143.         Output( "Vector" ); 
  144.     }
  145.     if (Procedure_Type == t) 
  146.     { 
  147.         Output( "Procedure" ); 
  148.     }
  149.     if (Primitive_Type == t) 
  150.     { 
  151.         Output( "Primitive" ); 
  152.     }
  153.     if (Continuation_Type == t) 
  154.     { 
  155.         Output( "Continuation" ); 
  156.     }
  157.     if (Port_Type == t) 
  158.     { 
  159.         Output( "Port" ); 
  160.     }
  161.     if (Eof_Type == t) 
  162.     { 
  163.         Output( "Eof" ); 
  164.     }
  165.     if (Variable_Type == t) 
  166.     { 
  167.         Output( "Variable" ); 
  168.     }
  169.     if (Apply_Type == t) 
  170.     { 
  171.         Output( "Apply" ); 
  172.     }
  173.     if (Lambda_Type == t) 
  174.     { 
  175.         Output( "Lambda" ); 
  176.     }
  177.     if (Conditional_Type == t) 
  178.     { 
  179.         Output( "Conditional" ); 
  180.     }
  181.     if (Assignment_Type == t) 
  182.     { 
  183.         Output( "Assignment" ); 
  184.     }
  185.     if (Definition_Type == t) 
  186.     { 
  187.         Output( "Definition" ); 
  188.     }
  189.     if (Macro_Type == t) 
  190.     { 
  191.         Output( "Macro" ); 
  192.     }
  193.     if (Macro_Call_Type == t) 
  194.     { 
  195.         Output( "Macro_Call" ); 
  196.     }
  197.     if (Sequence_Type == t) 
  198.     { 
  199.         Output( "Sequence" ); 
  200.     }
  201.     if (Delay_Type == t) 
  202.     { 
  203.         Output( "Delay" ); 
  204.     }
  205.     if (Promise_Type == t) 
  206.     { 
  207.         Output( "Promise" ); 
  208.     }
  209.     if (Error_Type == t) 
  210.     { 
  211.         Output( "Error" ); 
  212.     }
  213.     if (Environment_Frame_Type == t) 
  214.     { 
  215.         Output( "Environment_Frame" ); 
  216.     }
  217.     if (State_Frame_Type == t) 
  218.     { 
  219.         Output( "State_Frame" ); 
  220.     }
  221.     if (Any_Type == t) 
  222.     { 
  223.         Output( "Any" ); 
  224.     }
  225. }
  226.  
  227. /* Reading. */
  228.  
  229. #define    MAX_TOKEN_SIZE 1000
  230.  
  231. typedef enum
  232. {
  233.     Lparen_Token,    Rparen_Token,    Quote_Token,    Backquote_Token,
  234.     Dot_Token,    Comma_Token,    Open_Vec_Token,    True_Token,
  235.     False_Token,    String_Token,    Number_Token,    Character_Token,
  236.     Symbol_Token,    Error_Token,    Comma_At_Token,    Eof_Token
  237. Token ;
  238.  
  239. Private    Token    The_Token ;
  240. Private    String Token_String ;
  241. Private    Character Token_Buffer[ MAX_TOKEN_SIZE ] ;
  242. Private    Integer    Token_Index ;
  243. Private    Boolean Transcripting = FALSE;
  244.  
  245. #define Is_Control_Char iscntrl
  246. #define    Is_White_Space    isspace 
  247.  
  248. #define Scan_Char(f)    (Transcripting?Tscan(f):getc(f))
  249.  
  250. Private    void Read_Number() ;
  251. Private    void Read_Symbol() ;
  252. Private int  Force_Lower() ;
  253. Private void Read_Token();
  254. Private void Read_List();
  255.  
  256.  
  257. /* Auxiliary input routines. */
  258.  
  259. Private    int    Tscan( f )
  260.  
  261.     FILE *    f;
  262. {
  263.     int c; 
  264.     if ( (c = getc(f)) != EOF ) putc(c , Get_Port_File(The_Transcript_Port));
  265.     return( c );
  266. }
  267.  
  268.     
  269.  
  270. Private Boolean Is_Delimiter(c)
  271.  
  272.     int    c;
  273. {
  274.     return( Is_White_Space(c) || c == '(' || c == ')' || c == '"' || c == ';');
  275. }
  276.  
  277.  
  278. /* Force uppercase letters (and only letters) to lowercase. */
  279. Private    int Force_Lower( Ch )
  280.     int    Ch ;
  281. {
  282.     return( isupper( Ch ) ? (Ch - 'A' + 'a') : Ch ) ;
  283. }
  284.  
  285.  
  286. /* Implement the ANSI routine `toint'. */
  287.  
  288. Public Integer toint(c)
  289.     int    c;
  290. {
  291.     if (isxdigit(c))
  292.     {
  293.         c = Force_Lower(c);
  294.         if (c >= 'a')
  295.             return c - 'a' + 10;
  296.         else
  297.             return c - '0';
  298.     }
  299.     else 
  300.     {
  301.         Panic( "Non-hex digit passed to toint" );
  302.         return 0;
  303.     }
  304. }
  305.  
  306. /* Read a Scheme object from |Input_File|; leave it in Value_Register. */
  307.  
  308. Public    void Read( Input_File )
  309.  
  310.     FILE*    Input_File ;
  311. {
  312.     Transcripting = The_Transcript_Port != Nil 
  313.                 &&  Input_File == The_Standard_Input; 
  314.  
  315.     Read_Token( Input_File ) ;
  316.  
  317.     switch( The_Token )
  318.     {
  319.     case Symbol_Token :
  320.         Value_Register = Intern_Name( Token_String ) ;
  321.         break ;
  322.  
  323.     case Lparen_Token :
  324.         Read_List( Input_File ) ;
  325.         break ;
  326.  
  327.     case Number_Token :
  328.         Cstring_To_Number( Token_String , 0 ) ;
  329.         break ;
  330.  
  331.     case String_Token :
  332.         /* We want to allow nulls in string constants. Hence
  333.                    |memcpy| instead of |strcpy|. */
  334.         Make_String( Token_Index );
  335.         memcpy( Get_String_Value(Value_Register), Token_Buffer, 
  336.             Token_Index );
  337.         Get_String_Value( Value_Register ) [ Token_Index ] = '\0';
  338.         break ;
  339.  
  340.     case Character_Token :
  341.         Make_Character( *Token_String ) ;
  342.         break ;
  343.  
  344.     case True_Token :
  345.         Value_Register = The_True_Object ;
  346.         break ;
  347.  
  348.     case False_Token :
  349.         Value_Register = The_False_Object ;
  350.         break ;
  351.         
  352.         case Open_Vec_Token :
  353.         Read_List( Input_File ) ;
  354.         Push( Value_Register ) ;
  355.         List_To_Vector() ;
  356.         Pop( 1 ) ;
  357.         break ;
  358.  
  359.     case Dot_Token :
  360.         Value_Register = The_Dot_Object ;
  361.         break ;
  362.  
  363.     case Rparen_Token :
  364.         Value_Register = The_Rparen_Object ;
  365.         break ;
  366.  
  367.     case Quote_Token :
  368.         Push( Intern_Name( "quote" ) ) ;
  369.         Read( Input_File ) ;
  370.         Push( Value_Register ) ;
  371.         Push( Nil ) ;
  372.         Make_Pair() ;
  373.         Push( Value_Register ) ;
  374.         Make_Pair() ;
  375.         break ;
  376.  
  377.     case Backquote_Token :
  378.         Push( Intern_Name( "quasiquote" ) ) ;
  379.         Read( Input_File ) ;
  380.         Push( Value_Register ) ;
  381.         Push( Nil ) ;
  382.         Make_Pair() ;
  383.         Push( Value_Register ) ;
  384.         Make_Pair() ;
  385.         break ;
  386.  
  387.     case Comma_Token :
  388.         Push( Intern_Name( "unquote" ) ) ;
  389.         Read( Input_File ) ;
  390.         Push( Value_Register ) ;
  391.         Push( Nil ) ;
  392.         Make_Pair() ;
  393.         Push( Value_Register ) ;
  394.         Make_Pair() ;
  395.         break ;
  396.  
  397.     case Comma_At_Token :
  398.         Push( Intern_Name( "unquote-splicing" ) ) ;
  399.         Read( Input_File ) ;
  400.         Push( Value_Register ) ;
  401.         Push( Nil ) ;
  402.         Make_Pair() ;
  403.         Push( Value_Register ) ;
  404.         Make_Pair() ;
  405.         break ;
  406.  
  407.     case Error_Token :
  408.         Make_Error( Token_String ) ;
  409.         break ;
  410.  
  411.     case Eof_Token :
  412.         Value_Register = The_Eof_Object ;
  413.         break ;
  414.  
  415.     default :
  416.         Panic( "Unidentified token" ) ;
  417.         break ;
  418.     }
  419. }
  420.  
  421.  
  422. /* Read list from Input_File and leave it in Value_Register. This allows 
  423. the input `( . x )' (it treats it as equivalent to x), which is not strictly 
  424. legal according to the manual. */
  425.  
  426. Private    void Read_List( Input_File )
  427.  
  428.     FILE*    Input_File ;
  429. {
  430.     Read( Input_File ) ;
  431.  
  432.     if ( Value_Register == The_Rparen_Object )
  433.     {
  434.         Value_Register = Nil ;
  435.     }
  436.     else if ( Value_Register == The_Dot_Object )
  437.     {
  438.         Read( Input_File ) ;
  439.         if ( Value_Register == The_Rparen_Object || 
  440.             Value_Register == The_Dot_Object ||
  441.             Value_Register == The_Eof_Object )
  442.         {
  443.             Make_Error( "Bad syntax involving dot operator" ) ;
  444.         }
  445.         else
  446.         {
  447.             Push( Value_Register ) ;
  448.             Read( Input_File ) ;
  449.             if ( Value_Register != The_Rparen_Object )
  450.             {
  451.                 Make_Error("No right parenthesis after dot") ;
  452.             }
  453.             else
  454.             {
  455.                 Value_Register = Top( 1 ) ;
  456.             }
  457.             Pop( 1 ) ;
  458.         }
  459.     }
  460.     else if ( Value_Register == The_Eof_Object )
  461.     {
  462.         Make_Error( "Unexpected EOF" ) ;
  463.     }
  464.     else
  465.     {
  466.         Push( Value_Register ) ;
  467.         Read_List( Input_File ) ;
  468.         if ( Is_Error( Top( 1 ) ) )
  469.         {
  470.             Value_Register = Top( 1 ); /* Propagate first error. */
  471.             Pop( 1 ) ;
  472.         }
  473.         else if ( Is_Error( Value_Register ) )
  474.         {
  475.             Pop( 1 ) ;
  476.         }
  477.         else
  478.         {
  479.             Push( Value_Register ) ;
  480.             Make_Pair() ;
  481.         }
  482.     }
  483. }
  484.  
  485.  
  486. /* Read a single token from |Input_File|. Leave the result in |The_Token|, 
  487.    and the string matched in |Token_Buffer|. (|Token_Index| will be the 
  488.    length of the string matched. */
  489.  
  490. Private    void Read_Token( Input_File )
  491.  
  492.     FILE*    Input_File ;
  493. {
  494.     int    ch ;     /* Hold input characters */
  495.  
  496. READ_A_TOKEN:
  497.  
  498.     while ( Is_White_Space( ch = Scan_Char( Input_File ) ) );
  499.  
  500.     switch ( ch )
  501.     {
  502.     case '(' :
  503.         The_Token = Lparen_Token;
  504.         break;
  505.  
  506.     case ')' :
  507.         The_Token = Rparen_Token;
  508.         break;
  509.  
  510.     case '\'' :
  511.         The_Token = Quote_Token;
  512.         break;
  513.  
  514.     case '`' :
  515.         The_Token = Backquote_Token;
  516.         break;
  517.  
  518.     case '.' :
  519.         if ( isdigit( Peek_Char( Input_File ) ) )
  520.         {
  521.             Read_Number( '.' , Input_File );
  522.         }
  523.         else
  524.         {
  525.             The_Token = Dot_Token;
  526.         }
  527.         break;
  528.  
  529.     case ',' :
  530.         if ( Peek_Char( Input_File ) == '@' )
  531.         {
  532.             ch = Scan_Char( Input_File );
  533.             The_Token = Comma_At_Token ;
  534.         }
  535.         else
  536.         {
  537.             The_Token = Comma_Token ;
  538.         }
  539.         break ;
  540.         
  541.         case '#' :
  542.         switch ( Force_Lower( Peek_Char( Input_File ) ) )
  543.         {
  544.         case '(' :
  545.             ch = Scan_Char( Input_File );
  546.             The_Token = Open_Vec_Token ;
  547.             break ;
  548.  
  549.         case 't' :
  550.             ch = Scan_Char( Input_File );
  551.             The_Token = True_Token ;
  552.             break ;
  553.  
  554.         case 'f' :
  555.             ch = Scan_Char( Input_File );
  556.             The_Token = False_Token ;
  557.             break ;
  558.  
  559.         case '\\' :
  560.             ch = Scan_Char( Input_File );
  561.             The_Token = Character_Token ;
  562.  
  563.             /* Scan character or character name */
  564.  
  565.             Token_Index = 0 ;
  566.             Token_Buffer[Token_Index++] = ch = 
  567.                         Scan_Char( Input_File ) ;
  568.             if ( isalpha( ch ) )
  569.             {
  570.                       while (!Is_Delimiter( Peek_Char( Input_File )))
  571.                     {
  572.                         Token_Buffer[Token_Index++] = 
  573.                             Scan_Char( Input_File );
  574.                     }
  575.             }
  576.             Token_Buffer[Token_Index] = '\0' ;
  577.  
  578.             Token_String =
  579.                 Token_Index == 1 ? Token_Buffer :
  580.                 Eq_Strs( Token_Buffer , "space" )   ? " " :
  581.                 Eq_Strs( Token_Buffer , "tab" )     ? "\t" :
  582.                 Eq_Strs( Token_Buffer , "newline" ) ? "\n" :
  583.                 Eq_Strs( Token_Buffer , "newpage" ) ? "\f" :
  584.                 ( The_Token = Error_Token,
  585.                 "Unrecognized character name" ) ;
  586.             break ;
  587.  
  588.         case 'i' : 
  589.         case 'e' : 
  590.         case 's' : 
  591.         case 'l' :
  592.         case 'b' : 
  593.         case 'o' : 
  594.         case 'd' : 
  595.         case 'x' :
  596.  
  597.             /* All legal prefixes to numbers */
  598.             Read_Number( '#' , Input_File ) ;
  599.             break ;
  600.  
  601.         default :
  602.             /* Call it a symbol (not exactly legal) */
  603.             Read_Symbol( '#' , Input_File ) ;
  604.         }
  605.         break ;
  606.         
  607.         case '"' :
  608.         The_Token = String_Token ;
  609.         Token_Index = 0 ;
  610.         while ( (ch = Scan_Char( Input_File )) != '\"' ) 
  611.         {
  612.             if ( Token_Index >= MAX_TOKEN_SIZE )
  613.             {
  614.                 Error( "Missing closed quote on a string" );
  615.             }
  616.  
  617.             if ( ch == '\\' )
  618.             {
  619.                 /* \ is an escape character */
  620.                 ch = Scan_Char( Input_File ) ;
  621.             }
  622.             Token_Buffer[ Token_Index++ ] = ch ;
  623.         }
  624.         Token_Buffer[Token_Index] = '\0' ;
  625.         Token_String = Token_Buffer ;
  626.         break ;
  627.  
  628.     case '+' :
  629.     case '-' :
  630.         if ( (Is_Delimiter( Peek_Char( Input_File ) )) )
  631.         {
  632.             /* The symbol + or -. */
  633.             Read_Symbol( ch , Input_File ) ;
  634.         }
  635.         else
  636.         {
  637.             /* Otherwise the + or - must start a number. */
  638.             Read_Number( ch , Input_File ) ;
  639.         }
  640.         break ;
  641.  
  642.     case ';' :
  643.         /* ; announces a comment which extends to the newline */
  644.         Token_String = fgets(Token_Buffer, MAX_TOKEN_SIZE, Input_File);
  645.         goto READ_A_TOKEN ;
  646.         break ;
  647.  
  648.     case EOF :
  649.         The_Token = Eof_Token ;
  650.         break ;
  651.  
  652.     default :
  653.         if ( isdigit( ch ) )
  654.         {
  655.             Read_Number( ch , Input_File ) ;
  656.         }
  657.         else
  658.         {
  659.             Read_Symbol( ch , Input_File ) ;
  660.         }
  661.     }
  662. }
  663.  
  664.  
  665. /* We do a naive scan, scanning up to a delimiter.  The external rep is
  666.    actually parsed when it's converted to a number in Read. */
  667.  
  668. Private    void Read_Number( Ch , Input_File )
  669.  
  670.     Character    Ch ;        /* Leading Character of Number */
  671.     FILE*        Input_File ;    /* Containing remaining chars */
  672. {
  673.  
  674.     Token_Buffer[0] = Ch ;
  675.     Token_Index = 1 ;
  676.     while ( !Is_Delimiter( Force_Lower( Peek_Char( Input_File ) ) ) )
  677.     {
  678.         Token_Buffer[Token_Index++] = 
  679.             Force_Lower( Scan_Char( Input_File ) );
  680.     }
  681.     Token_Buffer[Token_Index] = '\0' ;
  682.     The_Token = Number_Token ;
  683.     Token_String = Token_Buffer ;
  684. }
  685.  
  686.  
  687. /* We do a naive scan, scanning up to a delimiter.  This allows for more than
  688.    is described in the formal syntax. We do eliminate control characters. */
  689.  
  690. Private    void Read_Symbol( Ch , Input_File )
  691.  
  692.     Character    Ch ;        /* Leading character of symbol. */
  693.     FILE*        Input_File ;    /* Containing remaining chars. */
  694. {
  695.     Token_Index = 0 ;
  696.     if (! Is_Control_Char(Ch))
  697.     {
  698.         Token_Buffer[Token_Index++] = Force_Lower( Ch ) ;
  699.     }
  700.  
  701.     while ( !Is_Delimiter( Peek_Char( Input_File ) ) )
  702.     {
  703.         Ch = Scan_Char( Input_File );
  704.         if (! Is_Control_Char(Ch))
  705.         {
  706.             Token_Buffer[Token_Index++] = Force_Lower( Ch ) ;
  707.         }
  708.     }; 
  709.  
  710.     if (Token_Index > 0)
  711.     {
  712.         Token_Buffer[Token_Index] = '\0' ;
  713.         The_Token = Symbol_Token ;
  714.         Token_String = Token_Buffer ;
  715.     } 
  716.     else
  717.     {
  718.         The_Token = Error_Token;
  719.         Token_String = "Null symbol name";
  720.     }
  721. }
  722.