/*@z05.c:Read Definitions:ReadLangDef()@**************************************/ /* */ /* THE LOUT DOCUMENT FORMATTING SYSTEM (VERSION 3.39) */ /* COPYRIGHT (C) 1991, 2008 Jeffrey H. Kingston */ /* */ /* Jeffrey H. Kingston (jeff@it.usyd.edu.au) */ /* School of Information Technologies */ /* The University of Sydney 2006 */ /* AUSTRALIA */ /* */ /* This program is free software; you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation; either Version 3, or (at your option) */ /* any later version. */ /* */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with this program; if not, write to the Free Software */ /* Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA */ /* */ /* FILE: z05.c */ /* MODULE: Read Definitions */ /* EXTERNS: ReadPrependDef(), ReadDatabaseDef(), ReadDefinitions() */ /* */ /*****************************************************************************/ #include "externs.h" /*****************************************************************************/ /* */ /* is_string(t, str) */ /* */ /* If t is a token denoting unquoted word str, return TRUE. */ /* */ /*****************************************************************************/ #define is_string(t, str) (type(t) == WORD && StringEqual(string(t), str) ) /*****************************************************************************/ /* */ /* static ReadLangDef(encl) */ /* */ /* Read one language definition and pass it on to the language module. The */ /* syntax is langdef ... { } */ /* */ /*****************************************************************************/ static void ReadLangDef(OBJECT encl) { OBJECT t, names, inside; New(names, ACAT); t = LexGetToken(); while( is_word(type(t)) ) { Link(names, t); t = LexGetToken(); } if( type(t) != LBR ) { Error(5, 4, "expected opening %s of langdef here", WARN, &fpos(t), KW_LBR); Dispose(t); return; } inside = Parse(&t, encl, FALSE, FALSE); inside = ReplaceWithTidy(inside, ACAT_TIDY); LanguageDefine(names, inside); return; } /* end ReadLangDef */ /*@::ReadPrependDef(), ReadDatabaseDef()@*************************************/ /* */ /* ReadPrependDef(typ, encl) */ /* */ /* Read @PrependGraphic { } and record its presence, unless it */ /* is there already; we allow multiple occurrences but only want to print */ /* the file once. */ /* */ /*****************************************************************************/ void ReadPrependDef(unsigned typ, OBJECT encl) { OBJECT t, fname; FILE_NUM fnum; t = LexGetToken(); if( type(t) != LBR ) { Error(5, 5, "left brace expected here in %s declaration", WARN, &fpos(t), KW_PREPEND); Dispose(t); return; } fname = Parse(&t, encl, FALSE, FALSE); fname = ReplaceWithTidy(fname, ACAT_TIDY); if( !is_word(type(fname)) ) { Error(5, 6, "name of %s file expected here", WARN, &fpos(fname),KW_PREPEND); DisposeObject(fname); return; } debug0(DFS, D, " calling DefineFile from ReadPrependDef"); fnum = FileNum(string(fname), STR_EMPTY); if( fnum == NO_FILE || FileType(fnum) != PREPEND_FILE ) DefineFile(string(fname), STR_EMPTY, &fpos(fname), PREPEND_FILE, typ == PREPEND ? INCLUDE_PATH : SYSINCLUDE_PATH); } /* end ReadPrependDef */ /*****************************************************************************/ /* */ /* ReadIncGRepeatedDef(typ, encl) */ /* */ /* Read @IncludeGraphicRepeated { } and record its presence. */ /* */ /*****************************************************************************/ void ReadIncGRepeatedDef(unsigned typ, OBJECT encl) { OBJECT t, fname; t = LexGetToken(); if( type(t) != LBR ) { Error(5, 5, "left brace expected here in %s declaration", WARN, &fpos(t), KW_INCG_REPEATED); Dispose(t); return; } fname = Parse(&t, encl, FALSE, FALSE); fname = ReplaceWithTidy(fname, ACAT_TIDY); if( !is_word(type(fname)) ) { Error(5, 6, "name of %s file expected here", WARN, &fpos(fname), KW_INCG_REPEATED); DisposeObject(fname); return; } debug0(DFS, D, " calling PS_IncGRepeated from ReadPrependDef"); incg_type(fname) = (typ == INCG_REPEATED ? INCGRAPHIC : SINCGRAPHIC); PS_IncGRepeated(fname); } /* end ReadPrependDef */ /*****************************************************************************/ /* */ /* ReadDatabaseDef(typ, encl) */ /* */ /* Read @Database ... { } and record it. */ /* */ /*****************************************************************************/ void ReadDatabaseDef(unsigned typ, OBJECT encl) { OBJECT symbs, t, fname; New(symbs, ACAT); t = LexGetToken(); while( type(t)==CLOSURE || (type(t)==WORD && string(t)[0]==CH_SYMSTART) ) { if( type(t) == CLOSURE ) { Link(symbs, t); } else { Error(5, 7, "unknown or misspelt symbol %s", WARN, &fpos(t), string(t)); Dispose(t); } t = LexGetToken(); } if( type(t) != LBR ) { Error(5, 8, "symbol name or %s expected here (%s declaration)", WARN, &fpos(t), KW_LBR, KW_DATABASE); Dispose(t); return; } if( Down(symbs) == symbs ) { Error(5, 9, "symbol names missing in %s declaration", WARN, &fpos(t), KW_DATABASE); } fname = Parse(&t, encl, FALSE, FALSE); fname = ReplaceWithTidy(fname, ACAT_TIDY); if( !is_word(type(fname)) ) { Error(5, 10, "name of %s file expected here", WARN, &fpos(fname), KW_DATABASE); DisposeObject(fname); return; } if( StringEndsWith(string(fname), DATA_SUFFIX) ) { Error(5, 47, "%s suffix should be omitted in %s clause", WARN, &fpos(fname), DATA_SUFFIX, KW_DATABASE); DisposeObject(fname); return; } if( Down(symbs) != symbs ) (void) DbLoad(fname, typ == DATABASE ? DATABASE_PATH : SYSDATABASE_PATH, TRUE, symbs, InMemoryDbIndexes); } /* end ReadDatabaseDef */ /*@::ReadTokenList()@*********************************************************/ /* */ /* static ReadTokenList(token, res) */ /* */ /* Read a list of tokens from input and append them to sym_body(res). */ /* The list is assumed to begin immediately after token, which is either */ /* an LBR or a @Begin, and input is to be read up to and including the */ /* matching RBR or @End @Sym. */ /* */ /*****************************************************************************/ #define NextToken(t, res) \ t = LexGetToken(); sym_body(res) = Append(sym_body(res), t, PARENT); static void ReadTokenList(OBJECT token, OBJECT res) { OBJECT t, xsym, new_par, imps, link, y; int scope_count, i; NextToken(t, res); for(;;) switch(type(t)) { case WORD: if( string(t)[0] == CH_SYMSTART ) Error(5, 11, "symbol %s unknown or misspelt", WARN, &fpos(t), string(t)); NextToken(t, res); break; case QWORD: NextToken(t, res); break; case VCAT: case HCAT: case ACAT: case CROSS: case FORCE_CROSS: case NULL_CLOS: case PAGE_LABEL: case BEGIN_HEADER: case END_HEADER: case SET_HEADER: case CLEAR_HEADER: case ONE_COL: case ONE_ROW: case WIDE: case HIGH: case HSHIFT: case VSHIFT: case HMIRROR: case VMIRROR: case HSCALE: case VSCALE: case HCOVER: case VCOVER: case SCALE: case KERN_SHRINK: case HCONTRACT: case VCONTRACT: case HLIMITED: case VLIMITED: case HEXPAND: case VEXPAND: case START_HVSPAN: case START_HSPAN: case START_VSPAN: case HSPAN: case VSPAN: case PADJUST: case HADJUST: case VADJUST: case ROTATE: case BACKGROUND: case RAW_VERBATIM: case VERBATIM: case CASE: case YIELD: case BACKEND: case XCHAR: case FONT: case SPACE: case YUNIT: case ZUNIT: case SET_CONTEXT: case GET_CONTEXT: case BREAK: case UNDERLINE: case UNDERLINE_COLOUR: case COLOUR: case TEXTURE: case OUTLINE: case LANGUAGE: case CURR_LANG: case CURR_FAMILY: case CURR_FACE: case CURR_YUNIT: case CURR_ZUNIT: case COMMON: case RUMP: case MELD: case INSERT: case ONE_OF: case NEXT: case PLUS: case MINUS: case TAGGED: case INCGRAPHIC: case SINCGRAPHIC: case PLAIN_GRAPHIC: case GRAPHIC: case LINK_SOURCE: case LINK_DEST: case LINK_DEST_NULL: case LINK_URL: case NOT_REVEALED: NextToken(t, res); break; case LUSE: case LVIS: case ENV: case USE: case DATABASE: case SYS_DATABASE: case PREPEND: case SYS_PREPEND: case INCG_REPEATED: case SINCG_REPEATED: case OPEN: Error(5, 12, "symbol %s not allowed in macro", WARN, &fpos(t), SymName(actual(t))); NextToken(t, res); break; case LBR: ReadTokenList(t, res); NextToken(t, res); break; case UNEXPECTED_EOF: Error(5, 13, "unexpected end of input", FATAL, &fpos(t)); break; case BEGIN: Error(5, 14, "%s not expected here", WARN, &fpos(t), SymName(actual(t))); NextToken(t, res); break; case RBR: if( type(token) != LBR ) Error(5, 15, "unmatched %s in macro", WARN, &fpos(t), KW_RBR); return; case END: if( type(token) != BEGIN ) Error(5, 16, "unmatched %s in macro", WARN, &fpos(t), KW_END); else { NextToken(t, res); if( type(t) != CLOSURE ) { if( type(t) == WORD && string(t)[0] == CH_SYMSTART ) Error(5, 17, "symbol %s unknown or misspelt", WARN, &fpos(t), string(t)); else Error(5, 18, "symbol name expected after %s", WARN,&fpos(t),KW_END); } else if( actual(token) != actual(t) ) Error(5, 19, "%s %s does not match %s %s", WARN, &fpos(t), SymName(actual(token)), KW_BEGIN, SymName(actual(t)), KW_END); } return; case CLOSURE: xsym = actual(t); PushScope(xsym, TRUE, FALSE); NextToken(t, res); PopScope(); if( type(t) == CROSS || type(t) == FORCE_CROSS ) { NextToken(t, res); break; } /* read named parameters */ while( type(t) == CLOSURE && enclosing(actual(t)) == xsym && type(actual(t)) == NPAR ) { new_par = t; NextToken(t, res); if( type(t) != LBR ) { if( type(t) == RBR ) { if( type(token) != LBR ) Error(5, 20, "unmatched %s in macro", WARN, &fpos(t), KW_RBR); return; } Error(5, 21, "%s must follow named parameter %s", WARN, &fpos(new_par), KW_LBR, SymName(actual(new_par))); break; } /* add import list of the named parameter to current scope */ scope_count = 0; imps = imports(actual(new_par)); if( imps != nilobj ) { for( link = Down(imps); link != imps; link = NextDown(link) ) { Child(y, link); PushScope(actual(y), FALSE, TRUE); scope_count++; } } /* read the body of the named parameter */ PushScope(actual(new_par), FALSE, FALSE); ReadTokenList(t, res); PopScope(); /* pop the scopes pushed for the import list */ for( i = 0; i < scope_count; i++ ) PopScope(); /* get next token, possibly another named parameter */ PushScope(xsym, TRUE, FALSE); NextToken(t, res); PopScope(); } /* read body parameter, if any */ if( has_body(xsym) ) { if( type(t) == LBR || type(t) == BEGIN ) { PushScope(xsym, FALSE, TRUE); PushScope(ChildSym(xsym, RPAR), FALSE, FALSE); if( type(t) == BEGIN ) actual(t) = xsym; ReadTokenList(t, res); PopScope(); PopScope(); NextToken(t, res); } else if( type(t) != RBR && type(t) != END ) Error(5, 22, "right parameter of %s must begin with %s", WARN, &fpos(t), SymName(xsym), KW_LBR); } break; default: Error(5, 23, "ReadTokenList: %s", INTERN, &fpos(t), Image(type(t))); break; } } /* end ReadTokenList */ /*@::ReadMacro()@*************************************************************/ /* */ /* static OBJECT ReadMacro(token, encl) */ /* */ /* Read a macro from input and insert into symbol table. */ /* Token *token contains the "macro" keyword. Input is read up to and */ /* including the closing right brace, and nilobj returned in *token if OK. */ /* The proper scope for reading the macro body is open at entry and exit. */ /* ReadMacro returns the new symbol table entry if successful, else nilobj. */ /* */ /*****************************************************************************/ static OBJECT ReadMacro(OBJECT *token, OBJECT curr_encl, OBJECT encl) { OBJECT t, res; /* find macro name and insert into symbol table */ SuppressScope(); Dispose(*token); t = LexGetToken(); if( !is_word(type(t)) ) { Error(5, 24, "%s ignored (name is missing)", WARN, &fpos(t), KW_MACRO); debug1(ANY, D, "offending type is %s", Image(type(t))); UnSuppressScope(); *token = t; return nilobj; } res = InsertSym(string(t), MACRO, &fpos(t), 0, FALSE,TRUE,0,curr_encl,nilobj); if( curr_encl != encl ) visible(res) = TRUE; UnSuppressScope(); /* find alternative names for this symbol */ Dispose(t); t = LexGetToken(); while( is_word(type(t)) ) { InsertAlternativeName(string(t), res, &fpos(t)); Dispose(t); t = LexGetToken(); } /* find opening left brace */ if( type(t) != LBR ) { Error(5, 25, "%s ignored (opening %s is missing)", WARN, &fpos(t), KW_MACRO, KW_LBR); *token = t; return nilobj; } /* read macro body */ ReadTokenList(t, res); Dispose(t); /* clean up (kill final RBR, dispose macro name) and exit */ t = pred(sym_body(res), PARENT); sym_body(res) = Delete(t, PARENT); Dispose(t); recursive(res) = FALSE; *token = nilobj; return res; } /* end ReadMacro */ /*@::ReadDefinitions()@*******************************************************/ /* */ /* ReadDefinitions(token, encl, res_type) */ /* */ /* Read a sequence of definitions and insert them into the symbol table. */ /* Either a sequence of local definitions (res_type == LOCAL) or named */ /* parameters (res_type == NPAR) is expected; *token is the first def etc. */ /* A scope appropriate for reading the bodies of the definitions is open. */ /* The parent definition is encl. */ /* */ /*****************************************************************************/ void ReadDefinitions(OBJECT *token, OBJECT encl, unsigned char res_type) { OBJECT t, res, res_target, export_list, import_list, link, y, z; OBJECT curr_encl; BOOLEAN compulsory_par, has_import_encl; t = *token; while( res_type==LOCAL || is_string(t, KW_NAMED) || is_string(t, KW_IMPORT) ) { curr_encl = encl; if( is_string(t, KW_LANGDEF) ) { ReadLangDef(encl); t = LexGetToken(); continue; /* next definition */ } else if( type(t) == PREPEND || type(t) == SYS_PREPEND ) { ReadPrependDef(type(t), encl); Dispose(t); t = LexGetToken(); continue; /* next definition */ } else if( type(t) == INCG_REPEATED || type(t) == SINCG_REPEATED ) { ReadIncGRepeatedDef(type(t), encl); Dispose(t); t = LexGetToken(); continue; /* next definition */ } else if( type(t) == DATABASE || type(t) == SYS_DATABASE ) { ReadDatabaseDef(type(t), encl); Dispose(t); t = LexGetToken(); continue; /* next definition */ } if( !is_string(t, KW_DEF) && !is_string(t, KW_MACRO) && !is_string(t, KW_NAMED) && !is_string(t, KW_IMPORT) && !is_string(t, KW_EXTEND) && !is_string(t, KW_EXPORT) ) break; /* get import or extend list and change scope appropriately */ BodyParNotAllowed(); New(import_list, ACAT); has_import_encl = FALSE; if( is_string(t, KW_IMPORT) ) { Dispose(t); t = LexGetToken(); while( type(t) == CLOSURE || (type(t)==WORD && !is_string(t,KW_EXPORT) && !is_string(t,KW_DEF) && !is_string(t, KW_MACRO) && !is_string(t, KW_NAMED)) ) { if( type(t) == CLOSURE ) { if( type(actual(t)) == LOCAL ) { /* *** letting this through now if( res_type == NPAR && has_par(actual(t)) ) { Error(5, 46, "named parameter import %s has parameters", WARN, &fpos(t), SymName(actual(t))); } else { *** */ PushScope(actual(t), FALSE, TRUE); if( actual(t) == encl ) has_import_encl = TRUE; Link(import_list, t); /* *** } *** */ } else { Error(5, 26, "import name expected here", WARN, &fpos(t)); Dispose(t); } } else { Error(5, 27, "import %s not in scope", WARN, &fpos(t), string(t)); Dispose(t); } t = LexGetToken(); } } else if( is_string(t, KW_EXTEND) ) { Dispose(t); t = LexGetToken(); while( type(t) == CLOSURE || (type(t)==WORD && !is_string(t,KW_EXPORT) && !is_string(t,KW_DEF) && !is_string(t, KW_MACRO)) ) { if( type(t) == CLOSURE ) { if( imports(actual(t)) != nilobj ) { Error(5, 48, "%s has %s clause, so cannot be extended", WARN, &fpos(t), SymName(actual(t)), KW_IMPORT); } else if( type(actual(t)) == LOCAL ) { PushScope(actual(t), FALSE, FALSE); curr_encl = actual(t); debug1(DRD, D, " curr_encl = %s", SymName(curr_encl)); Link(import_list, t); } else { Error(5, 28, "%s symbol name expected here", WARN, &fpos(t), KW_EXTEND); Dispose(t); } } else { Error(5, 29, "extend symbol %s not in scope", WARN,&fpos(t),string(t)); Dispose(t); } t = LexGetToken(); } } /* get export list and store for setting visible flags below */ New(export_list, ACAT); if( is_string(t, KW_EXPORT) ) { Dispose(t); SuppressScope(); t = LexGetToken(); while( is_word(type(t)) && !is_string(t, KW_DEF) && !is_string(t, KW_IMPORT) && !is_string(t, KW_MACRO) && !is_string(t, KW_EXTEND) ) { Link(export_list, t); t = LexGetToken(); } UnSuppressScope(); } if( res_type == LOCAL && !is_string(t, KW_DEF) && !is_string(t, KW_MACRO) ) { Error(5, 30, "keyword %s or %s expected here", WARN, &fpos(t), KW_DEF, KW_MACRO); break; } if( res_type == NPAR && !is_string(t, KW_NAMED) ) { Error(5, 31, "keyword %s expected here", WARN, &fpos(t), KW_NAMED); break; } if( is_string(t, KW_MACRO) ) { if( Down(export_list) != export_list ) Error(5, 32, "ignoring export list of macro", WARN, &fpos(t)); res = ReadMacro(&t, curr_encl, encl); } else { SuppressScope(); Dispose(t); t = LexGetToken(); /* check for compulsory keyword */ if( res_type == NPAR && is_string(t, KW_COMPULSORY) ) { compulsory_par = TRUE; Dispose(t); t = LexGetToken(); } else compulsory_par = FALSE; /* find name of symbol and insert it */ if( !is_word(type(t)) ) { Error(5, 33, "symbol name expected here", WARN, &fpos(t)); debug1(ANY, D, "offending type is %s", Image(type(t))); UnSuppressScope(); *token = t; return; } res = InsertSym(string(t), res_type, &fpos(t), DEFAULT_PREC, FALSE, FALSE, 0, curr_encl, nilobj); if( curr_encl != encl ) visible(res) = TRUE; if( has_import_encl ) { imports_encl(res) = TRUE; debug1(DCE, D, " setting import_encl(%s) to TRUE", SymName(res)); } if( compulsory_par ) { has_compulsory(encl)++; is_compulsory(res) = TRUE; } Dispose(t); t = LexGetToken(); /* find alternative names for this symbol */ while( is_word(type(t)) && !is_string(t, KW_NAMED) && !is_string(t, KW_IMPORT) && !is_string(t, KW_FORCE) && !is_string(t, KW_INTO) && !is_string(t, KW_HORIZ) && !is_string(t, KW_PRECEDENCE) && !is_string(t, KW_ASSOC) && !is_string(t, KW_LEFT) && !is_string(t, KW_RIGHT) && !is_string(t, KW_BODY) && !is_string(t, KW_LBR) && !is_string(t, KW_BEGIN) ) { InsertAlternativeName(string(t), res, &fpos(t)); Dispose(t); t = LexGetToken(); } /* find force, if any */ if( is_string(t, KW_FORCE) ) { force_target(res) = TRUE; Dispose(t); t = LexGetToken(); if( !is_string(t, KW_INTO) && !is_string(t, KW_HORIZ) ) Error(5, 34, "%s expected here", WARN, &fpos(t), KW_INTO); } /* find horizontally, if any */ if( is_string(t, KW_HORIZ) ) { horiz_galley(res) = COLM; Dispose(t); t = LexGetToken(); /* *** want to allow KW_HORIZ with @Target form now if( !is_string(t, KW_INTO) ) Error(5, 35, "%s expected here", WARN, &fpos(t), KW_INTO); *** */ } /* find into clause, if any */ res_target = nilobj; if( is_string(t, KW_INTO) ) { UnSuppressScope(); Dispose(t); t = LexGetToken(); if( type(t) != LBR ) { Error(5, 36, "%s expected here", WARN, &fpos(t), KW_LBR); debug1(ANY, D, "offending type is %s", Image(type(t))); UnSuppressScope(); *token = t; return; } res_target = Parse(&t, curr_encl, FALSE, FALSE); SuppressScope(); if( t == nilobj ) t = LexGetToken(); } /* find precedence clause, if any */ if( is_string(t, KW_PRECEDENCE) ) { int prec = 0; UnSuppressScope(); Dispose(t); t = LexGetToken(); while( type(t) == WORD && decimaldigit(string(t)[0]) ) { prec = prec * 10 + digitchartonum(string(t)[0]); Dispose(t); t = LexGetToken(); } SuppressScope(); if( prec < MIN_PREC ) { Error(5, 37, "precedence is too low (%d substituted)", WARN, &fpos(t), MIN_PREC); prec = MIN_PREC; } else if( prec > MAX_PREC ) { Error(5, 38, "precedence is too high (%d substituted)", WARN, &fpos(t), MAX_PREC); prec = MAX_PREC; } precedence(res) = prec; } /* find associativity clause, if any */ if( is_string(t, KW_ASSOC) ) { UnSuppressScope(); Dispose(t); t = LexGetToken(); if( is_string(t, KW_LEFT) ) right_assoc(res) = FALSE; else if( !is_string(t, KW_RIGHT) ) Error(5, 39, "associativity altered to %s", WARN, &fpos(t), KW_RIGHT); SuppressScope(); Dispose(t); t = LexGetToken(); } /* find left parameter, if any */ if( is_string(t, KW_LEFT) ) { Dispose(t); t = LexGetToken(); if( type(t) != WORD ) { Error(5, 40, "cannot find %s parameter name", WARN, &fpos(t), KW_LEFT); debug1(ANY, D, "offending type is %s", Image(type(t))); UnSuppressScope(); *token = t; return; } InsertSym(string(t), LPAR, &fpos(t), DEFAULT_PREC, FALSE, FALSE, 0, res, nilobj); Dispose(t); t = LexGetToken(); } /* find named parameters, if any */ UnSuppressScope(); ReadDefinitions(&t, res, NPAR); /* find right or body parameter, if any */ if( is_string(t, KW_RIGHT) || is_string(t, KW_BODY) ) { has_body(res) = is_string(t, KW_BODY); SuppressScope(); Dispose(t); t = LexGetToken(); if( type(t) != WORD ) { Error(5, 41, "cannot find %s parameter name", WARN,&fpos(t),KW_RIGHT); debug1(ANY, D, "offending type is %s", Image(type(t))); UnSuppressScope(); *token = t; return; } InsertSym(string(t), RPAR, &fpos(t), DEFAULT_PREC, FALSE, FALSE, 0, res, nilobj); UnSuppressScope(); Dispose(t); t = LexGetToken(); } /* read local definitions and body */ if( res_target != nilobj ) InsertSym(KW_TARGET, LOCAL, &fpos(res_target), DEFAULT_PREC, FALSE, FALSE, 0, res, res_target); if( type(t) == WORD && StringEqual(string(t), KW_LBR) ) { z = NewToken(LBR, &fpos(t), 0, 0, LBR_PREC, StartSym); Dispose(t); t = z; } else if( type(t) == WORD && StringEqual(string(t), KW_BEGIN) ) { z = NewToken(BEGIN, &fpos(t), 0, 0, BEGIN_PREC, StartSym); Dispose(t); t = z; } else if( type(t) != LBR && type(t) != BEGIN ) Error(5, 42, "opening left brace or @Begin of %s expected", FATAL, &fpos(t), SymName(res)); if( type(t) == BEGIN ) actual(t) = res; PushScope(res, FALSE, FALSE); BodyParAllowed(); sym_body(res) = Parse(&t, res, TRUE, FALSE); /* set visible flag of the exported symbols */ for( link=Down(export_list); link != export_list; link=NextDown(link) ) { Child(y, link); z = SearchSym(string(y), StringLength(string(y))); if( z == nilobj || enclosing(z) != res ) Error(5, 43, "exported symbol %s is not defined in %s", WARN, &fpos(y), string(y), SymName(res)); else if( has_body(res) && type(z) == RPAR ) Error(5, 44, "body parameter %s may not be exported", WARN, &fpos(y), string(y)); else if( visible(z) ) Error(5, 45, "symbol %s exported twice", WARN, &fpos(y), string(y)); else visible(z) = TRUE; } DisposeObject(export_list); /* pop scope of res */ PopScope(); } /* pop import scopes and store imports in sym tab */ for( link=Down(import_list); link != import_list; link=NextDown(link) ) { PopScope(); } if( Down(import_list) == import_list || curr_encl != encl ) { DisposeObject(import_list); import_list = nilobj; } else { imports(res) = import_list; } BodyParAllowed(); if( t == nilobj ) t = LexGetToken(); } /* end while */ *token = t; return; } /* end ReadDefinitions */