kyacclib/src/Rule.m3


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

MODULE Rule;
IMPORT Prec;
IMPORT CharRange;
IMPORT CharCodes;
IMPORT Sym;
IMPORT SymList;
IMPORT SymListParse;
IMPORT TextSubs;
IMPORT TextPrecTbl;
IMPORT TextBooleanTbl;
IMPORT TextIntTbl;
IMPORT Rd, Thread;
IMPORT Wr, TextWr;
IMPORT Fmt;
IMPORT Term, Fmt;
<*FATAL Rd.Failure, Wr.Failure, Thread.Alerted*>
REVEAL
  T = Public BRANDED OBJECT
    subs: TextSubs.T := NIL;
  END;

PROCEDURE DbgFormat(a: T): TEXT =
  VAR
    acc := a.name & " :";
    cur := a.syms;
  BEGIN
    WHILE cur # NIL DO
      acc := acc & " " & Sym.Format(cur.head);
      cur := cur.tail;
    END;
    RETURN acc;
  END DbgFormat;

PROCEDURE CountParams(a: T): INTEGER =
  VAR
    cur := a.syms;
    i: INTEGER := 0;
  BEGIN
    WHILE cur # NIL DO
      IF NOT Sym.IsConst(cur.head) THEN INC(i); END;
      cur := cur.tail;
    END;
    RETURN i;
  END CountParams;

PROCEDURE FormatParams(a: T; form: TEXT): TEXT =
  VAR
    cur := a.syms;
    wr := TextWr.New();
    i: INTEGER := 0;
    stackRef := SymList.Length(cur);
    name: TEXT;
    subs: TextSubs.T;
  BEGIN
    WHILE cur # NIL DO
      DEC(stackRef);
      IF NOT Sym.IsConst(cur.head) THEN
        INC(i);
        name := Sym.GetName(cur.head);
        subs := NEW(TextSubs.T).init();
        subs.add("%number", Fmt.Int(i));
        subs.add("%type", name);
        name := "";
        IF stackRef # 0 THEN
          name := Fmt.Int(-stackRef);
        END;
        subs.add("%offset", name);
        Wr.PutText(wr, subs.apply(form));
      END;
      cur := cur.tail;
    END;
    RETURN TextWr.ToText(wr);
  END FormatParams;

PROCEDURE Format(a: T; form: TEXT; last: BOOLEAN := TRUE): TEXT =
  VAR
    optionalComma := ",";
    optionalCR := "\n            ";
  PROCEDURE Pform(key, form: TEXT) =
    BEGIN
      a.subs.add(key, FormatParams(a, form));
    END Pform;
  BEGIN
    IF a.subs = NIL THEN
      IF last THEN optionalComma := "";END;
      IF a.syms=NIL THEN optionalCR := "";END;
      a.subs := NEW(TextSubs.T).init();
      a.subs.add("%debug", CharCodes.Q(DbgFormat(a)));
      a.subs.add("%name", a.name);
      a.subs.add("%return", Sym.GetName(a.return));
      a.subs.add("%length", Fmt.Int(a.length));
      a.subs.add("%number", Fmt.Int(a.number));
      a.subs.add("%codeReturn", Fmt.Int(Sym.GetCode(a.return)));
      Pform("%oparams", "; p%number: Original_%type");
      Pform("%sparams", "; p%number: %type");
      Pform("%uparams", ";<*UNUSED*>p%number: %type");
      Pform("%cparams", ", p%number");
      Pform("%fromStack", "p%number:%type:=a[p%offset].value.value;");
      Pform("%narrow", "    n%number := NARROW(p%number, %type);\n");
      a.subs.add("\\,", optionalComma);
      a.subs.add("\\\n", optionalCR);
      a.subs.add("\\\\\n", "");
    END;
    RETURN a.subs.apply(form);
  END Format;

PROCEDURE FromRd(rd: Rd.T; return: Sym.T;
                 allowedChars: CharRange.T;
                 number: INTEGER): T =
  VAR
    self := NEW(T, return := return, prec := NIL, number := number);
    <* FATAL Rd.EndOfFile *>
  BEGIN
    WHILE Rd.GetChar(rd) IN CharRange.WhiteSpace DO END;
    self.name := SymListParse.BackGetName(rd) & "_" &
                     Sym.GetName(self.return);
    self.syms := SymListParse.Parse(rd, allowedChars);
    self.length := SymList.Length(self.syms);
    RETURN self;
  END FromRd;

PROCEDURE LookupSyms(self: T;
                     prec: TextPrecTbl.T;
                     start: TextBooleanTbl.T;
                     codes: TextIntTbl.T;
                     const: TextIntTbl.T;
                     VAR lastCode: INTEGER) =
  PROCEDURE Lookup(sym: Sym.T) =
    BEGIN
      Sym.AllocCode(sym, codes, lastCode);
      Sym.SetAttrs(sym, start, const);
    END Lookup;
  VAR
    cur := self.syms;
    highestPrec := NEW(Prec.T, kind := Prec.Kind.None);
    thisPrec: Prec.T;
  BEGIN
    Lookup(self.return);
    WHILE cur # NIL DO
      Lookup(cur.head);
      thisPrec := Sym.GetPrec(cur.head, prec);
      IF thisPrec # NIL THEN
        IF highestPrec.val < thisPrec.val THEN
          highestPrec := thisPrec;
        END;
      END;
      cur := cur.tail;
    END;
    IF prec.get(self.name, highestPrec) THEN
Term.WrLn(Found prec: & self.name & Fmt.Int(highestPrec.val)); ELSE Term.WrLn(Not finding prec: & self.name);
    END;
    self.prec := highestPrec;
    self.prec.used := TRUE;
Term.WrLn(Marking used: & Fmt.Int(self.prec.val));
  END LookupSyms;

PROCEDURE Equal(<*UNUSED*>a, b: T): BOOLEAN =
  BEGIN <*ASSERT FALSE*> END Equal;

PROCEDURE Compare(a, b: T; assoc: BOOLEAN := FALSE): [-1 .. 1] =
  BEGIN
    IF b = NIL THEN
      RETURN 1;
    ELSIF a = NIL THEN
      RETURN -1;
    ELSE
      VAR
        aprec := a.prec.val;
        bprec := b.prec.val;
      BEGIN
        IF aprec = 0 OR bprec = 0 THEN
          RETURN 0;
        ELSIF aprec > bprec THEN
          RETURN 1;
        ELSIF bprec > aprec THEN
          RETURN -1;
        ELSIF a.prec.kind = Prec.Kind.None OR NOT assoc THEN
          RETURN 0;
        ELSIF a.prec.kind = Prec.Kind.Left THEN
          RETURN 1;
        ELSE
          RETURN -1;
        END;
      END;
    END;
  END Compare;

PROCEDURE Number(a: T): INTEGER =
  BEGIN
    IF a = NIL THEN
      RETURN 0;
    ELSE
      RETURN a.number;
    END;
  END Number;

BEGIN
END Rule.