⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gram.cpp

📁 自上而下语法分析器设计,词法分析器调用接口为lex()
💻 CPP
字号:
/*递归下降分析器示例程序,可识别的加法运算表达式文法为:
  E->E+E | i    ;i表示整数   (1)
  (1)转化为LL(1)文法后为:
  E->iE1					(2)
  E1->+EE1 | e(空串)		(3)
  程序是根据文法规则(2)(3)进行设计的。程序设计思路:
  为每文法的非终结符设计一个子程序,子程序实现代码根据非终结符
  对应的产生式的右部而编写,右部符号及其对应代码:
  |--- 用条件分枝语句实现。
  终结符---- 用匹配输入的代码去实现,如:if (sym==终结符) {Advance();... }。
  非终结符----用相应的子程序调用去实现。
  e(空串)----直接返回。
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include "gram.h"

char ch;            //字符变量,存放最新读进的源程序字符。
char strToken[30];  //字符数组,存放构成单词符号的字符串。
int lvalue;         //单词的内码值
char inbuf[300];            //扫描缓冲区
int sp;                     //起点指示器
int ep;                     //扫描指示器
token sym;					//向前看单词

/*函数GetChar,GetBC,Concat,isDigit,Retract,Lex用于词法分析。
词法分析器的调用接口函数为Lex(),参考实验1*/
void GetChar()
{
	int i = 0;
	ch = inbuf[ep];
	ep++;
}
void GetBC()
{
	while (ch==' ')
		GetChar();
}
void Concat()
{
	int length;
	length = ep-sp-1;
	strToken[length] = ch;
}
bool isDigit()
{
	if ((ch>='0')&&(ch<='9'))
		return true;
	return false;
}
void  Retract()
{
	if (ep==0)
		ep = 299;
	else
		ep--;
	ch = ' ';
}

int Lex()
{
	memset(strToken, 0, 30);
	GetChar();
	GetBC();
	sp = ep-1;
	lvalue = 0;
	if (isDigit())
	{
		while (isDigit())
		{
			Concat();GetChar();
		}
		Retract();
		sscanf(strToken, "%d", &lvalue);
		return $INT;
	}
	else if (ch == '+') 
	{
		strToken[0] = '+';
		return $PLUS;
	}
	else if (ch == '-') 
	{
		strToken[0] = '-';
		return $MINUS;
	}
	else if (ch == '*')
	{
		strToken[0] = '*';
		return $MUL;
	}
	else if (ch == '/')
	{
		strToken[0] = '/';
		return $DIV;
	}
	else if (ch == '\n')
	{
		return $END;
	}
	else 
	{
		strToken[0] = ch;
		return $UNKNOWN;
	}
}

/*读入向前看符号*/
void Advance()
{
	sym.code = Lex();
	sym.value = lvalue;
	strcpy(sym.name, strToken); 
}

void ProcError()
{
	switch (sym.code)
	{
		case $UNKNOWN:
			printf("错误(1):第%d个字符为非法字符。\n", sp+1);
			break;
		case $INT:
			printf("错误(2):第%d个字符开始处的单词%s前缺运算符。\n", sp+1, sym.name);
			break;
		case $PLUS:
		case $MINUS:
		case $MUL:
		case $DIV:
			printf("错误(3):第%d个字符开始处的单词%s前缺操作数。\n", sp+1, sym.name);
			break;
		case $END:
			printf("错误(4):语法错,非正常输入结束。\n");
			break;
		default:
			;
	}
}

int E1()
{
	if (sym.code == $PLUS)
	{
		Advance();
		if (E() == FAIL)
			return FAIL;
		if (E1() == FAIL)
			return FAIL;	
		return SUCCESS;
	}
	if (sym.code == $MINUS)
	{
		Advance();
		if (E() == FAIL)
			return FAIL;
		if (E1() == FAIL)
			return FAIL;	
		return SUCCESS;
	}
	if (sym.code == $MUL)
	{
		Advance();
		if (E() == FAIL)
			return FAIL;
		if (E1() == FAIL)
			return FAIL;	
		return SUCCESS;
	}
	if (sym.code == $DIV)
	{
		Advance();
		if (E() == FAIL)
			return FAIL;
		if (E1() == FAIL)
			return FAIL;	
		return SUCCESS;
	}
	//当sym属于FOLLOW(E1)时,用E->e (空串)自动匹配输入,否则发现错误。
	if (sym.code != $END)
		return FAIL;
	return SUCCESS;
}

int E()
{
	if (sym.code == $INT)
	{
		Advance();
		if (E1() == FAIL)
			return FAIL;
		//匹配结束符号
		if (sym.code != $END)
			return FAIL;
		return SUCCESS;
	}
	return FAIL;
}

void main()
{
	bool quit = false;
	int i;

	while (!quit)
	{
		memset(inbuf, 0, 300);
		printf("请输入四则运算表达式(回车结束):");
		i = 0;
		while ((inbuf[i] = getchar()) != '\n')
			i++;
		printf("\n");
		ep = 0;
		Advance();
		if (E() == SUCCESS)
			printf("分析成功,没有语法错误\n");
		else
			ProcError();
		printf("退出吗?(y/n)");
		if (toupper(getch()) == 'Y')
			quit = true;
		printf("\n");
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -