当前位置: 代码迷 >> 综合 >> 应用 yacc 和lex 实现 语法分析与词法分析 之复杂四则运算
  详细解决方案

应用 yacc 和lex 实现 语法分析与词法分析 之复杂四则运算

热度:48   发布时间:2024-01-21 07:03:44.0

为什么要实现四则运算,看是很傻比,但是只有你明白其中的用处,他才是有用的。呵呵~~~~~

简单四则运算实现:

#include <iostream>
using namespace std;
int fun(const char * pBuffer,const int &iLen)
{
int iEnd = 0;
int num[20];
int iNum = 0 ;
char str[20];
int  iStr = 0 ;for(int i = 0;i < iLen ; i++  ){if(pBuffer[i] >= '0' && pBuffer[i] <= '9'){num[iNum++] = pBuffer[i] - '0';}else if(pBuffer[i] == '*'){num[iNum - 1] = num[iNum - 1] * (pBuffer[i+1] - '0');i++;}else if(pBuffer[i] == '/'){num[iNum - 1] = num[iNum - 1] / (pBuffer[i+1] - '0');i++;}else{str[iStr++] = pBuffer[i];}}iEnd = num[0];for(int j = 0; j < iStr ; j ++ ){if(str[j] == '+'){iEnd = iEnd + num[ j + 1] ;}if(str[j] == '-'){iEnd = iEnd - num[ j + 1] ;}}
return iEnd;
}
int main() {
cout << "!!!Hello World!!!" << endl; // prints !!!Hello World!!!
char a[]="3*3+7+4/3";
int k=fun(a,9);
cout<<k<<endl;
return 0;
}


弊端:

1、表达式只含 +, -, *, / 四则运算符,不含括号 

2、表达式数值只包含个位整数(0-9),且不会出现0作为除数的情况

3、要考虑加减乘除按通常四则运算规定的计算优先级 
4、除法用整数除法,即仅保留除法运算结果的整数部分。比如8/3=2。输入表达式保证无0作为除数情况发生 
5、输入字符串一定是符合题意合法的表达式,其中只包括数字字符和四则运算符字符,除此之外不含其它任何字符,不会出现计算溢出情况 


yacc  lex  是什么,自己去百度吧!你会找到答案的。

math.y文件内容

%{int yylex(void);
#include"stdio.h"
char *mail;
char *cError;
typedef YY_BUFFER_STATE;%}%union
{long long   integer;   double  ldouble;
}%token NL LPAR RPAR END
%token <integer>INTEGER 
%token <ldouble>DOUBLE%type <ldouble> exprreal
%type <integer> exprint%left OP_ADD OP_SUB
%left OP_MUL OP_DIV
%left OP_MOD
%left OP_NEG
%left CAST_INT CAST_REAL%%Program: exprint  {sprintf(mail,"%d",$1);}|exprreal {sprintf(mail,"%f",$1);}
;exprint:CAST_INT LPAR exprint RPAR {$$ = (long long)$3;}|     exprint OP_ADD exprint {$$ = $1 + $3;}
| exprint OP_SUB exprint {$$ = $1 - $3;}
| exprint OP_MUL exprint {$$ = $1 * $3;}
| exprint OP_DIV exprint {if($3)$$ = $1 / $3;else {$$=0;sprintf(cError,"%s","/");}}
| exprint OP_MOD exprint {if($3)$$ = $1 % $3;else {$$=0;sprintf(cError,"%s","%");}}
| LPAR exprint RPAR {$$ = $2;}
| INTEGER {$$ = $1;}
;exprreal:CAST_REAL LPAR exprreal RPAR {$$ = (long double)$3;}
|     exprreal OP_ADD exprreal {$$ = $1 + $3;}
| exprreal OP_SUB exprreal {$$ = $1 - $3;}
| exprreal OP_MUL exprreal {$$ = $1 * $3;}
| exprreal OP_DIV exprreal {if($3)$$ = $1 / $3;else{$$=0;sprintf(cError,"%s","/");}}
|     LPAR exprreal RPAR {$$ = $2;}
|     DOUBLE  {$$ = $1;}
|     exprint OP_ADD   exprreal  { $$ = (double)$1 + $3;}
|     exprint OP_SUB   exprreal  { $$ = (double)$1 - $3;}
|     exprint OP_MUL   exprreal  { $$ = (double)$1 * $3;}
|     exprint OP_DIV   exprreal  {if($3) $$ = (double)$1 / $3;else{$$=0;sprintf(cError,"%s","/");}}    
|     exprreal OP_ADD  exprint   {$$ = $1 + (double)$3;}
|     exprreal OP_SUB  exprint   {$$ = $1 - (double)$3;}
|     exprreal OP_MUL  exprint   {$$ = $1 * (double)$3;}
|     exprreal OP_DIV  exprint   {if($3)$$ = $1 / (double)$3;else{$$=0;sprintf(cError,"%s","/");}}   
|     exprint  OP_ADD  exprint   {$$ = (double)$1 + (double)$3;}
|     exprint OP_SUB   exprint   {$$ = (double)$1 - (double)$3;}
|     exprint OP_MUL   exprint   {$$ = (double)$1 * (double)$3;}
|     exprint OP_DIV exprint{if($3)$$ = (double)$1 / (double)$3;else{$$=0;sprintf(cError,"%s","/");}} 
;%%
int yyerror(char *s)
{ printf ("%s\n",s);return 0;
}
int ZGMCommonFourOperationFunction(const char *str, int len, char *m,char *cErr)
{//printf("ZGM Common Four Operation Function !!!\n");mail = m;cError = cErr;YY_BUFFER_STATE state = yy_scan_bytes(str, len); yy_switch_to_buffer(state);yyparse();                      yy_delete_buffer(state);     return 0;
}


math.l文件内容

%{
#include <ctype.h>
#include"y.tab.h"
#include "stdio.h"
#include "string.h"
%}%%"+" {return OP_ADD;}
"-" {return OP_SUB;}
"*" {return OP_MUL;}
"/" {return OP_DIV;}
"%" {return OP_MOD;}
"(" {return LPAR;}
")" {return RPAR;}
(int|INT) {return CAST_INT;}
(real|REAL) {return CAST_REAL;}[0-9]+       {yylval.integer = atoi(yytext); return INTEGER;}[0-9]*\.[0-9]+    {sscanf(yytext,"%lf",&yylval.ldouble);return DOUBLE;}"0x"[0-9a-f]+ {sscanf (yytext,"%x",&yylval.integer); return (INTEGER); }[ \t] ;
\r {return END;}
\n { return END;}%%int yywrap()
{
return 1;
}


应用yacc 和 lex 命令编译他们 生成相应的 c 和 h文件。然后将c和h文件 应用 gcc  编译命令生成 对应用 c库,在应用生成的c库中的函数ZGMCommonFourOperationFunction 就可以实现各种复杂的四则运算了。  其中的应用价值,还是很广阔的,你会懂的的。