kyacc/src/Main.m3


 Copyright (c) 2000 California Institute of Technology 
 All rights reserved. See the file COPYRIGHT for a full description. 
 $Id: Main.m3,v 1.2 2001-09-19 15:13:58 wagner Exp $ 

MODULE Main;
IMPORT TokParams;
IMPORT FileWr, Wr, Thread, OSError;
IMPORT FileRdErr;
IMPORT Pathname;
IMPORT TextSubs;
IMPORT YaccParse;
IMPORT yaccformBundle;
IMPORT Bundle;
IMPORT PDA;
IMPORT PDATransListFlat;
IMPORT RuleList;
IMPORT Fmt;

 IMPORT Term, PDATransListOp, Env;
<* FATAL Thread.Alerted, Wr.Failure, OSError.E *>

VAR
  Debug := Env.Get("yaccDEBUG") # NIL;

  Form := yaccformBundle.Get();
  tp := TokParams.Get("yacc", ".y", "Parse.i3");
PROCEDURE RenumberRules(rules: RuleList.T; inc: INTEGER) =
  VAR
    cur := rules;
  BEGIN
    WHILE cur # NIL DO
      INC(cur.head.number, inc);
      cur := cur.tail;
    END;
  END RenumberRules;

PROCEDURE CodeRanges(subs: TextSubs.T;
                     symCodeLast, actionLast, stateLast: INTEGER) =
  VAR
    last := ARRAY [1..3] OF INTEGER{symCodeLast, actionLast, stateLast};
    bits :  ARRAY [1..3] OF INTEGER;
    base := ARRAY [1..3] OF TEXT{"%symCode", "%action", "%state"};
  VAR
    b, rep: INTEGER;
  BEGIN
    FOR i := 1 TO 3 DO
      b := 0;
      rep := 1;
      WHILE rep <= last[i] DO
        INC(b);
        INC(rep, rep);
      END;
      bits[i] := b;
    END;
    (* SRC Modula-3 packed type alignment *)
    b := bits[1] + bits[2];
    <* ASSERT b <= 32 *>
    IF b + bits[3] > 32 THEN
      bits[2] := 32 - bits[1];
    END;
    FOR i := 1 TO 3 DO
      subs.add(base[i] & "Last", Fmt.Int(last[i]));
      subs.add(base[i] & "Bits", Fmt.Int(bits[i]));
    END;
  END CodeRanges;

PROCEDURE TriNum(subs: TextSubs.T; prag: TEXT; val: INTEGER) =
  BEGIN
    FOR i := 0 TO 2 DO
      subs.add(prag & Fmt.Int(i), Fmt.Int(val+i));
    END;
  END TriNum;

PROCEDURE Subs(): TextSubs.T =
  VAR
    subs := NEW(TextSubs.T).init();
    rd := FileRdErr.Open(tp.source);
    tok := TokParams.ReadTokens(tp);
    yp := NEW(YaccParse.T).init(rd, tok, tp.outBase);
    rules := yp.getRules();
    numRules := RuleList.Length(rules);
    pda := PDA.New(rules, tok, yp.getCodes());
    lastShift := pda.lastShift;
    lastReduce := lastShift + numRules + 1;
    numSym, lastSymCode: INTEGER;
  BEGIN
    RenumberRules(yp.getRules(), lastShift+1);
    subs.add("\\\n", "");
    subs.add("%tok", tp.tokOutBase);
    subs.add("%yacc", tp.outBase);
    subs.add("%gen", "(* Generated by kyacc *)");
    subs.add("%prot",yp.fmtRules("    %name(VAR result: %return%sparams);\n"));
    subs.add("%defimpl", yp.fmtRules(Bundle.Get(Form, "yaccform.proc.m3")));
    subs.add("%type", yp.fmtTypes(Bundle.Get(Form,"yaccform.type.m3"),FALSE));
    subs.add("%orig", yp.fmtTypes(Bundle.Get(Form,"yaccform.orig.m3"),FALSE));
    subs.add("%ovr", yp.fmtRules("    %name := %name;\n"));
    subs.add("%gettok", tok.fmtVar("  %name = " &tp.tokOutBase& ".%name;\n"));
    subs.add("%tokOrig", tok.fmtOrig(NIL));
    pda.symInfo(numSym, lastSymCode);
    subs.add("%States", PDATransListFlat.Format(pda.statesArray,
                                                lastShift+1,
                                                lastReduce+1,
                                                lastSymCode+1));
    subs.add("%Symbols", pda.fmtSymbols());
    subs.add("%DECaction", Fmt.Int(numRules+1));
    subs.add("%Rules", yp.fmtRules(Bundle.Get(Form, "yaccform.rule.m3")));
    subs.add("%reduce", yp.fmtRules(Bundle.Get(Form, "yaccform.reduce.m3")));
   subs.add("%case",yp.fmtTypes(Bundle.Get(Form,"yaccform.typecase.m3"),TRUE));

    subs.add("%numSym", Fmt.Int(numSym));
    subs.add("%symCodePenult", Fmt.Int(lastSymCode));

    CodeRanges(subs, lastSymCode + 1, lastReduce + numRules + 1,
               LAST(pda.statesArray^));
    TriNum(subs, "%lastShift", lastShift);
    TriNum(subs, "%lastReduce", lastReduce);

    subs.add("%alloc", yp.fmtTypes("    allocate_%name: " &
      tp.tokOutBase & ".Allocator;\n", FALSE));
    subs.add("%purge", yp.fmtTypes("\n      + " &
      tp.tokOutBase & ".Purge(self.allocate_%name)", FALSE));

    IF Debug THEN
      PDATransListOp.PrintArray(pda.statesArray);
      Term.WrLn(yp.fmtRules("%debug\n"));
      RenumberRules(yp.getRules(), -(lastShift+1));
      PDA.Test(pda);
    END;

    RETURN subs;
  END Subs;

VAR
  subs := Subs();
PROCEDURE WriteFile(pathName: Pathname.T; formName: TEXT) =
  VAR
    wr := FileWr.Open(pathName);
  BEGIN
    Wr.PutText(wr, subs.apply(Bundle.Get(Form, formName)));
    Wr.Close(wr);
  END WriteFile;
BEGIN
  WriteFile(tp.out, "yaccform.i3");
  WriteFile(Pathname.ReplaceExt(tp.out, "m3"), "yaccform.m3");
END Main.