(****************************************
*                                       *
*     MODULA-2 Multi-Pass Compiler      *
*     ****************************      *
*                                       *
*     Implementation to M-Code          *
*                                       *
*                                       *
*     M2Pass2:                          *
*                                       * 
*     Pass 2                            *
*     Declaration analysis              *
*                                       * 
*     Version C18 of 25.09.81           *
*                                       *
*     Institut fuer Informatik          *
*     ETH-Zuerich                       *
*     CH-8092 Zuerich                   *
*                                       *
****************************************)

IMPLEMENTATION MODULE M2Pass2; (* LG / UA *)

  (* $T- *)
  FROM Storage IMPORT ALLOCATE, DEALLOCATE;
  FROM MCBase IMPORT
    Idptr, Stptr, Structform, Stset, Idclass, Idset,
    Varkind, Kindvar,
    Constval, Keyarr,
    root, mainmodp, globvarnext, sysmodp, intcarptr,
    procnumber, modnamlength, maxprio, noprio,
    Symbol;
  FROM MCP2IO IMPORT
    sy,
    val,
    PutSy, PutWord, StopOutput, RestartOutput,
    Error, ErrorLS,
    spix,
    GetSy, PutGetSy,
    SkipConstant, SkipType,
    GetModuleKey, DefModStatus, InitInOut, TermInOut;
  FROM P1IOId IMPORT 
    IdSetPos, IdGetChar;
  FROM MCP2Reference IMPORT
    Reference, EndReference, InitRef, TermRef;
  FROM MCP2Ident IMPORT
    Locate,
    NewImpList, TermImpList, EnterImpList,
    MarkScope, ReleaseScope,
    MsEntry,
    EnterList, EnterId,
    SearchInBlock, SearchId,
    ExportSearch, SymModSearch, GlobalKnown;

  FROM M2Pass2PV IMPORT
    scalars, oneword, doubleword, procmarkspace, charmax,
    nestlevel, symmod, defmod, impl, oldlist, proccount,
    FAmong, QualIdent, InitId;

  FROM P2Init IMPORT
      MarkInitBlock, ReleaseInitBlock, EnterInitModule,
      ToInitModule, InitModules, MustInit, Initrange,
      ResetModuleInit;
  FROM P2Const IMPORT ConstantVal, ConstantRange;
  FROM P2Type IMPORT ActualTyp, ArrayStruct, ParamList;
PROCEDURE Pass2;

  (* MODULE ModulInitialisation; - now in P2Init *)

  (* MODULE ConstDefinition; - now in P2Const *)

  (* MODULE TypeDefinition; - now in P2Type *)

  PROCEDURE Module(mp: Idptr; priority: CARDINAL;
                   VAR alladdr: CARDINAL; VAR varp: Idptr);
    VAR initindex : Initrange;
        priotp : Stptr;
        prioval : Constval;

    PROCEDURE ExportList; 
      VAR rf,x: Idptr;
          qualif : BOOLEAN;
    BEGIN 
      rf := mp^.expp;
      IF (sy = qualifiedsy) OR (sy = exportsy) THEN 
        qualif := (sy = qualifiedsy);
        GetSy;
        WHILE sy = ident DO 
          IF symmod THEN Locate(rf,x)
          ELSE x := NIL
          END;
          IF x = NIL THEN
            NEW(x,unknown); 
            InitId(x,unknown);
            EnterList(rf,x);
            IF NOT qualif THEN
              (* check whether this identifier is *)
              (* already known in the environment *)
              SearchInBlock(x); (* new value for x *)
              IF (x <> NIL) AND (x^.klass <> unknown) THEN Error(75) END
            END
          END;
          GetSy
        END;
        				(*  Only set qualexp when the
                                            exports list is 
                                            specifically mentioned.	  *)
        mp^.qualexp := qualif
      END;
      mp^.expp := rf; 
      (* generate inverse link for unknown elements in export-list *) 
      x := mp;
      WHILE rf <> NIL DO
        IF rf^.klass = unknown THEN rf^.nxtidp := x END;
        x := rf;
        rf := x^.link;
      END;
    END ExportList; 
  
    PROCEDURE TestExport; 
      VAR ip : Idptr; 
    BEGIN 
      ip := mp^.expp; 
      WHILE ip <> NIL DO
        IF ip^.klass = unknown THEN ErrorLS(101) END; 
        ip := ip^.link
      END 
    END TestExport; 

    PROCEDURE EnterExport(ip: Idptr); 
      VAR lip : Idptr;
    BEGIN (* enter exportlist of module in mslist of environment *) 
      IF NOT ip^.qualexp THEN
        ip := ip^.expp;
        MsEntry(ip);
        WHILE ip <> NIL DO 
          lip := ip;
          IF lip^.klass = indrct THEN lip := lip^.nxtidp END;
          WITH lip^ DO
            IF klass = mods THEN EnterExport(lip);
            ELSIF (klass = types) AND (idtyp <> NIL) THEN 
              WITH idtyp^ DO
                IF form = enums THEN MsEntry(fcstp) END;
              END;
            END;
          END;
          ip := ip^.link;
        END;
      END;
    END EnterExport; 

    PROCEDURE ImportList;
      (* analyse import list of a module *)
      VAR ip,ep : Idptr;  
          frommod : BOOLEAN; 
    BEGIN 
      NewImpList(mp^.impp); 
      WHILE (sy = importsy) OR (sy = fromsy) DO
        frommod := sy = fromsy; 
        IF frommod THEN 
          GetSy; 
          SearchId(ip); 
          IF (ip = NIL) OR (ip^.klass <> mods) THEN (* skip this list *) 
            PutSy(fromsy); 
            WHILE sy = ident DO PutGetSy END; 
          ELSE 
            ep := ip^.expp;
            GetSy; 
          END; 
        ELSE PutGetSy; (* importsy *)
        END; 
        WHILE sy = ident DO (* identifier skipped if module not found *) 
          IF frommod THEN ExportSearch(ep,ip) ELSE SearchId(ip) END; 
          IF ip = NIL THEN 
            IF frommod THEN Error(71); GetSy ELSE PutGetSy END;  
          ELSE 
            EnterImpList(ip); 
            GetSy; 
          END; 
        END; (* while *)  
      END; (* while *) 
      TermImpList(mp^.impp); 
    END ImportList; 

    PROCEDURE Block(VAR alladdr: CARDINAL; VAR varp: Idptr;
                    moduleblock: BOOLEAN);

      PROCEDURE DeleteOld(VAR ip: Idptr);
        (* delete old entry of implemented identifier *)
        VAR lip: Idptr; 
            pp1,pp2 : Idptr; 
      BEGIN (* assume ip <> NIL *)
        IF ip = oldlist THEN oldlist := ip^.link;   
        ELSE  
          lip := oldlist; 
          WHILE lip^.link <> ip DO lip := lip^.link END;
          lip^.link := ip^.link; 
        END; 
        IF oldlist = NIL THEN impl := FALSE END;
        CASE ip^.klass OF 
          types: DISPOSE(ip,types); 
         |pures,funcs: (* delete also parameter and structure entry *) 
            WITH ip^ DO 
              pp1 := idtyp^.fstparam; 
              WHILE pp1 <> NIL DO  
                pp2 := pp1; 
                pp1 := pp2^.vlink;
                DISPOSE(pp2,vars); 
              END;
              IF klass = pures THEN DISPOSE(idtyp,proctypes,pures) 
              ELSE DISPOSE(idtyp,proctypes,funcs) 
              END; 
            END; 
            DISPOSE(ip,pures,FALSE,pures); 
        END; (* case *)   
      END DeleteOld;

      PROCEDURE ConstDeclaration; 
        VAR lip: Idptr;
      BEGIN 
        WHILE sy = ident DO 
          IF symmod THEN SymModSearch(lip) ELSE lip := NIL END;
          IF lip = NIL THEN
            NEW(lip,consts);
            InitId(lip,consts);
            EnterId(lip); 
            GetSy;
            WITH lip^ DO ConstantVal(idtyp,cvalue) END;
          ELSE GetSy; SkipConstant;
          END;
        END;
      END ConstDeclaration; 

      PROCEDURE TypDeclaration; 
        VAR lip: Idptr;
            trf: Stptr; 
            oldp : Idptr;
      BEGIN 
        WHILE sy = ident DO 
          IF symmod THEN SymModSearch(lip) ELSE lip := NIL END;
          IF lip = NIL THEN
            oldp := NIL;
            IF impl AND (nestlevel = 0) AND GlobalKnown(spix) THEN
              (* implementation possible *)
              Locate(oldlist,oldp);
            END;
            NEW(lip,types); 
            InitId(lip,types);
            EnterId(lip); 
            GetSy; ActualTyp(trf);
            IF (trf <> NIL) AND (trf^.stidp = NIL) THEN
              trf^.stidp := lip;
            END;
            lip^.idtyp := trf; 
            IF (oldp <> NIL) AND (oldp^.klass = types) THEN
              (* implementation of hidden type *)
              WITH oldp^.idtyp^ DO (* replace hidden structure *)
                form := opens;
                openstruc := trf;
              END;
              IF NOT FAmong(trf,Stset{ints,cards,words,pointers,
                                      sets,hides}) THEN
                ErrorLS(82)
              END;
              DeleteOld(oldp);
            END;
            Reference(lip);
          ELSE GetSy; SkipType;
          END;
        END;
      END TypDeclaration; 

      PROCEDURE VarDeclaration(VAR vhead: Idptr);
        VAR v, vn, vt : Idptr;
            trf : Stptr;
            space : CARDINAL; (* space for allocation *)
            decl : BOOLEAN; (* identifier is new declared *)
            indac : BOOLEAN; (* indirect access to variable *)
            absval : Constval;
      BEGIN      
        IF vhead = NIL THEN vt := NIL
        ELSE (* search last entry *)
          vn := vhead;
          WHILE vn <> NIL DO vt := vn; vn := vn^.vlink END;
        END;
        WHILE sy = ident DO
          vn := vt; (* mark for new declared list of variables *)
          WHILE sy <> colon DO
            IF symmod THEN SymModSearch(v) ELSE v := NIL END;
            IF v = NIL THEN
              decl := TRUE;
              NEW(v,vars);
              InitId(v,vars);
              WITH v^ DO
                indaccess := FALSE;
                vkind := noparam;
                vaddr := 177777B; vlevel := nestlevel;
                IF vlevel = 0 THEN state := global;
                ELSE state := local;
                END;
                vlink := NIL;
              END;
              IF vhead = NIL THEN vhead := v ELSE vt^.vlink := v END;
              vt := v;
              EnterId(v);
            ELSE decl := FALSE
            END;
            GetSy;
            IF symmod THEN
              IF sy = lbrack THEN
                GetSy; (* lbrack *)
                IF decl THEN
                  WITH v^ DO
                    vaddr := val; state := absolute; vlevel := 0;
                  END;
                END;
                GetSy; (* cardcon *)
                GetSy; (* rbrack *)
              ELSE
                IF decl THEN
                  WITH v^ DO
                    vaddr := val; state := separate; vlevel := 0;
                  END;
                END;
                GetSy; (* cardcon *)
              END;
            ELSIF sy = lbrack THEN
              GetSy; (* lbrack *)
              ConstantVal(trf,absval);
              IF decl THEN
                WITH v^ DO
                  IF FAmong(trf,Stset{cards}) THEN
                    vaddr := absval.value;
                  ELSE ErrorLS(78); vaddr := 0;
                  END;
                  state := absolute;
                  vlevel := 0;
                END;
              END;
              GetSy; (* rbrack *)
            END;
          END; (* WHILE *)
          GetSy; (* colon *)
          IF decl THEN
            ActualTyp(trf);
            space := oneword; indac := FALSE;
            IF trf <> NIL THEN
              IF FAmong(trf,Stset{arrays,records}) THEN indac := TRUE
              ELSE space := trf^.size; (* especially for reals *)
              END;
            END;
            (* allocation and type entry *)
            IF vn = NIL THEN vn := vhead ELSE vn := vn^.vlink END;
            WHILE vn <> NIL DO
              WITH vn^ DO
                idtyp := trf;
                IF (state = local) OR (state = global) THEN
                  vaddr := alladdr; INC(alladdr,space)
                END;
                IF state <> absolute THEN indaccess := indac END;
                Reference(vn);
                vn := vlink;
              END;
            END; 
          ELSE SkipType;
          END;
        END;
      END VarDeclaration;

      PROCEDURE ProcFuncDecl;
        VAR localaddr : CARDINAL;
            localvar : Idptr; (* list of local variables *)
            xb,oldp : Idptr;
            PS : CARDINAL;
	    wp : Idptr;

        PROCEDURE CompProc(oproc,nproc: Stptr);
          (* compare old procedure from definition module with *)
          (* new declared procedure in implementation module   *)
          VAR op,np : Idptr; (* parameters *) 
              os,ns : Stptr; (* structures *) 
              comp : BOOLEAN; 
   
          PROCEDURE Equivalent(os,ns: Stptr): BOOLEAN;  
          BEGIN 
            RETURN
              (os = ns) OR
              (os<>NIL) AND (os^.form=opens) AND (os^.openstruc=ns);
          END Equivalent; 
  
          PROCEDURE DynArr(sp: Stptr): BOOLEAN; 
          BEGIN 
            RETURN (sp <> NIL) AND (sp^.form = arrays) AND sp^.dyn;
          END DynArr; 

        BEGIN (* CompProc *)
          comp := oproc^.rkind = nproc^.rkind;
          op := oproc^.fstparam; np := nproc^.fstparam;
          WHILE comp AND (op <> np) DO
            IF (op=NIL) OR (np=NIL) OR (op^.vkind<>np^.vkind) THEN
              comp := FALSE 
            ELSE 
              os := op^.idtyp; ns := np^.idtyp; 
              comp := Equivalent(os,ns) OR
                      DynArr(os) AND DynArr(ns) AND
                      Equivalent(os^.elp,ns^.elp); 
              op := op^.vlink; 
              np := np^.vlink; 
            END; 
          END; 
          IF comp AND (oproc^.rkind = funcs) THEN 
            comp := Equivalent(oproc^.funcp,nproc^.funcp) 
          END; 
          IF NOT comp THEN ErrorLS(83) END;
        END CompProc; 

      BEGIN (* ProcFuncDecl *)
        IF symmod THEN SymModSearch(xb) ELSE xb := NIL END;
        IF xb = NIL THEN
          oldp := NIL;
          IF impl AND (nestlevel = 0) AND GlobalKnown(spix) THEN
            (* implementation possible *)
            Locate(oldlist,oldp);
          END;
          localaddr := 0; localvar := NIL;
          NEW(xb,pures,FALSE,pures); (* = NEW(xb,funcs,FALSE,funcs) *)
          InitId(xb,pures);
          EnterId(xb); GetSy;
          INC(nestlevel);
          WITH xb^ DO
            locp := NIL;
            msp := NIL;
            plev := nestlevel;
            isstandard := FALSE; (* initialisation *)
            IF symmod THEN procnum := val; GetSy; GetSy; (* symbolic *)
            ELSIF oldp <> NIL THEN procnum := oldp^.procnum; (* impl *)
            ELSE procnum := proccount; INC(proccount);
            END;
            priolev := priority;
            externalaccess := (oldp <> NIL) AND oldp^.externalaccess;
            codeproc := FALSE; (* initialisation *)
          END;
          Reference(xb);
          MarkScope(xb);
          ParamList(NOT symmod,localaddr,xb^.idtyp);
IF NOT symmod THEN
wp := xb^.idtyp^.fstparam;
PS := localaddr - 4;
WHILE wp # NIL DO
    WITH wp^ DO
	IF klass = vars THEN
	    IF state = local THEN
		ParmSpace := PS
	    END;
	END;
	wp := vlink
    END
END;
END;
          WITH xb^ DO
            idtyp^.stidp := xb; (* enter identifier reference *)
            klass := idtyp^.rkind;
          END;
          IF (oldp <> NIL) AND (oldp^.klass IN Idset{pures,funcs}) THEN
            (* implementation of procedure from definition module *)
            CompProc(oldp^.idtyp,xb^.idtyp);
            DeleteOld(oldp);
          END;
          IF NOT (symmod OR defmod) THEN (* block expected *)
            PutSy(proceduresy); PutWord(xb);
            Block(localaddr,localvar,FALSE); 
wp := localvar;
WHILE wp # NIL DO
    WITH wp^ DO
	IF klass = vars THEN
	    IF state = local THEN
		ParmSpace := PS
	    END;
	END;
	wp := vlink
    END;
END;
          END;
          ReleaseScope(xb);
          WITH xb^ DO
            varlength := localaddr;
            locvarp := localvar;
          END;
          EndReference(xb);
          DEC(nestlevel);
        ELSE
          GetSy; (* ident *)
          GetSy; (* cardcon = Procedure number *)
          SkipType;
        END;
      END ProcFuncDecl;

    BEGIN (* Block *) 
      MarkInitBlock;
      IF sy = codesy THEN
        (* skip code sequence *)
        IF moduleblock THEN
          Error(112);
          WHILE sy <> endblock DO GetSy END;
        ELSE
          WHILE sy <> endblock DO PutGetSy END;
        END;
      ELSE
        REPEAT
          IF sy = varsy THEN GetSy; VarDeclaration(varp); 
          ELSIF sy = proceduresy THEN GetSy; ProcFuncDecl;
          ELSIF sy = modulesy THEN
            GetSy; ModuleDeclaration(priority,alladdr,varp);
          ELSIF sy = typesy THEN GetSy; TypDeclaration; 
          ELSIF sy = constsy THEN GetSy; ConstDeclaration; 
          END 
        UNTIL (sy = beginsy) OR (sy = endblock) OR (sy = codesy);
        IF sy = codesy THEN
          (* error message in pass1 *)
          (* skip code sequence *)
          WHILE sy <> endblock DO GetSy END;
        ELSIF (sy = beginsy) OR MustInit() THEN
          IF moduleblock THEN
            ToInitModule(initindex);
          END; 
          IF sy = beginsy THEN PutGetSy ELSE PutSy(beginsy) END;
          InitModules;
          (* skip statements *)
          WHILE sy <> endblock DO PutGetSy END; 
          IF moduleblock THEN PutSy(endblock) END;
        END;
      END;
      PutGetSy; (* endblock *)
      ReleaseInitBlock;
    END Block;

  BEGIN (* Module *)   
    PutSy(modulesy); PutWord(mp); 
    IF sy = lbrack THEN (* priority specified *)   
      GetSy; (* lbrack *)
      ConstantVal(priotp,prioval);
      IF (priotp = intcarptr) AND (prioval.value <= maxprio) AND
         ((priority = noprio) OR (priority <= prioval.value))
      THEN
        priority := prioval.value;
      ELSE
        ErrorLS(80);
      END;
      GetSy; (* rbrack *)
    END;
    EnterInitModule(mp,initindex);
    mp^.priolev := priority;
    ImportList;   
    ExportList; 
    MarkScope(mp);
    Block(alladdr,varp,TRUE); 
    TestExport; 
    ReleaseScope(mp);
    EnterExport(mp); 
  END Module; 

  PROCEDURE EnterMods(VAR ip: Idptr);
    (* initialisation and entry of a module *)
  BEGIN
    InitId(ip,mods);
    WITH ip^ DO
      isstandard := FALSE;
      procnum := proccount; INC(proccount);
      plev := nestlevel + 1;
      varlength := procmarkspace; (* for module initialisation *)
      priolev := noprio;
      externalaccess := FALSE;
      locp := NIL; msp := NIL; impp := NIL; expp := NIL;
      qualexp := FALSE; globalmodule := FALSE;
    END; 
    EnterId(ip);
  END EnterMods;
 
  PROCEDURE ModuleDeclaration(oldprio : CARDINAL;
                              VAR alladdr: CARDINAL; VAR varp: Idptr);
    (* declaration of local modules *)
    VAR ip : Idptr;
  BEGIN  
    NEW(ip,mods,FALSE,mods,FALSE);
    EnterMods(ip);
    GetSy; (* identifier *)
    Reference(ip);
    Module(ip,oldprio,alladdr,varp);
    EndReference(ip);
  END ModuleDeclaration;

  PROCEDURE StartDecl; 

    VAR globaladdr : CARDINAL;
        ip : Idptr;
        modcount : CARDINAL;
        modkey : Keyarr;
        ix : CARDINAL;

    PROCEDURE InitImplementation(VAR listp: Idptr; exp: BOOLEAN);
      (* initialisation of an implementation module *)   
      VAR ip1, ip2 : Idptr;
          ndp : Idptr; (* identifier to be new declared *)
          newdecl : BOOLEAN; 

    BEGIN   
      ip1 := listp; ip2 := NIL; 
      WHILE ip1 <> NIL DO 
        newdecl := FALSE; 
        WITH ip1^ DO 
          CASE klass OF 
            types: (* hidden declared types must be implemented *)
              newdecl := (idtyp^.form = hides) AND (idtyp^.stidp = ip1);
              Reference(ip1);
           |vars: (* search for maximal used allocation address *)  
              Reference(ip1);
              IF state <> absolute THEN
                state := global;
                IF vaddr >= globaladdr THEN
                  globaladdr := vaddr;
                  IF indaccess THEN INC(globaladdr,oneword);
                  ELSE INC(globaladdr,idtyp^.size);
                  END;
                END;  
              END;  
           |pures,funcs: (* implementation; maximal procedure number *)
              newdecl := TRUE; 
              IF procnum >= proccount THEN proccount := procnum + 1 END; 
              externalaccess := exp;
          ELSE (* nothing for consts *)
          END; (* case *)     
        END; (* with *)   
        IF newdecl THEN 
          ndp := ip1;  
          IF exp THEN (* replace by unknown identifier in exportlist *) 
            NEW(ip1,unknown); 
            WITH ip1^ DO 
              name := ndp^.name; klass := unknown;
              link := ndp^.link; (* nxtidp is set in procedure ExportList *)
              globmodp := mainmodp;
            END; (* with *) 
            IF ip2 = NIL THEN listp := ip1 ELSE ip2^.link := ip1 END; 
          ELSE (* delete in local list *)  
            IF ip2=NIL THEN listp := ip1^.link;
            ELSE ip2^.link := ip1^.link;
            END;  
            ip1 := ip2; 
          END; 
          (* enter identifier for implementation in separate list *)
          EnterList(oldlist,ndp);                                          
        END;
        ip2 := ip1;
        IF ip1 = NIL THEN ip1 := listp ELSE ip1 := ip1^.link END;
      END; (* while *)   
    END InitImplementation;

    PROCEDURE EnterGlobMods(VAR ip: Idptr);
      (* complete global module entry *)
      VAR ch : CHAR;
          pos : CARDINAL;
    BEGIN
      INC(modcount);
      WITH ip^ DO
        globalmodule := TRUE;
        externalaccess := TRUE; (* call always from environment *)
        modulekey := modkey;
        globvarp := NIL;
        modnum := modcount;
        (* copy identifier *)
        IdSetPos(name);
        pos := 0;
        IdGetChar(ch);
        WHILE (ch <> ' ') AND (pos < modnamlength) DO
          identifier[pos] := ch;
          INC(pos);
          IdGetChar(ch);
        END;
        (* fill with 0C *)
        WHILE pos < modnamlength DO
          identifier[pos] := 0C;
          INC(pos);
        END;
      END; 
    END EnterGlobMods;
 
  BEGIN (* StartDecl *)
    nestlevel := 0;
    modcount := 0; (* initialisation *)
    root^.locp := sysmodp; (* enter link to system module *)
    spix := sysmodp^.name;
    EnterId(sysmodp); (* module SYSTEM *)
    GetSy;
    WHILE sy <> eop DO
      ip := NIL;
      impl := FALSE;
      globaladdr := 3; (* 0, 1 and 2 reserved for compiler (pass4) *)
      proccount := 0; (* 0 for initialisation part of global module *)
      symmod := sy = symbolsy;
      defmod := sy = definitionsy;
      impl := sy = implementationsy;
      IF NOT (defmod OR symmod) THEN InitRef END;
      GetSy;
      IF impl THEN (* implementation module *)
        SymModSearch(ip);
        oldlist := NIL;
        IF ip = NIL THEN
          Error(81);
          FOR ix := 0 TO 2 DO modkey[ix] := 0 END;
        ELSE
          mainmodp := ip;
          Reference(ip);
          proccount := 1; (* at least module procedure is entered *)
          InitImplementation(ip^.expp,TRUE);
          InitImplementation(ip^.locp,FALSE);
        END;
        impl := oldlist <> NIL; (* objects to implement *)
      ELSIF symmod THEN (* symbolic module *)
        (* key to compilation version *)
        FOR ix := 0 TO 2 DO modkey[ix] := val; GetSy END;
        SymModSearch(ip);
        IF ip <> NIL THEN
          mainmodp := ip;
          FOR ix := 0 TO 2 DO
            IF modkey[ix] <> ip^.modulekey[ix] THEN Error(86) END;
          END;
        END;   
      ELSE (* defmod or module *)
        GetModuleKey(modkey);
        IF defmod THEN DefModStatus END;
      END;
      IF ip = NIL THEN (* generate new entry *)
        NEW(ip,mods,FALSE,mods,TRUE);
        mainmodp := ip;
        EnterMods(ip);
        EnterGlobMods(ip);
        Reference(ip); (* no effect for defmod or symmod *)
      END;
      GetSy; (* ident *)
      IF defmod OR symmod THEN StopOutput END;
      ResetModuleInit;
      Module(ip,noprio,globaladdr,ip^.globvarp);
      IF defmod OR symmod THEN
        RestartOutput;
      ELSE
        IF impl THEN ErrorLS(84) END; (* some implementations missing *)
        EndReference(ip);
        TermRef;
      END;
    END;
    globvarnext := globaladdr;
    procnumber := proccount;
  END StartDecl; 

BEGIN (* Pass2 *)
  InitInOut;
  StartDecl; 
  TermInOut;
END Pass2;


END M2Pass2.
