问题描述:
编译原理实验要求构造语法分析程序,实现一个简单计算器的功能
实现功能:
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
一个简单的栈,用来打印语法分析器的推导序列
#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
词法分析程序,用来识别输入并且返回给语法分析器
%{ 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; }
语法分析程序,实现要求的功能
%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帮我处理了一个问题,学以致用
感觉数据结构和编译原理很重要,学吧