-- CreateNewLookupImpl.mesa -- ryu 27-Jun-84 19:48:39 DIRECTORY CESDictDataDefs USING [DictBytesPerEntry, Entry], JLispLookupFile USING [MaxKanaPerEntry, MaxKanjiPerEntry, LEntry, DictPtr], CharDefs USING [Char, Code], PhonicDefs USING [Phonics], CreateLookupDictDefs, Heap USING [Create, Delete], Put USING [Text, Line, Decimal], Stream USING [Block, CompletionCode, Handle, PutByte, PutWord, GetBlock, SetPosition], Space USING [PageCount], Window USING [Handle]; CreateNewLookupImpl: PROGRAM IMPORTS Stream, Heap, Put EXPORTS CreateLookupDictDefs = BEGIN -- Types IndexRecord: TYPE = RECORD [ kana: CharDefs.Code, flag: {internal, external} ← internal, count: CARDINAL ← 0, next: LONG POINTER TO IndexRecord ← NIL, lower: LONG POINTER TO IndexRecord ← NIL, firstI: CARDINAL ← 0, lastI: CARDINAL ← 0, dictPtr: JLispLookupFile.DictPtr ← [0, , 0]]; -- Constants Onesbyte: CARDINAL = 377B; nullPhonic: CharDefs.Code = PhonicDefs.Phonics[nullPhonic].ORD; nullPtr: JLispLookupFile.DictPtr = [0, , 0]; MaxEntries : CARDINAL = 134; maxCount: CARDINAL = 30; -- Variables pRootIndex, pI0, pI1, pI2: LONG POINTER TO IndexRecord ← NIL; currentIndex: CARDINAL ← 0; kana0, kana1, kana2: CharDefs.Code ← nullPhonic; nKanaCodes : CARDINAL ← 0; KanaCode : PACKED ARRAY [0..JLispLookupFile.MaxKanaPerEntry) OF CharDefs.Code; kanjiArray: ARRAY [0..JLispLookupFile.MaxKanjiPerEntry) OF CharDefs.Char; nKanjis: CARDINAL ← 0; mEntry: CESDictDataDefs.Entry; pMEntry: LONG POINTER TO CESDictDataDefs.Entry ← @mEntry; inBlock: Stream.Block ← [LOOPHOLE [LONG[@mEntry]], 0, CESDictDataDefs.DictBytesPerEntry]; nBytes: CARDINAL ← 0; currentDictPtr, oldDictPtr: JLispLookupFile.DictPtr; recsize : CARDINAL ← 0; nLEntries : CARDINAL ← 0; pLEntry : ARRAY [0 .. MaxEntries] OF LONG POINTER TO JLispLookupFile.LEntry; myZone: UNCOUNTED ZONE; zoneSize: Space.PageCount = 200; firstTime: BOOLEAN; why: Stream.CompletionCode; -- Create is the Main Line of this module CreateLookupDict: PUBLIC PROCEDURE [masterStrH: Stream.Handle, lookupStrH: Stream.Handle, indexStrH: Stream.Handle, msgSW, logSW: Window.Handle] RETURNS [nEntry, ctSkipped: LONG CARDINAL] = BEGIN -- Initialize initializes the index table (first part) of the lookup dictionary Initialize: PROCEDURE[] = BEGIN myZone ← Heap.Create[initial: zoneSize, increment: 10, threshold: 16, checking: TRUE]; KanaCode ← ALL [nullPhonic]; -- kana0, kana1, kana2 ← nullPhonic; nLEntries ← 0; pLEntry ← ALL [NIL]; recsize ← 0; currentDictPtr.dictPageNo ← 0; currentDictPtr.relAddr ← 1; oldDictPtr ← currentDictPtr; Stream.SetPosition[indexStrH, LONG[0] ]; Stream.PutWord[lookupStrH, 0]; firstTime ← TRUE; END; -- Pass1 Pass1: PROCEDURE[] = BEGIN DO -- Pass 1 [nBytes, why] ← Stream.GetBlock[masterStrH, inBlock]; IF why = endOfStream THEN { LastEntry[pMEntry]; EXIT }; IF pMEntry.pos >= 1 AND pMEntry.pos <= 60B AND --(pMEntry.freq >= 8 OR pMEntry.kanji[1].code.ORD = Onesbyte AND pMEntry.freq >= 5) (pMEntry.kanji[1].code.ORD = Onesbyte OR pMEntry.freq >= 4) THEN AddEntry[pMEntry]; ENDLOOP; Put.Line[logSW, "End of Pass 1"L]; END; -- AddEntry AddEntry: PROCEDURE [pMEntry: LONG POINTER TO CESDictDataDefs.Entry] = BEGIN ConvertNullPhonic[pMEntry]; IF EqKana[KanaCode, pMEntry.kana] THEN SameRecord[pMEntry] ELSE DifferentRecord[pMEntry]; END; -- ConvertNullPhonic ConvertNullPhonic: PROCEDURE [pMEntry: LONG POINTER TO CESDictDataDefs.Entry] = BEGIN FOR i: CARDINAL IN [0..JLispLookupFile.MaxKanaPerEntry) DO IF pMEntry.kana[i] = Onesbyte THEN pMEntry.kana[i] ← nullPhonic; ENDLOOP; END; -- EqKana EqKana: PROCEDURE[kana1, kana2: PACKED ARRAY [0..JLispLookupFile.MaxKanaPerEntry) OF CharDefs.Code] RETURNS[BOOLEAN] = BEGIN FOR i: CARDINAL IN [0..JLispLookupFile.MaxKanaPerEntry) DO IF kana1[i] # kana2[i] THEN RETURN[FALSE]; IF kana1[i] = nullPhonic THEN RETURN[TRUE]; ENDLOOP; RETURN[TRUE] END; -- SameRecord SameRecord: PROCEDURE [pMEntry: LONG POINTER TO CESDictDataDefs.Entry] = BEGIN nWords: CARDINAL; IF nLEntries >= MaxEntries THEN { Put.Text[logSW, "Entry table overflow: "L]; FOR i: CARDINAL IN [0 .. nKanaCodes-1) DO Put.Decimal[logSW, KanaCode[i]]; Put.Text[logSW, ", "] ENDLOOP; Put.Decimal[logSW, KanaCode[nKanaCodes-1]]; Put.Line[logSW, " "L] } ELSE { [nWords, pLEntry[nLEntries]] ← ConvertEntry[pMEntry]; nLEntries ← nLEntries + 1; recsize ← recsize + nWords; pI0.count ← pI0.count + 1; pI1.count ← pI1.count + 1; pI2.count ← pI2.count + 1; nEntry ← nEntry + 1 }; END; -- ConvertEntry ConvertEntry: PROCEDURE [pMEntry: LONG POINTER TO CESDictDataDefs.Entry] RETURNS [nWords: CARDINAL, pLEntry: LONG POINTER TO JLispLookupFile.LEntry] = BEGIN nKanjis ← 0; FOR i: CARDINAL IN [0..JLispLookupFile.MaxKanjiPerEntry) DO kanjiArray[i] ← pMEntry.kanji[i]; IF kanjiArray[i].code # Onesbyte THEN nKanjis ← i + 1; ENDLOOP; pLEntry ← myZone.NEW[JLispLookupFile.LEntry[nKanjis]]; pLEntry.pos ← pMEntry.pos; pLEntry.pre ← 1; pLEntry.freq ← pMEntry.freq; pLEntry.nKanjis ← nKanjis; FOR i: CARDINAL IN [0..nKanjis) DO pLEntry.kanji[i] ← pMEntry.kanji[i] ENDLOOP; nWords ← nKanjis + 3; RETURN [nWords, pLEntry]; END; -- DifferentRecord DifferentRecord: PROCEDURE [pMEntry: LONG POINTER TO CESDictDataDefs.Entry] = BEGIN nWords: CARDINAL; IF ~firstTime THEN OutputPrevRecord[]; SetupKanaCodes[pMEntry]; ClearAllLEntries[]; [nWords, pLEntry[0]] ← ConvertEntry[pMEntry]; nLEntries ← 1; recsize ← nWords + CeilQuotient[nKanaCodes, 2] + 3; -- for recsize(1), nKanaCodes(1), and nLEntries(1) pI0.count ← pI0.count + 1; pI1.count ← pI1.count + 1; pI2.count ← pI2.count + 1; nEntry ← nEntry + 1; END; -- OutputPrevRecord OutputPrevRecord: PROCEDURE = BEGIN Stream.PutWord[lookupStrH, recsize]; Stream.PutWord[lookupStrH, nKanaCodes]; FOR i: CARDINAL IN [0..nKanaCodes) DO Stream.PutByte[lookupStrH, KanaCode[i]] ENDLOOP; IF nKanaCodes MOD 2 # 0 THEN Stream.PutByte[lookupStrH, nullPhonic]; Stream.PutWord[lookupStrH, nLEntries]; FOR i: CARDINAL IN [0..nLEntries) DO OutputEntry[ pLEntry[i] ]; ENDLOOP; AdvancePtr[recsize]; END; -- OutputEntry OutputEntry: PROCEDURE[pLEntry: LONG POINTER TO JLispLookupFile.LEntry] = BEGIN Stream.PutWord[lookupStrH, pLEntry.nKanjis]; FOR i: CARDINAL IN [0..pLEntry.nKanjis) DO Stream.PutByte[lookupStrH, pLEntry.kanji[i].chset]; Stream.PutByte[lookupStrH, pLEntry.kanji[i].code] ENDLOOP; Stream.PutByte[lookupStrH, pLEntry.pos]; Stream.PutByte[lookupStrH, pLEntry.pre]; Stream.PutByte[lookupStrH, pLEntry.freq]; Stream.PutByte[lookupStrH, pLEntry.reserved]; END; -- OutputDictPtr OutputDictPtr: PROCEDURE [strH: Stream.Handle, aDictPtr: JLispLookupFile.DictPtr] = BEGIN Stream.PutWord[strH, aDictPtr.dictPageNo]; Stream.PutByte[strH, aDictPtr.padding]; Stream.PutByte[strH, aDictPtr.relAddr]; END; -- AdvancePtr AdvancePtr: PROCEDURE[adv: CARDINAL] = BEGIN temp: CARDINAL; temp ← CARDINAL[currentDictPtr.relAddr] + adv; currentDictPtr.dictPageNo ← currentDictPtr.dictPageNo + temp/256; currentDictPtr.relAddr ← temp MOD 256; END; -- ClearAllLEntries ClearAllLEntries: PROCEDURE = BEGIN FOR i: CARDINAL IN [0.. nLEntries) DO myZone.FREE[ @pLEntry[i] ]; ENDLOOP; END; -- SetupKanaCodes SetupKanaCodes: PROCEDURE [pMEntry: LONG POINTER TO CESDictDataDefs.Entry] = BEGIN FOR i: CARDINAL IN [0..JLispLookupFile.MaxKanaPerEntry) DO KanaCode[i] ← pMEntry.kana[i]; IF KanaCode[i] # nullPhonic THEN nKanaCodes ← i + 1 ENDLOOP; IF KanaCode[0] # kana0 THEN NewKana0[] ELSE IF KanaCode[1] # kana1 THEN NewKana1[] ELSE IF KanaCode[2] # kana2 THEN NewKana2[]; END; -- NewKana0 NewKana0: PROCEDURE [] = BEGIN new: LONG POINTER TO IndexRecord; kana0 ← KanaCode[0]; kana1 ← KanaCode[1]; kana2 ← KanaCode[2]; pI2 ← myZone.NEW[IndexRecord]; pI2↑ ← IndexRecord[kana: KanaCode[2], next: NIL, count: 0, flag: external, lower: NIL, dictPtr: currentDictPtr]; pI1 ← myZone.NEW[IndexRecord]; pI1↑ ← IndexRecord[kana: KanaCode[1], next: NIL, count: 0, lower: pI2, flag: internal, dictPtr: nullPtr]; new ← myZone.NEW[IndexRecord]; IF firstTime THEN { firstTime ← FALSE; pRootIndex ← new} ELSE pI0.next ← new; pI0 ← new; pI0↑ ← IndexRecord[kana: KanaCode[0], next: NIL, count: 0, lower: pI1, flag: internal, dictPtr: nullPtr]; END; -- NewKana1 NewKana1: PROCEDURE [] = BEGIN new: LONG POINTER TO IndexRecord; kana1 ← KanaCode[1]; kana2 ← KanaCode[2]; pI2 ← myZone.NEW[IndexRecord]; pI2↑ ← IndexRecord[kana: kana2, next: NIL, count: 0, flag: external, dictPtr: currentDictPtr]; new ← myZone.NEW[IndexRecord]; pI1.next ← new; pI1 ← new; pI1↑ ← IndexRecord[kana: kana1, next: NIL, count: 0, flag: internal, lower: pI2, dictPtr: nullPtr]; END; -- NewKana2 NewKana2: PROCEDURE [] = BEGIN new: LONG POINTER TO IndexRecord; kana2 ← KanaCode[2]; new ← myZone.NEW[IndexRecord]; pI2.next ← new; pI2 ← new; pI2↑ ← IndexRecord[kana: kana2, next: NIL, count: 0, flag: external, dictPtr: currentDictPtr]; END; -- LastEntry LastEntry: PROCEDURE [pMEntry: LONG POINTER TO CESDictDataDefs.Entry] = BEGIN OutputPrevRecord[]; ClearAllLEntries[]; END; -- CeilQuotient CeilQuotient: PROCEDURE [x, y: CARDINAL] RETURNS[CARDINAL] = BEGIN IF x MOD y = 0 THEN RETURN[x/y] ELSE RETURN[x/y+1] END; -- Pass2 Pass2: PROCEDURE [] = BEGIN FOR pi: LONG POINTER TO IndexRecord ← pRootIndex, pi.next UNTIL pi = NIL DO MergeIndex[pi]; ENDLOOP; Put.Line[logSW, "End of Pass 2"L]; END; -- MergeIndex MergeIndex: PROCEDURE [pI: LONG POINTER TO IndexRecord] = BEGIN IF pI = NIL OR pI.flag = external THEN RETURN; FOR pi: LONG POINTER TO IndexRecord ← pI, pi.next UNTIL pi = NIL DO IF pi.flag = internal THEN { MergeIndex[pi.lower]; IF pi.count <= maxCount OR pi.lower.next = NIL THEN { pi.flag ← external; pi.dictPtr ← pi.lower.dictPtr; pi.lower ← NIL; -- ? -- FreeIndex[pi.lower] -- } } ENDLOOP; END; -- FreeIndex FreeIndex: PROCEDURE [pI: LONG POINTER TO IndexRecord] = BEGIN this, next: LONG POINTER TO IndexRecord; IF pI = NIL THEN RETURN; this ← pI; next ← this.next; WHILE next ~= NIL DO myZone.FREE[ @this ]; this ← next; next ← this.next; ENDLOOP; myZone.FREE[ @this ]; END; -- Pass3 Pass3: PROCEDURE [] = BEGIN level0Count, level0F, level0L: CARDINAL; first, last: CARDINAL; level0L ← TotalCount[pRootIndex]; level0Count ← OneLevelCount[pRootIndex]; level0F ← level0L - level0Count + 1; OutputIndexHead[level0L, level0F, level0L]; [first, last] ← OutputIndices[pRootIndex]; IF first ~= level0F THEN { Put.Text[logSW, "level0F calculation error ... Calculated = "L]; Put.Decimal[logSW, level0F]; Put.Text[logSW, ", but real value = "L]; Put.Decimal[logSW, first]; Put.Line[logSW, " "L] }; IF last ~= level0L THEN { Put.Text[logSW, "level0L calculation error ... Calculated = "L]; Put.Decimal[logSW, level0L]; Put.Text[logSW, ", but real value = "L]; Put.Decimal[logSW, last]; Put.Line[logSW, " "L] }; Put.Line[logSW, "End of Pass 3"L]; END; -- OneLevelCount OneLevelCount: PROCEDURE [pI: LONG POINTER TO IndexRecord] RETURNS[count: CARDINAL] = BEGIN count ← 0; FOR pi: LONG POINTER TO IndexRecord ← pI, pi.next UNTIL pi = NIL DO count ← count + 1; ENDLOOP; RETURN[count]; END; -- TotalCount TotalCount: PROCEDURE [pI: LONG POINTER TO IndexRecord] RETURNS[count: CARDINAL] = BEGIN count ← 0; FOR pi: LONG POINTER TO IndexRecord ← pI, pi.next UNTIL pi = NIL DO IF pi.flag = internal THEN count ← count + 1 + TotalCount[pi.lower] ELSE count ← count + 1; ENDLOOP; RETURN [count]; END; -- OutputIndexHead OutputIndexHead: PROCEDURE [size, level0F, level0L: CARDINAL] = BEGIN Stream.PutWord[indexStrH, size]; Stream.PutWord[indexStrH, level0F]; Stream.PutWord[indexStrH, level0L]; currentIndex ← 1; END; -- OutputIndices OutputIndices: PROCEDURE [pI: LONG POINTER TO IndexRecord] RETURNS[first,last: CARDINAL] = BEGIN FOR pi: LONG POINTER TO IndexRecord ← pI, pi.next UNTIL pi = NIL DO IF pi.flag = internal THEN [pi.firstI, pi.lastI] ← OutputIndices[pi.lower]; ENDLOOP; first ← currentIndex; FOR pi: LONG POINTER TO IndexRecord ← pI, pi.next UNTIL pi = NIL DO OutputIndex[pi]; ENDLOOP; last ← currentIndex - 1; RETURN [first, last]; END; -- OutputIndex OutputIndex: PROCEDURE[pI: LONG POINTER TO IndexRecord] = BEGIN Stream.PutByte[indexStrH, pI.kana]; IF pI.flag = internal THEN { Stream.PutByte[indexStrH, pI.flag.ORD]; Stream.PutWord[indexStrH, pI.firstI]; Stream.PutWord[indexStrH, pI.lastI] } ELSE { Stream.PutByte[indexStrH, pI.flag.ORD]; OutputDictPtr[indexStrH, pI.dictPtr] }; currentIndex ← currentIndex + 1; END; -- main line of Create Initialize[]; nEntry ← 1; Pass1[]; Pass2[]; Pass3[]; Heap.Delete[myZone,TRUE]; RETURN[nEntry, 0]; END; -- of Create END.