⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cra.mod

📁 一个Modula-2语言分析器
💻 MOD
📖 第 1 页 / 共 3 页
字号:
  (* Find states reached by a context transition *)
    VAR
      a: Action;
      s: INTEGER;
    BEGIN
      s := rootState;
      WHILE s <= lastState DO
        a := state[s].firstAction;
        WHILE a # NIL DO
          IF a^.tc = CRT.contextTrans THEN
            state[a^.target^.state].ctx := TRUE
          END;
          a := a^.next
        END;
        INC(s)
      END;
    END FindCtxStates;

  BEGIN
    out := CRS.lst;
    lastSimState := lastState;
    FindCtxStates;
    s := rootState;
    WHILE s <= lastState DO
      REPEAT MakeUnique(s, changed) UNTIL ~ changed;
      INC(s)
    END;
    correct := TRUE;
    s := rootState;
    WHILE s <= lastState DO MeltStates(s, correct); INC(s) END;
    DeleteRedundantStates;
    CombineShifts;
(* ====    IF CRT.ddt["A"] THEN PrintStates END ==== *)
  END MakeDeterministic;



(* GenComment            Generate a procedure to scan comments
-------------------------------------------------------------------------*)
PROCEDURE GenComment (leftMarg: CARDINAL; com: Comment);

  PROCEDURE GenBody (leftMarg: CARDINAL);
    BEGIN
      PutB(leftMarg); PutS("LOOP$");
      PutB(leftMarg + 2); PutS("IF ");
      PutChCond(com^.stop[0]); PutS(" THEN$");
      IF FileIO.SLENGTH(com^.stop) = 1 THEN
        PutB(leftMarg + 4);
        PutS("DEC(level); oldEols := curLine - startLine; NextCh;$");
        PutB(leftMarg + 4); PutS("IF level = 0 THEN RETURN TRUE END;$");
      ELSE
        PutB(leftMarg + 4); PutS("NextCh;$");
        PutB(leftMarg + 4); PutS("IF ");
        PutChCond(com^.stop[1]); PutS(" THEN$");
        PutB(leftMarg + 6); PutS("DEC(level); NextCh;$");
        PutB(leftMarg + 6); PutS("IF level = 0 THEN RETURN TRUE END$");
        PutB(leftMarg + 4); PutS("END;$");
      END;
      IF com^.nested THEN
        PutB(leftMarg + 2); PutS("ELSIF "); PutChCond(com^.start[0]);
        PutS(" THEN$");
        IF FileIO.SLENGTH(com^.start) = 1 THEN
          PutB(leftMarg + 4); PutS("INC(level); NextCh;$");
        ELSE
          PutB(leftMarg + 4); PutS("NextCh;$");
          PutB(leftMarg + 4); PutS("IF "); PutChCond(com^.start[1]);
          PutS(" THEN "); PutS("INC(level); NextCh "); PutS("END;$");
        END;
      END;
      PutB(leftMarg + 2); PutS("ELSIF ch = EOF THEN RETURN FALSE$");
      PutB(leftMarg + 2); PutS("ELSE NextCh END;$");
      PutB(leftMarg); PutS("END; (* LOOP *)$");
    END GenBody;

  BEGIN
    PutS("IF "); PutChCond(com^.start[0]); PutS(" THEN$");
    IF FileIO.SLENGTH(com^.start) = 1 THEN
      PutB(leftMarg + 2); PutS("NextCh;$");
      GenBody(leftMarg + 2);
    ELSE
      PutB(leftMarg + 2); PutS("NextCh;$");
      PutB(leftMarg + 2); PutS("IF ");
      PutChCond(com^.start[1]); PutS(" THEN$");
      PutB(leftMarg + 4); PutS("NextCh;$");
      GenBody(leftMarg + 4);
      PutB(leftMarg + 2); PutS("ELSE$");
      PutB(leftMarg + 4);
      PutS("IF (ch = CR) OR (ch = LF) THEN$");
      PutB(leftMarg + 6);
      PutS("DEC(curLine); lineStart := oldLineStart$");
      PutB(leftMarg + 4); PutS("END;$");
      PutB(leftMarg + 4);
      PutS("DEC(bp); ch := lastCh;$");
      PutB(leftMarg + 2); PutS("END;$");
    END;
    PutB(leftMarg); PutS("END;$"); PutB(leftMarg);
  END GenComment;

(* CopyFramePart   Copy from file <fram> to file <framOut> until <stopStr>
-------------------------------------------------------------------------*)
PROCEDURE CopyFramePart (stopStr: ARRAY OF CHAR; VAR leftMarg: CARDINAL;
                         VAR framIn, framOut:FileIO.File);
  VAR
    ch, startCh: CHAR;
    slen, i: CARDINAL;
    temp: ARRAY [0 .. 63] OF CHAR;
  BEGIN
    startCh := stopStr[0]; FileIO.Read(framIn, ch);
    slen := FileIO.SLENGTH(stopStr);
    WHILE FileIO.Okay DO
      IF (ch = FileIO.EOL) OR (ch = FileIO.CR) OR (ch = FileIO.LF)
        THEN leftMarg := 0
        ELSE INC(leftMarg)
      END;
(* ProgArgs.Assert(leftMarg <= 100); for gpm version *)
      IF ch = startCh
        THEN (* check if stopString occurs *)
          i := 0;
          WHILE (i + 1 < slen) & (ch = stopStr[i]) & FileIO.Okay DO
            temp[i] := ch; INC(i); FileIO.Read(framIn, ch)
          END;
          IF ch = stopStr[i] THEN DEC(leftMarg); RETURN END;
          (* found ==> exit , else continue *)
          FileIO.WriteText(framOut, temp, i);
          FileIO.Write(framOut, ch);
          INC(leftMarg, i);
        ELSE FileIO.Write(framOut, ch)
      END;
      FileIO.Read(framIn, ch)
    END;
  END CopyFramePart;

(* ImportSymConsts      Generates the import of the named symbol constants
-------------------------------------------------------------------------*)
PROCEDURE ImportSymConsts (putS: PutSProc);
  VAR
    i, len,
    oldLen, pos: INTEGER;
    cname: CRT.Name;
    gn: CRT.GraphNode;
    sn: CRT.SymbolNode;
    gramName: ARRAY [0 .. 31] OF CHAR;

  PROCEDURE PutImportSym;
    BEGIN
      IF pos + oldLen > MaxSourceLineLength THEN putS("$  "); pos := 2 END;
      putS(cname); INC(pos, oldLen + 1);
      (* This is not strictly correct, as the increase of 2 should be
         lower. I omitted it, because to separate it would be too
         complicated, and no unexpected side effects are likely, since it
         is only called again outside the loop - after which "pos" is not
         used again
      *)
    END PutImportSym;

  BEGIN
    (* ----- Import list of the generated Symbol Constants Module ----- *)
    putS(";$$FROM  ");
    CRT.GetNode(CRT.root, gn); CRT.GetSym(gn.p1, sn);
    FileIO.Extract(sn.name, 0, 7, gramName);
    putS(gramName); putS("G  IMPORT ");
    i := 0; pos := MaxSourceLineLength + 1; oldLen := 0;
    LOOP
      CRT.GetSym(i, sn); len := FileIO.SLENGTH(sn.constant);
      IF len > 0 THEN
        IF oldLen > 0 THEN PutImportSym; putS(", ") END;
        oldLen := len + 1; cname := sn.constant;
      END;
      IF i = CRT.maxP THEN EXIT END;
      INC(i);
    END; (* LOOP *)
    PutImportSym;
  END ImportSymConsts;

(* GenLiterals           Generate CASE for the recognition of literals
-------------------------------------------------------------------------*)
PROCEDURE GenLiterals (leftMarg: CARDINAL);
  VAR
    FirstLine: BOOLEAN;
    i, j, k: INTEGER;
    key: ARRAY [0 .. CRT.maxLiterals] OF CRT.Name;
    knr: ARRAY [0 .. CRT.maxLiterals] OF INTEGER;
    ch: CHAR;
    sn: CRT.SymbolNode;
  BEGIN
    (*-- sort literal list*)
    i := 0; k := 0;
    WHILE i <= CRT.maxT DO
      CRT.GetSym(i, sn);
      IF sn.struct = CRT.litToken THEN
        j := k-1;
        WHILE (j >= 0) & (FileIO.Compare(sn.name, key[j]) < 0) DO
          key[j + 1] := key[j]; knr[j + 1] := knr[j]; DEC(j)
        END;
        key[j + 1] := sn.name; knr[j + 1] := i;
        INC(k); IF k > CRT.maxLiterals THEN CRT.Restriction(10, CRT.maxLiterals) END;
      END;
      INC(i)
    END;
    (*-- print CASE statement*)
    IF k # 0 THEN
      PutS("CASE CurrentCh(bp0) OF$"); PutB(leftMarg);
      i := 0; FirstLine := TRUE;
      WHILE i < k DO
        ch := key[i, 1]; (*key[i, 0] = quote*)
        IF i # 0 THEN PutLn; PutB(leftMarg) END;
        IF FirstLine THEN
          FirstLine := FALSE; PutS("  ") ELSE PutS("| ")
        END;
        PutC(ch); j := i;
        REPEAT
          IF i = j THEN
            PutS(": IF") ELSE PutB(leftMarg + 6); PutS(" ELSIF")
          END;
          PutS(" Equal("); PutS(key[i]); PutS(") THEN ");
          PutSE(knr[i]); PutLn;
          INC(i);
        UNTIL (i = k) OR (key[i, 1] # ch);
        PutB(leftMarg + 6); PutS(" END");
      END;
      PutLn; PutB(leftMarg); PutS("ELSE$");
      PutB(leftMarg); PutS("END")
    END;
  END GenLiterals;

(* WriteState           Write the source text of a scanner state
-------------------------------------------------------------------------*)
PROCEDURE WriteState (leftMarg, s: INTEGER; VAR FirstState: BOOLEAN);
  VAR
    action: Action;
    ind: INTEGER;
    first, ctxEnd: BOOLEAN;
    sn: CRT.SymbolNode;
    endOf: INTEGER;
    set: CRT.Set;
  BEGIN
    endOf := state[s].endOf;
    IF (endOf > CRT.maxT) & (endOf # CRT.noSym) THEN
      (*pragmas have been moved*)
      endOf := CRT.maxT + CRT.maxSymbols - endOf
    END;
(* ProgArgs.Assert(leftMarg <= 100); for gpm version *)
    Indent(leftMarg);
    IF FirstState THEN FirstState := FALSE; PutS("  ") ELSE PutS("| ") END;
    PutI2(s, 2); PutS(": ");
    first := TRUE; ctxEnd := state[s].ctx;
    action := state[s].firstAction;
    WHILE action # NIL DO
      IF first
        THEN PutS("IF "); first := FALSE; ind := leftMarg + 3;
        ELSE PutB(leftMarg + 6); PutS("ELSIF "); ind := leftMarg + 6;
      END;
      IF action^.typ = CRT.char THEN PutChCond(CHR(action^.sym))
      ELSE CRT.GetClass(action^.sym, set); PutRange(set,leftMarg + ind)
      END;
      PutS(" THEN");
      IF action^.target^.state # s THEN
        PutS(" state := "); PutI(action^.target^.state); Put(";")
      END;
      IF action^.tc = CRT.contextTrans
        THEN PutS(" INC(apx)"); ctxEnd := FALSE
        ELSIF state[s].ctx THEN PutS(" apx := Long0")
      END;
      PutS(" $");
      action := action^.next
    END;
    IF state[s].firstAction # NIL THEN
      PutB(leftMarg + 6); PutS("ELSE ")
    END;
    IF endOf = CRT.noSym THEN PutS("sym := noSym; ");
    ELSE (*final state*)
      CRT.GetSym(endOf, sn);
      IF ctxEnd THEN (*cut appendix*)
        PutS("bp := bp - apx - Long1;");
        PutS(" DEC(nextLen, ORDL(apx)); NextCh; ")
      END;
      PutSE(endOf);
      IF sn.struct = CRT.classLitToken THEN PutS("CheckLiteral; ") END
    END;
    PutS("RETURN$");
    IF state[s].firstAction # NIL THEN
      PutB(leftMarg + 6); PutS("END;$")
    END
  END WriteState;

(* WriteScanner         Write the scanner source file
-------------------------------------------------------------------------*)
PROCEDURE WriteScanner;
  CONST
    ListingWidth = 78;
  VAR
    gramName: ARRAY [0 .. 31] OF CHAR;
    fGramName, fn: ARRAY [0 .. 63] OF CHAR;
    startTab: ARRAY [0 .. 255] OF INTEGER;
    com: Comment;
    i, j, s: INTEGER;
    gn: CRT.GraphNode;
    sn: CRT.SymbolNode;

  PROCEDURE FillStartTab;
    VAR
      action: Action;
      i, targetState, undefState: INTEGER;
      class: CRT.Set;
    BEGIN
      undefState := lastState + 2;
      startTab[0] := lastState + 1; (*eof*)
      i := 1;
      WHILE i < 256 (*PDT*) DO startTab[i] := undefState; INC(i) END;
      action := state[rootState].firstAction;
      WHILE action # NIL DO
        targetState := action^.target^.state;
        IF action^.typ = CRT.char THEN
          startTab[action^.sym] := targetState
        ELSE
          CRT.GetClass(action^.sym, class); i := 0;
          WHILE i < 256 (*PDT*) DO
            IF Sets.In(class, i) THEN startTab[i] := targetState END;
            INC(i)
          END
        END;
        action := action^.next
      END
    END FillStartTab;

VAR
  LeftMargin: CARDINAL;
  FirstState: BOOLEAN;
  ScannerFrame: ARRAY [0 .. 63] OF CHAR;

  BEGIN
    FillStartTab;
    FileIO.Concat(CRS.directory, "scanner.frm", ScannerFrame);
    FileIO.Open(fram, ScannerFrame, FALSE);
    IF ~ FileIO.Okay THEN
      FileIO.SearchFile(fram, "CRFRAMES", "scanner.frm", FALSE);
      IF ~ FileIO.Okay THEN
        FileIO.WriteLn(FileIO.StdOut);
        FileIO.WriteString(FileIO.StdOut, "'scanner.frm' not found.");
        FileIO.WriteLn(FileIO.StdOut);
        FileIO.WriteString(FileIO.StdOut, "Aborted.");
        FileIO.QuitExecution
      END
    END;
    LeftMargin := 0;

    CRT.GetNode(CRT.root, gn); CRT.GetSym(gn.p1, sn);
    FileIO.Extract(sn.name, 0, 7, gramName);
    FileIO.Concat(CRS.directory, gramName, fGramName);

    (*------- *S.MOD -------*)
    FileIO.Concat(fGramName, "S", fn);
    FileIO.Concat(fn, FileIO.ModExt, fn);
(* ++
    FileIO.WriteLn(FileIO.StdOut);
    FileIO.WriteString(FileIO.StdOut, "  ");
    FileIO.WriteString(FileIO.StdOut, fn);
 ++ *)
    FileIO.Open(scanner, fn, TRUE);
    out := scanner;
    CopyFramePart("-->modulename", LeftMargin, fram, out);
    PutS(gramName); Put("S");
    IF CRT.ddt["N"] OR CRT.symNames THEN ImportSymConsts(PutS) END;

    CopyFramePart("-->unknownsym", LeftMargin, fram, out);
    IF CRT.ddt["N"] OR CRT.symNames
      THEN PutSN(CRT.maxT)
      ELSE PutI(CRT.maxT)
    END;
    CopyFramePart("-->comment", LeftMargin, fram, out);
    com := firstComment;
    WHILE com # NIL DO GenComment(LeftMargin, com); com := com^.next END;

    CopyFramePart("-->literals", LeftMargin, fram, out);
    GenLiterals(LeftMargin);

    CopyFramePart("-->GetSy1", LeftMargin, fram, out);
    NewLine := FALSE;
    IF ~ Sets.In(CRT.ignored, ORD(cr)) THEN
      Indent(LeftMargin);
      PutS("IF oldEols > 0 THEN DEC(bp);");
      PutS(" DEC(oldEols); ch := CR END;$")
    END;
    Indent(LeftMargin); PutS("WHILE (ch=' ')");
    IF ~ Sets.Empty(CRT.ignored) THEN
      PutS(" OR$"); Indent(LeftMargin + 6)
    END;
    PutRange(CRT.ignored, LeftMargin + 6); PutS(" DO NextCh END;");
    IF firstComment # NIL THEN
      PutLn; PutB(LeftMargin); PutS("IF ("); com := firstComment;
      WHILE com # NIL DO
        PutChCond(com^.start[0]);
        IF com^.next # NIL THEN PutS(" OR ") END;
        com := com^.next
      END;
      PutS(") & Comment() THEN Get(sym); RETURN END;");
    END;

    CopyFramePart("-->GetSy2", LeftMargin, fram, out);
    NewLine := FALSE; s := rootState + 1; FirstState := TRUE;
(* ProgArgs.Assert(leftMarg <= 100); for gpm version *)
    WHILE s <= lastState DO
      WriteState(LeftMargin, s, FirstState); INC(s)
    END;
    PutB(LeftMargin); PutS("| "); PutI2(lastState + 1, 2);
    PutS(": "); PutSE(0); PutS("ch := 0C; DEC(bp); RETURN");

    CopyFramePart("-->initializations", LeftMargin, fram, out);
    IF CRT.ignoreCase
      THEN PutS("CurrentCh := CapChAt;$")
      ELSE PutS("CurrentCh := CharAt;$")
    END;
    PutB(LeftMargin);
    i := 0;
    WHILE i < 64 (*PDT*) DO
      IF i # 0 THEN PutLn; PutB(LeftMargin); END;
      j := 0;
      WHILE j < 4 DO
        PutS("start["); PutI2(4*i + j,3); PutS("] := ");
        PutI2(startTab[4*i + j],2); PutS("; "); INC(j);
      END;
      INC(i);
    END;

    CopyFramePart("-->modulename", LeftMargin, fram, out);
    PutS(gramName); Put("S");
    CopyFramePart("-->definition", LeftMargin, fram, out);
    FileIO.Close(scanner);

    (*------- *S.DEF -------*)
    IF ~ CRT.ddt["D"] THEN
      FileIO.Concat(fGramName, "S", fn);
      FileIO.Concat(fn, FileIO.DefExt, fn);
(* ++
      FileIO.WriteLn(FileIO.StdOut);
      FileIO.WriteString(FileIO.StdOut, "  ");
      FileIO.WriteString(FileIO.StdOut, fn);
 ++ *)
      FileIO.Open(scanner, fn, TRUE);
      out := scanner;
      CopyFramePart("-->modulename", LeftMargin, fram, out);
      PutS(gramName); Put("S");

      CopyFramePart("-->modulename", LeftMargin, fram, out);
      PutS(gramName); Put("S");

      CopyFramePart("-->implementation", LeftMargin, fram, out);
      FileIO.Close(scanner);
    END;
    FileIO.Close(fram);
  END WriteScanner;

BEGIN (* CRA *)
  lastState := -1; rootState := NewState();
  firstMelted := NIL; firstComment := NIL;
  NewLine := TRUE;
END CRA.

⌨️ 快捷键说明

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