编译原理-用Bison构造语法分析程序

问题描述:

编译原理实验要求构造语法分析程序,实现一个简单计算器的功能


实现功能:

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;
}

运行结果:

编译原理-用Bison构造语法分析程序_第1张图片


小结:

刚开学比较新鲜,也比较喜欢孔繁茹老师,写程序时用心了

在中间的时候,应用了lex帮我处理了一个问题,学以致用

感觉数据结构和编译原理很重要,学吧

你可能感兴趣的:(编译原理,bison)