(* Copyright (C) 2015-2025 Free Software Foundation, Inc. *)
(* 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.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
. *)
IMPLEMENTATION MODULE mcMetaError ;
FROM nameKey IMPORT Name, keyToCharStar, NulName ;
FROM StrLib IMPORT StrLen ;
FROM mcLexBuf IMPORT getTokenNo ;
FROM mcError IMPORT error, newError, newWarning, errorString, internalError, chainError, flushErrors ;
FROM FIO IMPORT StdOut, WriteLine ;
FROM SFIO IMPORT WriteS ;
FROM StringConvert IMPORT ctos ;
FROM varargs IMPORT vararg ;
IMPORT varargs ;
FROM DynamicStrings IMPORT String, InitString, InitStringCharStar,
ConCat, ConCatChar, Mark, string, KillString,
Dup, char, Length, Mult ;
FROM decl IMPORT node, isType, isTemporary, getType, getSymName, getScope, isDef,
isExported, isZtype, isRtype, skipType, getDeclaredMod, getDeclaredDef,
getFirstUsed, isLiteral, isConst, isConstSet, isArray, isVar,
isEnumeration, isEnumerationField, isUnbounded, isProcType, isProcedure,
isPointer, isParameter, isVarParam, isRecord, isRecordField,
isVarient, isModule, isImp, isSet, isSubrange ;
TYPE
errorType = (newerror, newwarning, chained) ;
(*
ebnf := { percent
| lbra
| any % copy ch %
}
=:
percent := '%' anych % copy anych %
=:
lbra := '{' [ '!' ] percenttoken '}' =:
percenttoken := '%' (
'1' % doOperand(1) %
op
| '2' % doOperand(2) %
op
| '3' % doOperand(3) %
op
| '4' % doOperand(4) %
op
)
} =:
op := {'a'|'q'|'t'|'d'|'n'|'s'|'D'|'I'|'U'|'E'|'W'} then =:
then := [ ':' ebnf ] =:
*)
(*
internalFormat - produces an informative internal error.
*)
PROCEDURE internalFormat (s: String; i: INTEGER; m: ARRAY OF CHAR) ;
VAR
e: error ;
BEGIN
e := newError (getTokenNo()) ;
s := WriteS (StdOut, s) ;
WriteLine (StdOut) ;
s := KillString (s) ;
IF i>0
THEN
DEC(i)
END ;
s := Mult (InitString (' '), i) ;
s := ConCatChar (s, '^') ;
s := WriteS (StdOut, s) ;
WriteLine (StdOut) ;
internalError (m, __FILE__, __LINE__)
END internalFormat ;
(*
x - checks to see that a=b.
*)
PROCEDURE x (a, b: String) : String ;
BEGIN
IF a#b
THEN
internalError('different string returned', __FILE__, __LINE__)
END ;
RETURN a
END x ;
(*
isWhite - returns TRUE if, ch, is a space.
*)
PROCEDURE isWhite (ch: CHAR) : BOOLEAN ;
BEGIN
RETURN ch=' '
END isWhite ;
(*
then := [ ':' ebnf ] =:
*)
PROCEDURE then (VAR e: error; VAR t: errorType;
VAR r: String; s: String;
sym: vararg;
VAR i: INTEGER; l: INTEGER;
o: String; positive: BOOLEAN) ;
BEGIN
IF char (s, i) = ':'
THEN
INC (i) ;
ebnf (e, t, r, s, sym, i, l) ;
IF (i 0
THEN
RETURN o
ELSE
quotes := FALSE ;
varargs.next (sym, bol) ;
varargs.arg (sym, c) ;
RETURN ConCat (o, ctos (c, 0, ' '))
END
END doNumber ;
(*
doCount -
*)
PROCEDURE doCount (bol: CARDINAL;
sym: vararg; o: String;
VAR quotes: BOOLEAN) : String ;
VAR
c: CARDINAL ;
BEGIN
IF Length(o) > 0
THEN
RETURN o
ELSE
quotes := FALSE ;
varargs.next (sym, bol) ;
varargs.arg (sym, c) ;
o := ConCat (o, ctos (c, 0, ' ')) ;
CASE c MOD 100 OF
11..13: o := ConCat (o, Mark (InitString ('th')))
ELSE
CASE c MOD 10 OF
1: o := ConCat (o, Mark (InitString ('st'))) |
2: o := ConCat (o, Mark (InitString ('nd'))) |
3: o := ConCat (o, Mark (InitString ('rd')))
ELSE
o := ConCat (o, Mark (InitString ('th')))
END
END ;
RETURN o
END
END doCount ;
PROCEDURE doAscii (bol: CARDINAL; sym: vararg; o: String) : String ;
VAR
n: node ;
BEGIN
varargs.next (sym, bol) ;
varargs.arg (sym, n) ;
IF (Length (o) > 0) OR isTemporary (n)
THEN
RETURN o
ELSE
RETURN ConCat (o, InitStringCharStar (keyToCharStar (getSymName (n))))
END
END doAscii ;
PROCEDURE doName (bol: CARDINAL; sym: vararg; o: String; VAR quotes: BOOLEAN) : String ;
VAR
n: node ;
BEGIN
varargs.next (sym, bol) ;
varargs.arg (sym, n) ;
IF (Length (o) > 0) OR isTemporary (n)
THEN
RETURN o
ELSE
IF isZtype (n)
THEN
quotes := FALSE ;
RETURN ConCat (o, Mark (InitString ('the ZType')))
ELSIF isRtype (n)
THEN
quotes := FALSE ;
RETURN ConCat (o, Mark (InitString ('the RType')))
ELSIF getSymName (n) # NulName
THEN
RETURN ConCat (o, InitStringCharStar (keyToCharStar (getSymName (n))))
ELSE
RETURN o
END
END
END doName ;
PROCEDURE doQualified (bol: CARDINAL; sym: vararg; o: String) : String ;
VAR
s, n: node ;
mod : vararg ;
BEGIN
varargs.next (sym, bol) ;
varargs.arg (sym, n) ;
IF (Length (o) > 0) OR isTemporary (n)
THEN
RETURN o
ELSE
s := getScope (n) ;
mod := varargs.start1 (s) ;
IF isDef(s) AND isExported(n)
THEN
o := x (o, doAscii (0, mod, o)) ;
o := x (o, ConCatChar (o, '.')) ;
o := x (o, ConCat (o, InitStringCharStar (keyToCharStar (getSymName (n)))))
ELSE
o := x (o, doAscii (bol, sym, o))
END ;
varargs.end (mod) ;
RETURN o
END
END doQualified ;
(*
doType - returns a string containing the type name of
sym. It will skip pseudonym types. It also
returns the type symbol found.
*)
PROCEDURE doType (bol: CARDINAL;
VAR sym: vararg; o: String) : String ;
VAR
n: node ;
BEGIN
varargs.next (sym, bol) ;
varargs.arg (sym, n) ;
IF (Length (o) > 0) OR (getType (n) = NIL)
THEN
RETURN o
ELSE
n := skipType (getType (n)) ;
varargs.next (sym, bol) ;
varargs.replace (sym, n) ;
RETURN x (o, doAscii (bol, sym, o))
END
END doType ;
(*
doSkipType - will skip all pseudonym types. It also
returns the type symbol found and name.
*)
PROCEDURE doSkipType (bol: CARDINAL; VAR sym: vararg; o: String) : String ;
VAR
n: node ;
BEGIN
varargs.next (sym, bol) ;
varargs.arg (sym, n) ;
IF Length (o) > 0
THEN
RETURN o
ELSE
n := skipType (getType (n)) ;
varargs.next (sym, bol) ;
varargs.replace (sym, n) ;
IF getSymName(n) = NulName
THEN
RETURN o
ELSE
RETURN x (o, doAscii (bol, sym, o))
END
END
END doSkipType ;
PROCEDURE doKey (bol: CARDINAL; sym: vararg; o: String) : String ;
VAR
n: Name ;
BEGIN
IF Length (o) > 0
THEN
RETURN o
ELSE
varargs.next (sym, bol) ;
varargs.arg (sym, n) ;
RETURN ConCat (o, InitStringCharStar (keyToCharStar (n)))
END
END doKey ;
(*
doError - creates and returns an error note.
*)
PROCEDURE doError (e: error; t: errorType; tok: CARDINAL) : error ;
BEGIN
CASE t OF
chained: IF e=NIL
THEN
internalError ('should not be chaining an error onto an empty error note', __FILE__, __LINE__)
ELSE
e := chainError (tok, e)
END |
newerror: IF e=NIL
THEN
e := newError (tok)
END |
newwarning: IF e=NIL
THEN
e := newWarning (tok)
END
ELSE
internalError ('unexpected enumeration value', __FILE__, __LINE__)
END ;
RETURN e
END doError ;
(*
doDeclaredDef - creates an error note where sym[bol] was declared.
*)
PROCEDURE doDeclaredDef (e: error; t: errorType;
bol: CARDINAL;
sym: vararg) : error ;
VAR
n: node ;
BEGIN
IF bol <= varargs.nargs (sym)
THEN
varargs.next (sym, bol) ;
varargs.arg (sym, n) ;
e := doError (e, t, getDeclaredDef (n))
END ;
RETURN e
END doDeclaredDef ;
(*
doDeclaredMod - creates an error note where sym[bol] was declared.
*)
PROCEDURE doDeclaredMod (e: error; t: errorType;
bol: CARDINAL;
sym: vararg) : error ;
VAR
n: node ;
BEGIN
IF bol <= varargs.nargs (sym)
THEN
varargs.next (sym, bol) ;
varargs.arg (sym, n) ;
e := doError (e, t, getDeclaredMod (n))
END ;
RETURN e
END doDeclaredMod ;
(*
doUsed - creates an error note where sym[bol] was first used.
*)
PROCEDURE doUsed (e: error; t: errorType;
bol: CARDINAL;
sym: vararg) : error ;
VAR
n: node ;
BEGIN
IF bol <= varargs.nargs (sym)
THEN
varargs.next (sym, bol) ;
varargs.arg (sym, n) ;
e := doError (e, t, getFirstUsed (n))
END ;
RETURN e
END doUsed ;
(*
ConCatWord - joins sentances, a, b, together.
*)
PROCEDURE ConCatWord (a, b: String) : String ;
BEGIN
IF (Length(a) = 1) AND (char (a, 0) = 'a')
THEN
a := x (a, ConCatChar (a, 'n'))
ELSIF (Length(a) > 1) AND (char (a, -1) = 'a') AND isWhite (char (a, -2))
THEN
a := x (a, ConCatChar (a, 'n'))
END ;
IF (Length(a) > 0) AND (NOT isWhite (char (a, -1)))
THEN
a := x (a, ConCatChar (a, ' '))
END ;
RETURN x (a, ConCat (a, b))
END ConCatWord ;
(*
symDesc -
*)
PROCEDURE symDesc (n: node; o: String) : String ;
BEGIN
IF isLiteral (n)
THEN
RETURN ConCatWord (o, Mark (InitString ('literal')))
ELSIF isConstSet (n)
THEN
RETURN ConCatWord (o, Mark (InitString ('constant set')))
(*
ELSIF IsConstructor(n)
THEN
RETURN( ConCatWord (o, Mark (InitString ('constructor'))) )
*)
ELSIF isConst (n)
THEN
RETURN ConCatWord (o, Mark (InitString ('constant')))
ELSIF isArray (n)
THEN
RETURN ConCatWord (o, Mark (InitString ('array')))
ELSIF isVar (n)
THEN
RETURN ConCatWord (o, Mark (InitString ('variable')))
ELSIF isEnumeration (n)
THEN
RETURN ConCatWord (o, Mark (InitString ('enumeration type')))
ELSIF isEnumerationField (n)
THEN
RETURN ConCatWord (o, Mark (InitString ('enumeration field')))
ELSIF isUnbounded (n)
THEN
RETURN ConCatWord (o, Mark (InitString ('unbounded parameter')))
ELSIF isProcType (n)
THEN
RETURN ConCatWord (o, Mark (InitString ('procedure type')))
ELSIF isProcedure (n)
THEN
RETURN ConCatWord (o, Mark (InitString ('procedure')))
ELSIF isPointer (n)
THEN
RETURN ConCatWord (o, Mark (InitString ('pointer')))
ELSIF isParameter (n)
THEN
IF isVarParam (n)
THEN
RETURN ConCatWord (o, Mark (InitString ('var parameter')))
ELSE
RETURN ConCatWord (o, Mark (InitString ('parameter')))
END
ELSIF isType (n)
THEN
RETURN ConCatWord (o, Mark (InitString ('type')))
ELSIF isRecord (n)
THEN
RETURN ConCatWord (o, Mark (InitString ('record')))
ELSIF isRecordField (n)
THEN
RETURN ConCatWord (o, Mark (InitString ('record field')))
ELSIF isVarient (n)
THEN
RETURN ConCatWord (o, Mark (InitString ('varient record')))
ELSIF isModule(n)
THEN
RETURN ConCatWord (o, Mark (InitString ('module')))
ELSIF isDef(n)
THEN
RETURN ConCatWord (o, Mark (InitString ('definition module')))
ELSIF isImp(n)
THEN
RETURN ConCatWord (o, Mark (InitString ('implementation module')))
ELSIF isSet (n)
THEN
RETURN ConCatWord(o, Mark (InitString ('set')))
ELSIF isSubrange (n)
THEN
RETURN ConCatWord(o, Mark (InitString ('subrange')))
ELSE
RETURN o
END
END symDesc ;
(*
doDesc -
*)
PROCEDURE doDesc (bol: CARDINAL;
sym: vararg; o: String;
VAR quotes: BOOLEAN) : String ;
VAR
n: node ;
BEGIN
IF Length (o) = 0
THEN
varargs.next (sym, bol) ;
varargs.arg (sym, n) ;
o := symDesc (n, o) ;
IF Length (o) > 0
THEN
quotes := FALSE
END
END ;
RETURN o
END doDesc ;
(*
addQuoted - if, o, is not empty then add it to, r.
*)
PROCEDURE addQuoted (r, o: String; quotes: BOOLEAN) : String ;
BEGIN
IF Length (o) > 0
THEN
IF NOT isWhite (char (r, -1))
THEN
r := x (r, ConCatChar (r, " "))
END ;
IF quotes
THEN
r := x (r, ConCatChar (r, "'"))
END ;
r := x (r, ConCat (r, o)) ;
IF quotes
THEN
r := x (r, ConCatChar (r, "'"))
END
END ;
RETURN r
END addQuoted ;
(*
op := {'a'|'q'|'t'|'d'|'k'|'n'|'s'|'D'|'I'|'U'|'E'|'W'} then =:
*)
PROCEDURE op (VAR e: error; VAR t: errorType;
VAR r: String; s: String;
sym: vararg;
VAR i: INTEGER; l: INTEGER;
bol: CARDINAL; positive: BOOLEAN) ;
VAR
o : String ;
c : vararg ;
quotes: BOOLEAN ;
BEGIN
c := varargs.copy (sym) ;
o := InitString ('') ;
quotes := TRUE ;
WHILE (i 0) AND (NOT isWhite (char (r, -1)))) OR
(NOT isWhite (char (s, i))))
THEN
r := x (r, ConCatChar (r, char (s, i)))
END
END ;
INC (i)
END
END ebnf ;
(*
doFormat -
*)
PROCEDURE doFormat (VAR e: error; VAR t: errorType;
s: String; sym: vararg) : String ;
VAR
r : String ;
i, l: INTEGER ;
BEGIN
r := InitString ('') ;
i := 0 ;
l := Length (s) ;
ebnf (e, t, r, s, sym, i, l) ;
s := KillString (s) ;
RETURN r
END doFormat ;
PROCEDURE metaErrorStringT1 (tok: CARDINAL; m: String; s: ARRAY OF BYTE) ;
VAR
str: String ;
e : error ;
sym: vararg ;
t : errorType ;
BEGIN
e := NIL ;
sym := varargs.start1 (s) ;
t := newerror ;
str := doFormat (e, t, m, sym) ;
e := doError (e, t, tok) ;
errorString (e, str) ;
varargs.end (sym)
END metaErrorStringT1 ;
PROCEDURE metaErrorT1 (tok: CARDINAL; m: ARRAY OF CHAR; s: ARRAY OF BYTE) ;
BEGIN
metaErrorStringT1 (tok, InitString (m), s)
END metaErrorT1 ;
PROCEDURE metaErrorStringT2 (tok: CARDINAL; m: String; s1, s2: ARRAY OF BYTE) ;
VAR
str: String ;
e : error ;
sym: vararg ;
t : errorType ;
BEGIN
e := NIL ;
sym := varargs.start2 (s1, s2) ;
t := newerror ;
str := doFormat (e, t, m, sym) ;
e := doError (e, t, tok) ;
errorString (e, str) ;
varargs.end (sym)
END metaErrorStringT2 ;
PROCEDURE metaErrorT2 (tok: CARDINAL; m: ARRAY OF CHAR; s1, s2: ARRAY OF BYTE) ;
BEGIN
metaErrorStringT2 (tok, InitString (m), s1, s2)
END metaErrorT2 ;
PROCEDURE metaErrorStringT3 (tok: CARDINAL; m: String; s1, s2, s3: ARRAY OF BYTE) ;
VAR
str: String ;
e : error ;
sym: vararg ;
t : errorType ;
BEGIN
e := NIL ;
sym := varargs.start3 (s1, s2, s3) ;
t := newerror ;
str := doFormat (e, t, m, sym) ;
e := doError (e, t, tok) ;
errorString (e, str) ;
varargs.end (sym)
END metaErrorStringT3 ;
PROCEDURE metaErrorT3 (tok: CARDINAL; m: ARRAY OF CHAR; s1, s2, s3: ARRAY OF BYTE) ;
BEGIN
metaErrorStringT3 (tok, InitString (m), s1, s2, s3)
END metaErrorT3 ;
PROCEDURE metaErrorStringT4 (tok: CARDINAL; m: String; s1, s2, s3, s4: ARRAY OF BYTE) ;
VAR
str: String ;
e : error ;
sym: vararg ;
t : errorType ;
BEGIN
e := NIL ;
sym := varargs.start4 (s1, s2, s3, s4) ;
t := newerror ;
str := doFormat (e, t, m, sym) ;
e := doError (e, t, tok) ;
errorString (e, str) ;
varargs.end (sym)
END metaErrorStringT4 ;
PROCEDURE metaErrorT4 (tok: CARDINAL; m: ARRAY OF CHAR;
s1, s2, s3, s4: ARRAY OF BYTE) ;
BEGIN
metaErrorStringT4 (tok, InitString (m), s1, s2, s3, s4)
END metaErrorT4 ;
PROCEDURE metaError1 (m: ARRAY OF CHAR; s: ARRAY OF BYTE) ;
BEGIN
metaErrorT1 (getTokenNo (), m, s)
END metaError1 ;
PROCEDURE metaError2 (m: ARRAY OF CHAR; s1, s2: ARRAY OF BYTE) ;
BEGIN
metaErrorT2 (getTokenNo (), m, s1, s2)
END metaError2 ;
PROCEDURE metaError3 (m: ARRAY OF CHAR; s1, s2, s3: ARRAY OF BYTE) ;
BEGIN
metaErrorT3 (getTokenNo (), m, s1, s2, s3)
END metaError3 ;
PROCEDURE metaError4 (m: ARRAY OF CHAR; s1, s2, s3, s4: ARRAY OF BYTE) ;
BEGIN
metaErrorT4 (getTokenNo (), m, s1, s2, s3, s4)
END metaError4 ;
(*
wrapErrors -
*)
PROCEDURE wrapErrors (tok: CARDINAL;
m1, m2: ARRAY OF CHAR;
sym: vararg) ;
VAR
e, f: error ;
str : String ;
t : errorType ;
BEGIN
e := NIL ;
t := newerror ;
str := doFormat (e, t, InitString(m1), sym) ;
e := doError (e, t, tok) ;
errorString (e, str) ;
f := e ;
t := chained ;
str := doFormat (f, t, InitString (m2), sym) ;
IF e=f
THEN
t := chained ;
f := doError (e, t, tok)
END ;
errorString (f, str)
END wrapErrors ;
PROCEDURE metaErrorsT1 (tok: CARDINAL; m1, m2: ARRAY OF CHAR; s: ARRAY OF BYTE) ;
VAR
sym: vararg ;
BEGIN
sym := varargs.start1 (s) ;
wrapErrors (tok, m1, m2, sym) ;
varargs.end (sym)
END metaErrorsT1 ;
PROCEDURE metaErrorsT2 (tok: CARDINAL; m1, m2: ARRAY OF CHAR; s1, s2: ARRAY OF BYTE) ;
VAR
sym: vararg ;
BEGIN
sym := varargs.start2 (s1, s2) ;
wrapErrors (tok, m1, m2, sym) ;
varargs.end (sym)
END metaErrorsT2 ;
PROCEDURE metaErrorsT3 (tok: CARDINAL; m1, m2: ARRAY OF CHAR; s1, s2, s3: ARRAY OF BYTE) ;
VAR
sym: vararg ;
BEGIN
sym := varargs.start3 (s1, s2, s3) ;
wrapErrors (tok, m1, m2, sym) ;
varargs.end (sym)
END metaErrorsT3 ;
PROCEDURE metaErrorsT4 (tok: CARDINAL; m1, m2: ARRAY OF CHAR; s1, s2, s3, s4: ARRAY OF BYTE) ;
VAR
sym: vararg ;
BEGIN
sym := varargs.start4 (s1, s2, s3, s4) ;
wrapErrors (tok, m1, m2, sym) ;
varargs.end (sym)
END metaErrorsT4 ;
PROCEDURE metaErrors1 (m1, m2: ARRAY OF CHAR; s: ARRAY OF BYTE) ;
BEGIN
metaErrorsT1 (getTokenNo (), m1, m2, s)
END metaErrors1 ;
PROCEDURE metaErrors2 (m1, m2: ARRAY OF CHAR; s1, s2: ARRAY OF BYTE) ;
BEGIN
metaErrorsT2 (getTokenNo (), m1, m2, s1, s2)
END metaErrors2 ;
PROCEDURE metaErrors3 (m1, m2: ARRAY OF CHAR; s1, s2, s3: ARRAY OF BYTE) ;
BEGIN
metaErrorsT3 (getTokenNo (), m1, m2, s1, s2, s3)
END metaErrors3 ;
PROCEDURE metaErrors4 (m1, m2: ARRAY OF CHAR; s1, s2, s3, s4: ARRAY OF BYTE) ;
BEGIN
metaErrorsT4 (getTokenNo (), m1, m2, s1, s2, s3, s4)
END metaErrors4 ;
PROCEDURE metaErrorString1 (m: String; s: ARRAY OF BYTE) ;
BEGIN
metaErrorStringT1 (getTokenNo (), m, s)
END metaErrorString1 ;
PROCEDURE metaErrorString2 (m: String; s1, s2: ARRAY OF BYTE) ;
BEGIN
metaErrorStringT2 (getTokenNo (), m, s1, s2)
END metaErrorString2 ;
PROCEDURE metaErrorString3 (m: String; s1, s2, s3: ARRAY OF BYTE) ;
BEGIN
metaErrorStringT3 (getTokenNo (), m, s1, s2, s3)
END metaErrorString3 ;
PROCEDURE metaErrorString4 (m: String; s1, s2, s3, s4: ARRAY OF BYTE) ;
BEGIN
metaErrorStringT4 (getTokenNo (), m, s1, s2, s3, s4)
END metaErrorString4 ;
END mcMetaError.