もう AWK なんて使わないなんて言わないよ絶対〜
人間の偉大さは -- クリスマスの夜,一人孤独に耐える誇り高き姿にある (ギリシアの史家プルタルコス)
とかいう話はどうでも良いとして… またまた AWK をやってしまいました… orz
オレの葛 !!! (過去の過ちの記録と,さいとう先生の偉大さ.今を生きるのは〜 過去があったから (SO YOUNG 〜 THE YELLOW MONKEY))
AWK には魔物が潜んでいる… いつも始める前は,「ニョホ ! それ AWK (それ AWK なら ← 略にならない)」 と思い立って始めるものの,途中エライはまってニッチもサッチも行かなくなる !!
やりたかったこと : CASL II のアセンブラを楽に書きたかった…
結果
#!/usr/bin/awk -f
BEGIN {
PR = 0;
}
function isCASLInst(s) {
return s == "LD" ||
s == "ST" ||
s == "LAD" ||
s == "ADDA" ||
s == "SUBA" ||
s == "ADDL" ||
s == "SUBL" ||
s == "AND" ||
s == "OR" ||
s == "XOR" ||
s == "SLA" ||
s == "SRA" ||
s == "SLL" ||
s == "SRL" ||
s == "CPA" ||
s == "CPL" ||
s == "JPL" ||
s == "JMI" ||
s == "JNZ" ||
s == "JZE" ||
s == "JOV" ||
s == "JUMP" ||
s == "PUSH" ||
s == "POP" ||
s == "CALL" ||
s == "RET" ||
s == "SVC" ||
s == "NOP"
}
function x2b (n) {
if(n == "0")
return "0000"
else if(n == "1")
return "0001"
else if(n == "2")
return "0010"
else if(n == "3")
return "0011"
else if(n == "4")
return "0100"
else if(n == "5")
return "0101"
else if(n == "6")
return "0110"
else if(n == "7")
return "0111"
else {
printf("%s : Invalid GR num (in x2b) !\n", n)
return ""
}
}
function asm1(inst) {
PR += 1
if(inst == "NOP")
return sprintf("[%d] 0000 0000 0000 0000 (NOP)\n", PR - 1)
else if(inst == "RET")
return sprintf("[%d] 1000 0001 0000 0000 (RET)\n", PR - 1)
else {
printf("%s : Invalid CASL Inst !\n", inst)
return ""
}
}
function asm2(inst, arg1, arg2) {
# printf "inst : \"%s\", arg1 : \"%s\", arg2 : \"%s\"\n", inst, arg1, arg2
# register = "GR0", "GR1", "GR2", "GR3", "GR4", "GR5", "GR6", "GR7"
r1 = x2b(substr(arg1, 3, 1))
if(arg2 == "")
r2 = "0000"
else
r2 = x2b(substr(arg2, 3, 1))
PR += 1
if(inst == "LD")
return sprintf("[%d] 0001 0100 %s %s (%s %s %s)\n", PR - 1, r1, r2, inst, arg1, arg2)
else if(inst == "ADDA")
return sprintf("[%d] 0010 0100 %s %s (%s %s %s)\n", PR - 1, r1, r2, inst, arg1, arg2)
else if(inst == "SUBA")
return sprintf("[%d] 0010 0101 %s %s (%s %s %s)\n", PR - 1, r1, r2, inst, arg1, arg2)
else if(inst == "ADDL")
return sprintf("[%d] 0010 0110 %s %s (%s %s %s)\n", PR - 1, r1, r2, inst, arg1, arg2)
else if(inst == "SUBL")
return sprintf("[%d] 0010 0111 %s %s (%s %s %s)\n", PR - 1, r1, r2, inst, arg1, arg2)
else if(inst == "AND")
return sprintf("[%d] 0011 0100 %s %s (%s %s %s)\n", PR - 1, r1, r2, inst, arg1, arg2)
else if(inst == "OR")
return sprintf("[%d] 0011 0101 %s %s (%s %s %s)\n", PR - 1, r1, r2, inst, arg1, arg2)
else if(inst == "XOR")
return sprintf("[%d] 0011 0110 %s %s (%s %s %s)\n", PR - 1, r1, r2, inst, arg1, arg2)
else if(inst == "CPA")
return sprintf("[%d] 0100 0100 %s %s (%s %s %s)\n", PR - 1, r1, r2, inst, arg1, arg2)
else if(inst == "CPL")
return sprintf("[%d] 0100 0101 %s %s (%s %s %s)\n", PR - 1, r1, r2, inst, arg1, arg2)
else if(inst == "POP")
return sprintf("[%d] 0111 0001 %s %s (%s %s %s)\n", PR - 1, r1, r2, inst, arg1, arg2)
else {
printf("%s %s %s : Invalid CASL Inst !", inst, arg1, arg2)
return ""
}
}
function asm3(inst, arg1, adr, arg2) {
# printf "inst : \"%s\", arg1 : \"%s\", adr : \"%s\", arg2 : \"%s\"\n", inst, arg1, adr, arg2
# register = "GR0", "GR1", "GR2", "GR3", "GR4", "GR5", "GR6", "GR7"
if(arg1 == "")
r = "0000"
else
r = x2b(substr(arg1, 3, 1))
if(arg2 == "")
x = "0000"
else
x = x2b(substr(arg2, 3, 1))
if(adr ~ /^[0-9]/)
adr1 = adr
else
adr1 = sprintf("<ADR %s>", adr)
PR += 2
if(inst == "LD")
return sprintf("[%d] 0001 0000 %s %s (%s %s %s %s)\n%s\n", PR - 2, r, x, inst, arg1, adr, arg2, adr1)
else if(inst == "ST")
return sprintf("[%d] 0001 0001 %s %s (%s %s %s %s)\n%s\n", PR - 2, r, x, inst, arg1, adr, arg2, adr1)
else if(inst == "LAD")
return sprintf("[%d] 0001 0010 %s %s (%s %s %s %s)\n%s\n", PR - 2, r, x, inst, arg1, adr, arg2, adr1)
else if(inst == "ADDA")
return sprintf("[%d] 0010 0000 %s %s (%s %s %s %s)\n%s\n", PR - 2, r, x, inst, arg1, adr, arg2, adr1)
else if(inst == "SUBA")
return sprintf("[%d] 0010 0001 %s %s (%s %s %s %s)\n%s\n", PR - 2, r, x, inst, arg1, adr, arg2, adr1)
else if(inst == "ADDL")
return sprintf("[%d] 0010 0010 %s %s (%s %s %s %s)\n%s\n", PR - 2, r, x, inst, arg1, adr, arg2, adr1)
else if(inst == "SUBL")
return sprintf("[%d] 0010 0011 %s %s (%s %s %s %s)\n%s\n", PR - 2, r, x, inst, arg1, adr, arg2, adr1)
else if(inst == "AND")
return sprintf("[%d] 0011 0000 %s %s (%s %s %s %s)\n%s\n", PR - 2, r, x, inst, arg1, adr, arg2, adr1)
else if(inst == "OR")
return sprintf("[%d] 0011 0001 %s %s (%s %s %s %s)\n%s\n", PR - 2, r, x, inst, arg1, adr, arg2, adr1)
else if(inst == "XOR")
return sprintf("[%d] 0011 0010 %s %s (%s %s %s %s)\n%s\n", PR - 2, r, x, inst, arg1, adr, arg2, adr1)
else if(inst == "CPA")
return sprintf("[%d] 0100 0000 %s %s (%s %s %s %s)\n%s\n", PR - 2, r, x, inst, arg1, adr, arg2, adr1)
else if(inst == "CPL")
return sprintf("[%d] 0100 0001 %s %s (%s %s %s %s)\n%s\n", PR - 2, r, x, inst, arg1, adr, arg2, adr1)
else if(inst == "SLA")
return sprintf("[%d] 0101 0000 %s %s (%s %s %s %s)\n%s\n", PR - 2, r, x, inst, arg1, adr, arg2, adr1)
else if(inst == "SRA")
return sprintf("[%d] 0101 0001 %s %s (%s %s %s %s)\n%s\n", PR - 2, r, x, inst, arg1, adr, arg2, adr1)
else if(inst == "SLL")
return sprintf("[%d] 0101 0010 %s %s (%s %s %s %s)\n%s\n", PR - 2, r, x, inst, arg1, adr, arg2, adr1)
else if(inst == "SRL")
return sprintf("[%d] 0101 0011 %s %s (%s %s %s %s)\n%s\n", PR - 2, r, x, inst, arg1, adr, arg2, adr1)
else if(inst == "JMI")
return sprintf("[%d] 0110 0001 %s %s (%s %s %s %s)\n%s\n", PR - 2, r, x, inst, arg1, adr, arg2, adr1)
else if(inst == "JNZ")
return sprintf("[%d] 0110 0010 %s %s (%s %s %s %s)\n%s\n", PR - 2, r, x, inst, arg1, adr, arg2, adr1)
else if(inst == "JZE")
return sprintf("[%d] 0110 0011 %s %s (%s %s %s %s)\n%s\n", PR - 2, r, x, inst, arg1, adr, arg2, adr1)
else if(inst == "JUMP")
return sprintf("[%d] 0110 0100 %s %s (%s %s %s %s)\n%s\n", PR - 2, r, x, inst, arg1, adr, arg2, adr1)
else if(inst == "JPL")
return sprintf("[%d] 0110 0101 %s %s (%s %s %s %s)\n%s\n", PR - 2, r, x, inst, arg1, adr, arg2, adr1)
else if(inst == "JOV")
return sprintf("[%d] 0110 0110 %s %s (%s %s %s %s)\n%s\n", PR - 2, r, x, inst, arg1, adr, arg2, adr1)
else if(inst == "PUSH")
return sprintf("[%d] 0111 0000 %s %s (%s %s %s %s)\n%s\n", PR - 2, r, x, inst, arg1, adr, arg2, adr1)
else if(inst == "CALL")
return sprintf("[%d] 1000 0000 %s %s (%s %s %s %s)\n%s\n", PR - 2, r, x, inst, arg1, adr, arg2, adr1)
else if(inst == "SVC")
return sprintf("[%d] 1111 0000 %s %s (%s %s %s %s)\n%s\n", PR - 2, r, x, inst, arg1, adr, arg2, adr1)
else {
printf("%s %s %s %s : Invalid CASL Inst !", inst, arg1, adr, arg2)
return ""
}
}
function asm(inst, argv) {
if(inst == "NOP" || inst == "RET")
return asm1(inst)
else if(inst == "JMI" ||
inst == "JNZ" ||
inst == "JZE" ||
inst == "JUMP" ||
inst == "JPL" ||
inst == "JOV" ||
inst == "PUSH" ||
inst == "CALL" ||
inst == "SVC")
return asm3(inst, "", argv[1], argv[2])
else if (inst == "POP")
return asm2(inst, argv[1], "")
else if(argv[2] ~ /GR[0-7]/)
return asm2(inst, argv[1], argv[2])
else
return asm3(inst, argv[1], argv[2], argv[3])
}
isCASLInst($1) {
args = ""
for(i = 2; i <= NF; i++) {
if($i ~ /^;/)
break
args = args $i
}
argc = split(args, argv, ",")
obj = obj asm($1, argv)
next
}
isCASLInst($2) {
label = $1
if(LABEL2PR[label] == 0)
LABEL2PR[label] = PR
printf("[LABEL] %s [ADR] %s\n", label, LABEL2PR[label]);
args = ""
for(i = 3; i <= NF; i++) {
if($i ~ /^;/)
break
args = args $i
}
argc = split(args, argv, ",")
obj = obj asm($2, argv)
next
}
$2 == "DC" {
label = $1
if(LABEL2PR[label] == 0)
LABEL2PR[label] = PR
obj = obj sprintf("[%d] [LABEL] %s : [VALUE] %d\n", PR, $1, $3)
PR += 1
}
END {
for(label in LABEL2PR) {
r = sprintf("<ADR %s>", label)
gsub(r, LABEL2PR[label], obj)
}
print obj
}
一行野郎言語 AWK で 250 行って… orz
一応実行結果.ここの例題
MAIN START BEGIN
BEGIN LAD GR3, 7 ; 階乗計算の $n$ を GR3 にセット
; ここから階乗計算の手続き FACT が始まる →GR1:=(GR3)!
FACT OR GR3, GR3 ; GR3 ($n$)==0 か?
JZE SKIP ; もし $n=0$ だったら $0!=1$ なので計算せ ずに SKIP へ抜ける
LD GR2, GR3 ; 後で使うので GR3($n$) を GR2 にコピーし ておく
SUBA GR3, ONE ; GR3:=GR3-1 ($=n-1$)
PUSH 0, GR2 ; GR2($=n$) をスタックに保存
CALL FACT ; GR3($=n-1$) の階乗計算を呼び出す (結果は GR1 に ($n-1$)!)
POP GR2 ; スタックに保存しておいた GR2($=n$) を取り出し,
CALL MULTI ; 乗算 GR1($n!$):=GR2($n$)$\times$ GR1(($n-1$)!)
RET ; 復帰
;
SKIP LAD GR1, 1 ; $0!=1$ を GR1 に返す
RET ;
; ここから乗算副プログラ ム MULTI (GR1:=GR2$\times$GR1)
MULTI PUSH 0, GR2 ; 被乗数 GR2 をスタックに保存
XOR GR0, GR0 ; 演算を行う算盤 (GR0) を 0 にクリアする
NEXT SRL GR2, 1 ; シフト命令を使って 被乗数の LSB が 0 か 1 かを調べる
JOV PADD ; もし被乗数の LSB が 1 だったら乗数を算盤 に加算する
JZE EXIT ; そもそも被乗数が 0 だったら乗算を終了する
JUMP PART ; 被乗数が 0 でなく LSB も 1 でないときは その桁の乗算はしない
PADD ADDA GR0, GR1 ; 乗数(GR1)を算盤(GR0)に加える
PART SLL GR1, 1 ; 乗数の位取りを一桁分桁あげ変更する
JUMP NEXT ; 次の桁のチェック
EXIT POP GR2 ; 計算終了したら被乗数 GR2 の内容を復帰させ,
LD GR1, GR0 ; 算盤の内容 (GR0) つまり「積」を GR1 にコピーして
RET ; 戻る
ONE DC 1
;
END
を,fact.casl とすると.
aloha@alohax:~/comet$ ./casm.awk fact.casl
[LABEL] BEGIN [ADR] 0
[LABEL] FACT [ADR] 2
[LABEL] SKIP [ADR] 16
[LABEL] MULTI [ADR] 19
[LABEL] NEXT [ADR] 22
[LABEL] PADD [ADR] 30
[LABEL] PART [ADR] 31
[LABEL] EXIT [ADR] 35
[0] 0001 0010 0011 0000 (LAD GR3 7 )
7
[2] 0011 0101 0011 0011 (OR GR3 GR3)
[3] 0110 0011 0000 0000 (JZE SKIP )
16
[5] 0001 0100 0010 0011 (LD GR2 GR3)
[6] 0010 0001 0011 0000 (SUBA GR3 ONE )
38
[8] 0111 0000 0000 0010 (PUSH 0 GR2)
0
[10] 1000 0000 0000 0000 (CALL FACT )
2
[12] 0111 0001 0010 0000 (POP GR2 )
[13] 1000 0000 0000 0000 (CALL MULTI )
19
[15] 1000 0001 0000 0000 (RET)
[16] 0001 0010 0001 0000 (LAD GR1 1 )
1
[18] 1000 0001 0000 0000 (RET)
[19] 0111 0000 0000 0010 (PUSH 0 GR2)
0
[21] 0011 0110 0000 0000 (XOR GR0 GR0)
[22] 0101 0011 0010 0000 (SRL GR2 1 )
1
[24] 0110 0110 0000 0000 (JOV PADD )
30
[26] 0110 0011 0000 0000 (JZE EXIT )
35
[28] 0110 0100 0000 0000 (JUMP PART )
31
[30] 0010 0100 0000 0001 (ADDA GR0 GR1)
[31] 0101 0010 0001 0000 (SLL GR1 1 )
1
[33] 0110 0100 0000 0000 (JUMP NEXT )
22
[35] 0111 0001 0010 0000 (POP GR2 )
[36] 0001 0100 0001 0000 (LD GR1 GR0)
[37] 1000 0001 0000 0000 (RET)
[38] [LABEL] ONE : [VALUE] 1
とかなる.まだ途中だけど.AWK でバイナリデータを読み書きする方法がよくわからんので,実際のオブジェクトファイルが作れない…
まぁ,こんだけ (´・ω・`)
またクリスマス,というか,日曜があっというまに終わってしまった… 何やってんじゃ > わし.
結局何もしてねーよ.メイドインヘブン !!!
おまけにタイムリーなことに,
return
x1 ||
x2
とかうっかりやってしまうと,値がちゃんと返らない罠にもしっかり嵌まってしまったし… そんなとこばっかりフォローして !! しっかし,セミコロンとかが自由自在に省略できるってのは,いろいろアレな気が.型付けも物凄い緩いし.AWK がよきにはからってくれるので,文字列と整数の区別が無いという素敵さ.
結論 : Perl は偉大.
P ナントカとか R ナントカを使ったら負けかと思ってる (23 才,負け組)
