| (* M2DebugStack.mod display parameter stack. |
| |
| Copyright (C) 2011-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. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU Modula-2; see the file COPYING3. If not see |
| <http://www.gnu.org/licenses/>. *) |
| |
| 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 i<e |
| THEN |
| CASE char(s, i) OF |
| |
| 's': (* symbol number *) |
| INC(i) ; |
| RETURN doSymbol(p, o) | |
| 'd': (* decimal number *) |
| INC(i) ; |
| RETURN doNumber(p, o) | |
| 'a': (* symbol name key *) |
| INC(i) ; |
| RETURN doSymName(p, o) | |
| 'n': (* ascii name key *) |
| INC(i) ; |
| RETURN doName(p, o) |
| |
| ELSE |
| InternalError ("incorrect format specifier expecting one of 's', 'd' or 'a'") |
| END |
| END ; |
| RETURN p |
| END doOperand ; |
| |
| |
| (* |
| doPercent - |
| *) |
| |
| PROCEDURE doPercent (o, s: String; |
| VAR i: INTEGER; e: INTEGER; n: CARDINAL) : String ; |
| BEGIN |
| INC(i) ; |
| IF i<e |
| THEN |
| CASE char(s, i) OF |
| |
| '1': RETURN doOperand(o, s, i, e, OperandT(n)) | |
| '2': RETURN doOperand(o, s, i, e, OperandF(n)) | |
| '3': RETURN doOperand(o, s, i, e, OperandTok(n)) |
| |
| ELSE |
| InternalError ('unrecognised format specifier - expecting 1, 2 or 3 after the %') |
| END |
| END ; |
| InternalError ('end of field found before format specifier - expecting 1, 2 or 3 after the %') |
| END doPercent ; |
| |
| |
| (* |
| doNameLength - increment, l, by the ascii length of string determined by, o. |
| *) |
| |
| PROCEDURE doNameLength (VAR l: CARDINAL; o: WORD) ; |
| VAR |
| s: String ; |
| BEGIN |
| s := InitStringCharStar(KeyToCharStar(o)) ; |
| INC(l, Length(s)) ; |
| s := KillString(s) |
| END doNameLength ; |
| |
| |
| (* |
| doSymNameLength - increment, l, by the ascii length of symbol, o. |
| *) |
| |
| PROCEDURE doSymNameLength (VAR l: CARDINAL; o: WORD) ; |
| VAR |
| s: String ; |
| BEGIN |
| s := InitStringCharStar(KeyToCharStar(GetSymName(o))) ; |
| INC(l, Length(s)) ; |
| s := KillString(s) |
| END doSymNameLength ; |
| |
| |
| (* |
| doNumberLength - convert, o, to a cardinal and increment the length, l, |
| by the number of characters required to represent, o. |
| *) |
| |
| PROCEDURE doNumberLength (VAR l: CARDINAL; o: WORD) ; |
| VAR |
| s: String ; |
| BEGIN |
| s := CardinalToString(VAL(CARDINAL, o), 0, ' ', 10, TRUE) ; |
| INC(l, Length(s)) ; |
| s := KillString(s) |
| END doNumberLength ; |
| |
| |
| (* |
| doSymbolLength - handles a symbol indicated by, o. |
| *) |
| |
| PROCEDURE doSymbolLength (VAR l: CARDINAL; o: WORD) ; |
| VAR |
| s: String ; |
| BEGIN |
| s := symDesc(o, InitString('')) ; |
| INC(l, Length(s)) ; |
| s := KillString(s) |
| END doSymbolLength ; |
| |
| |
| (* |
| doOperandLength - |
| *) |
| |
| PROCEDURE doOperandLength (s: String; VAR i: INTEGER; e: INTEGER; VAR l: CARDINAL; o: WORD) ; |
| BEGIN |
| INC(i) ; |
| IF i<e |
| THEN |
| CASE char(s, i) OF |
| |
| 's': (* symbol number *) |
| INC(i) ; |
| doSymbolLength(l, o) | |
| 'd': (* decimal number *) |
| INC(i) ; |
| doNumberLength(l, o) | |
| 'a': (* ascii name key *) |
| INC(i) ; |
| doSymNameLength(l, o) | |
| 'n': (* ascii name key *) |
| INC(i) ; |
| doNameLength(l, o) |
| |
| ELSE |
| InternalError ("incorrect format specifier expecting one of 's', 'd' or 'a'") |
| END |
| END |
| END doOperandLength ; |
| |
| |
| (* |
| doPercentLength - |
| *) |
| |
| PROCEDURE doPercentLength (s: String; VAR i: INTEGER; e: INTEGER; |
| VAR l: CARDINAL; n: CARDINAL) ; |
| BEGIN |
| INC(i) ; |
| IF i<e |
| THEN |
| CASE char(s, i) OF |
| |
| '1': doOperandLength(s, i, e, l, OperandT(n)) | |
| '2': doOperandLength(s, i, e, l, OperandF(n)) | |
| '3': doOperandLength(s, i, e, l, OperandTok(n)) | |
| |
| ELSE |
| InternalError ('unrecognised format specifier - expecting 1, 2 or 3 after the %') |
| END |
| END |
| END doPercentLength ; |
| |
| |
| (* |
| doFieldLength - compute the string length given in annotation |
| at position, n, on the stack between characters |
| b and e. |
| |
| The string description between: b..e can contain any |
| of these patterns: |
| |
| %a ascii name key. |
| %s symbol number. |
| %d decimal cardinal number. |
| | indicates the next field. |
| *) |
| |
| PROCEDURE doFieldLength (b, e: INTEGER; n: CARDINAL) : CARDINAL ; |
| VAR |
| l: CARDINAL ; |
| i: INTEGER ; |
| s: String ; |
| BEGIN |
| IF b=-1 |
| THEN |
| RETURN( 0 ) |
| END ; |
| s := OperandAnno(n) ; |
| IF e=-1 |
| THEN |
| e := Length(s) |
| END ; |
| l := 0 ; |
| i := b ; |
| WHILE i<e DO |
| CASE char(s, i) OF |
| |
| '|': RETURN l | |
| '%': doPercentLength(s, i, e, l, n) ; |
| |
| ELSE |
| INC(l) |
| END ; |
| INC(i) |
| END ; |
| RETURN l |
| END doFieldLength ; |
| |
| |
| (* |
| stop - |
| *) |
| |
| PROCEDURE stop ; |
| BEGIN |
| END stop ; |
| |
| |
| (* |
| doMaxCard - returns the maximum of two CARDINALs. |
| *) |
| |
| PROCEDURE doMaxCard (a, b: CARDINAL) : CARDINAL ; |
| BEGIN |
| IF (a>100) 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 (i<h) DO |
| IF Index(s, '|', i)>0 |
| THEN |
| DEC(n) ; |
| IF (i<h) AND (char(s, i+1)='|') |
| THEN |
| (* comment seen, no field available *) |
| RETURN -1 |
| END ; |
| i := Index(s, '|', i) |
| ELSE |
| RETURN -1 |
| END ; |
| INC(i) |
| END ; |
| IF i=h |
| THEN |
| i := -1 |
| END ; |
| RETURN i |
| END SkipToField ; |
| |
| |
| (* |
| Pad - padds out string, s, to paddedLength characters. |
| *) |
| |
| PROCEDURE Pad (o: String; paddedLength: CARDINAL) : String ; |
| VAR |
| i: CARDINAL ; |
| BEGIN |
| i := Length(o) ; |
| IF i<paddedLength |
| THEN |
| REPEAT |
| o := ConCatChar(o, ' ') ; |
| INC(i) |
| UNTIL i=paddedLength |
| END ; |
| RETURN o |
| END Pad ; |
| |
| |
| (* |
| doField - compute the string length given in annotation |
| at position, n, on the stack between characters |
| b and e. |
| |
| The string description between: b..e can contain any |
| of these patterns: |
| |
| %a ascii name key. |
| %s symbol number. |
| %d decimal cardinal number. |
| | indicates the next field. |
| *) |
| |
| PROCEDURE doField (s: String; n: CARDINAL; f: CARDINAL; l: CARDINAL) : String ; |
| VAR |
| h, i, j: INTEGER ; |
| o : String ; |
| BEGIN |
| h := Length(s) ; |
| i := SkipToField(s, f) ; |
| o := InitString('') ; |
| IF i>=0 |
| THEN |
| j := SkipToField(s, f+1) ; |
| IF j=-1 |
| THEN |
| j := h |
| END ; |
| WHILE i<h DO |
| CASE char(s, i) OF |
| |
| '|': i := h | |
| '%': o := doPercent(o, s, i, h, n) |
| |
| ELSE |
| o := ConCatChar(o, char(s, i)) ; |
| INC(i) |
| END |
| END |
| END ; |
| o := Pad(o, l) ; |
| RETURN o |
| END doField ; |
| |
| |
| (* |
| doAnnotation - |
| *) |
| |
| PROCEDURE doAnnotation (s: String; n: CARDINAL; |
| field: CARDINAL; width: CARDINAL) : String ; |
| VAR |
| c : INTEGER ; |
| cf, o: String ; |
| BEGIN |
| c := GetComment(s) ; |
| IF c>=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. |