<<>> <> <> <> <> <> <> <> <> DIRECTORY Commander USING [CommandProc, Register], IO USING [char, Error, GetChar, GetInt, int, PeekChar, PutF1, PutFR1, PutRope, Reset, SkipWhitespace, STREAM], Process USING [Detach], Rope USING [ROPE], ViewerIO USING [CreateViewerStreams]; Calculate: CEDAR MONITOR --(note 1.2) IMPORTS Commander, IO, Process, ViewerIO = BEGIN ROPE: TYPE = Rope.ROPE; windowCount: INT ¬ 0; -- a count of the number of calculators created. MakeCalculator: ENTRY Commander.CommandProc = { --(note 1.10) <<[cmd: Commander.Handle] RETURNS [result: REF ANY _ NIL, msg: ROPE _ NIL]>> <<>> <> title: ROPE; windowCount ¬ windowCount + 1; title ¬ IO.PutFR1["Adding Machine #%g", IO.int[windowCount]]; --(note 1.11) TRUSTED {Process.Detach[FORK Calculate[title]];} --(note 1.12) }; Calculate: PROC[title: ROPE] = { <> in, out: IO.STREAM; [in: in, out: out] ¬ ViewerIO.CreateViewerStreams[title]; --(note 1.13) DO -- Read an expression, terminated by a CR: ENABLE IO.Error => --(note 1.14) IF ec=SyntaxError THEN { IO.Reset[in]; IO.PutRope[out, "\nIncorrect input. Please retype the expression.\n\n"]; LOOP; } ELSE EXIT; answer: INT ¬ 0; -- initialize sum to zero. opChar: CHAR ¬ '+; -- first integer should be added. IO.PutRope[out, "Type one or more integers separated by + and - and terminate with CR to compute value:\n"]; DO -- Read an operator and an integer, skipping leading blanks, eg., NUL, CR, SP, etc. number: INT ¬ IO.GetInt[in]; SELECT opChar FROM '+ => answer ¬ answer + number; '- => answer ¬ answer - number; ENDCASE => { IO.PutF1[out, "Illegal operator (%g). Please retype the expression.\n\n", IO.char[opChar]]; EXIT; }; IF IO.PeekChar[in]='\n THEN GO TO NextLine; -- the normal way out. []¬ IO.SkipWhitespace[in]; opChar ¬ IO.GetChar[in]; REPEAT NextLine => { [] ¬ IO.GetChar[in]; -- toss CR (note 1.15) IO.PutF1[out, "\nThe answer is: %g.\n\n", IO.int[answer]]; }; ENDLOOP; ENDLOOP; }; <<>> <> Commander.Register[key: "Calculate", proc: MakeCalculator, doc: "A simple adding machine"]; END.