crt.mod

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

MOD
1,434
字号
IMPLEMENTATION MODULE CRT;

(* CRT   Table Handler
   ===   =============

  (1) handles a symbol table for terminals, pragmas and nonterminals
  (2) handles a table for character classes (for scanner generation)
  (3) handles a top-down graph for productions
  (4) computes various sets (start symbols, followers, any sets)
  (5) contains procedures for grammar tests

  --------------------------------------------------------------------*)

IMPORT CRS, FileIO, Sets, Storage;
IMPORT SYSTEM (* for TSIZE only *);

CONST
  maxSetNr   = 256;  (* max. number of symbol sets *)
(* moved next declaration to def module Fri  08-20-1993, and was 150
  maxClasses = 250;  (* max. number of character classes *) *)
  maxNames   = 100;  (* max. number of declared token names *)

TYPE
  FirstSets   = ARRAY [0 .. maxNt] OF RECORD
    ts:    Set;      (* terminal symbols *)
    ready: BOOLEAN;  (* TRUE = ts is complete *)
  END;
  FollowSets  = ARRAY [0 .. maxNt] OF RECORD
    ts:  Set;        (* terminal symbols *)
    nts: Set;        (* nts whose start set is to be included in ts *)
  END;
  CharClass   = RECORD
    name: Name;      (* class name *)
    set:  INTEGER    (* ptr to set representing the class *)
  END;
  SymbolTable = ARRAY [0 .. maxSymbols] OF SymbolNode;
  ClassTable  = ARRAY [0 .. maxClasses] OF CharClass;
  GraphList   = ARRAY [0 .. maxNodes] OF GraphNode;
  SymbolSet   = ARRAY [0 .. maxSetNr] OF Set;
  NameTable   = ARRAY [1 .. maxNames] OF RECORD name, definition: Name END;

VAR
  (* moved symbol table to the heap Fri  08-20-1993 to allow larger one *)
  st:        POINTER TO SymbolTable; (* symbol table for terminals,
                                         pragmas, and nonterminals *)
  gn:        POINTER TO GraphList; (* top-down graph *)
  tt:        NameTable;   (* table of token name declarations *)
  first:     FirstSets;   (* first[i]  = first symbols of st[i+firstNt] *)
  follow:    FollowSets;  (* follow[i] = followers of st[i+firstNt] *)
  chClass:   ClassTable;  (* character classes *)
  set:       SymbolSet;   (* set[0] = all SYNC symbols *)
  maxSet:    INTEGER;     (* index of last symbol set *)
  lastName,
  dummyName: CARDINAL;    (* for unnamed character classes *)
  ch:        CHAR;


(* Restriction          Implementation restriction
----------------------------------------------------------------------*)
PROCEDURE Restriction (n, limit: INTEGER);
(* Fri  08-20-1993 extended *)
  BEGIN
    FileIO.WriteLn(FileIO.StdOut);
    FileIO.WriteString(FileIO.StdOut, "Restriction  ");
    FileIO.WriteInt(FileIO.StdOut, n, 1); FileIO.WriteLn(FileIO.StdOut);
    CASE n OF
      1  : FileIO.WriteString(FileIO.StdOut, "Too many graph nodes")
    | 2  : FileIO.WriteString(FileIO.StdOut, "Too many symbols")
    | 3  : FileIO.WriteString(FileIO.StdOut, "Too many sets")
    | 4  : FileIO.WriteString(FileIO.StdOut, "Too many character classes")
    | 5  : FileIO.WriteString(FileIO.StdOut, "Too many symbol sets")
    | 6  : FileIO.WriteString(FileIO.StdOut, "Too many token names")
    | 7  : FileIO.WriteString(FileIO.StdOut, "Too many states")
    | 8  : FileIO.WriteString(FileIO.StdOut, "Semantic text buffer overflow")
    | 9  : FileIO.WriteString(FileIO.StdOut, "Circular check buffer overflow")
    | 10 : FileIO.WriteString(FileIO.StdOut, "Too many literal terminals")
    | -1 : FileIO.WriteString(FileIO.StdOut, "Compiler error")
    END;
    IF n > 0 THEN
      FileIO.WriteString(FileIO.StdOut, " (limited to ");
      FileIO.WriteInt(FileIO.StdOut, limit, 1);
      FileIO.Write(FileIO.StdOut, ")");
    END;
(* maybe we want CRX.WriteStatistics; *)
    FileIO.QuitExecution
  END Restriction;

(* MovePragmas          Move pragmas after terminals
----------------------------------------------------------------------*)
PROCEDURE MovePragmas;
  VAR
    i: INTEGER;
  BEGIN
    IF maxP > firstNt THEN
      i := maxSymbols - 1; maxP := maxT;
      WHILE i > lastNt DO
        INC(maxP); IF maxP >= firstNt THEN Restriction(2, maxSymbols) END;
        st^[maxP] := st^[i]; DEC(i)
      END;
    END
  END MovePragmas;

(* ClearMarkList        Clear mark list m
----------------------------------------------------------------------*)
PROCEDURE ClearMarkList (VAR m: MarkList);
  VAR
    i: INTEGER;
  BEGIN
    i := 0;
    WHILE i < maxNodes DIV Sets.size DO m[i] := BITSET{}; INC(i) END;
  END ClearMarkList;

(* GetNode              Get node with index gp in n
----------------------------------------------------------------------*)
PROCEDURE GetNode (gp: INTEGER; VAR n: GraphNode);
  BEGIN
    n := gn^[gp]
  END GetNode;

(* PutNode              Replace node with index gp by n
----------------------------------------------------------------------*)
PROCEDURE PutNode (gp: INTEGER; n: GraphNode);
  BEGIN
    gn^[gp] := n
  END PutNode;

(* NewName              Collects a user defined token name
----------------------------------------------------------------------*)
PROCEDURE NewName (n: Name; s: ARRAY OF CHAR);
  BEGIN
    IF lastName = maxNames THEN Restriction(6, maxNames)
    ELSE
      INC(lastName); symNames := TRUE;
      tt[lastName].name := n; FileIO.Assign(s, tt[lastName].definition);
    END;
  END NewName;

(* NewSym               Generate a new symbol and return its index
----------------------------------------------------------------------*)
PROCEDURE NewSym (typ: INTEGER; name: Name; line: INTEGER): INTEGER;
  VAR
    i: INTEGER;
  BEGIN
    IF maxT + 1 = firstNt THEN Restriction(2, maxSymbols)
    ELSE
      CASE typ OF
        t:  INC(maxT); i := maxT;
      | pr: DEC(maxP); DEC(firstNt); DEC(lastNt); i := maxP;
      | nt, unknown: DEC(firstNt); i := firstNt;
      END;
      IF maxT + 1 >= firstNt THEN Restriction(2, maxSymbols) END;
      st^[i].typ := typ; st^[i].name := name;
      st^[i].constant := ""; (* Bug fix - PDT *)
      st^[i].struct := 0;  st^[i].deletable := FALSE;
      st^[i].attrPos.beg := - FileIO.Long1;
      st^[i].semPos.beg  := - FileIO.Long1;
      st^[i].line := line;
    END;
    RETURN i;
  END NewSym;

(* GetSym               Get symbol sp in sn
----------------------------------------------------------------------*)
PROCEDURE GetSym (sp: INTEGER; VAR sn: SymbolNode);
  BEGIN
    sn := st^[sp]
  END GetSym;

(* PutSym               Replace symbol with index snix by sn
----------------------------------------------------------------------*)
PROCEDURE PutSym (sp: INTEGER; sn: SymbolNode);
  BEGIN
    st^[sp] := sn
  END PutSym;

(* FindSym              Find index of symbol with name n
----------------------------------------------------------------------*)
PROCEDURE FindSym (n: Name): INTEGER;
  VAR
    i: INTEGER;
  BEGIN
    i := 0; (*search in terminal list*)
    WHILE (i <= maxT) & (FileIO.Compare(st^[i].name, n) # 0) DO
      INC(i)
    END;
    IF i <= maxT THEN RETURN i END;
    i := firstNt; (*search in nonterminal/pragma list*)
    WHILE (i < maxSymbols) & (FileIO.Compare(st^[i].name, n) # 0) DO
      INC(i)
    END;
    IF i < maxSymbols THEN RETURN i ELSE RETURN noSym END
  END FindSym;

(* PrintSet             Print set s
----------------------------------------------------------------------*)
PROCEDURE PrintSet (f: FileIO.File; s: ARRAY OF BITSET; indent: INTEGER);
  CONST
    maxLineLen = 80;
  VAR
    col, i, len: INTEGER;
    empty: BOOLEAN;
    sn: SymbolNode;
  BEGIN
    i := 0; col := indent; empty := TRUE;
    WHILE i <= maxT DO
      IF Sets.In(s, i) THEN
        empty := FALSE; GetSym(i, sn); len := FileIO.SLENGTH(sn.name);
        IF col + len + 2 > maxLineLen THEN
          FileIO.WriteLn(f); col := 1;
          WHILE col < indent DO FileIO.Write(f, " "); INC(col) END
        END;
        FileIO.WriteString(f, sn.name);
        FileIO.WriteString(f, "  ");
        INC(col, len + 2)
      END;
      INC(i)
    END;
    IF empty THEN FileIO.WriteString(f, "-- empty set --") END;
    FileIO.WriteLn(f)
  END PrintSet;

(* NewSet               Stores s as a new set and return its index
----------------------------------------------------------------------*)
PROCEDURE NewSet (s: Set): INTEGER;
(*any-set computation requires not to search if s is already in set*)
  BEGIN
    INC(maxSet); IF maxSet > maxSetNr THEN Restriction(3, maxSetNr) END;
    set[maxSet] := s; RETURN maxSet
  END NewSet;

(* CompFirstSet         Compute first symbols of (sub) graph at gp
----------------------------------------------------------------------*)
PROCEDURE CompFirstSet (gp: INTEGER; VAR fs: Set);
  VAR
    visited: MarkList;

  PROCEDURE CompFirst (gp: INTEGER; VAR fs: Set);
    VAR
      s: Set;
      gn: GraphNode;
      sn: SymbolNode;
    BEGIN
      Sets.Clear(fs);
      WHILE (gp # 0) & ~ Sets.In(visited, gp) DO
        GetNode(gp, gn); Sets.Incl(visited, gp);
        CASE gn.typ OF
          nt:
            IF first[gn.p1 - firstNt].ready THEN
              Sets.Unite(fs, first[gn.p1 - firstNt].ts);
            ELSE
              GetSym(gn.p1, sn);
              CompFirst(sn.struct, s); Sets.Unite(fs, s);
            END;
        | t, wt:
            Sets.Incl(fs, gn.p1);
        | any:
            Sets.Unite(fs, set[gn.p1])
        | alt, iter, opt:
            CompFirst(gn.p1, s); Sets.Unite(fs, s);
            IF gn.typ = alt THEN CompFirst(gn.p2, s); Sets.Unite(fs, s) END
        ELSE (* eps, sem, sync, ind: nothing *)
        END;
        IF ~ DelNode(gn) THEN RETURN END;
        gp := ABS(gn.next)
       END
    END CompFirst;

  BEGIN (* ComputeFirstSet *)
    ClearMarkList(visited);
    CompFirst(gp, fs);
    IF ddt["I"] THEN
      FileIO.WriteLn(FileIO.StdOut);
      FileIO.WriteString(FileIO.StdOut, "ComputeFirstSet: gp = ");
      FileIO.WriteInt(FileIO.StdOut, gp, 1);
      FileIO.WriteLn(FileIO.StdOut);
      PrintSet(FileIO.StdOut, fs, 0);
    END;
  END CompFirstSet;

(* CompFirstSets        Compute first symbols of nonterminals
----------------------------------------------------------------------*)
PROCEDURE CompFirstSets;
  VAR
    i: INTEGER;
    sn: SymbolNode;
  BEGIN
    i := firstNt;
    WHILE i <= lastNt DO first[i - firstNt].ready := FALSE; INC(i) END;
    i := firstNt;
    WHILE i <= lastNt DO (* for all nonterminals *)
      GetSym(i, sn); CompFirstSet(sn.struct, first[i - firstNt].ts);
      first[i - firstNt].ready := TRUE;
      INC(i)
    END;
  END CompFirstSets;

(* CompExpected     Compute symbols expected at location gp in Symbol sp
----------------------------------------------------------------------*)
PROCEDURE CompExpected (gp, sp: INTEGER; VAR exp: Set);
  BEGIN
    CompFirstSet(gp, exp);
    IF DelGraph(gp) THEN Sets.Unite(exp, follow[sp - firstNt].ts) END
  END CompExpected;

(* CompFollowSets       Get follow symbols of nonterminals
----------------------------------------------------------------------*)
PROCEDURE CompFollowSets;
  VAR
    sn: SymbolNode;
    curSy, i, size: INTEGER;
    visited: MarkList;

  PROCEDURE CompFol (gp: INTEGER);
    VAR
      s: Set;
      gn: GraphNode;
    BEGIN
      WHILE (gp > 0) & ~ Sets.In(visited, gp) DO
        GetNode(gp, gn); Sets.Incl(visited, gp);
        IF gn.typ = nt THEN
          CompFirstSet(ABS(gn.next), s);
          Sets.Unite(follow[gn.p1 - firstNt].ts, s);
          IF DelGraph(ABS(gn.next)) THEN
            Sets.Incl(follow[gn.p1 - firstNt].nts, curSy - firstNt)
          END
        ELSIF (gn.typ=opt) OR (gn.typ=iter) THEN CompFol(gn.p1)
        ELSIF gn.typ = alt THEN CompFol(gn.p1); CompFol(gn.p2)
        END;
        gp := gn.next
      END
    END CompFol;

  PROCEDURE Complete (i: INTEGER);
    VAR
      j: INTEGER;
    BEGIN
      IF Sets.In(visited, i) THEN RETURN END;
      Sets.Incl(visited, i);
      j := 0;
      WHILE j <= lastNt - firstNt DO (* for all nonterminals *)
        IF Sets.In(follow[i].nts, j) THEN
          Complete(j); Sets.Unite(follow[i].ts, follow[j].ts);
          (* fix 1.42 *) IF i = curSy THEN Sets.Excl(follow[i].nts, j) END
        END;
        INC(j)
      END;
    END Complete;

  BEGIN (* GetFollowSets *)
    size := (lastNt - firstNt + 2) DIV Sets.size;
    curSy := firstNt;
    WHILE curSy <= lastNt DO
      Sets.Clear(follow[curSy - firstNt].ts);
      i := 0;
      WHILE i <= size DO
        follow[curSy - firstNt].nts[i] := BITSET{}; INC(i)
      END;
      INC(curSy)
    END;

⌨️ 快捷键说明

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