お知らせ

電子会議

ライブラリ

パレット

Delphi FAQ検索

Delphi FAQ一覧

サンプル蔵





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

"式の解釈と計算(1/2)"



 

 こんにちは。
 いつも FDELPHI に助けてもらっている見習いプログラマ(46歳)です。
 ご恩返しにと思い、昨年2Wででっちあげた計算ルーチンをアップします。

 高速化・高機能化・高精度化などいくつも課題がありますが、みなさんの
参考になれば幸いです。

-----------------------------------------------------------------------------
unit Calcp;

// 式の解釈と演算を行う逆ポーランド式計算ルーチン
// 式及び答えは文字列とする
// 注意:有効桁は16進4桁に限定しているがもちろん変更可

// 使い方の例
{
var Ans, Exp: String;
begin
  WorkList   := TStringList.Create;
  TokenList  := TStringList.Create;
  SymbolList := TStringList.Create;

  SymbolList.Add('x:0001'); // xは 1(16進数表記)
  SymbolList.Add('y:000F'); // yは15(16進数表記)

  Exp := '(x+y)*(x-y)+$10'; // 式
  Ans := IntToStr(HexToInt(Calc(Exp))); // 答えを10進文字列に変換
  ShowMessage(Ans);

  WorkList.Free;
  TokenList.Free;
  SymbolList.Free;
end;
}

// 数値    :10進数、先頭が$なら16進数
//           演算の答えは16進数の文字列である
// シンボル:シンボルリストに定義すれば使用可能
// 演算子  :算術 +、−、*、/、MOD
//           論理 AND、OR、XOR
//           シフト  SHR、SHL
//           単項 +、−、NOT、
//                HIGH、LOW(それぞれ2バイトの上位下位バイト)
//           他   (、)
// 優先順位は考慮していないので、括弧を活用して明示すること

// Factor・Term・Expression ルーチンは
// 中田育男著オーム社「コンパイラ」の同名ルーチン(C言語)を
// 参考にしました

// Push・Pop・Calculation ルーチンは
// SBORLAND ライブラリ2-59 EasyCalc(Oh!NO!さん)を参考にしました

interface

uses Classes, Dialogs, SysUtils;

const
  InValidValue = 99999;
  calcFault    = '演算不能';
  UnDefined    = '未定義';

function  Calc(s: String): String;
function  HexToInt(s: String): Integer;
procedure Expression;

var
  Index     : Integer;
  StackPtr  : Integer;
  NewSelect : Boolean;
  token     : String;
  IntStack  : array[0..99] of String;
  WorkList  : TStringList;
  TokenList : TStringList;
  SymbolList: TStringList;
// SymbolTextの内容は
// 名前文字列:16進4桁文字列
// の並びとしてください
// ':'が名前と数値文字列との区分文字となります

implementation

// 16進数文字列→整数
function HexToInt(s: String): Integer;
begin
  Result := StrToInt('$'+s);
end;

// 文字列は数値か
function IsNumber(s: String): Boolean;
begin
  if StrToIntDef(s, InValidValue) <> InValidValue then Result := True
  else                                                 Result := False;
end;

// 文字列をスタックへ積む
procedure Push(s: String);
begin
  IntStack[StackPtr] := s;
  Inc(StackPtr);
end;

// スタックから文字列を取り出す
function Pop: String;
begin
  Dec(StackPtr);
  Result := IntStack[StackPtr];
end;

// シンボル定義リストから文字列(シンボル)に一致するものを探して
// 16進数値文字列を返す
function GetVal(s: String): String;
var i: Integer; str: String;
begin
  Result := UnDefined;

  for i := 0 to SymbolList.Count-1 do
  begin
    str := AnsiUpperCase(SymbolList[i]);

    if s = Copy(str, 1, AnsiPos(':', str)-1) then
    begin
      Result := Copy(str, AnsiPos(':', str)+1, 4);
      Break;
    end;
  end;
end;

// トークンリストから次のトークンを取り出す
function NextToken: String;
begin
  Result := '';

  if Index < TokenList.Count then
  begin
    Result := TokenList[Index];
    Inc(Index);
  end;
end;

// 式の因子のコンパイル
procedure Factor;
begin
  if (token <> '+')   and (token <> '-')   and (token <> '*')   and
     (token <> '/')   and (token <> '(')   and (token <> ')')   and
     (token <> 'MOD') and (token <> 'SHR') and (token <> 'SHL') and
     (token <> 'AND') and (token <> 'OR')  and (token <> 'XOR') and
     (not IsNumber(token)) then // シンボル
  begin
    WorkList.Add(GetVal(token));
    token := NextToken;
  end
  else
  begin
    if IsNumber(token) then
    begin     // 定数
      WorkList.Add(IntToHex(StrToInt(token), 4));
      token := NextToken;
    end
    else
      if token = '(' then
      begin   // 「(」「因子」「)」
        token := NextToken;
        Expression;
        if token = ')' then token := NextToken;
      end;
  end;
end;

// 式の項のコンパイル
procedure Term;
var k: String;
begin
  Factor;

  k := token;
  while (k = '*')   or (k = '/')   or
        (k = 'MOD') or (k = 'SHR') or (k = 'SHL') or
        (k = 'AND') or (k = 'OR')  or (k = 'XOR') do
  begin
    token := NextToken;
    Factor;
    if k = '*'   then WorkList.Add('MUL_')
    else
    if k = '/'   then WorkList.Add('DIV_')
    else
    if k = 'MOD' then WorkList.Add('MOD_')
    else
    if k = 'SHR' then WorkList.Add('SHR_')
    else
    if k = 'SHL' then WorkList.Add('SHL_')
    else
    if k = 'AND' then WorkList.Add('AND_')
    else
    if k = 'OR'  then WorkList.Add('OR__')
    else
    if k = 'XOR' then WorkList.Add('XOR_');

    k := token;
  end;
end;


Original document by TAK8            氏 ID:(QYR01421)


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

Copyright 1996-2002 Delphi Users' Forum