############################################################################ # # File: expander.icn # # Subject: Procedures to convert character pattern expressions # # Author: Ralph E. Griswold # # Date: May 2, 2001 # ############################################################################ # # This file is in the public domain. # ############################################################################ # # pfl2str(pattern) expands pattern-form expressions, which have the form # # [] # # to the corresponding string. # # The value of determines the operation to be performed. # # pfl2gxp(pattern) expands pattern-form expressions into generators # that, when compiled and evaluated, produce the corresponding # string. # # pfl2pwl(pattern) converts pattern-form expressions to Painter's # weaving language. # ###########################################################################n # # Links: strings, weaving # ############################################################################ link strings link weaving procedure pfl2str(pattern) #: pattern-form to plain string local result, expr1, expr2, op static operator, optbl initial { operator := '*-!|+,/~:?%<>#`' optbl := table() optbl["*"] := repl optbl["<"] := Upto optbl[">"] := Downto optbl["-"] := UpDown optbl["|"] := Palindrome # optbl["!"] := Palindroid optbl["+"] := Block optbl["~"] := Interleave optbl["->"] := Extend optbl[":"] := Template optbl["?"] := Permute optbl["%"] := Pbox optbl["<>"] := UpDown optbl["><"] := DownUp optbl["#"] := rotate optbl["`"] := reverse optbl[","] := proc("||", 2) } result := "" pattern ? { while result ||:= tab(upto('[')) do { move(1) # expr1 := pfl2str(tab(bal(operator, '[', ']'))) | return error("1", pattern) expr1 := pfl2str(tab(bal(operator, '[', ']'))) | { result ||:= pfl2str(tab(bal(']', '[', ']'))) move(1) next } op := tab(many(operator)) | return error("2", pattern) expr2 := pfl2str(tab(bal(']', '[', ']'))) | return error("3", pattern) result ||:= \optbl[op](expr1, expr2) | return error("4", pattern) move(1) } if not pos(0) then result ||:= tab(0) } return result end procedure pfl2pwl(pattern) #: pattern form to Painter expression local result, i, j, slist, s, expr1, expr2, op, head static operator, optbl initial { operator := '*-!|+,;/~:?%<>#`' optbl := table() optbl["*"] := "*" optbl["<"] := "<" optbl[">"] := ">" optbl["-"] := "-" optbl["|"] := "|" optbl["!"] := "!" # not supported in PWL optbl["+"] := "[]" optbl["->"] := "->" optbl["~"] := "~" optbl[":"] := ":" optbl["?"] := " perm " optbl["%"] := " pbox " optbl["<>"] := "<>" optbl["><"] := "><" optbl["#"] := "#" optbl["`"] := "`" optbl[","] := "," } result := "" pattern ? { while head := tab(upto('[')) do { if *head > 0 then result ||:= "," || head move(1) expr1 := pfl2pwl(tab(bal(operator, '[', ']'))) | return error() op := tab(many(operator)) | return error() expr2 := pfl2pwl(tab(bal(']', '[', ']'))) | return error() result ||:= "," || "(" || expr1 || \optbl[op] || expr2 || ")" | return error() move(1) } if not pos(0) then result ||:= "," || tab(0) } return result[2:0] end procedure error(expr1, expr2) write(&errout, "*** error ", expr1, " ", expr2) fail end procedure pfl2gxp(pattern, arg) #: pattern form to generating expression local result, i, j, slist, s, expr1, expr2, op static operator, optbl, argtbl initial { operator := ',.*-!|+;/~:?%<>#`' optbl := table() optbl["*"] := "Repl{" optbl["<"] := "Upto{" optbl[">"] := "Downto{" optbl["-"] := "UpDownto{" optbl["|"] := "TileMirror{" optbl["!"] := "Palin{" optbl["+"] := "Valrpt{" optbl["~"] := "Inter{" optbl["->"] := "ExtendSeq{" optbl["~"] := "Parallel{" optbl[":"] := "Template{" optbl["?"] := "Permut{" optbl["%"] := "Pbox{" optbl["<>"] := "UpDown{" optbl["><"] := "DownUp{" optbl["#"] := "Rotate{" optbl["`"] := "Reverse{" optbl["*"] := repl } /arg := str # Handling of literal arguments argtbl := table(str) argtbl["*"] := 1 argtbl["#"] := 1 argtbl["->"] := 1 if /pattern | (*pattern = 0) then return image("") result := "" pattern ? { while result ||:= arg(tab(upto('['))) do { move(1) expr1 := pfl2gxp(tab(bal(operator, '[', ']')), arg) | { result ||:= tab(bal(']', '[', ']')) || " | " # no operator move(1) next } if ="." then result ||:= tab(bal(']', '[', ']')) || " | " else { op := tab(many(operator)) | return error() expr2 := pfl2gxp(tab(bal(']', '[', ']')), argtbl[op]) | return error() result ||:= \optbl[op] || expr1 || "," || expr2 || ") | " | return error() } move(1) } if not pos(0) then result ||:= arg(tab(0)) } return trim(result, '| ') end procedure lit(s) return "!" || image(s) end procedure str(s) return lit(s) || " | " end procedure galt(s) return "Galt{" || collate(s, repl(",", *s - 1)) || "}" end procedure pwl2pfl(wexpr) #: Painter expression to pattern form return pwlcvt(prepare(wexpr)) end procedure prepare(wexpr) # preprocess pwl local inter, result static names, names1 initial { names := [ "", # expression placeholder " block ", "[]", " repeat ", "*", " rep ", "*", " extend ", "==", " ext ", "==", " concat ", ",", " interleave ", "~", " int ", "~", " upto ", ">", " downto ", "<", " template ", ":", " temp ", ":", " palindrome ", "|", " pal ", "|", " pal", "|", " permute ", "?", " perm ", "?", " pbox ", "%", " updown ", "<>", " downup ", "><", " rotate ", "#", " rot ", "#", " reverse ", "`", " rev ", "`", " rev", "`", ] names1 := [ "", # expression placeholder "pal", "|", "rev", "`" ] } result := "" wexpr ? { while result ||:= tab(upto('[')) do { move(1) inter := tab(bal(']')) if *inter > 0 then result ||:= spray(inter) else result ||:= "[]" move(1) } result ||:= tab(0) } if upto(result, ' ') then { if upto(result, &letters) then { names[1] := result result := (replacem ! names) } } if upto(result, &letters) then { names1[1] := result result := (replacem ! names1) } return deletec(map(result, "[]", "=="), ' ') end procedure pwlcvt(wexpr) local result, inter wexpr ?:= { 2(="(", tab(bal(')')), pos(-1)) } result := "" wexpr ? { while result ||:= form1(pwlcvt(tab(bal('|`', '([', ']('))), move(1)) result ||:= tab(0) } wexpr := result result := "" wexpr ? { while result ||:= form2(pwlcvt(tab(bal('->:#*=~', '([', ')]'))), =("#" | "*" | "->" | "~" | ":" | "=="), pwlcvt(tab(0))) result ||:= tab(0) } wexpr := result result := "" wexpr ? { while result ||:= form2(pwlcvt(tab(bal('<>', '([', ')]'))), =("><" | "<>"), pwlcvt(tab(0))) result ||:= tab(0) } wexpr := result result := "" wexpr ? { while result ||:= form2(pwlcvt(tab(bal('<->,', '([', ')]'))), =(">" | "<" | "-" | ","), pwlcvt(tab(0))) result ||:= tab(0) } return result end procedure form1(wexpr, op) return "[" || wexpr || op || "]" end procedure form2(wexpr1, op, wexpr2) return "[" || wexpr1 || op || wexpr2 || "]" end procedure spray(inter) local count, s1, s2, s3, colors s1 := s2 := s3 := "" inter ?:= { # only palindome and reflection allowed, it seems 1(tab(upto('|`') | 0), s3 := tab(0)) } inter ? { while s1 ||:= colors := tab(upto(' ')) do { tab(many(' ')) count := tab(upto(' ') | 0) if *count = 1 then s2 ||:= repl(count, *colors) else s2 ||:= repl("{" || count || "}", *colors) move(1) | break } } return "((" || s1 || s3 || ")" || "[]" || s2 || ")" end