返回   cpper编程论坛 > Zion/测试
注册账号 论坛帮助 会员列表 日历事件 搜索 今日新帖 标记版面已读

Zion/测试 惹人烦的东西这边来

回复
 
LinkBack 主题工具 显示模式
  #1 (permalink)  
旧 2004-07-21
polyrandom 的头像
超级版主
 
注册日期: 2002-09-03
帖子: 3,138
文章: 20
polyrandom 正向着好的方向发展
默认 关于 C++ 的 eval 接口

我想写一个 C++ 下的 eval 函数,可以对类似于
代码:
"i * 100 - 2000 * sin ( x )"
这样的代码求值。
如果只是一个表达式分析,那么接口很简单:
代码:
typedef implemented_specified number; number eval( const char* expr );
如果要加入变量,那么就变为
代码:
typedef implemented_specified number; number eval( const char* expr , const map< string, number >& variables );
可是关于函数,我就比较迷惑了,因为函数接受的参数不同,目前我能想到的是利用重载:
代码:
typedef implemented_specified number; number eval( const char* expr , const map< string, number >& variables, const map< string, unary_function > unary ); number eval( const char* expr , const map< string, number >& variables, const map< string, unary_function > unary , const map< string, binary_function > binary ); ......
不知道大家还有什么更好的想法?
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #2 (permalink)  
旧 2004-07-21
高级会员
 
注册日期: 2003-11-04
帖子: 210
pomb 正向着好的方向发展
发送 MSN 消息给 pomb
默认

我想如果将脚本(表达式)中的函数直接映射到函数调用的话,这种做法不是很好,强类型检查将绑住你的手脚。
我想对这种问题最好还是把参数统一化,不管是用Variant类作为统一参数也好,还是用一个流作为输入参数也好(当然如果需要输出的话可以传两个流),总之需要保持接口一致性。模拟函数调用的动作,调用方将参数流化,函数自己从流中取参数。
或者不怕死的话自己写汇编压参数也可以——我这么做过,不是不可以,麻烦,扩展性差。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #3 (permalink)  
旧 2004-07-21
polyrandom 的头像
超级版主
 
注册日期: 2002-09-03
帖子: 3,138
文章: 20
polyrandom 正向着好的方向发展
默认

那么干脆就这样
代码:
typedef implemented_specified number; number eval( const char* expr , const map< string, number >& variables , const map< string, unary_function > unary ); number eval( const char* expr , const map< string, number >& variables , const map< string, function > functions
其中每一个 function 接受一个 const vector<number>& 做参数,然后返回一个 number,这样也应该可以了,而且封装的还算高级。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #4 (permalink)  
旧 2004-07-21
高级会员
 
注册日期: 2003-11-04
帖子: 210
pomb 正向着好的方向发展
发送 MSN 消息给 pomb
默认

嗯,其实vector<number>就是一个简单的仅接受number的流:)
做好了让我们看看啊!
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #5 (permalink)  
旧 2004-07-21
高级会员
 
注册日期: 2004-02-20
帖子: 228
SnowFlacon 正向着好的方向发展
默认

我觉得C++就不要做这种事情了八。
做出来也没有太多的意义,Python/Javascript这种动态语言的eval函数的意义不仅仅是表达式求值或者函数调用,更加重要的是把数据的地位提高了,Data is Program.C++能写出这样的东西么?
class B
{
virtual print()=0;
}
string s=" class A ublic B\
{\
print()\
{ }\
}";
B * =eval;
不能的话,用embed Python或者embed Javascript 不是很好么?
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #6 (permalink)  
旧 2004-07-21
polyrandom 的头像
超级版主
 
注册日期: 2002-09-03
帖子: 3,138
文章: 20
polyrandom 正向着好的方向发展
默认

引用:
作者: pomb
嗯,其实vector<number>就是一个简单的仅接受number的流:)
做好了让我们看看啊!
我还不一定真会写呢,因为不清楚有没有时间。不过如果这边有人合作的话,可以考虑,呵呵。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #7 (permalink)  
旧 2004-07-21
yumagi 的头像
高级会员
 
注册日期: 2003-06-09
住址: 上海
帖子: 314
yumagi 正向着好的方向发展
发送 MSN 消息给 yumagi
默认

写一个吧,我也有兴趣。看了Scheme里的动态实现,搬到C++里来实验一下,应该蛮有意思的。现在好像很流行把fpl的东西搬到C++里来折腾
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #8 (permalink)  
旧 2004-07-21
高级会员
 
注册日期: 2003-11-04
帖子: 210
pomb 正向着好的方向发展
发送 MSN 消息给 pomb
默认

是打算写一个自己的脚本解析器么?
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #9 (permalink)  
旧 2004-07-21
高级会员
 
注册日期: 2003-11-04
帖子: 210
pomb 正向着好的方向发展
发送 MSN 消息给 pomb
默认

引用:
作者: SnowFlacon
我觉得C++就不要做这种事情了八。
做出来也没有太多的意义,Python/Javascript这种动态语言的eval函数的意义不仅仅是表达式求值或者函数调用,更加重要的是把数据的地位提高了,Data is Program.C++能写出这样的东西么?
class B
{
virtual print()=0;
}
string s=" class A ublic B\
{\
print()\
{ }\
}";
B * =eval;
不能的话,用embed Python或者embed Javascript 不是很好么?
Perl也有同样的功能,就是把自己当作解析器来用了。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #10 (permalink)  
旧 2004-07-21
polyrandom 的头像
超级版主
 
注册日期: 2002-09-03
帖子: 3,138
文章: 20
polyrandom 正向着好的方向发展
默认

引用:
作者: SnowFlacon
我觉得C++就不要做这种事情了八。
做出来也没有太多的意义,Python/Javascript这种动态语言的eval函数的意义不仅仅是表达式求值或者函数调用,更加重要的是把数据的地位提高了,Data is Program.C++能写出这样的东西么?
class B
{
virtual print()=0;
}
string s=" class A ublic B\
{\
print()\
{ }\
}";
B * =eval;
不能的话,用embed Python或者embed Javascript 不是很好么?
这不一样的。
我并不需要一个完整的语言支持,我需要的是一个比较强的表达式分析器。也就是说,如果别人写程序用到复杂的表达式分析了,就可以 include 我这个库,相对于 embedded python 来说,这方便不少。
像这样一个库,基本上可以适应一般环境下的表达式分析了。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #11 (permalink)  
旧 2004-07-22
高级会员
 
注册日期: 2002-09-15
帖子: 2,531
ajoo 正向着好的方向发展
默认

为什么要把这些vector什么的单独当作参数传递呢?
它们难道不都是一些environment吗?
直接做一个Environment对象,把所有这些东西都放在里面,
然后把Environment传入不行吗?
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #12 (permalink)  
旧 2004-07-22
高级会员
 
注册日期: 2003-11-04
帖子: 210
pomb 正向着好的方向发展
发送 MSN 消息给 pomb
默认

引用:
作者: PolyRandom
那么干脆就这样
代码:
typedef implemented_specified number; number eval( const char* expr , const map< string, number >& variables , const map< string, unary_function > unary ); number eval( const char* expr , const map< string, number >& variables , const map< string, function > functions
其中每一个 function 接受一个 const vector<number>& 做参数,然后返回一个 number,这样也应该可以了,而且封装的还算高级。
如果是这样的话,那么我建议给函数传入一个非const的Stack,而不要返回值(有没有无所谓)。因为如果传入const的vector而且返回计算结果的话,明显就是外部控制器去取操作数传入函数,然后对返回值进行处理——通常就是弹栈和压栈的操作。
问题是现在外界无法准确知道函数需要的操作数个数,由外界去决定如何弹栈还不如直接由函数自己决定,这样控制器遇到需要应用操作符(包括函数)的话,只需要把操作数的栈传给相应的函数就OK了。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #13 (permalink)  
旧 2004-07-22
polyrandom 的头像
超级版主
 
注册日期: 2002-09-03
帖子: 3,138
文章: 20
polyrandom 正向着好的方向发展
默认

to ajoo:
你这个说法只是另一个方法,但是也不能说一定好。

to pomb:
这可不一样,譬如它写 1 + combine ( 100, 10 ) - 100,那么我必须把 100, 100 传给 combine ,否则就应该出错。而不是任由函数自己去取参数。
当然你的想法也可以进一步引申,那样就可以写出一个类似于 forth 的语言了。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #14 (permalink)  
旧 2004-07-22
高级会员
 
注册日期: 2003-11-04
帖子: 210
pomb 正向着好的方向发展
发送 MSN 消息给 pomb
默认

pora,我想我大概明白你的意思。你的意思就是需要加上校验,如果combine这个方法必需两个参数,那么combine(10)这样的表达式就需要报错,而不是任由combine去弹出栈中另外一个不该由它消费的数。也就是对参数个数进行匹配检查,对么?
但是这样的话,每个function类都需要给出一个额外的信息,即它接受多少个参数吧?
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #15 (permalink)  
旧 2004-07-22
polyrandom 的头像
超级版主
 
注册日期: 2002-09-03
帖子: 3,138
文章: 20
polyrandom 正向着好的方向发展
默认

引用:
作者: pomb
pora,我想我大概明白你的意思。你的意思就是需要加上校验,如果combine这个方法必需两个参数,那么combine(10)这样的表达式就需要报错,而不是任由combine去弹出栈中另外一个不该由它消费的数。也就是对参数个数进行匹配检查,对么?
但是这样的话,每个function类都需要给出一个额外的信息,即它接受多少个参数吧?
不用,我们支持同一个函数可以接受不同数目的参数,譬如说 sum。
但是如果一个函数发现参数数目不对,它应该吐个异常出来让大家看看。
就是说,这个交流都是用户自己的事情,用户在表达式里面用错参数数目,我们不必操心。我们就按部就班的作,除了错误也是用户扛着。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #16 (permalink)  
旧 2004-07-22
高级会员
 
注册日期: 2003-11-04
帖子: 210
pomb 正向着好的方向发展
发送 MSN 消息给 pomb
默认

嗯,这也是个不错的选择哈。(推卸责任,哈哈哈)
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #17 (permalink)  
旧 2004-07-23
polyrandom 的头像
超级版主
 
注册日期: 2002-09-03
帖子: 3,138
文章: 20
polyrandom 正向着好的方向发展
默认

写好了,支持 +-*/,**是乘方,()也支持。可以使用变量,名字必须用字母开头,后续可以是数字和字母。可以使用函数调用,语法为 函数名 (参数列表),参数列表用","隔开。我给出的例子里面,有一个 sum 是使用可变参数的。请大家有什么意见/ bug 都告诉我。
CppEval.h
代码:
#ifndef CPP_EVAL_H_0AF40410D697CB5483C80E2594B25CF0_20040721__ #define CPP_EVAL_H_0AF40410D697CB5483C80E2594B25CF0_20040721__ #include <cmath> #include <map> #include <vector> #include <sstream> #include <stdexcept> #include <cstdlib> namespace cpp_eval { template< typename N > N eval( const char* E ); template< typename N > N eval( const char* E, const ::std::map< ::std::string, N >& V ); template< typename N, typename F > N eval( const char* E, const ::std::map< ::std::string, N >& V, F& f ); class eval_exception: public ::std::logic_error { public: eval_exception( const char* desc ): logic_error(desc) {} }; template< typename N > class DF { public: N operator()( const char*, const ::std::vector< N >& P ) { throw eval_exception( "unexisting function called" ); // return N(); } }; template< typename N > N eval( const char* E ) { ::std::map< ::std::string, N > V; DF< N > f; return eval( E, V, f ); } template< typename N > N eval( const char* E, const ::std::map< ::std::string, N >& V ) { DF< N > f; return eval( E, V, f ); } template< typename N, typename F > class evaler { const ::std::map< ::std::string, N >& MV; F& MF; const char* MC; enum TT { AP = '+', SN = '-', MU = '*', DI = '/', PO = '~', LB = '(', RB = ')', PS = ',', I = 257, U = 258, FI = 259 }; TT MTT; std::string MI; N MVA; void L() { for(;;) { if( isspace( *MC ) ) { ++MC; continue; } else if( *MC == '*' && *( MC + 1 ) == '*' ) MTT = PO, MC += 2; else if( *MC == AP || *MC == SN || *MC == MU || *MC == DI || *MC == LB || *MC == RB || *MC == PS ) MTT = ( TT )*MC, ++MC; else if( isalpha( *MC ) ) { MTT = I; MI.clear(); MI += *MC; ++MC; while( isalpha( *MC ) || isdigit( *MC ) ) MI += *MC, ++MC; } else if( *MC == 0) MTT = FI; else { MTT = U; istringstream iss( MC ); iss >> MVA; if( ! iss ) throw eval_exception( "error in format" ); MC += iss.rdbuf()->pubseekoff( 0, ios::cur, ios::in ); } break; } } void M( TT TT ) { if( MTT == TT ) L(); else throw eval_exception( "unmatched token" ); } N E() { N R = ER( HR() ); return R; } N ER( const N& L ) { N R = L; if( MTT == AP ) M( AP ), R = ER( L + HR() ); else if( MTT == SN ) M( SN ), R = ER( L - HR() ); return R; } N HR() { return HER( SE() ); } N HER( const N& L ) { N R = L; if( MTT == MU ) M( MU ), R = HER( L * SE() ); else if( MTT == DI ) M( DI ), R = HER( L / SE() ); return R; } N SE() { N R; if( MTT == AP ) M( AP ), R = SE(); else if( MTT == SN ) M( SN ), R = - SE(); else R = PE(); return R; } N PE() { N R = FA(); if( MTT == PO ) M( PO ), R = std::pow( R, static_cast< int >( PE() ) ); return R; } N FA() { N R; if( MTT == U ) R = MVA, M( U ); else if( MTT == LB ) M( LB ), R = E(), M( RB ); else R = LS(); return R; } N LS() { std::string id = MI; M( I ); return LT( id ); } N LT( const std::string& id ) { N R; if( MTT == LB ) { M( LB ); std::vector< N > P = PL(); R = MF( id.c_str(), P ); } else { if( MV.find( id ) == MV.end() ) throw eval_exception( "cannot find variable" ); R = MV.find( id )->second; } return R; } std::vector< N > PL() { std::vector< N > R; for(;;) { if( MTT == RB ) { M( RB ); break; } R.push_back( E() ); PT( R ); } return R; } void PT( std::vector< N >& P ) { if( MTT == PS ) M( PS ), P.push_back( E() ), PT( P ); } public: evaler( const ::std::map< ::std::string, N >& V, F& f ) : MV( V ), MF( f ) {} N operator()( const char* expr ) { MC = expr; L(); N R = E(); if( MTT != FI ) throw eval_exception( "unexpect expression format" ); return R; } }; template< typename N, typename F > N eval( const char* E, const ::std::map< ::std::string, N >& V, F& f ) { return evaler< N, F >( V, f )( E ); } }; #endif//CPP_EVAL_H_0AF40410D697CB5483C80E2594B25CF0_20040721__
CppEval.cpp
代码:
#include "CppEval.h" #include <iostream> #include <numeric> using namespace std; class functions { public: int operator()( const char* name, const ::std::vector< int >& params ) { if( stricmp( name, "return1" ) == 0 ) { if( params.size() != 0 ) throw 1; return 1; } else if( stricmp( name, "negative" ) == 0 ) { if( params.size() != 1 ) throw 1; return - params[ 0 ]; } else if( stricmp( name, "sum" ) == 0 ) { return accumulate( params.begin(), params.end(), 0 ); } } }; int main() { map< string, int > variables; variables[ "aa" ] = 100; variables[ "b" ] = 200; functions f; cout<<cpp_eval::eval< int >( " + aa * aa / b - b / -2 /2/2 -- 5 ** 2 + -100 " " + ( aa * aa / b - b / -2 /2/2 -- 5 ** 2 + -100 )" " + return1() + negative( 1 ) + sum( 1, 2, 3, sum( 1 + 2 *5-7, 555, 111 ) )", variables, f )<<endl; return 0; }
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #18 (permalink)  
旧 2004-07-23
初级会员
 
注册日期: 2003-06-13
帖子: 12
firingme 正向着好的方向发展
默认

楼上的这个代码看起来很像P.J博士写的风格,可惜又没有那么多注释。看不懂,看不懂……
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #19 (permalink)  
旧 2004-07-23
polyrandom 的头像
超级版主
 
注册日期: 2002-09-03
帖子: 3,138
文章: 20
polyrandom 正向着好的方向发展
默认

引用:
作者: firingme
楼上的这个代码看起来很像P.J博士写的风格,可惜又没有那么多注释。看不懂,看不懂……
不需要看懂,只需要使用。如果使用下来没问题,那不就可以了? 当然,如果你用下来有问题,可以告诉我。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #20 (permalink)  
旧 2004-07-23
高级会员
 
注册日期: 2002-09-16
帖子: 1,087
文章: 1
SpitFire 正向着好的方向发展
默认

唉,pora代码风格果然不只是在某些程序上有问题

b4你
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
回复

书签
主题工具
显示模式

发帖规则
不可以发表新主题
不可以发表回复
不可以上传附件
不可以编辑自己的帖子

启用 BB 代码
论坛启用 表情符号
论坛启用 [IMG] 代码
论坛禁用 HTML 代码
Trackbacks are 启用
Pingbacks are 启用
Refbacks are 启用


相似的主题
主题 主题作者 版面 回复 最后发表
[普通]关于functional langauge和oo的一些粗浅感想 ajoo 技术杂烩 16 2004-11-25 11:36 AM
一句话 COM - 给 C++ 程序员的 COM 入门指南 polyrandom 技术杂烩 6 2004-11-12 10:12 PM
ACE中的线程安全接口模式(zt) wy 技术杂烩 0 2004-04-26 05:50 AM
套间(Apartment)的基础知识 famel 技术杂烩 7 2004-04-07 03:10 AM
cg的接口和实现分离的示例代码(I/O流库的设计) ajoo 技术杂烩 3 2003-07-31 02:50 AM


所有时间均为格林尼治时间 +9。现在的时间是 08:55 AM


Powered by vBulletin® 版本 3.7.0
版权所有 ©2000 - 2009,Jelsoft Enterprises Ltd.
(C) Copy Right All Right Reserved 2001 - 2007

Search Engine Friendly URLs by vBSEO 3.1.0