crt.mod

来自「一个Modula-2语言分析器」· MOD 代码 · 共 1,434 行 · 第 1/4 页

MOD
1,434
字号
    (* search lines where symbol has been defined and insert in order *)
    i := 1;
    WHILE i <= lastNt DO (*for all symbols*)
      GetSym(i, sn); p := xList[i].lptr; q := NIL;
      WHILE (p # NIL) & (p^.line > sn.line) DO q := p; p := p^.next END;
      Storage.ALLOCATE(l, SYSTEM.TSIZE(ListNode)); l^.next := p;
      l^.line := -sn.line;
      IF q # NIL THEN q^.next := l ELSE xList[i].lptr := l END;
      IF i = maxP THEN i := firstNt ELSE INC(i) END
    END;

    (* print cross reference listing *)
    FileIO.WriteString(CRS.lst, "Cross reference list:");
    FileIO.WriteLn(CRS.lst); FileIO.WriteLn(CRS.lst);
    FileIO.WriteString(CRS.lst, "Terminals:"); FileIO.WriteLn(CRS.lst);
    FileIO.WriteString(CRS.lst, "  0  EOF"); FileIO.WriteLn(CRS.lst);
    i := 1;
    WHILE i <= lastNt DO (* for all symbols *)
      IF i = maxT THEN
        FileIO.WriteLn(CRS.lst);
        FileIO.WriteString(CRS.lst, "Pragmas:"); FileIO.WriteLn(CRS.lst);
      ELSE
        FileIO.WriteInt(CRS.lst, i, 3); FileIO.WriteString(CRS.lst, "  ");
        FileIO.WriteText(CRS.lst, xList[i].name, 25);
        l := xList[i].lptr; col := 35;
        WHILE l # NIL DO
          IF col + 5 > maxLineLen THEN
            FileIO.WriteLn(CRS.lst); FileIO.WriteText(CRS.lst, "", 30);
            col := 35
          END;
          IF l^.line = 0 THEN FileIO.WriteString(CRS.lst, "undef")
          ELSE FileIO.WriteInt(CRS.lst, l^.line, 5)
          END;
          INC(col, 5);
          l := l^.next
        END;
        FileIO.WriteLn(CRS.lst);
      END;
      IF i = maxP THEN
        FileIO.WriteLn(CRS.lst);
        FileIO.WriteString(CRS.lst, "Nonterminals:");
        FileIO.WriteLn(CRS.lst);
        i := firstNt
      ELSE INC(i)
      END
    END;
    FileIO.WriteLn(CRS.lst); FileIO.WriteLn(CRS.lst);
  END XRef;

(* NewNode              Generate a new graph node and return its index gp
----------------------------------------------------------------------*)
PROCEDURE NewNode (typ, p1, line: INTEGER): INTEGER;
  BEGIN
    INC(nNodes); IF nNodes > maxNodes THEN Restriction(1, maxNodes) END;
    gn^[nNodes].typ     := typ;    gn^[nNodes].next     := 0;
    gn^[nNodes].p1      := p1;     gn^[nNodes].p2       := 0;
    gn^[nNodes].pos.beg := - FileIO.Long1; (* Bugfix - PDT *)
    gn^[nNodes].pos.len := 0;      gn^[nNodes].pos.col := 0;
    gn^[nNodes].line    := line;
    RETURN nNodes;
  END NewNode;

(* CompleteGraph        Set right ends of graph gp to 0
----------------------------------------------------------------------*)
PROCEDURE CompleteGraph (gp: INTEGER);
  VAR
    p: INTEGER;
  BEGIN
    WHILE gp # 0 DO
      p := gn^[gp].next; gn^[gp].next := 0; gp := p
    END
  END CompleteGraph;

(* ConcatAlt            Make (gL2, gR2) an alternative of (gL1, gR1)
----------------------------------------------------------------------*)
PROCEDURE ConcatAlt (VAR gL1, gR1: INTEGER; gL2, gR2: INTEGER);
  VAR
    p: INTEGER;
  BEGIN
    gL2 := NewNode(alt, gL2, 0); p := gL1;
    WHILE gn^[p].p2 # 0 DO p := gn^[p].p2 END;
    gn^[p].p2 := gL2; p := gR1;
    WHILE gn^[p].next # 0 DO p := gn^[p].next END;
    gn^[p].next := gR2
  END ConcatAlt;

(* ConcatSeq            Make (gL2, gR2) a successor of (gL1, gR1)
----------------------------------------------------------------------*)
PROCEDURE ConcatSeq (VAR gL1, gR1: INTEGER; gL2, gR2: INTEGER);
  VAR
    p, q: INTEGER;
  BEGIN
    p := gn^[gR1].next; gn^[gR1].next := gL2; (*head node*)
    WHILE p # 0 DO (*substructure*)
      q := gn^[p].next; gn^[p].next := -gL2; p := q
    END;
    gR1 := gR2
  END ConcatSeq;

(* MakeFirstAlt         Generate alt-node with (gL,gR) as only alternative
----------------------------------------------------------------------*)
PROCEDURE MakeFirstAlt (VAR gL, gR: INTEGER);
  BEGIN
    gL := NewNode(alt, gL, 0); gn^[gL].next := gR; gR := gL
  END MakeFirstAlt;

(* MakeIteration        Enclose (gL, gR) into iteration node
----------------------------------------------------------------------*)
PROCEDURE MakeIteration (VAR gL, gR: INTEGER);
  VAR
    p, q: INTEGER;
  BEGIN
    gL := NewNode(iter, gL, 0); p := gR; gR := gL;
    WHILE p # 0 DO
      q := gn^[p].next; gn^[p].next := - gL; p := q
    END
  END MakeIteration;

(* MakeOption           Enclose (gL, gR) into option node
----------------------------------------------------------------------*)
PROCEDURE MakeOption (VAR gL, gR: INTEGER);
  BEGIN
    gL := NewNode(opt, gL, 0); gn^[gL].next := gR; gR := gL
  END MakeOption;

(* StrToGraph           Generate node chain from characters in s
----------------------------------------------------------------------*)
PROCEDURE StrToGraph (s: ARRAY OF CHAR; VAR gL, gR: INTEGER);
  VAR
    i, len: CARDINAL;
  BEGIN
    gR := 0; i := 1; len := FileIO.SLENGTH(s) - 1; (*strip quotes*)
    WHILE i < len DO
      gn^[gR].next := NewNode(char, ORD(s[i]), 0); gR := gn^[gR].next;
      INC(i)
    END;
    gL := gn^[0].next; gn^[0].next := 0
  END StrToGraph;

(* DelGraph             Check if graph starting with index gp is deletable
----------------------------------------------------------------------*)
PROCEDURE DelGraph (gp: INTEGER): BOOLEAN;
  VAR
    gn: GraphNode;
  BEGIN
    IF gp = 0 THEN RETURN TRUE END; (*end of graph found*)
    GetNode(gp, gn);
    RETURN DelNode(gn) & DelGraph(ABS(gn.next));
  END DelGraph;

(* DelNode              Check if graph node gn is deletable
----------------------------------------------------------------------*)
PROCEDURE DelNode (gn: GraphNode): BOOLEAN;
  VAR
    sn: SymbolNode;

  PROCEDURE DelAlt (gp: INTEGER): BOOLEAN;
    VAR
      gn: GraphNode;
    BEGIN
      IF gp <= 0 THEN RETURN TRUE END; (*end of graph found*)
      GetNode(gp, gn);
      RETURN DelNode(gn) & DelAlt(gn.next);
    END DelAlt;

  BEGIN
    IF gn.typ = nt THEN GetSym(gn.p1, sn); RETURN sn.deletable
    ELSIF gn.typ = alt THEN
      RETURN DelAlt(gn.p1) OR (gn.p2 # 0) & DelAlt(gn.p2)
    ELSE RETURN (gn.typ = eps) OR (gn.typ = iter)
                OR (gn.typ = opt) OR (gn.typ = sem) OR (gn.typ = sync)
    END
  END DelNode;

(* PrintGraph           Print the graph
----------------------------------------------------------------------*)
PROCEDURE PrintGraph;
  VAR
    i: INTEGER;

  PROCEDURE WriteTyp2 (typ: INTEGER);
    BEGIN
      CASE typ OF
        nt  : FileIO.WriteString(CRS.lst, "nt  ")
      | t   : FileIO.WriteString(CRS.lst, "t   ")
      | wt  : FileIO.WriteString(CRS.lst, "wt  ")
      | any : FileIO.WriteString(CRS.lst, "any ")
      | eps : FileIO.WriteString(CRS.lst, "eps ")
      | sem : FileIO.WriteString(CRS.lst, "sem ")
      | sync: FileIO.WriteString(CRS.lst, "sync")
      | alt : FileIO.WriteString(CRS.lst, "alt ")
      | iter: FileIO.WriteString(CRS.lst, "iter")
      | opt : FileIO.WriteString(CRS.lst, "opt ")
      ELSE    FileIO.WriteString(CRS.lst, "--- ")
      END;
    END WriteTyp2;

  BEGIN (* PrintGraph *)
    FileIO.WriteString(CRS.lst, "GraphList:");
    FileIO.WriteLn(CRS.lst); FileIO.WriteLn(CRS.lst);
    FileIO.WriteString(CRS.lst, " nr   typ    next     p1     p2   line");
(* useful for debugging - PDT *)
    FileIO.WriteString(CRS.lst, " posbeg poslen poscol");
(* *)
    FileIO.WriteLn(CRS.lst); FileIO.WriteLn(CRS.lst);
    i := 0;
    WHILE i <= nNodes DO
      FileIO.WriteInt(CRS.lst, i, 3); FileIO.WriteString(CRS.lst, "   ");
      WriteTyp2(gn^[i].typ); FileIO.WriteInt(CRS.lst, gn^[i].next, 7);
      FileIO.WriteInt(CRS.lst, gn^[i].p1, 7);
      FileIO.WriteInt(CRS.lst, gn^[i].p2, 7);
      FileIO.WriteInt(CRS.lst, gn^[i].line, 7);
(* useful for debugging - PDT *)
      FileIO.WriteInt(CRS.lst, FileIO.INTL(gn^[i].pos.beg), 7);
      FileIO.WriteCard(CRS.lst, gn^[i].pos.len, 7);
      FileIO.WriteInt(CRS.lst, gn^[i].pos.col, 7);
(*  *)
      FileIO.WriteLn(CRS.lst);
      INC(i);
    END;
    FileIO.WriteLn(CRS.lst); FileIO.WriteLn(CRS.lst);
  END PrintGraph;

(* FindCircularProductions      Test grammar for circular derivations
----------------------------------------------------------------------*)
PROCEDURE FindCircularProductions (VAR ok: BOOLEAN);
  TYPE
    ListEntry = RECORD
      left: INTEGER;
      right: INTEGER;
      deleted: BOOLEAN;
    END;
  VAR
    changed, onLeftSide,
    onRightSide: BOOLEAN;
    i, j, listLength: INTEGER;
    list: ARRAY [0 .. maxList] OF ListEntry;
    singles: MarkList;
    sn: SymbolNode;

  PROCEDURE GetSingles (gp: INTEGER; VAR singles: MarkList);
    VAR
      gn: GraphNode;
    BEGIN
      IF gp <= 0 THEN RETURN END; (* end of graph found *)
      GetNode (gp, gn);
      IF gn.typ = nt THEN
        IF DelGraph(ABS(gn.next)) THEN Sets.Incl(singles, gn.p1) END
      ELSIF (gn.typ = alt) OR (gn.typ = iter) OR (gn.typ = opt) THEN
        IF DelGraph(ABS(gn.next)) THEN
          GetSingles(gn.p1, singles);
          IF gn.typ = alt THEN GetSingles(gn.p2, singles) END
        END
      END;
      IF DelNode(gn) THEN GetSingles(gn.next, singles) END
    END GetSingles;

  BEGIN (* FindCircularProductions *)
    i := firstNt; listLength := 0;
    WHILE i <= lastNt DO (* for all nonterminals i *)
      ClearMarkList(singles); GetSym(i, sn);
      GetSingles(sn.struct, singles); (* get nt's j such that i-->j *)
      j := firstNt;
      WHILE j <= lastNt DO (* for all nonterminals j *)
        IF Sets.In(singles, j) THEN
          list[listLength].left := i; list[listLength].right := j;
          list[listLength].deleted := FALSE;
          INC(listLength);
          IF listLength > maxList THEN Restriction(9, maxList) END
        END;
        INC(j)
      END;
      INC(i)
    END;

    REPEAT
      i := 0; changed := FALSE;
      WHILE i < listLength DO
        IF ~ list[i].deleted THEN
          j := 0; onLeftSide := FALSE; onRightSide := FALSE;
          WHILE j < listLength DO
            IF ~ list[j].deleted THEN
              IF list[i].left = list[j].right THEN onRightSide := TRUE END;
              IF list[j].left = list[i].right THEN onLeftSide := TRUE END
            END;
            INC(j)
          END;
          IF ~ onRightSide OR ~ onLeftSide THEN
            list[i].deleted := TRUE; changed := TRUE
          END
        END;
        INC(i)
      END
    UNTIL ~ changed;

    FileIO.WriteString(CRS.lst, "Circular derivations:    ");
    i := 0; ok := TRUE;
    WHILE i < listLength DO
      IF ~ list[i].deleted THEN
        ok := FALSE;
        FileIO.WriteLn(CRS.lst); FileIO.WriteString(CRS.lst, "     ");
        GetSym(list[i].left, sn); FileIO.WriteText(CRS.lst, sn.name, 20);
        FileIO.WriteString(CRS.lst, " --> ");
        GetSym(list[i].right, sn); FileIO.WriteText(CRS.lst, sn.name, 20);
      END;
      INC(i)
    END;
    IF ok THEN FileIO.WriteString(CRS.lst, " -- none --") END;
    FileIO.WriteLn(CRS.lst);
  END FindCircularProductions;

(* LL1Test              Collect terminal sets and checks LL(1) conditions
----------------------------------------------------------------------*)
PROCEDURE LL1Test (VAR ll1: BOOLEAN);
  VAR
    sn: SymbolNode;
    curSy: INTEGER;

  PROCEDURE LL1Error (cond, ts: INTEGER);
    VAR
      sn: SymbolNode;
    BEGIN
      ll1 := FALSE;
      FileIO.WriteLn(CRS.lst);
      FileIO.WriteString(CRS.lst, " LL(1) error in ");
      GetSym(curSy, sn); FileIO.WriteString(CRS.lst, sn.name);
      FileIO.WriteString(CRS.lst, ": ");
      IF ts > 0 THEN
        GetSym(ts, sn); FileIO.WriteString(CRS.lst, sn.name);
        FileIO.WriteString(CRS.lst, " is ");
      END;
      CASE cond OF
        1: FileIO.WriteString(CRS.lst,
                  "the start of several alternatives.")
      | 2: FileIO.WriteString(CRS.lst,
                  "the start & successor of a deletable structure")
      | 3: FileIO.WriteString(CRS.lst,
                  "an ANY node that matches no symbol")
      END;
    END LL1Error;

  PROCEDURE Check (cond: INTEGER; VAR s1, s2: Set);
    VAR
      i: INTEGER;
    BEGIN
      i := 0;
      WHILE i <= maxT DO
        IF Sets.In(s1, i) & Sets.In(s2, i) THEN LL1Error(cond, i) END;
        INC(i)
      END
    END Check;

  PROCEDURE CheckAlternatives (gp: INTEGER);
    VAR
      gn, gn1: GraphNode;
      s1, s2: Set;
      p: INTEGER;
    BEGIN
      WHILE gp > 0 DO

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?