(* M2DebugStack.mod display parameter stack. Copyright (C) 2011-2024 Free Software Foundation, Inc. Contributed by Gaius Mulley . 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 GNU Modula-2; see the file COPYING3. If not see . *) IMPLEMENTATION MODULE M2DebugStack ; FROM DynamicStrings IMPORT InitString, KillString, Dup, Index, Slice, char, ConCat, ConCatChar, InitStringCharStar, Length, Mark ; FROM SymbolTable IMPORT IsConstLit, IsConstSet, IsConstructor, IsConst, IsArray, IsVar, IsEnumeration, IsFieldEnumeration, IsUnbounded, IsProcType, IsProcedure, IsPointer, IsParameter, IsParameterVar, IsType, IsRecord, IsRecordField, IsVarient, IsModule, IsDefImp, IsSet, IsSubrange, GetSymName, NulSym ; FROM StringConvert IMPORT CardinalToString ; FROM NameKey IMPORT Name, KeyToCharStar ; FROM FIO IMPORT File, StdOut ; FROM SFIO IMPORT WriteS ; FROM M2Error IMPORT InternalError ; FROM M2Printf IMPORT printf0, printf1, printf2, printf3, printf4 ; CONST Debugging = FALSE ; VAR OperandTok, OperandT, OperandF, OperandA, OperandD, OperandRW : ProcedureWord ; OperandAnno: ProcedureString ; (* x - checks to see that a=b. *) PROCEDURE x (a, b: String) : String ; BEGIN IF a#b THEN InternalError ('different string returned') END ; RETURN( a ) END x ; (* IsWhite - returns TRUE if, ch, is a space. *) PROCEDURE IsWhite (ch: CHAR) : BOOLEAN ; BEGIN RETURN( ch=' ' ) END IsWhite ; (* 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 (sym: CARDINAL; o: String) : String ; BEGIN IF sym = NulSym THEN RETURN( ConCatWord(o, Mark(InitString('NulSym'))) ) ELSIF IsConstLit(sym) THEN RETURN( ConCatWord(o, Mark(InitString('constant literal'))) ) ELSIF IsConstSet(sym) THEN RETURN( ConCatWord(o, Mark(InitString('constant set'))) ) ELSIF IsConstructor(sym) THEN RETURN( ConCatWord(o, Mark(InitString('constructor'))) ) ELSIF IsConst(sym) THEN RETURN( ConCatWord(o, Mark(InitString('constant'))) ) ELSIF IsArray(sym) THEN RETURN( ConCatWord(o, Mark(InitString('array'))) ) ELSIF IsVar(sym) THEN RETURN( ConCatWord(o, Mark(InitString('variable'))) ) ELSIF IsEnumeration(sym) THEN RETURN( ConCatWord(o, Mark(InitString('enumeration type'))) ) ELSIF IsFieldEnumeration(sym) THEN RETURN( ConCatWord(o, Mark(InitString('enumeration field'))) ) ELSIF IsUnbounded(sym) THEN RETURN( ConCatWord(o, Mark(InitString('unbounded parameter'))) ) ELSIF IsProcType(sym) THEN RETURN( ConCatWord(o, Mark(InitString('procedure type'))) ) ELSIF IsProcedure(sym) THEN RETURN( ConCatWord(o, Mark(InitString('procedure'))) ) ELSIF IsPointer(sym) THEN RETURN( ConCatWord(o, Mark(InitString('pointer'))) ) ELSIF IsParameter(sym) THEN IF IsParameterVar(sym) THEN RETURN( ConCatWord(o, Mark(InitString('var parameter'))) ) ELSE RETURN( ConCatWord(o, Mark(InitString('parameter'))) ) END ELSIF IsType(sym) THEN RETURN( ConCatWord(o, Mark(InitString('type'))) ) ELSIF IsRecord(sym) THEN RETURN( ConCatWord(o, Mark(InitString('record'))) ) ELSIF IsRecordField(sym) THEN RETURN( ConCatWord(o, Mark(InitString('record field'))) ) ELSIF IsVarient(sym) THEN RETURN( ConCatWord(o, Mark(InitString('varient record'))) ) ELSIF IsModule(sym) THEN RETURN( ConCatWord(o, Mark(InitString('module'))) ) ELSIF IsDefImp(sym) THEN RETURN( ConCatWord(o, Mark(InitString('definition or implementation module'))) ) ELSIF IsSet(sym) THEN RETURN( ConCatWord(o, Mark(InitString('set'))) ) ELSIF IsSubrange(sym) THEN RETURN( ConCatWord(o, Mark(InitString('subrange'))) ) ELSE RETURN( o ) END END symDesc ; (* Output - output string, s, to Stdout. It also disposes of the string, s. *) PROCEDURE Output (s: String) ; BEGIN s := WriteS(StdOut, s) ; s := KillString(s) END Output ; (* GetComment - *) PROCEDURE GetComment (s: String) : INTEGER ; VAR c: INTEGER ; BEGIN c := Index(s, '|', 0) ; WHILE c>=0 DO INC(c) ; IF c>=VAL(INTEGER, Length(s)) THEN RETURN -1 ELSIF char(s, c)='|' THEN RETURN c+1 END ; c := Index(s, '|', c) END ; RETURN -1 END GetComment ; (* doName - concatenate namekey, o, to, p. *) PROCEDURE doName (p: String; o: WORD) : String ; BEGIN RETURN ConCat(p, InitStringCharStar(KeyToCharStar(o))) ; END doName ; (* doSymName - concatenate symbol, o, name to, p. *) PROCEDURE doSymName (p: String; o: WORD) : String ; BEGIN RETURN ConCat(p, InitStringCharStar(KeyToCharStar(GetSymName(o)))) ; END doSymName ; (* doNumber - convert, o, to a cardinal and increment the length, l, by the number of characters required to represent, o. *) PROCEDURE doNumber (p: String; o: WORD) : String ; BEGIN RETURN ConCat(p, CardinalToString(VAL(CARDINAL, o), 0, ' ', 10, TRUE)) END doNumber ; (* doSymbol - handles a symbol indicated by, o. *) PROCEDURE doSymbol (p: String; o: WORD) : String ; BEGIN RETURN symDesc(o, p) END doSymbol ; (* doOperand - *) PROCEDURE doOperand (p, s: String; VAR i: INTEGER; e: INTEGER; o: WORD) : String ; BEGIN INC(i) ; IF i100) OR (b>100) THEN stop END ; IF a>b THEN RETURN a ELSE RETURN b END END doMaxCard ; (* GetAnnotationFieldLength - *) PROCEDURE GetAnnotationFieldLength (n: CARDINAL; f: CARDINAL) : CARDINAL ; VAR c, e: INTEGER ; BEGIN c := GetComment(OperandAnno(n)) ; IF c>0 THEN IF Debugging THEN printf0('full anno is: ') ; Output(Dup(OperandAnno(n))) ; printf0('\n') ; printf0('comment field is: ') ; Output(Slice(OperandAnno(n), c, 0)) ; printf0('\n') END ; e := Index(OperandAnno(n), '|', c) ; IF f=0 THEN RETURN doFieldLength(c, e, n) ELSE IF e>=0 THEN INC(e) END ; RETURN doFieldLength(e, -1, n) END ELSE RETURN 0 END END GetAnnotationFieldLength ; (* GetAnnotationLength - *) PROCEDURE GetAnnotationLength (n: CARDINAL; f: CARDINAL) : CARDINAL ; VAR l: CARDINAL ; BEGIN IF OperandAnno(n)=NIL THEN l := 0 ; IF f=0 THEN doNumberLength(l, OperandT(n)) ELSE doNumberLength(l, OperandF(n)) END ; RETURN l ELSE RETURN GetAnnotationFieldLength(n, f) END END GetAnnotationLength ; (* GetFieldLength - returns the number of characters used in field, f, at position, n, on the stack. *) PROCEDURE GetFieldLength (n: CARDINAL; f: CARDINAL) : CARDINAL ; VAR c, b, e: INTEGER ; BEGIN c := GetComment(OperandAnno(n)) ; IF c>1 THEN e := c-2 ELSE e := Length(OperandAnno(n)) END ; IF f=0 THEN b := 0 ELSE b := Index(OperandAnno(n), '|', 0) ; IF b=-1 THEN RETURN 0 ELSE INC(b) END END ; RETURN doFieldLength(b, e, n) END GetFieldLength ; (* GetMaxFieldAnno - returns the maximum number of characters required by either the annotation or field, f, at position, n, on the stack. *) PROCEDURE GetMaxFieldAnno (n: CARDINAL; f: CARDINAL) : CARDINAL ; BEGIN RETURN doMaxCard(GetAnnotationLength(n, f), GetFieldLength(n, f)) END GetMaxFieldAnno ; (* GetStackFieldLengths - assigns, tn, and, fn, with the maximum field width values. *) PROCEDURE GetStackFieldLengths (VAR tn, fn, tk: CARDINAL; amount: CARDINAL) ; VAR i: CARDINAL ; BEGIN i := 1 ; tn := 0 ; fn := 0 ; tk := 0 ; WHILE i<=amount DO tn := doMaxCard(tn, GetMaxFieldAnno(i, 0)) ; fn := doMaxCard(fn, GetMaxFieldAnno(i, 1)) ; tk := doMaxCard(tk, GetMaxFieldAnno(i, 2)) ; INC(i) END END GetStackFieldLengths ; (* DisplayRow - *) PROCEDURE DisplayRow (tn, fn, tk: CARDINAL; initOrFinal: BOOLEAN) ; VAR i: CARDINAL ; BEGIN printf0('+-') ; FOR i := 1 TO tn DO printf0('-') END ; IF (fn=0) AND (tk=0) THEN IF initOrFinal THEN printf0('-+-') ELSE printf0('-|-') END ELSE IF initOrFinal THEN printf0('-+-') ELSE printf0('-|-') END ; IF fn#0 THEN FOR i := 1 TO fn DO printf0('-') END END ; IF initOrFinal THEN printf0('-+-') ELSE printf0('-|-') END ; IF tk#0 THEN FOR i := 1 TO tk DO printf0('-') END ; printf0('-+\n') END END END DisplayRow ; (* SkipToField - *) PROCEDURE SkipToField (s: String; n: CARDINAL) : INTEGER ; VAR i, h: INTEGER ; BEGIN i := 0 ; h := Length(s) ; WHILE (n>0) AND (i0 THEN DEC(n) ; IF (i=0 THEN j := SkipToField(s, f+1) ; IF j=-1 THEN j := h END ; WHILE i=0 THEN cf := Slice(s, c, 0) ; o := doField(cf, n, field, width) ; cf := KillString(cf) ; RETURN o ELSE RETURN InitString('') END END doAnnotation ; (* DisplayFields - *) PROCEDURE DisplayFields (n: CARDINAL; tn, fn, tk: CARDINAL) ; VAR s : String ; t, f, k: CARDINAL ; BEGIN s := OperandAnno(n) ; IF s=NIL THEN t := OperandT(n) ; f := OperandF(n) ; k := OperandTok(n) ; printf0('| ') ; Output(Pad(CardinalToString(VAL(CARDINAL, t), 0, ' ', 10, TRUE), tn)) ; printf0(' | ') ; Output(Pad(CardinalToString(VAL(CARDINAL, f), 0, ' ', 10, TRUE), fn)) ; printf0(' | ') ; Output(Pad(CardinalToString(VAL(CARDINAL, k), 0, ' ', 10, TRUE), tk)) ; printf0(' |\n') ELSE IF tn>0 THEN printf0('| ') ; Output(doField(s, n, 0, tn)) END ; IF fn>0 THEN printf0(' | ') ; Output(doField(s, n, 1, fn)) END ; IF tk>0 THEN printf0(' | ') ; Output(doField(s, n, 2, tk)) END ; printf0(' |\n') ; IF tn>0 THEN printf0('| ') ; Output(doAnnotation(s, n, 0, tn)) END ; IF fn>0 THEN printf0(' | ') ; Output(doAnnotation(s, n, 1, fn)) END ; IF tk>0 THEN printf0(' | ') ; Output(doAnnotation(s, n, 2, tk)) END ; printf0(' |\n') END END DisplayFields ; (* DebugStack - displays the stack. *) PROCEDURE DebugStack (amount: CARDINAL; opt, opf, opa, opd, oprw, optk: ProcedureWord; opanno: ProcedureString) ; VAR i : CARDINAL ; tn, fn, tk: CARDINAL ; BEGIN OperandT := opt ; OperandF := opf ; OperandA := opa ; OperandD := opd ; OperandRW := oprw ; OperandAnno := opanno ; OperandTok := optk ; GetStackFieldLengths(tn, fn, tk, amount) ; i := 1 ; WHILE i<=amount DO IF i=1 THEN DisplayRow(tn, fn, tk, TRUE) END ; DisplayFields(i, tn, fn, tk) ; DisplayRow(tn, fn, tk, i=amount) ; INC(i) END END DebugStack ; END M2DebugStack.