/*	
 *	clipexpr.h
 *
 *	操車場アルゴリズム(改良版)
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2016 Naoyuki Sawa
 *
 *	* Fri Jun 24 21:38:01 JST 2016 Naoyuki Sawa
 *	- 1stリリース。
 *	- 基本的には既存のclipshya.cモジュールの動作と同じですが、以下の点を改良しました。
 *	  ・clipshya.cのShuntingYard()は、入力キュー,出力キュー,スタックを個別に設けていました。
 *	    それに対して、clipexpr.cのexprsort()は、入力キューをそのまま出力キュー,及び,スタックとしても使用します。
 *	    これによって、作業用メモリの消費量が低減しました。
 *	  ・ShuntingYard()は、トークンを(int)で表す事しか出来ませんでした。
 *	    exprsort()は、任意のバイト数のデータで、トークンを表せるようになりました。
 *	  ・ShuntingYard()は、入力キューの終端を0で示していました。
 *	    exprsort()は、入力キューの要素数を、明示的に引数で示すようになりました。
 *	  ・以上の改良に伴い、exprsort()の引数形式は、qsort()等のソート関数に近いものとなりました。
 *	    実際の所、操車場アルゴリズムは一種のソートと見なせますので、関数仕様が判り易くなったと思います。
 *	  ・ShuntingYard()が内包していたバグを、exprsort()では修正しました。
 *	    詳細は、ShuntingYard()内の「//{{2016/06/24コメント追記:〜」を参照して下さい。
 *	- 基本的な関数である、exprsort()の改良点は、以上です。
 *	  さらに、基本的な関数を使用したユーティリティ関数についても、以下の改良を行いました。
 *	  ・clipshya.cのShuntingYard_Eval()は、整数の式しか扱えませんでした。
 *	    それに対して、clipexpr.cのexpreval()は、実数の式も扱えるようになりました。
 *	    'USE_EXPREVAL_NEWVER'シンボルを定義すると、実数版のexpreval()が有効になります。
 *	  ・引数を取らない関数の実装例として、rnd()を追加しました。
 *	* Fri Jun 24 22:10:38 JST 2016 Naoyuki Sawa
 *	- exprsort(),及び,exprsort_r()に、関数の実引数の数を通知するコールバック関数(fnIncrFnNumArgs)を追加しました。
 *	  使用例は、「実数版，動的メモリ確保有り」版のexpreval()の実装を参照して下さい。
 *	* Sat Jun 25 21:55:36 JST 2016 Naoyuki Sawa
 *	- 「実数版，動的メモリ確保有り」版のexpreval()に、アプリケーション定義変数,関数に対応する機能を追加しました。
 *	  元々expreval()はexprsort()の使用方法を示すためのサンプルでしたが、実際のアプリケーションで汎用的に使用出来るぐらいの機能になったと思います。
 *	  尚、「整数版，動的メモリ確保無し」版のexpreval()には、上記の機能は追加していません。
 *	* Sun Sep 04 21:41:17 JST 2016 Naoyuki Sawa
 *	- 64ビット版では、例外コードをアドレスでなく、一意なFourCC識別子で表すようにしました。
 *	  setjmp()/longjmp()のパラメータは(int)であり、(void*)や(intptr_t)を使えないからです。
 *	  尚、32ビット版も64ビット版と共通に変更しても良いのですが、万一既存のコードに影響が生じる事を防ぐために、32ビット版はこれまで通りとしました。
 */
#ifndef __CLIP_EXPR_H__
#define __CLIP_EXPR_H__
#ifdef  __cplusplus
extern "C" {
#endif//__cplusplus
#define USE_EXPR_SEH	//このシンボルを定義すると、clipexpr.c内のDIE()を全て、SEH_throw(ExprException)に置き換えます。
#ifdef  USE_EXPR_SEH
//{{2016/09/04変更:64ビット版では、例外コードをアドレスでなく、一意なFourCC識別子で表すようにしました。
//extern const char ExprException[1/*dummy*/];
//↓2016/09/04変更:64ビット版では、例外コードをアドレスでなく、一意なFourCC識別子で表すようにしました。
#ifndef _WIN64
extern const char ExprException[1/*dummy*/];		//32ビット版
#else //_WIN64
#define ExprException MAKEFOURCC('E','x','p','r')	//64ビット版
#endif//_WIN64
//}}2016/09/04変更:64ビット版では、例外コードをアドレスでなく、一意なFourCC識別子で表すようにしました。
#endif//USE_EXPR_SEH
/****************************************************************************
 *	定数
 ****************************************************************************/
//トークンの種類(アプリケーション定義のfnGetTokenType関数が返すべき値)
#define exprsort_TokenType_Number			1	//数値
#define exprsort_TokenType_Function			2	//関数
#define exprsort_TokenType_FunctionArgumentSeparator	3	//関数の引数セパレータ(カンマなど)
#define exprsort_TokenType_Operator			4	//演算子
#define exprsort_TokenType_LeftParenthesis		5	//左括弧
#define exprsort_TokenType_RightParenthesis		6	//右括弧
/****************************************************************************
 *	基本的な関数
 ****************************************************************************/
int exprsort(void* base, size_t num, size_t width,
  int (*fnGetTokenType)(const void* pToken),					//アプリケーション定義の関数:トークンの種類を返す。		exprsort_TokenType_〜のいずれかの値を返して下さい。
  int (*fnIsOpLeftAssoc)(const void* pOpTok),					//アプリケーション定義の関数:演算子が左結合かを返す。		左結合ならば0以外の値,右結合ならば0を返して下さい。
  int (*fnCompareOpPrec)(const void* pOpTok1, const void* pOpTok2),		//アプリケーション定義の関数:演算子の優先順位を較べる。		pOpTok1の優先順位が高ければ正の値,pOpTok2の優先順位が高ければ負の値,同じならば0を返して下さい。
  void (*fnIncrFnNumArgs/*NULL可*/)(void* pFnTok));				//アプリケーション定義の関数:関数の実引数の数を通知する。	実引数の数の回数分呼び出される。個々の関数トークンに実引数の数を記録しておき、実引数の数が正しい事を検査したり、可変引数に対応する事も出来る。	式の中で関数を使用していない,又は,関数を使用していても通知が不要ならば、NULLを指定出来ます。
int exprsort_r(void* base, size_t num, size_t width,
  int (*fnGetTokenType)(const void* pToken, void* arg),				//アプリケーション定義の関数:トークンの種類を返す。		exprsort_TokenType_〜のいずれかの値を返して下さい。
  int (*fnIsOpLeftAssoc)(const void* pOpTok, void* arg),			//アプリケーション定義の関数:演算子が左結合かを返す。		左結合ならば0以外の値,右結合ならば0を返して下さい。
  int (*fnCompareOpPrec)(const void* pOpTok1, const void* pOpTok2, void* arg),	//アプリケーション定義の関数:演算子の優先順位を較べる。		pOpTok1の優先順位が高ければ正の値,pOpTok2の優先順位が高ければ負の値,同じならば0を返して下さい。
  void (*fnIncrFnNumArgs/*NULL可*/)(void* pFnTok, void* arg),			//アプリケーション定義の関数:関数の実引数の数を通知する。	実引数の数の回数分呼び出される。個々の関数トークンに実引数の数を記録しておき、実引数の数が正しい事を検査したり、可変引数に対応する事も出来る。	式の中で関数を使用していない,又は,関数を使用していても通知が不要ならば、NULLを指定出来ます。
  void* arg);
/****************************************************************************
 *	ユーティリティ関数
 ****************************************************************************/
double expreval(const char* expr,
  double (*fnGetVar/*NULL可*/)(const char* name),							//アプリケーション定義の関数:変数の値を返す。	式の中で変数を使用していなければ、NULLを指定出来ます。
  double (*fnDoFunc/*NULL可*/)(const char* name, int argc, const double* argv/*[argc]*/));		//アプリケーション定義の関数:関数の結果を返す。	式の中で関数を使用していなければ、NULLを指定出来ます。
double expreval_r(const char* expr,
  double (*fnGetVar/*NULL可*/)(const char* name, void* arg),						//アプリケーション定義の関数:変数の値を返す。	式の中で変数を使用していなければ、NULLを指定出来ます。
  double (*fnDoFunc/*NULL可*/)(const char* name, int argc, const double* argv/*[argc]*/, void* arg),	//アプリケーション定義の関数:関数の結果を返す。	式の中で関数を使用していなければ、NULLを指定出来ます。
  void* arg);
#ifdef  __cplusplus
}//extern "C"
#endif//__cplusplus
#endif//__CLIP_EXPR_H__
