十進BASICに添付されたサンプルプログラム"\BASICw32\SAMPLE\INTERPRE.bas"は数値式の評価を行います。
数値式を入力すると、その式の値を出力します。
それを次のように拡張しました。
(1) 数値定数
小数点で始まる小数や、指数部のある数値も扱える。
(2) 組込み関数
十進BASICの組込み関数は、配列や特殊な例を除きほとんど利用できる。
(3) 変数
数値式に変数を使える。
数値式内に変数を認識すると,変数名を表示し入力を求めてくる(中止は[中止]ボタンで)。
変数への入力は数値式も可。ただし,この数値式に変数を含むことは不可。
例) a^2+1 の変数a に[4],[-3/2],[8-3*5],[sqr(5)-1],[SIN(pi/6)]など入力可。[4*n+9]は不可。
変数名の命名規則は十進BASICに準ずる(漢字可、PI,RND,MAXNUM,DATE,TIME,DATE$,TIME$以外の機能語も可)。
配列には対応していない。
(4) 文字列式
文字列式の評価も行える。その場合は入力する文字列式の先頭に「$=」を付ける。
例) $=REPEAT$("aBc D",3) ; $="alphabet "&CHR$(64+Number) ; $="2*3+7="&STR$(2*3+7)
文字列では大文字と小文字を区別する。空白も認識する。漢字も可。
(5) 文字列変数
数値式や文字列式に、文字列変数を使用できる。
文字列変数への入力は、文字列定数(前後の(")は不要)または文字列式が可。
文字列変数に文字列式を入力する場合は先頭に「$=」を付ける。この文字列式に変数を含むことは不可。
例) $=USING$(a$,800.52) のa$に[###],[$=REPEAT$("#",3)]など入力可。
例) LEN(mj$&"yz") のmj$に[ab漢],[$=LTRIM$(" ab")&UCASE$"cd"]など入力可。[$="mn"&A$]は不可。
例) VAL(c$)+7 のc$に[-2.5],[$=str$(1/2-3)]など入力可(-2.5は"-2.5"という文字列定数)。
(6) 部分文字列指定
文字列変数に部分文字列指定ができる。
ただし部分文字列指定より前に,同名の文字列変数が書かれている必要がある。
例) $=a$&","&a$(3:5) ; $=UCASE$(cap$&"aBc")&cap$(2:2-1+m) ; POS(r$,r$(k:k))
誤入力例) $=box$(2:4)&","&box$
修正例) $=REPEAT$(box$,0)&box$(2:4)&","&box$ ; $=SUBSTR$(box$,2,4)&","&box$
(7) ユーザー定義関数
数値式に独自に定義した関数を使えるようにした。
関数名は F1(a)、F2(a,b)、F3(a,b,c)、FS$(a$,b,c)。
変数への入力にも使える。 例) SQR(r-4)+1 のrに[2*F2(3,7-5)]など入力可。
この関数の定義部は1260行の後ろにあるので必要に応じて変更して下さい。再帰呼び出しも可能です。
入力例(関数名,変数名は大文字と小文字の区別はしない)
2*.43+7E2 ; MOD(10^2,int(MAX(7.4,sqr(10)+3)))-1 ; sin(a)^2+cos(b)^2
2*x^2-7*x+6 ; 1+INT(RND*n) ; INT(借入金*(1+年利/100)^年数) ; LEN("ab""cd ef gh")
$=mj$&"xYz"&STR$(n) ; $=UCASE$(p$)&","&LCASE$(p$) ; $="0x"&BSTR$(Decimal,16)
$=STR$(1/(2*a)*(-b+sqr(b^2-4*a*c)))&","&STR$((-b-sqr(b^2-4*a*c))/(2*a)) !2次方程式の2根
$="a="&STR$(abs(m^2-n^2))&",b="&STR$(2*m*n)&",c="&STR$(m^2+n^2) !ピタゴラス数
$=enter$&TIME$&USING$(".#",FP(TIME)) ; m*f3(N-5,4,sqr(M)) ; $=FS$("abc",x,6)&"."
目標としたのは「PRINT *******」で出力できる数値式、文字列式を網羅することでした。
配列以外は達成できたと思うのですがどうでしょう。
すべてをチェックしているわけでなく間違った数値式を入力してもエラー表示されないかもしれません。
不具合があれば報告お願いします。
REM 十進BASIC添付"\BASICw32\SAMPLE\INTERPRE.bas"に加筆
REM 行番号のない行が加筆部分。行番号は削除可。
1000 REM Full BASICのモジュールの使い方を示すサンプル
1010 REM
1020 REM 数値式の評価を行う
1030 REM 組込み関数は,SIN,COS,TAN, LOG, EXP, SQR, INT,ABSとPIのみ
1040 REM 大文字と小文字の区別はしない
1050 REM 数値式の文法はほぼFull BASICに準ずるが,関数名に続く括弧は空白を入れずに書く。
1060 REM 数値は,数字で始まり,コンマを1個以下含む数字の列としてのみ書ける。
1070 REM 零除算エラーなどは考慮していない。
1080 DECLARE EXTERNAL FUNCTION interpreter.expression ! 数値式を評価する関数
1090 DECLARE EXTERNAL STRING interpreter.s$ ! 入力行
1100 DECLARE EXTERNAL NUMERIC interpreter.i ! 入力行の文字位置
1110 DECLARE EXTERNAL SUB interpreter.skip ! 空白文字を読み飛ばす副プログラム
DECLARE EXTERNAL FUNCTION interpreter.str_expression$ !文字列式を評価する関数
DECLARE EXTERNAL NUMERIC interpreter.vc,interpreter.sc !変数の個数(vc=数値,sc=文字列)
DECLARE EXTERNAL SUB interpreter.error !エラーメッセージ
1120 LINE INPUT s$
1130 ! LET s$=UCASE$(s$) !文字列の小文字保持のため無効にした
DO
LET vc,sc=0
1140 LET i=1
1150 CALL skip
IF s$(i:i)="$" THEN
LET i=i+1
CALL skip
IF s$(i:i)="=" THEN
LET i=i+1
CALL skip
PRINT str_expression$ ! 文字列式評価
ELSE
CALL error("$=")
END IF
ELSE
1160 PRINT expression ! 数値式評価
END IF
1170 IF i<>LEN(s$)+1 THEN PRINT "Syntax error" ! 比較式をi<LEN(s$)から変更
LOOP UNTIL vc+sc=0 OR i<>LEN(s$)+1 ! 中止は[中止]ボタンで
1180 END
1190 !
1200 MODULE interpreter
! MODULE OPTION ARITHMETIC NATIVE ! DECIMAL_HIGH,COMPLEX,RATIONAL 数値オプション
1210 PUBLIC STRING s$
1220 PUBLIC NUMERIC i
1230 PUBLIC FUNCTION expression
1240 PUBLIC SUB skip
1250 SHARE FUNCTION term,factor,primary,numeric
PUBLIC FUNCTION str_expression$
PUBLIC NUMERIC vc,sc
PUBLIC SUB error
SHARE FUNCTION check,argument,rounding,position,bitval,v_chr,variable
SHARE FUNCTION str_primary$,str_constant$,str_naming$,sub_string$,str_input$,bitstr$
SHARE NUMERIC vari_val(20),inputv ! 20=変数の個数
SHARE STRING sn$,vari_name$(20),string$(20),str_name$(20)
SHARE FUNCTION F1,F2,F3,FS$ !!! ユーザー定義関数
! MODULE OPTION ANGLE DEGREES ! 角の大きさの単位
! MODULE OPTION CHARACTER BYTE ! 文字列処理の単位
LET inputv=0
1260 !
EXTERNAL FUNCTION F1(a) !!! ユーザー定義関数
let F1=a
END FUNCTION
EXTERNAL FUNCTION F2(a,b) !!! ユーザー定義関数
let F2=a+b
END FUNCTION
EXTERNAL FUNCTION F3(a,b,c) !!! ユーザー定義関数
let F3=a+b+c
END FUNCTION
EXTERNAL FUNCTION FS$(a$,b,c) !!! ユーザー定義関数
let FS$=a$&str$(b)&str$(c)
END FUNCTION
!
1270 EXTERNAL SUB skip
1280 DO WHILE s$(i:i)=" "
1290 LET i=i+1
1300 LOOP
1310 END SUB
1320 !
1330 EXTERNAL FUNCTION expression
1340 DECLARE NUMERIC n
1350 DECLARE STRING op$
1360 SELECT CASE s$(i:i)
1370 CASE "-"
1380 LET i=i+1
1390 CALL skip
1400 LET n=-term
1410 CASE "+"
1420 LET i=i+1
1430 CALL skip
1440 LET n=term
1450 CASE ELSE
1460 LET n=term
1470 END SELECT
1480 DO WHILE s$(i:i)="+" OR s$(i:i)="-"
1490 LET op$=s$(i:i)
1500 LET i=i+1
1510 CALL skip
1520 IF op$="+" THEN LET n=n+term ELSE LET n=n-term
1530 LOOP
1540 LET expression =n
1550 CALL skip
1560 END FUNCTION
1570 !
1580 EXTERNAL FUNCTION term
1590 DECLARE NUMERIC n
1600 DECLARE STRING op$
1610 LET n=factor
1620 DO WHILE s$(i:i)="*" OR s$(i:i)="/"
1630 LET op$=s$(i:i)
1640 LET i=i+1
1650 CALL skip
1660 IF op$="*" THEN LET n=n*factor ELSE LET n=n/factor
1670 LOOP
1680 LET term=n
1690 END FUNCTION
1700 !
1710 EXTERNAL FUNCTION factor
1720 DECLARE NUMERIC n
1730 LET n=primary
1740 DO WHILE s$(i:i)="^"
1750 LET i=i+1
1760 CALL skip
1770 LET n=n^primary
1780 LOOP
1790 LET factor=n
1800 END FUNCTION
1810 !
1820 EXTERNAL FUNCTION primary
1830 IF s$(i:i)>="0" AND s$(i:i)<="9" THEN
1840 LET primary=numeric
ELSEIF s$(i:i)="." THEN
LET primary=numeric
1850 ELSEIF UCASE$(s$(i:i+1))="PI" AND check(s$(i+2:i+2))=1 THEN ! 関数check加筆
1860 LET i=i+2
1870 CALL skip
1880 LET primary=PI ! 有理数モード注意
ELSEIF UCASE$(s$(i:i+2))="RND" AND check(s$(i+3:i+3))=1 THEN
LET i=i+3
CALL skip
LET primary=RND ! 変数入力がある数値式では都度更新
ELSEIF UCASE$(s$(i:i+3))="TIME" AND check(s$(i+4:i+4))=1 THEN
LET i=i+4
CALL skip
LET primary=TIME ! 変数入力がある数値式では都度更新
ELSEIF UCASE$(s$(i:i+3))="DATE" AND check(s$(i+4:i+4))=1 THEN
LET i=i+4
CALL skip
LET primary=DATE ! 変数入力がある数値式では都度更新
!ELSEIF UCASE$(s$(i:i+5))="MAXNUM" AND check(s$(i+6:i+6))=1 THEN
! LET i=i+6
! CALL skip
! LET primary=MAXNUM ! 有理数モード不可
1890 ELSE
1900 IF s$(i:i)="(" THEN
1910 LET i=i+1
1920 CALL skip
1930 LET primary=expression
ELSEIF UCASE$(s$(i:i+2))="F1(" THEN !!! ユーザー定義関数
LET i=i+3
CALL skip
LET Primary=F1(expression)
ELSEIF UCASE$(s$(i:i+2))="F2(" THEN !!! ユーザー定義関数
LET i=i+3
CALL skip
LET primary=F2(expression,argument)
ELSEIF UCASE$(s$(i:i+2))="F3(" THEN !!! ユーザー定義関数
LET i=i+3
CALL skip
LET primary=F3(expression,argument,argument)
1940 ELSEIF UCASE$(s$(i:i+3))="SIN(" THEN ! 超越関数
1950 LET i=i+4
1960 CALL skip
1970 LET Primary=SIN(expression)
1980 ELSEIF UCASE$(s$(i:i+3))="COS(" THEN ! 超越関数
1990 LET i=i+4
2000 CALL skip
2010 LET Primary=COS(expression)
2020 ELSEIF UCASE$(s$(i:i+3))="TAN(" THEN ! 超越関数
2030 LET i=i+4
2040 CALL skip
2050 LET Primary=TAN(expression)
2060 ELSEIF UCASE$(s$(i:i+3))="LOG(" THEN ! 超越関数
2070 LET i=i+4
2080 CALL skip
2090 LET Primary=LOG(expression)
2100 ELSEIF UCASE$(s$(i:i+3))="EXP(" THEN ! 超越関数
2110 LET i=i+4
2120 CALL skip
2130 LET Primary=EXP(expression)
2140 ELSEIF UCASE$(s$(i:i+3))="SQR(" THEN ! 有理数モード注意
2150 LET i=i+4
2160 CALL skip
2170 LET Primary=SQR(expression)
2180 ELSEIF UCASE$(s$(i:i+3))="INT(" THEN
2190 LET i=i+4
2200 CALL skip
2210 LET Primary=INT(expression)
2220 ELSEIF UCASE$(s$(i:i+3))="ABS(" THEN
2230 LET i=i+4
2240 CALL skip
2250 LET Primary=ABS(expression)
ELSEIF UCASE$(s$(i:i+3))="MOD(" THEN
LET i=i+4
CALL skip
LET primary=MOD(expression,argument)
ELSEIF UCASE$(s$(i:i+5))="ROUND(" THEN
LET i=i+6
CALL skip
LET primary=rounding
ELSEIF UCASE$(s$(i:i+4))="CEIL(" THEN
LET i=i+5
CALL skip
LET Primary=CEIL(expression)
ELSEIF UCASE$(s$(i:i+3))="SGN(" THEN
LET i=i+4
CALL skip
LET Primary=SGN(expression)
ELSEIF UCASE$(s$(i:i+2))="IP(" THEN
LET i=i+3
CALL skip
LET Primary=IP(expression)
ELSEIF UCASE$(s$(i:i+2))="FP(" THEN
LET i=i+3
CALL skip
LET Primary=FP(expression)
ELSEIF UCASE$(s$(i:i+9))="REMAINDER(" THEN
LET i=i+10
CALL skip
LET primary=REMAINDER(expression,argument)
ELSEIF UCASE$(s$(i:i+8))="TRUNCATE(" THEN
LET i=i+9
CALL skip
LET primary=TRUNCATE(expression,argument)
ELSEIF UCASE$(s$(i:i+4))="LOG2(" THEN ! 超越関数
LET i=i+5
CALL skip
LET Primary=LOG2(expression)
ELSEIF UCASE$(s$(i:i+5))="LOG10(" THEN ! 超越関数
LET i=i+6
CALL skip
LET Primary=LOG10(expression)
ELSEIF UCASE$(s$(i:i+3))="CSC(" THEN ! 超越関数
LET i=i+4
CALL skip
LET Primary=CSC(expression)
ELSEIF UCASE$(s$(i:i+3))="SEC(" THEN ! 超越関数
LET i=i+4
CALL skip
LET Primary=SEC(expression)
ELSEIF UCASE$(s$(i:i+3))="COT(" THEN ! 超越関数
LET i=i+4
CALL skip
LET Primary=COT(expression)
ELSEIF UCASE$(s$(i:i+4))="ASIN(" THEN ! 超越関数
LET i=i+5
CALL skip
LET Primary=ASIN(expression)
ELSEIF UCASE$(s$(i:i+4))="ACOS(" THEN ! 超越関数
LET i=i+5
CALL skip
LET Primary=ACOS(expression)
ELSEIF UCASE$(s$(i:i+3))="ATN(" THEN ! 超越関数
LET i=i+4
CALL skip
LET Primary=ATN(expression)
ELSEIF UCASE$(s$(i:i+5))="ANGLE(" THEN ! 超越関数
LET i=i+6
CALL skip
LET primary=ANGLE(expression,argument)
ELSEIF UCASE$(s$(i:i+4))="SINH(" THEN ! 超越関数
LET i=i+5
CALL skip
LET Primary=SINH(expression)
ELSEIF UCASE$(s$(i:i+4))="COSH(" THEN ! 超越関数
LET i=i+5
CALL skip
LET Primary=COSH(expression)
ELSEIF UCASE$(s$(i:i+4))="TANH(" THEN ! 超越関数
LET i=i+5
CALL skip
LET Primary=TANH(expression)
!ELSEIF UCASE$(s$(i:i+3))="EPS(" THEN ! 有理数モード不可
! LET i=i+4
! CALL skip
! LET Primary=EPS(expression)
ELSEIF UCASE$(s$(i:i+3))="DEG(" THEN
LET i=i+4
CALL skip
LET Primary=DEG(expression)
ELSEIF UCASE$(s$(i:i+3))="RAD(" THEN
LET i=i+4
CALL skip
LET Primary=RAD(expression)
ELSEIF UCASE$(s$(i:i+3))="MAX(" THEN
LET i=i+4
CALL skip
LET primary=MAX(expression,argument)
ELSEIF UCASE$(s$(i:i+3))="MIN(" THEN
LET i=i+4
CALL skip
LET primary=MIN(expression,argument)
ELSEIF UCASE$(s$(i:i+4))="FACT(" THEN !十進BASIC独自拡張
LET i=i+5
CALL skip
LET Primary=FACT(expression)
ELSEIF UCASE$(s$(i:i+4))="PERM(" THEN !十進BASIC独自拡張
LET i=i+5
CALL skip
LET primary=PERM(expression,argument)
ELSEIF UCASE$(s$(i:i+4))="COMB(" THEN !十進BASIC独自拡張
LET i=i+5
CALL skip
LET primary=COMB(expression,argument)
ELSEIF UCASE$(s$(i:i+10))="COLORINDEX(" THEN !十進BASIC独自拡張
LET i=i+11
CALL skip
LET primary=COLORINDEX(expression,argument,argument)
!ELSEIF UCASE$(s$(i:i+7))="COMPLEX(" THEN !複素関数
! LET i=i+8
! CALL skip
! LET primary=COMPLEX(expression,argument)
!ELSEIF UCASE$(s$(i:i+2))="RE(" THEN !複素関数
! LET i=i+3
! CALL skip
! LET Primary=RE(expression)
!ELSEIF UCASE$(s$(i:i+2))="IM(" THEN !複素関数
! LET i=i+3
! CALL skip
! LET Primary=IM(expression)
!ELSEIF UCASE$(s$(i:i+4))="CONJ(" THEN !複素関数
! LET i=i+5
! CALL skip
! LET Primary=CONJ(expression)
!ELSEIF UCASE$(s$(i:i+3))="ARG(" THEN !複素関数
! LET i=i+4
! CALL skip
! LET Primary=ARG(expression)
!ELSEIF UCASE$(s$(i:i+5))="NUMER(" THEN !有理数モード専用
! LET i=i+6
! CALL skip
! LET Primary=NUMER(expression)
!ELSEIF UCASE$(s$(i:i+5))="DENOM(" THEN !有理数モード専用
! LET i=i+6
! CALL skip
! LET Primary=DENOM(expression)
!ELSEIF UCASE$(s$(i:i+3))="GCD(" THEN !有理数モード専用
! LET i=i+4
! CALL skip
! LET primary=GCD(expression,argument)
!ELSEIF UCASE$(s$(i:i+6))="INTSQR(" THEN !有理数モード専用
! LET i=i+7
! CALL skip
! LET Primary=INTSQR(expression)
!ELSEIF UCASE$(s$(i:i+7))="INTLOG2(" THEN !有理数モード専用
! LET i=i+8
! CALL skip
! LET Primary=INTLOG2(expression)
ELSEIF UCASE$(s$(i:i+3))="LEN(" THEN
LET i=i+4
CALL skip
LET primary=LEN(str_expression$)
ELSEIF UCASE$(s$(i:i+3))="POS(" THEN
LET i=i+4
CALL skip
LET primary=position
ELSEIF UCASE$(s$(i:i+3))="VAL(" THEN
LET i=i+4
CALL skip
LET primary=VAL(str_expression$)
ELSEIF UCASE$(s$(i:i+3))="ORD(" THEN
LET i=i+4
CALL skip
LET primary=ORD(str_expression$)
ELSEIF UCASE$(s$(i:i+4))="BVAL(" THEN
LET i=i+5
CALL skip
LET primary=bitval
ELSEIF UCASE$(s$(i:i+4))="BLEN(" THEN !十進BASIC独自拡張
LET i=i+5
CALL skip
LET primary=BLEN(str_expression$)
ELSEIF v_chr(s$(i:i))=1 THEN
LET primary=variable ! 変数
CALL skip
EXIT FUNCTION
2260 ELSE
CALL error("FUNCTION primary")
2270 PRINT "Syntax error"
2280 STOP
2290 END IF
2300 IF s$(i:i)=")" THEN
2310 LET i=i+1
2320 CALL skip
2330 ELSE
CALL error("FUNCTION primary")
2340 PRINT "Syntax error"
2350 STOP
2360 END IF
2370 END IF
2380 END FUNCTION
2390 !
2400 EXTERNAL FUNCTION numeric
2410 DECLARE NUMERIC i0
2420 CALL skip
2430 LET i0=i
IF s$(i:i)="." THEN ! 小数点で始まる
LET i=i+1
ELSE
2440 DO WHILE s$(i:i)>="0" AND s$(i:i)<="9"
2450 LET i=i+1
2460 LOOP
2470 IF s$(i:i)="." THEN LET i=i+1
END IF
2480 DO WHILE s$(i:i)>="0" AND s$(i:i)<="9"
2490 LET i=i+1
2500 LOOP
IF LEN(s$)>=i AND UCASE$(s$(i:i))="E" THEN ! 指数部
LET i=i+1
IF s$(i:i)="+" OR s$(i:i)="-" THEN LET i=i+1
DO WHILE s$(i:i)>="0" AND s$(i:i)<="9"
LET i=i+1
LOOP
END IF
2510 LET numeric=VAL(s$(i0:i-1))
2520 CALL skip
2530 END FUNCTION
2540 !
![その2]へ続く