<> <> <> DIRECTORY Ascii USING [CR, LF, SP, TAB], BasicTime USING [GMT], Commander USING [CommandProc, Handle, Register], CommandTool USING [DoCommand], FS USING [Delete, EnumerateForNames, Error, GetInfo, GetName, OpenFile, OpenFileFromStream, StreamOpen], IO USING [Close, EndOf, EndOfStream, GetBlock, GetIndex, GetTokenRope, PutBlock, PutChar, PutRope, RIS, SetIndex, STREAM], Rope USING [Concat, Equal, Fetch, Find, FromProc, Length, ROPE, Substr]; ExpungeOpensImpl: CEDAR PROGRAM IMPORTS IO, FS, Rope, Commander, CommandTool ~ BEGIN ROPE: TYPE ~ Rope.ROPE; Scanner: TYPE ~ REF ScannerRep; ScannerRep: TYPE ~ RECORD [ stream: IO.STREAM, tokenKind: Kind, inputBuffer: REF TEXT, locationOfBufferStart: INT, tokenStart: NAT, tokenLength: NAT ]; inputBufferSize: NAT _ 16*1024; CreateScanner: PROC [stream: IO.STREAM] RETURNS [scanner: Scanner] ~ { scanner _ NEW[ScannerRep _ [ stream: stream, tokenKind: whitespace, inputBuffer: NEW[TEXT[inputBufferSize]], locationOfBufferStart: IO.GetIndex[stream], tokenStart: 0, tokenLength: 0 ]]; }; Kind: TYPE ~ {identifier, special, charconst, string, whitespace, newline, comment, eof}; KindOf: PROC [c: CHAR] RETURNS [Kind] ~ { SELECT c FROM IN ['a..'z], IN ['A..'Z], IN ['0..'9], '$ => RETURN [identifier]; Ascii.SP, Ascii.TAB, Ascii.LF => RETURN [whitespace]; Ascii.CR => RETURN [newline]; ENDCASE => RETURN [special]; }; breakLoc: INT _ LAST[INT]; breakCount: INT _ 0; GetCharConstant: PROC [scanner: Scanner] ~ { IF scanner.tokenStart>=scanner.inputBuffer.length-10 THEN RefillBuffer[scanner]; scanner.tokenKind _ charconst; scanner.tokenLength _ 2; IF scanner.inputBuffer[scanner.tokenStart+1] = '\\ THEN { IF scanner.inputBuffer[scanner.tokenStart+scanner.tokenLength] IN ['0..'7] THEN { WHILE scanner.inputBuffer[scanner.tokenStart+scanner.tokenLength] IN ['0..'7] DO scanner.tokenLength _ scanner.tokenLength + 1; ENDLOOP; } ELSE scanner.tokenLength _ 3; }; }; GetStringConstant: PROC [scanner: Scanner] ~ { GetC: PROC ~ { IF scanner.tokenStart+scanner.tokenLength>=scanner.inputBuffer.length-10 THEN RefillBuffer[scanner]; scanner.tokenLength _ scanner.tokenLength + 1; IF scanner.inputBuffer[scanner.tokenStart+scanner.tokenLength] = '\\ THEN { scanner.tokenLength _ scanner.tokenLength + 1; IF scanner.inputBuffer[scanner.tokenStart+scanner.tokenLength] IN ['0..'7] THEN { WHILE scanner.inputBuffer[scanner.tokenStart+scanner.tokenLength] IN ['0..'7] DO scanner.tokenLength _ scanner.tokenLength + 1; ENDLOOP; } ELSE scanner.tokenLength _ scanner.tokenLength + 1; }; }; scanner.tokenLength _ 0; GetC[]; UNTIL scanner.inputBuffer[scanner.tokenStart+scanner.tokenLength] = '" DO GetC[]; ENDLOOP; scanner.tokenLength _ scanner.tokenLength + 1; }; GetComment: PROC [scanner: Scanner] ~ { c: CHAR _ ' ; -- next char after the current end-of-token cc: CHAR _ ' ; -- char after c PeekCC: PROC ~ { IF scanner.tokenStart+scanner.tokenLength+2>=scanner.inputBuffer.length THEN RefillBuffer[scanner]; c _ cc _ '\n; IF scanner.tokenStart+scanner.tokenLength { SELECT TRUE FROM Match[scanner, "DIRECTORY"], Match[scanner, "PROGRAM"], Match[scanner, "MONITOR"] => specialNest _ TRUE; Match[scanner, "BEGIN"] => {IF useCurlys THEN {EmitCurlyBegin[]; LOOP} ELSE Nest[]}; Match[scanner, "DO"], Match[scanner, "FROM"] => Nest[]; Match[scanner, "END"] => {IF useCurlys THEN {EmitCurlyEnd[]; LOOP} ELSE UnNest[]}; Match[scanner, "ENDLOOP"], Match[scanner, "ENDCASE"] => UnNest[]; Match[scanner, "OPEN"] => {ParseOpen[]; LOOP}; ENDCASE => { IF afterDot THEN NULL ELSE TryToInsertQualifier[]; }; afterDot _ FALSE; CopyToken[]; }; special => { char: CHAR _ scanner.inputBuffer[scanner.tokenStart]; IF char = '_ OR char = '\251 THEN specialNest _ TRUE; IF char = '; OR char = '~ OR char = '= OR char = '} THEN specialNest _ FALSE; IF char = '{ OR char = '( OR char = '[ THEN Nest[] ELSE IF char = '} THEN {EmitCurlyEnd[]; LOOP} ELSE IF char = ') OR char = '] THEN UnNest[]; afterDot _ (char = '.); CopyToken[]; }; charconst, string => {afterDot _ FALSE; CopyToken[]}; whitespace => {IF adjustIndentation AND NOT somethingSinceNewLine THEN NULL ELSE CopyToken[]}; comment => CopyToken[]; newline => {lineNumber _ lineNumber + 1; EmitNewLine[]}; eof => EXIT; ENDCASE => ERROR; ENDLOOP; END; stream.Close; output.Close; }; GetCmdToken: PROC [stream: IO.STREAM] RETURNS [rope: ROPE _ NIL] ~ { rope _ IO.GetTokenRope[stream ! IO.EndOfStream => CONTINUE].token; }; ExpungeOpensCommand: Commander.CommandProc ~ { c: IO.STREAM _ IO.RIS[cmd.commandLine]; FOR stem: ROPE _ GetCmdToken[c], GetCmdToken[c] UNTIL stem.Length = 0 DO pattern: ROPE _ Rope.Concat[stem, ".mesa"]; ForEachFile: PROC [fullFName: ROPE] RETURNS [continue: BOOLEAN _ TRUE] ~ { base: ROPE _ fullFName.Substr[0, fullFName.Find[".mesa"]]; result _ CommandTool.DoCommand[Rope.Concat["SetKeep 6 ", fullFName], cmd]; IF result = $Failure THEN RETURN [FALSE]; result _ CommandTool.DoCommand[Rope.Concat["WriteMesaPlain ", fullFName], cmd]; IF result = $Failure THEN RETURN [FALSE]; result _ CommandTool.DoCommand[Rope.Concat["UsingList ", base], cmd]; IF result = $Failure THEN RETURN [FALSE]; ExpungeOpensIn[fullFName, base, cmd]; result _ CommandTool.DoCommand[Rope.Concat["TiogaMesa ", fullFName], cmd]; IF result = $Failure THEN RETURN [FALSE]; }; IF Rope.Find[pattern, "*"] >= 0 THEN FS.EnumerateForNames[pattern, ForEachFile ! FS.Error => {cmd.out.PutRope[error.explanation]; cmd.out.PutChar['\n]; result _ $Failure; CONTINUE}] ELSE [] _ ForEachFile[pattern ! FS.Error => {cmd.out.PutRope[error.explanation]; cmd.out.PutChar['\n]; result _ $Failure; CONTINUE}]; IF result = $Failure THEN RETURN; ENDLOOP; }; Commander.Register["ExpungeOpens", ExpungeOpensCommand, "Attempt to remove OPENs from a Cedar program"]; END.