101 lines
3.3 KiB
Plaintext
101 lines
3.3 KiB
Plaintext
markov = cluster is make, run
|
|
rule = struct[from, to: string, term: bool]
|
|
rep = array[rule]
|
|
|
|
% Remove leading and trailing whitespace from a string
|
|
trim = proc (s: string) returns (string)
|
|
ac = array[char]
|
|
sc = sequence[char]
|
|
own ws: string := "\n\t "
|
|
a: ac := string$s2ac(s)
|
|
while ~ac$empty(a) cand string$indexc(ac$bottom(a), ws) ~= 0 do
|
|
ac$reml(a)
|
|
end
|
|
while ~ac$empty(a) cand string$indexc(ac$top(a), ws) ~= 0 do
|
|
ac$remh(a)
|
|
end
|
|
return(string$sc2s(sc$a2s(a)))
|
|
end trim
|
|
|
|
% Parse a single Markov rule
|
|
parse = proc (s: string) returns (rule) signals (comment, invalid(string))
|
|
if string$empty(s) cor s[1]='#' then signal comment end
|
|
arrow: int := string$indexs(" -> ", s)
|
|
if arrow=0 then signal invalid(s) end
|
|
left: string := trim(string$substr(s, 1, arrow-1))
|
|
right: string := trim(string$rest(s, arrow+4))
|
|
|
|
if ~string$empty(right) cand right[1] = '.' then
|
|
right := string$rest(right, 2)
|
|
return(rule${from: left, to: right, term: true})
|
|
else
|
|
return(rule${from: left, to: right, term: false})
|
|
end
|
|
end parse
|
|
|
|
% Add a rule to the list
|
|
add_rule = proc (m: cvt, s: string) signals (invalid(string))
|
|
rep$addh(m, parse(s)) resignal invalid
|
|
except when comment: end
|
|
end add_rule
|
|
|
|
% Read rules in sequence from a stream
|
|
add_rules = proc (m: cvt, s: stream) signals (invalid(string))
|
|
while true do
|
|
add_rule(up(m), stream$getl(s)) resignal invalid
|
|
except when end_of_file: break end
|
|
end
|
|
end add_rules
|
|
|
|
make = proc (s: stream) returns (cvt) signals (invalid(string))
|
|
a: rep := rep$new()
|
|
add_rules(up(a), s)
|
|
return(a)
|
|
end make
|
|
|
|
% Apply a rule to a string
|
|
apply_rule = proc (r: rule, s: string) returns (string) signals (no_match)
|
|
match: int := string$indexs(r.from, s)
|
|
if match = 0 then signal no_match end
|
|
new: string := string$substr(s, 1, match-1)
|
|
|| r.to
|
|
|| string$rest(s, match+string$size(r.from))
|
|
return(new)
|
|
end apply_rule
|
|
|
|
% Apply all rules to a string repeatedly
|
|
run = proc (c: cvt, s: string) returns (string)
|
|
i: int := 1
|
|
while i <= rep$high(c) do
|
|
r: rule := c[i]
|
|
begin
|
|
s := apply_rule(r, s)
|
|
i := 1
|
|
if r.term then break end
|
|
end except when no_match:
|
|
i := i+1
|
|
end
|
|
end
|
|
return(s)
|
|
end run
|
|
end markov
|
|
|
|
start_up = proc ()
|
|
po: stream := stream$primary_output()
|
|
eo: stream := stream$error_output()
|
|
|
|
begin
|
|
args: sequence[string] := get_argv()
|
|
file: string := args[1]
|
|
input: string := args[2]
|
|
fs: stream := stream$open(file_name$parse(file), "read")
|
|
mkv: markov := markov$make(fs)
|
|
stream$close(fs)
|
|
stream$putl(po, markov$run(mkv, input))
|
|
end except
|
|
when bounds: stream$putl(eo, "Arguments: markov [filename] [string]")
|
|
when not_possible(s: string): stream$putl(eo, "File error: " || s)
|
|
when invalid(s: string): stream$putl(eo, "Parse error: " || s)
|
|
end
|
|
end start_up
|