|
||||||
# Expresso # # This code takes an expression, parses it, and then mutates it. # # The transformations are normally taken from a *.exp file (see default.exp # for the default set of transformations). # # It involves a recursive descent parser, and a lot of uncommented code. # function webexpresso(gen,seed1,fn,x,...) { initialargs = 4 ntrans = nargs() - initialargs transforms = [] for ( n=0; n<ntrans; n++ ) { transforms[argv(initialargs+n)] = 1 } if ( fn != "" ) { p = readmf(fn); # how many notes we want to pick howmany = 20 p = onlynotes(p); lng1 = sizeof(p); if ( lng1 > howmany ) { rnd1 = rand(lng1-howmany) p = p{??.number >= rnd1} p = strip(head(p,howmany)) } } else { p = phrase("'"+x+"'") } p = expresso(transforms,gen,seed1,p) print("EXPR = ",Gexpr,"<br><font size=-2><i>random seed used was",seed1,"<i><font>") limit = 5000 psize = sizeof(p) if ( psize > limit ) { print("<p>NOTE: Generated phrase was too large (",psize,"), it has been truncated at ",limit," notes.") p = head(p,limit) } p.length = latest(p) writemf(p,"www.mid") writelines(p,"www.lines") } function etest(p) { if ( nargs() <= 0 ) { p = 'c,e,g' } return(expresso("default",10,currtime(),p)) # print ("xx=",xx) # print("EXPR = ",Gexpr) } function expresso(transforms,gen,seed1,x) { if ( typeof(transforms) == "string" ) { fn = pathsearch(transforms+".exp") if ( fn == "" ) { print("Can't find file "+transforms+".exp") return('') } transforms = read_transforms(fn) } rand(-seed1) p = gen_expresso(transforms,gen,x,1) return(p) } Gtokes = [] Gtypes = [] GEN_EOF = -1 GEN_NOTHING = 0 GEN_NUMBER = "number" GEN_STRING = "string" GEN_WORD = "word" GEN_BINOP = "binop" GEN_UNOP = "unop" GEN_PUNCT = "punct" function gen_init_transforms(transforms) { n = 0; Gtrans_from = [] Gtrans_to = [] for ( k in transforms ) { b = split(k,"=") Gtrans_from[n] = gen_parsexp(b[0]) Gtrans_to[n] = gen_parsexp(b[1]) n++ } } function read_transforms(fname) { arr = [] f = open(fname) fifoctl(f,"type","l") # read line-at-a-time while ( (ln=get(f)) != Eof ) { if ( substr(ln,1,1) != "#" ) { arr[ln] = 1 } } return(arr) } function gran(transforms,g) { if ( nargs() < 1 ) g = 10 r = '' for ( n=0; n<g; n++ ) { r += gen_expresso(transforms,10,'cd12,c',0) } return(r) } function gen_expresso(transforms,ng,x,verbose) { if ( nargs() < 1 ) ng = 3 if ( nargs() < 2 ) x='cd12,co4,c,c' if ( nargs() < 3 ) verbose = 1 gen_init_transforms(transforms) Gexpr = "X" pn = gen_parsexp(Gexpr) for ( i=0; i<ng; i++ ) { pn = gen_mutate(pn) } Gexpr = gen_sprint(pn) X=x eval "GEN="+Gexpr return(GEN) } function gen_parsexp(s) { gen_tokens(s) Gpeekn = 0 gen_peek(); # to prime Glookahead return(gen_binopexpr()) } function gen_isbinop(c) { return ( c ~~ "[-+*/|&]" ); } function gen_subvar(oldvarname,subvarname,subexpr) { pn = []; op = subexpr["op"] if ( op == "var" ) { pn["op"] = op if ( subexpr["var"] == subvarname ) { pn["var"] = oldvarname } else { pn["var"] = subexpr["var"] } } else if ( gen_isbinop(op) ) { pn["op"] = op pn["operand1"] = gen_subvar(oldvarname,subvarname,subexpr["operand1"]) pn["operand2"] = gen_subvar(oldvarname,subvarname,subexpr["operand2"]) } else if ( op == "func" ) { pn["op"] = op pn["func"] = subexpr["func"] i = 1 as = "arg"+string(i) while ( as in subexpr ) { pn[as] = gen_subvar(oldvarname,subvarname,subexpr[as]) as = "arg"+string(++i) } } else if ( op == "number" || op == "string") { pn = arraycopy(subexpr) } else { print("WARNING: gen_subvar isn't handling subexpr[op]=",subexpr["op"],", using original var") pn["op"] = subexpr["op"] pn["var"] = oldvarname } return(pn) } function gen_mutate(pn) { if ( typeof(pn) != "array" ) { printf("NONARRAY(",pn,")") } else if ( pn["op"] == "var" ) { # Look through the transformations to see how many # "var" ones we have nv = 0 for ( k in Gtrans_from ) { pf = Gtrans_from[k] if ( pf["op"] == "var" ) nv++ } prob = 100/nv; for ( k in Gtrans_from ) { pf = Gtrans_from[k] if ( pf["op"] == "var" && (rand(100) < prob) ) { # apply it - save the old variable name oldvarname = pn["var"] subvarname = pf["var"] # delete the original array for ( i in pn ) delete(pn[i]) # copy the transformation, replacing # all the instances of subvarname with # the oldvarname pn = gen_subvar(oldvarname,subvarname,Gtrans_to[k]) break; } } } else if ( pn["op"] == "number" ) { # printf(pn["number"]) } else if ( pn["op"] == "func" ) { # gen_mutate(pn["func"]) for ( n=1; ; n++ ) { a = "arg"+string(n) if ( a in pn ) { pn[a] = gen_mutate(pn[a]) } else { break } } } else if ( gen_isbinop(pn["op"]) ) { # op = pn["op"] # if ( op == "+" ) # pn["op"] = "-" # else if ( op == "-" ) # pn["op"] = "+" pn["operand1"] = gen_mutate(pn["operand1"]) pn["operand2"] = gen_mutate(pn["operand2"]) } else { # printf(pn["op"]) } return(pn) } function gen_sprint(pn) { if ( typeof(pn) != "array" ) { return("RAW("+pn+")") } else if ( pn["op"] == "!" ) { return("!("+gen_sprint(pn["operand1"])+")") } else if ( pn["op"] == "var" ) { return(pn["var"]) } else if ( pn["op"] == "number" ) { return(pn["number"]) } else if ( pn["op"] == "func" ) { r = pn["func"]+"(" sep = "" for ( n=1; ; n++ ) { a = "arg"+string(n) if ( a in pn ) { if ( sep != "" ) r += sep r += gen_sprint(pn[a]) } else { break } sep = "," } r += ")" return(r) } else if ( gen_isbinop(pn["op"]) ) { return("(" +gen_sprint(pn["operand1"]) +pn["op"] +gen_sprint(pn["operand2"]) +")") } else { return("(RAWOP=pn="+string(pn)+")") } } function gen_peek() { if ( Gpeekn < sizeof(Gtokes) ) { Glookahead = Gtokes[Gpeekn] Glookaheadtype = Gtypes[Gpeekn] } else { Glookahead = EOF Glookaheadtype = GEN_EOF } } function gen_eat() { w = Gtokes[Gpeekn++] gen_peek() return(w) } function gen_binopexpr() { t1 = gen_val_expr(); while ( Glookaheadtype == GEN_BINOP ) { op = gen_eat() t2 = gen_val_expr(); tree = [] tree["op"] = op tree["operand1"] = t1 tree["operand2"] = t2 t1 = tree } return(t1) } function gen_val_expr() { tree = [] if ( Glookahead == "(" ) { gen_match("("); n = gen_binopexpr(); gen_match(")"); return(n) } if ( Glookaheadtype == GEN_UNOP ) { tree["op"] = gen_eat() tree["operand1"] = gen_binopexpr(); return(tree) } if ( Glookaheadtype == GEN_NUMBER ) { tree["op"] = "number" tree["number"] = gen_eat() return(tree) } if ( Glookaheadtype == GEN_WORD ) { w1 = gen_eat() if ( Glookahead == "(" ) { gen_eat() tree["op"] = "func" tree["func"] = w1; na = 0; if ( Glookahead != ")" ) { while ( 1 ) { n2 = gen_binopexpr(); na++ tree["arg"+string(na)] = n2 if ( Glookahead == "," ) { gen_match(",") } else if ( Glookahead == ")" ) { gen_match(")") break; } else { print("Unexpected input: "+Glookahead) return([]) } } } } else { tree["op"] = "var" tree["var"] = w1 } return(tree) } return(tree) } function gen_match(c) { if ( Gtokes[Gpeekn] == c ) { Gpeekn++ Glookahead = Gtokes[Gpeekn]; Glookaheadtype = Gtypes[Gpeekn]; } else { print("Didn't find expected token: ",c); } } function gen_tokens(s) { current = "" lng = sizeof(s) Gtokes = [] Gtypes = [] ntokes = 0 inside = 0 for ( n=0; n<lng; n++ ) { c = substr(s,n+1,1) if ( inside == GEN_STRING ) { current += c if ( c == substr(current,1,1) ) { Gtokes[ntokes] = current ntokes++ inside = GEN_NOTHING current = "" } continue } if ( inside == GEN_NUMBER ) { if ( c ~~ "[0123456789.]" ) { current += c continue } Gtokes[ntokes] = current ntokes++ } if ( inside == GEN_WORD ) { if ( c ~~ "[a-zA-Z]" ) { current += c continue } Gtokes[ntokes] = current ntokes++ } inside = GEN_NOTHING current = "" if ( c == "(" || c == ")" || c == "," ) { Gtypes[ntokes] = GEN_PUNCT Gtokes[ntokes] = c ntokes++ current = "" } else if ( c == "!" ) { Gtypes[ntokes] = GEN_UNOP Gtokes[ntokes] = c ntokes++ current = "" } else if ( c == "-" ) { cnext = substr(s,n+2,1) if ( cnext ~~ "[0123456789]" ) { Gtypes[ntokes] = GEN_NUMBER inside = GEN_NUMBER current = "-"+cnext n++ } else { Gtypes[ntokes] = GEN_UNOP Gtokes[ntokes] = c ntokes++ } } else if ( gen_isbinop(c) ) { Gtypes[ntokes] = GEN_BINOP Gtokes[ntokes] = c ntokes++ current = "" } else if ( c ~~ "[0123456789]" ) { Gtypes[ntokes] = GEN_NUMBER inside = GEN_NUMBER current = c } else if ( c ~~ "[a-zA-Z]" ) { Gtypes[ntokes] = GEN_WORD inside = GEN_WORD current = c } else if ( c ~~ "\"" || c ~~ "'" ) { current = c Gtypes[ntokes] = GEN_STRING inside = GEN_STRING } else { current += c } } if ( current != "" ) Gtokes[ntokes++] = current return() } |