以前用C写过一个,你参考一下改改吧,其实改动并不大。
/*
* 文件 MathExpression.c : 使用递归下降分析法的计算表达式程序。
*
* 算法:
* 请参考《编译原理》中EBNF表示法以及递归下降分析法部分
*
* 表达式语法:
* number :: 0|1|2|3|4|5|6|7|8|9
* addopt :: +|-
* mulopt :: *|/
* expr :: term [addopt term]
* term :: factor [mulopt factor]
* factor :: (expr) | number
*
* 限制条件:
* 仅支持 + - * / ( ) 运算
* 仅支持个位数字的运算
* 不支持两位以上数字及小数的运算(但结果可以是多位数字或小数)
* 不支持数字的符号位(正负号)
* 输入字符串(表达式)最大长度限制为255个字符
*
* 改进:
* 建立一个扫描器,可以识别完整的数字 float :: [+|-]number+"."number+
* 增加标识符号表和赋值运算符,可以使用变量进行运算
* 目前的读取输入的方法存在缓冲区溢出问题
* 使用新的扫描器读取算法,可以取消输入长度限制,甚至可以支持使用文件作为输入
*
* 注意事项:
* 使用 Turbo C 编译需要注释 #include "stdafx.h" 一行
* 使用 Visual Studio.Net C++ 编译需要取消 #include "stdafx.h" 一行的注释
* 如果有需要, 注意适当的删除注释
*
* 开发环境:
* Windows 2003 Server, Visual Studio.Net 2003 (C++)
*
* 刘云涛 2003-10-5 email
assos@21cn.com QQ:8596677
*/
/* #include "stdafx.h" /* COMMENT this line if Turbo C 2.0 compile this file */
#include <stdio.h>
/* 定义运算符和数字的记号类型 token type */
typedef enum {
PLUS, /* + */
MINUS, /* - */
MULTI, /* * */
DIV, /* / */
LB, /* ( */
RB, /* ) */
NUM, /* 数字 */
END, /* 结束 */
ERR /* 错误 */
} TokenType;
char buffer[255];
/* 输入缓冲区 */
char* bp;
/* 输入缓冲区读指针,指向下一个字符 */
TokenType token;
/* 当前标记 */
char token_str[255];
/* 当前标记字符*/
/* 函数原型前置声明 */
void get_token(void);
float expr( void );
float term( void );
float factor( void );
/* 输出错误信息 */
void error(TokenType token, char* msg=NULL, char argv=NULL)
{
printf("/n");
switch (token) {
case PLUS: fprintf(stderr, "ERROR: expect +");
break;
case MINUS: fprintf(stderr, "ERROR: expect -");
break;
case MULTI: fprintf(stderr, "ERROR: expect *");
break;
case DIV: fprintf(stderr, "ERROR: expect /");
break;
case LB: fprintf(stderr, "ERROR: expect (");
break;
case RB: fprintf(stderr, "ERROR: expect )");
break;
case NUM: fprintf(stderr, "ERROR: expect number");
break;
case ERR: fprintf(stderr, msg, argv);
break;
default: fprintf(stderr, "Unknown error.");
break;
}
printf("/n");
exit(1);
}
/* 测试是否是需要的标记 */
void match(TokenType expect_token)
{
if (token == expect_token)
get_token();
else
error(expect_token);
}
/* 获取下一个标记 */
void get_token( void )
{
/* 读取下一个字符,跳过空格 */
do
{
token_char = *bp++;
} while ( token_char == ' ' );
switch ( token_char ) {
case ' ': get_token();
break;
case '+': token = PLUS;
break;
case '-': token = MINUS;
break;
case '*': token = MULTI;
break;
case '/': token = DIV;
break;
case '(': token = LB;
break;
case ')': token = RB;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9': token = NUM;
break;
case NULL:
case '/n': token = end;
break;
default: error(ERR, "ERROR: unknown ident %c", token_char);
}
}
float expr( void )
{
float result;
result = term();
while ( (token == PLUS) || (token == MINUS) ) {
switch ( token ) {
case PLUS:
match(PLUS);
result = result + term();
break;
case MINUS:
match(MINUS);
result = result - term();
break;
}
}
return result;
}
float term( void )
{
float result, tmp;
result = factor();
while ( (token == MULTI) || (token == DIV) ) {
switch ( token ) {
case MULTI:
match(MULTI);
result = result * factor();
break;
case DIV:
match(DIV);
tmp = factor();
if (tmp != 0)
result = result / tmp;
else
error(ERR, "ERROR: Divided by zero");
break;
}
}
return result;
}
float factor( void )
{
float result;
switch ( token ) {
case LB:
match(LB);
result = expr();
match(RB);
break;
case NUM:
/* 这里只处理个位数字的情况
* 如果要求数字为多位或者小数,则需要修改获取数字的算法
*/
result = token_char - '0';
get_token();
break;
default:
error(ERR, "ERROR: expect number or (");
break;
}
return result;
}
int main(int argc, char* argv[])
{
float result;
printf("Input the expression:/n");
gets( buffer );
/* 改进此读取方法,以避免缓冲区溢出*/
bp = buffer;
get_token();
result = expr();
if ( token == END )
printf("=%.2f", result);
else
error(ERR, "ERROR: syntax error: '%c'", token_char);
return 0;
}