crp.mod

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

MOD
820
字号
IMPLEMENTATION MODULE CRP;

(* Parser generated by Coco/R - assuming FileIO library will be available. *)

IMPORT FileIO, CRS;

IMPORT CRT, CRA, Sets;

CONST
  ident = 0; string = 1;  (* symbol kind *)
TYPE
  INT32 = FileIO.INT32;

PROCEDURE FixString (VAR name: ARRAY OF CHAR; len: CARDINAL);
  VAR
    double, spaces: BOOLEAN;
    i: CARDINAL;
  BEGIN
    IF len = 2 THEN SemError(129); RETURN END;
    IF CRT.ignoreCase THEN (* force uppercase *)
      FOR i := 1 TO len - 2 DO name[i] := CAP(name[i]) END
    END;
    double := FALSE; spaces := FALSE;
    FOR i := 1 TO len - 2 DO (* search for interior " or spaces *)
      IF name[i] = '"' THEN double := TRUE END;
      IF name[i] <= ' ' THEN spaces := TRUE END;
    END;
    IF ~ double THEN (* force delimiters to be " quotes *)
      name[0] := '"'; name[len-1] := '"'
    END;
    IF spaces THEN SemError(124) END;
  END FixString;

PROCEDURE MatchLiteral (sp: INTEGER);
(* store string either as token or as literal *)
  VAR
    sn, sn1:  CRT.SymbolNode;
    matchedSp: INTEGER;
  BEGIN
    CRT.GetSym(sp, sn);
    CRA.MatchDFA(sn.name, sp, matchedSp);
    IF matchedSp # CRT.noSym THEN
      CRT.GetSym(matchedSp, sn1);
      sn1.struct := CRT.classLitToken;
      CRT.PutSym(matchedSp, sn1);
      sn.struct := CRT.litToken
    ELSE sn.struct := CRT.classToken;
    END;
    CRT.PutSym(sp, sn)
  END MatchLiteral;

PROCEDURE SetCtx (gp: INTEGER);
(* set transition code to CRT.contextTrans *)
  VAR
    gn: CRT.GraphNode;
  BEGIN
    WHILE gp > 0 DO
      CRT.GetNode(gp, gn);
      IF (gn.typ = CRT.char) OR (gn.typ = CRT.class) THEN
        gn.p2 := CRT.contextTrans; CRT.PutNode(gp, gn)
      ELSIF (gn.typ = CRT.opt) OR (gn.typ = CRT.iter) THEN SetCtx(gn.p1)
      ELSIF gn.typ = CRT.alt THEN SetCtx(gn.p1); SetCtx(gn.p2)
      END;
      gp := gn.next
    END
  END SetCtx;

PROCEDURE SetOption (s: ARRAY OF CHAR);
  VAR
    i: CARDINAL;
  BEGIN
    i := 1;
    WHILE s[i] # 0C DO
      s[i] := CAP(s[i]);
      IF (s[i] >= "A") AND (s[i] <= "Z") THEN CRT.ddt[s[i]] := TRUE END;
      INC(i);
    END;
  END SetOption;

(*--------------------------------------------------------------------*)



CONST 
  maxT = 41;
  maxP = 42;
  minErrDist  =  2;  (* minimal distance (good tokens) between two errors *)
  setsize     = 16;  (* sets are stored in 16 bits *)

TYPE
  SymbolSet = ARRAY [0 .. maxT DIV setsize] OF BITSET;

VAR
  symSet:  ARRAY [0 ..  18] OF SymbolSet; (*symSet[0] = allSyncSyms*)
  errDist: CARDINAL;   (* number of symbols recognized since last error *)
  sym:     CARDINAL;   (* current input symbol *)

PROCEDURE SemError (errNo: INTEGER);
  BEGIN
    IF errDist >= minErrDist THEN
      CRS.Error(errNo, CRS.line, CRS.col, CRS.pos);
    END;
    errDist := 0;
  END SemError;

PROCEDURE SynError (errNo: INTEGER);
  BEGIN
    IF errDist >= minErrDist THEN
      CRS.Error(errNo, CRS.nextLine, CRS.nextCol, CRS.nextPos);
    END;
    errDist := 0;
  END SynError;

PROCEDURE Get;
  VAR
    s: ARRAY [0 .. 31] OF CHAR;
  BEGIN
    REPEAT
      CRS.Get(sym);
      IF sym <= maxT THEN
        INC(errDist);
      ELSE
        CASE sym OF
          42: CRS.GetName(CRS.nextPos, CRS.nextLen, s); SetOption(s);
        END;
        CRS.nextPos := CRS.pos;
        CRS.nextCol := CRS.col;
        CRS.nextLine := CRS.line;
        CRS.nextLen := CRS.len;
      END;
    UNTIL sym <= maxT
  END Get;

PROCEDURE In (VAR s: SymbolSet; x: CARDINAL): BOOLEAN;
  BEGIN
    RETURN x MOD setsize IN s[x DIV setsize];
  END In;

PROCEDURE Expect (n: CARDINAL);
  BEGIN
    IF sym = n THEN Get ELSE SynError(n) END
  END Expect;

PROCEDURE ExpectWeak (n, follow: CARDINAL);
  BEGIN
    IF sym = n
      THEN Get
      ELSE SynError(n); WHILE ~ In(symSet[follow], sym) DO Get END
    END
  END ExpectWeak;

PROCEDURE WeakSeparator (n, syFol, repFol: CARDINAL): BOOLEAN;
  VAR
    s: SymbolSet;
    i: CARDINAL;
  BEGIN
    IF sym = n
      THEN Get; RETURN TRUE
      ELSIF In(symSet[repFol], sym) THEN RETURN FALSE
      ELSE
        i := 0;
        WHILE i <= maxT DIV setsize DO
          s[i] := symSet[0, i] + symSet[syFol, i] + symSet[repFol, i]; INC(i)
        END;
        SynError(n); WHILE ~ In(s, sym) DO Get END;
        RETURN In(symSet[syFol], sym)
    END
  END WeakSeparator;

PROCEDURE LexName (VAR Lex: ARRAY OF CHAR);
  BEGIN
    CRS.GetName(CRS.pos, CRS.len, Lex)
  END LexName;

PROCEDURE LexString (VAR Lex: ARRAY OF CHAR);
  BEGIN
    CRS.GetString(CRS.pos, CRS.len, Lex)
  END LexString;

PROCEDURE LookAheadName (VAR Lex: ARRAY OF CHAR);
  BEGIN
    CRS.GetName(CRS.nextPos, CRS.nextLen, Lex)
  END LookAheadName;

PROCEDURE LookAheadString (VAR Lex: ARRAY OF CHAR);
  BEGIN
    CRS.GetString(CRS.nextPos, CRS.nextLen, Lex)
  END LookAheadString;

PROCEDURE Successful (): BOOLEAN;
  BEGIN
    RETURN CRS.errors = 0
  END Successful;

(* ----- FORWARD not needed in multipass compilers

PROCEDURE TokenFactor (VAR gL, gR: INTEGER); FORWARD;
PROCEDURE TokenTerm (VAR gL, gR: INTEGER); FORWARD;
PROCEDURE Factor (VAR gL, gR: INTEGER); FORWARD;
PROCEDURE Term (VAR gL, gR: INTEGER); FORWARD;
PROCEDURE Symbol (VAR name: CRT.Name; VAR kind: INTEGER); FORWARD;
PROCEDURE SingleChar (VAR n: CARDINAL); FORWARD;
PROCEDURE SimSet (VAR set: CRT.Set); FORWARD;
PROCEDURE Set (VAR set: CRT.Set); FORWARD;
PROCEDURE TokenExpr (VAR gL, gR: INTEGER); FORWARD;
PROCEDURE NameDecl; FORWARD;
PROCEDURE TokenDecl (typ: INTEGER); FORWARD;
PROCEDURE SetDecl; FORWARD;
PROCEDURE Expression (VAR gL, gR: INTEGER); FORWARD;
PROCEDURE SemText (VAR semPos: CRT.Position); FORWARD;
PROCEDURE Attribs (VAR attrPos: CRT.Position); FORWARD;
PROCEDURE Declaration; FORWARD;
PROCEDURE Ident (VAR name: CRT.Name); FORWARD;
PROCEDURE CR; FORWARD;

----- *)

PROCEDURE TokenFactor (VAR gL, gR: INTEGER);
  VAR
    kind, c: INTEGER;
    set:     CRT.Set;
    name:    CRT.Name;
  BEGIN
    gL :=0; gR := 0;
    IF (sym = 1) OR (sym = 2) THEN
      Symbol(name, kind);
      IF kind = ident THEN
        c := CRT.ClassWithName(name);
        IF c < 0 THEN
          SemError(115);
          Sets.Clear(set); c := CRT.NewClass(name, set)
        END;
        gL := CRT.NewNode(CRT.class, c, 0); gR := gL
      ELSE (* string *)
        CRT.StrToGraph(name, gL, gR)
      END;
    ELSIF (sym = 25) THEN
      Get;
      TokenExpr(gL, gR);
      Expect(26);
    ELSIF (sym = 29) THEN
      Get;
      TokenExpr(gL, gR);
      Expect(30);
      CRT.MakeOption(gL, gR);
    ELSIF (sym = 31) THEN
      Get;
      TokenExpr(gL, gR);
      Expect(32);
      CRT.MakeIteration(gL, gR);
    ELSE SynError(42);
    END;
  END TokenFactor;

PROCEDURE TokenTerm (VAR gL, gR: INTEGER);
  VAR
    gL2, gR2: INTEGER;
  BEGIN
    TokenFactor(gL, gR);
    WHILE (sym = 1) OR (sym = 2) OR (sym = 25) OR (sym = 29) OR (sym = 31) DO
      TokenFactor(gL2, gR2);
      CRT.ConcatSeq(gL, gR, gL2, gR2);
    END;
    IF (sym = 34) THEN
      Get;
      Expect(25);
      TokenExpr(gL2, gR2);
      SetCtx(gL2); CRT.ConcatSeq(gL, gR, gL2, gR2);
      Expect(26);
    END;
  END TokenTerm;

PROCEDURE Factor (VAR gL, gR: INTEGER);
  VAR
    sp, kind:    INTEGER;
    name:        CRT.Name;
    gn:          CRT.GraphNode;
    sn:          CRT.SymbolNode;
    set:         CRT.Set;
    undef, weak: BOOLEAN;
    pos:         CRT.Position;
  BEGIN
    gL :=0; gR := 0; weak := FALSE;
    CASE sym OF
      1, 2, 28 :
        IF (sym = 28) THEN
          Get;
          weak := TRUE;
        END;
        Symbol(name, kind);
        sp := CRT.FindSym(name); undef := sp = CRT.noSym;
        IF undef THEN
          IF kind = ident THEN  (* forward nt *)
            sp := CRT.NewSym(CRT.nt, name, 0)
          ELSIF CRT.genScanner THEN
            sp := CRT.NewSym(CRT.t, name, CRS.line);
            MatchLiteral(sp)
          ELSE (* undefined string in production *)
            SemError(106); sp := 0
          END
        END;
        CRT.GetSym(sp, sn);
        IF (sn.typ # CRT.t) & (sn.typ # CRT.nt) THEN SemError(104) END;
        IF weak THEN
          IF sn.typ = CRT.t THEN sn.typ := CRT.wt
          ELSE SemError(123)
          END
        END;
        gL := CRT.NewNode(sn.typ, sp, CRS.line); gR := gL;
        IF (sym = 35) OR (sym = 37) THEN
          Attribs(pos);
          CRT.GetNode(gL, gn); gn.pos := pos;
          CRT.PutNode(gL, gn);
          CRT.GetSym(sp, sn);
          IF sn.typ # CRT.nt THEN SemError(103) END;
          IF undef THEN
            sn.attrPos := pos; CRT.PutSym(sp, sn)
          ELSIF sn.attrPos.beg < FileIO.Long0 THEN SemError(105)
          END;
        ELSIF In(symSet[1], sym) THEN
          CRT.GetSym(sp, sn);
          IF sn.attrPos.beg >= FileIO.Long0 THEN SemError(105) END;
        ELSE SynError(43);
        END;
    | 25 :
        Get;
        Expression(gL, gR);
        Expect(26);
    | 29 :
        Get;
        Expression(gL, gR);
        Expect(30);
        CRT.MakeOption(gL, gR);
    | 31 :
        Get;
        Expression(gL, gR);
        Expect(32);
        CRT.MakeIteration(gL, gR);
    | 39 :
        SemText(pos);
        gL := CRT.NewNode(CRT.sem, 0, 0); gR := gL;
        CRT.GetNode(gL, gn);
        gn.pos := pos;
        CRT.PutNode(gL, gn);
    | 23 :
        Get;
        Sets.Fill(set); Sets.Excl(set, CRT.eofSy);
        gL := CRT.NewNode(CRT.any, CRT.NewSet(set), 0); gR := gL;
    | 33 :
        Get;
        gL := CRT.NewNode(CRT.sync, 0, 0); gR := gL;
    ELSE SynError(44);
    END;
  END Factor;

PROCEDURE Term (VAR gL, gR: INTEGER);
  VAR
    gL2, gR2: INTEGER;
  BEGIN
    gL := 0; gR := 0;
    IF In(symSet[2], sym) THEN
      Factor(gL, gR);
      WHILE In(symSet[2], sym) DO
        Factor(gL2, gR2);
        CRT.ConcatSeq(gL, gR, gL2, gR2);
      END;
    ELSIF (sym = 8) OR (sym = 26) OR (sym = 27) OR (sym = 30) OR (sym = 32) THEN
      gL := CRT.NewNode(CRT.eps, 0, 0); gR := gL;
    ELSE SynError(45);
    END;
  END Term;

PROCEDURE Symbol (VAR name: CRT.Name; VAR kind: INTEGER);
  BEGIN
    IF (sym = 1) THEN
      Ident(name);
      kind := ident;
    ELSIF (sym = 2) THEN
      Get;
      CRS.GetName(CRS.pos, CRS.len, name); kind := string;
      FixString(name, CRS.len);
    ELSE SynError(46);
    END;
  END Symbol;

PROCEDURE SingleChar (VAR n: CARDINAL);
  VAR
    i: CARDINAL;
    s: ARRAY [0 .. 127] OF CHAR;
  BEGIN
    Expect(24);
    Expect(25);
    Expect(4);
    CRS.GetName(CRS.pos, CRS.len, s);
    n := 0; i := 0;
    WHILE s[i] # 0C DO
      n := 10 * n + ORD(s[i]) - ORD("0"); INC(i)
    END;
    IF n > 255 THEN SemError(118); n := n MOD 256 END;
    IF CRT.ignoreCase THEN n := ORD(CAP(CHR(n))) END;
    Expect(26);
  END SingleChar;

PROCEDURE SimSet (VAR set: CRT.Set);
  VAR
    i, n1, n2: CARDINAL;
    c:         INTEGER;
    name:      CRT.Name;
    s:         ARRAY [0 .. 127] OF CHAR;
  BEGIN

⌨️ 快捷键说明

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