お知らせ

電子会議

ライブラリ

パレット

Delphi FAQ検索

Delphi FAQ一覧

サンプル蔵





FDelphi FAQ
16番会議室「玉石混淆みんなで作るSample蔵」に寄せられたサンプル

"eval:関数電卓つきグリッド(300行)"

この発言に対し以下のコメントが寄せられています
#00562 熊谷秀武 さん RE:eval:関数電卓つきグリッド(300行)
#00566 熊谷秀武 さん RE:eval:関数電卓つきグリッド(300行)

 Eval 〜 関数電卓付きグリッド    比較的コンパクトな eval (数式の文字列を計算して数値を返す関数)が出 来たので公開します。  累乗(^)・四則演算、カッコ、数学関数(int,sin、log など)、変数 (A..Z) が使えます。 演算子の優先順位は、「^」累乗>「*,/,%」>「+,-」> 「=」 です。  空文字列を与えると0を返します。カッコの中が空の場合にも0を返す。  −−  静的項目を作って、OnSetText イベントに次のように記述すると関数電卓付 きのDBグリッドやDBエディットになります。 procedure TForm1.Table1MIN_SALARYSetText(Sender: TField; const Text: String); begin TField(Sender).asInteger := round(eval(text)); end;  −−  制限:  変数は A から Z の半角1文字だけです。Eval_Variables[ 'X' ]で他から でも参照できます。  関数の引数の数は1つか0だけです。2個以上の引数のある関数は定義でき ません。  デルファイ1な人間なのでデルファイ2以降への対応と、バグ情報をお願い します。  −− const Eval_VarNames = ['A'..'Z'] ; var Eval_Variables : array[ 'A'..'Z' ] of extended; function Eval( const S:string ):extended; type TFnc = ( fncNul , fncATan , fncAbs , fncCos , fncExp , fncFrac , fncInt , fncLn , fncLog , fncPi , fncSin , fncTan ); var p:integer; function getVal:extended;forward; procedure EvalError( const msg:string ); begin raise exception.create( copy(s,1,p)+' <-err:'+Msg+' '+copy(S,p+1,255) ); end; function Power( v1,v2:extended ):extended; var a1:extended; begin if v1 = 0 then begin result := 0 ; exit ; end; { 93-03-25 } if v2 = 0 then begin result := 1 ; exit ; end; { 93-03-25 } a1 := Ln(abs(v1)) * v2; (* a1:は答えのlog *) if ( v1 < 0 ) (* 被累乗数がマイナスのとき *) and ( trunc(v2) <> v2 ) (* 整数でないときは *) then EvalError('マイナスの非整数乗'); a1 := Exp(a1); (* a1:は答えの絶対値 *) if ( v1 < 0 ) (* 被累乗数がマイナスで *) and ( odd(trunc(v2)) ) (* 奇数乗なら *) then a1 := -a1; (* 答えはマイナス *) result := a1; end; function calc( val1:extended ; op:char ; val2:extended ):extended; begin case op of '+' : result := val1 + val2; '-' : result := val1 - val2; '*' : result := val1 * val2; '/' : if val2 = 0 then EvalError('割る数が0') else result := val1 / val2; '%' : result := trunc(val1) mod trunc(val2); '^' : result := power( val1 , val2 ); else EvalError('知らない演算子'); end; { case } end; procedure skipSpace; begin while ( p <= length(S) ) and ( s[p] <= ' ' ) do inc(p); end; function OpPriority( op:char ):integer; begin {00 1 112223334} result := pos( op , 'xx'+#0+')=+--*/%^' ) div 3; end; function isOP( op:char ):boolean; begin result := ( OpPriority( op ) > 0 ); end; function getOP:char; begin skipSpace; if p > length(S) then result := #0 else result := s[p]; if not isOP( result ) then EvalError('演算子でない'); if not ( result in [ #0 , ')' ] ) then inc(p); end; function isFunc( var fnc:TFnc ):boolean; const MaxNameLen = length('ARCTAN')+1; var tmp:string; kakko:integer; begin result := false; tmp := UpperCase(copy(s,p, MaxNameLen )); kakko := pos( '(' , tmp ); if ( kakko = 0 ) then exit; tmp := upperCase(copy(tmp,1,kakko-1)); if tmp = '' then fnc := fncNul else if tmp = 'INT' then fnc := fncInt else if tmp = 'SIN' then fnc := fncSin else if tmp = 'COS' then fnc := fncCos else if tmp = 'TAN' then fnc := fncTan else if tmp = 'ARCTAN' then fnc := fncATan else if tmp = 'EXP' then fnc := fncExp else if tmp = 'LN' then fnc := fncLn else if tmp = 'LOG' then fnc := fncLog else if tmp = 'ABS' then fnc := fncAbs else if tmp = 'FRAC' then fnc := fncFrac else if tmp = 'PI' then fnc := fncPi else exit; { else exit now } inc(p,length(tmp)+1); result := true; end; function isVar( var index:char ):boolean; var c:char; begin result := true; c := upCase(s[p]); if ( c in Eval_VarNames ) and ( ( p >= length(s) ) or ( not ( upcase(s[p+1]) in Eval_VarNames )) ) then index := c else result := false; end; function getNum:extended; var Minus:boolean; Start:integer; tmp:string; func:tFnc; tmpVar:char; begin Minus := false; skipSpace; if ( p > length(s)) or ( s[p] = ')' ) then begin result := 0 ; exit; end; if ( p <= length(s)) and ( s[p] in [ '-','+' ] ) then begin if ( s[p] in [ '-' ] ) then Minus := true; inc(p); skipSpace; end; if isVar( tmpVar ) then begin inc(p); result := Eval_Variables[ tmpVar ] ; end else if isFunc( func ) then begin result := getVal; if getOP <> ')' then EvalError('終わりのカッコがない') else inc(p); case func of fncNul : ; { '(' } fncInt : result := int(result); fncSin : result := sin(result); fnccos : result := cos(result); fncTan : if ( abs(cos(result)) < 0.000000001 ) then EvalError('無限大になる') else result := sin(result) / cos(result); fncAtan : result := arcTan(result); fncExp : result := Exp(result); fncLn : result := ln(result); fncLog : result := ln(result) / ln(10); fncAbs : result := abs(result); fncFrac : result := frac(result); fncPi : result := pi; else EvalError('知らない関数'); end; end else begin Start := p; if ( p <= length(s)) and ( s[p] in [ '$'] ) then inc(p); while ( p <= length(s)) and ( s[p] in [ '0'..'9' , '.' ] ) do inc(p); if ( p=Start ) then EvalError('数?'); tmp := copy( s , start , p-Start ); if ( pos( '$' , tmp ) <> 0 ) then result := StrToInt( tmp ) else result := StrToFloat( tmp ); end; if Minus then result := -result; end; function getVal:extended; label getVal2,getOp2,testOp2,GetOP3,setVar; var val1,val2,val3,val4:extended; op1,op2,op3:char; dstVar,tmpVar:char; begin result := 0; dstVar := #0; tmpVar := #0; isVar( tmpVar ); val1 := getNum; op1 := getOP; if op1 = '=' then begin dstVar := tmpVar; if dstVar = #0 then EvalError('左辺に変数がない'); val1 := getNum; op1 := getOP; end; if op1 in [ #0,')' ] then begin result := val1; goto setVar; end; getVal2: val2 := getNum; getOp2: op2 := getOP; testOp2: if op2 in [ #0,')' ] then begin result := calc( val1 , op1 , val2 ); goto setVar; end; { v1 o1 v2 o2 v3 o3 v4 } { v1 o1 v2 o2 v3 o3 v4 } { 1 + 2 + 3 * 4 } { 3 + 3 * 4 } { 1 * 2 + 3 + 4 } { 2 + 3 + 4 } if ( opPriority(op1) >= opPriority(op2) ) then begin val1 := calc( val1 , op1 , val2 ); op1 := op2; goto getVal2; end; val3 := getNum; getOP3: op3 := getOP; { v1 o1 v2 o2 v3 o3 v4 } { v1 o1 v2 o2 v3 o3 v4 } { 1 + 2 ^ 3 * 4 } { 1 + 8 * 4 } { 1 * 2 ^ 3 + 4 } { 1 * 8 + 4 } if ( opPriority(op2) >= opPriority(op3) ) then begin val2 := calc( val2 , op2 , val3 ); op2 := op3; goto testOp2; end; { v1 o1 v2 o2 v3 o3 v4 } { 1 + 2 * 3 ^ 4 * 5 } val4 := getNum; val3 := calc( val3 , op3 , val4 ); goto getop3; setVar: if dstVar in Eval_VarNames then Eval_Variables[ dstVar ] := result; end; begin { Evel 関数の本体 } p := 1; result := getVal; if getOP <> #0 then EvalError('カッコが多すぎる'); end; 98/6/11(Thu) GGB03124 熊谷秀武 Original document by 熊谷秀武 氏 ID:(GGB03124)



ここにあるドキュメントは NIFTY SERVEの Delphi Users' Forum の16番会議室「玉石混淆みんなで作るSample蔵」に投稿されたサンプルです。これらのサンプルはボーランド株式会社がサポートする公式のものではありません。また、必ずしも動作が検証されているものではありません。これらのサンプルを使用したことに起因するいかなる損害も投稿者、およびフォーラムスタッフはその責めを負いません。使用者のリスクの範疇でご使用下さい。

Copyright 1996-2002 Delphi Users' Forum