鳳鳴は祖父の俳号

日記 メモ そんなの

awkで書いたforthもどきその1

 ふと思い立ってawkでforth書けないかなとやってみた。ただしリターンスタックは現在使っておらず逆ポーランド電卓レベル。ワードも今は定義するだけ。
 gawk4.0.0が必要。split関数で4番目の引数(セパレータの格納)を使っているため。
 パラメータスタックを毎回操作しているがもちろん直接参照すれば速いとは思います。分かりやすさ優先。
 forthではスタックに積む値は16ビットの固定幅ですが、awkで書いてあるためawkで扱える値が積めます。ただ参照するときにそのままでは使えないので連想配列で参照する予定。

#! /usr/local/bin/gawk -f
#
# FORTH inerpreter by awk
#
# 2012.05.07 Pstack & standard op
# 2012.05.09 ( comment) & ." string"
# 2012.05.10 word
#
#
BEGIN{
	Pptr=0	# Parameter Stack Pointer
	Rptr=0	# Return Stack Pointer
	Pmax=30000
	Rmax=30000

	P[0]=""	# Parameter Stack
	R[0]=""	# Return Stack
	M[0]=""	# Memory

	TRUE=-1
	FALSE=0

	Printbegin=""
	Printend=""
	string=""
	Comment=""
	Compile=""

	print "* awkforth *"
	print "--"
}
{
	r=eval($0);
	if (r==0) {
		if (Compile!="") {
			print " compiled"
		} else {
			print " ok"
		}
	} else {
		print "ERR: " r
	}
}


function eval(str ,i,j,num,w,wj){
	num = split(str,word,FS,word_sep)
	for(i=1;i<=num;i++) {
		w=word[i];
		if(Compile=="" && w==":") {	# compile mode
			Compile=":"
			continue
		}
		if(Compile==":") {	# compile word
			Compile=w
			Word[Compile]=""
			continue
		}
		if(Compile!="") {	# compile
			if (w==";") {
				Compile=""
			} else {
				Word[Compile]=Word[Compile] " " w
			}
			continue
		}

		if (w=="(") {	# comment
			Comment="("
			continue
		}
		if (Comment!="" && substr(w,length(w),1)==")") {
			Comment=""
			continue
		}

		if (w==".\"" || w==".'") {
			Printbegin=w
			Printend=last(w)
			continue
		}
		if (Printbegin!="") {
			for(j=i;j<=num;j++) {
				i++
				wj=word[j]
				if (wj==Printbegin) continue ;
				if(last(wj)==Printend) {
					string = string head(wj)
					print string
					string=""
					PrintBegin=""
					break
				}
				string=string wj
				if (j<num) string=string word_sep[j]
			}
		}

		if ((nerr=isnum(w))&&(oerr=isop(w))) {
			return nerr+oerr
		}
	}
	return 0
}

function push(n) {
	if (Pptr>=Pmax) {
		print "# P Stack Overflow!"
		return 0
	}
	P[Pptr]=n
	Pptr++
}
function pop( n) {
	if (Pptr<=0) {
		print "# P stack Underflow!"
		return 0
	}
	--Pptr
	n=P[Pptr]
	return n
}

function last(word){
	return substr(word,length(word),1)
}
function head(word){
	return substr(word,1,length(word)-1)
}

function isnum(n) {
	if (n~"^[-]*[0-9]+$") {
		push(n);
		return 0
	} else {
		return 1
	}
}

function isop(x ,t,n,nn,r) {
	switch(x) {
	case ".":	# . ( n -- )
		print " " pop()
		r=0;break
	case "+":	# ( n1 n2 -- n2+n1 )
		t=pop();push(pop()+t)
		r=0;break
	case "-":	# ( n1 n2 -- n2-n1 )
		t=pop();push(pop()-t)
		r=0;break
	case "*":	# ( n1 n2 -- n2*n1 )
		t=pop();push(pop()*t)
		r=0;break
	case "/":	# ( n1 n2 -- n2/n1 )
		t=pop();push(pop()/t)
		r=0;break
	case "1+":	# ( n -- n+1 )
		t=pop();push(t+1)
		r=0;break
	case "1-":	# ( n -- n-1 )
		t=pop();push(t-1)
		r=0;break
	case "NEGATE":	# ( n -- -n )
		t=pop();push(-t)
		r=0;break
	case "ABS":	# ( n -- |n| )
		t=pop();push(t+0<0?-t:t+0)
		r=0;break
	case "MAX":	# ( n1 n2 -- n3 )
		t=pop();n=pop()
		push(t>n?t:n)
		r=0;break
	case "MIN":	# ( n1 n2 -- n3 )
		t=pop();n=pop()
		push(t<n?t:n)
		r=0;break
	case "<":	# ( n1 n2 -- n3 )
		t=pop();n=pop()
		push(n<t?TRUE:FALSE)
		r=0;break
	case ">":	# ( n1 n2 -- n3 )
		t=pop();n=pop()
		push(n>t?TRUE:FALSE)
		r=0;break
	case "DROP":	# ( n -- )
		pop()
		r=0;break
	case "DUP":	# ( n -- n n )
		t=pop();push(t);push(t)
		r=0;break
	case "DDUP":	# ( n -- n n n )
		t=pop();push(t);push(t);push(t)
		r=0;break
	case "OVER":	# ( n1 n2 -- n1 n2 n1 )
		t=pop();n=pop();push(n);push(t);push(n)
		r=0;break
	case "ROT":	# ( n1 n2 n3 -- n2 n3 n1 )
		t=pop();n=pop();nn=pop()
		push(n);push(t);push(nn)
		r=0;break
	case "SWAP":	# ( n1 n2 -- n2 n1 )
		t=pop();n=pop()
		push(t);push(n)
		r=0;break
	case "VLIST":	# ( -- )
		for(t in Word) {
			print t
		}
		r=0;break
	default:
		r=n
	}
	return r
}