● リファレンス
single character memory
半角カタカナの一文字を使ってメモリを表現する機能です。
例.
ア + 12 - ニ
次の文字を使用する事ができます。
ア イ ウ エ オ カ キ ク ケ コ サ シ ス セ ソ タ チ ツ テ ト ナ ニ ヌ ネ ノ
ハ ヒ フ ヘ ホ マ ミ ム メ モ ヤ ユ ヨ ラ リ ル レ ロ ワ ン
'ア' 〜 'ン'(0xb1 〜 0xdd)の 45 文字に割り当てられています。
実装
STRCALC_PARAM 構造体のメンバ pmem にメモリの実体の先頭アドレスを設定します。また、有効にするメモリ要素数を memmax に設定します。
例.全てのメモリを使用する場合
STRCALC_PARAM prm;
double scm[45] = {0}; ← 45 要素が最大
・
・
・
(StrCalc_init 実行後)
prm.pmem = scm;
prm.memmax = sizeof(scm) / sizeof(double);
memmax を 45 よりも小さくすると、範囲を狭める事ができます。
計算式上の半角カタカナが 0 〜 memmax の範囲を超えている場合、STATUS_SCMEMORY_RANGEOVER を返します。例えば、memmax = 5 の場合、'ア' 〜 'オ' の変数が有効になり、その状態で 'カ' 〜 'ン' を指定するとエラーが返されます。
値のセット
StrCalc には single character memory に値をセットする機能は無く、アプリケーションが独自にセットしなければなりません。
代入式の左辺にも指定できません。
無効にする
single character memory を使用しない場合は、メンバpmem に NULL をセットするか、memmax に 0 以下の値をセットします(通常は 0 )。無効にした状態で、計算式に半角カタカナを記述すると STATUS_SCMEMORY_NOTREADY を返します。
関数StrCalc_init を実行した直後は、NULL と 0 がセットされています(デフォルトでは無効状態)。
利点
- メモリの実体が StrCalc の直接の管理下には無いため、変数の場合のような手続きを取らなくとも、複数のメモリ集合体を簡単に切り替えて使用する事ができます(ポインタと最大要素数を替えるだけ)。
- メモリ表現が半角カタカナ一文字だけなので、計算式の文字列操作が容易です。
- 名前の比較や環境内の検索が発生しないため、StrCalc が持つ変数管理よりも高速に処理されます。
この機能は、仮引数を持つ計算式を処理するような場合等、アプリケーションが内部処理に利用する事を想定して用意されています。
そのため、操作上の使い易さまでは考慮されていません。直感的に理解し難い表現であり、エンドユーザが誤用する可能性があるので、通常の用途ではアプリケーションのみが利用するようにした方が良いでしょう。
|
ユーザ定義関数例.
/*
関数名は任意です。引数は 3 つ。
登録時に、呼び出し元の STRCALC_PARAM 情報を追加情報として渡します。
*/
double __stdcall user_func(
double *arg,
int argcnt,
int *pret,
PSTRCALC_PARAM pcur)
{
/*
呼び出し元情報をそのまま使う事はできないので、ローカルにコピーして
使用します(「コールバック関数MFUNC」の「注意点」参照の事)。
*/
STRCALC_PARAM prm = *pcur;
/*
引数1 、引数2 、引数3 が ア 、イ 、ウ に対応する事になります。
引数が格納されているテーブルは、関数が呼び出される度に確保されるので、
再帰的な計算を行わせる事も可能です。ただし、その場合は終了条件に注意
してください。
*/
prm.str = "tan(ア) * イ - 9.80665 * イ^2 / (2 * ウ^2 * cos(ア)^2)";
prm.pmem = arg;
prm.memmax = argcnt;
*pret = StrCalc(&prm);
return prm.ans;
}
基本的な事ですが、直にメモリ表現の操作を行う場合は、コード範囲が 0xb1 〜 0xdd になる点に留意してください。char 型で扱うと、符号拡張された時に問題が発生する場合があります。
|
テスト.single character memory の代入式処理
#include <ctype.h>
#include "sc39.h"
#define MEM_START 0xb1 /* ア */
#define MEM_END 0xdd /* ン */
#define MEM_MAX (MEM_END - MEM_START + 1)
int StrCalc_substitution_SCM(PSTRCALC_PARAM prm,char *ptr,int btemp)
{
int c,ret;
while(isspace(*ptr)) /* 先頭側の空白を飛ばす */
ptr++;
/*
最初の文字が 0xb1 よりも小さい場合は
標準の代入式処理関数を呼び出す
*/
if ((c = *(unsigned char *)ptr) < MEM_START)
return StrCalc_substitution(prm,ptr,btemp,0,0,0);
/* 次の文字がイコールであるか調べる */
do{
ptr++;
}while(isspace(*ptr));
if (*ptr != '=')
return STATUS_NEED_EQUAL;
/* single character memory が使用禁止であるか調べる */
if (!prm->pmem || prm->memmax <= 0)
return STATUS_SCMEMORY_NOTREADY;
/* インデックスが最大範囲を超えているか調べる */
if ((c -= MEM_START) > MEM_MAX || c >= prm->memmax)
return STATUS_SCMEMORY_RANGEOVER;
/* 右辺の計算とメモリへの代入 */
prm->str = ptr + 1;
if ((ret = StrCalc(prm)) != STATUS_NORMAL)
return ret;
prm->pmem[c] = prm->ans;
return STATUS_NORMAL;
}
#include <stdio.h>
void main(void)
{
STRCALC_PARAM prm;
double mem[5] = {0};
char *pstr;
int ret;
if (!StrCalc_init(&prm)){
printf("init err.\n");
return;
}
prm.pmem = mem;
prm.memmax = sizeof(mem) / sizeof(double);
pstr = " オ = 1+2+3+4+5";
ret = StrCalc_substitution_SCM(&prm,pstr,0);
StrCalc_term(&prm);
if (ret != STATUS_NORMAL)
printf("err.%d\n",ret);
else
printf("%.16G\n",mem['オ' - 'ア']);
}
テストプログラム ソースファイル(zip)