]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
PR modula2/122407: similar error messages are emitted for an unknown symbol
authorGaius Mulley <gaiusmod2@gmail.com>
Fri, 24 Oct 2025 12:04:10 +0000 (13:04 +0100)
committerGaius Mulley <gaiusmod2@gmail.com>
Fri, 24 Oct 2025 12:04:10 +0000 (13:04 +0100)
This followup to PR modula2/122241 reduces error message clutter by
filtering unknown symbol error ensuring that only one error message
is emitted for an unknown symbol at a particular location.
The filter is implemented using two binary trees.  A new generic
(based on the address type) binary dictionary module is added to
the base libraries.

gcc/m2/ChangeLog:

PR modula2/122407
* Make-lang.in (GM2-LIBS-BOOT-DEFS): Add BinDict.def.
(GM2-LIBS-BOOT-MODS): Add BinDict.mod.
(GM2-COMP-BOOT-DEFS): Add FilterError.def.
(GM2-COMP-BOOT-MODS): Add FilterError.mod.
(GM2-LIBS-DEFS): Add BinDict.def.
(GM2-LIBS-MODS): Add BinDict.mod.
* gm2-compiler/M2Error.def (KillError): New procedure.
* gm2-compiler/M2Error.mod (WriteFormat3): Reformat.
(NewError): Rewrite and call AddToList.
(AddToList): New procedure.
(SubFromList): Ditto.
(WipeReferences): Ditto.
(KillError): Ditto.
* gm2-compiler/M2LexBuf.mod (MakeVirtualTok): Return
caret if all token positions are identical.
* gm2-compiler/M2MetaError.mod (KillError): Import.
(FilterError): Import.
(FilterUnknown): New global.
(initErrorBlock): Initialize symcause and token.
(push): Capitalize comments.
(pop): Copy symcause to toblock if discovered.
(doError): Add parameter sym.
(defaultError): Assign token if discovered.
Pass NulSym to doError.
(updateTokSym): New procedure.
(chooseError): Call updateTokSym.
(doErrorScopeModule): Pass sym to doError.
(doErrorScopeForward): Ditto.
(doErrorScopeMod): Ditto.
(doErrorScopeFor): Ditto.
(doErrorScopeDefinition): Ditto.
(doErrorScopeDef): Ditto.
(doErrorScopeProc): Ditto.
(used): Pass sym[bol] to doError.
(op): Assign symcause when encountering
an error, warning or note.
(MetaErrorStringT1): Rewrite.
(MetaErrorStringT2): Ditto.
(MetaErrorStringT3): Ditto.
(MetaErrorStringT4): Ditto.
(isUniqueError): New procedure function.
(wrapErrors): Rewrite.
(FilterUnknown): Initialize.
* gm2-compiler/M2Quads.mod (BuildTSizeFunction): Add spell check
hint specifier.
* gm2-compiler/FilterError.def: New file.
* gm2-compiler/FilterError.mod: New file.
* gm2-libs/BinDict.def: New file.
* gm2-libs/BinDict.mod: New file.

libgm2/ChangeLog:

PR modula2/122407
* libm2pim/Makefile.am (M2MODS): Add BinDict.mod.
(M2DEFS): Add BinDict.def.
* libm2pim/Makefile.in: Regenerate.

Signed-off-by: Gaius Mulley <gaiusmod2@gmail.com>
12 files changed:
gcc/m2/Make-lang.in
gcc/m2/gm2-compiler/FilterError.def [new file with mode: 0644]
gcc/m2/gm2-compiler/FilterError.mod [new file with mode: 0644]
gcc/m2/gm2-compiler/M2Error.def
gcc/m2/gm2-compiler/M2Error.mod
gcc/m2/gm2-compiler/M2LexBuf.mod
gcc/m2/gm2-compiler/M2MetaError.mod
gcc/m2/gm2-compiler/M2Quads.mod
gcc/m2/gm2-libs/BinDict.def [new file with mode: 0644]
gcc/m2/gm2-libs/BinDict.mod [new file with mode: 0644]
libgm2/libm2pim/Makefile.am
libgm2/libm2pim/Makefile.in

index cd4dc9f06984eb17345c4260a503d14e679c161a..110a8a189664d64054e45c6189cbb14079885add 100644 (file)
@@ -671,6 +671,7 @@ GM2-LIBS-BOOT-DEFS = \
    ASCII.def \
    Args.def \
    Assertion.def \
+   BinDict.def \
    Break.def \
    CmdArgs.def \
    Debug.def \
@@ -718,6 +719,7 @@ GM2-LIBS-BOOT-MODS = \
    ASCII.mod \
    Args.mod \
    Assertion.mod \
+   BinDict.mod \
    Break.mod \
    CmdArgs.mod \
    Debug.mod \
@@ -769,6 +771,7 @@ GM2-LIBS-BOOT-CC = \
 # Definition modules for the front end found in gm2-compiler.
 
 GM2-COMP-BOOT-DEFS = \
+   FilterError.def \
    FifoQueue.def \
    Lists.def \
    M2ALU.def \
@@ -845,6 +848,7 @@ GM2-COMP-BOOT-DEFS = \
 # Implementation modules for the front end found in gm2-compiler.
 
 GM2-COMP-BOOT-MODS = \
+   FilterError.mod \
    FifoQueue.mod \
    Lists.mod \
    Lists.mod \
@@ -946,6 +950,7 @@ GM2-LIBS-DEFS = \
    ASCII.def \
    Args.def \
    Assertion.def \
+   BinDict.def \
    Break.def \
    Builtins.def \
    COROUTINES.def \
@@ -1000,6 +1005,7 @@ GM2-LIBS-MODS = \
    ASCII.mod \
    Args.mod \
    Assertion.mod \
+   BinDict.mod \
    Break.mod \
    Builtins.mod \
    COROUTINES.mod \
@@ -1062,6 +1068,7 @@ GM2-LIBS-CC = \
 # cc1gm2$(exeext) uses these definition modules found in the gm2-compiler directory.
 
 GM2-COMP-DEFS = \
+   FilterError.def \
    FifoQueue.def \
    Lists.def \
    M2ALU.def \
@@ -1135,6 +1142,7 @@ GM2-COMP-DEFS = \
 # cc1gm2$(exeext) uses these implementation modules found in the gm2-compiler directory.
 
 GM2-COMP-MODS = \
+   FilterError.mod \
    FifoQueue.mod \
    Lists.mod \
    M2ALU.mod \
diff --git a/gcc/m2/gm2-compiler/FilterError.def b/gcc/m2/gm2-compiler/FilterError.def
new file mode 100644 (file)
index 0000000..ef84aef
--- /dev/null
@@ -0,0 +1,61 @@
+(* FilterError.def provides a filter for token and symbol.
+
+Copyright (C) 2025 Free Software Foundation, Inc.
+Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.
+
+This file is part of GNU Modula-2.
+
+GNU Modula-2 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.
+
+GNU Modula-2 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.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  *)
+
+DEFINITION MODULE FilterError ;
+
+TYPE
+   Filter ;
+
+
+(*
+   Init - return a new empty Filter.
+*)
+
+PROCEDURE Init () : Filter ;
+
+
+(*
+   AddSymError - adds the pair sym token to the filter.
+*)
+
+PROCEDURE AddSymError (filter: Filter;
+                       sym: CARDINAL; token: CARDINAL) ;
+
+(*
+   IsSymError - return TRUE if the pair sym token have been entered in the filter.
+*)
+
+PROCEDURE IsSymError (filter: Filter; sym: CARDINAL; token: CARDINAL) : BOOLEAN ;
+
+
+(*
+   Kill - deletes the entire filter tree.
+*)
+
+PROCEDURE Kill (VAR filter: Filter) ;
+
+
+END FilterError.
diff --git a/gcc/m2/gm2-compiler/FilterError.mod b/gcc/m2/gm2-compiler/FilterError.mod
new file mode 100644 (file)
index 0000000..b2070de
--- /dev/null
@@ -0,0 +1,229 @@
+(* FilterError.def implements a filter for token and symbol.
+
+Copyright (C) 2025 Free Software Foundation, Inc.
+Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.
+
+This file is part of GNU Modula-2.
+
+GNU Modula-2 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.
+
+GNU Modula-2 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.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  *)
+
+IMPLEMENTATION MODULE FilterError ;
+
+(* The purpose of this module is to be able to filter out multiple error
+   reports refering to the same symbol and token.  This is achieved by
+   maintaining a dictionary of symbols each pointing to a dictionary of
+   tokens.  *)
+
+FROM SYSTEM IMPORT ADDRESS, ADR ;
+FROM Storage IMPORT DEALLOCATE, ALLOCATE ;
+FROM BinDict IMPORT Node ;
+FROM Assertion IMPORT Assert ;
+FROM libc IMPORT printf ;
+
+IMPORT BinDict ;
+
+CONST
+   Debugging = FALSE ;
+
+TYPE
+   Filter = POINTER TO RECORD
+                          Sym2Dict: BinDict.Dictionary ;
+                       END ;
+
+   PtrToCardinal = POINTER TO CARDINAL ;
+   PtrToBoolean = POINTER TO BOOLEAN ;
+
+
+(*
+   Init - return a new empty Filter.
+*)
+
+PROCEDURE Init () : Filter ;
+VAR
+   filter: Filter ;
+BEGIN
+   NEW (filter) ;
+   WITH filter^ DO
+      Sym2Dict := BinDict.Init (CompareCardinal, DeleteCardinal, DeleteTree) ;
+   END ;
+   RETURN filter
+END Init ;
+
+
+(*
+   Kill - deletes the entire filter tree and all contents.
+*)
+
+PROCEDURE Kill (VAR filter: Filter) ;
+BEGIN
+   BinDict.Kill (filter^.Sym2Dict) ;
+   DISPOSE (filter)
+END Kill ;
+
+
+(*
+   CompareCardinal - return an INTEGER representing the comparison
+                     between left and right.
+                     0 if left == right, -1 if left < right,
+                    +1 if left > right.
+*)
+
+PROCEDURE CompareCardinal (left, right: PtrToCardinal) : INTEGER ;
+BEGIN
+   IF left^ = right^
+   THEN
+      RETURN 0
+   ELSIF left^ < right^
+   THEN
+      RETURN -1
+   ELSE
+      RETURN 1
+   END
+END CompareCardinal ;
+
+
+(*
+   DeleteCardinal - deallocate the cardinal key.
+*)
+
+PROCEDURE DeleteCardinal (card: PtrToCardinal) ;
+BEGIN
+   DISPOSE (card)
+END DeleteCardinal ;
+
+
+(*
+   DeleteBoolean - deallocate the boolean value.
+*)
+
+PROCEDURE DeleteBoolean (boolean: PtrToBoolean) ;
+BEGIN
+   DISPOSE (boolean)
+END DeleteBoolean ;
+
+
+(*
+   DeleteTree - delete tree and all its contents.
+*)
+
+PROCEDURE DeleteTree (ErrorTree: BinDict.Dictionary) ;
+BEGIN
+   BinDict.Kill (ErrorTree)
+END DeleteTree ;
+
+
+(*
+   AddSymError - adds the pair sym token to the filter.
+*)
+
+PROCEDURE AddSymError (filter: Filter;
+                       sym: CARDINAL; token: CARDINAL) ;
+BEGIN
+   IF NOT IsSymError (filter, sym, token)
+   THEN
+      AddNewEntry (filter, sym, token, TRUE)
+   END
+END AddSymError ;
+
+
+(*
+   AddNewEntry - adds a new value to the sym token pair.
+*)
+
+PROCEDURE AddNewEntry (filter: Filter; sym: CARDINAL;
+                       token: CARDINAL; value: BOOLEAN) ;
+VAR
+   TokenTree : BinDict.Dictionary ;
+   ptrToToken,
+   ptrToCard : PtrToCardinal ;
+   ptrToBool : PtrToBoolean ;
+BEGIN
+   TokenTree := BinDict.Get (filter^.Sym2Dict, ADR (sym)) ;
+   IF TokenTree = NIL
+   THEN
+      TokenTree := BinDict.Init (CompareCardinal, DeleteCardinal, DeleteBoolean) ;
+      NEW (ptrToCard) ;
+      ptrToCard^ := sym ;
+      BinDict.Insert (filter^.Sym2Dict, ptrToCard, TokenTree) ;
+      Assert (BinDict.Get (filter^.Sym2Dict, ptrToCard) = TokenTree)
+   END ;
+   NEW (ptrToBool) ;
+   ptrToBool^ := value ;
+   NEW (ptrToToken) ;
+   ptrToToken^ := token ;
+   IF Debugging
+   THEN
+      printf ("adding sym %d: key = 0x%x, value = 0x%x  (%d, %d)\n",
+              sym, ptrToToken, ptrToBool, ptrToToken^, ptrToBool^)
+   END ;
+   BinDict.Insert (TokenTree, ptrToToken, ptrToBool) ;
+   Assert (BinDict.Get (TokenTree, ptrToToken) = ptrToBool) ;
+   IF Debugging
+   THEN
+      BinDict.PostOrder (TokenTree, PrintNode)
+   END
+END AddNewEntry ;
+
+
+(*
+   PrintNode -
+*)
+
+PROCEDURE PrintNode (node: Node) ;
+VAR
+   ptrToCard : PtrToCardinal ;
+   ptrToBool : PtrToBoolean ;
+BEGIN
+   ptrToCard := BinDict.Key (node) ;
+   ptrToBool := BinDict.Value (node) ;
+   printf ("key = 0x%x, value = 0x%x  (%d, %d)\n",
+            ptrToCard, ptrToBool, ptrToCard^, ptrToBool^)
+END PrintNode ;
+
+
+(*
+   IsSymError - return TRUE if the pair sym token have been
+                entered in the filter.
+*)
+
+PROCEDURE IsSymError (filter: Filter; sym: CARDINAL; token: CARDINAL) : BOOLEAN ;
+VAR
+   ptb      : PtrToBoolean ;
+   TokenTree: BinDict.Dictionary ;
+BEGIN
+   TokenTree := BinDict.Get (filter^.Sym2Dict, ADR (sym)) ;
+   (* RETURN (TokenTree # NIL) ; *)
+   IF TokenTree = NIL
+   THEN
+      (* No symbol registered, therefore FALSE.  *)
+      RETURN FALSE
+   END ;
+   ptb := BinDict.Get (TokenTree, ADR (token)) ;
+   IF ptb = NIL
+   THEN
+      (* The symbol was registered, but no entry for token, therefore FALSE.  *)
+      RETURN FALSE
+   END ;
+   (* Found symbol and token so we return the result.  *)
+   RETURN ptb^
+END IsSymError ;
+
+
+END FilterError.
index 427bd08bc89c1fc2495632b98900824a3f55ec98..7f945e42dc2ae41956d82c076f57705ae7d01237 100644 (file)
@@ -129,6 +129,14 @@ PROCEDURE ChainError (AtTokenNo: CARDINAL; e: Error) : Error ;
 PROCEDURE MoveError (e: Error; AtTokenNo: CARDINAL) : Error ;
 
 
+(*
+   KillError - remove error e from the error list and deallocate
+               memory associated with e.
+*)
+
+PROCEDURE KillError (VAR e: Error) ;
+
+
 (*
    SetColor - informs the error module that this error will have had colors
               assigned to it.  If an error is issued without colors assigned
index 561f42cf6343fd34e238991eba4b10b1726493d8..095e7327794d553fa33d29417766ed2f8b43355a 100644 (file)
@@ -369,8 +369,8 @@ PROCEDURE WriteFormat3 (a: ARRAY OF CHAR; w1, w2, w3: ARRAY OF BYTE) ;
 VAR
    e: Error ;
 BEGIN
-   e := NewError(GetTokenNo()) ;
-   e^.s := DoFormat3(a, w1, w2, w3)
+   e := NewError (GetTokenNo ()) ;
+   e^.s := DoFormat3 (a, w1, w2, w3)
 END WriteFormat3 ;
 
 
@@ -394,7 +394,7 @@ END MoveError ;
 
 PROCEDURE NewError (AtTokenNo: CARDINAL) : Error ;
 VAR
-   e, f: Error ;
+   e: Error ;
 BEGIN
    IF AtTokenNo = UnknownTokenNo
    THEN
@@ -414,18 +414,7 @@ BEGIN
    END ;
    (* Assert (scopeKind # noscope) ;  *)
    e^.scope := currentScope ;
-   IF (head=NIL) OR (head^.token>AtTokenNo)
-   THEN
-      e^.next := head ;
-      head    := e
-   ELSE
-      f := head ;
-      WHILE (f^.next#NIL) AND (f^.next^.token<AtTokenNo) DO
-         f := f^.next
-      END ;
-      e^.next := f^.next ;
-      f^.next := e
-   END ;
+   AddToList (e) ;
    RETURN( e )
 END NewError ;
 
@@ -462,6 +451,95 @@ BEGIN
 END NewNote ;
 
 
+(*
+   AddToList - adds error e to the list of errors in token order.
+*)
+
+PROCEDURE AddToList (e: Error) ;
+VAR
+   f: Error ;
+BEGIN
+   IF (head=NIL) OR (head^.token > e^.token)
+   THEN
+      e^.next := head ;
+      head    := e
+   ELSE
+      f := head ;
+      WHILE (f^.next # NIL) AND (f^.next^.token < e^.token) DO
+         f := f^.next
+      END ;
+      e^.next := f^.next ;
+      f^.next := e
+   END ;
+END AddToList ;
+
+
+(*
+   SubFromList - remove e from the global list.
+*)
+
+PROCEDURE SubFromList (e: Error) ;
+VAR
+   f: Error ;
+BEGIN
+   IF head = e
+   THEN
+      head := head^.next
+   ELSE
+      f := head ;
+      WHILE (f # NIL) AND (f^.next # e) DO
+         f := f^.next
+      END ;
+      IF (f # NIL) AND (f^.next = e)
+      THEN
+         f^.next := e^.next
+      ELSE
+         InternalError ('expecting e to be on the global list')
+      END
+   END ;
+   DISPOSE (e)
+END SubFromList ;
+
+
+(*
+   WipeReferences - remove any reference to e from the global list.
+*)
+
+PROCEDURE WipeReferences (e: Error) ;
+VAR
+   f: Error ;
+BEGIN
+   f := head ;
+   WHILE f # NIL DO
+      IF f^.parent = e
+      THEN
+         f^.parent := NIL
+      END ;
+      IF f^.child = e
+      THEN
+         f^.child := NIL
+      END ;
+      f := f^.next
+   END
+END WipeReferences ;
+
+
+(*
+   KillError - remove error e from the error list and deallocate
+               memory associated with e.
+*)
+
+PROCEDURE KillError (VAR e: Error) ;
+BEGIN
+   IF head # NIL
+   THEN
+      SubFromList (e) ;
+      WipeReferences (e) ;
+      e := NIL
+   END
+END KillError ;
+
+
 (*
    ChainError - creates and returns a new error handle, this new error
                 is associated with, e, and is chained onto the end of, e.
index 143190e06a02ee0fa39348585a1990f311c280f5..51982430296c4719e50bedc1649139dc5b2501b9 100644 (file)
@@ -1078,6 +1078,10 @@ BEGIN
    THEN
       caret := right
    END ;
+   IF (caret = left) AND (left = right)
+   THEN
+      RETURN caret
+   END ;
    IF isSrcToken (caret) AND isSrcToken (left) AND isSrcToken (right)
    THEN
       lc := TokenToLocation (caret) ;
index dc14e6b06beae83349c11842df0adac33f164b38..aae0f02eb100b478e7c0b2f1a4f87a7533463efa 100644 (file)
@@ -26,7 +26,11 @@ FROM M2Base IMPORT ZType, RType, IsPseudoBaseFunction, IsPseudoBaseProcedure ;
 FROM NameKey IMPORT Name, KeyToCharStar, NulName ;
 FROM StrLib IMPORT StrLen ;
 FROM M2LexBuf IMPORT GetTokenNo, UnknownTokenNo ;
-FROM M2Error IMPORT Error, NewError, NewWarning, NewNote, ErrorString, InternalError, ChainError, SetColor, FlushErrors, FlushWarnings ;
+
+FROM M2Error IMPORT Error, NewError, KillError,
+                    NewWarning, NewNote, ErrorString, InternalError,
+                    ChainError, SetColor, FlushErrors, FlushWarnings ;
+
 FROM FIO IMPORT StdOut, WriteLine ;
 FROM SFIO IMPORT WriteS ;
 FROM StringConvert IMPORT ctos ;
@@ -67,6 +71,9 @@ FROM SymbolTable IMPORT NulSym,
 
 IMPORT M2ColorString ;
 IMPORT M2Error ;
+IMPORT FilterError ;
+
+FROM FilterError IMPORT Filter, AddSymError, IsSymError ;
 
 
 CONST
@@ -85,6 +92,8 @@ TYPE
    errorBlock = RECORD
                    useError  : BOOLEAN ;
                    e         : Error ;
+                   symcause  : CARDINAL ;  (* The symbol (or NulSym) associated with the token no.  *)
+                   token     : CARDINAL ;
                    type      : errorType ;
                    out, in   : String ;
                    highplus1 : CARDINAL ;
@@ -115,12 +124,13 @@ TYPE
 
 
 VAR
-   lastRoot  : Error ;
-   lastColor : colorType ;
-   seenAbort : BOOLEAN ;
-   dictionary : Index ;
-   outputStack: Index ;
-   freeEntry  : dictionaryEntry ;
+   lastRoot     : Error ;
+   lastColor    : colorType ;
+   seenAbort    : BOOLEAN ;
+   dictionary   : Index ;
+   outputStack  : Index ;
+   freeEntry    : dictionaryEntry ;
+   FilterUnknown: Filter ;
 
 
 (*
@@ -513,6 +523,8 @@ BEGIN
    WITH eb DO
       useError   := TRUE ;
       e          := NIL ;
+      symcause   := NulSym ;
+      token      := UnknownTokenNo ;
       type       := error ;  (* Default to the error color.  *)
       out        := InitString ('') ;
       in         := input ;
@@ -543,9 +555,9 @@ END initErrorBlock ;
 
 PROCEDURE push (VAR newblock: errorBlock; oldblock: errorBlock) ;
 BEGIN
-   pushColor (oldblock) ;  (* save the current color.  *)
-   newblock := oldblock ;  (* copy all the fields.  *)
-   newblock.out := NIL ;  (* must do this before a clear as we have copied the address.  *)
+   pushColor (oldblock) ;  (* Save the current color.  *)
+   newblock := oldblock ;  (* Now copy all the fields.  *)
+   newblock.out := NIL ;  (* We must do this before a clear as we have copied the address.  *)
    clear (newblock) ;
    newblock.quotes := TRUE
 END push ;
@@ -604,6 +616,10 @@ BEGIN
    THEN
       toblock.e := fromblock.e
    END ;
+   IF toblock.symcause = NulSym
+   THEN
+      toblock.symcause := fromblock.symcause
+   END ;
    toblock.chain := fromblock.chain ;
    toblock.root := fromblock.root ;
    toblock.ini := fromblock.ini ;
@@ -1173,35 +1189,54 @@ END doChain ;
    doError - creates and returns an error note.
 *)
 
-PROCEDURE doError (VAR eb: errorBlock; tok: CARDINAL) ;
+PROCEDURE doError (VAR eb: errorBlock; tok: CARDINAL; sym: CARDINAL) ;
 BEGIN
    IF eb.useError
    THEN
-      chooseError (eb, tok)
+      chooseError (eb, tok, sym)
    END
 END doError ;
 
 
 (*
-   defaultError - adds the default error location to, tok, if one has not already been
-                  assigned.
+   defaultError - adds the default error location to, tok,
+                  if one has not already been assigned.
 *)
 
 PROCEDURE defaultError (VAR eb: errorBlock; tok: CARDINAL) ;
 BEGIN
    IF eb.e = NIL
    THEN
-      doError (eb, tok)
+      doError (eb, tok, NulSym)
+   END ;
+   IF eb.token = UnknownTokenNo
+   THEN
+      eb.token := tok
    END
 END defaultError ;
 
 
+(*
+   updateTokSym - assign symcause to sym if not NulSym.
+                  Update token.
+*)
+
+PROCEDURE updateTokSym (VAR eb: errorBlock; tok: CARDINAL; sym: CARDINAL) ;
+BEGIN
+   IF sym # NulSym
+   THEN
+      eb.symcause := sym
+   END ;
+   eb.token := tok
+END updateTokSym ;
+
+
 (*
    chooseError - choose the error kind dependant upon type.
                  Either an error, warning or note will be generated.
 *)
 
-PROCEDURE chooseError (VAR eb: errorBlock; tok: CARDINAL) ;
+PROCEDURE chooseError (VAR eb: errorBlock; tok: CARDINAL; sym: CARDINAL) ;
 BEGIN
    IF eb.chain
    THEN
@@ -1217,19 +1252,22 @@ BEGIN
                    eb.e := NewError (tok)
                 ELSE
                    eb.e := MoveError (eb.e, tok)
-                END |
+                END ;
+                updateTokSym (eb, tok, sym) |
       warning:  IF eb.e=NIL
                 THEN
                    eb.e := NewWarning (tok)
                 ELSE
                    eb.e := MoveError (eb.e, tok)
-                END |
+                END ;
+                updateTokSym (eb, tok, sym) |
       note   :  IF eb.e=NIL
                 THEN
                    eb.e := NewNote (tok)
                 ELSE
                    eb.e := MoveError (eb.e, tok)
-                END
+                END ;
+                updateTokSym (eb, tok, sym)
 
       ELSE
          InternalError ('unexpected enumeration value')
@@ -1257,9 +1295,9 @@ BEGIN
    THEN
       IF IsInnerModule (scope)
       THEN
-         doError (eb, GetDeclaredMod (sym))
+         doError (eb, GetDeclaredMod (sym), sym)
       ELSE
-         doError (eb, GetDeclaredMod (sym))
+         doError (eb, GetDeclaredMod (sym), sym)
       END
    ELSE
       Assert (IsDefImp (scope)) ;
@@ -1269,9 +1307,9 @@ BEGIN
          UNTIL GetScope(OuterModule)=NulSym.  *)
       IF GetDeclaredModule (sym) = UnknownTokenNo
       THEN
-         doError (eb, GetDeclaredDef (sym))
+         doError (eb, GetDeclaredDef (sym), sym)
       ELSE
-         doError (eb, GetDeclaredMod (sym))
+         doError (eb, GetDeclaredMod (sym), sym)
       END
    END
 END doErrorScopeModule ;
@@ -1290,9 +1328,9 @@ BEGIN
    THEN
       IF IsInnerModule (scope)
       THEN
-         doError (eb, GetDeclaredFor (sym))
+         doError (eb, GetDeclaredFor (sym), sym)
       ELSE
-         doError (eb, GetDeclaredFor (sym))
+         doError (eb, GetDeclaredFor (sym), sym)
       END
    ELSE
       Assert (IsDefImp (scope)) ;
@@ -1302,9 +1340,9 @@ BEGIN
          UNTIL GetScope(OuterModule)=NulSym.  *)
       IF GetDeclaredModule (sym) = UnknownTokenNo
       THEN
-         doError (eb, GetDeclaredDef (sym))
+         doError (eb, GetDeclaredDef (sym), sym)
       ELSE
-         doError (eb, GetDeclaredFor (sym))
+         doError (eb, GetDeclaredFor (sym), sym)
       END
    END
 END doErrorScopeForward ;
@@ -1324,12 +1362,12 @@ BEGIN
    IF scope = NulSym
    THEN
       M2Error.EnterErrorScope (NIL) ;
-      doError (eb, GetDeclaredMod (sym))
+      doError (eb, GetDeclaredMod (sym), sym)
    ELSE
       M2Error.EnterErrorScope (GetErrorScope (scope)) ;
       IF IsProcedure (scope)
       THEN
-         doError (eb, GetDeclaredMod (sym))
+         doError (eb, GetDeclaredMod (sym), sym)
       ELSE
          doErrorScopeModule (eb, sym)
       END
@@ -1353,12 +1391,12 @@ BEGIN
    IF scope = NulSym
    THEN
       M2Error.EnterErrorScope (NIL) ;
-      doError (eb, GetDeclaredFor (sym))
+      doError (eb, GetDeclaredFor (sym), sym)
    ELSE
       M2Error.EnterErrorScope (GetErrorScope (scope)) ;
       IF IsProcedure (scope)
       THEN
-         doError (eb, GetDeclaredFor (sym))
+         doError (eb, GetDeclaredFor (sym), sym)
       ELSE
          doErrorScopeForward (eb, sym)
       END
@@ -1392,16 +1430,16 @@ BEGIN
    IF IsModule (scope)
    THEN
       (* No definition module for a program module.  *)
-      doError (eb, GetDeclaredMod (sym))
+      doError (eb, GetDeclaredMod (sym), sym)
    ELSE
       Assert (IsDefImp (scope)) ;
       IF GetDeclaredDefinition (sym) = UnknownTokenNo
       THEN
          (* Fall back to the implementation module if no declaration exists
             in the definition module.  *)
-         doError (eb, GetDeclaredMod (sym))
+         doError (eb, GetDeclaredMod (sym), sym)
       ELSE
-         doError (eb, GetDeclaredDef (sym))
+         doError (eb, GetDeclaredDef (sym), sym)
       END
    END
 END doErrorScopeDefinition ;
@@ -1421,12 +1459,12 @@ BEGIN
    IF scope = NulSym
    THEN
       M2Error.EnterErrorScope (NIL) ;
-      doError (eb, GetDeclaredFor (sym))
+      doError (eb, GetDeclaredFor (sym), sym)
    ELSE
       M2Error.EnterErrorScope (GetErrorScope (scope)) ;
       IF IsProcedure (scope)
       THEN
-         doError (eb, GetDeclaredDef (sym))
+         doError (eb, GetDeclaredDef (sym), sym)
       ELSE
          doErrorScopeDefinition (eb, sym)
       END
@@ -1477,25 +1515,25 @@ BEGIN
    IF scope = NulSym
    THEN
       M2Error.EnterErrorScope (NIL) ;
-      doError (eb, GetDeclaredDef (sym))
+      doError (eb, GetDeclaredDef (sym), sym)
    ELSE
       M2Error.EnterErrorScope (GetErrorScope (scope)) ;
       IF IsVar (sym) OR IsParameter (sym)
       THEN
-         doError (eb, GetVarParamTok (sym))
+         doError (eb, GetVarParamTok (sym), sym)
       ELSIF IsProcedure (scope)
       THEN
-         doError (eb, GetDeclaredDef (sym))
+         doError (eb, GetDeclaredDef (sym), sym)
       ELSIF IsModule (scope)
       THEN
-         doError (eb, GetDeclaredMod (sym))
+         doError (eb, GetDeclaredMod (sym), sym)
       ELSE
          Assert (IsDefImp (scope)) ;
          IF GetDeclaredDefinition (sym) = UnknownTokenNo
          THEN
-            doError (eb, GetDeclaredMod (sym))
+            doError (eb, GetDeclaredMod (sym), sym)
          ELSE
-            doError (eb, GetDeclaredDef (sym))
+            doError (eb, GetDeclaredDef (sym), sym)
          END
       END
    END ;
@@ -1550,7 +1588,7 @@ PROCEDURE used (VAR eb: errorBlock; sym: ARRAY OF CARDINAL; bol: CARDINAL) ;
 BEGIN
    IF bol <= HIGH (sym)
    THEN
-      doError (eb, GetFirstUsed (sym[bol]))
+      doError (eb, GetFirstUsed (sym[bol]), sym[bol])
    END
 END used ;
 
@@ -1755,7 +1793,8 @@ BEGIN
       'B':  declaredType (eb, sym, bol) |
       'C':  eb.chain := TRUE |
       'D':  declaredDef (eb, sym, bol) |
-      'E':  eb.type := error |
+      'E':  eb.type := error ;
+            eb.symcause := sym[bol] |
       'F':  filename (eb) ;
             DEC (eb.ini) |
       'G':  declaredFor (eb, sym, bol) |
@@ -1764,7 +1803,8 @@ BEGIN
             DEC (eb.ini) |
       'M':  declaredMod (eb, sym, bol) |
       'N':  doCount (eb, sym, bol) |
-      'O':  eb.type := note |
+      'O':  eb.type := note ;
+            eb.symcause := sym[bol] |
       'P':  pushColor (eb) |
       'Q':  resetDictionary |
       'R':  eb.root := TRUE |
@@ -1772,7 +1812,8 @@ BEGIN
       'T':  doGetType (eb, sym, bol) |
       'U':  used (eb, sym, bol) |
       'V':  declaredVar (eb, sym, bol) |
-      'W':  eb.type := warning |
+      'W':  eb.type := warning ;
+            eb.symcause := sym[bol] |
       'X':  pushOutput (eb) |
       'Y':  processDefine (eb) |
       'Z':  popOutput (eb) |
@@ -2402,7 +2443,12 @@ BEGIN
    ebnf (eb, sym) ;
    flushColor (eb) ;
    defaultError (eb, tok) ;
-   ErrorString (eb.e, Dup (eb.out)) ;
+   IF isUniqueError (eb)
+   THEN
+      ErrorString (eb.e, Dup (eb.out)) ;
+   ELSE
+      KillError (eb.e)
+   END ;
    killErrorBlock (eb) ;
    checkAbort
 END MetaErrorStringT1 ;
@@ -2425,7 +2471,12 @@ BEGIN
    ebnf (eb, sym) ;
    flushColor (eb) ;
    defaultError (eb, tok) ;
-   ErrorString (eb.e, Dup (eb.out)) ;
+   IF isUniqueError (eb)
+   THEN
+      ErrorString (eb.e, Dup (eb.out))
+   ELSE
+      KillError (eb.e)
+   END ;
    killErrorBlock (eb) ;
    checkAbort
 END MetaErrorStringT2 ;
@@ -2450,7 +2501,12 @@ BEGIN
    ebnf (eb, sym) ;
    flushColor (eb) ;
    defaultError (eb, tok) ;
-   ErrorString (eb.e, Dup (eb.out)) ;
+   IF isUniqueError (eb)
+   THEN
+      ErrorString (eb.e, Dup (eb.out))
+   ELSE
+      KillError (eb.e)
+   END ;
    killErrorBlock (eb) ;
    checkAbort
 END MetaErrorStringT3 ;
@@ -2475,7 +2531,12 @@ BEGIN
    ebnf (eb, sym) ;
    flushColor (eb) ;
    defaultError (eb, tok) ;
-   ErrorString (eb.e, Dup (eb.out)) ;
+   IF isUniqueError (eb)
+   THEN
+      ErrorString (eb.e, Dup (eb.out))
+   ELSE
+      KillError (eb.e)
+   END ;
    killErrorBlock (eb) ;
    checkAbort
 END MetaErrorStringT4 ;
@@ -2517,6 +2578,31 @@ BEGIN
 END MetaError4 ;
 
 
+(*
+   isUniqueError - return TRUE if the symbol associated with the
+                   error block is unknown and we have seen the same
+                   token before.
+*)
+
+PROCEDURE isUniqueError (VAR eb: errorBlock) : BOOLEAN ;
+BEGIN
+   IF (eb.symcause # NulSym) AND IsUnknown (eb.symcause)
+   THEN
+      (* A candidate for filtering.  *)
+      IF IsSymError (FilterUnknown, eb.symcause, eb.token)
+      THEN
+         (* Seen and reported about this unknown and token
+            location before.  *)
+         RETURN FALSE
+      ELSE
+         (* Remember this combination.  *)
+         AddSymError (FilterUnknown, eb.symcause, eb.token)
+      END
+   END ;
+   RETURN TRUE
+END isUniqueError ;
+
+
 (*
    wrapErrors -
 *)
@@ -2531,15 +2617,20 @@ BEGIN
    ebnf (eb, sym) ;
    flushColor (eb) ;
    defaultError (eb, tok) ;
-   lastRoot := eb.e ;
-   ErrorString (eb.e, Dup (eb.out)) ;
-   killErrorBlock (eb) ;
-   initErrorBlock (eb, InitString (m2), sym) ;
-   eb.type := chained ;
-   ebnf (eb, sym) ;
-   flushColor (eb) ;
-   defaultError (eb, tok) ;
-   ErrorString (eb.e, Dup (eb.out)) ;
+   IF isUniqueError (eb)
+   THEN
+      lastRoot := eb.e ;
+      ErrorString (eb.e, Dup (eb.out)) ;
+      killErrorBlock (eb) ;
+      initErrorBlock (eb, InitString (m2), sym) ;
+      eb.type := chained ;
+      ebnf (eb, sym) ;
+      flushColor (eb) ;
+      defaultError (eb, tok) ;
+      ErrorString (eb.e, Dup (eb.out))
+   ELSE
+      KillError (eb.e)
+   END ;
    killErrorBlock (eb)
 END wrapErrors ;
 
@@ -2871,5 +2962,6 @@ BEGIN
    seenAbort := FALSE ;
    outputStack := InitIndex (1) ;
    dictionary := InitIndex (1) ;
-   freeEntry := NIL
+   freeEntry := NIL ;
+   FilterUnknown := FilterError.Init ()
 END M2MetaError.
index 3bdf8c56ced0c02c4bb1c00693a0153bc73d03d4..bacd9561a725fd58956360abaec7ab3d39ba2646 100644 (file)
@@ -10776,8 +10776,9 @@ BEGIN
          PutVar (ReturnVar, Cardinal) ;
          GenQuadO (resulttok, SizeOp, ReturnVar, NulSym, GetSType (OperandT (1)), FALSE)
       ELSE
+         (* Spellcheck.  *)
          MetaErrorT1 (resulttok,
-                      '{%E}SYSTEM procedure function {%kTSIZE} expects a variable or type as its first parameter, seen {%1Ed}',
+                      '{%E}SYSTEM procedure function {%kTSIZE} expects a variable or type as its first parameter, seen {%1Ed} {%1&s}',
                       OperandT (1)) ;
          ReturnVar := MakeConstLit (resulttok, MakeKey ('0'), Cardinal)
       END
diff --git a/gcc/m2/gm2-libs/BinDict.def b/gcc/m2/gm2-libs/BinDict.def
new file mode 100644 (file)
index 0000000..16272fd
--- /dev/null
@@ -0,0 +1,92 @@
+(* BinDict.def provides a generic binary dictionary.
+
+Copyright (C) 2025 Free Software Foundation, Inc.
+Contributed by Gaius Mulley <gaiusmod2@gmail.com>.
+
+This file is part of GNU Modula-2.
+
+GNU Modula-2 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.
+
+GNU Modula-2 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.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  *)
+
+DEFINITION MODULE BinDict ;
+
+FROM SYSTEM IMPORT ADDRESS ;
+
+TYPE
+   Dictionary ;
+   Node ;
+   Compare   = PROCEDURE (ADDRESS, ADDRESS) : INTEGER ;
+   Delete    = PROCEDURE (ADDRESS) ;
+   VisitNode = PROCEDURE (Node) ;
+
+
+(*
+   Init - create and return a new binary dictionary which will use
+          the compare procedure to order the contents as they are added.
+*)
+
+PROCEDURE Init (KeyCompare: Compare;
+                KeyDelete, ValueDelete: Delete) : Dictionary ;
+
+
+(*
+   Kill - delete the dictionary and its contents.
+          dict is assigned to NIL.
+*)
+
+PROCEDURE Kill (VAR dict: Dictionary) ;
+
+
+(*
+   PostOrder - visit each dictionary entry in post order.
+*)
+
+PROCEDURE PostOrder (dict: Dictionary; visit: VisitNode) ;
+
+
+(*
+   Insert - insert key value pair into the dictionary.
+*)
+
+PROCEDURE Insert (dict: Dictionary; key, value: ADDRESS) ;
+
+
+(*
+   Get - return the value associated with the key or NIL
+         if it does not exist.
+*)
+
+PROCEDURE Get (dict: Dictionary; key: ADDRESS) : ADDRESS ;
+
+
+(*
+   Value - return the value from node.
+*)
+
+PROCEDURE Value (node: Node) : ADDRESS ;
+
+
+(*
+   Key - return the key from node.
+*)
+
+PROCEDURE Key (node: Node) : ADDRESS ;
+
+
+END BinDict.
diff --git a/gcc/m2/gm2-libs/BinDict.mod b/gcc/m2/gm2-libs/BinDict.mod
new file mode 100644 (file)
index 0000000..f8bb873
--- /dev/null
@@ -0,0 +1,272 @@
+(* BinDict.mod provides a generic binary dictionary.
+
+Copyright (C) 2025 Free Software Foundation, Inc.
+Contributed by Gaius Mulley <gaiusmod2@gmail.com>.
+
+This file is part of GNU Modula-2.
+
+GNU Modula-2 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.
+
+GNU Modula-2 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.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  *)
+
+IMPLEMENTATION MODULE BinDict ;
+
+FROM Storage IMPORT ALLOCATE, DEALLOCATE ;
+
+
+TYPE
+   Dictionary = POINTER TO RECORD
+                              content    : Node ;
+                              compare    : Compare ;
+                              deleteKey,
+                              deleteValue: Delete
+                           END ;
+
+   Node = POINTER TO RECORD
+                        dict : Dictionary ;
+                        left,
+                        right: Node ;
+                        key,
+                        value: ADDRESS ;
+                     END ;
+
+
+(*
+   Init - create and return a new binary dictionary which will use
+          the compare procedure to order the contents as they are
+          added.
+*)
+
+PROCEDURE Init (KeyCompare: Compare; KeyDelete,
+                ValueDelete: Delete) : Dictionary ;
+VAR
+   dict: Dictionary ;
+BEGIN
+   NEW (dict) ;
+   WITH dict^ DO
+      content := NIL ;
+      compare := KeyCompare ;
+      deleteKey := KeyDelete ;
+      deleteValue := ValueDelete
+   END ;
+   RETURN dict
+END Init ;
+
+
+(*
+   Kill - delete the dictionary and its contents.
+          dict is assigned to NIL.
+*)
+
+PROCEDURE Kill (VAR dict: Dictionary) ;
+BEGIN
+   PostOrder (dict, DeleteNode) ;
+   DISPOSE (dict) ;
+   dict := NIL
+END Kill ;
+
+
+(*
+   DeleteNode - deletes node dict, key and value.
+*)
+
+PROCEDURE DeleteNode (node: Node) ;
+BEGIN
+   IF node # NIL
+   THEN
+      WITH node^ DO
+         dict^.deleteKey (key) ;
+         dict^.deleteValue (value)
+      END ;
+      DISPOSE (node)
+   END
+END DeleteNode ;
+
+
+(*
+   Insert - insert key value pair into the dictionary.
+*)
+
+PROCEDURE Insert (dict: Dictionary; key, value: ADDRESS) ;
+BEGIN
+   dict^.content := InsertNode (dict, dict^.content, key, value)
+END Insert ;
+
+
+(*
+   InsertNode - insert the key value pair as a new node in the
+                binary tree within dict.
+*)
+
+PROCEDURE InsertNode (dict: Dictionary;
+                      node: Node;
+                      key, value: ADDRESS) : Node ;
+BEGIN
+   IF node = NIL
+   THEN
+      RETURN ConsNode (dict, key, value, NIL, NIL)
+   ELSE
+      CASE dict^.compare (key, node^.key) OF
+
+       0:  HALT |  (* Not expecting to replace a key value.  *)
+      -1:  RETURN ConsNode (dict, node^.key, node^.value,
+                            InsertNode (dict, node^.left,
+                                        key, value), node^.right) |
+      +1:  RETURN ConsNode (dict, node^.key, node^.value,
+                            node^.left,
+                            InsertNode (dict, node^.right,
+                                        key, value))
+      END
+   END
+END InsertNode ;
+
+
+(*
+   ConsNode - return a new node containing the pairing key and value.
+              The new node fields are assigned left, right and dict.
+*)
+
+PROCEDURE ConsNode (dict: Dictionary;
+                    key, value: ADDRESS;
+                    left, right: Node) : Node ;
+VAR
+   node: Node ;
+BEGIN
+   NEW (node) ;
+   node^.key := key ;
+   node^.value := value ;
+   node^.left := left ;
+   node^.right := right ;
+   node^.dict := dict ;
+   RETURN node
+END ConsNode ;
+
+
+(*
+   KeyExist - return TRUE if dictionary contains an entry key.
+              It compares the content and not the address pointer.
+*)
+
+PROCEDURE KeyExist (dict: Dictionary; key: ADDRESS) : BOOLEAN ;
+BEGIN
+   RETURN KeyExistNode (dict^.content, key)
+END KeyExist ;
+
+
+(*
+   KeyExistNode - return TRUE if the binary tree under node contains
+                  key.
+*)
+
+PROCEDURE KeyExistNode (node: Node; key: ADDRESS) : BOOLEAN ;
+BEGIN
+   IF node # NIL
+   THEN
+      CASE node^.dict^.compare (key, node^.key) OF
+
+       0:  RETURN TRUE |
+      -1:  RETURN KeyExistNode (node^.left, key) |
+      +1:  RETURN KeyExistNode (node^.right, key)
+
+      END
+   END ;
+   RETURN FALSE
+END KeyExistNode ;
+
+
+(*
+   Value - return the value from node.
+*)
+
+PROCEDURE Value (node: Node) : ADDRESS ;
+BEGIN
+   RETURN node^.value
+END Value ;
+
+
+(*
+   Key - return the key from node.
+*)
+
+PROCEDURE Key (node: Node) : ADDRESS ;
+BEGIN
+   RETURN node^.value
+END Key ;
+
+
+(*
+   Get - return the value associated with the key or NIL
+         if it does not exist.
+*)
+
+PROCEDURE Get (dict: Dictionary; key: ADDRESS) : ADDRESS ;
+BEGIN
+   RETURN GetNode (dict^.content, key)
+END Get ;
+
+
+(*
+   GetNode - return the value in binary node tree which
+             is associated with key.
+*)
+
+PROCEDURE GetNode (node: Node; key: ADDRESS) : ADDRESS ;
+BEGIN
+   IF node # NIL
+   THEN
+      CASE node^.dict^.compare (key, node^.key) OF
+
+       0: RETURN node^.value |
+      +1: RETURN GetNode (node^.right, key) |
+      -1: RETURN GetNode (node^.left, key)
+
+      END
+   END ;
+   RETURN NIL
+END GetNode ;
+
+
+(*
+   PostOrder - visit each dictionary entry in post order.
+*)
+
+PROCEDURE PostOrder (dict: Dictionary; visit: VisitNode) ;
+BEGIN
+   IF dict # NIL
+   THEN
+      PostOrderNode (dict^.content, visit)
+   END
+END PostOrder ;
+
+
+(*
+   PostOrderNode - visit the tree node in post order.
+*)
+
+PROCEDURE PostOrderNode (node: Node; visit: VisitNode) ;
+BEGIN
+   IF node # NIL
+   THEN
+      PostOrderNode (node^.left, visit) ;
+      PostOrderNode (node^.right, visit) ;
+      visit (node)
+   END
+END PostOrderNode ;
+
+
+END BinDict.
index 91990d710927ba6d85922028db50001dcc50806b..cc27a07703098bff26b86ff4293c25b56dfa2c4e 100644 (file)
@@ -96,8 +96,9 @@ FLAGS_TO_PASS = $(AM_MAKEFLAGS)
 if BUILD_PIMLIB
 toolexeclib_LTLIBRARIES = libm2pim.la
 
-M2MODS = ASCII.mod IO.mod \
-       Args.mod M2RTS.mod \
+M2MODS = ASCII.mod \
+       Args.mod BinDict.mod \
+       IO.mod M2RTS.mod \
        M2Dependent.mod \
        M2Diagnostic.mod \
        M2WIDESET.mod \
@@ -130,7 +131,8 @@ M2MODS = ASCII.mod IO.mod \
 # COROUTINES.mod has been removed as it is implemented in ../libm2iso.
 
 M2DEFS = Args.def   ASCII.def \
-         Assertion.def  Break.def \
+         Assertion.def  BinDict.def \
+         Break.def \
          Builtins.def  cbuiltin.def \
          CmdArgs.def CFileSysOp.def \
          COROUTINES.def \
index 139aec94ec0811e092369e52a44908fbcf11b3c7..33b97bf6554024f6fefe4a74365bc2b6cdd7ba06 100644 (file)
@@ -159,13 +159,13 @@ am__uninstall_files_from_dir = { \
 am__installdirs = "$(DESTDIR)$(toolexeclibdir)"
 LTLIBRARIES = $(toolexeclib_LTLIBRARIES)
 libm2pim_la_LIBADD =
-@BUILD_PIMLIB_TRUE@am__objects_1 = ASCII.lo IO.lo Args.lo M2RTS.lo \
-@BUILD_PIMLIB_TRUE@    M2Dependent.lo M2Diagnostic.lo M2WIDESET.lo \
-@BUILD_PIMLIB_TRUE@    Assertion.lo NumberIO.lo Break.lo SYSTEM.lo \
-@BUILD_PIMLIB_TRUE@    CmdArgs.lo Scan.lo StrCase.lo FIO.lo \
-@BUILD_PIMLIB_TRUE@    StrIO.lo StrLib.lo TimeString.lo \
-@BUILD_PIMLIB_TRUE@    Environment.lo FpuIO.lo Debug.lo \
-@BUILD_PIMLIB_TRUE@    SysStorage.lo Storage.lo StdIO.lo \
+@BUILD_PIMLIB_TRUE@am__objects_1 = ASCII.lo Args.lo BinDict.lo IO.lo \
+@BUILD_PIMLIB_TRUE@    M2RTS.lo M2Dependent.lo M2Diagnostic.lo \
+@BUILD_PIMLIB_TRUE@    M2WIDESET.lo Assertion.lo NumberIO.lo \
+@BUILD_PIMLIB_TRUE@    Break.lo SYSTEM.lo CmdArgs.lo Scan.lo \
+@BUILD_PIMLIB_TRUE@    StrCase.lo FIO.lo StrIO.lo StrLib.lo \
+@BUILD_PIMLIB_TRUE@    TimeString.lo Environment.lo FpuIO.lo \
+@BUILD_PIMLIB_TRUE@    Debug.lo SysStorage.lo Storage.lo StdIO.lo \
 @BUILD_PIMLIB_TRUE@    SEnvironment.lo DynamicStrings.lo SFIO.lo \
 @BUILD_PIMLIB_TRUE@    SArgs.lo SCmdArgs.lo PushBackInput.lo \
 @BUILD_PIMLIB_TRUE@    StringConvert.lo FormatStrings.lo \
@@ -479,8 +479,9 @@ AM_MAKEFLAGS = \
 # Subdir rules rely on $(FLAGS_TO_PASS)
 FLAGS_TO_PASS = $(AM_MAKEFLAGS)
 @BUILD_PIMLIB_TRUE@toolexeclib_LTLIBRARIES = libm2pim.la
-@BUILD_PIMLIB_TRUE@M2MODS = ASCII.mod IO.mod \
-@BUILD_PIMLIB_TRUE@       Args.mod M2RTS.mod \
+@BUILD_PIMLIB_TRUE@M2MODS = ASCII.mod \
+@BUILD_PIMLIB_TRUE@       Args.mod BinDict.mod \
+@BUILD_PIMLIB_TRUE@       IO.mod M2RTS.mod \
 @BUILD_PIMLIB_TRUE@       M2Dependent.mod \
 @BUILD_PIMLIB_TRUE@       M2Diagnostic.mod \
 @BUILD_PIMLIB_TRUE@       M2WIDESET.mod \
@@ -513,7 +514,8 @@ FLAGS_TO_PASS = $(AM_MAKEFLAGS)
 
 # COROUTINES.mod has been removed as it is implemented in ../libm2iso.
 @BUILD_PIMLIB_TRUE@M2DEFS = Args.def   ASCII.def \
-@BUILD_PIMLIB_TRUE@         Assertion.def  Break.def \
+@BUILD_PIMLIB_TRUE@         Assertion.def  BinDict.def \
+@BUILD_PIMLIB_TRUE@         Break.def \
 @BUILD_PIMLIB_TRUE@         Builtins.def  cbuiltin.def \
 @BUILD_PIMLIB_TRUE@         CmdArgs.def CFileSysOp.def \
 @BUILD_PIMLIB_TRUE@         COROUTINES.def \