用C++设计简单算数表达式语法分析器算法;(LR来实现)输入表达式不带#号,输出为TRue或者False

时间: 2024-01-24 22:17:54 浏览: 80
LR(1) 算法可以用于实现简单算数表达式语法分析器。下面是一个用 C++ 设计的算法实现: ```c++ #include <iostream> #include <string> #include <stack> #include <map> #include <vector> using namespace std; const int MAXN = 1000; // 符号类别 enum TokenType { TOKEN_PLUS, // + TOKEN_MINUS, // - TOKEN_MULTIPLY, // * TOKEN_DIVIDE, // / TOKEN_LPAREN, // ( TOKEN_RPAREN, // ) TOKEN_NUMBER // 数字 }; // 符号项 struct Token { TokenType type; // 符号类别 int value; // 数字值 }; // LR(1) 项 struct LR1Item { int production; // 产生式编号 int dot; // 点的位置 vector<int> lookahead; // 向前看符号 }; // 产生式 struct Production { TokenType left; // 左部 vector<TokenType> right; // 右部 }; // LR(1) 项目集族 vector<vector<LR1Item>> item_sets; // ACTION 表 map<pair<int, TokenType>, pair<char, int>> action; // GOTO 表 map<pair<int, TokenType>, int> goto_table; // 产生式序列 vector<Production> productions = { {TOKEN_NUMBER, {TOKEN_NUMBER}}, {TOKEN_NUMBER, {TOKEN_NUMBER, TOKEN_PLUS, TOKEN_NUMBER}}, {TOKEN_NUMBER, {TOKEN_NUMBER, TOKEN_MINUS, TOKEN_NUMBER}}, {TOKEN_NUMBER, {TOKEN_NUMBER, TOKEN_MULTIPLY, TOKEN_NUMBER}}, {TOKEN_NUMBER, {TOKEN_NUMBER, TOKEN_DIVIDE, TOKEN_NUMBER}}, {TOKEN_NUMBER, {TOKEN_LPAREN, TOKEN_NUMBER, TOKEN_RPAREN}} }; // 符号优先级表 int priority_table[MAXN][MAXN] = { // + - * / ( ) number { 1, 1, -1, -1, -1, 1, -1}, // + { 1, 1, -1, -1, -1, 1, -1}, // - { 1, 1, 1, 1, -1, 1, -1}, // * { 1, 1, 1, 1, -1, 1, -1}, // / {-1, -1, -1, -1, -1, 0, -1}, // ( { 1, 1, 1, 1, -1, 1, -1}, // ) {-1, -1, -1, -1, -1, -1, 0} // number }; // 将符号转化为字符串 string tokenToString(TokenType type) { switch (type) { case TOKEN_PLUS: return "+"; case TOKEN_MINUS: return "-"; case TOKEN_MULTIPLY: return "*"; case TOKEN_DIVIDE: return "/"; case TOKEN_LPAREN: return "("; case TOKEN_RPAREN: return ")"; case TOKEN_NUMBER: return "number"; default: return ""; } } // 判断一个符号是否为终结符 bool isTerminal(TokenType type) { return type == TOKEN_PLUS || type == TOKEN_MINUS || type == TOKEN_MULTIPLY || type == TOKEN_DIVIDE || type == TOKEN_LPAREN || type == TOKEN_RPAREN || type == TOKEN_NUMBER; } // 计算表达式的值 int calculate(vector<Token> tokens) { stack<int> value_stack; stack<TokenType> op_stack; for (size_t i = 0; i < tokens.size(); i++) { Token token = tokens[i]; if (token.type == TOKEN_NUMBER) { value_stack.push(token.value); } else { while (!op_stack.empty() && priority_table[op_stack.top()][token.type] >= 0) { TokenType op = op_stack.top(); op_stack.pop(); int b = value_stack.top(); value_stack.pop(); int a = value_stack.top(); value_stack.pop(); switch (op) { case TOKEN_PLUS: value_stack.push(a + b); break; case TOKEN_MINUS: value_stack.push(a - b); break; case TOKEN_MULTIPLY: value_stack.push(a * b); break; case TOKEN_DIVIDE: value_stack.push(a / b); break; } } if (token.type == TOKEN_RPAREN) { op_stack.pop(); } else { op_stack.push(token.type); } } } while (!op_stack.empty()) { TokenType op = op_stack.top(); op_stack.pop(); int b = value_stack.top(); value_stack.pop(); int a = value_stack.top(); value_stack.pop(); switch (op) { case TOKEN_PLUS: value_stack.push(a + b); break; case TOKEN_MINUS: value_stack.push(a - b); break; case TOKEN_MULTIPLY: value_stack.push(a * b); break; case TOKEN_DIVIDE: value_stack.push(a / b); break; } } return value_stack.top(); } // 获取产生式字符串 string productionToString(Production production) { string result = tokenToString(production.left) + " ->"; for (size_t i = 0; i < production.right.size(); i++) { result += " " + tokenToString(production.right[i]); } return result; } // 获取 LR(1) 项目字符串 string lr1ItemToString(LR1Item item) { string result = productionToString(productions[item.production]) + ", dot = " + to_string(item.dot); result += ", lookahead = { "; for (size_t i = 0; i < item.lookahead.size(); i++) { result += tokenToString(item.lookahead[i]) + " "; } result += "}"; return result; } // 获取项目集字符串 string itemSetToString(int index) { string result = "{\n"; for (size_t i = 0; i < item_sets[index].size(); i++) { result += " " + lr1ItemToString(item_sets[index][i]) + "\n"; } result += "}"; return result; } // 获取 ACTION 表字符串 string actionTableToString() { string result = "ACTION TABLE:\n"; for (auto it = action.begin(); it != action.end(); it++) { int state = it->first.first; TokenType token = it->first.second; char action_type = it->second.first; int action_param = it->second.second; result += " [" + to_string(state) + ", " + tokenToString(token) + "] = "; if (action_type == 's') { result += "SHIFT " + to_string(action_param) + "\n"; } else if (action_type == 'r') { result += "REDUCE " + productionToString(productions[action_param]) + "\n"; } else if (action_type == 'a') { result += "ACCEPT\n"; } } return result; } // 获取 GOTO 表字符串 string gotoTableToString() { string result = "GOTO TABLE:\n"; for (auto it = goto_table.begin(); it != goto_table.end(); it++) { int state = it->first.first; TokenType symbol = it->first.second; int next_state = it->second; result += " [" + to_string(state) + ", " + tokenToString(symbol) + "] = " + to_string(next_state) + "\n"; } return result; } // 初始化符号项 void initItem(Token token, vector<int>& lookahead, vector<LR1Item>& items) { for (size_t i = 0; i < productions.size(); i++) { Production production = productions[i]; if (production.left == token.type) { LR1Item item; item.production = i; item.dot = 0; item.lookahead = lookahead; items.push_back(item); } } } // 计算闭包 void closure(vector<LR1Item>& items) { bool changed = true; while (changed) { changed = false; for (size_t i = 0; i < items.size(); i++) { LR1Item item = items[i]; if (item.dot < productions[item.production].right.size() && !isTerminal(productions[item.production].right[item.dot])) { TokenType symbol = productions[item.production].right[item.dot]; vector<int> lookahead = item.lookahead; if (item.dot + 1 < productions[item.production].right.size()) { lookahead.clear(); lookahead.push_back(productions[item.production].right[item.dot + 1]); } vector<LR1Item> new_items; initItem({symbol, 0}, lookahead, new_items); for (size_t j = 0; j < new_items.size(); j++) { if (find(items.begin(), items.end(), new_items[j]) == items.end()) { items.push_back(new_items[j]); changed = true; } } } } } } // 计算转移 void gotoState(vector<LR1Item> items, TokenType symbol, vector<LR1Item>& new_items) { for (size_t i = 0; i < items.size(); i++) { LR1Item item = items[i]; if (item.dot < productions[item.production].right.size() && productions[item.production].right[item.dot] == symbol) { LR1Item new_item = item; new_item.dot++; new_items.push_back(new_item); } } closure(new_items); } // 计算项目集族 void calculateItemSets() { vector<LR1Item> initial_items; initItem({TOKEN_NUMBER, 0}, {TOKEN_NUMBER}, initial_items); closure(initial_items); item_sets.push_back(initial_items); bool changed = true; while (changed) { changed = false; for (size_t i = 0; i < item_sets.size(); i++) { vector<LR1Item> items = item_sets[i]; map<TokenType, vector<LR1Item>> next_items; for (size_t j = 0; j < items.size(); j++) { LR1Item item = items[j]; if (item.dot < productions[item.production].right.size()) { TokenType symbol = productions[item.production].right[item.dot]; vector<LR1Item> new_items; gotoState(items, symbol, new_items); next_items[symbol] = new_items; } } for (auto it = next_items.begin(); it != next_items.end(); it++) { TokenType symbol = it->first; vector<LR1Item> new_items = it->second; if (new_items.size() > 0 && find(item_sets.begin(), item_sets.end(), new_items) == item_sets.end()) { item_sets.push_back(new_items); changed = true; goto_table[{i, symbol}] = item_sets.size() - 1; } } } } } // 计算 ACTION 表和 GOTO 表 void calculateTables() { for (size_t i = 0; i < item_sets.size(); i++) { vector<LR1Item> items = item_sets[i]; for (size_t j = 0; j < items.size(); j++) { LR1Item item = items[j]; if (item.dot == productions[item.production].right.size()) { if (item.production == 0) { action[{i, TOKEN_NUMBER}] = {'a', 0}; } else { for (size_t k = 0; k < item.lookahead.size(); k++) { TokenType lookahead = item.lookahead[k]; if (action.count({i, lookahead}) > 0) { cout << "ERROR: Reduce-Reduce conflict!\n"; return; } else { action[{i, lookahead}] = {'r', item.production}; } } } } } for (auto it = productions.begin(); it != productions.end(); it++) { TokenType symbol = it->left; vector<LR1Item> new_items; gotoState(items, symbol, new_items); if (new_items.size() > 0) { int j = find(item_sets.begin(), item_sets.end(), new_items) - item_sets.begin(); goto_table[{i, symbol}] = j; } } for (size_t j = 0; j < items.size(); j++) { LR1Item item = items[j]; if (item.dot < productions[item.production].right.size()) { TokenType symbol = productions[item.production].right[item.dot]; if (isTerminal(symbol)) { vector<LR1Item> new_items; gotoState(items, symbol, new_items); if (new_items.size() > 0) { int j = find(item_sets.begin(), item_sets.end(), new_items) - item_sets.begin(); if (action.count({i, symbol}) > 0) { cout << "ERROR: Shift-Reduce conflict!\n"; return; } else { action[{i, symbol}] = {'s', j}; } } } } } } } // 将表达式转化为符号串 vector<Token> expressionToTokens(string expr) { vector<Token> tokens; int i = 0; while (i < expr.length()) { if (isdigit(expr[i])) { int j = i; while (j < expr.length() && isdigit(expr[j])) { j++; } tokens.push_back({TOKEN_NUMBER, stoi(expr.substr(i, j - i))}); i = j; } else if (expr[i] == '+') { tokens.push_back({TOKEN_PLUS, 0}); i++; } else if (expr[i] == '-') { tokens.push_back({TOKEN_MINUS, 0}); i++; } else if (expr[i] == '*') { tokens.push_back({TOKEN_MULTIPLY, 0}); i++; } else if (expr[i] == '/') { tokens.push_back({TOKEN_DIVIDE, 0}); i++; } else if (expr[i] == '(') { tokens.push_back({TOKEN_LPAREN, 0}); i++; } else if (expr[i] == ')') { tokens.push_back({TOKEN_RPAREN, 0}); i++; } else { i++; } } return tokens; } // 使用算法分析表达式 bool analyzeExpression(string expr) { vector<Token> tokens = expressionToTokens(expr); tokens.push_back({TOKEN_NUMBER, 0}); stack<int> state_stack; stack<TokenType> symbol_stack; state_stack.push(0); symbol_stack.push(TOKEN_NUMBER); size_t i = 0; while (!state_stack.empty()) { int state = state_stack.top(); TokenType symbol = symbol_stack.top(); if (action.count({state, symbol}) == 0) { return false; } char action_type = action[{state, symbol}].first; int action_param = action[{state, symbol}].second; if (action_type == 's') { state_stack.push(action_param); symbol_stack.push(symbol); state_stack.push(0); symbol_stack.push(tokens[i].type); i++; } else if (action_type == 'r') { Production production = productions[action_param]; for (size_t j = 0; j < production.right.size(); j++) { state_stack.pop(); symbol_stack.pop(); } int top_state = state_stack.top(); TokenType top_symbol = symbol_stack.top(); if (goto_table.count({top_state, production.left}) == 0) { return false; } int next_state = goto_table[{top_state, production.left}]; state_stack.push(next_state); symbol_stack.push(production.left); } else if (action_type == 'a') { return true; } else { return false; } } return false; } int main() { calculateItemSets(); calculateTables(); cout << actionTableToString() << endl; cout << gotoTableToString() << endl; string expr; cout << "Enter an expression: "; cin >> expr; if (analyzeExpression(expr)) { vector<Token> tokens = expressionToTokens(expr); cout << "Result: " << calculate(tokens) << endl; } else { cout << "ERROR: Invalid expression!\n"; } return 0; } ``` 这里使用了一个简单的算数表达式语法,只包含加、减、乘、除和括号运算,并且没有考虑优先级和结合性。算法输出 ACTION 表和 GOTO 表,并且可以解析输入的表达式并计算其值。
阅读全文

相关推荐

最新推荐

recommend-type

基于算符优先分析方法的表达式语法分析器

基于算符优先分析方法的表达式语法分析器是计算机科学中的一种语法分析技术,旨在对表达式进行语法分析,以确保表达式的正确性和合法性。该技术基于算符优先分析方法,即根据算符的优先级来确定表达式的语法结构。 ...
recommend-type

无符号数的算术四则运算LR语法分析器设计实现

无符号数的算术四则运算LR语法分析器设计实现 本资源是一个基于C++的编译原理实验,旨在设计、编制和调试一个典型的语法分析程序,以实现对无符号数的算术四则运算的语法检查和结构分析。 一、实验目的与要求 该...
recommend-type

表达式语法分析器 编译原理实验报告

在本实验报告中,我们关注的是“表达式语法分析器”的设计与实现,这涉及到编译原理中的核心概念——LL(1)语法分析。实验的主要目的是让学生熟悉如何设计和实现一个LL(1)语法分析器,同时理解其工作原理。 首先,...
recommend-type

编译原理实验报告——表达式语法分析

【编译原理实验报告——表达式语法分析】 ...总结,本次实验报告详细介绍了如何设计和实现一个递归下降的表达式语法分析器,涵盖了编译原理中的基本概念和技术,有助于提升学生在编译技术方面的理论知识和实践能力。
recommend-type

编译原理实验报告 表达式语法分析设计

实验目的是通过设计和实现一个表达式的语法分析器来熟悉这一过程。这涉及到形式语言的基础知识,包括文法运算,以及四种常见的语法分析方法:递归下降分析、LL(1)分析、简单优先分析和SLR(1)分析。 首先,递归下降...
recommend-type

C语言数组操作:高度检查器编程实践

资源摘要信息: "C语言编程题之数组操作高度检查器" C语言是一种广泛使用的编程语言,它以其强大的功能和对低级操作的控制而闻名。数组是C语言中一种基本的数据结构,用于存储相同类型数据的集合。数组操作包括创建、初始化、访问和修改元素以及数组的其他高级操作,如排序、搜索和删除。本资源名为“c语言编程题之数组操作高度检查器.zip”,它很可能是一个围绕数组操作的编程实践,具体而言是设计一个程序来检查数组中元素的高度。在这个上下文中,“高度”可能是对数组中元素值的一个比喻,或者特定于某个应用场景下的一个术语。 知识点1:C语言基础 C语言编程题之数组操作高度检查器涉及到了C语言的基础知识点。它要求学习者对C语言的数据类型、变量声明、表达式、控制结构(如if、else、switch、循环控制等)有清晰的理解。此外,还需要掌握C语言的标准库函数使用,这些函数是处理数组和其他数据结构不可或缺的部分。 知识点2:数组的基本概念 数组是C语言中用于存储多个相同类型数据的结构。它提供了通过索引来访问和修改各个元素的方式。数组的大小在声明时固定,之后不可更改。理解数组的这些基本特性对于编写有效的数组操作程序至关重要。 知识点3:数组的创建与初始化 在C语言中,创建数组时需要指定数组的类型和大小。例如,创建一个整型数组可以使用int arr[10];语句。数组初始化可以在声明时进行,也可以在之后使用循环或单独的赋值语句进行。初始化对于定义检查器程序的初始状态非常重要。 知识点4:数组元素的访问与修改 通过使用数组索引(下标),可以访问数组中特定位置的元素。在C语言中,数组索引从0开始。修改数组元素则涉及到了将新值赋给特定索引位置的操作。在编写数组操作程序时,需要频繁地使用这些操作来实现功能。 知识点5:数组高级操作 除了基本的访问和修改之外,数组的高级操作包括排序、搜索和删除。这些操作在很多实际应用中都有广泛用途。例如,检查器程序可能需要对数组中的元素进行排序,以便于进行高度检查。搜索功能用于查找特定值的元素,而删除操作则用于移除数组中的元素。 知识点6:编程实践与问题解决 标题中提到的“高度检查器”暗示了一个具体的应用场景,可能涉及到对数组中元素的某种度量或标准进行判断。编写这样的程序不仅需要对数组操作有深入的理解,还需要将这些操作应用于解决实际问题。这要求编程者具备良好的逻辑思维能力和问题分析能力。 总结:本资源"c语言编程题之数组操作高度检查器.zip"是一个关于C语言数组操作的实际应用示例,它结合了编程实践和问题解决的综合知识点。通过实现一个针对数组元素“高度”检查的程序,学习者可以加深对数组基础、数组操作以及C语言编程技巧的理解。这种类型的编程题目对于提高编程能力和逻辑思维能力都有显著的帮助。
recommend-type

管理建模和仿真的文件

管理Boualem Benatallah引用此版本:布阿利姆·贝纳塔拉。管理建模和仿真。约瑟夫-傅立叶大学-格勒诺布尔第一大学,1996年。法语。NNT:电话:00345357HAL ID:电话:00345357https://theses.hal.science/tel-003453572008年12月9日提交HAL是一个多学科的开放存取档案馆,用于存放和传播科学研究论文,无论它们是否被公开。论文可以来自法国或国外的教学和研究机构,也可以来自公共或私人研究中心。L’archive ouverte pluridisciplinaire
recommend-type

【KUKA系统变量进阶】:揭秘从理论到实践的5大关键技巧

![【KUKA系统变量进阶】:揭秘从理论到实践的5大关键技巧](https://giecdn.blob.core.windows.net/fileuploads/image/2022/11/17/kuka-visual-robot-guide.jpg) 参考资源链接:[KUKA机器人系统变量手册(KSS 8.6 中文版):深入解析与应用](https://wenku.csdn.net/doc/p36po06uv7?spm=1055.2635.3001.10343) # 1. KUKA系统变量的理论基础 ## 理解系统变量的基本概念 KUKA系统变量是机器人控制系统中的一个核心概念,它允许
recommend-type

如何使用Python编程语言创建一个具有动态爱心图案作为背景并添加文字'天天开心(高级版)'的图形界面?

要在Python中创建一个带动态爱心图案和文字的图形界面,可以结合使用Tkinter库(用于窗口和基本GUI元素)以及PIL(Python Imaging Library)处理图像。这里是一个简化的例子,假设你已经安装了这两个库: 首先,安装必要的库: ```bash pip install tk pip install pillow ``` 然后,你可以尝试这个高级版的Python代码: ```python import tkinter as tk from PIL import Image, ImageTk def draw_heart(canvas): heart = I
recommend-type

基于Swift开发的嘉定单车LBS iOS应用项目解析

资源摘要信息:"嘉定单车汇(IOS app).zip" 从标题和描述中,我们可以得知这个压缩包文件包含的是一套基于iOS平台的移动应用程序的开发成果。这个应用是由一群来自同济大学软件工程专业的学生完成的,其核心功能是利用位置服务(LBS)技术,面向iOS用户开发的单车共享服务应用。接下来将详细介绍所涉及的关键知识点。 首先,提到的iOS平台意味着应用是为苹果公司的移动设备如iPhone、iPad等设计和开发的。iOS是苹果公司专有的操作系统,与之相对应的是Android系统,另一个主要的移动操作系统平台。iOS应用通常是用Swift语言或Objective-C(OC)编写的,这在标签中也得到了印证。 Swift是苹果公司在2014年推出的一种新的编程语言,用于开发iOS和macOS应用程序。Swift的设计目标是与Objective-C并存,并最终取代后者。Swift语言拥有现代编程语言的特性,包括类型安全、内存安全、简化的语法和强大的表达能力。因此,如果一个项目是使用Swift开发的,那么它应该会利用到这些特性。 Objective-C是苹果公司早前主要的编程语言,用于开发iOS和macOS应用程序。尽管Swift现在是主要的开发语言,但仍然有许多现存项目和开发者在使用Objective-C。Objective-C语言集成了C语言与Smalltalk风格的消息传递机制,因此它通常被认为是一种面向对象的编程语言。 LBS(Location-Based Services,位置服务)是基于位置信息的服务。LBS可以用来为用户提供地理定位相关的信息服务,例如导航、社交网络签到、交通信息、天气预报等。本项目中的LBS功能可能包括定位用户位置、查找附近的单车、计算骑行路线等功能。 从文件名称列表来看,包含的三个文件分别是: 1. ios期末项目文档.docx:这份文档可能是对整个iOS项目的设计思路、开发过程、实现的功能以及遇到的问题和解决方案等进行的详细描述。对于理解项目的背景、目标和实施细节至关重要。 2. 移动应用开发项目期末答辩.pptx:这份PPT文件应该是为项目答辩准备的演示文稿,里面可能包括项目的概览、核心功能演示、项目亮点以及团队成员介绍等。这可以作为了解项目的一个快速入门方式,尤其是对项目的核心价值和技术难点有直观的认识。 3. LBS-ofo期末项目源码.zip:这是项目的源代码压缩包,包含了完成单车汇项目所需的全部Swift或Objective-C代码。源码对于理解项目背后的逻辑和实现细节至关重要,同时也是评估项目质量、学习最佳实践、复用或扩展功能的基础。 综合上述信息,"嘉定单车汇(IOS app).zip"不仅仅是一个应用程序的压缩包,它还代表了一个团队在软件工程项目中的完整工作流程,包含了项目文档、演示材料和实际编码,为学习和评估提供了一个很好的案例。