【实验目的】
(1)理解语法分析在编译程序中的作用,以及它与词法分析程序的关系 (2)加深对递归下降语法分析原理的理解 (3)掌握递归下降语法分析的实现方法
【实验内容】
编制一个递归下降分析程序,实现对词法分析程序提供的单词序列的语法检查和结构分析。
【实验要求】
(1)待分析的简单语言的词法同实验 1
(2)待分析的简单语言的语法 用扩充的 BNF 表示如下:
1)::=beginend、 2) ::={;} 、3) ::= 、4) ::=ID:= 、5) ::={+|-}、
6) ::={*|/} 、7) ::=ID|NUM|()
(3)语法分析程序的功能 输入单词串以”#”结束,如果是文法正确的句子,输出成功信息;否则输出错误信息。
例如: 输入 begin a:=9; x:=2 * 3; b:=a + x end # 输出 success
输入 x:=a + b * c end # 输出 error
【实验代码】
实验二是在实验一的基础上进行的,只需对实验一的头文件稍作修改,再加入一点语法判断即可。
下面的三个文件都需要,根据实验要求对不需要的代码做注释即可
做了修改的实验一的头文件.hpp
#ifndef TEST_HPP_2_1
#define TEST_HPP_2_1
#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <algorithm>
#include <cctype>
#include "2.2_test.hpp"
std::unordered_map<std::string, int> TOKEN_MAPPING = {
{"begin", 1},
{"if", 2},
{"then", 3},
{"while", 4},
{"do", 5},
{"end", 6},
{"letter(letter|digit)*", 10},
{"digitdigit*", 11},
{"+", 13},
{"-", 14},
{"*", 15},
{"/", 16},
{":", 17},
{":=", 18},
{"<", 20},
{"<>", 21},
{"<=", 22},
{">", 23},
{">=", 24},
{"=", 25},
{";", 26},
{"(", 27},
{")", 28},
{"#", 0}};
// 函数声明
bool isLetter(char c);
bool isDigit(char c);
bool isOperator(char c);
bool isDelimiter(char c);
bool isValidIdentifierChar(char c);
bool isAssignmentOperator(const std::string &token);
// 逻辑函数实现
std::vector<int> Scanner(std::string input)
{
std::vector<int> v;
for (size_t i = 0; i < input.size(); ++i)
{
char c = input[i];
if (isspace(c)) // Skip whitespace
continue;
else if (isLetter(c)) // Variable or keyword
{
std::string token = "";
while (i < input.size() && isValidIdentifierChar(input[i]))
token += input[i++];
--i; // 循环中增加了i,这里需要减回来
auto it = TOKEN_MAPPING.find(token);
if (it != TOKEN_MAPPING.end())
{
std::cout << "(" << it->second << ", " << token << ") ";
v.push_back(it->second);
}
else
{
std::cout << "(" << TOKEN_MAPPING["letter(letter|digit)*"] << ", " << token << ") ";
v.push_back(TOKEN_MAPPING["letter(letter|digit)*"]);
}
}
else if (isDigit(c)) // Number
{
std::string token = "";
while (i < input.size() && isDigit(input[i]))
token += input[i++];
--i; // 循环中增加了i,这里需要减回来
std::cout << "(" << TOKEN_MAPPING["digitdigit*"] << ", " << token << ") ";
v.push_back(TOKEN_MAPPING["digitdigit*"]);
}
else if (isOperator(c) || c == ':') // Operator or start of assignment operator
{
std::string token = "";
token += c;
if (c == ':' && i + 1 < input.size() && input[i + 1] == '=')
token += input[++i]; // 捕获 :=
if (c == '<' || c == '>')
if (i + 1 < input.size() && input[i + 1] == '=')
token += input[++i]; // Capture <= or >=
auto it = TOKEN_MAPPING.find(token);
if (it != TOKEN_MAPPING.end())
{
std::cout << "(" << it->second << ", " << token << ") ";
v.push_back(it->second);
}
}
else if (isDelimiter(c)) // Delimiter
{
std::string token = "";
token += c;
std::cout << "(" << TOKEN_MAPPING[token] << ", " << token << ") ";
v.push_back(TOKEN_MAPPING[token]);
}
}
std::cout << "\nProgram ended." << std::endl;
Print(v);
return v;
}
// 函数定义
bool isLetter(char c)
{
return std::isalpha(c);
}
bool isDigit(char c)
{
return std::isdigit(c);
}
bool isOperator(char c)
{
return c == '+' || c == '-' || c == '*' || c == '/' || c == '>' || c == '<';
}
bool isDelimiter(char c)
{
return c == '(' || c == ')' || c == ';' || c == '#';
}
bool isValidIdentifierChar(char c)
{
return isLetter(c) || isDigit(c);
}
bool isAssignmentOperator(const std::string &token)
{
return token == ":=";
}
#endif // TEST_HPP_2_1
实验二要求的语法分析的头文件.hpp
#ifndef TEST_HPP_2_2
#define TEST_HPP_2_2
#include <vector>
#include <iostream>
std::vector<std::vector<int>> splitSegments(const std::vector<int> &input, int delimiter);
void Print(std::vector<int> v);
void PrintTwo(std::vector<std::vector<int>> segments);
bool Assign(std::vector<int> row);
bool check_alternate(const std::vector<int> &num, int data, const std::vector<int> &sequence);
bool Yucu(std::vector<int> v)
{
if (v[0] != 1 || v[v.size() - 1] != 0 || v[v.size() - 2] != 6)
return false;
// 弹出首元素
v.erase(v.begin());
// 弹出两个尾元素
v.pop_back();
v.pop_back();
// Print(v);
int delimiter = 26;
// 调用函数将输入数据分割成多个段(用;分隔语句)
std::vector<std::vector<int>> segments = splitSegments(v, delimiter);
// PrintTwo(segments);
// 逐句检查
// 赋值语句: 找值为18的元素,且前面只有一个元素为10,后面为表达式 √ 只实现这个应付实验足矣
// 分支语句:找到if2,直接用then3进行分段,如果then3前面没有if2,则语句出错
// 表达式语句: 特征就是没有赋值符18,只有运算符和数字11间隔出现,没有变量10
// 比较语句: 出现[20,25](不包括21)且不为首尾的表达式语句,和表达式语句类似
for (const auto &row : segments)
{
for (int num : row)
{
// if (num == 2) // 分支语句
// return IsIfThen(row);
if (num == 18) // 赋值语句
return Assign(row);
}
}
return true;
}
// // 判断是否为if...then...语句
// bool IsIfThen(std::vector<int> row)
// {
// // 没有then(3)就不会分段
// std::vector<std::vector<int>> IfThen = splitSegments(row, 3);
// PrintTwo(IfThen);
// }
// 判断是否为赋值语句
bool Assign(std::vector<int> row)
{
if (row.size() <= 2 || row[0] != 10)
return false;
std::vector<int> num = {13, 14, 15, 16};
int data = 11;
return check_alternate(num, data, row);
}
// 数字和运算符是否交叉出现
bool check_alternate(const std::vector<int> &num, int data, const std::vector<int> &sequence)
{
if (num.empty() || sequence.empty())
return false;
bool is_num_turn = true; // 表示当前轮到数字11
size_t index = 0;
for (int i = 0; i < sequence.size(); ++i)
if (sequence[i] == data)
if (is_num_turn)
is_num_turn = false;
else
return false;
else
{
if (index < i && sequence[index] == sequence[i])
return false;
index = i;
}
return !is_num_turn;
}
// 遍历vector
void Print(std::vector<int> v)
{
std::cout << "Elements:";
for (int elem : v)
std::cout << " " << elem;
std::cout << std::endl;
}
// 打印分组的二维 vector
void PrintTwo(std::vector<std::vector<int>> segments)
{
std::cout << "Remaining elements:" << std::endl;
for (const auto &row : segments)
{
for (int num : row)
std::cout << num << " ";
std::cout << std::endl;
}
}
std::vector<std::vector<int>> splitSegments(const std::vector<int> &input, int delimiter)
{
std::vector<std::vector<int>> segments;
std::vector<int> segment;
for (int num : input)
{
if (num == delimiter)
{
// 如果遇到分隔符,则将当前段存储到结果中,并开始一个新段
if (!segment.empty())
{
segments.push_back(segment);
segment.clear();
}
}
else
{
// 将数字添加到当前段中
segment.push_back(num);
}
}
// 将最后一个段添加到结果中(如果它不为空)
if (!segment.empty())
{
segments.push_back(segment);
}
return segments;
}
#endif // TEST_HPP_2_2
实验二的逻辑函数源文件.cpp
#include "2.1_test.hpp"
#include "2.2_test.hpp"
#include <iostream>
using namespace std;
int main()
{
string prog;
do
{
cout << "Please input string: ";
getline(cin, prog);
if (prog.length() >= 2 && prog[prog.length() - 1] != '#')
cout << "\nInput string should end with '#'." << endl;
else
{
vector<int> vector = Scanner(prog);
if (Yucu(vector))
cout << "\nsuccess" << endl;
else
cout << "\nerror" << endl;
}
} while (prog.length() < 2 || prog[prog.length() - 1] != '#');
return 0;
}
// begin x:=9;if x>0 then x:=2*x+1/3;end#
// 输入 begin a:=9; x:=2 * 3; b:=a + x end #
// 输出 success
// 输入 x:=a + b * c end #
// 输出 error