MODULE; IMPORT Rd; IMPORT CharRange; IMPORT CharCodes; IMPORT Text; IMPORT TextSubs; IMPORT TextList; IMPORT TextIntTbl; IMPORT IntTextTbl; IMPORT Thread; IMPORT FileRdErr; IMPORT TextReader; IMPORT Pragma, PragmaRead; IMPORT Wr, TextWr; TokSpec
IMPORT Stdio;
<* FATAL Rd.EndOfFile, Rd.Failure, Wr.Failure, Thread.Alerted *>
REVEAL
T = Public BRANDED OBJECT
OVERRIDES
init := Init;
read := Read;
error := Error;
fmtVar := FmtVar;
fmtOrig := FmtOrig;
END;
PROCEDURE Init (self: T): T =
BEGIN
self.tokens := NIL;
self.varTokens := NIL;
self.charTokens := CharRange.NoChars;
self.lastConstCode := ORD(LAST(CHAR));
self.constTokens := NEW(TextIntTbl.Default).init();
self.constTokensR := NEW(IntTextTbl.Default).init();
RETURN self;
END Init;
TYPE
TokPragma = Pragma.T OBJECT
spec: T;
END;
PROCEDURE ParseCharToken (p: TokPragma; rd: Rd.T) =
VAR
self := p.spec;
line := Rd.GetLine(rd);
r1 := Text.FindChar(line, '[');
r2 := Text.FindCharR(line, ']');
BEGIN
IF r1 = -1 THEN self.error(rd, "%char: enclose in []"); END;
IF r2 = -1 THEN self.error(rd, "%char: missing `]'"); END;
self.charTokens := self.charTokens +
CharRange.FromText(Text.Sub(line, r1, r2-r1+1));
END ParseCharToken;
PROCEDURE ShatterLine (rd: Rd.T): TextList.T =
VAR
line := Rd.GetLine(rd);
tr := NEW(TextReader.T).init(line);
BEGIN
Wr.PutText(Stdio.stderr, line & \n);
RETURN tr.shatter(" ,", "", TRUE);
END ShatterLine;
PROCEDURE ParseConstToken (p: TokPragma; rd: Rd.T) =
VAR
self := p.spec;
cur := ShatterLine(rd);
BEGIN
(* DebugPrintList(cur, "Const"); *)
self.tokens := TextList.Append(self.tokens, cur);
WHILE cur # NIL DO
INC(self.lastConstCode);
EVAL self.constTokens.put(cur.head, self.lastConstCode);
EVAL self.constTokensR.put(self.lastConstCode, cur.head);
cur := cur.tail;
END;
END ParseConstToken;
PROCEDURE MakeCharConsts (self: T) =
VAR
name: TEXT;
code: INTEGER;
BEGIN
FOR c := FIRST(CHAR) TO LAST(CHAR) DO
IF c IN self.charTokens THEN
code := ORD(c);
name := CharCodes.QC(c);
EVAL self.constTokens.put(name, code);
EVAL self.constTokensR.put(code, name);
END;
END;
END MakeCharConsts;
PROCEDURE DebugPrintList(a: TextList.T; m: TEXT) =
VAR
cur := a;
BEGIN
WHILE cur # NIL DO
Wr.PutText(Stdio.stderr, m & : & cur.head & \n);
cur := cur.tail;
END;
END DebugPrintList;
PROCEDUREParseToken (p: TokPragma; rd: Rd.T) = VAR self := p.spec; newTokens := ShatterLine(rd); BEGIN (* DebugPrintList(newTokens, "VAR"); *) self.tokens := TextList.Append(self.tokens, newTokens); self.varTokens := TextList.Append(self.varTokens, newTokens); END ParseToken; PROCEDURECheckDuplicates (self: T) = VAR cur := self.tokens; check := NEW(TextIntTbl.Default).init(); dummy: INTEGER; BEGIN WHILE cur # NIL DO IF check.get(cur.head, dummy) THEN self.error(NIL, "duplicate token: " & CharCodes.Q(cur.head)); ELSE EVAL check.put(cur.head, dummy); END; cur := cur.tail; END; END CheckDuplicates; PROCEDURERead (self: T; from: Rd.T) = VAR charToken := NEW(TokPragma, spec := self, do := ParseCharToken); const := NEW(TokPragma, spec := self, do := ParseConstToken); token := NEW(TokPragma, spec := self, do := ParseToken); prag := NEW(PragmaRead.T).init(); BEGIN prag.add(charToken, "%char"); prag.add(const, "%const"); prag.add(token, "%token"); prag.add(token, ""); prag.apply(from); MakeCharConsts(self); CheckDuplicates(self); END Read; PROCEDUREError (<*UNUSED*>self: T; rd: Rd.T; message: TEXT) = BEGIN FileRdErr.E(rd, message); END Error; PROCEDUREFmtVar (self: T; form: TEXT): TEXT = VAR cur := self.varTokens; wr := TextWr.New(); subs: TextSubs.T; BEGIN WHILE cur # NIL DO subs := NEW(TextSubs.T).init(); subs.add("%name", cur.head); Wr.PutText(wr, subs.apply(form)); cur := cur.tail; END; RETURN TextWr.ToText(wr); END FmtVar; PROCEDUREFmtOrig (self: T; tokMN: TEXT): TEXT = VAR tokMNa: TEXT; BEGIN IF tokMN = NIL THEN tokMNa := ""; ELSE tokMNa := tokMN & ".Original_"; END; RETURN self.fmtVar(" Original_%name = " &tokMNa& "%name;\n"); END FmtOrig; BEGIN END TokSpec.