DIRECTORY Ascii, Atom USING [MakeAtom], CIFS USING [ConnectionErrors, Error, Open, OpenFile, Close, GetFC, read], Directory USING [GetProperty], File USING [Capability], Intime USING [EventTime], FileIO USING [Open, StreamFromCapability], IO USING [Handle, Close, Error, GetIndex, int, Put, PutRope, SetLength], GPM USING [Close, Error, GetChar, GetIndex, Handle, Open], Interminal USING [KeyName], PropertyTypes USING [tCreateDate], Rope USING [Concat, Find, ROPE, FromRefText, Substr], SafeStorage USING [NewZone], System USING [GreenwichMeanTime, SecondsSinceEpoch], TIPPrivate, TIPUser, TIPTables; TIPTableBuilder: CEDAR MONITOR IMPORTS TIPPrivate, CIFS, Directory, GPM, SafeStorage, System, Rope, Atom, FileIO, IO EXPORTS TIPPrivate, TIPUser = BEGIN OPEN TIPPrivate, TIPTables, TIPUser; ReservedWord: REF PACKED ARRAY Symbol OF BOOLEAN _ NEW[PACKED ARRAY Symbol OF BOOLEAN]; fh: GPM.Handle; filename: Rope.ROPE; errlogfh: IO.Handle; fastOption: BOOLEAN; fastMouseOption: BOOLEAN; keyOption : KeyOption; errorText : PUBLIC REF ARRAY [0..nrOfErrors] OF Rope.ROPE _ NEW[ARRAY [0..nrOfErrors] OF Rope.ROPE]; keyNames: PUBLIC REF ARRAY Interminal.KeyName OF Rope.ROPE _ NEW[ARRAY Interminal.KeyName OF Rope.ROPE]; qZ: PUBLIC ZONE _ SafeStorage.NewZone[quantized]; -- quantized zone for allocations thereAreErrors: BOOLEAN; ch : CHARACTER; nextch : CHARACTER; havenext : BOOLEAN; symbol : Symbol; atom : ATOM; keyName : Interminal.KeyName; symPos : INT; number : CARDINAL; ident : REF TEXT _ NEW[TEXT[100]]; errcnt : CARDINAL; printKeyTable, defaultKeyTable: TIPTable _ NIL; DefaultTable: PROC [printKeys: BOOLEAN] RETURNS [TIPTable] = TRUSTED BEGIN key: Interminal.KeyName; enableTerm: keyEnable TIPTerm _ [keyEnable[[Ctrl, up]]]; charTerm: char TIPTerm _ [char[stdChar]]; resultTerm: result TIPTerm _ [result[qZ.LIST[charTerm.ch]]]; IF printKeys THEN BEGIN IF printKeyTable = NIL THEN BEGIN ctrlUpDefault: TIPChoice _ qZ.CONS[enableTerm, qZ.CONS[charTerm, qZ.LIST[resultTerm]]]; printKeyTable _ qZ.NEW[fast TIPTableRec]; printKeyTable.ignore.down _ FALSE; FOR key IN Interminal.KeyName DO -- includes CR, TAB and Space! SELECT key FROM IN [Five..BackSlash], IN [Three..RightBracket], IN [One..One], IN [TAB..F], IN [C..Z], IN [Period..Arrow], IN [R..M], IN [Space..Equal] => WITH printKeyTable SELECT FROM fast => keyDown[key] _ ctrlUpDefault; ENDCASE; ENDCASE; ENDLOOP; END; RETURN [printKeyTable]; END ELSE BEGIN IF defaultKeyTable = NIL THEN BEGIN normalDefault: TIPChoice _ qZ.CONS[charTerm, qZ.LIST[resultTerm]]; ctrlUpDefault: TIPChoice _ qZ.CONS[enableTerm, qZ.CONS[charTerm, qZ.LIST[resultTerm]]]; defaultKeyTable _ qZ.NEW[fast TIPTableRec]; defaultKeyTable.ignore.down _ FALSE; FOR key IN Interminal.KeyName DO -- includes CR and Space! SELECT key FROM E, IN [D..V], K, P, IN [W..A], IN [I..L], F, IN [C..Z], IN [R..H], IN [N..M] => WITH defaultKeyTable SELECT FROM fast => keyDown[key] _ normalDefault; ENDCASE; IN [Five..Six], IN [Seven..Seven], IN [Zero..Zero], IN [Dash..Dash], IN [Slash..BackSlash], IN [Three..Two], IN [Nine..Nine], IN [Comma..RightBracket], IN [One..One], IN [Period..Arrow], IN [Eight..Eight], IN [Space..Equal], IN [DEL..DEL], IN [LF..BS], IN [ESC..TAB] => WITH printKeyTable SELECT FROM fast => keyDown[key] _ normalDefault; ENDCASE; ENDCASE; ENDLOOP; END; RETURN [defaultKeyTable]; END; END; -- DefaultTable EndOfFile: SIGNAL = CODE; GetChar: PROC = BEGIN GetGPMChar: PROC RETURNS [ch: CHAR] = INLINE { ch _ GPM.GetChar[fh ! GPM.Error => { IF ec=EndOfStream THEN ch _ 0C; CONTINUE }] }; IF havenext THEN { havenext _ FALSE; ch _ nextch } ELSE ch _ GetGPMChar[]; IF ch = '- THEN BEGIN IF (nextch _ GetGPMChar[]) = '- THEN { -- scan over comment DO -- go to CR or double dash SELECT GetGPMChar[] FROM Ascii.CR, 0C => EXIT; '- => SELECT GetGPMChar[] FROM '-, Ascii.CR => EXIT; ENDCASE; ENDCASE; ENDLOOP; ch _ Ascii.SP } ELSE havenext _ TRUE; END; END; NCONC: PROC [list1, list2: TIPChoice] RETURNS[TIPChoice] = BEGIN l: TIPChoice _ list1; IF l = NIL THEN RETURN[list2]; UNTIL l.rest = NIL DO l _ l.rest; ENDLOOP; l.rest _ list2; RETURN[list1]; END; InstantiateNewTIPTable: PUBLIC PROC [file: Rope.ROPE _ NIL] RETURNS [table: TIPTable _ NIL] = { comp: Rope.ROPE; -- name of the compiled file compC, fileC: File.Capability; tryC: BOOLEAN _ TRUE; stream: IO.Handle; Lookup: PROC [name: Rope.ROPE] RETURNS [fc: File.Capability] = { fh: CIFS.OpenFile; fc _ CIFS.GetFC[fh _ CIFS.Open[name, CIFS.read]]; CIFS.Close[fh] }; GetCreateDate: PROC [fc: File.Capability] RETURNS [date: System.GreenwichMeanTime] = TRUSTED { Directory.GetProperty[file: fc, property: PropertyTypes.tCreateDate, propertyValue: DESCRIPTOR[@date, SIZE[System.GreenwichMeanTime]]] }; fileCD, compCD: System.GreenwichMeanTime; option, newKeyOption: KeyOption; newTable: TIPTable; slash: INT; comp _ Rope.Concat[file,"C"]; WHILE (slash _ Rope.Find[comp, "/"]) >= 0 DO -- strip off the remote info from front comp _ Rope.Substr[comp, slash+1]; ENDLOOP; compC _ Lookup[comp ! CIFS.Error => CHECKED { tryC _ FALSE; CONTINUE } ]; IF tryC THEN fileC _ Lookup[file ! CIFS.Error => CHECKED { tryC _ FALSE; CONTINUE } ]; IF tryC THEN { fileCD _ GetCreateDate[fileC]; compCD _ GetCreateDate[compC]; tryC _ System.SecondsSinceEpoch[fileCD] < System.SecondsSinceEpoch[compCD] }; IF tryC THEN { stream _ FileIO.Open[comp,read,oldOnly]; [table, option] _ ReadTIPTable[stream ! BadTable => CONTINUE]; IO.Close[stream] }; IF table # NIL THEN { IF option # none THEN { table.link _ DefaultTable[option=printKeys]; table.opaque _ FALSE }; RETURN }; [table, option] _ BuildNewTIPTable[file]; stream _ FileIO.Open[comp,overwrite]; WriteTIPTable[table, option, stream]; IO.Close[stream]; stream _ FileIO.Open[comp,read,oldOnly]; [newTable, newKeyOption] _ ReadTIPTable[stream]; IO.Close[stream]; IF newKeyOption # option THEN ERROR; EqualTables[table, newTable] }; BuildNewTIPTable: ENTRY PROC [file: Rope.ROPE] RETURNS [table: TIPTable _ NIL, option: KeyOption] = BEGIN ENABLE UNWIND => IF thereAreErrors THEN { GPM.Close[fh]; TruncateErrorLog[]; IO.Close[errlogfh]}; GetFile: PROC [file: Rope.ROPE] RETURNS [fh: CIFS.OpenFile] = CHECKED BEGIN err: BOOL _ FALSE; fh _ CIFS.Open[file, CIFS.read ! CIFS.Error => IF code IN CIFS.ConnectionErrors THEN {err _ TRUE; CONTINUE}]; IF err THEN BEGIN -- maybe the file is also on IVY tryFile: Rope.ROPE; tryFile _ Rope.Substr[file, 1]; tryFile _ Rope.Substr[tryFile, Rope.Find[tryFile, "/"]]; tryFile _ Rope.Concat["/Ivy", tryFile]; fh _ CIFS.Open[tryFile, CIFS.read]; -- if this fails then give up END; END; errMsg: Rope.ROPE; BEGIN -- fake begin to get around bug where double catch phrase fails ENABLE BEGIN GPM.Error => {errMsg _ errorMsg; GOTO MacroCleanup}; TIPError => GOTO Cleanup; END; statement: TIPChoiceSeries; cifsFH: CIFS.OpenFile; filename _ file; cifsFH _ GetFile[file]; fh _ GPM.Open[FileIO.StreamFromCapability[CIFS.GetFC[cifsFH],read]]; CIFS.Close[cifsFH]; fh.startCall _ '[; fh.endCall _ ']; fh.singleQuote _ '; -- 004 octal fh.startQuote _ '(; fh.endQuote _ '); fh.sepArg _ ',; fh.numArg _ '~; thereAreErrors _ FALSE; errcnt _ 0; havenext _ FALSE; fastOption _ FALSE; fastMouseOption _ FALSE; keyOption _ none; GetChar; GetSymbol; IF symbol = OptionSym THEN Options; option _ keyOption; IF symbol = Select THEN BEGIN GetSymbol; IF symbol = Trigger THEN BEGIN GetSymbol; statement _ TriggerStmt[]; END ELSE Error[5]; IF symbol # Dot THEN Error[3]; END ELSE Error[1]; GPM.Close[fh]; IF ~thereAreErrors THEN table _ CreateTable[statement]; IF thereAreErrors THEN ErrorFinish; -- finish the error log and raise signal EXITS Cleanup => { ErrorFinish }; MacroCleanup => { IF ~thereAreErrors THEN OpenErrorLog; thereAreErrors _ TRUE; errcnt _ errcnt+1; IO.PutRope[errlogfh, "Error from macro package\n\n"]; IO.PutRope[errlogfh, errMsg]; ErrorFinish }; END; -- fake block (see above) END; -- InstantiateNewTIPTable TruncateErrorLog: PROC = { { ENABLE IO.Error => GOTO Exit; IO.SetLength[errlogfh, IO.GetIndex[errlogfh]] } EXITS Exit => NULL }; ErrorFinish: PROC = { OPEN IO; TruncateErrorLog[]; Close[errlogfh]; SIGNAL InvalidTable[Rope.Concat[filename," errors on TIP.ERRORS"]] }; CreateTable: PROC[series: TIPChoiceSeries] RETURNS[table: TIPTable] = TRUSTED BEGIN IF fastOption THEN BEGIN table _ qZ.NEW[fast TIPTableRec]; WITH table SELECT FROM fast => FOR choiceSeries: TIPChoiceSeries _ series, choiceSeries.rest UNTIL choiceSeries = NIL DO choice: TIPChoice _ choiceSeries.first; WITH choice.first SELECT FROM keyTrigger => IF keyState.state = up THEN BEGIN ignore.up _ FALSE; IF keyUp[keyState.key] # NIL THEN DoubleDef[keyState.key]; keyUp[keyState.key] _ choice.rest; END ELSE BEGIN ignore.down _ FALSE; IF keyDown[keyState.key] # NIL THEN DoubleDef[keyState.key]; keyDown[keyState.key] _ choice.rest; END; mouseTrigger => BEGIN ignore.move _ FALSE; IF mouse # NIL THEN Error[25]; mouse _ choice.rest END; timeTrigger => Error[]; -- to be detected earlier !!! ENDCASE; ENDLOOP; ENDCASE; END ELSE BEGIN table _ qZ.NEW[small TIPTableRec]; WITH table SELECT FROM small => BEGIN FOR choiceSeries: TIPChoiceSeries _ series, choiceSeries.rest UNTIL choiceSeries = NIL DO choice: TIPChoice _ choiceSeries.first; WITH choice.first SELECT FROM keyTrigger => IF keyState.state = up THEN ignore.up _ FALSE ELSE ignore.down _ FALSE; mouseTrigger => ignore.move _ FALSE; timeTrigger => Error[]; -- to be detected earlier !!! ENDCASE => ERROR; ENDLOOP; all _ series; END; ENDCASE; END; IF keyOption # none THEN BEGIN table.link _ DefaultTable[keyOption=printKeys]; table.opaque _ FALSE; END; IF fastMouseOption THEN table.mouseTicks _ 0; END; -- CreateTable Options: PROC = BEGIN GetSymbol; DO -- until see Semicolon SELECT symbol FROM Fast => fastOption _ TRUE; Small => fastOption _ FALSE; DefaultKeys => keyOption _ defaultKeys; PrintKeys => keyOption _ printKeys; FastMouse => fastMouseOption _ TRUE; SlowMouse => fastMouseOption _ FALSE; ENDCASE => Error[18]; GetSymbol; SELECT symbol FROM Semicolon => EXIT; Comma => NULL; ENDCASE => Error[19]; GetSymbol; ENDLOOP; GetSymbol; END; -- Options CheckForUniqueSymbol: PROC[symbols: LIST OF ATOM] = BEGIN FOR list: LIST OF ATOM _ symbols, list.rest UNTIL list = NIL DO IF list.first = atom THEN GOTO notUnique; REPEAT notUnique => Error[17]; FINISHED => symbols _ qZ.CONS[atom, symbols]; -- !!! ENDLOOP; END; TriggerStmt: PROC RETURNS[choiceSeries: TIPChoiceSeries] = BEGIN usedSymbols: LIST OF ATOM _ NIL; IF symbol = From THEN GetSymbol ELSE BEGIN Error[6]; END; choiceSeries _ TriggerChoiceSeries[]; END; -- TriggerStmt EnableStmt: PROC RETURNS[choiceSeries: TIPChoiceSeries] = BEGIN usedSymbols: LIST OF ATOM _ NIL; IF symbol = From THEN GetSymbol ELSE BEGIN Error[20]; END; choiceSeries _ EnableChoiceSeries[]; END; -- EnableStmt TriggerChoiceSeries: PROC RETURNS[choiceSeries: TIPChoiceSeries] = BEGIN choice: TIPChoice; IF symbol = Endcase THEN BEGIN GetSymbol; choiceSeries _ FinalChoice[]; RETURN END; choice _ TriggerChoice[]; IF symbol = Semicolon THEN BEGIN GetSymbol; choiceSeries _ qZ.CONS[choice, TriggerChoiceSeries[]]; END ELSE IF symbol = Endcase THEN BEGIN GetSymbol; choiceSeries _ qZ.CONS[choice, FinalChoice[]]; -- may be NIL !?!? END ELSE BEGIN Error[2]; END; END; -- TriggerChoiceSeries EnableChoiceSeries: PROC RETURNS[choiceSeries: TIPChoiceSeries] = BEGIN choice: TIPChoice; IF symbol = Endcase THEN BEGIN GetSymbol; choiceSeries _ FinalChoice[]; RETURN END; choice _ EnableChoice[]; IF symbol = Semicolon THEN BEGIN GetSymbol; choiceSeries _ qZ.CONS[choice, EnableChoiceSeries[]]; END ELSE IF symbol = Endcase THEN BEGIN GetSymbol; choiceSeries _ qZ.CONS[choice, FinalChoice[]]; -- may be NIL !?!? END ELSE BEGIN Error[2]; END; END; -- EnableChoiceSeries TriggerChoice: PROC RETURNS[triggerChoice: TIPChoice] = BEGIN term: TIPChoice _ TriggerTerm[]; triggerChoice _ NCONC[term, Expression[]]; END; -- TriggerChoice EnableChoice: PROC RETURNS[enableChoice: TIPChoice] = BEGIN term: TIPChoice _ EnableTerm[]; enableChoice _ NCONC[term, Expression[]]; END; -- EnableChoice TriggerTerm: PROC RETURNS[triggerTerm: TIPChoice] = BEGIN SELECT symbol FROM KeyIdent => BEGIN keyTerm: keyTrigger TIPTerm; keyTerm.keyState _ Key[]; triggerTerm _ qZ.LIST[keyTerm]; END; Mouse => BEGIN mouseTerm: mouseTrigger TIPTerm; triggerTerm _ qZ.LIST[mouseTerm]; GetSymbol; END; ENDCASE => BEGIN Error[8]; END; IF symbol = Before OR symbol = After THEN triggerTerm _ qZ.CONS[TimeOut[], triggerTerm]; END; -- TriggerTerm EnableTerm: PROC RETURNS[enableTerm: TIPChoice] = BEGIN IF symbol = KeyIdent THEN enableTerm _ Keys[] ELSE IF symbol = Ident THEN BEGIN predTerm: predEnable TIPTerm; predTerm.predicate _ atom; enableTerm _ qZ.LIST[predTerm]; GetSymbol; END ELSE BEGIN Error[21] END; END; -- EnableTerm Keys: PROC RETURNS[enableTerm: TIPChoice] = TRUSTED BEGIN first: TIPKeyState _ Key[]; SELECT symbol FROM VertBar => BEGIN rest: TIPChoice; GetSymbol; IF symbol # KeyIdent THEN Error[21]; rest _ Keys[]; WITH x:rest.first SELECT FROM keyEnable => BEGIN keyTerm: key2Enable TIPTerm; keyTerm.keyState1 _ first; keyTerm.keyState2 _ x.keyState; enableTerm _ qZ.LIST[keyTerm]; END; key2Enable => BEGIN keyTerm: keyEnableList TIPTerm; keyTerm.lst _ qZ.LIST[first, x.keyState1, x.keyState2]; enableTerm _ qZ.LIST[keyTerm]; END; keyEnableList => BEGIN keyTerm: keyEnableList TIPTerm; keyTerm.lst _ qZ.CONS[first, x.lst]; enableTerm _ qZ.LIST[keyTerm]; END; ENDCASE => ERROR; END; ENDCASE => BEGIN keyTerm: keyEnable TIPTerm; keyTerm.keyState _ first; enableTerm _ qZ.LIST[keyTerm]; END; END; -- Keys Key: PROC RETURNS[keySt: TIPKeyState] = BEGIN name: Interminal.KeyName _ keyName; GetSymbol; IF symbol = Up OR symbol = Down THEN BEGIN keySt _ [key: name, state: IF symbol = Up THEN up ELSE down]; GetSymbol; END ELSE Error[12]; END; -- Key TimeOut: PROC RETURNS[timeoutExpr: timeTrigger TIPTerm] = BEGIN fl: TimeoutFlavor _ IF symbol = Before THEN lt ELSE gt; GetSymbol; IF symbol = Number THEN BEGIN timeoutExpr.flavor _ fl; timeoutExpr.mSecs _ number; GetSymbol; END ELSE BEGIN Error[10]; END; END; -- TimeOut Expression: PROC RETURNS[expression: TIPChoice] = BEGIN SELECT symbol FROM And => BEGIN GetSymbol; expression _ TriggerChoice[]; END; While => BEGIN GetSymbol; expression _ EnableChoice[]; END; RightArrow => BEGIN GetSymbol; expression _ Statement[]; END; ENDCASE => Error[22]; END; -- Expression Results: PROC RETURNS[resultList: LIST OF REF ANY, resultChoice: TIPChoice] = BEGIN resultItem: REF ANY; resultExpr: REF TIPTerm; IF symbol = LeftCurly THEN BEGIN GetSymbol; [resultList, resultChoice] _ ResultItems[]; RETURN; END; [resultItem, resultExpr] _ ResultItem[]; SELECT symbol FROM Comma => BEGIN resultItemList: LIST OF REF ANY; resultExprList: TIPChoice; GetSymbol; [resultItemList, resultExprList] _ Results[]; resultList _ qZ.CONS[resultItem, resultItemList]; resultChoice _ IF resultExpr = NIL THEN resultExprList ELSE qZ.CONS[resultExpr^, resultExprList]; END; ENDCASE => BEGIN userResultList: result TIPTerm; resultList _ qZ.LIST[resultItem]; resultChoice _ IF resultExpr = NIL THEN qZ.LIST[userResultList] ELSE qZ.CONS[resultExpr^, qZ.LIST[userResultList]]; END; END; -- Results Store: PROC[resultList: LIST OF REF ANY, tree: TIPChoice] = BEGIN nestedChoice: TIPChoiceSeries; FOR choice: TIPChoice _ tree, choice.rest UNTIL choice=NIL DO TRUSTED {WITH term: choice.first SELECT FROM nested => FOR nestedChoice _ term.statement, nestedChoice.rest UNTIL nestedChoice=NIL DO Store[resultList, nestedChoice.first]; ENDLOOP; result => BEGIN IF term.list = NIL THEN term.list _ resultList ELSE BEGIN Error[24]; term.list _ resultList; -- !!! END; END; ENDCASE}; ENDLOOP; END; -- Store ResultItems: PROC RETURNS[resultList: LIST OF REF ANY, resultChoice: TIPChoice] = BEGIN resultItem: REF ANY; resultExpr: REF TIPTerm; [resultItem, resultExpr] _ ResultItem[]; SELECT symbol FROM RightCurly => BEGIN userResultList: result TIPTerm; GetSymbol; resultList _ qZ.LIST[resultItem]; resultChoice _ IF resultExpr = NIL THEN qZ.LIST[userResultList] ELSE qZ.CONS[resultExpr^, qZ.LIST[userResultList]]; END; ENDCASE => BEGIN resultItemList: LIST OF REF ANY; resultExprList: TIPChoice; [resultItemList, resultExprList] _ ResultItems[]; resultList _ qZ.CONS[resultItem, resultItemList]; resultChoice _ IF resultExpr = NIL THEN resultExprList ELSE qZ.CONS[resultExpr^, resultExprList]; END; END; ResultItem: PROC RETURNS[resultItem: REF ANY, resultExpr: REF TIPTerm _ NIL] = BEGIN SELECT symbol FROM Char => BEGIN resultExpr _ qZ.NEW[char TIPTerm _ [char[resultItem _ stdChar]]]; GetSymbol; END; Coords => BEGIN resultExpr _ qZ.NEW[coords TIPTerm _ [coords[resultItem _ stdCoords]]]; GetSymbol; END; Time => BEGIN resultExpr _ qZ.NEW[time TIPTerm _ [time[resultItem _ stdTime]]]; GetSymbol; END; KeyIdent, -- result names might be key names Ident => BEGIN resultItem _ atom; GetSymbol; END; Number => BEGIN resultItem _ qZ.NEW[LONG INTEGER]; WITH resultItem SELECT FROM z: REF LONG INTEGER => z^ _ number; ENDCASE; GetSymbol; END; String => BEGIN resultItem _ NEW[TEXT[ident.length]]; WITH resultItem SELECT FROM z: REF TEXT => BEGIN FOR i: CARDINAL IN [0..ident.length) DO z[i] _ ident[i]; ENDLOOP; z.length _ ident.length; END; ENDCASE; GetSymbol; END; ENDCASE => IF ReservedWord[symbol] THEN BEGIN resultItem _ atom; GetSymbol; END ELSE Error[9]; END; -- ResultItem FinalChoice: PROC RETURNS[finalChoice: TIPChoiceSeries] = BEGIN IF symbol = RightArrow THEN BEGIN GetSymbol; finalChoice _ qZ.LIST[Statement[]]; END; END; -- FinalChoice Statement: PROC RETURNS[stmt: TIPChoice] = BEGIN IF symbol = Select THEN BEGIN term: nested TIPTerm; GetSymbol; IF symbol = Trigger OR symbol = Enable THEN BEGIN sy: Symbol _ symbol; GetSymbol; term.statement _ IF sy = Trigger THEN TriggerStmt[] ELSE EnableStmt[]; stmt _ qZ.LIST[term]; END ELSE BEGIN Error[13]; END; END ELSE BEGIN userResults: LIST OF REF ANY; [userResults, stmt] _ Results[]; Store[userResults, stmt]; END; END; -- Statement stdChar: PUBLIC REF CHARACTER _ qZ.NEW[CHARACTER]; stdCoords: PUBLIC TIPScreenCoords _ qZ.NEW[TIPScreenCoordsRec]; stdTime: PUBLIC TIPTables.TIPTime _ qZ.NEW[Intime.EventTime]; InvalidTable: PUBLIC SIGNAL [errorMsg: Rope.ROPE] = CODE; OpenErrorLog: PROC = { errlogfh _ FileIO.Open["tip.errors",overwrite]; IO.PutRope[errlogfh, filename]; IO.PutRope[errlogfh, " TIP TABLE error log.\n\n"] }; DoubleDef: PROC[key: Interminal.KeyName] = BEGIN IF ~thereAreErrors THEN OpenErrorLog; thereAreErrors _ TRUE; errcnt _ errcnt+1; IO.PutRope[errlogfh, keyNames[key]]; IO.PutRope[errlogfh, " entry must not occur more than once in table.\n\n"]; END; TIPError: ERROR = CODE; debug: BOOL _ FALSE; Error: PROC[nr: CARDINAL _ 0] = { OPEN IO; IF ~thereAreErrors THEN OpenErrorLog; thereAreErrors _ TRUE; errcnt _ errcnt+1; PutRope[errlogfh, errorText[nr]]; PutRope[errlogfh, " at "]; Put[errlogfh, int[symPos]]; PutRope[errlogfh, "\n\n"]; IF debug THEN ERROR ELSE ERROR TIPError }; GetSymbol: PROC = BEGIN GetNumber: PROC = BEGIN symbol _ Number; number _ 0; WHILE ch IN ['0..'9] DO number _ 10*number + ch-'0; GetChar; ENDLOOP; END; TranslateAtom: PROC[name: Interminal.KeyName, sym: Symbol] = INLINE BEGIN symbol _ sym; keyName _ name END; GetWord: PROC = BEGIN dummy: Interminal.KeyName = allUp; i: CARDINAL _ 0; WHILE ch IN ['0..'9] OR ch IN ['a..'z] OR ch IN ['A..'Z] DO ident[i] _ ch; i _ i + 1; GetChar; ENDLOOP; ident.length _ i; atom _ Atom.MakeAtom[Rope.FromRefText[ident]]; SELECT atom FROM $OPTIONS => TranslateAtom[dummy, OptionSym]; $SELECT => TranslateAtom[dummy, Select]; $TRIGGER => TranslateAtom[dummy, Trigger]; $ENABLE => TranslateAtom[dummy, Enable]; $FROM => TranslateAtom[dummy, From]; $ENDCASE => TranslateAtom[dummy, Endcase]; $END => TranslateAtom[dummy, End]; $AND => TranslateAtom[dummy, And]; $WHILE => TranslateAtom[dummy, While]; $AFTER => TranslateAtom[dummy, After]; $BEFORE => TranslateAtom[dummy, Before]; $Up => TranslateAtom[dummy, Up]; $Down => TranslateAtom[dummy, Down]; $Mouse => TranslateAtom[dummy, Mouse]; $Char => TranslateAtom[dummy, Char]; $Coords => TranslateAtom[dummy, Coords]; $TIME => TranslateAtom[dummy, Time]; $Small => TranslateAtom[dummy, Small]; $Fast => TranslateAtom[dummy, Fast]; $FastMouse => TranslateAtom[dummy, FastMouse]; $SlowMouse => TranslateAtom[dummy, SlowMouse]; $PrintKeys => TranslateAtom[dummy, PrintKeys]; $DefaultKeys => TranslateAtom[dummy, DefaultKeys]; $x0 => TranslateAtom[x0, KeyIdent]; $x1 => TranslateAtom[x1, KeyIdent]; $x2 => TranslateAtom[x2, KeyIdent]; $x3 => TranslateAtom[x3, KeyIdent]; $x4 => TranslateAtom[x4, KeyIdent]; $x5 => TranslateAtom[x5, KeyIdent]; $x6 => TranslateAtom[x6, KeyIdent]; $Pen => TranslateAtom[pen, KeyIdent]; $Keyset1 => TranslateAtom[Keyset1, KeyIdent]; $Keyset2 => TranslateAtom[Keyset2, KeyIdent]; $Keyset3 => TranslateAtom[Keyset3, KeyIdent]; $Keyset4 => TranslateAtom[Keyset4, KeyIdent]; $Keyset5 => TranslateAtom[Keyset5, KeyIdent]; $Red => TranslateAtom[Red, KeyIdent]; $Blue => TranslateAtom[Blue, KeyIdent]; $Yellow => TranslateAtom[Yellow, KeyIdent]; $Five => TranslateAtom[Five, KeyIdent]; $Four => TranslateAtom[Four, KeyIdent]; $Six => TranslateAtom[Six, KeyIdent]; $E => TranslateAtom[E, KeyIdent]; $Seven => TranslateAtom[Seven, KeyIdent]; $D => TranslateAtom[D, KeyIdent]; $U => TranslateAtom[U, KeyIdent]; $V => TranslateAtom[V, KeyIdent]; $Zero => TranslateAtom[Zero, KeyIdent]; $K => TranslateAtom[K, KeyIdent]; $Dash => TranslateAtom[Dash, KeyIdent]; $P => TranslateAtom[P, KeyIdent]; $Slash => TranslateAtom[Slash, KeyIdent]; $BackSlash => TranslateAtom[BackSlash, KeyIdent]; $LF => TranslateAtom[LF, KeyIdent]; $BS => TranslateAtom[BS, KeyIdent]; $Three => TranslateAtom[Three, KeyIdent]; $Two => TranslateAtom[Two, KeyIdent]; $W => TranslateAtom[W, KeyIdent]; $Q => TranslateAtom[Q, KeyIdent]; $S => TranslateAtom[S, KeyIdent]; $A => TranslateAtom[A, KeyIdent]; $Nine => TranslateAtom[Nine, KeyIdent]; $I => TranslateAtom[I, KeyIdent]; $X => TranslateAtom[X, KeyIdent]; $O => TranslateAtom[O, KeyIdent]; $L => TranslateAtom[L, KeyIdent]; $Comma => TranslateAtom[Comma, KeyIdent]; $Quote => TranslateAtom[Quote, KeyIdent]; $RightBracket => TranslateAtom[RightBracket, KeyIdent]; $Spare2 => TranslateAtom[Spare2, KeyIdent]; $BW => TranslateAtom[BW, KeyIdent]; $One => TranslateAtom[One, KeyIdent]; $ESC => TranslateAtom[ESC, KeyIdent]; $TAB => TranslateAtom[TAB, KeyIdent]; $F => TranslateAtom[F, KeyIdent]; $Ctrl => TranslateAtom[Ctrl, KeyIdent]; $C => TranslateAtom[C, KeyIdent]; $J => TranslateAtom[J, KeyIdent]; $B => TranslateAtom[B, KeyIdent]; $Z => TranslateAtom[Z, KeyIdent]; $LeftShift => TranslateAtom[LeftShift, KeyIdent]; $Period => TranslateAtom[Period, KeyIdent]; $SemiColon => TranslateAtom[SemiColon, KeyIdent]; $Return => TranslateAtom[Return, KeyIdent]; $Arrow => TranslateAtom[Arrow, KeyIdent]; $DEL => TranslateAtom[DEL, KeyIdent]; $FL3 => TranslateAtom[FL3, KeyIdent]; $R => TranslateAtom[R, KeyIdent]; $T => TranslateAtom[T, KeyIdent]; $G => TranslateAtom[G, KeyIdent]; $Y => TranslateAtom[Y, KeyIdent]; $H => TranslateAtom[H, KeyIdent]; $Eight => TranslateAtom[Eight, KeyIdent]; $N => TranslateAtom[N, KeyIdent]; $M => TranslateAtom[M, KeyIdent]; $Lock => TranslateAtom[Lock, KeyIdent]; $Space => TranslateAtom[Space, KeyIdent]; $LeftBracket => TranslateAtom[LeftBracket, KeyIdent]; $Equal => TranslateAtom[Equal, KeyIdent]; $RightShift => TranslateAtom[RightShift, KeyIdent]; $Spare3 => TranslateAtom[Spare3, KeyIdent]; $FL4 => TranslateAtom[FL4, KeyIdent]; ENDCASE => TranslateAtom[dummy, Ident]; END; GetString: PROC = BEGIN i: CARDINAL _ 0; DO -- process the characters of the string SELECT ch _ GPM.GetChar[fh] FROM '" => EXIT; '\\ => SELECT ch _ GPM.GetChar[fh] FROM 'n, 'N, 'r, 'R => ch _ Ascii.CR; 't, 'T => ch _ Ascii.TAB; 'b, 'B => ch _ Ascii.BS; 'f, 'F => ch _ Ascii.FF; 'l, 'L => ch _ Ascii.LF; '\\, '', '" => NULL; IN ['0..'3] => { d: CARDINAL _ ch-'0; IF (ch _ GPM.GetChar[fh]) NOT IN ['0..'7] THEN Error[26]; d _ d*8 + ch-'0; IF (ch _ GPM.GetChar[fh]) NOT IN ['0..'7] THEN Error[26]; d _ d*8 + ch-'0; ch _ LOOPHOLE[d] }; ENDCASE => Error[26]; ENDCASE; ident[i] _ ch; i _ i + 1; ENDLOOP; ident.length _ i; GetChar; symbol _ String; END; GetPunctuation: PROC = BEGIN SELECT ch FROM '; => symbol _ Semicolon; ', => symbol _ Comma; '> => symbol _ Greater; '. => symbol _ Dot; '| => symbol _ VertBar; '= => BEGIN GetChar; IF ch = '> THEN symbol _ RightArrow ELSE symbol _ Illegal; END; '{ => symbol _ LeftCurly; '} => symbol _ RightCurly; ENDCASE => symbol _ Illegal; GetChar; END; WHILE ch = Ascii.SP OR ch = Ascii.TAB OR ch = Ascii.CR DO GetChar; ENDLOOP; symPos _ GPM.GetIndex[fh]-1; SELECT ch FROM IN ['0..'9] => GetNumber; IN ['a..'z], IN ['A..'Z] => GetWord; = '" => GetString; ENDCASE => GetPunctuation; END; InitBuilder[]; FOR s: Symbol IN Symbol DO ReservedWord[s] _ TRUE; ENDLOOP; ReservedWord[String] _ FALSE; ReservedWord[Semicolon] _ FALSE; ReservedWord[Comma] _ FALSE; ReservedWord[Greater] _ FALSE; ReservedWord[Dot] _ FALSE; ReservedWord[RightArrow] _ FALSE; ReservedWord[Illegal] _ FALSE; ReservedWord[LeftCurly] _ FALSE; ReservedWord[RightCurly] _ FALSE; ReservedWord[VertBar] _ FALSE; ReservedWord[Number] _ FALSE; ReservedWord[KeyIdent] _ FALSE; END. ’TIPTableBuilder.mesa; Last Edited by McGregor, September 10, 1982 10:28 am Last Edited by Paxton, July 30, 1982 9:08 am Last Edited by: Maxwell, January 3, 1983 11:59 am global scanner variables: charTerm: char TIPTerm _ [char[qZ.NEW[CHARACTER]]]; - for the general case - *** the scanner: *** Satterthwaite suggested all this crap about the GOTO. strip off the // maintain the list symbols used to label the branches of the current statement TriggerStmt ::= SELECT TRIGGER FROM TriggerChoiceSeries skip until choice-begin EnableStmt ::= SELECT ENABLE FROM EnableChoiceSeries skip until (enable)choice-begin TriggerChoiceSeries ::= TriggerChoice ; TriggerChoiceSeries | TriggerChoice ENDCASE FinalChoice | ENDCASE FinalChoice skip until choice-begin or else EnableChoiceSeries ::= EnableChoice ; EnableChoiceSeries | EnableChoice ENDCASE FinalChoice | ENDCASE FinalChoice skip until choice-begin or else TriggerChoice ::= TriggerTerm Expression EnableChoice ::= EnableTerm Expression TriggerTerm ::= Key TimeOut | MOUSE TimeOut skip EnableTerm ::= Keys | PredicateIdent Keys ::= Key | Key "|" Keys KeyIdent UP | KeyIdent DOWN TimeOut ::= empty | BEFORE Number | AFTER Number skip Expression ::= AND TriggerChoice | WHILE EnableChoice | => Statement Results ::= ResultItem | ResultItem , Results | { ResultItem* } find all leaves l:[result TIPTermRec] of the tree, append the list found there to a copy of resultList, and store the resulting list as l.list ResultItems ::= ResultItem } | ResultItem ResultItems ResultItem ::= COORDS | CHAR | TIME | String | Number | ResultIdent FinalChoice ::= empty | => Statement Statement ::= TriggerStmt | EnableStmt | Results note that all parameters share the same variable for notification users must copy parameter if they want to save value after returning from notify $Opaque => TranslateAtom[dummy, Opaque]; $FR5 => TranslateAtom[FR5, KeyIdent]; find next symbol: classify symbol: main code: Κ$θ– "Mesa" style˜JšΟcJ™JJš,™,J™1J˜šΟk ˜ J˜Jšœžœ ˜Jšžœžœ?˜IJšœ žœ˜Jšœžœ˜Jšœžœ ˜Jšœžœ˜*Jšžœžœ@˜HJšžœžœ1˜:Jšœ žœ ˜Jšœžœ˜"Jšœžœžœ˜5Jšœ žœ ˜Jšœžœ(˜4J˜ J˜J˜ J˜—Jšœž ˜˜Jšžœ žœ žœ+ž˜UJšžœ˜J˜—šžœ˜Jšžœ ˜$J˜š œžœžœžœžœžœ˜2Jš žœžœžœžœžœ˜$—Jšœžœ˜Jšœžœ˜Jšœ žœ˜J˜Jšœ žœ˜Jšœžœ˜J˜J˜š œ žœžœžœžœžœ˜;Jšžœžœžœžœ˜(J˜—š œ žœžœžœžœžœ˜Jšžœ˜—šžœ žœžœ˜šžœžœ˜J˜,Jšœžœ˜—Jšžœ˜ —J˜)J˜%J˜%Jšžœ˜J˜(J˜0Jšžœ˜Jšžœžœžœ˜$J˜J˜—šŸœžœžœ žœ˜.Jšžœžœ˜4Jšž˜˜Jš5™5J˜—šžœžœžœžœ˜)Jšžœ žœ˜7J˜—š Ÿœžœ žœžœžœ žœž˜KJšœžœžœ˜šœžœ žœ˜Jšœžœ žœžœžœžœžœžœ˜N—šžœžœžœ ˜2Jšœžœ˜Jš™J˜J˜8J˜'Jšœžœžœ˜AJšžœ˜—Jšžœ˜J˜Jšœ žœ˜J˜Jšžœ?˜EJ˜šžœž˜ Jšžœžœ˜4Jšœ žœ ˜Jšžœ˜J˜——J˜Jšœžœ ˜J˜J˜J˜J˜Jšœžœ"žœ˜Dšžœ˜J˜J˜Jšœ ˜!J˜J˜J˜J˜—Jšœžœ˜J˜ Jšœ žœ˜Jšœ žœ˜Jšœžœ˜J˜J˜J˜J˜Jšžœžœ ˜#J˜J˜šžœžœž˜J˜ šžœžœž˜J˜ J˜Jšž˜—Jšžœ ˜Jšžœžœ ˜Jšž˜—Jšžœ ˜J˜Jšžœ ˜Jšžœžœ ˜7Jšžœžœ(˜LJ˜Jšž˜J˜˜Jšžœžœ˜%Jšœžœ˜J˜šžœ3˜5Jšžœ˜J˜J˜——Jšžœ˜J˜Jšžœ˜J˜—šŸœžœ˜Jš œžœžœ žœžœžœ˜OJšžœ žœ˜J˜—šŸ œžœžœžœ˜J˜J˜Jšžœ?˜EJ˜—šŸ œžœžœž ˜Sšžœ žœž˜Jšœ žœ˜!Jšžœžœžœ ˜Jšžœ;˜>šžœžœž˜J˜'šžœžœž˜˜ šžœžœž˜!Jšœ žœ˜Jšžœžœžœ˜:J˜"Jšž˜—šžœž˜ Jšœžœ˜Jšžœžœžœ˜