「数の組」に対する「式の評価(計算)」ができるように次の拡張を行った。
・構文解析と演算との部分を分離
・FUNCTION文では返り値を1つのみのため、SUB文で記述
「数の組」とは
関数、変数、定数の通常の数式の場合、「値」(1つ)
有理数の場合、「分子と分母」(2つ)
複素数の場合、「実数部と虚数部」(2つ)
ベクトル、行列の場合、「要素列」(n個)
1変数多項式の係数が整数の場合、「係数列」(n個)
とする。
記述例 1変数多項式の係数が整数の場合
!式(中置記法)の評価 - 1変数多項式の係数が整数の場合 ※UBASIC相当
DECLARE EXTERNAL SUB expr.eval
!LET s$="(x-2)*(x-3)*(x-4)*(x-5)"
LET s$="(x^2-2*x+3)^2"
!LET s$="(x^5-5*x^3+5*x^2-1)/(x^2+3*x+1)" !商 x^3-3*x^2+3*x-1、余り 0
!LET s$="mod(2*x^3-13*x^2-26*x-15,x^2-2*x+3)" !商 2*x-9、余り -50*x+12
!LET s$="gcd(3*x^2+5*x-2,3*x^2-7*x+2)" !12*x-4 { 3*x-1 }
!LET s$="lcm(3*x^2+5*x-2,3*x^2-7*x+2)" !3/4*x^3-1/4*x^2-3*x+1 { (x+2)*(x-2)*(3*x-1) }
!LET s$="lcm(x^3-16*x,x^3-8*x^2+16*x)"
DIM a(0 TO 8) !係数 a(n)*x^n+a(n-1)*x^(n-1)+ … +a(1)*x+a(0)
CALL eval(s$, a,rc) !式
MAT PRINT a; !x^0,x^1,x^2, … の順 debug
IF rc=0 THEN CALL poly_disp(a) !結果を表示する
END
MODULE expr
PUBLIC NUMERIC p,ErrNo !共通変数
!●解析部分
!下位の共通ルーチン
EXTERNAL FUNCTION token$(s$) !1文字読み込む
CALL EatSpace(s$)
IF p<=LEN(s$) THEN LET token$=s$(p:p) ELSE LET token$=""
END FUNCTION
EXTERNAL SUB EatSpace(s$) !空白を読み飛ばす
DO WHILE s$(p:p)=" " AND p<=LEN(s$)
LET p=p+1
LOOP
END SUB
EXTERNAL SUB CheckToken(s$,L$) !文字を確認する
CALL EatSpace(s$)
IF UCASE$(s$(p:p+LEN(L$)-1))<>L$ THEN CALL Error(L$&"がありません。")
LET p=p+LEN(L$) !eat it
END SUB
EXTERNAL SUB Error(x$) !メッセージを表示する
PRINT
PRINT x$; p
LET errNo=1
END SUB
!上位ルーチン
PUBLIC SUB eval
EXTERNAL SUB eval(s$, v(),rc) !式の評価
LET errNo=0 !エラーコード
LET p=1 !文字列へのポインタ
CALL expression(s$, v) !計算する
LET rc=errNo
END SUB
EXTERNAL SUB expression(s$, v()) !式
DIM w(0 TO UBOUND(v))
LET t$=token$(s$)
IF t$="-" THEN !符号なら
LET p=p+1 !eat it
CALL term(s$, v)
IF errNo<>0 THEN EXIT SUB
CALL op_neg(v, v) !v=-v
ELSE
IF t$="+" THEN LET p=p+1 !eat it
CALL term(s$, v)
END IF
IF errNo<>0 THEN EXIT SUB
LET t$=token$(s$)
DO WHILE t$="+" OR t$="-" !加算、減算なら
LET p=p+1 !eat it
CALL term(s$, w)
IF errNo<>0 THEN EXIT SUB
IF t$="+" THEN !計算する
CALL op_add(v,w, v) !v=v+w
ELSE
CALL op_sub(v,w, v) !v=v-w
END IF
IF errNo<>0 THEN EXIT SUB
LET t$=token$(s$) !次へ
LOOP
END SUB
EXTERNAL SUB term(s$, v()) !項
DIM w(0 TO UBOUND(v))
CALL factor(s$,v)
IF errNo<>0 THEN EXIT SUB
LET t$=token$(s$)
DO WHILE t$="*" OR t$="/" !乗算、除算なら
LET p=p+1 !eat it
CALL factor(s$,w)
IF errNo<>0 THEN EXIT SUB
IF t$="*" THEN !計算する
CALL op_mul(v,w, v) !v=v*w
ELSE
CALL op_div(v,w, v) !v=v/w
END IF
IF errNo<>0 THEN EXIT SUB
LET t$=token$(s$) !次へ
LOOP
END SUB
EXTERNAL SUB factor(s$, v()) !因子
DIM w(0 TO UBOUND(v))
LET t$=token$(s$)
IF t$="(" THEN !括弧なら
LET p=p+1 !eat it
CALL expression(s$,w) !式
IF errNo<>0 THEN EXIT SUB
MAT v=w
CALL CheckToken(s$,")") !閉じ括弧か確認する
ELSE
CALL num(s$,v)
END IF
IF errNo<>0 THEN EXIT SUB
LET t$=token$(s$)
DO WHILE t$="^" !べき乗なら
LET p=p+1 !eat it
LET t$=token$(s$)
IF t$="(" THEN !括弧なら
LET p=p+1 !eat it
CALL expression(s$,w) !式
IF errNo<>0 THEN EXIT SUB
CALL CheckToken(s$,")") !閉じ括弧か確認する
ELSE
CALL num(s$,w)
END IF
IF errNo<>0 THEN EXIT SUB
CALL op_pow(v,w, v) !計算する v=v^w
IF errNo<>0 THEN EXIT SUB
LET t$=token$(s$) !次へ
LOOP
END SUB
EXTERNAL SUB num(s$,v()) !数
DIM w(0 TO UBOUND(v)),x(0 TO UBOUND(v))
LET c=fnc(s$)
IF c>0 THEN !関数なら
LET t$=token$(s$)
IF t$="(" THEN !括弧なら
LET p=p+1 !eat it
CALL expression(s$,w) !引数1
IF errNo<>0 THEN EXIT SUB
MAT v=w
CALL CheckToken(s$,",") !カンマか確認する
CALL expression(s$,w) !引数2
IF errNo<>0 THEN EXIT SUB
IF c=1 THEN !modpow(a,n,b)形式
CALL CheckToken(s$,",") !カンマか確認する
CALL expression(s$,w) !引数3
IF errNo<>0 THEN EXIT SUB
MAT x=w
CALL set_fnc3(c,v,w,x, v) !v=fnc(v,w,x)
ELSE
CALL set_fnc2(c,v,w, v) !v=fnc(v,w)
END IF
IF errNo<>0 THEN EXIT SUB
CALL CheckToken(s$,")") !閉じ括弧か確認する
ELSE
CALL Error("不正な文字です。")
END IF
ELSE
LET c=var(s$)
IF c>0 THEN !変数なら
CALL set_var(c, v)
ELSE
LET c=number(s$)
IF c>=0 THEN !定数(数値)なら
CALL set_number(c, v)
ELSE
CALL Error("不正な文字です。")
END IF
END IF
END IF
END SUB
EXTERNAL FUNCTION fnc(s$) !関数
DATA "MODPOW","MODINV","MOD","GCD","LCM" !※文字長が大きい順
LET k=0
DO
LET k=k+1
READ IF MISSING THEN EXIT DO: d$
IF UCASE$(s$(p:p+LEN(d$)-1))=UCASE$(d$) THEN !一致したら
LET p=p+LEN(d$)
LET fnc=k
EXIT FUNCTION
END IF
LOOP
LET fnc=-1
END FUNCTION
EXTERNAL FUNCTION var(s$) !変数
LET t$=UCASE$(token$(s$)) !大文字へ
IF "A"<=t$ AND t$<="Z" THEN
!!!IF t$="X" THEN
LET p=p+1 !eat it
LET var=ORD(t$)-ORD("@") !オフセット @=0,A=1,B=2,…,Z=26
ELSE
LET var=-1
END IF
END FUNCTION
EXTERNAL FUNCTION number(s$) !数値(0、正の整数)
LET i0=p !先頭位置を記録する
LET t$=token$(s$)
DO WHILE t$>="0" AND t$<="9"
LET p=p+1
LET t$=token$(s$)
LOOP
LET number=-1
IF p>i0 THEN LET number=VAL(s$(i0:p-1)) !数字列の範囲を切り取る
END FUNCTION
つづく