tock-mirror/testcases/course.occ

277 lines
7.7 KiB
Plaintext

-- Various stuff taken from the course library that's used by these testcases.
-- This has all been translated back to occam2 for now.
VAL BYTE NULL IS 0: --* ASCII NUL
VAL BYTE BELL IS 7: --* ASCII BEL - terminal bell
VAL BYTE BACK IS 8: --* ASCII BS - backspace key
VAL BYTE ESCAPE IS 27: --* ASCII ESC - escape key
VAL BYTE DELETE IS 127: --* ASCII DEL - delete key
VAL BYTE FLUSH IS 255: --* Flush output buffer
VAL BYTE END.OF.FILE IS 255: --* End of file
--{{{ PROC out.repeat (VAL BYTE ch, VAL INT n, CHAN OF BYTE out)
--* Write a character repeatedly to a channel.
-- This outputs [@code ch] down the channel [@code out] [@code n] times. If
-- [@code n] is negative, nothing happens.
-- @param ch Character
-- @param n Number of times to output (negative values result in no output)
-- @param out Channel to write to
PROC out.repeat (VAL BYTE ch, VAL INT n, CHAN OF BYTE out)
--{{{
IF
n > 0
SEQ i = 0 FOR n
out ! ch
TRUE
SKIP
--}}}
:
--}}}
--{{{ PROC out.string (VAL []BYTE s, VAL INT field, CHAN OF BYTE out)
--* Write a string to a channel.
-- This outputs [@code s] in a fieldwidth [@code field] down [@code out].
-- @param s String
-- @param field Field width to right-justify in
-- @param out Channel to write to
PROC out.string (VAL []BYTE s, VAL INT field, CHAN OF BYTE out)
--{{{
VAL INT length IS SIZE s:
SEQ
out.repeat (' ', field - length, out)
SEQ i = 0 FOR length
out ! s[i]
--}}}
:
--}}}
--{{{ PROC out.byte (VAL BYTE b, VAL INT field, CHAN OF BYTE out)
--* Write a byte in decimal to a channel.
-- This outputs [@code b] in a fieldwidth [@code field] down [@code out]. If
-- the fieldwidth is too wide for [@code b], it right-justifies [@code b] with
-- spaces on the left. If the field is not wide enough, it prints the [@code
-- b] anyway. These rules for fieldwidth are the same as those used by the
-- Pascal [@text write] procedure.
-- @param b Byte
-- @param field Field width to right-justify in
-- @param out Channel to write to
PROC out.byte (VAL BYTE b, VAL INT field, CHAN OF BYTE out)
--{{{
VAL BYTE hundreds IS b/100:
VAL BYTE rest IS b\100:
VAL BYTE tens IS rest/10:
VAL BYTE ones IS rest\10:
IF
hundreds > 0
SEQ
out.repeat (' ', field - 3, out)
out ! hundreds + '0'
out ! tens + '0'
out ! ones + '0'
tens > 0
SEQ
out.repeat (' ', field - 2, out)
out ! tens + '0'
out ! ones + '0'
TRUE
SEQ
out.repeat (' ', field - 1, out)
out ! ones + '0'
--}}}
:
--}}}
--{{{ PROC out.int (VAL INT n, VAL INT field, CHAN OF BYTE out)
--* Write an integer in decimal to a channel.
-- This outputs [@code n] in a fieldwidth [@code field] down [@code out]. The
-- rules for fieldwidth are as [@ref out.byte].
-- @param n Integer
-- @param field Field width to right-justify in
-- @param out Channel to write to
PROC out.int (VAL INT n, VAL INT field, CHAN OF BYTE out)
--{{{
IF
n = (MOSTNEG INT)
--{{{ minint
out.string ("-2147483648", field, out)
--}}}
n = 0
--{{{ zero
SEQ
IF
1 < field
out.repeat (' ', field - 1, out)
TRUE
SKIP
out ! '0'
--}}}
TRUE
--{{{ anything else
VAL INT max.digits IS 20:
[max.digits]INT D:
INT x, i:
SEQ
--{{{ check negative
IF
n < 0
x := -n
TRUE -- (n > 0)
x := n
--}}}
--{{{ decompose
SEQ
i := 0
WHILE x > 0
SEQ
D[i] := x\10
x := x/10
i := i + 1
--}}}
--{{{ pad
IF
n > 0
out.repeat (' ', field - i, out)
TRUE
SEQ
out.repeat (' ', (field - 1) - i, out)
out ! '-'
--}}}
--{{{ output
WHILE i > 0
SEQ
i := i - 1
out ! BYTE (D[i] + (INT '0'))
--}}}
--}}}
--}}}
:
--}}}
--{{{ PROC make.string ([]BYTE a, VAL INT length)
--* Converts a [@code BYTE] array into a string.
-- This is needed for strings that have been input using a counted-array
-- protocol (where we know the length, but the string characters have been
-- left-justified and the elements of the array after the string need setting
-- to [@ref NULL]).
-- @param a Array to convert
-- @param length Length of string in [@code a]
PROC make.string ([]BYTE a, VAL INT length)
--{{{
IF
(SIZE a) > length
SEQ i = length FOR (SIZE a) - length
a[i] := NULL
TRUE
SKIP
--}}}
:
--}}}
--{{{ PROC copy.string (VAL []BYTE a, []BYTE b)
--* Copy a string.
-- This copies the string from [@code a] into [@code b]. If [@code a] is
-- shorter than [@code b], the string gets padded with [@ref NULL]s. If
-- [@code b] is shorter than [@code a], the string gets truncated.
-- @param a Source string
-- @param b Destination string
PROC copy.string (VAL []BYTE a, []BYTE b)
--{{{
INT min:
SEQ
--{{{ min := minimum (SIZE a, SIZE b)
IF
(SIZE a) > (SIZE b)
min := SIZE b
TRUE
min := SIZE a
--}}}
--{{{ copy a to b
[b FROM 0 FOR min] := [a FROM 0 FOR min]
--}}}
--{{{ pad with NULLs
SEQ i = min FOR (SIZE b) - min
b[i] := NULL
--}}}
--}}}
:
--}}}
--{{{ PROC erase.screen (CHAN OF BYTE out)
--* Erase whole screen.
-- This outputs a VT220 control sequence to erase all characters from the
-- screen.
-- @param out Channel to write to
PROC erase.screen (CHAN OF BYTE out)
--{{{
SEQ
out ! ESCAPE
out ! '['
out ! '2'
out ! 'J'
--}}}
:
--}}}
--{{{ PROC cursor.x.y (VAL BYTE x, y, CHAN OF BYTE out)
--* Place the cursor.
-- This outputs a VT220 control sequence down channel [@code out] to place the
-- cursor at screen coordinates ([@code x], [@code y]).
-- @param x X coordinate
-- @param y Y coordinate
-- @param out Channel to write to
PROC cursor.x.y (VAL BYTE x, y, CHAN OF BYTE out)
--{{{
SEQ
out ! ESCAPE
out ! '['
out.byte (y, 0, out)
out ! ';'
out.byte (x, 0, out)
out ! 'H'
--}}}
:
--}}}
--{{{ INT, INT FUNCTION random (VAL INT upto, seed)
--* Pseudorandom number generator.
-- This is an implementation by David Morse of the "minimal standard"
-- described in
-- "[@link http://portal.acm.org/citation.cfm?id=63042 Random number
-- generators: Good ones are hard to find]",
-- Park, K.P. & Miller, K.W. (1988), Comm. ACM, 31(10), 1192-1201.
--
-- The routine must be called with a valid seed: an integer of
-- between 1 and 2 147 483 647. The value of the seed must be
-- preserved from one call of the function to the next. This
-- implementation of the random number generator returns an integer
-- lying between 0 and ([@code upto] - 1) inclusive as its first result,
-- the seed is the second result.
--
-- The random number is full period, with a period of 2 ** 31,
-- that is 2 147 483 647.
--
-- @param upto The upper bound (exclusive) of the output value
-- @param seed The input seed
-- @return The output value
-- @return The output seed
INT, INT FUNCTION random (VAL INT upto, seed)
--{{{ miscellaneous constants
VAL INT magic IS 16807:
VAL INT period IS 2147483647:
VAL INT quotient IS period / magic:
VAL INT remainder IS period \ magic:
--}}}
INT int.result, new.seed:
VALOF
--{{{
INT lo, hi, test:
SEQ
hi := seed / quotient
lo := seed \ quotient
test := (magic TIMES lo) MINUS (remainder TIMES hi)
IF
test > 0
new.seed := test
TRUE
new.seed := test PLUS period
int.result := new.seed \ upto
--}}}
RESULT int.result, new.seed
:
--}}}