问题描述:
编译原理实验要求构造语法分析程序,实现一个简单计算器的功能
实现功能:
1,基本运算
a) 加、减、乘、除
b) 乘方、开方
c) 位运算:与、或、非
d) 阶乘运算
e) 三角函数运算
f) 可自定义变量并参与运算
2,输出对应于输入的后缀表达式(输入的是中缀表达式)
3,打印语法分析器构造的语法树
代码:
1,myCal.h
一个简单的单链表,用来保存已经定义的变量
#ifndef MYCAL_H_INCLUDED
#define MYCAL_H_INCLUDED
#define NULL 0
#include <string.h>
typedef struct Node
{
double num;
double data;
char *str;
int len;
struct Node *next;
}LinkList;
LinkList* InitList()
{
LinkList *h;
h =(LinkList*)malloc(sizeof(LinkList));
h->next = NULL;
h->str = NULL;
return h;
}
void DestroyList(LinkList* h)
{
LinkList* ah;
while(h->next != NULL)
{
ah=h->next;
free(h);
h=ah;
}
free(h);
}
void InsertData(LinkList* h,double n,char *c,int l)
{
LinkList* ah=h;
while(ah->next!=NULL)
{
ah=ah->next;
}
ah->next=(LinkList*)malloc(sizeof(LinkList));
ah->next->next=NULL;
ah->next->num=n;
ah->next->len=l;
int i=0;
ah->next->str=(char*)malloc(sizeof(char)*l);
while(i<l)
{
ah->next->str[i]=c[i];
i++;
}
}
double GetData(LinkList *h,double d)
{
LinkList* ah = h;
int i=0;
while(i<(int)d)
{
ah = ah -> next;
i++;
}
return ah->data;
}
void AssignData(LinkList* h,double theData,double exp)
{
int i=0;
LinkList* ah = h;
while(i<(int)theData)
{
ah=ah->next;
i++;
}
ah->data = exp;
}
double IsExist(LinkList* h,char *c,int l)
{
LinkList* ah=h->next;
while(ah!=NULL)
{
if(ah->len!=l)
{
ah=ah->next;
continue;
}
if(strncmp(ah->str,c,l)==0)
return ah->num;
else
ah=ah->next;
}
return 0;
}
#endif // MYCAL_H_INCLUDED
2,Sqstack.h
一个简单的栈,用来打印语法分析器的推导序列
#ifndef SQSTACK_H_INCLUDED
#define SQSTACK_H_INCLUDED
typedef struct
{
char* s[100];
int top;
}SqStack;
SqStack* InitStack()
{
SqStack* sta=(SqStack*)malloc(sizeof(SqStack));
int i=0;
while(i<50)
{
sta->s[i]=(char*)malloc(sizeof(char)*20);
i++;
}
sta->top=-1;
return sta;
}
void Push(SqStack* sta,char *a)
{
sta->top++;
int i=0;
while(a[i]!='\0')
{
sta->s[sta->top][i]=a[i];
i++;
}
sta->s[sta->top][i]='\0';
}
char* Pop(SqStack* sta)
{
return sta->s[sta->top--];
}
#endif // SQSTACK_H_INCLUDED
3, myCal.lex
词法分析程序,用来识别输入并且返回给语法分析器
%{
int n=1;
%}
tri tan|sin|cos|SIN|COS|TAN
num [0-9]
number {num}+(\.{num}+)?(e([+-])?{num}+)?
id [_a-zA-Z][_a-zA-Z0-9]*
op [\+\-\*\/\|\&\~\^\!\(\)\=]
space [\ \t]+
%%
{space} ;
sqrt|SQRT {
return SQRT;
}
{tri} {
if(yytext[0]=='s'&&yytext[1]=='i'&&yytext[2]=='n' || yytext[0]=='S'&&yytext[1]=='I'&&yytext[2]=='N')
{
yylval=0;
return TRI;
}
if(yytext[0]=='c'&&yytext[1]=='o'&&yytext[2]=='s' || yytext[0]=='C'&&yytext[1]=='O'&&yytext[2]=='S')
{
yylval=1;
return TRI;
}
if(yytext[0]=='t'&&yytext[1]=='a'&&yytext[2]=='n' || yytext[0]=='T'&&yytext[1]=='A'&&yytext[2]=='N')
{
yylval=2;
return TRI;
}
}
{number} {
yylval = atof(yytext);
return NUM;
}
{id} {
double i=IsExist(h,yytext,yyleng);
if(i!=0)
{
yylval=i;
return VAR;
}
else
{
yylval = n++;
InsertData(h,yylval,yytext,yyleng);
return VAR;
}
}
{op}|\n {
return *yytext;
}
. printf("find error\n");
%%
int yywrap(void)
{
return 1;
}
4,myCal.y
语法分析程序,实现要求的功能
%token NUM VAR SQRT TRI
%left '&' '|'
%left '+' '-'
%left '*' '/'
%right '~'
%right '!' '^'
%{
#include<stdio.h>
#include<math.h>
#include <stdlib.h>
#include "myCal.h"
#include "SqStack.h"
#define YYSTYPE double
void yyerror(char*);
double factorial(double d);
LinkList* h;
SqStack* sta;
char* buf;
FILE* f;
%}
%%
start:
start stat '\n' {
Push(sta,"start->stat \\n\n");
Push(sta,"Right Grammer!\n\n");
while(sta->top!=-1)
{
buf=Pop(sta);
printf("%s",buf);
fprintf(f,"%s",buf);
}
}
|
;
stat:
VAR '=' exp {
AssignData(h,$1,$3);
Push(sta,"stat->VAR=exp\n");
}
|exp {
printf("\nvalue is :%.3f\n",$1);
fprintf(f,"\nvalue is :%.3f\n",$1);
Push(sta,"stat->exp\n");
}
;
exp:
NUM {
$$ = $1;
printf("%.3f ",$1);
fprintf(f,"%.3f ",$1);
Push(sta,"exp->num\n");
}
|VAR {
$$ = GetData(h,$1);
printf("%.3f ",$$);
fprintf(f,"%.3f ",$$);
Push(sta,"exp->VAR\n");
}
|exp '+' exp {
$$ = $1 + $3;
printf("+ ");
fprintf(f,"+ ");
Push(sta,"exp->exp+exp\n");
}
|exp '-' exp {
$$ = $1 - $3;
printf("- ");
fprintf(f,"- ");
Push(sta,"exp->exp-exp\n");
}
|exp '*' exp {
$$ = $1 * $3;
printf("* ");
fprintf(f,"* ");
Push(sta,"exp->exp*exp\n");
}
|exp '/' exp {
$$ = $1 / $3;
printf("/ ");
fprintf(f,"/ ");
Push(sta,"exp->exp/exp\n");
}
|exp '&' exp {
$$ = (int)$1 & (int)$3;
printf("& ");
fprintf(f,"& ");
Push(sta,"exp->exp&exp\n");
}
|exp '|' exp {
$$ = (int)$1 | (int)$3;
printf("| ");
fprintf(f,"| ");
Push(sta,"exp->exp|exp\n");
}
|'~' exp {
$$ = ~(int)$2;
printf("~ ");
fprintf(f,"~ ");
Push(sta,"exp->~exp\n");
}
|exp '!' {
$$ = factorial($1);
printf("! ");
fprintf(f,"! ");
Push(sta,"exp->exp!\n");
}
|exp '^' exp {
$$ = pow($1,$3);
printf("^ ");
fprintf(f,"^ ");
Push(sta,"exp->exp^exp\n");
}
|SQRT '(' exp ')' {
$$ = sqrt($3);
printf("sqrt ");
fprintf(f,"sqrt ");
Push(sta,"exp->sqrt(exp)\n");
}
|TRI '(' exp ')' {
switch((int)$1)
{
case 0:{
$$ = sin($3);
printf("sin ");
fprintf(f,"sin ");
Push(sta,"exp->sin(exp)\n");
break;
}
case 1:{
$$ = cos($3);
printf("cos ");
fprintf(f,"cos ");
Push(sta,"exp->cos(exp)\n");
break;
}
case 2:{
$$ = tan($3);
printf("tan ");
fprintf(f,"tan ");
Push(sta,"exp->tan(exp)\n");
break;
}
}
}
|'(' exp ')' {
$$ = $2;
Push(sta,"exp->(exp)\n");
}
;
%%
#include "lex.yy.c"
int main(void)
{
f=fopen("mycal.txt","w");
h=InitList(h);
sta=InitStack();
printf(" --------------------------\n| my cal |\n --------------------------\n");
yyparse();
fclose(f);
return 0;
}
void yyerror(char* s){}
double factorial(double d)
{
if(d==0 || d==1)
return 1;
int i=1,sum=1;
while(i<=(int)d)
{
sum*=i;
i++;
}
return sum;
}
运行结果:
小结:
刚开学比较新鲜,也比较喜欢孔繁茹老师,写程序时用心了
在中间的时候,应用了lex帮我处理了一个问题,学以致用
感觉数据结构和编译原理很重要,学吧