一、程序描述
在理解编译原理基本思想的基础上,选择一个自己熟悉的程序设计语言,完成编译程序的设计和实现过程。
编译程序的设计可以采用自顶向下和自底向上两种不同的方法。由于许多高级语言(如PASCAL,C)中的语法成分都是递归定义的,所以本实习要求学生采用递归下降分析技术,这是一种自顶向下的的编译方法,其基本思想是对语言的每个(或若干个)语法成分编制一个处理子程序,从处理<程序>这个语法成分的子程序开始,在分析过程中调用一系列过程或函数,对源程序进行语法和语义分析,直到整个源程序处理完毕为止。
本上机实习是为C语言(子集)设计一个编译程序,完成词法分析、语法分析、语义分析等功能,并生成某种机器上的目标代码(汇编语言)或中间代码(四元式)。
二、功能
(1)词法分析
扫描源程序,根据词法规则,识别单词,填写相应的表。如果产生词法错误,则显示错误信息、位置,并试图从错误中恢复。简单的恢复方法是忽略该字符(或单词)继续扫描。
(2)语法分析
对源程序作语法分析,确定是否属于C语言小子集,同时揭示出程序的内在结构。
(3)语法错误检查
根据C语言小子集的文法规则设置检测手段,通过查错子程序或一些查错语句,报告源程序出错位置、性质等,直至整个程序结束为止。
(4)语义分析与目标代码生成
在语法分析的基础上,进行语义分析,生成输入源程序的目标代码。输入源程序的目标代码可以建立在一个假想的处理机(虚拟机)上,或者以所学的汇编语言为基础,也可以生成四元式序列。
三、C语言小子集的文法规则
注:文法规则灰色部分代表存在左递归,需要对其进行消除左递归操作,使其变为LL(1)文法。
红色部分较为简单,默认已解决,本文不做过多介绍
<程序>::=main(){<分程序>}
<分程序>::=<变量说明部分>;<语句部分>
<变量说明部分>::=<变量说明><标识符表>
<变量说明>::=int
<标识符表>::=<标识符表>,<标识符>
<标识符表>::=<标识符>
<标识符>::=<字母>
<标识符>::=<标识符><字母>
<标识符>::=<标识符><数字>
<语句部分>::=<语句部分>;<语句>|<语句>
<语句>::=<赋值语句>|<条件语句>|<循环语句>|
<赋值语句>::=<标识符>=<表达式>
<条件>::=<表达式><关系运算符><表达式>
<表达式>::=<项>|<表达式><加法运算符><项>
<项>::=<因子>|<项><乘法运算符><因子>
<因子>::=<标识符>|<常量>|(<表达式>)
<常量>::=<无符号整数>
<无符号整数>::=<数字序列>
<数字序列>::=<数字序列><数字>
<数字序列>::=<数字>
<加法运算符>::=+|-
<乘法运算符>::=*|/
<关系运算符>::=<|>|!=|>=|<=|==
<复合语句>::={<语句部分>}
<语句1>::=<语句>|<复合语句>
<条件语句>::=if(<条件>)<语句1>else<语句1>
<循环语句>::=while(<条件>)do<语句1>
<字母>::=a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z
<数字>::=0|1|2|3|4|5|6|7|8|9
四、代码部分
我将代码需要实现的功能都封装在不同的类里,最后在进行调用而达到实现功能的目标。
Word.hpp:词法分析
Grammar.hpp.:语法分析
Semantic.hpp:四元式
main.cpp:运行程序
input.txt:存入要分析的程序
首先是词法分析功能:
#include <iostream>
#include <fstream>
using namespace std;
string word[200]; //^ 存放单词的表
string value[2][100]; //^存放变量的表
int length = 0; //数组a有效内容的长度
string beauty[200]; //^美化后的代码
static int len = 0;
int ke = 0;
string keep[100];
/*
& 保留字 1~6
& 运算符 7~16
& 分隔符 17~22
& 标识符 23
& 数字 24
*/
int keyWord(string s); //*返回保留字编号
int symOperator(string s); //*返回运算符编号
int symSeparator(string s); //*返回分隔符编号
int typeOfWord(string s); //*当前字符类型
void printWord(string s, int n); //*词法分析打印
void toword(); //*取单词
int keyWord(string s)
{
string sym[6] = {"main", "int", "if", "else", "while", "do"};
for (int i = 0; i < 6; i++)
{
if (s == sym[i])
return i + 1;
}
return 0;
}
int symOperator(string s)
{
string sym[10] = {">=", "<=", "!=", "==", "+", "-", "*", "/", ">", "<"};
for (int i = 0; i < 10; i++)
{
if (s == sym[i])
return i + 7;
}
return 0;
}
int symSeparator(string s)
{
string separator[7] = {",", ";", "(", ")", "{", "}", " "};
for (int i = 0; i < 6; i++)
{
if (s == separator[i])
return i + 17;
}
return 0;
}
int typeOfWord(string s)
{
/*
& 1 字母
& 2 数字
& 3 运算符
& 4 分隔符
*/
if (s >= "a" && s <= "z")
{
return 1;
}
else if (s >= "0" && s <= "9")
{
return 2;
}
else if (s == "+" || s == "-" || s == "*" || s == "/" || s == ">" || s == "<" || s == "!" || s == "=")
{
return 3;
}
else if (s == "," || s == ";" || s == "(" || s == ")" || s == "{" || s == "}" || s == " ")
{
return 4;
}
return 0;
}
void printWord(string s, int n)
{
char *b = (char *)s.c_str();
cout << "{ " << b << " , " << n << " }" << endl;
}
void toword()
{
char c; //暂时保存当前字符
char a[1000]; //一个数组,保存取出来的字符
int count = 0;
int k; //用来返回当前单个字符的类型
char *p; //指针
p = a;
string str, ch; //str用于保存获取的单词,ch指向当前字符
str = "";
int id = 0; //word[]的有效长度
int obj = 17;
int op = 0; //第几个运算符,用于接收前两位正确的运算符
int row = 1; //统计第几行,用于显示出错
//! 获取txt文本内的内容,把内容放到char里
ifstream infile;
string file = "input.txt";
//! 将文件流对象与文件连接起来
infile.open(file.data());
infile >> noskipws;
while (!infile.eof())
{
infile >> c;
a[length] = c; //! 把文件的内容放到数组里
// cout << a[length]; //! 用来测试输入内容是否成功
length++;
}
//!识别单词
// ~ 待解决:只输入单个的字符
for (int i = 0; i < length; i++)
{
ch = *(p + i);
k = typeOfWord(ch);
string last, next;
last = *(p + i - 1); //前一位字符
next = *(p + i + 1); //后一位字符
if (ch == "\n")
{
row++;
if (str != "")
{
word[id] = str;
word[id + 1] = ch;
id += 2;
}
else
{
word[id] = ch;
id += 1;
}
str = "";
}
switch (k)
{
case 1:
{
if (typeOfWord(last) == 1 || typeOfWord(last) == 3 || typeOfWord(last) == 4 || str == "")
{
str += ch;
}
else
{
char *b = (char *)ch.c_str();
char *s = (char *)str.c_str();
cout << "Error:第" << row << "行 在" << s << " 后加入 " << b << " 不符合文法规则\n";
}
break;
}
case 2:
{
str += ch;
break;
}
case 3:
{
if (typeOfWord(last) != 3 && typeOfWord(next) != 3) //?单个的运算符
{
if (str != "")
{
word[id] = str;
word[id + 1] = ch;
id += 2;
str = "";
}
else
{
word[id] = ch;
id++;
}
}
else if (typeOfWord(last) != 3 && typeOfWord(next) == 3) //?连续运算符的第一个运算符
{
if (str != "")
{
word[id] = str;
word[id + 1] = ch;
id++;
str = "";
}
else
{
word[id] = ch;
}
op++;
}
else if (typeOfWord(last) == 3 && typeOfWord(next) == 3)
{
op++;
if (op <= 2)
{
word[id] += ch;
id++;
}
else
{
char *b = (char *)ch.c_str();
char *s = (char *)str.c_str();
cout << "Error:第" << row << "行 在 " << s << " 后加入运算符:" << b << "导致运算符非法\n";
}
}
else if (typeOfWord(last) == 3 && typeOfWord(next) != 3) //?最后一个运算符
{
op++;
if (op == 2)
{
word[id] += ch;
id++;
}
else
{
char *b = (char *)ch.c_str();
char *s = (char *)str.c_str();
cout << "Error:第" << row << "行 在 " << s << " 后加入运算符:" << b << "导致运算符非法\n";
}
op = 0;
}
break;
}
case 4:
{
if (ch == " ")
{
if (str != "") //?除掉连续空格的影响
{
word[id] = str;
id++;
str = "";
}
}
else if (str != "") //?单个的分界符,保存str,保存当前的ch
{
word[id] = str;
word[id + 1] = ch;
id += 2;
str = "";
}
else //?连续的分界符,str为空,保存当前的ch
{
word[id] = ch;
id++;
}
}
default:
{
break;
}
}
}
//! 对word[]进行打印
// for (int i = 0; i < id; i++)
// {
// string t;
// t = word[i];
// char *b = (char *)t.c_str();
// if (t == "\n")
// {
// cout << i << " \\n"
// << endl;
// }
// else
// {
// cout << i << " " << b << endl;
// }
// //cout << b <<" ";
// }
infile.close(); //关闭文件输入流
cout << "词法分析完成" << endl;
}
void beBeauty()
{
int od = 0;
for (int i = 0; i < length; i++)
{
string a = word[i];
int k = typeOfWord(a);
switch (k)
{
case 1:
{
if (keyWord(a) == 4 || keyWord(a) == 6)
{
beauty[len] = "\n";
len++;
for (int j = 0; j < od; j++)
{
beauty[len + j] = "\t";
}
len += od;
beauty[len] = a;
beauty[len + 1] = " ";
len += 2;
}
else if (keyWord(a))
{
beauty[len] = a;
beauty[len + 1] = " ";
len += 2;
}
else
{
beauty[len] = a;
len++;
}
break;
}
case 2:
{
beauty[len] = a;
len++;
break;
}
case 3:
{
beauty[len] = " ";
beauty[len + 1] = a;
beauty[len + 2] = " ";
len += 3;
break;
}
case 4:
if (symSeparator(a) == 17)
{
beauty[len] = a;
beauty[len + 1] = " ";
len += 2;
}
else if (symSeparator(a) == 18)
{
beauty[len] = a;
beauty[len + 1] = "\n";
len += 2;
for (int j = 0; j < od; j++)
{
beauty[len + j] = "\t";
}
len += od;
}
else if (symSeparator(a) == 19)
{
beauty[len] = a;
len++;
}
else if (symSeparator(a) == 20)
{
beauty[len] = a;
beauty[len + 1] = " ";
len += 2;
}
else if (symSeparator(a) == 21)
{
beauty[len] = "\n";
len++;
for (int j = 0; j < od; j++)
{
beauty[len + j] = "\t";
}
len += od;
beauty[len] = a;
beauty[len + 1] = "\n";
len += 2;
od++;
for (int j = 0; j < od; j++)
{
beauty[len + j] = "\t";
}
len += od;
}
else if (symSeparator(a) == 22)
{
beauty[len] = "\n";
len++;
od--;
for (int j = 0; j < od; j++)
{
beauty[len + j] = "\t";
}
len += od;
beauty[len + 1] = a;
len += 2;
}
default:
break;
}
}
}
void printBeauty()
{
beBeauty();
cout << "美化后的代码:\n";
for (int i = 0; i < len; i++)
{
char *e = (char *)beauty[i].c_str();
cout << e;
}
}
完成了词法分析,就要对其进行语法分析,用递归下降的方式来做
#include <iostream>
#include <fstream>
#include <stack>
#include <string>
#include <cstring>
#include "Word.hpp"
#include "Semantic.hpp"
using namespace std;
static int num = 0; //^单词个数
static int rows = 1; //^行数
static int v_num = 0; //^变量个数
void Program(); //*程序
void Prase(); //*分程序
void Variable_description_part(); //*变量说明部分
void Variable_description(); //*变量说明
void Identity_table(); //*标识符表
void Identity(); //*标识符
void sIdentity(); //*子标识符
void Statement_part(); //*语句部分
void Statament(); //*语句
void sStatament(); //*子语句
void Statament_1(); //*语句1
void Condition(); //*条件
void Compound_statament(); //*复合语句
void Item(); //*项
void Divisor(); //*因子
void Subitem(); //*子项
void Expression(); //*表达式
void sExpression();
void Loop_statament(); //*循环语句
void Condition_statament(); //*条件语句
void Assignment_statament(); //*赋值语句
void MatchToken(string s);
bool RelationOperator(); //*关系运算符
bool AddOperator(); //*加法运算表
bool MultiplyOperator(); //*乘法运算表
void variable(); //*变量声明表
void AddRow(); //*格式
void printText(); //*查看当前字符
void printVar(); //*打印变量
stack<string> Stack1; //*赋值语句 操作数栈
stack<string> Stack2; //*赋值语句 操作符栈
stack<int> Stack3; //*循环语句 记录栈
void aStruct();
//& **********************************************************************
//& **********************************************************************
void MatchToken(string s)
{
if (word[num] == s)
{
num++;
}
else
{
char *b = (char *)s.c_str();
cout << "Error:第" << rows << "行出错,缺少 " << b << "\n";
}
}
void AddRow()
{
while (word[num] == "\n")
{
rows++;
num++;
}
}
void variable()
{
string a = word[num];
char *b = (char *)a.c_str();
int k = 1;
for (int i = 0; i < v_num; i++)
{
if (word[num] == value[0][i])
{
k = 0;
break;
}
}
if (k)
{
value[0][v_num] = word[num];
value[1][v_num] = "0";
v_num++;
}
else
{
cout << "Error:第" << rows << "行出错," << b << " 已经被声明过了\n";
}
}
void printVar()
{
//! 打印value表
for (int i = 0; i < v_num; i++)
{
string v = value[0][i];
char *e = (char *)v.c_str();
cout << i << " " << e << endl;
}
}
void printText()
{
string s = word[num];
char *b = (char *)s.c_str();
cout << b << endl;
}
void aStruct()
{
if (MultiplyOperator() || AddOperator())
{
se[yuan].s2 = Stack1.top();
Stack1.pop();
se[yuan].s1 = Stack1.top();
Stack1.pop();
se[yuan].result = tmp[temp];
Stack1.push(se[yuan].result);
se[yuan].opra = Stack2.top();
Stack2.pop();
temp++;
yuan++;
}
else
{
se[yuan].s2 = Stack1.top();
Stack1.pop();
se[yuan].s1 = Stack1.top();
Stack1.pop();
if (Stack2.size() == 1)
{
se[yuan].result = Stack1.top();
}
else
{
se[yuan].result = tmp[temp];
Stack1.push(se[yuan].result);
temp++;
}
se[yuan].opra = Stack2.top();
Stack2.pop();
yuan++;
}
}
void wStruct()
{
se[yuan].s2 = Stack1.top();
Stack1.pop();
se[yuan].s1 = Stack1.top();
Stack1.pop();
se[yuan].opra = Stack2.top();
Stack2.pop();
yuan++;
}
void Identity()
{
string a = word[num];
char *b = (char *)a.c_str();
// cout << b << endl;
if (a >= "a" && a <= "z")
{
if (v_num == 0)
{
value[0][0] = word[num];
value[1][0] == "0";
v_num++;
}
}
else
{
cout << "Error:第" << rows << "行出错," << b << " 不是一个合法的标识符\n";
}
num++;
}
void sIdentity()
{
// <子标识符表>::=,<标识符><子标识符表>|ε
if (word[num] == ",")
{
num++;
variable();
Identity();
sIdentity();
}
}
bool MultiplyOperator()
{
string op[2] = {
"*",
"/"};
for (int i = 0; i < 2; i++)
{
if (word[num] == op[i])
{
break;
}
else if (word[num] != op[i] && i == 1)
{
return false;
}
}
return true;
}
bool AddOperator()
{
string op[2] = {
"+",
"-"};
for (int i = 0; i < 2; i++)
{
if (word[num] == op[i])
{
break;
}
else if (i == 1)
{
return false;
}
}
return true;
}
bool RelationOperator()
{
string op[6] = {
"<=",
">=",
"!=",
"==",
"<",
">"};
for (int i = 0; i < 6; i++)
{
if (word[num] == op[i])
{
break;
}
else if (i == 6)
{
return false;
}
}
return true;
}
void Subitem()
{
// <子项>::=<乘法运算符><因子><子项>|ε
if (MultiplyOperator())
{
Stack2.push(word[num]);
num++;
Divisor();
aStruct();
Subitem();
}
else
{
}
}
void Divisor()
{
// <因子>::=<标识符>|<常量>|(<表达式>
if (word[num] >= "a" && word[num] <= "z")
{
Stack1.push(word[num]);
for (int i = 0; i < v_num; i++)
{
//! 打印变量表
// string t = value[0][i];
// char *b = (char *)t.c_str();
// cout << b << endl;
if (word[num] == value[0][i])
{
break;
}
else if (word[num] != value[0][i] && i == v_num - 1)
{
string s = word[num];
char *b = (char *)s.c_str();
cout << "Error:第" << rows << "行,没有声明过 " << b << " 这个变量\n";
}
}
Identity();
}
else if (word[num] >= "0" && word[num] <= "9")
{
Stack1.push(word[num]);
num++;
}
else if (word[num] == "(")
{
MatchToken("(");
Expression();
MatchToken(")");
}
else
{
string s = word[num];
char *b = (char *)s.c_str();
cout << "Error:第" << rows << "行 " << b << " 不是合法的因子\n";
}
}
void Item()
{
// <项>::=<因子><子项>
Divisor();
Subitem();
}
void sExpression()
{
// <子表达式>::=<加法运算符><项><子表达式>|ε
if (AddOperator())
{
Stack2.push(word[num]);
num++;
Item();
aStruct();
sExpression();
}
else
{
}
}
void Expression()
{
// <表达式>::= <项> <子表达式>
Item();
sExpression();
}
void Assignment_statament()
{
// <赋值语句>::=<标识符>=<表达式>
for (int i = 0; i < v_num; i++)
{
if (word[num] == value[0][i])
{
break;
}
else if (word[num] != value[0][i] && i == v_num - 1)
{
string s = word[num];
char *b = (char *)s.c_str();
cout << "Error:第" << rows << "行,没有声明过 " << b << " 这个变量\n";
}
}
Stack1.push(word[num]);
Identity();
MatchToken("=");
Expression();
if (word[num - 2] == "=")
{ //! a=b
se[yuan].s1 = Stack1.top();
Stack1.pop();
se[yuan].result = Stack1.top();
Stack1.pop();
yuan++;
}
AddRow();
}
void Condition_statament()
{
// if(<条件>)<语句1>else<语句1>
num++;
MatchToken("(");
Stack1.push(tmp[temp]);
temp++;
Stack3.push(yuan);
Condition();
MatchToken(")");
AddRow();
Statament_1();
AddRow();
int r1 = yuan;
yuan++;
MatchToken("else");
string r = "GOTO(" + to_string(yuan) + ")";
se[Stack3.top()].result = r;
Stack3.pop();
AddRow();
Statament_1();
se[r1].opra = "GOTO(" + to_string(yuan) + ")";
AddRow();
}
void Loop_statament()
{
num++;
MatchToken("(");
Stack1.push(tmp[temp]);
temp++;
Condition();
MatchToken(")");
AddRow();
MatchToken("do");
AddRow();
Statament_1();
string r = "GOTO(" + to_string(yuan + 1) + ")";
se[Stack3.top()].result = r;
Stack3.pop();
string rt = "GOTO(" + to_string(Stack3.top()) + ")";
se[yuan].opra = rt;
yuan++;
}
void Statament_1()
{
// <语句>|<复合语句>
if (word[num] == "{")
{
Compound_statament();
}
else
{
Statament();
}
}
void Compound_statament()
{
// {<语句部分>}
MatchToken("{");
AddRow();
Statament();
sStatament();
MatchToken("}");
}
void Condition()
{
// <表达式><关系运算符><表达式>
Stack3.push(yuan);
Expression();
if (RelationOperator())
{
if (word[num] == ">")
{
Stack2.push("<=");
}
else if (word[num] == "<")
{
Stack2.push(">=");
}
else if (word[num] == "==")
{
Stack2.push("!=");
}
else if (word[num] == "!=")
{
Stack2.push("==");
}
else if (word[num] == ">=")
{
Stack2.push("<");
}
else if (word[num] == "<=")
{
Stack2.push(">");
}
num++;
}
else
{
string t = word[num];
char *b = (char *)t.c_str();
cout << "Error:第" << rows << "行," << b << "不是关系运算符\n";
}
Expression();
Stack3.push(yuan);
wStruct();
}
void Statament()
{
AddRow();
// <语句>::=<赋值语句>|<条件语句>|<循环语句>|
if (word[num] == "while")
{
Loop_statament();
}
else if (word[num] == "if")
{
Condition_statament();
}
else if (word[num] >= "a" && word[num] <= "z")
{
Assignment_statament();
}
else
{
string s = word[num];
char *b = (char *)s.c_str();
cout << "Error:第" << rows << "行, " << b << " 前没有语句\n";
}
}
void sStatament()
{
// <子语句部分>:: = ;<语句><子语句部分> | ε
if (word[num] == ";")
{
MatchToken(";");
AddRow();
Statament();
sStatament();
}
else
{
AddRow();
}
}
void Statement_part()
{
Statament();
sStatament();
}
void Identity_table()
{
// <标识符表>::=<标识符><子标识符表>
Identity();
sIdentity();
}
void Variable_description()
{
// <变量说明>::=int
AddRow();
if (word[num] != "int")
{
cout << "Error:第" << rows << "行缺少变量说明 int \n";
}
else
{
num++;
}
}
void Variable_description_part()
{ // <变量说明部分>::=<变量说明><标识符表>
Variable_description();
Identity_table();
}
//^分程序
void Prase()
{
// <分程序>::=<变量说明部分>;<语句部分>
Variable_description_part();
MatchToken(";");
Statement_part();
}
void Program()
{
// <程序>::=main(){<分程序>}
toTep();
toword();
if (word[num] == "main")
{
num++;
if (word[num] == "(")
{
num++;
if (word[num] == ")")
{
num++;
AddRow();
if (word[num] == "{")
{
num++;
AddRow();
Prase();
AddRow();
if (word[num] != "}")
{
cout << "Error:第" << rows << "行出错,缺少:}\n";
}
else
{
cout << "语法分析完成" << endl;
}
}
else
{
cout << "Error:第" << rows << "行出错,缺少 {\n";
}
}
else
{
cout << "Error:第" << rows << "行出错,缺少 )\n";
}
}
else
{
cout << "Error:第" << rows << "行出错,缺少 (\n";
}
}
else
{
cout << "Error:第" << rows << "行出错,缺少 main\n";
}
}
下面是四元式,这个类里主要是写结构体和打印四元式的方法,而四元式的主要生产部分主要在上一个代码里完成,在完成递归下降的过程中到合适的时候就输出四元式。
#include <iostream>
using namespace std;
int temp = 0;
string tmp[100]; //*四元式中间变量
static int yuan = 0; //^四元式个数
struct Semantic
{
string opra = "=";
string s1 = "/";
string s2 = "/";
string result = "/";
} se[100];
void toTep()
{
for (int i = 0; i < 100; i++)
{
tmp[i] = "t" + to_string(i);
}
}
void printSemantic()
{
for (int i = 0; i < yuan; i++)
{
char *o = (char *)se[i].opra.c_str();
char *s1 = (char *)se[i].s1.c_str();
char *s2 = (char *)se[i].s2.c_str();
char *r = (char *)se[i].result.c_str();
cout << "(" << i << ")"
<< " (" << o << ","
<< s1 << ","
<< s2 << ","
<< r << ")\n";
}
}
main.cpp:
#include <iostream>
#include <fstream>
#include "Grammar.hpp"
using namespace std;
int main()
{
Program();
printSemantic();
// printBeauty();
return 0;
}
当然后续有时间我会更详尽的写各代码用到的思路是什么,告诉大家我为什么这么写。如果不想深究为什么这么写,直接复制代码拿来用就可以了。