实验二 语法分析1——递归子程序法

目的和内容

1、 实验目的:通过完成语法分析程序,了解语法分析的过程和作用
2、 实验内容:用递归子程序法实现对pascal的子集程序设计语言的分析程序
3、 实验要求:对源程序的内码流进行分析,如为文法定义的句子输出”是”否则输出”否”,根据需要处理说明语句填写写相应的符号表供以后代码生成时使用

文法的改变

为适合递归子程序法,对实验一中的文法改写成无左递归和无左共因子的BNF如下:
<程序>→<程序首部><分程序>.
<程序首部>→PROGRAM标识符;
<分程序>→<常量说明部分><变量说明部分><过程说明部分> <复合语句>
<常量说明部>→CONST<常量定义><常量定义后缀> |ε
<常量定义>→标识符=无符号整数
<常量定义后缀>→,<常量定义><常量定义后缀> |ε
<变量说明部分>→VAR<变量定义><变量定义后缀> |ε
<变量定义>→标识符<标识符后缀>:<类型>;
<标识符后缀>→,标识符<标识符后缀> |ε
<变量定义后缀>→<变量定义><变量定义后缀> |ε
<类型>→INTEGER | LONG
<过程说明部分>→<过程首部><分程序>;<过程说明部分后缀>|ε
<过程首部>→PROCEDURE标识符<参数部分>;
<参数部分>→(标识符: <类型>)|ε
<过程说明部分后缀>→<过程首部><分程序>;<过程说明部分后缀>|ε
<语句>→<赋值或调用语句>|<条件语句>|<当型循环语句>|<读语句>
|<写语句>|<复合语句>|ε
<赋值或调用语句>→标识符<后缀>
<后缀>→:=<表达式>|(<表达式>)|ε
<条件语句>→IF<条件>THEN<语句>
<当型循环语句>→WHILE<条件>DO <语句>
<读语句>→READ(标识符<标识符后缀>)
<写语句>→WRITE(<表达式><表达式后缀>)
<表达式后缀>→,<表过式><表达式后缀>|ε
<复合语句>→BEGIN<语句><语句后缀>END
<语句后缀>→;<语句><语句后缀>|ε
<条件>→<表达式><关系运算符><表达式>|ODD<表达式>
<表达式>→+<项><项后缀>|-<项><项后缀>|<项><项后缀>
<项后缀>→<加型运算符><项><项后缀>|ε
<项>→<因子><因子后缀>
<因子后缀>→<乘型运算符><因子><因子后缀>|e
<因子>→标识符|无符号整数|(<表达式>)
<加型运算符>→+|-
<乘型运算型>→*|/
<关系运算符>→ =|<>|<|<=|>|>=

非终结符和函数名对照表

为适用递归子程序,下表为非终结符和函数名对照表

非终结符

函数名

非终结符

函数名

<程序>

program

<程序首部>

proghead

<分程序>

block

<常量说明部分>

consexpl

<常量定义>

consdefi

<变量说明部分>

varexl

<常量定义后缀>

conssuff

<变量定义>

vardefi

<变量定义后缀>

varsuff

<>过程说明部分>

procdefi

<类型>

typeil

<过程首部>

procedh

<过程说明部分后缀>

procsuff

<赋值或调用语句>

assipro

<语句>

sentence

<后缀>

suffix

<条件语句>

ifsent

<读语句>

read

<当型循环语句>

whilsent

<标识符后缀>

idsuff

<写语句>

Write

<复合语句>

compsent

<表达式后缀>

Exprsuff

<语句后缀>

sentsuff

<条件>

Conditio

<项后缀>

termsuff

<表达式>

Express

<>

term

<因子后缀>

Factsuff

<参数部分>

argument

<因子>

Factor

<加型运算符>

addoper

<乘型运算符>

Muloper

<关系运算符>

respoper

递归子程序的设计思想

为每个非终结符设计一个识别的子程序,寻找该非终结符也就是调用相应的子程序。由于单词在语法分析中作为一个整体,故在语法识别中仅使用其内码。在这里将词法分析作为语法分析的一个子程序,当语法分析需要单词时,就调用相应的词法分析程序获得一个单词。语法分析的作用是识别输入符号串是否是文法上定义的句子,即判断输入符号串是否是满足“程序”定义的要求。也就是当语法识别程序从正常退出表示输入符号串是正确的“程序”;若从出错退出,则输入符号串不是正确的“程序”。出错时,可以根据读字符的位置判断出错的位置。

实验流程

下面是部分子程序的流程图
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

实验代码

#include<bits/stdc++.h>
using namespace std;
#define PROGRAM 1
#define CONST 2
#define VAR 3
#define INTEGER 4
#define LONG 5
#define PROCEDURE 6
#define IF 7
#define THEN 8
#define WHILE 9
#define DO 10
#define READ 11
#define WRITE 12
#define BEGIN 13
#define END 14
#define ODD 15
#define ADD 16
#define SUB 17
#define MUL 18
#define DIV 19
#define EQU 20
#define NEQ 21
#define LES 22
#define LEQ 23
#define LAG 24
#define GEQ 25
#define DOT 26
#define COM 27
#define SEM 28
#define COL 29
#define ASS 30
#define LBR 31
#define RBR 32
#define INT 33
#define ID 34
#define EIN 35
#define lenth1 15
#define lenth2 17
struct Ident
{
	char name[21];
	int type;
	int addr;
};
Ident indent[1000]; // 定义标识符表
struct St
{
	char name[21];
	int code;
};
St sym;

int lenth = 0;  // 表示标识符表长度
FILE* f1, * f2; //f1、f2分别指向输入输出文件

int line = 0, row = 0, val;
void getsym();char getchr();void error(int);
void program(); void proghead();
void block(); void consexpl();
void consdefi(); void varexpl();
void conssuff(); void vardefi();
void varsuff(); void procdefi();
void typeil(); void procedh();
void procsuff(); void assipro();
void sentence(); void suffix();
void ifsent(); void read();
void whilsent(); void idsuff();
void write(); void compsent();
void exprsuff(); void sentsuff();
void conditio(); void termsuff();
void express(); void term();
void factsuff(); void argument();
void factor(); void addoper();
void muloper(); void respoper();

int main(int argc, char* argv[]) {
	if ((f1 = fopen(argv[1], "r")) == NULL) {  // 打开输入文件流
		cout << "can not open the input file!" << endl;
		exit(0);
	}
	getsym();
	program();
	cout << "该程序通过语法分析!" << endl;
	fclose(f1);
	return 0;
}

void getsym() {
	static char a[lenth1][10] = {
		"program","const","var","integer","long","procedure","if",
		"then","while","do","read","write","begin","end","odd"
	},
		d[lenth2][3] = { "+","-","*","/","=","<>","<","<=",">",">=",
						".",",",";",":",":=","(",")" },
		str[21], ch = ' ';
	int i, n; // n判断单词长度,i判断是哪个关键字
	while (isspace(ch))
	{
		ch = getchr();
	}
	if (isalpha(ch)) { //判断字母开头的字符
		n = 0;
		while (isalpha(ch) || isdigit(ch)) {
			if (isalpha(ch))
				ch = tolower(ch);
			str[n++] = ch;
			ch = getchr();
		}
		str[n] = '\0';
		for (i = 0;i < lenth1;i++) {
			if (!strcmp(str, a[i]))
				break;
		}
		if (i < lenth1) { //找到匹配关键字
			strcpy(sym.name, a[i]);
			sym.code = i + 1;
		}
		else {
			for (i = 0;i < lenth;i++) { //遍历已记录的标识符记录表
				if (!strcmp(str, indent[i].name))
					break;
			}
			if (i == lenth) {
				strcpy(indent[i].name, str);
			}
			strcpy(sym.name, indent[i].name);
			sym.code = 34;
		}
	}
	else if (isdigit(ch)) { // 判断数字开头的字符
		val = 0;n = 0;
		while (isdigit(ch)) {
			val = val * 10 + ch - '0';
			sym.name[n++] = ch;
			ch = getchr();
		}
		sym.name[n] = '\0';
		sym.code = 33;
	}
	else {  // 判断特殊字符
		if (ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '=' ||
			ch == '.' || ch == ',' || ch == ';' || ch == '(' || ch == ')') {
			str[0] = ch; str[1] = '\0';
			ch = getchr();
			for (i = 0;i < lenth2;i++) {
				if (!strcmp(str, d[i])) {
					strcpy(sym.name, str);
					sym.code = i + 16;
					break;
				}
			}
		}
		else if (ch == '#') {
			str[0] = ch; str[1] = '\0';
			ch = getchr();
			strcpy(sym.name, str);
			sym.code = 35;
		}
		else if (ch == '<') {
			char b = getchr();
			if (b == '>') {
				str[0] = '<';str[1] = '>';str[2] = '\0';
				strcpy(sym.name, str);
				sym.code = 21;
				ch = getchr();
			}
			else if (b == '=') {
				str[0] = '<';str[1] = '=';str[2] = '\0';
				strcpy(sym.name, str);
				sym.code = 23;
				ch = getchr();
			}
			else {
				str[0] = '<';str[1] = '\0';
				strcpy(sym.name, str);
				sym.code = 22;
				ch = b;
			}
		}
		else if (ch == '>') {
			char b = getchr();
			if (b == '=') {
				str[0] = '>';str[1] = '=';str[2] = '\0';
				strcpy(sym.name, str);
				sym.code = 25;
				ch = getchr();
			}
			else {
				str[0] = '>';str[1] = '\0';
				strcpy(sym.name, str);
				sym.code = 24;
				ch = b;
			}
		}
		else if (ch == ':') {
			char b = getchr();
			if (b == '=') {
				str[0] = ch;str[1] = b;str[2] = '\0';
				strcpy(sym.name, str);
				sym.code = 30;
				ch = getchr();
			}
			else {
				str[0] = ch;str[1] = '\0';
				strcpy(sym.name, str);
				sym.code = 29;
				ch = b;
			}
		}
	}
}


char getchr() {  // 从文件中获取下一个非空字符
	char ch = fgetc(f1);
	if (ch == '\n') {
		row = 1;
		line++;
	}
	else {
		if (ch != ' ' && ch != '\t') {
			row++;
		}
	}
	return ch;
}

void error(int n) {
	printf("There are %d-error\n", n);
	exit(0);
}

void program() { // 程序
	proghead();block();
	cout<<sym.code<<" "<<sym.name<<endl;
	cout<<!feof(f1)<<endl;
	if (sym.code == DOT && feof(f1)) {
		return ;
	}
	else {
		error(2);
	}
}

void proghead() { // 程序首部
	if (sym.code == PROGRAM) {
		getsym(); // 获取next token
		if (sym.code == ID) {
			getsym();
			if (sym.code == SEM)
				getsym();
			else
				error(5);
		}
		else
			error(4);
	}
	else
		error(3);
}

void block() {  // 分程序
	consexpl();
	varexpl();
	procdefi();
	compsent();
}

void consexpl() { // 常量说明部分
	if (sym.code == CONST) {
		getsym();
		consdefi();
		conssuff();
		if (sym.code == SEM)
			getsym();
		else
			error(6);
	} // 无else表示可以为空
}

void consdefi() {   // 常量定义
	if (sym.code == ID) {
		getsym();
		if (sym.code == EQU) {
			getsym();
			if (sym.code == INT)
				getsym();
			else
				error(9);
		}
		else
			error(8);
	}
	else
		error(7);
}

void conssuff() {  // 常量定义后缀
	if (sym.code == COM) {
		getsym();
		consdefi();
		conssuff();
//		if (sym.code == SEM)
	//		getsym();
		//else
			//error(10);
	}// 无else表示可以为空
}
void varexpl() {  // 变量说明部分
	if (sym.code == VAR) {
		getsym();
		vardefi();
		varsuff();
	}// 无else表示可以为空
}

void vardefi() {  // 变量定义
	if (sym.code == ID) {
		getsym();
		idsuff();
		if (sym.code == COL) {
			getsym();
			typeil();
			if (sym.code == SEM)
				getsym();
			else
				error(12);
		}
		else
			error(11);
	}
	//	else
	//		error(10);
}

void varsuff() {
	if (sym.code == ID) {
		vardefi();
		varsuff();
	}// 无else表示可以为空
}

void typeil() {
	if (sym.code == INTEGER || sym.code == LONG)
		getsym();
	else
		error(13);
}

void procdefi() {
	if (sym.code == PROCEDURE)
	{
		procedh();
		block();
		if (sym.code == SEM) {
			procsuff();
		}
		else
			error(14);
	}// 无else表示可以为空
}

void procedh() {
	if (sym.code == PROCEDURE) {
		getsym();
		if (sym.code == ID) {
			getsym();
			argument();
			if (sym.code == SEM)
				getsym();
			else
				error(16);
		}
		else
			error(15);
	}
}

void argument() {
	if (sym.code == LBR) {
		getsym();
		if (sym.code == ID) {
			getsym();
			if (sym.code == COL) {
				getsym();
				if (sym.code == RBR)
					getsym();
				else
					error(19);
			}
			else
				error(18);
		}
		error(17);
	}
}

void procsuff() {
	if (sym.code == PROCEDURE) {
		procedh();
		block();
		if (sym.code == SEM) {
			getsym();
			procsuff();
		}
		else
			error(20);
	}
}

void assipro() {
	if (sym.code == ID) {
		getsym();
		suffix();
	}
	else
		error(21);
}

void sentence() {
	if (sym.code == ID) {
		assipro();
	}
	else if (sym.code == IF) {
		ifsent();
	}
	else if (sym.code == WHILE)
		whilsent();
	else if (sym.code == READ)
		read();
	else if (sym.code == WRITE)
		write();
	else if (sym.code == BEGIN)
		compsent();
}

void suffix() {
	if (sym.code == ASS) {
		getsym();
		express();
	}
	else if (sym.code == LBR) {
		getsym();
		express();
		if (sym.code == RBR)
			getsym();
		else error(22);
	}
}

void ifsent() {
	if (sym.code == IF) {
		getsym();
		conditio();
		if (sym.code == THEN) {
			getsym();
			sentence();
		}
		else
			error(24);
	}
	else
		error(23);
}

void whilsent() {
	if (sym.code == WHILE) {
		getsym();
		conditio();
		if (sym.code == DO) {
			getsym();
			sentence();
		}
		else
			error(26);
	}
	else
		error(25);
}

void read() {
	if (sym.code == READ) {
		getsym();
		if (sym.code == LBR) {
			getsym();
			if (sym.code == ID) {
				getsym();
				idsuff();
				if (sym.code == RBR)
					getsym();
				else error(27);
			}
			else
				error(30);
		}
		else error(29);
	}
	else error(28);
}

void idsuff() {
	if (sym.code == COM) {
		getsym();
		if (sym.code == ID) {
			getsym();
			idsuff();
		}
		else
			error(30);
	} // 无else表示可以为空
}

void write() {
	if (sym.code == WRITE) {
		getsym();
		if (sym.code == LBR) {
			getsym();
			express();
			exprsuff();
			if (sym.code == RBR)
				getsym();
			else error(34);
		}
		else error(33);
	}
	else error(32);
}

void compsent() {
	if (sym.code == BEGIN) {
		getsym();
		sentence();
		sentsuff();
		if (sym.code == END)
			getsym();
		else error(36);
	}
	else error(35);
}

void exprsuff() {
	if (sym.code == COM) {
		getsym();
		express();
		exprsuff();
	}
}

void sentsuff() {
	if (sym.code == SEM) {
		getsym();
		sentence();
		sentsuff();
	}
}

void conditio() {
	if (sym.code == ODD) {
		getsym();
		express();
	}
	else {
		express();
		respoper();
		express();
	}
}

void express() {
	if (sym.code == ADD || sym.code == SUB)
		getsym();
	term();
	termsuff();
}

void term() {
	factor();
	factsuff();
}

void termsuff() {
	if (sym.code == ADD || sym.code == SUB) {
		getsym();
		factor();
		factsuff();
	}
}

void factsuff() {
	if (sym.code == MUL || sym.code == DIV) {
		getsym();
		factor();
		factsuff();
	}
}

void factor() {
	if (sym.code == ID) {
		getsym();
//		factsuff();
	}
	else if (sym.code == INT) {
		getsym();
	}
	else if (sym.code == LBR) {
		getsym();
		express();
		if (sym.code == RBR)
			getsym();
		else error(38);
	}
	else error(37);
}

void addoper() {
	if (sym.code == ADD || sym.code == SUB)
		getsym();
	else
		error(39);
}

void muloper() {
	if (sym.code == MUL || sym.code == DIV)
		getsym();
	else
		error(40);
}

void respoper() {
	if (sym.code >= EQU && sym.code <= GEQ)
		getsym();
	else
		error(41);
}

实验结果

待分析代码

program main;
const x = 1, y=2,z=444;
var z,x:long;xx:long;
a:long;
begin
z := z*3/2;
read(xx,dsaf);
write(dsaf,xx);
if x > y
then
x := x+1;
begin
x := x+1;
y:= xx -12;
x := +123;
x := (1+2);
x:= 213 * 3 + 21/x;
y := y/2 +2;
begin
while x<=10
do
y:=y+1;
end
end
end.

以上代码只是单纯为了检测是否能够通过语法分析,并没有什么实际含义(o゜▽゜)o
在这里插入图片描述

在这里插入图片描述
语法分析检测通过!

  • 6
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Andy-wen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值