编译原理-语法分析(实验 C语言)

语法分析

1. 实验目的

编制一个递归下降分析程序,实现对词法分析程序所提供的单词序列的语法检查和结构分析

2. 实验要求

利用C语言编制递归下降分析程序,并对简单语言进行语法分析

2.1 待分析的简单语言的语法

用扩充的BNF表示如下:

  1. <程序> ::= begin<语句串> end
  2. <语句串> ::= <语句> {;<语句>}
  3. <语句> ::= <赋值语句>
  4. <赋值表达式> ::= ID := <表达式>
  5. <表达式> ::= <项> { + <项> | - <项> }
  6. <项> ::= <因子> { * <因子> | / <因子>}
  7. <因子> ::= ID | NUM | (<表达式>)

2.2 实验要求说明

输入单词串,以“#”结束,如果是文法正确的句子,则输出成功信息,答应“success”,否则输出“error”

例如:
输入 begin a := 9; x := 2 * 3; b := a + x end #
输出 success
输入 x := a + b * c end #
输出 error

3. 语法分析程序的算法思想

  1. 主程序示意图如图
    在这里插入图片描述

  2. 递归下降分析程序示意图如图
    在这里插入图片描述

  3. 语句串分析过程示意图如图
    在这里插入图片描述

  4. statement语句分析函数流程如图
    statement语句分析函数示意图
    在这里插入图片描述

    expression表达式分析函数示意图
    在这里插入图片描述

    term分析函数示意图
    在这里插入图片描述

    factor分析过程示意图
    在这里插入图片描述

4. 实验源代码

源代码:


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define _KEY_WORD_END "waiting for your expanding"

//结构体
typedef struct
{
	int typenum;
	char *word;
}WORD;

//函数声明
char m_getch();
void getbc();
void concat();
int letter();
int digit();
int reserve();
void retract();
char *dtb();
WORD *scaner();
void lrparser(WORD *word);
WORD *yucu(WORD *word);
WORD *factor(WORD *word);
WORD *statement(WORD *word);
WORD *expression(WORD *word);
WORD *term(WORD *word);

char input[255];
char token[255] = "";
int p_input;
int p_token;
char ch;
int kk = 0;
char *rwtab[] = {"begin","if","then","while","do","end",_KEY_WORD_END};


int main(void)
{
	int over = 1;
	WORD *oneword = new WORD;//new为c++中的关键字 在使用new进行内存分配时,需要包含相关类型的头文件。#include <iostream>
	while(1)  //无限循环
	{
		printf("Enter Your words(end with #):");
		scanf("%[^#]",input); //读入源程序字符串到缓冲区,以#结束,允许多行输入
		p_input = 0;
		printf("Your words: \n%s\n",input);
		oneword = scaner();
		lrparser(oneword);
		while(getchar() != '\n'){
		}
		printf("press # to exit:");
		if(getchar() == 35){
			return 0;
		}
		while(getchar() != '\n'){
		}
	}
}

// 词法分析
// 从输入缓冲区读取一个字符到ch中
char m_getch()
{
    ch = input[p_input];
    p_input = p_input + 1;
    return(ch);
}

// 去掉空白符号
void getbc()
{
    while(ch == ' ' || ch == 10)
    {
        ch = input[p_input];
        p_input = p_input + 1;
    }
}

//拼写单词
void concat()
{
    token[p_token] = ch;
    p_token = p_token + 1;
    token[p_token] = '\0';
}

//判断是否字母
int letter()
{
    if(ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z')
        return 1;
    else 
        return 0;
}

//判断是否数字
int digit()
{
    if(ch >= '0' && ch <= '9')
        return 1;
    else 
        return 0;
}

// 检索关键字表格
int reserve()
{
    int i = 0;
    while(strcmp(rwtab[i],_KEY_WORD_END))
    {
        if(!strcmp(rwtab[i],token))
        {
            return i + 1;
        }
        i = i + 1;
    }
    return 10;
}

//回退一个字符
void retract()
{
	p_input = p_input - 1;
}

//数字转换成二进制
char *dtb(char *buffer)
{
	int j = 0;
	int flag = 0;
	int k = (sizeof(char)<<3) - 1;
	
	char temp = ch - '0';
	for(int i = 0; i < (sizeof(char)<<3); i++,k--){
		if((temp >> k & 0x01) == 0){
			if(flag == 1){
				buffer[j++] = 0 + '0';
			}	
		}
		else{
			flag = 1;
			buffer[j++] = (temp >> k & 0x01) + '0';
		}
	}
	buffer[j] = 0;
	return buffer;
	
   // Converts the ch to binary;
}


WORD *scaner()
{
	WORD *myword = (WORD *)malloc(sizeof(WORD));
	myword -> typenum = 10;
	myword -> word = "";
	p_token = 0;
	m_getch();
	getbc();
	if(letter())
	{
		while(letter() || digit())
		{
			concat();
			m_getch();
		}
		retract();
		myword -> typenum = reserve();
		myword -> word = token;
		return myword;
	}
	else if(digit())
	{
		while(digit())
		{
			concat();
			m_getch();
		}
		retract();
		myword -> typenum = 11;
		myword -> word = token;
		return myword;
	}
	else
	{
		switch(ch)
		{
			case'=':
				m_getch();
				if(ch == '=')
				{
					myword -> typenum = 39;
					myword -> word = "==";
					return myword;
				}
				retract();
				myword->typenum = 25;
				myword->word = "=";
				return myword;
				break;
			case'+':
				myword->typenum = 13;
				myword->word = "+";
				return myword;
				break;
			case'-':
				myword->typenum = 14;
				myword->word = "-";
				return myword;
				break;
			case'*':
				myword->typenum = 15;
				myword->word = "*";
				return myword;
				break;
			case'/':
				myword->typenum = 16;
				myword->word = "/";
				return myword;
				break;
			case'(':
				myword->typenum = 27;
				myword->word = "(";
				return myword;
				break;
			case')':
				myword->typenum = 28;
				myword->word = ")";
				return myword;
				break;
			case'[':
				myword->typenum = 28;
				myword->word = "[";
				return myword;
				break;
			case']':
				myword->typenum = 29;
				myword->word = "]";
				return myword;
				break;
			case'{':
				myword->typenum = 30;
				myword->word = "{";
				return myword;
				break;
			case'}':
				myword->typenum = 31;
				myword->word = "}";
				return myword;
				break;
			case',':
				myword->typenum = 32;
				myword->word = ",";
				return myword;
				break;
			case':':
				m_getch();
				if(ch == '=')
				{
					myword->typenum = 18;
					myword->word = ":=";
					return myword;
				}
				retract();
				myword->typenum = 17;
				myword->word = ":";
				return myword;
				break;
			case';':
				myword->typenum = 26;
				myword->word = ";";
				return myword;
				break;
			case'>':
				m_getch();
				if(ch=='=')
				{
					myword->typenum = 24;
					myword->word = ">=";
					return myword;
				}
				retract();
				myword->typenum = 23;
				myword->word = ">";
				return myword;
				break;
			case'<':
				m_getch();
				if(ch=='=')
				{
					myword->typenum = 22;
					myword->word = "<=";
					return myword;
				}else if(ch == '>')
				{
					myword->typenum = 21;
					myword->word = "<>";
				}
				retract();
				myword->typenum = 20;
				myword->word = "<";
				return myword;
				break;
			case'!':
				m_getch();
				if(ch=='=')
				{
					myword->typenum = 40;
					myword->word = "!=";
					return myword;
				}
				retract();
				myword->typenum = -1;
				myword->word = "ERROR";
				return myword;
				break;
			case'\0':
				myword->typenum = 1000;
				myword->word = "OVER";
				return myword;
				break;
			default:
				myword->typenum = 0;
				myword->word = "#";
				return myword;
		}
	}
}


// 语法分析 判断begin和end
void lrparser(WORD *word)
{
	WORD *w;
	if(word == NULL)
	{
		return;
	}
	if(word -> typenum == 1) //种别码为1,有关键字begin
	{  
		free(word); //释放空间
		w = scaner();
		w = yucu(w);
		if(w == NULL)
		{
			return ;
		}
		if(w -> typenum == 6)  //种别码为6,有关键字end
		{
			free(w);
			w = scaner();
			if(w -> typenum==0&&kk==0)
				free(w);
				printf("success  成功\n");
		}
		else
		{
			free(w);
			if(kk!=1)
				printf("lack END error!  错误 缺少END\n"); //缺少end
			kk = 1;
		}
	}
	else
	{
		free(word);
		printf("Begin error!  begin 错误\n");//无begin报错
		kk = 1;
	}
	return ;
}

//语句以;号结尾
WORD *yucu(WORD *word)
{
	WORD *w;
	w = statement(word); //语句段分析
	if(w == NULL)
	{
		return NULL;
	}
	while(w->typenum == 26) //有;号
	{
		free(w);
		w = scaner();
		w = statement(w);
		if(w == NULL)
		{
			return NULL;
		}
	}
	return w;
}

//语句段分析
WORD *statement(WORD *word)
{
	WORD *w;
	if(word == NULL)
	{
		return NULL;
	}
	if(word->typenum == 10) //字符串
	{ 
		free(word);
		w = scaner();
		if(w->typenum == 18) //赋值符号
		{ 
			free(w);
			w = scaner();
			w = expression(w); //表达式
			if(w == NULL)
			{
				return NULL;
			}
			return w;
		}
		else
		{
			free(w);
			printf("assignment token error! 赋值号错误\n");
			return NULL;
			kk = 1;
		}
	}
	else
	{
		free(word);
		printf("statement error! 语句错误\n");
		return NULL;
	}
}

//表达式处理
WORD *expression(WORD *word)
{
	WORD *w;
	w = term(word);
	if(w == NULL)
	{
		return NULL;
	}
	// +-法
	while(w -> typenum == 13 || w -> typenum == 14)
	{
		free(w);
		w = scaner();
		w = term(w);
		if(w == NULL){
			return NULL;
		}
	}
	return w;
}


WORD *term(WORD *word)
{
	WORD *w;
	w = factor(word);
	if(w == NULL)
	{
		return NULL;
	}
	// */法
	while(w -> typenum == 15 || w -> typenum == 16)
	{
		free(w);
		w = scaner();
		w = factor(w);
		if(w == NULL)
		{
			return NULL;
		}
	}
	return w;
}

//括号分析
WORD *factor(WORD *word)
{
	WORD *w;
	if(word == NULL)
	{
		return NULL;
	}
	if(word -> typenum == 10 || word -> typenum == 11)
	{
		free(word);
		w = scaner();
	}
	else if(word -> typenum == 27)
	{
		free(word);
		w = scaner();
		w = expression(w);
		if(w == NULL)
		{
			return NULL;
		}
		if(w -> typenum == 28)
		{
			free(w);
			w = scaner();
		}
		else{
			free(w);
			printf(") error!  ')' 错误\n");
			kk = 1;
			return NULL;
		}
	}
	else
	{
		free(word);
		printf("expression error!  表达式错误\n");
		kk = 1;
		return NULL;
	}
	return w;
}


5. 实验结果

  1. 输入正确语法

在这里插入图片描述

  1. 输入任意字符后继续输入无begin语法

在这里插入图片描述

  1. 输入赋值号错误的语法

在这里插入图片描述

6. 实验小结

  1. 将main函数中的输入输出语句放入无限循环中,使其不断调用,直至键盘输入#号

    int main(void)
    {
    	int over = 1;
    	WORD *oneword = new WORD;//new为c++中的关键字 在使用new进行内存分配时,需要包含相关类型的头文件。#include <iostream>
    	while(1)  //无限循环
    	{
    		printf("Enter Your words(end with #):");
    		scanf("%[^#]",input); //读入源程序字符串到缓冲区,以#结束,允许多行输入
    		p_input = 0;
    		printf("Your words: \n%s\n",input);
    		oneword = scaner();
    		lrparser(oneword);
    		while(getchar() != '\n'){
    		}
    		printf("press # to exit:");
    		if(getchar() == 35){
    			return 0;
    		}
    		while(getchar() != '\n'){
    		}
    	}
    }
    
  2. 使用原先词法分析中所写的代码,语法分析时在词法分析通过的前提下进行的

  3. 对代码进行语法检测需判断begin和end这两个开始和结束符

  4. 判断每个语句段是以;号结尾

  5. 判断语句段中的字符串,赋值符,表达式是否正确

  6. 判断 + - * / 是否正确

递归下降分析是一种常用的语法分析方法,它通过递归调用函数来实现对语法的检查和分析。在C语言编写递归下降分析程序,可以通过定义不同的语法规则和相应的递归函数来实现。 首先,需要定义语法规则,例如可以定义一个简单的表达式语法规则:E -> E + T | T,其中E表示表达式,+表示加法操作符,T表示项。根据这个语法规则,可以编写一个递归函数来实现递归下降分析: ```c #include <stdio.h> // 声明递归函数 void E(); void T(); // 定义词法分析所提供的单词序列 char input[] = "2 + 3 * 4"; // 定义全局变量来表示当前读取的位置 int pos = 0; // 定义一个函数来获取下一个符号 char getNextToken() { return input[pos++]; } // 定义函数来实现E的递归下降分析 void E() { T(); char token = getNextToken(); if (token == '+') { E(); } else { pos--; } } // 定义函数来实现T的递归下降分析 void T() { char token = getNextToken(); if (token >= '0' && token <= '9') { // 如果是数字,则继续往后读取 token = getNextToken(); } else { printf("语法错误\n"); return; } } int main() { // 开始进行递归下降分析 E(); return 0; } ``` 上述代码实现了一个简单的递归下降分析程序,用于对词法分析程序提供的单词序列进行语法检查。执行程序后,程序会按照定义的语法规则递归地进行分析,并输出语法错误信息(如果有错误)。在这个例子中,程序会对输入的表达式进行语法检查,如果发现错误,则会输出"语法错误"。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值