编译原理(二):语法分析程序(自动求First集、Follow集、预测分析表)

一、简介

语法分析任务

  • 识别由词法分析得出的单词序列是否是给定文法的句子

语法分析理论基础

  • 上下文无关文法和下推自动机

自上而下语法分析的方式

  • 反复使用不同产生式进行推导以谋求与输入符号 串相匹配

二、算法

1.消除左递归

问题:什么是左递归 ?

答:文法存在产生式P →Pa,则是直接左递归,文法存在产生式P →Pa ,P →Aa, A→Pb,则是间接左递归。

消除直接左递归的方法
本质上就是将左递归转换为右递归
在这里插入图片描述
如果有间接左递归的话该怎么办呢?

在这里插入图片描述
直接看定义不好理解,看完例题立马就清楚了。
在这里插入图片描述

另外需要注意的是,如果上述的排序顺序不同,最终得到的文法可能不同,但是这些文法是等价的,并且开始符号不能改变。

2.消除回溯

之前所以会产生回溯,是因为可能会产生虚假匹配。
(1)、求候选式的First集
在这里插入图片描述
在这里插入图片描述

(2)、求候选式的Follow集
First集中可能有空串,但是Follow集中肯定没有空串
在这里插入图片描述
(3)、提取左因子
在这里插入图片描述

(3)、构造预测分析表
在这里插入图片描述

三、代码实现

本程序支持自定义文法,程序会自动分析文法,求出First集合、Follow集合并且算出预测分析表。根据预测分析表,我们可以直接写出PDA进行语法分析,因为时间关系,写的比较粗糙,后面如果有时间会对其进行改良

词法分析程序

该程序是对上节进行改良的

#pragma once
#include <set>
#include <fstream>
#include <stdio.h>
#include <string>
#include <map>
#include <iostream>
#include <vector>
#define END_ACCEPT 20
#define END_NO_ACCEPT 21
#define ERR 22
using namespace std;
namespace Lex {
	void init();
};
extern map<string, int> KEYWORD_TAB;
extern map<string, int> TYPE_TAB;
extern map<string, int> BASE_TAB;
extern map<string, int> Operator;
extern map<string, int> Seperator;


#define TYPE_DEFINE 1001
#define CONSTANT 1002
#define IDENTIFIER 1003
#define OPERATOR 1004
#define Separator 1005
#define KeyWord 1005


class Token
{
public:
	string token;
	int Line;
	int TYPE;
	Token(int line):Line(line){
		token = "";
	}
public:
	void append(char ch) {
		token += ch;
	}
public:
	bool finished = false;
	void finish() {
		if (finished) {
			finished = true;
			return;
		}
		cout << "Line" << Line << ":";
		if (TYPE_TAB.count(token) != 0) {
			cout << "类型->";
			TYPE = TYPE_DEFINE;
		}
		else if (isConstant(token)) {
			cout << "常量->";
			TYPE = CONSTANT;
		}
		else if (Operator.count(token) != 0) {
			cout << "操作符->";
			TYPE = OPERATOR;
		}
		else if (Seperator.count(token) != 0) {
			cout << "分隔符->";
			TYPE = Separator;
		}else if (KEYWORD_TAB.count(token)!=0) {
			cout << "关键字->";
			TYPE = Separator;

		}
		else {
			cout << "标识符->";
			TYPE = IDENTIFIER;
		}
		cout << token<<endl;
	}
public:
	bool isConstant(string str) {
		for (int i = 0; i < str.size();i++) {
			char c = str[i];
			if (c != '.' && !(c >= '0' && c <= '9')) {
				return false;
			}
		}
		return true;
	}
};


class LexAna {
private:
	ifstream in;
	int cursor = 0;
	int Line = 0;
	string Line_content;
	vector<Token*> Line_vector;
private:
	int State = 0;
	Token *token=NULL;
public:
	LexAna(string filename):in(filename),Line_content(""),Line(0){
		next_line();
	}
public:
	bool next_line() {
		if (in.eof()) {
			Line_content = "";
			return true;
		}
		cursor=0;
		Line++;
		token = new Token(Line);
		getline(in,Line_content);
		Line_content += '\n';
		return false;
	}
	vector<Token*> scanner() {
		if (Line_content=="") {
			return vector<Token*>();
		}
		token = new Token(Line);
		while (true)
		{
			if (cursor>=Line_content.size()) {
				next_line();
				vector<Token*> res = Line_vector;
				Token *t=new Token(Line);
				t->append('#');
				res.push_back(t);
				Line_vector.clear();
				return res;
			}
			char ch = Line_content[cursor++];
			switch (State)
			{
			case 0:
				S0(ch);
				break;
			case 1:
				S1(ch);
				break;
			case 2:
				S2(ch);
				break;
			case 3:
				S3(ch);
				break;
			case 4:
				S4(ch);
				break;
			case 5:
				S5(ch);
				break;
			}
			if (State !=END_ACCEPT && State!=END_NO_ACCEPT && State!=0) {
				token->append(ch);
			}else if (State == END_ACCEPT) {
				token->append(ch);
				end();
			}
			else if (State == END_NO_ACCEPT) {
				end();
				back();
			}
		}
	}
	void back() {
		cursor--;
	}
private:
	bool isNum(int ch) {
		return (ch >= 48 && ch <= 57);
	}
	bool isNoDisplayCharactor(int ch) {
		return (ch >= 0 && ch <= 32) || (ch == 127);
	}

private: //终止状态
	void end() {
		token->finish();
		Line_vector.push_back(token);
		State = 0;
		token = new Token(Line);
	}
	
private: //非终止状态
	void S0(char ch) {
		if (isalpha(ch)) {
			State = 1;
		}
		else if (isNum(ch)) {
			State = 2;
		}
		else if (ch=='-' || ch == '+') {
			State = 4;
		}
		else if (ch=='*' || ch =='/') {
			State = 5;
		}
		else if (ch==',' || ch==';'||ch=='('||ch=='{'||ch==')'||ch=='}'||ch=='['||ch==']' || ch=='=') {
			State = END_ACCEPT;
		}
	}

	//变量名
	void S1(char ch) {
		if (isalpha(ch) || isNum(ch)) {
			//State保持不变
		}
		else{
			State = END_NO_ACCEPT;
		}
	}

	//数字
	void S2(char ch) {
		if (isNum(ch)) {
			//State保持不变		
		}else if(ch=='.'){
			State = 3;
		}
		else{
			State = END_NO_ACCEPT;
		}
	}


	void S3(char ch) {
		if (isNum(ch)) {
			State = 2;
		}
		else {
			State =ERR;
		}
	}


	void S4(char ch) {
		if (isNum(ch)) {
			State = 2;
		}
		else if(ch=='='){
			State = END_ACCEPT;
		}
		else {
			State = END_NO_ACCEPT;
		}
	}

	void S5(char ch) {
		if (ch=='=') {
			State = END_ACCEPT;
		}
		else {
			State = ERR;
		}
	}
};
文法分析程序
#pragma once
#include <fstream>
#include <string>
#include <list>
#include <vector>
#include <set>
#include<algorithm>
#define  T_SYMPLE 2001
#define  N_SYMPLE 2002
#define	 E 2003
#define START_SYMPLE "开始"
using namespace std;
class Symple {
public:
	string name;
	int ID;
	bool empty;
	bool start = false;
public:
	Symple() {

	}
	Symple(string n,int i):name(n),ID(i),empty(false){
		if (n=="$") {
			empty = true;
		}
	}
	bool operator<(const Symple& d) const {
		return name < d.name;
	}
	bool operator==(const Symple& d) const {
		return name == d.name;
	}
	bool operator!=(const Symple& d) const {
		return name!=d.name;
	}

	

private:


};

class derivation {
public:
	Symple left;
	vector<vector<Symple>> right;
	derivation() {

	}
	derivation(pair<vector<Symple>, vector<int>> p):left(p.first.front().name, p.first.front().ID){
		vector<Symple> & temp_list = p.first;
		vector<int> splitindex = p.second;

		int start = 1;
		int index = 0;
		for (int i = 0;i < splitindex.size();i++) {
			index= splitindex[i];
			vector<Symple>::iterator start_it = temp_list.begin() + start;
			vector<Symple>::iterator end_it = temp_list.begin()+index;
			vector<Symple> res1 = vector<Symple>(start_it, end_it);
			start = index;
			right.push_back(res1);
			//A ( B )  C  void
		}
		vector<Symple>::iterator start_it = temp_list.begin() + start;
		vector<Symple>::iterator end_it = temp_list.end();
		vector<Symple> res1 = vector<Symple>(start_it, end_it);
		right.push_back(res1);
	}
public:
	bool Right_contain(Symple symple) {
		for (vector<Symple> symples:right) {
			for (Symple s : symples) {
				if (s==symple) {
					return true;
				}
			}
		}
		return false;

	}
	
};


map<string,Symple> N_SYMPLE_SET;
map<Symple,derivation> der;




namespace Syntax {

	pair<vector<Symple>,vector<int>> parser(string line) {
		int cursor = 0;
		int state = 0;
		string token = "";
		vector<int> res;
		vector<Symple> res_list;
		bool head=false;
		while (cursor<line.size())
		{
			if (line[cursor]==':') {
				cursor++;
				continue;
			}
			if (state == 0 && line[cursor]=='<' ) {
				state = 1;
			}
			else if (state==0 && line[cursor]!='<' && line[cursor] != '|') {
				token += line[cursor];
				state = 2;
			}
			else if (state ==1&&line[cursor]!='>') {
				token += line[cursor];
			}
			else if (state ==1 && line[cursor]=='>') {
				res_list.push_back(Symple(token, N_SYMPLE));
				cout<<"非终结符:" << token<<endl;
				state = 0;
				token = "";
			}
			else if (state == 2 && line[cursor]!=' ' && line[cursor] != '|' && line[cursor] != '<') {
				token += line[cursor];
			}
			else if(state == 2 &&!(line[cursor] != ' ' && line[cursor] != '|' && line[cursor] != '<')){
				res_list.push_back(Symple(token, T_SYMPLE));
				cout << "终结符:" << token << endl;
				state = 0;
				token = "";
				if (line[cursor] == '<'|| line[cursor] == '|') cursor--;
			}else if (state==0 && line[cursor]=='|') {
				res.push_back(res_list.size());
			}
			cursor++;
		}
		if (token.size()>0&&line[cursor-1]!='>') {
			res_list.push_back(Symple(token, T_SYMPLE));
			cout << "终结符:" << token << endl;
		}
		else if(token.size()>0) {
			res_list.push_back(Symple(token, N_SYMPLE));
			cout << "非终结符:" << token << endl;
		}
		return pair<vector<Symple>,vector<int>>(res_list,res);
	}
	
	void init() {
		ifstream in("C:\\Users\\user\\Desktop\\Message\\简单文法.txt");
		string line;
		while (getline(in, line))
		{
			pair<vector<Symple>, vector<int>> res= Syntax::parser(line);
			vector<Symple> l1= res.first;
			for (vector<Symple>::iterator i = l1.begin();i != l1.end();i++) {
				Symple s = *i;
				if (s.ID==N_SYMPLE) {
					N_SYMPLE_SET[s.name]=s;
				}
			}
			derivation d = derivation(res);
			der[d.left] = d;
		}
		cout << "一共有非终结符:" << N_SYMPLE_SET.size()<<endl;
	}


}

//函数:求First集
map<Symple, list<Symple>> ALL_FIRST;
list<Symple> First(Symple symple) {
	if (symple.ID==T_SYMPLE) {
		list<Symple> res = list<Symple>();
		res.push_back(symple);
		return res;
	}
	if (ALL_FIRST.count(symple)>0) {
		return ALL_FIRST[symple];
	}
	derivation d = der[symple];
	vector<vector<Symple>> r= d.right;
	list<Symple> first_unin;
	bool flag = false;
	for (vector<Symple> vec :r) {
		int cursor = 0;
		while (cursor<vec.size())
		{
			Symple s = vec[cursor++];
			if (s.ID == T_SYMPLE ) {
				first_unin.push_back(s);
				flag = false;
				break;
			}
			else if (s.ID == N_SYMPLE) {
				list<Symple> s_fir = First(s);
				list<Symple>::iterator it = find(s_fir.begin(), s_fir.end(), Symple("$", T_SYMPLE));
				if (it == s_fir.end()) {
					flag = false;
					first_unin.splice(first_unin.begin(), s_fir);
					break;
				}
				else {
					flag = true;
					s_fir.remove(Symple("$", T_SYMPLE));
					first_unin.splice(first_unin.begin(), s_fir);
				}
			}
		}
		if (cursor==vec.size() && flag==true) {
			first_unin.push_back(Symple("$", T_SYMPLE));
		}
	}
	first_unin.unique();
	ALL_FIRST[symple] = first_unin;
	return first_unin;
}


map<Symple, list<Symple>> ALL_Follow;

//函数求Follow集
list<Symple> Follow(Symple symple_) {
	if (ALL_Follow.count(symple_)>0) {
		return ALL_Follow[symple_];
	}
	list<Symple> follow_unin;
	if (symple_.start == true) {
		follow_unin.push_back(Symple("#",T_SYMPLE));
	}
	map<Symple, derivation>::iterator it_start=der.begin();
	map<Symple, derivation>::iterator it_end = der.end();
	vector<derivation> target;
	for (;it_start != it_end;it_start++) {
		derivation d = (*it_start).second;
		if (d.Right_contain(symple_)) {
			target.push_back(d);
		}
	}
	for (derivation d : target) {
		vector<vector<Symple>> r = d.right;
		for (vector<Symple> vec : r) {
			for (int i = 0;i < vec.size();i++) {
				Symple symple = vec[i];
				if (symple.ID == T_SYMPLE && symple != symple_) {
					continue;
				}
				else if (symple == symple_) {
					if (i + 1 == vec.size() && d.left!=symple) {
						list<Symple> list_symple = Follow(d.left);
						list_symple.remove(Symple("$", T_SYMPLE));
						follow_unin.splice(follow_unin.begin(), list_symple);
					}
					else if (i + 1 < vec.size() && vec[i + 1].ID == T_SYMPLE) {
						follow_unin.push_back(vec[i+1]);
					}
					else if (i + 1 < vec.size() && vec[i + 1].ID == N_SYMPLE) {
						list<Symple> temp = First(vec[i + 1]);
						auto it = find(temp.begin(),temp.end(),Symple("$",T_SYMPLE));
						if (it==temp.end()) {
							follow_unin.splice(follow_unin.begin(), temp);
						}
						else{
							temp.remove(Symple("$", T_SYMPLE));
							follow_unin.splice(follow_unin.begin(), temp);
							list<Symple> list_symple = Follow(d.left);
							follow_unin.splice(follow_unin.begin(), list_symple);
						}
					}
				}
			}
		}
	}
	if (symple_.name==START_SYMPLE) {
		follow_unin.push_back(Symple("#",T_SYMPLE));
	}
	follow_unin.sort();
	follow_unin.unique();
	ALL_Follow[symple_] = follow_unin;
	return follow_unin;
}

bool contain_NULLSymle(list<Symple> &fi) {
	auto it = find(fi.begin(),fi.end(), Symple("$", T_SYMPLE));
	return it != fi.end();
}

// 创建Select集合
map<Symple, vector<Symple>> select;
map<string, map<Symple, vector<Symple>>> predict_table;

// 创建预测分析表
void CreatePredictiveAnalysisTable(list<Symple> input, Symple nsym, vector<Symple> predict) {
	for (Symple i : input) {
		map < Symple, vector<Symple>> p2 = predict_table[i.name];
		p2[nsym] = predict;
		predict_table[i.name] = p2;
	}
}

void createSelect() {
	auto it = der.begin();
	auto it_e = der.end();
	for (;it != it_e;it++) {
		derivation d= (*it).second;
		vector<vector<Symple>> s = d.right;
		list<Symple> sub_select;
		for (vector<Symple> symples:s) {
			for (Symple s_:symples) {
				if (contain_NULLSymle(sub_select)) {
					sub_select.remove(Symple("$", T_SYMPLE));
				}
				list<Symple> fi = First(s_);
				sub_select.splice(sub_select.begin(), fi);
				if (!contain_NULLSymle(fi)) {
					break;
				}
			}
			if (contain_NULLSymle(sub_select)) {
				list<Symple> fi = Follow(d.left);
				sub_select.splice(sub_select.begin(), fi);
				sub_select.remove(Symple("$", T_SYMPLE));
			}
			CreatePredictiveAnalysisTable(sub_select,d.left,symples);
			sub_select.clear();
		}
	}
}
语法分析程序

复制的地方主要就在于自动分析文法。有了预测分析表之后可以非常轻松的实现PDA

#include <stack>
namespace Syntax{
	class PDA {
		stack<Symple> H;
		deque<Token> input;
	public:
		PDA() {
			H.push(Symple("#", T_SYMPLE));
			H.push(Symple("开始", N_SYMPLE));

		}
	public:
		void parser(vector<Token*> line) {
			try
			{
				for (Token* t : line) {
					input.push_back(*t);
				}
				while (input.size()>0)
				{
					Symple s = H.top();
					if (s.ID == N_SYMPLE) {
						s1(s);
					}
					else {
						s2(s);
					}
				}
			}
			catch (const const char *s)
			{
				throw s;
			}
			cout << "语法正确" << endl;
		}
	private:
		// 处理终结符号
		void s1(Symple s) {
			Token t= input.front();
			string token =t.token;
			if (token == "#") {
				input.pop_front();
				return;
			}
			if (predict_table.count(token)==0) {
				cout << token << ",";
				throw "输入未知符号";
			}
			else {
				map<Symple,vector<Symple>> mvs= predict_table[token];
				if (mvs.count(s)==0) {
					cout << token << "不应该被输入" <<",应该输入"<<s.name <<endl;
					throw "语法错误!";
				}
				H.pop();
				vector<Symple> vs = mvs[s];
				for (int i = vs.size() - 1;i >=0;i--) {
					if (vs[i].name!="$") {
						H.push(vs[i]);
					}
				}
			}
		}
		//  处理非终结符号
		void s2(Symple s) {
			Token t = input.front();
			string token = t.token;
			if (token == "#") {
				input.pop_front();
				return;
			}
			if (s.name == token) {
				input.pop_front();
				H.pop();
			}
			else {
				cout << "应该输入:" << s.name << ",但是您确输入" << token << endl;
				throw "语法错误!";
			}
		}
	};
}

文法定义

文法定义实在太烦了,只写了下面部分文法,以后有时间了再完善。

<开始>:<函数定义>
<函数定义>:<类型><变量>(<参数声明>) {<函数块>}
<参数声明>:<声明>|$
<赋初值>:=<右值>|$
<右值>:<表达式>
<表达式>:<因子><>
<数字闭包>:<数字><数字闭包>|$
<因子>:<因式><因式递归>
<因式递归>:*<因式><因式递归>|/<因式><因式递归>|$
<因式>:(<表达式>)|<变量>|<数字>
<数字>:1|2|3|4|5|6|7|8|9|0
<>:+<因子><>|-<因子><>|$
<声明>:<类型><变量>
<类型>:int|void|double|long|short|
<取地址>:$
<变量>:<标志符>
<标志符>:regan|CNN|RNN|main|a|b|c
<函数块>:<声明语句闭包><函数块闭包>
<声明语句闭包>:<声明语句><声明语句闭包>|$
<声明语句>:<声明>;
<声明>:<类型><变量><赋初值>
<函数块闭包>:<赋值函数><函数块闭包> |<for循环><函数块闭包>|<条件语句><函数块闭包>|<函数返回><函数块闭包>|$
<函数返回>:return<因式>;
<for循环>:for (<赋值函数><逻辑表达式>;<后缀表达式>) {<函数块>}
<赋值函数>:<变量>=<右值>; 
<逻辑表达式>:<表达式><逻辑运算符><表达式>
<逻辑运算符>:=|!=
<后缀表达式>:<变量><后缀运算符>
<后缀运算符>:+|-
程序输入与输出
int main(){
	int a=1 + 2 + (3 + 1);
	for(regan=0;regan=8;regan+){
		int c=8;
	}
	return a;
}
非终结符:开始
非终结符:函数定义
非终结符:函数定义
非终结符:类型
非终结符:变量
终结符:(
非终结符:参数声明
终结符:)
终结符:{
非终结符:函数块
终结符:}
非终结符:参数声明
非终结符:声明
终结符:$
非终结符:赋初值
终结符:=
非终结符:右值
终结符:$
非终结符:右值
非终结符:表达式
非终结符:表达式
非终结符:因子
非终结符:项
非终结符:数字闭包
非终结符:数字
非终结符:数字闭包
终结符:$
非终结符:因子
非终结符:因式
非终结符:因式递归
非终结符:因式递归
终结符:*
非终结符:因式
非终结符:因式递归
终结符:/
非终结符:因式
非终结符:因式递归
终结符:$
非终结符:因式
终结符:(
非终结符:表达式
终结符:)
非终结符:变量
非终结符:数字
非终结符:数字
终结符:1
终结符:2
终结符:3
终结符:4
终结符:5
终结符:6
终结符:7
终结符:8
终结符:9
终结符:0
非终结符:项
终结符:+
非终结符:因子
非终结符:项
终结符:-
非终结符:因子
非终结符:项
终结符:$
非终结符:声明
非终结符:类型
非终结符:变量
非终结符:类型
终结符:int
终结符:void
终结符:double
终结符:long
终结符:short
非终结符:取地址
终结符:$
非终结符:变量
非终结符:标志符
非终结符:标志符
终结符:regan
终结符:CNN
终结符:RNN
终结符:main
终结符:a
终结符:b
终结符:c
非终结符:函数块
非终结符:声明语句闭包
非终结符:函数块闭包
非终结符:声明语句闭包
非终结符:声明语句
非终结符:声明语句闭包
终结符:$
非终结符:声明语句
非终结符:声明
终结符:;
非终结符:声明
非终结符:类型
非终结符:变量
非终结符:赋初值
非终结符:函数块闭包
非终结符:赋值函数
非终结符:函数块闭包
终结符:
非终结符:for循环
非终结符:函数块闭包
非终结符:条件语句
非终结符:函数块闭包
非终结符:函数返回
非终结符:函数块闭包
终结符:$
非终结符:函数返回
终结符:return
非终结符:因式
终结符:;
非终结符:for循环
终结符:for
终结符:(
非终结符:赋值函数
非终结符:逻辑表达式
终结符:;
非终结符:后缀表达式
终结符:)
终结符:{
非终结符:函数块
终结符:}
非终结符:赋值函数
非终结符:变量
终结符:=
非终结符:右值
终结符:;
非终结符:逻辑表达式
非终结符:表达式
非终结符:逻辑运算符
非终结符:表达式
非终结符:逻辑运算符
终结符:=
终结符:!=
非终结符:后缀表达式
非终结符:变量
非终结符:后缀运算符
非终结符:后缀运算符
终结符:+
终结符:-
一共有非终结符:29
输入: 替换:函数块闭包->$
输入:!=替换:逻辑运算符->!=      项->$      因式递归->$
输入:(替换:表达式->因子 项      逻辑表达式->表达式 逻辑运算符 表达式      因式->( 表达式 )
 右值->表达式
输入:)替换:参数声明->$      赋初值->$      项->$      因式递归->$
输入:*替换:因式递归->* 因式 因式递归
输入:+替换:后缀运算符->+      项->+ 因子 项      因式递归->$
输入:-替换:后缀运算符->-      项->- 因子 项      因式递归->$
输入:/替换:因式递归->/ 因式 因式递归
输入:0替换:表达式->因子 项      逻辑表达式->表达式 逻辑运算符 表达式      数字->0      数字
->数字      因子->因式 因式递归      右值->表达式
输入:1替换:表达式->因子 项      逻辑表达式->表达式 逻辑运算符 表达式      数字->1      数字
->数字      因子->因式 因式递归      右值->表达式
输入:2替换:表达式->因子 项      逻辑表达式->表达式 逻辑运算符 表达式      数字->2      数字
->数字      因子->因式 因式递归      右值->表达式
输入:3替换:表达式->因子 项      逻辑表达式->表达式 逻辑运算符 表达式      数字->3      数字
->数字      因子->因式 因式递归      右值->表达式
输入:4替换:表达式->因子 项      逻辑表达式->表达式 逻辑运算符 表达式      数字->4      数字
->数字      因子->因式 因式递归      右值->表达式
输入:5替换:表达式->因子 项      逻辑表达式->表达式 逻辑运算符 表达式      数字->5      数字
->数字      因子->因式 因式递归      右值->表达式
输入:6替换:表达式->因子 项      逻辑表达式->表达式 逻辑运算符 表达式      数字->6      数字
->数字      因子->因式 因式递归      右值->表达式
输入:7替换:表达式->因子 项      逻辑表达式->表达式 逻辑运算符 表达式      数字->7      数字
->数字      因子->因式 因式递归      右值->表达式
输入:8替换:表达式->因子 项      逻辑表达式->表达式 逻辑运算符 表达式      数字->8      数字
->数字      因子->因式 因式递归      右值->表达式
输入:9替换:表达式->因子 项      逻辑表达式->表达式 逻辑运算符 表达式      数字->9      数字
->数字      因子->因式 因式递归      右值->表达式
输入:;替换:赋初值->$      项->$      因式递归->$
输入:=替换:赋初值->= 右值      逻辑运算符->=      项->$      因式递归->$
输入:CNN替换:变量->标志符      标志符->CNN      表达式->因子 项      赋值函数->变量 = 右值
函数块闭包        后缀表达式->变量 后缀运算符      逻辑表达式->表达式 逻辑运算符 表达式
变量      因子->因式 因式递归      右值->表达式
输入:RNN替换:变量->标志符      标志符->RNN      表达式->因子 项      赋值函数->变量 = 右值
函数块闭包        后缀表达式->变量 后缀运算符      逻辑表达式->表达式 逻辑运算符 表达式
变量      因子->因式 因式递归      右值->表达式
输入:a替换:变量->标志符      标志符->a      表达式->因子 项      赋值函数->变量 = 右值 ;
块闭包        后缀表达式->变量 后缀运算符      逻辑表达式->表达式 逻辑运算符 表达式      声
      因子->因式 因式递归      右值->表达式
输入:b替换:变量->标志符      标志符->b      表达式->因子 项      赋值函数->变量 = 右值 ;
块闭包        后缀表达式->变量 后缀运算符      逻辑表达式->表达式 逻辑运算符 表达式      声
      因子->因式 因式递归      右值->表达式
输入:c替换:变量->标志符      标志符->c      表达式->因子 项      赋值函数->变量 = 右值 ;
块闭包        后缀表达式->变量 后缀运算符      逻辑表达式->表达式 逻辑运算符 表达式      声
      因子->因式 因式递归      右值->表达式
输入:double替换:参数声明->声明      函数定义->类型 变量 ( 参数声明 ) { 函数块 }      函数块
  开始->函数定义      类型->double      声明->类型 变量 赋初值      声明语句->声明 ;
句闭包
输入:for替换:for循环->for ( 赋值函数 逻辑表达式 ; 后缀表达式 ) { 函数块 }      函数块闭包-
语句闭包->$
输入:int替换:参数声明->声明      函数定义->类型 变量 ( 参数声明 ) { 函数块 }      函数块->
开始->函数定义      类型->int      声明->类型 变量 赋初值      声明语句->声明 ;      声明语

输入:long替换:参数声明->声明      函数定义->类型 变量 ( 参数声明 ) { 函数块 }      函数块-
开始->函数定义      类型->long      声明->类型 变量 赋初值      声明语句->声明 ;      声明
包
输入:main替换:变量->标志符      标志符->main      表达式->因子 项      赋值函数->变量 = 右
 函数块闭包        后缀表达式->变量 后缀运算符      逻辑表达式->表达式 逻辑运算符 表达式
>变量      因子->因式 因式递归      右值->表达式
输入:regan替换:变量->标志符      标志符->regan      表达式->因子 项      赋值函数->变量 =
数 函数块闭包        后缀表达式->变量 后缀运算符      逻辑表达式->表达式 逻辑运算符 表达式
式->变量      因子->因式 因式递归      右值->表达式
输入:return替换:函数返回->return 因式 ;      函数块闭包->函数返回 函数块闭包      声明语句
输入:short替换:参数声明->声明      函数定义->类型 变量 ( 参数声明 ) { 函数块 }      函数块
 开始->函数定义      类型->short      声明->类型 变量 赋初值      声明语句->声明 ;      声
闭包
输入:void替换:参数声明->声明      函数定义->类型 变量 ( 参数声明 ) { 函数块 }      函数块-
开始->函数定义      类型->void      声明->类型 变量 赋初值      声明语句->声明 ;      声明
包
输入:}替换:函数块->声明语句闭包 函数块闭包      函数块闭包->$      声明语句闭包->$
Line1:类型->int
Line1:标识符->main
Line1:操作符->(
Line1:操作符->)
Line1:分隔符->{
语法正确
------------------
Line2:类型->int
Line2:标识符->a
Line2:操作符->=
Line2:常量->1
Line2:操作符->+
Line2:常量->2
Line2:操作符->+
Line2:操作符->(
Line2:常量->3
Line2:操作符->+
Line2:常量->1
Line2:操作符->)
Line2:分隔符->;
语法正确
------------------
Line3:关键字->for
Line3:操作符->(
Line3:标识符->regan
Line3:操作符->=
Line3:常量->0
Line3:分隔符->;
Line3:标识符->regan
Line3:操作符->=
Line3:常量->8
Line3:分隔符->;
Line3:标识符->regan
Line3:操作符->+
Line3:操作符->)
Line3:分隔符->{
语法正确
------------------
Line4:类型->int
Line4:标识符->c
Line4:操作符->=
Line4:常量->8
Line4:分隔符->;
语法正确
------------------
Line5:分隔符->}
语法正确
------------------
Line6:关键字->return
Line6:标识符->a
Line6:分隔符->;
语法正确
------------------
Line7:分隔符->}
语法正确
------------------

F:\All_C++_Pro\语法_词法分析结合\Debug\语法_词法分析结合.exe (进程 8828)已退出,代码为 0。
按任意键关闭此窗口. . .
  • 3
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 编译原理中,解文法的First、Follow和Select是非常重要的步骤。C语言可以实现这些集合的计算。 首先,需要定义一个数据结构来示文法中的符号。可以使用结构体来示,包含符号的名称和类型等信息。 然后,需要实现一个函数来计算文法中每个符号的First集合。这个函数可以使用递归下降的方法来实现,对于每个符号,递归地计算它的First集合,直到所有符号的First集合都被计算出来。 接着,可以实现一个函数来计算文法中每个符号的Follow集合。这个函数也可以使用递归下降的方法来实现,对于每个符号,递归地计算它的Follow集合,直到所有符号的Follow集合都被计算出来。 最后,可以实现一个函数来计算文法中每个产生式的Select集合。这个函数可以根据每个产生式的右部符号的First集合Follow集合来计算Select集合。 总之,使用C语言可以实现解文法的First、Follow和Select集合算法。 ### 回答2: 首先,理解一下编译原理中的一些基本定义: - 终止符:不再展开的符号,例如数字、变量、运算符等。 - 非终止符:可以展开的符号,例如if、for、while等。 - 产生式:用于示非终止符如何展开成产生式中的符号序列。 - FIRST:一个非终止符所能推导出的所有最左终止符的集合。 - FOLLOW:一个非终止符B在所有推出B的右侧(或最右侧)的符号中能推导出的所有终止符的集合。 - SELECT:一个产生式的开头符号可以推导出的所有符号的集合。 然后,根据这些定义,我们可以进行以下步骤实现解FIRST、FOLLOW和SELECT: 1. 对于每个终止符,FIRST集合就是自己本身。 2. 对于每个产生式,如果右侧第一个字符是终止符,则将该终止符加入到该非终止符的FIRST集合中;如果是非终止符,则将该非终止符的FIRST集合加入到该非终止符的FIRST集合中,直到右侧第一个字符不再是非终止符。 3. 对于每个非终止符,将FOLLOW集合初始化为空。 4. 对于每个产生式中每个非终止符,将该非终止符的FOLLOW集合加入到产生式右侧非终止符的FIRST集合中,直到该非终止符不再出现在右侧中。 5. 对于每个产生式,将该产生式右侧非终止符的FIRST集合加入到该产生式的SELECT中,如果该非终止符的FIRST集合包含空串,则将该非终止符的FOLLOW集合加入该产生式的SELECT中。 最后,通过遍历每个产生式来计算所有非终止符的FIRST、FOLLOW和SELECT集合,得出结果。需要注意的是,计算的顺序需要按照依赖关系进行。例如,需要先计算出所有产生式右侧非终止符的FIRST集合,才能计算得出某个产生式的SELECT集合。 ### 回答3: 在编译原理中,取First、Follow和Select是非常重要的话题。在C语言中,我们可以通过编写程序来实现这些集合解。 首先,我们需要了解这些集合的概念。First示一个非终结符号的第一个终结符号的集合Follow示紧跟在一个非终结符号后面的终结符号集合,而Select示一个产生式可以推导出的句子的集合。 在解这些集合时,我们需要遍历整个文法,并根据产生式推导规则和符号串之间的关系来计算。为了方便处理,我们可以将文法示为一个结构体数组,每个结构体包含产生式的左边和右边符号串的信息。 接下来,我们可以编写一个函数来计算每个非终结符号的First。该函数需要接受一个非终结符和文法结构体数组作为参数,然后递归地处理每个非终结符的First。在计算过程中,我们需要考虑该非终结符可以生成空串、终结符和其他非终结符的情况。具体实现可以使用递归或循环的方式来处理。 同样地,我们可以编写一个函数来计算每个非终结符号的Follow。该函数需要接受一个非终结符和文法结构体数组作为参数,然后递归地处理每个非终结符号的Follow。在计算过程中,我们需要考虑产生式的右边符号串中该非终结符号的出现位置和其他非终结符号的情况。具体实现可以使用递归或循环的方式来处理。 最后,我们可以编写一个函数来计算每个产生式的Select。该函数需要接受一个产生式和文法结构体数组作为参数,然后调用First和Follow函数来计算该产生式的Select。具体实现可以根据文法的分类和规则来进行判断和处理。 总之,在编译原理中,取First、Follow和Select是非常重要的任务。通过使用C语言编写程序实现这些集合解,我们可以更好地理解和掌握这一领域的知识。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

ReWz

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

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

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

打赏作者

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

抵扣说明:

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

余额充值