home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / APPS / lout2.lzh / LOUT2 / z05.c < prev    next >
Text File  |  1994-01-23  |  21KB  |  620 lines

  1. /*@z05.c:Read Definitions:ReadFontDef()@**************************************/
  2. /*                                                                           */
  3. /*  LOUT: A HIGH-LEVEL LANGUAGE FOR DOCUMENT FORMATTING (VERSION 2.05)       */
  4. /*  COPYRIGHT (C) 1993 Jeffrey H. Kingston                                   */
  5. /*                                                                           */
  6. /*  Jeffrey H. Kingston (jeff@cs.su.oz.au)                                   */
  7. /*  Basser Department of Computer Science                                    */
  8. /*  The University of Sydney 2006                                            */
  9. /*  AUSTRALIA                                                                */
  10. /*                                                                           */
  11. /*  This program is free software; you can redistribute it and/or modify     */
  12. /*  it under the terms of the GNU General Public License as published by     */
  13. /*  the Free Software Foundation; either version 1, or (at your option)      */
  14. /*  any later version.                                                       */
  15. /*                                                                           */
  16. /*  This program is distributed in the hope that it will be useful,          */
  17. /*  but WITHOUT ANY WARRANTY; without even the implied warranty of           */
  18. /*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            */
  19. /*  GNU General Public License for more details.                             */
  20. /*                                                                           */
  21. /*  You should have received a copy of the GNU General Public License        */
  22. /*  along with this program; if not, write to the Free Software              */
  23. /*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                */
  24. /*                                                                           */
  25. /*  FILE:         z05.c                                                      */
  26. /*  MODULE:       Read Definitions                                           */
  27. /*  EXTERNS:      ReadPrependDef(), ReadDatabaseDef(), ReadDefinitions()     */
  28. /*                                                                           */
  29. /*****************************************************************************/
  30. #include "externs"
  31.  
  32.  
  33. /*****************************************************************************/
  34. /*                                                                           */
  35. /*  is_string(t, str)                                                        */
  36. /*                                                                           */
  37. /*  If t is a token denoting unquoted word str, return TRUE.                 */
  38. /*                                                                           */
  39. /*****************************************************************************/
  40.  
  41. #define is_string(t, str)    (type(t) == WORD && StringEqual(string(t), str) )
  42.  
  43.  
  44. /*****************************************************************************/
  45. /*                                                                           */
  46. /*  static ReadFontDef(encl)                                                 */
  47. /*                                                                           */
  48. /*  Read one font definition and pass it on to the font module.  The         */
  49. /*  syntax is  fontdef <family> <face> { <object> }.                         */
  50. /*                                                                           */
  51. /*****************************************************************************/
  52.  
  53. static ReadFontDef(encl)
  54. OBJECT encl;
  55. { OBJECT t, family, face, inside;
  56.   
  57.   SuppressScope();
  58.   family = LexGetToken();
  59.   if( !is_word(type(family)) )
  60.     Error(WARN, &fpos(family), "expected font family name here");
  61.   face = LexGetToken();
  62.   if( !is_word(type(face)) )
  63.     Error(WARN, &fpos(face), "expected font face name here");
  64.   UnSuppressScope();
  65.   t = LexGetToken();
  66.   if( type(t) != LBR )
  67.   { Error(WARN, &fpos(t), "expected opening %s of fontdef here", KW_LBR);
  68.     Dispose(t);
  69.     return;
  70.   }
  71.   inside = Parse(&t, encl, FALSE, FALSE);
  72.   inside = ReplaceWithTidy(inside);
  73.   FontDefine(family, face, inside);
  74.   return;
  75. } /* end ReadFontDef */
  76.  
  77.  
  78. /*@::ReadPrependDef(), ReadDatabaseDef()@*************************************/
  79. /*                                                                           */
  80. /*  ReadPrependDef(typ, encl)                                                */
  81. /*                                                                           */
  82. /*  Read @Prepend { <filename> } and record its presence.                    */
  83. /*                                                                           */
  84. /*****************************************************************************/
  85.  
  86. ReadPrependDef(typ, encl)
  87. unsigned typ;  OBJECT encl;
  88. { OBJECT t, fname;  FILE_NUM fnum;
  89.   t = LexGetToken();
  90.   if( type(t) != LBR )
  91.   { Error(WARN, &fpos(t), "symbol name or %s expected here in %s declaration",
  92.       KW_LBR, KW_PREPEND);
  93.     Dispose(t);
  94.     return;
  95.   }
  96.   fname = Parse(&t, encl, FALSE, FALSE);
  97.   fname = ReplaceWithTidy(fname);
  98.   if( !is_word(type(fname)) )
  99.   { Error(WARN, &fpos(fname), "name of %s file expected here", KW_PREPEND);
  100.     DisposeObject(fname);
  101.     return;
  102.   }
  103.   fnum = DefineFile(string(fname), STR_EMPTY, &fpos(fname), PREPEND_FILE,
  104.        typ == PREPEND ? INCLUDE_PATH : SYSINCLUDE_PATH);
  105.  
  106. } /* end ReadPrependDef */
  107.  
  108.  
  109. /*****************************************************************************/
  110. /*                                                                           */
  111. /*  ReadDatabaseDef(typ, encl)                                               */
  112. /*                                                                           */
  113. /*  Read @Database <symname> ... <symname> { <filename> } and record it.     */
  114. /*                                                                           */
  115. /*****************************************************************************/
  116.  
  117. ReadDatabaseDef(typ, encl)
  118. unsigned typ;  OBJECT encl;
  119. { OBJECT symbs, t, db, fname;
  120.   symbs = New(ACAT);
  121.   t = LexGetToken();
  122.   while( type(t) == CLOSURE )
  123.   { Link(symbs, t);
  124.     t = LexGetToken();
  125.   }
  126.   if( type(t) != LBR )
  127.   { Error(WARN, &fpos(t), "symbol name or %s expected here in %s declaration",
  128.       KW_LBR, KW_DATABASE);
  129.     Dispose(t);
  130.     return;
  131.   }
  132.   if( Down(symbs) == symbs )
  133.   { Error(WARN, &fpos(t), "symbol names missing in %s declaration",
  134.       KW_DATABASE);
  135.     Dispose(t);
  136.     return;
  137.   }
  138.   fname = Parse(&t, encl, FALSE, FALSE);
  139.   fname = ReplaceWithTidy(fname);
  140.   if( !is_word(type(fname)) )
  141.   { Error(WARN, &fpos(fname), "name of %s file expected here", KW_DATABASE);
  142.     DisposeObject(fname);
  143.     return;
  144.   }
  145.   db = DbLoad(fname, typ == DATABASE ? DATABASE_PATH : SYSDATABASE_PATH,
  146.      TRUE, symbs);
  147. } /* end ReadDatabaseDef */
  148.  
  149.  
  150. /*@::ReadTokenList()@*********************************************************/
  151. /*                                                                           */
  152. /*  static ReadTokenList(res)                                                */
  153. /*                                                                           */
  154. /*  Read a list of tokens from input and append them to sym_body(res).       */
  155. /*  The list is assumed to begin immediately after an LBR, and input is      */
  156. /*  to be read up to and including the matching RBR.                         */
  157. /*                                                                           */
  158. /*****************************************************************************/
  159. #define NextToken(t, res)                        \
  160.   t = LexGetToken(); sym_body(res) = Append(sym_body(res), t, PARENT);
  161.  
  162. static ReadTokenList(res)
  163. OBJECT res;
  164. { OBJECT t, xsym, new_par;
  165.   NextToken(t, res);
  166.   for(;;) switch(type(t))
  167.   {
  168.     case WORD:
  169.  
  170.       if( string(t)[0] == CH_SYMSTART )
  171.     Error(WARN, &fpos(t), "symbol %s unknown", string(t));
  172.       NextToken(t, res);
  173.       break;
  174.  
  175.  
  176.     case QWORD:
  177.  
  178.       NextToken(t, res);
  179.       break;
  180.  
  181.  
  182.     case VCAT:
  183.     case HCAT:
  184.     case ACAT:
  185.     case CROSS:
  186.     case NULL_CLOS:
  187.     case ONE_COL:
  188.     case ONE_ROW:
  189.     case WIDE:
  190.     case HIGH:
  191.     case HSCALE:
  192.     case VSCALE:
  193.     case SCALE:
  194.     case HCONTRACT:
  195.     case VCONTRACT:
  196.     case HEXPAND:
  197.     case VEXPAND:
  198.     case PADJUST:
  199.     case HADJUST:
  200.     case VADJUST:
  201.     case ROTATE:
  202.     case CASE:
  203.     case YIELD:
  204.     case XCHAR:
  205.     case FONT:
  206.     case SPACE:
  207.     case BREAK:
  208.     case NEXT:
  209.     case TAGGED:
  210.     case INCGRAPHIC:
  211.     case SINCGRAPHIC:
  212.     case GRAPHIC:
  213.  
  214.       NextToken(t, res);
  215.       break;
  216.  
  217.  
  218.     case LVIS:
  219.     case ENV:
  220.     case USE:
  221.     case BEGIN:
  222.     case END:
  223.     case DATABASE:
  224.     case SYS_DATABASE:
  225.     case PREPEND:
  226.     case SYS_PREPEND:
  227.     case OPEN:
  228.  
  229.       Error(WARN, &fpos(t), "symbol %s not allowed in macro",
  230.     SymName(actual(t)));
  231.       NextToken(t, res);
  232.       break;
  233.  
  234.  
  235.     case LBR:
  236.  
  237.       ReadTokenList(res);
  238.       NextToken(t, res);
  239.       break;
  240.  
  241.  
  242.     case RBR:
  243.  
  244.       return;
  245.  
  246.  
  247.     case CLOSURE:
  248.  
  249.       xsym = actual(t);
  250.       PushScope(xsym, TRUE, FALSE);
  251.       NextToken(t, res);
  252.       PopScope();
  253.       if( type(t) == CROSS )
  254.       { NextToken(t, res);
  255.     break;
  256.       }
  257.  
  258.       /* read named parameters */
  259.       while( type(t) == CLOSURE && enclosing(actual(t)) == xsym &&
  260.          type(actual(t)) == NPAR )
  261.       {    new_par = t;
  262.     NextToken(t, res);
  263.     if( type(t) != LBR )
  264.     { Error(WARN, &fpos(new_par), "%s must follow name parameter %s",
  265.         KW_LBR, SymName(actual(new_par)));
  266.       break;
  267.     }
  268.     PushScope(actual(new_par), FALSE, FALSE);
  269.     ReadTokenList(res);
  270.     PopScope();
  271.  
  272.     /* get next token, possibly another named parameter */
  273.     PushScope(xsym, TRUE, FALSE);
  274.     NextToken(t, res);
  275.     PopScope();
  276.       }
  277.  
  278.       /* read body parameter, if any */
  279.       if( has_body(xsym) )
  280.       {    if( type(t) == LBR )
  281.     { PushScope(xsym, FALSE, TRUE);
  282.       PushScope(ChildSym(xsym, RPAR), FALSE, FALSE);
  283.       ReadTokenList(res);
  284.       PopScope();
  285.       PopScope();
  286.       NextToken(t, res);
  287.     }
  288.     else Error(WARN, &fpos(t), "right parameter of %s must begin with %s",
  289.         SymName(xsym), KW_LBR);
  290.       }
  291.       break;
  292.  
  293.     default:
  294.  
  295.  
  296.       Error(INTERN, &fpos(t), "unknown token type %s", Image(type(t)));
  297.       break;
  298.  
  299.   }
  300. } /* end ReadTokenList */
  301.  
  302.  
  303. /*@::ReadMacro()@*************************************************************/
  304. /*                                                                           */
  305. /*  static OBJECT ReadMacro(token, encl)                                     */
  306. /*                                                                           */
  307. /*  Read a macro from input and insert into symbol table.                    */
  308. /*  Token *token contains the "macro" keyword.  Input is read up to and      */
  309. /*  including the closing right brace, and nil is returned in *token if OK.  */
  310. /*  The proper scope for reading the macro body is open at entry and exit.   */
  311. /*  ReadMacro returns the new symbol table entry if successful, else nil.    */
  312. /*                                                                           */
  313. /*****************************************************************************/
  314.  
  315. static OBJECT ReadMacro(token, encl)
  316. OBJECT *token, encl;
  317. { OBJECT t, res;
  318.  
  319.   /* find macro name and insert into symbol table */
  320.   SuppressScope();
  321.   Dispose(*token);  t = LexGetToken();
  322.   if( !is_word(type(t)) )
  323.   { Error(WARN, &fpos(t), "%s ignored - name is missing", KW_MACRO);
  324.     debug1(ANY, D, "offending type is %s", Image(type(t)));
  325.     UnSuppressScope();
  326.     *token = t;
  327.     return nil;
  328.   }
  329.   res = InsertSym(string(t), MACRO, &fpos(t), 0, FALSE, TRUE, 0, encl, nil);
  330.  
  331.   /* find opening left brace */
  332.   t = LexGetToken();
  333.   if( !is_string(t, KW_LBR) )
  334.   { Error(WARN, &fpos(t), "%s ignored - opening %s missing", KW_MACRO, KW_LBR);
  335.     UnSuppressScope();
  336.     *token = t;
  337.     return nil;
  338.   }
  339.   Dispose(t);
  340.   
  341.   /* read macro body */
  342.   UnSuppressScope();
  343.   ReadTokenList(res);
  344.  
  345.   /* clean up (kill final RBR, dispose macro name) and exit */
  346.   sym_body(res) = DeleteAndDispose(pred(sym_body(res), PARENT), PARENT);
  347.   recursive(res) = FALSE;
  348.   *token = nil;
  349.   return res;
  350. } /* end ReadMacro */
  351.  
  352.  
  353. /*@::ReadDefinitions()@*******************************************************/
  354. /*                                                                           */
  355. /*  ReadDefinitions(token, encl, res_type)                                   */
  356. /*                                                                           */
  357. /*  Read a sequence of definitions and insert them into the symbol table.    */
  358. /*  Either a sequence of local definitions (res_type == LOCAL) or named      */
  359. /*  parameters (res_type == NPAR) is expected; *token is the first def etc.  */
  360. /*  A scope appropriate for reading the bodies of the definitions is open.   */
  361. /*  The parent definition is encl.                                           */
  362. /*                                                                           */
  363. /*****************************************************************************/
  364.  
  365. ReadDefinitions(token, encl, res_type)
  366. OBJECT *token, encl;  unsigned char res_type;
  367. { OBJECT t, res, res_target, export_list, import_list, link, y, z;
  368.   t = *token;
  369.  
  370.   while( res_type != LOCAL ? is_string(t, KW_NAMED) : TRUE )
  371.   {
  372.     if( is_string(t, KW_FONTDEF) )
  373.     { ReadFontDef(encl);
  374.       t = LexGetToken();
  375.       continue;  /* next definition */
  376.     }
  377.     else if( type(t) == PREPEND || type(t) == SYS_PREPEND )
  378.     { ReadPrependDef(type(t), encl);
  379.       Dispose(t);
  380.       t = LexGetToken();
  381.       continue;  /* next definition */
  382.     }
  383.     else if( type(t) == DATABASE || type(t) == SYS_DATABASE )
  384.     { ReadDatabaseDef(type(t), encl);
  385.       Dispose(t);
  386.       t = LexGetToken();
  387.       continue;  /* next definition */
  388.     }
  389.  
  390.     if( !is_string(t, KW_DEF)   && !is_string(t, KW_MACRO)  &&
  391.     !is_string(t, KW_NAMED) && !is_string(t, KW_IMPORT) &&
  392.         !is_string(t, KW_EXPORT) )
  393.       break;
  394.  
  395.     /* get import list and change scope appropriately */
  396.     BodyParNotAllowed();
  397.     import_list = New(ACAT);
  398.     if( is_string(t, KW_IMPORT) )
  399.     { Dispose(t);
  400.       t = LexGetToken();
  401.       while( type(t) == CLOSURE ||
  402.            (type(t)==WORD && !is_string(t,KW_EXPORT) && !is_string(t,KW_DEF)
  403.            && !is_string(t, KW_MACRO)) )
  404.       {    if( type(t) == CLOSURE )
  405.     { if( type(actual(t)) == LOCAL )
  406.       { PushScope(actual(t), FALSE, TRUE);
  407.         Link(import_list, t);
  408.       }
  409.       else
  410.       { Error(WARN, &fpos(t), "import name expected here");
  411.         Dispose(t);
  412.       }
  413.     }
  414.     else
  415.     { Error(WARN,&fpos(t),"import %s not in scope", string(t));
  416.       Dispose(t);
  417.     }
  418.     t = LexGetToken();
  419.       }
  420.     }
  421.  
  422.     /* get export list and store for setting visible flags below */
  423.     export_list = New(ACAT);
  424.     if( is_string(t, KW_EXPORT) )
  425.     { Dispose(t);
  426.       SuppressScope();
  427.       t = LexGetToken();
  428.       while( is_word(type(t)) && !is_string(t, KW_DEF) )
  429.       { Link(export_list, t);
  430.     t = LexGetToken();
  431.       }
  432.       UnSuppressScope();
  433.     }
  434.  
  435.  
  436.     if( res_type == LOCAL && !is_string(t, KW_DEF) && !is_string(t, KW_MACRO) )
  437.     { Error(WARN,&fpos(t),"keyword %s or %s expected here", KW_DEF, KW_MACRO);
  438.       break;
  439.     }
  440.     if( res_type == NPAR && !is_string(t, KW_NAMED) )
  441.     { Error(WARN, &fpos(t), "keyword %s expected here", KW_NAMED);
  442.       break;
  443.     }
  444.  
  445.     if( is_string(t, KW_MACRO) )
  446.     { if( Down(export_list) != export_list )
  447.     Error(WARN, &fpos(t), "ignoring %s list of %s", KW_EXPORT, KW_MACRO);
  448.       res = ReadMacro(&t, encl);
  449.     }
  450.     else
  451.     {
  452.       SuppressScope();  Dispose(t);  t = LexGetToken();
  453.  
  454.       /* find name of symbol and insert it */
  455.       if( !is_word(type(t)) )
  456.       { Error(WARN, &fpos(t), "cannot find symbol name");
  457.     debug1(ANY, D, "offending type is %s", Image(type(t)));
  458.     UnSuppressScope();
  459.     *token = t;
  460.     return;
  461.       }
  462.       res = InsertSym(string(t), res_type, &fpos(t), DEFAULT_PREC,
  463.         FALSE, FALSE, 0, encl, nil);
  464.       t = LexGetToken();
  465.  
  466.       /* find force, if any */
  467.       if( is_string(t, KW_FORCE) )
  468.       {    force_target(res) = TRUE;
  469.     Dispose(t);  t = LexGetToken();
  470.     if( !is_string(t, KW_INTO) )
  471.        Error(WARN, &fpos(t), "%s expected after %s", KW_INTO, KW_FORCE);
  472.       }
  473.     
  474.       /* find into clause, if any */
  475.       res_target = nil;
  476.       if( is_string(t, KW_INTO) )
  477.       { UnSuppressScope();
  478.     Dispose(t);  t = LexGetToken();
  479.     if( type(t) != LBR )
  480.     { Error(WARN, &fpos(t), "%s expected after %s", KW_LBR, KW_INTO);
  481.       debug1(ANY, D, "offending type is %s", Image(type(t)));
  482.       UnSuppressScope();
  483.       *token = t;
  484.       return;
  485.     }
  486.     res_target = Parse(&t, encl, FALSE, FALSE);
  487.     SuppressScope();
  488.     if( t == nil )  t = LexGetToken();
  489.       }
  490.  
  491.       /* find precedence clause, if any */
  492.       if( is_string(t, KW_PRECEDENCE) )
  493.       {    int prec = 0;
  494.     Dispose(t);
  495.     t = LexGetToken();
  496.     while( type(t) == WORD && decimaldigit(string(t)[0]) )
  497.     {
  498.       prec = prec * 10 + digitchartonum(string(t)[0]);
  499.       Dispose(t);  t = LexGetToken();
  500.     }
  501.  
  502.     if( prec < MIN_PREC )
  503.     { Error(WARN, &fpos(t), "%s is too low - %d substituted",
  504.         KW_PRECEDENCE, MIN_PREC);
  505.       prec = MIN_PREC;
  506.     }
  507.     else if( prec > MAX_PREC )
  508.     { Error(WARN, &fpos(t), "%s is too high - %d substituted",
  509.         KW_PRECEDENCE, MAX_PREC);
  510.       prec = MAX_PREC;
  511.     }
  512.     precedence(res) = prec;
  513.       }
  514.  
  515.       /* find associativity clause, if any */
  516.       if( is_string(t, KW_ASSOC) )
  517.       {    Dispose(t);  t = LexGetToken();
  518.     if( is_string(t, KW_LEFT) )  right_assoc(res) = FALSE;
  519.     else if( !is_string(t, KW_RIGHT) )
  520.       Error(WARN, &fpos(t), "%s replaced by %s", KW_ASSOC, KW_RIGHT);
  521.     Dispose(t);  t = LexGetToken();
  522.       }
  523.  
  524.       /* find left parameter, if any */
  525.       if( is_string(t, KW_LEFT) )
  526.       {    Dispose(t);  t = LexGetToken();
  527.     if( type(t) != WORD )
  528.     { Error(WARN, &fpos(t), "cannot find %s parameter name", KW_LEFT);
  529.       debug1(ANY, D, "offending type is %s", Image(type(t)));
  530.       UnSuppressScope();
  531.       *token = t;
  532.       return;
  533.     }
  534.     InsertSym(string(t), LPAR, &fpos(t), DEFAULT_PREC, 
  535.       FALSE, FALSE, 0, res, nil);
  536.     Dispose(t);  t = LexGetToken();
  537.       }
  538.  
  539.       /* find named parameters, if any */
  540.       UnSuppressScope();
  541.       ReadDefinitions(&t, res, NPAR);
  542.  
  543.       /* find right or body parameter, if any */
  544.       if( is_string(t, KW_RIGHT) || is_string(t, KW_BODY) )
  545.       {    has_body(res) = is_string(t, KW_BODY);
  546.     SuppressScope();
  547.     Dispose(t);  t = LexGetToken();
  548.     if( type(t) != WORD )
  549.     { Error(WARN, &fpos(t), "cannot find %s parameter name", KW_RIGHT);
  550.       debug1(ANY, D, "offending type is %s", Image(type(t)));
  551.       UnSuppressScope();
  552.       *token = t;
  553.       return;
  554.     }
  555.     InsertSym(string(t), RPAR, &fpos(t), DEFAULT_PREC,
  556.       FALSE, FALSE, 0, res, nil);
  557.     UnSuppressScope();
  558.     Dispose(t);  t = LexGetToken();
  559.       }
  560.  
  561.       /* read local definitions and body */
  562.       if( res_target != nil )
  563.     InsertSym(KW_TARGET, LOCAL, &fpos(res_target), DEFAULT_PREC,
  564.             FALSE, FALSE, 0, res, res_target);
  565.       if( type(t) == WORD && StringEqual(string(t), KW_LBR) )
  566.       {    z = NewToken(LBR, &fpos(t), 0, 0, LBR_PREC, StartSym);
  567.     Dispose(t);
  568.     t = z;
  569.       }
  570.       else if( type(t) == WORD && StringEqual(string(t), KW_BEGIN) )
  571.       {    z = NewToken(BEGIN, &fpos(t), 0, 0, BEGIN_PREC, StartSym);
  572.     Dispose(t);
  573.     t = z;
  574.       }
  575.       else if( type(t) != LBR && type(t) != BEGIN )
  576.     Error(FATAL, &fpos(t), "opening %s or %s of %s expected",
  577.      KW_LBR, KW_BEGIN, SymName(res));
  578.       if( type(t) == BEGIN )  actual(t) = res;
  579.       PushScope(res, FALSE, FALSE);
  580.       BodyParAllowed();
  581.       sym_body(res) = Parse(&t, res, TRUE, FALSE);
  582.  
  583.       /* set visible flag of the exported symbols */
  584.       for( link=Down(export_list);  link != export_list;  link=NextDown(link) )
  585.       {    Child(y, link);
  586.     z = SearchSym(string(y), StringLength(string(y)));
  587.     if( z == nil || enclosing(z) != res )
  588.       Error(WARN, &fpos(y), "exported symbol %s not defined in %s",
  589.         string(y), SymName(res));
  590.     else if( has_body(res) && type(z) == RPAR )
  591.       Error(WARN, &fpos(y), "body parameter %s may not be exported",
  592.         string(y));
  593.     else if( visible(z) )
  594.       Error(WARN, &fpos(y), "symbol %s exported twice", string(y));
  595.     else visible(z) = TRUE;
  596.       }
  597.       DisposeObject(export_list);
  598.  
  599.       /* pop scope of res */
  600.       PopScope();
  601.     }
  602.  
  603.     /* pop import scopes and store imports in sym tab */
  604.     for( link=Down(import_list);  link != import_list;  link=NextDown(link) )
  605.       PopScope();
  606.     if( Down(import_list) == import_list )
  607.     { Dispose(import_list);
  608.       import_list = nil;
  609.     }
  610.     if( res != nil )  imports(res) = import_list;
  611.  
  612.     BodyParAllowed();
  613.     if( t == nil ) t = LexGetToken();
  614.  
  615.   } /* end while */
  616.  
  617.   *token = t;
  618.   return;
  619. } /* end ReadDefinitions */
  620.