#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include "Stack/GcStack.h"
#include "StandardValue/ConstValue.h"
#include "WordAnalysis/WordAnalysis.h"
#include "Queue/GCQueue.h"
#define INPUT_MAX_LENGTH 100
#define TOKEN_LENGTH 100
#define DEBUG
// 建立一些全局变量
GCQueue myQueue;
Element element;
char token[TOKEN_LENGTH];
char *pToken=token;//用于制定token当前位置
int tokenType=GC_NO_CONTENT;
void ShowDebugInfo(char *msg);
void ResetToken();
void ShowTip();
int main(void)
{
ShowTip();
char inputWords[INPUT_MAX_LENGTH];
memset(inputWords,0,sizeof(inputWords));
printf("请输入要计算的公式,按回车键结束:\n");
scanf("%s",inputWords);
printf("输入的公式是:%s\n",inputWords);
// 创建一个队列
if(InitQueue(&myQueue)==GC_ERROR)
{
exit(-3);
}
// 创建一个临时元素
memset(token,0,sizeof(token));
// 开始分析字符串
char *pNow=inputWords;// 用于制定当前分析位置
char cNow;
float fltValue=0;
printf("开始分析字符串...\n");
// 先压入一个起始符
element.Type=1;
element.Value.Opt='#';
if(EnQueue(&myQueue, &element)!=GC_OK)
{
exit(GC_ERROR);
}
while(*pNow!='\0')
{
cNow=*pNow;
if(IsDigital(cNow))
{
if(tokenType==GC_NO_CONTENT || tokenType==GC_NUMBER)
{
*pToken=cNow;
pToken++;
tokenType=GC_NUMBER;
}
else
{
ResetToken();
}
}
else if(IsCharacter(cNow))
{
if(tokenType==GC_NO_CONTENT || tokenType==GC_FUNCTION)
{
*pToken=cNow;
pToken++;
tokenType=GC_FUNCTION;
}
else
{
ResetToken();
}
}
else
{
// 检测token中是否有内容,有的话转换、存储内容
if(strlen(token)>0)
{
ResetToken();
}
if(IsOpt(cNow)==GC_OK)
{
element.Type=GC_INSTRUCTION;
element.Value.Opt=cNow;
if(EnQueue(&myQueue, &element)!=GC_OK)
{
exit(GC_ERROR);
}
}
}
pNow++;
}
// 最后检测一个堆栈中是否还有数字
if(strlen(token)>0)
{
ResetToken();
}
// 最后压入一个结束符
element.Type=1;
element.Value.Opt='#';
if(EnQueue(&myQueue, &element)!=GC_OK)
{
exit(GC_ERROR);
}
printf("显示字符串分析结果...\n");
// 显示堆栈中的内容
EnumQueueElement(&myQueue);
printf("开始进行公式计算...\n\n");
// 建立两个栈,一个存操作符,一个存数字
GCStack optStack;
GCStack noStack;
InitStack(&optStack);
InitStack(&noStack);
if(DeQueue(&myQueue,&element)!=GC_OK)
{
exit(-1);
}
StackPush(&optStack,&element);
if(DeQueue(&myQueue,&element)!=GC_OK)
{
exit(-1);
}
Element eleInStack;
Element eleX;
Element a;
Element b;
Element result;
GetStackTop(optStack,&eleInStack);
while((element.Type!=GC_INSTRUCTION || element.Value.Opt!='#') || \
(eleInStack.Value.Opt!='#' ))
{
if(element.Type==GC_NUMBER)
{
StackPush(&noStack,&element);
if(DeQueue(&myQueue,&element)!=GC_OK)
{
exit(-1);
}
}
else
{
//switch(CompareOpt(eleInStack.Value.Opt,element.Value.Opt))
int compareResult=CompareOptWithFunc(eleInStack.Type,eleInStack.Value.Opt,element.Type,element.Value.Opt);
switch(compareResult)
{
case -1:// 栈顶元素优先权低
StackPush(&optStack,&element);
if(DeQueue(&myQueue,&element)!=GC_OK)
{
exit(-1);
}
break;
case 0:// 等号关系肯定是括号,脱括号并接收下一个字符
StackPop(&optStack,&eleX);
if(DeQueue(&myQueue,&element)!=GC_OK)
{
exit(-1);
}
break;
case 1:
// 这里先分为两类来处理,目前的函数都是一元函数
StackPop(&optStack,&eleX);
switch(eleX.Type)
{
case GC_INSTRUCTION:
StackPop(&noStack,&a);
StackPop(&noStack,&b);
result.Type=GC_NUMBER;
result.Value.Number=Operate(b.Value.Number,eleX.Value.Opt, \
a.Value.Number);
StackPush(&noStack,&result);
break;
case GC_FUNCTION:
StackPop(&noStack,&a);
result.Type=GC_NUMBER;
result.Value.Number=FuncOperate(eleX.Value.FuncIndex,a.Value.Number);
StackPush(&noStack,&result);
break;
}
break;
}
GetStackTop(optStack,&eleInStack);
}
}
// 显示结果
printf("现在显示计算结果...\n");
EnumStackElement(&noStack);
ClearStack(&noStack);
ClearStack(&optStack);
ClearQueue(&myQueue);
return 0;
}
void ResetToken()
{
if(strlen(token)>0)
{
switch(tokenType)
{
case GC_NUMBER:
element.Type=GC_NUMBER;
element.Value.Number=(float)atof(token);
if(EnQueue(&myQueue, &element)!=GC_OK)
{
exit(GC_ERROR);
}
break;
case GC_FUNCTION:
element.Type=GC_FUNCTION;
element.Value.FuncIndex=IsSupportedFunc(token);
if(element.Value.FuncIndex<0 || EnQueue(&myQueue, &element)!=GC_OK)
{
exit(GC_ERROR);
}
break;
}
// 重置信息
memset(token,0,sizeof(token));
pToken=token;
tokenType=GC_NO_CONTENT;
}
}
void ShowDebugInfo(char *msg)
{
#ifdef DEBUG
printf("[DEBUG]:%s.......\n",msg);
#endif
}
void ShowTip()
{
printf("\n");
printf("\n");
printf("==================================\n");
printf("简单公式计算程序 version 1.0\n");
printf("目前仅支持数字和六种操作符:\n");
printf("+、-、*、/、(、)\n");
printf("输入简单的公式进行结果计算,公式长度最好不超过100个字符\n");
printf("==================================\n");
printf("\n");
printf("\n");
}
MathCalculateV2.zip
需积分: 0 22 浏览量
更新于2021-07-15
收藏 27KB ZIP 举报
《C语言实现简单表达式求值程序解析》
在编程领域,C语言因其高效、灵活和广泛的应用而备受青睐。本篇文章将详细探讨一个用C语言编写的名为"MathCalculateV2"的简单表达式求值程序。这个程序旨在解析并计算用户输入的数学表达式,从而提供一个方便的计算工具。
一、C语言基础
C语言是一种结构化编程语言,它的语法简洁明了,执行效率高。在这个项目中,C语言被用来实现表达式的解析和计算。这涉及到变量定义、函数声明、运算符使用等基本概念。程序员需要对C语言的数据类型、控制结构(如if-else,for,while循环)以及函数调用有深入理解。
二、表达式求值
表达式求值是计算机科学中的一个核心概念,它涉及到算术运算、比较运算和逻辑运算。在这个程序中,"MathCalculateV2"可能采用了递归下降解析(Recursive Descent Parsing)的方法来解析表达式。这种方法通过自顶向下的方式逐层分解表达式,直到解析出最小的运算单元,然后进行运算。
三、表达式解析
在C语言中,处理用户输入的字符串表达式需要进行字符串操作,如字符串拷贝、比较、查找等。表达式解析通常包括以下几个步骤:
1. 分词(Tokenization):将输入的字符串分割成一个个有意义的单元,如数字、运算符、括号等。
2. 语法分析(Syntax Analysis):检查这些单元是否符合语法规则,形成语法树。
3. 语义分析(Semantic Analysis):根据语法树进行计算,确定表达式的值。
四、中缀表达式与后缀表达式
常见的表达式求值方法有两种:中缀表达式(常规的运算符在操作数之间)和后缀表达式(也称为逆波兰表示法,运算符在操作数之后)。后缀表达式求值相对简单,因为它避免了优先级和括号的问题。"MathCalculateV2"可能使用了后缀表达式的方式来解析和计算,因为这种方式更利于栈数据结构的运用。
五、栈数据结构
在处理后缀表达式时,栈数据结构扮演了关键角色。栈是一种“后进先出”(LIFO)的数据结构,适用于处理运算符的优先级。当遇到操作数时,将其压入栈;遇到运算符时,取出栈顶的操作数进行运算,并将结果压回栈中。当表达式结束时,栈顶的元素即为最终结果。
六、错误处理
在实际应用中,程序需要能够处理各种异常情况,如无效的表达式、除以零、溢出等问题。"MathCalculateV2"可能会包含一套错误检测和处理机制,确保在遇到这些问题时能给出适当的反馈。
总结,"MathCalculateV2"是一个基于C语言的简单表达式求值程序,它利用了C语言的强大功能和灵活性,通过解析和计算用户输入的数学表达式,实现了计算工具的功能。通过对字符串的处理、表达式的解析和栈数据结构的运用,该程序展示了计算机科学中的一些基本原理和技巧。理解并掌握这些知识点对于提升C语言编程能力和解决实际问题具有重要意义。

gc_2299
- 粉丝: 2609
最新资源
- 用于车身控制模块的单片机和本地互连网络的作用.docx
- 综合性学习《我们的互联网时代》ppt课件1.ppt
- 社会网络分析-凝聚子群PPT课件.ppt
- 计算机操作员填空题及答案.doc
- 基于单片机的智能小车文献综述(超详细).doc
- 高中数学1.循环结构的程序框图的算法公开课获奖课件.pptx
- 智能无线网络WIA产品及其解决方案探析.doc
- 基因工程及其应用教案{公开课).doc
- 神经网络-第二章-单层前向网络及LMS算法.ppt
- 网络优化部绩效考核实施办法.doc
- 软件课程设计员工信息管理系统.doc
- 软件工程方法与实践课后答案.pdf
- 职位说明书(Job-Description)模板.doc
- 互联网展示类广告新趋势-从买媒体到买人群-互联网新趋势.doc
- 是网络录像带租赁系统是基于收入共享的观念.pptx
- 非标自动化电气设计流程与规范标准详.doc