awkでparsec風パーサを実装した際に作成したeval風関数。
使用例
コードを読み込んでeval関数を生成する。
sample
awk "`./geneval << EOF
function hoge(arg1, arg2) {
print arg1" "arg2
return 1
}
function fuga(fun) {
return eval(fun)
}
BEGIN {
fuga("hoge hello eval!")
}
EOF
`"
$ ./sample
hello eval!
引数の文字列が関数から始まると仮定して、最初に現れた関数名に使用できない文字を引数間の区切り文字だと判断する。awkだと文字列と数値をよきに変換してくれるのでそれなりに動くが、配列オブジェクトを渡す手段はない…
コード
geneval
#!/usr/bin/awk -f
BEGIN{
if (ENVIRON["CALLER"]) CALLER=ENVIRON["CALLER"]
else CALLER="eval"
if (skip) REG="#[ ]*"skip
f=1
print " function " CALLER "(args, ret, arg) {"
print " if (match(args, /[^_a-zA-Z0-9]/))"
print " split(args, arg, substr(args, RSTART, 1))"
print " else"
print " arg[1]=args"
}
{buffer[NR]=$0}
REG && $0~REG {if (f) f=0; else f=1}
f && /\<function[ ]+/ {
gsub(/.*\<function[ ]*|\( .*|, .*|\).*/, "")
gsub(/[(,]/, " ")
n=split($0, funarg)
if (n>1) {
args="("
for (i=2; i<=n; i++) args=args "arg[" i "], "
sub(/, $/, ")", args)
} else args="()"
if (! c++)
print " if (arg[1]==\""funarg[1]"\") {"
else
print " } else if (arg[1]==\""funarg[1]"\") {"
print " ret=" funarg[1] args
}
END{
print " } else {"
print " print \""CALLER": \"arg[1]\" is not found!\" > \"/dev/stderr\""
print " exit 1"
print " }"
print " return ret"
print " }"
for (i=0; i<=NR; i++) print buffer[i]
}