DIRECTORY Ascii USING [BS, CR, FF, LF, SP, TAB], Atom USING [MakeAtom], BasicTime USING [GMT, nullGMT, Update], DefaultRemoteNames USING [Get], FS USING [ComponentPositions, Error, ExpandName, FileInfo, nullOpenFile, Open, OpenFile, OpenFileFromStream, SetByteCountAndCreatedTime, StreamFromOpenFile, StreamOpen], GPM USING [Close, Error, GetChar, GetIndex, Handle, Open], Interminal USING [KeyName], Intime USING [EventTime], IO USING [STREAM, Close, Error, GetIndex, int, Put, PutRope, SetLength], Rope USING [Cat, Concat, FromRefText, ROPE, Substr], TIPPrivate USING [BadTable, EqualTables, InitBuilder, KeyOption, nrOfErrors, ReadTIPTable, Symbol, WriteTIPTable], TIPTables USING [TimeoutFlavor, TIPChoice, TIPChoiceSeries, TIPKeyState, TIPScreenCoords, TIPScreenCoordsRec, TIPTable, TIPTableRec, TIPTerm, TIPTime], TIPUser USING []; TIPTableBuilder: CEDAR MONITOR IMPORTS Atom, BasicTime, DefaultRemoteNames, FS, GPM, IO, Rope, TIPPrivate EXPORTS TIPPrivate, TIPUser = { OPEN TIPPrivate, TIPTables; ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; LORA: TYPE = LIST OF REF ANY; ReservedWord: REF PACKED ARRAY Symbol OF BOOL _ NEW[PACKED ARRAY Symbol OF BOOL]; fh: GPM.Handle; filename: ROPE; errlogfh: STREAM; fastOption: BOOL; fastMouseOption: BOOL; keyOption : KeyOption; errorText: PUBLIC REF ARRAY [0..nrOfErrors] OF ROPE _ NEW[ARRAY [0..nrOfErrors] OF ROPE]; keyNames: PUBLIC REF ARRAY Interminal.KeyName OF ROPE _ NEW[ARRAY Interminal.KeyName OF ROPE]; ch: CHAR; nextch: CHAR; havenext: BOOL; symbol: Symbol; atom: ATOM; keyName: Interminal.KeyName; symPos: INT; number: CARDINAL; ident: REF TEXT _ NEW[TEXT[100]]; errcnt: CARDINAL; printKeyTable: TIPTable _ NIL; defaultKeyTable: TIPTable _ NIL; DefaultTable: PROC [printKeys: BOOL] RETURNS [TIPTable] = TRUSTED { SELECT TRUE FROM printKeys AND printKeyTable # NIL => RETURN [printKeyTable]; NOT printKeys AND defaultKeyTable # NIL => RETURN [defaultKeyTable]; ENDCASE => { key: Interminal.KeyName; enableTerm: keyEnable TIPTerm _ [keyEnable[[Ctrl, up]]]; charTerm: char TIPTerm _ [char[stdChar]]; resultTerm: result TIPTerm _ [result[LIST[charTerm.ch]]]; normalDefault: TIPChoice _ ConsTerm[charTerm, ConsTerm[resultTerm]]; ctrlUpDefault: TIPChoice _ ConsTerm[enableTerm, normalDefault]; default: TIPChoice _ IF printKeys THEN ctrlUpDefault ELSE normalDefault; tab: REF fast TIPTableRec _ NEW[fast TIPTableRec]; tab.ignore.down _ FALSE; FOR key IN Interminal.KeyName DO -- includes CR and Space! SELECT key FROM A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, Zero, One, Two, Three, Four, Five, Six, Seven, Eight, Nine, Dash, Slash, BackSlash, Comma, Quote, RightBracket, Period, SemiColon, Return, Arrow, Space, LeftBracket, Equal, DEL, LF, BS, ESC, TAB => tab.keyDown[key] _ default; ENDCASE; ENDLOOP; IF printKeys THEN { printKeyTable _ tab; tab.keyDown[TAB] _ ctrlUpDefault; } ELSE defaultKeyTable _ tab; RETURN [tab] }; }; -- DefaultTable GetChar: PROC = { 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 { 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; }; }; NCONC: PROC [list1, list2: TIPChoice] RETURNS[TIPChoice] = { l: TIPChoice _ list1; IF l = NIL THEN RETURN[list2]; UNTIL l.rest = NIL DO l _ l.rest; ENDLOOP; l.rest _ list2; RETURN[list1]; }; ForceDirectory: PROC [name: ROPE, dir: ROPE] RETURNS [ROPE] = { cp: FS.ComponentPositions _ FS.ExpandName[name].cp; short: ROPE _ Rope.Substr[name, cp.base.start, cp.base.length + 1 + cp.ext.length]; RETURN [FS.ExpandName[short, dir].fullFName]; }; TrySeveralDirectories: PROC [name: ROPE] RETURNS [fullName: ROPE, date: BasicTime.GMT] = { date _ BasicTime.nullGMT; fullName _ name; [created: date, fullFName: fullName] _ FS.FileInfo[name: name, remoteCheck: FALSE ! FS.Error => CONTINUE]; IF date # BasicTime.nullGMT THEN RETURN; name _ ForceDirectory[name, "///"]; [created: date, fullFName: fullName] _ FS.FileInfo[name: name, remoteCheck: FALSE ! FS.Error => CONTINUE]; IF date # BasicTime.nullGMT THEN RETURN; name _ ForceDirectory[name, Rope.Concat[DefaultRemoteNames.Get[].current, "Tip>"]]; [created: date, fullFName: fullName] _ FS.FileInfo[name: name, remoteCheck: FALSE ! FS.Error => CONTINUE]; }; InstantiateNewTIPTable: PUBLIC PROC [file: ROPE _ NIL] RETURNS [table: TIPTable _ NIL] = { comp: ROPE; -- name of the compiled file tryC: BOOL _ TRUE; stream: STREAM; fileCD, compCD: BasicTime.GMT _ BasicTime.nullGMT; option, newKeyOption: KeyOption; newTable: TIPTable; cp: FS.ComponentPositions; file _ FS.ExpandName[file].fullFName; [cp: cp] _ FS.ExpandName[file]; comp _ Rope.Cat["///TipC/", Rope.Substr[file, cp.base.start, cp.base.length], ".tipC"]; { fullComp: ROPE _ comp; [file, fileCD] _ TrySeveralDirectories[file]; IF fileCD = BasicTime.nullGMT THEN GO TO noComp; fileCD _ BasicTime.Update[fileCD, 1]; [created: compCD, fullFName: fullComp] _ FS.FileInfo[name: comp, wantedCreatedTime: fileCD, remoteCheck: FALSE ! FS.Error => GO TO noComp]; stream _ FS.StreamOpen[fullComp, $read ! FS.Error => GO TO noComp]; [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 }; EXITS noComp => {}}; [table, option] _ BuildNewTIPTable[file]; stream _ FS.StreamOpen[comp, $create]; FS.SetByteCountAndCreatedTime[file: FS.OpenFileFromStream[stream], created: fileCD]; WriteTIPTable[table, option, stream]; IO.Close[stream]; stream _ FS.StreamOpen[comp, $read]; [newTable, newKeyOption] _ ReadTIPTable[stream]; IO.Close[stream]; IF newKeyOption # option THEN ERROR; EqualTables[table, newTable]; }; BuildNewTIPTable: ENTRY PROC [file: ROPE] RETURNS [table: TIPTable _ NIL, option: KeyOption] = { ENABLE UNWIND => IF errcnt#0 THEN { GPM.Close[fh]; TruncateErrorLog[]; IO.Close[errlogfh]}; GetFile: PROC [file: ROPE] RETURNS [fh: STREAM _ NIL] = CHECKED { openFile: FS.OpenFile _ FS.nullOpenFile; file _ FS.ExpandName[file].fullFName; openFile _ FS.Open[name: file, remoteCheck: FALSE]; fh _ FS.StreamFromOpenFile[openFile]; }; errMsg: ROPE; { -- fake begin to get around bug where double catch phrase fails ENABLE { GPM.Error => {errMsg _ errorMsg; GOTO MacroCleanup}; TIPError => GOTO Cleanup; }; statement: TIPChoiceSeries; filename _ file; fh _ GPM.Open[GetFile[file]]; fh.startCall _ '[; fh.endCall _ ']; fh.singleQuote _ '; -- 004 octal fh.startQuote _ '(; fh.endQuote _ '); fh.sepArg _ ',; fh.numArg _ '~; errcnt _ 0; havenext _ FALSE; fastOption _ FALSE; fastMouseOption _ FALSE; keyOption _ none; GetChar; GetSymbol; IF symbol = OptionSym THEN Options; option _ keyOption; IF symbol = Select THEN { GetSymbol; IF symbol = Trigger THEN { GetSymbol; statement _ TriggerStmt[]; } ELSE Error[5]; IF symbol # Dot THEN Error[3]; } ELSE Error[1]; GPM.Close[fh]; IF errcnt=0 THEN table _ CreateTable[statement] ELSE ErrorFinish; -- finish the error log and raise signal EXITS Cleanup => { ErrorFinish }; MacroCleanup => { IF errcnt=0 THEN OpenErrorLog; errcnt _ errcnt+1; IO.PutRope[errlogfh, "Error from macro package\n\n"]; IO.PutRope[errlogfh, errMsg]; ErrorFinish; }; }; -- fake block (see above) }; -- InstantiateNewTIPTable TruncateErrorLog: PROC = { ENABLE IO.Error => GOTO Exit; IO.SetLength[errlogfh, IO.GetIndex[errlogfh]]; EXITS Exit => {}; }; ErrorFinish: PROC = { TruncateErrorLog[]; IO.Close[errlogfh]; SIGNAL InvalidTable[Rope.Concat[filename," errors on TIP.ERRORS"]]; }; ConsTerm: PROC [term: TIPTerm, list: TIPChoice _ NIL] RETURNS [TIPChoice] = { RETURN [CONS[term, list]]; }; ConsAny: PROC [x: REF, list: LORA _ NIL] RETURNS [LORA] = { RETURN [CONS[x, list]]; }; CreateTable: PROC[series: TIPChoiceSeries] RETURNS[table: TIPTable] = TRUSTED { IF fastOption THEN { table _ 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 { ignore.up _ FALSE; IF keyUp[keyState.key] # NIL THEN DoubleDef[keyState.key]; keyUp[keyState.key] _ choice.rest; } ELSE { ignore.down _ FALSE; IF keyDown[keyState.key] # NIL THEN DoubleDef[keyState.key]; keyDown[keyState.key] _ choice.rest; }; mouseTrigger => { ignore.move _ FALSE; IF mouse # NIL THEN Error[25]; mouse _ choice.rest }; timeTrigger => Error[]; -- to be detected earlier !!! ENDCASE; ENDLOOP; ENDCASE; } ELSE { table _ NEW[small TIPTableRec]; WITH table SELECT FROM small => { 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; }; ENDCASE; }; IF keyOption # none THEN { table.link _ DefaultTable[keyOption=printKeys]; table.opaque _ FALSE; }; IF fastMouseOption THEN table.mouseTicks _ 0; }; -- CreateTable Options: PROC = { 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; }; -- Options TriggerStmt: PROC RETURNS[choiceSeries: TIPChoiceSeries] = { usedSymbols: LIST OF ATOM _ NIL; IF symbol = From THEN GetSymbol ELSE { Error[6]; }; choiceSeries _ TriggerChoiceSeries[]; }; -- TriggerStmt EnableStmt: PROC RETURNS[choiceSeries: TIPChoiceSeries] = { usedSymbols: LIST OF ATOM _ NIL; IF symbol = From THEN GetSymbol ELSE { Error[20]; }; choiceSeries _ EnableChoiceSeries[]; }; -- EnableStmt TriggerChoiceSeries: PROC RETURNS [choiceSeries: TIPChoiceSeries _ NIL] = { tail: TIPChoiceSeries _ NIL; IF symbol = Endcase THEN RETURN[FinalChoice[]]; DO choice: TIPChoice = TriggerChoice[]; temp: TIPChoiceSeries = LIST[choice]; IF choiceSeries = NIL THEN choiceSeries _ temp ELSE tail.rest _ temp; tail _ temp; IF symbol = Semicolon THEN { GetSymbol; IF symbol # Endcase THEN LOOP; }; IF symbol = Endcase THEN { tail.rest _ FinalChoice[]; RETURN; }; Error[2]; ENDLOOP; }; -- TriggerChoiceSeries EnableChoiceSeries: PROC RETURNS[choiceSeries: TIPChoiceSeries _ NIL] = { tail: TIPChoiceSeries _ NIL; IF symbol = Endcase THEN RETURN[FinalChoice[]]; DO choice: TIPChoice = EnableChoice[]; temp: TIPChoiceSeries _ LIST[choice]; IF choiceSeries = NIL THEN choiceSeries _ temp ELSE tail.rest _ temp; tail _ temp; IF symbol = Semicolon THEN { GetSymbol; IF symbol # Endcase THEN LOOP; }; IF symbol = Endcase THEN { tail.rest _ FinalChoice[]; RETURN; }; Error[2]; ENDLOOP; }; -- EnableChoiceSeries TriggerChoice: PROC RETURNS[triggerChoice: TIPChoice] = { term: TIPChoice _ TriggerTerm[]; triggerChoice _ NCONC[term, Expression[]]; }; -- TriggerChoice EnableChoice: PROC RETURNS[enableChoice: TIPChoice] = { term: TIPChoice _ EnableTerm[]; enableChoice _ NCONC[term, Expression[]]; }; -- EnableChoice TriggerTerm: PROC RETURNS[triggerTerm: TIPChoice] = { SELECT symbol FROM KeyIdent => { keyTerm: keyTrigger TIPTerm; keyTerm.keyState _ Key[]; triggerTerm _ LIST[keyTerm]; }; Mouse => { mouseTerm: mouseTrigger TIPTerm; triggerTerm _ LIST[mouseTerm]; GetSymbol; }; ENDCASE => { Error[8]; }; IF symbol = Before OR symbol = After THEN triggerTerm _ ConsTerm[TimeOut[], triggerTerm]; }; -- TriggerTerm EnableTerm: PROC RETURNS[enableTerm: TIPChoice] = { IF symbol = KeyIdent THEN enableTerm _ Keys[] ELSE IF symbol = Ident THEN { predTerm: predEnable TIPTerm; predTerm.predicate _ atom; enableTerm _ LIST[predTerm]; GetSymbol; } ELSE { Error[21] }; }; -- EnableTerm Keys: PROC RETURNS[enableTerm: TIPChoice] = TRUSTED { first: TIPKeyState _ Key[]; SELECT symbol FROM VertBar => { rest: TIPChoice; GetSymbol; IF symbol # KeyIdent THEN Error[21]; rest _ Keys[]; WITH x:rest.first SELECT FROM keyEnable => { keyTerm: key2Enable TIPTerm; keyTerm.keyState1 _ first; keyTerm.keyState2 _ x.keyState; enableTerm _ LIST[keyTerm]; }; key2Enable => { keyTerm: keyEnableList TIPTerm; keyTerm.lst _ LIST[first, x.keyState1, x.keyState2]; enableTerm _ ConsTerm[keyTerm]; }; keyEnableList => { keyTerm: keyEnableList TIPTerm; keyTerm.lst _ CONS[first, x.lst]; enableTerm _ ConsTerm[keyTerm]; }; ENDCASE => ERROR; }; ENDCASE => { keyTerm: keyEnable TIPTerm; keyTerm.keyState _ first; enableTerm _ ConsTerm[keyTerm]; }; }; -- Keys Key: PROC RETURNS[keySt: TIPKeyState] = { name: Interminal.KeyName _ keyName; GetSymbol; IF symbol = Up OR symbol = Down THEN { keySt _ [key: name, state: IF symbol = Up THEN up ELSE down]; GetSymbol; } ELSE Error[12]; }; -- Key TimeOut: PROC RETURNS[timeoutExpr: timeTrigger TIPTerm] = { fl: TimeoutFlavor _ IF symbol = Before THEN lt ELSE gt; GetSymbol; IF symbol = Number THEN { timeoutExpr.flavor _ fl; timeoutExpr.mSecs _ number; GetSymbol; } ELSE { Error[10]; }; }; -- TimeOut Expression: PROC RETURNS [expression: TIPChoice] = { SELECT symbol FROM And => { GetSymbol; expression _ TriggerChoice[]; }; While => { GetSymbol; expression _ EnableChoice[]; }; RightArrow => { GetSymbol; expression _ Statement[]; }; ENDCASE => Error[22]; }; -- Expression Results: PROC RETURNS [resultList: LORA, resultChoice: TIPChoice] = { resultItem: REF; resultExpr: REF TIPTerm; IF symbol = LeftCurly THEN { GetSymbol; [resultList, resultChoice] _ ResultItems[]; RETURN; }; [resultItem, resultExpr] _ ResultItem[]; SELECT symbol FROM Comma => { resultItemList: LORA; resultExprList: TIPChoice; GetSymbol; [resultItemList, resultExprList] _ Results[]; resultList _ ConsAny[resultItem, resultItemList]; resultChoice _ IF resultExpr = NIL THEN resultExprList ELSE ConsTerm[resultExpr^, resultExprList]; }; ENDCASE => { userResultList: result TIPTerm; resultList _ ConsAny[resultItem]; resultChoice _ ConsTerm[userResultList]; IF resultExpr # NIL THEN resultChoice _ ConsTerm[resultExpr^, resultChoice]; }; }; -- Results Store: PROC [resultList: LORA, tree: TIPChoice] = { 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 => { IF term.list = NIL THEN term.list _ resultList ELSE { Error[24]; term.list _ resultList; -- !!! }; }; ENDCASE}; ENDLOOP; }; -- Store ResultItems: PROC RETURNS[resultList: LORA, resultChoice: TIPChoice] = { resultItem: REF; resultExpr: REF TIPTerm; [resultItem, resultExpr] _ ResultItem[]; SELECT symbol FROM RightCurly => { userResultList: result TIPTerm; GetSymbol; resultList _ LIST[resultItem]; resultChoice _ IF resultExpr = NIL THEN ConsTerm[userResultList] ELSE ConsTerm[resultExpr^, ConsTerm[userResultList]]; }; ENDCASE => { resultItemList: LORA; resultExprList: TIPChoice; [resultItemList, resultExprList] _ ResultItems[]; resultList _ ConsAny[resultItem, resultItemList]; resultChoice _ IF resultExpr = NIL THEN resultExprList ELSE ConsTerm[resultExpr^, resultExprList]; }; }; ResultItem: PROC RETURNS[resultItem: REF, resultExpr: REF TIPTerm _ NIL] = { SELECT symbol FROM Char => { resultExpr _ NEW[char TIPTerm _ [char[resultItem _ stdChar]]]; GetSymbol; }; Coords => { resultExpr _ NEW[coords TIPTerm _ [coords[resultItem _ stdCoords]]]; GetSymbol; }; Time => { resultExpr _ NEW[time TIPTerm _ [time[resultItem _ stdTime]]]; GetSymbol; }; KeyIdent, -- result names might be key names Ident => { resultItem _ atom; GetSymbol; }; Number => { resultItem _ NEW[INT]; WITH resultItem SELECT FROM z: REF INT => z^ _ number; ENDCASE; GetSymbol; }; String => { resultItem _ NEW[TEXT[ident.length]]; WITH resultItem SELECT FROM z: REF TEXT => { FOR i: CARDINAL IN [0..ident.length) DO z[i] _ ident[i]; ENDLOOP; z.length _ ident.length; }; ENDCASE; GetSymbol; }; ENDCASE => IF ReservedWord[symbol] THEN { resultItem _ atom; GetSymbol; } ELSE Error[9]; }; -- ResultItem FinalChoice: PROC RETURNS [finalChoice: TIPChoiceSeries] = { GetSymbol; -- we always get here with a pending ENDCASE IF symbol = RightArrow THEN { GetSymbol; finalChoice _ LIST[Statement[]]; }; }; -- FinalChoice Statement: PROC RETURNS[stmt: TIPChoice] = { IF symbol = Select THEN { term: nested TIPTerm; GetSymbol; IF symbol = Trigger OR symbol = Enable THEN { sy: Symbol _ symbol; GetSymbol; term.statement _ IF sy = Trigger THEN TriggerStmt[] ELSE EnableStmt[]; stmt _ LIST[term]; } ELSE { Error[13]; }; } ELSE { userResults: LORA; [userResults, stmt] _ Results[]; Store[userResults, stmt]; }; }; -- Statement stdChar: PUBLIC REF CHAR _ NEW[CHAR]; stdCoords: PUBLIC TIPScreenCoords _ NEW[TIPScreenCoordsRec]; stdTime: PUBLIC TIPTables.TIPTime _ NEW[Intime.EventTime]; InvalidTable: PUBLIC SIGNAL [errorMsg: ROPE] = CODE; OpenErrorLog: PROC = { errlogfh _ FS.StreamOpen["tip.errors", $create]; IO.PutRope[errlogfh, filename]; IO.PutRope[errlogfh, " TIP TABLE error log.\n\n"]; }; DoubleDef: PROC[key: Interminal.KeyName] = { IF errcnt=0 THEN OpenErrorLog[]; errcnt _ errcnt+1; IO.PutRope[errlogfh, keyNames[key]]; IO.PutRope[errlogfh, " entry must not occur more than once in table.\n\n"]; }; TIPError: ERROR = CODE; Error: PROC[nr: CARDINAL _ 0] = { OPEN IO; IF errcnt=0 THEN OpenErrorLog; errcnt _ errcnt+1; PutRope[errlogfh, errorText[nr]]; PutRope[errlogfh, " at "]; Put[errlogfh, int[symPos]]; PutRope[errlogfh, "\n\n"]; ERROR TIPError; }; GetSymbol: PROC = { GetNumber: PROC = { symbol _ Number; number _ 0; WHILE ch IN ['0..'9] DO number _ 10*number + ch-'0; GetChar; ENDLOOP; }; GetWord: PROC = { 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]]; symbol _ KeyIdent; keyName _ dummy; SELECT atom FROM $OPTIONS => symbol _ OptionSym; $SELECT => symbol _ Select; $TRIGGER => symbol _ Trigger; $ENABLE => symbol _ Enable; $FROM => symbol _ From; $ENDCASE => symbol _ Endcase; $END => symbol _ End; $AND => symbol _ And; $WHILE => symbol _ While; $AFTER => symbol _ After; $BEFORE => symbol _ Before; $Up => symbol _ Up; $Down => symbol _ Down; $Mouse => symbol _ Mouse; $Char => symbol _ Char; $Coords => symbol _ Coords; $TIME => symbol _ Time; $Small => symbol _ Small; $Fast => symbol _ Fast; $FastMouse => symbol _ FastMouse; $SlowMouse => symbol _ SlowMouse; $PrintKeys => symbol _ PrintKeys; $DefaultKeys => symbol _ DefaultKeys; $x0 => keyName _ x0; $x1 => keyName _ x1; $x2 => keyName _ x2; $x3 => keyName _ x3; $x4 => keyName _ x4; $x5 => keyName _ x5; $x6 => keyName _ x6; $Pen => keyName _ pen; $Keyset1 => keyName _ Keyset1; $Keyset2 => keyName _ Keyset2; $Keyset3 => keyName _ Keyset3; $Keyset4 => keyName _ Keyset4; $Keyset5 => keyName _ Keyset5; $Red => keyName _ Red; $Blue => keyName _ Blue; $Yellow => keyName _ Yellow; $Five => keyName _ Five; $Four => keyName _ Four; $Six => keyName _ Six; $E => keyName _ E; $Seven => keyName _ Seven; $D => keyName _ D; $U => keyName _ U; $V => keyName _ V; $Zero => keyName _ Zero; $K => keyName _ K; $Dash => keyName _ Dash; $P => keyName _ P; $Slash => keyName _ Slash; $BackSlash => keyName _ BackSlash; $LF => keyName _ LF; $BS => keyName _ BS; $Three => keyName _ Three; $Two => keyName _ Two; $W => keyName _ W; $Q => keyName _ Q; $S => keyName _ S; $A => keyName _ A; $Nine => keyName _ Nine; $I => keyName _ I; $X => keyName _ X; $O => keyName _ O; $L => keyName _ L; $Comma => keyName _ Comma; $Quote => keyName _ Quote; $RightBracket => keyName _ RightBracket; $Spare2 => keyName _ Spare2; $BW => keyName _ BW; $One => keyName _ One; $ESC => keyName _ ESC; $TAB => keyName _ TAB; $F => keyName _ F; $Ctrl => keyName _ Ctrl; $C => keyName _ C; $J => keyName _ J; $B => keyName _ B; $Z => keyName _ Z; $LeftShift => keyName _ LeftShift; $Period => keyName _ Period; $SemiColon => keyName _ SemiColon; $Return => keyName _ Return; $Arrow => keyName _ Arrow; $DEL => keyName _ DEL; $FL3 => keyName _ FL3; $R => keyName _ R; $T => keyName _ T; $G => keyName _ G; $Y => keyName _ Y; $H => keyName _ H; $Eight => keyName _ Eight; $N => keyName _ N; $M => keyName _ M; $Lock => keyName _ Lock; $Space => keyName _ Space; $LeftBracket => keyName _ LeftBracket; $Equal => keyName _ Equal; $RightShift => keyName _ RightShift; $Spare3 => keyName _ Spare3; $FL4 => keyName _ FL4; ENDCASE => symbol _ Ident; }; GetString: PROC = { 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; }; GetPunctuation: PROC = { SELECT ch FROM '; => symbol _ Semicolon; ', => symbol _ Comma; '> => symbol _ Greater; '. => symbol _ Dot; '| => symbol _ VertBar; '= => { GetChar; IF ch = '> THEN symbol _ RightArrow ELSE symbol _ Illegal; }; '{ => symbol _ LeftCurly; '} => symbol _ RightCurly; ENDCASE => symbol _ Illegal; GetChar[]; }; 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[]; }; 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; }. 2TIPTableBuilder.mesa Copyright c 1984 by Xerox Corporation. All rights reserved. McGregor, September 10, 1982 10:28 am Paxton, July 30, 1982 9:08 am Maxwell, January 3, 1983 11:59 am Paul Rovner, July 21, 1983 11:09 am Russ Atkinson, November 6, 1984 5:32:52 pm PST global scanner variables: charTerm: char TIPTerm _ [char[qZ.NEW[CHAR]]]; - for the general case - Also include TAB *** the scanner: *** construct the tipC name from the tip name Try to open and read the compiled (tipC) version of the tip file. The tipC file is always stored on the ///TipC/ directory to avoid multiple copies. The create date of the tipC file is one second later than the create date of the tip file so we can determine correspondence between the two. At this point there is no tipC file, so we will have to make one. We start from the tip file, and any FS.Error will propagate from here. FS.Error will percolate up 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 find next symbol: classify symbol: main code: Reserved word initialization Κ)– "Mesa" style˜šΟc™Jšœ Οmœ1™ŸœŸœŸœŸœŸœŸœŸœŸœŸœŸœŸœŸœŸœŸœŸœŸœŸœŸœŸœŸœŸœŸœŸœŸœŸœŸœ―ŸœŸœŸœŸœŸœ˜“Kšœ˜—KšŸœ˜—KšŸœ˜—J˜šŸœ ˜ šŸœ˜Jšœ™Jšœ˜Jšœ Ÿœ˜!Jšœ˜—JšŸœ˜—JšŸœ˜ J˜——JšŸœ˜J˜J˜—Jš™J˜š œŸœ˜š   œŸœŸœŸœŸœ˜.Jš œŸœŸœ ŸœŸœ Ÿœ˜S—JšŸœ ŸœŸœŸœ˜JšŸœ Ÿœ˜šŸœŸœ˜;JšŸœ˜šŸœŸ˜JšœŸœŸœ˜šœŸœŸ˜Jšœ ŸœŸœ˜JšŸœ˜—JšŸœ˜JšŸœ˜ —Jšœ Ÿœ˜JšŸœ Ÿœ˜—Jšœ˜—Jšœ˜J˜—šŸœŸœŸœ˜Ÿ˜GJšœŸœ ŸœŸœ ˜——Jš œ ŸœŸœ ŸœŸœ ˜CJšœ4Ÿœ˜>JšŸœ˜šŸœ ŸœŸœ˜šŸœŸœ˜J˜,JšœŸœ˜—JšŸœ˜ —JšŸœ˜—Jšœ‰™‰J˜)Jšœ Ÿœ˜&JšŸœ"Ÿœ.˜TJ˜%JšŸœ˜Jšœ Ÿœ˜$J˜0JšŸœ˜JšŸœŸœŸœ˜$J˜J˜J˜—š œŸœŸœŸœ˜)JšŸœŸœ˜6J˜šŸœŸœŸœ Ÿœ˜#JšŸœ Ÿœ˜7J˜—š œŸœŸœŸœŸœŸœŸœ˜AJšœ™Jšœ Ÿœ Ÿœ˜(JšœŸœ˜%Jšœ ŸœŸœ˜3JšœŸœ˜%Jšœ˜J˜—šœŸœ˜ J˜—šŸœ?˜AJ˜šŸœ˜JšŸœŸœ˜4Jšœ Ÿœ ˜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šŸœŸœ ˜Jšœ˜—JšŸœ ˜J˜JšŸœ ˜šŸœ ˜ JšŸœ˜#JšŸœ(˜:—J˜šŸ˜J˜˜JšŸœ Ÿœ˜J˜JšŸœ3˜5JšŸœ˜J˜ ˜J˜———JšŸœ˜—J˜JšŸœ˜J˜—š œŸœ˜JšŸœŸœ Ÿœ˜JšŸœŸœ˜.JšŸœ ˜Jšœ˜J˜—š  œŸœ˜J˜JšŸœ˜JšŸœ=˜CJšœ˜J˜—š œŸœ#ŸœŸœ˜MJšŸœŸœ˜J˜J˜—š œŸœŸœŸœŸœŸœŸœ˜;JšŸœŸœ ˜J˜J˜—š  œŸœŸœŸœ˜OšŸœ ˜ šŸœ˜JšœŸœ˜šŸœŸœŸ˜šœ˜šŸœ;˜>šŸœŸœŸ˜J˜'šŸœŸœŸ˜˜ šŸœŸœ˜Jšœ Ÿœ˜JšŸœŸœŸœ˜:J˜"Jšœ˜—šŸœ˜JšœŸœ˜JšŸœŸœŸœ˜J˜ —Jšœ˜—šœ ˜ šœ Ÿœ4˜DJ˜ —Jšœ˜—šœ ˜ šœ Ÿœ.˜>J˜ —Jšœ˜—Jšœ "˜-šœ ˜ J˜J˜ Jšœ˜—šœ ˜ šœ ŸœŸœ˜šŸœ ŸœŸ˜JšœŸœŸœ˜JšŸœ˜——J˜ Jšœ˜—šœ ˜ šœ ŸœŸœ˜%šŸœ ŸœŸ˜šœŸœŸœ˜šŸœŸœŸœŸ˜'J˜JšŸœ˜—J˜——šœ˜JšŸœ˜——˜ Jšœ˜——šŸœ˜ šŸœŸœ˜J˜J˜ šœ˜JšŸœ ˜————JšŸœ ˜J˜J˜—š  œŸœŸœ"˜