一个简易的四则运算单元...(15.12.15 BUG更新)
网上找的, 没有作者信息, 只能在这里感谢一下了, 支持标准写法的四则运算
--2015-12-15
修改了一个内存泄漏的BUG - Pop方法没有释放申请的内存
unit Base.Calculate; interface uses
System.SysUtils, System.Classes, System.Contnrs, System.Generics.Collections; type
TTokenType = (tkNumber, tkAdd, tkSub, tkMul, tkDiv, tkLBracket, tkRBracket); TToken = record
Token: TTokenType;
DValue: Double;
end;
PToken = ^TToken; /// <summary>
/// 解析表达式
/// </summary>
/// <param name="AInExpr">
/// 表达式字符串
/// </param>
/// <param name="AInList">
/// 解析列表输出
/// </param>
/// <returns>
/// 返回值为解析错误的字符串位置(从1开始) 如果返回值为0表示表达式正确
/// </returns>
function ParseExpression(AInExpr: String; AInList: TList<TToken>): Integer;
/// <summary>
/// 展开输出值为计算顺序描述字符
/// </summary>
/// <param name="AInList">
/// ParseExpression的输出列表
/// </param>
/// <returns>
/// 计算顺序描述字符
/// </returns>
function InsideToSuffix(AInList: TList<TToken>): String;
/// <summary>
/// 获得计算结果
/// </summary>
/// <param name="ASuExpr">
/// 计算顺序描述字符
/// </param>
/// <returns>
/// 计算结果
/// </returns>
function Evaluate(ASuExpr: String): Double; (*
Demo: var
nList: TList<TToken>;
nErrIndex: Integer;
begin
nErrIndex := ParseExpression(edtInput.Text, nList);
if nErrIndex = 0 then
edtOutput.Test := FloatToStr(Evaluate(InsideToSuffix(nList)))
else
begin
edtInput.SetFocus;
edtInput.SelStart := nErrIndex - 1;
edtInput.SelLength := 1;
end;
end;
*) implementation procedure Push(AStack: TStack; AData: String);
begin
AStack.Push(StrNew(PChar(AData)));
end; function Pop(AStack: TStack): String;
var
nP: PChar;
begin
nP := PChar(AStack.Pop);
Result := StrPas(nP);
StrDispose(nP);
end; function Peek(AStack: TStack): String;
begin
Result := StrPas(PChar(AStack.Peek));
end; function IsEmpty(AStack: TStack): Boolean;
begin
Result := AStack.Count = ;
end; function CompareSymbol(SymA, SymB: String): Boolean;
begin
Result := True;
Case SymA[] of
'*', '/':
if SymB[] in ['*', '/'] then
Result := False;
end;
end; function ParseExpression(AInExpr: String; AInList: TList<TToken>): Integer; procedure _ListAdd(const AToken: TToken);
begin
if AInList <> nil then
AInList.Add(AToken);
end; procedure _ListClear;
begin
if AInList <> nil then
AInList.Clear;
end; var
nToken: TToken;
nTemp: String;
nIsExists: Boolean;
i, nLen, nBracket: Integer;
nNextToken: set of TTokenType;
begin
i := ;
Result := ;
nBracket := ;
nLen := Length(AInExpr);
nNextToken := [tkNumber, tkLBracket];
While i <= nLen do
begin
Case AInExpr[i] of
''..'':
begin
nTemp := '';
nIsExists := False;
if not (tkNumber in nNextToken) then
begin
Result := i;
_ListClear;
Break;
end;
While i <= nLen do
begin
Case AInExpr[i] of
''..'':
nTemp := nTemp + AInExpr[i];
'.':
if nIsExists then
begin
Result := i;
i := nLen;
_ListClear;
Break;
end
else
begin
nTemp := nTemp + AInExpr[i];
nIsExists := True;
end;
else
Dec(i);
Break;
end;
Inc(i);
end;
if nTemp[Length(nTemp)] = '.' then
begin
Result := i;
_ListClear;
Break;
end;
nToken.Token := tkNumber;
nToken.DValue := StrToFloat(nTemp);
_ListAdd(nToken);
nNextToken := [tkAdd, tkSub, tkMul, tkDiv, tkRBracket];
end;
'+':
begin
if not (tkAdd in nNextToken) then
begin
Result := i;
_ListClear;
Break;
end;
nToken.Token := tkAdd;
_ListAdd(nToken);
nNextToken := [tkNumber, tkLBracket];
end;
'-':
begin
if not (tkSub in nNextToken) then
begin
Result := i;
_ListClear;
Break;
end;
nToken.Token := tkSub;
_ListAdd(nToken);
nNextToken := [tkNumber, tkLBracket];
end;
'*':
begin
if not (tkMul in nNextToken) then
begin
Result := i;
_ListClear;
Break;
end;
nToken.Token := tkMul;
_ListAdd(nToken);
nNextToken := [tkNumber, tkLBracket];
end;
'/':
begin
if not (tkDiv in nNextToken) then
begin
Result := i;
_ListClear;
Break;
end;
nToken.Token := tkDiv;
_ListAdd(nToken);
nNextToken := [tkNumber, tkLBracket];
end;
'(':
begin
if not (tkLBracket in nNextToken) then
begin
Result := i;
_ListClear;
Break;
end;
Inc(nBracket);
nToken.Token := tkLBracket;
_ListAdd(nToken);
nNextToken := [tkNumber, tkLBracket];
end;
')':
begin
if not (tkRBracket in nNextToken) then
begin
Result := i;
_ListClear;
Break;
end;
Dec(nBracket);
nToken.Token := tkRBracket;
_ListAdd(nToken);
nNextToken := [tkAdd, tkSub, tkMul, tkDiv, tkRBracket];
end;
' ':;
else
Result := i;
_ListClear;
Break;
end;
Inc(i);
end;
if nBracket > then
begin
Result := nLen;
_ListClear;
end;
end; function InsideToSuffix(AInList: TList<TToken>): String;
var
i: Integer;
nStack: TStack;
nToken: TToken;
nTemp, nSymbol: String;
begin
nTemp := '';
nStack := TStack.Create;
for i := to AInList.Count - do
begin
nToken := AInList.Items[i];
Case nToken.Token of
tkNumber:
nTemp := nTemp + FloatToStr(nToken.DValue) + ' ';
tkAdd:
if not IsEmpty(nStack) then
if Peek(nStack) = '(' then
Push(nStack, '+')
else
begin
nSymbol := Pop(nStack);
nTemp := nTemp + nSymbol + ' ';
Push(nStack, '+');
end
else
Push(nStack, '+');
tkSub:
if not IsEmpty(nStack) then
if Peek(nStack) = '(' then
Push(nStack, '-')
else
begin
nSymbol := Pop(nStack);
nTemp := nTemp + nSymbol + ' ';
Push(nStack, '-');
end
else
Push(nStack, '-');
tkMul:
if not IsEmpty(nStack) then
begin
nSymbol := Peek(nStack);
if nSymbol = '(' then
Push(nStack, '*')
else if CompareSymbol('*', nSymbol) then
Push(nStack, '*')
else
begin
nSymbol := Pop(nStack);
nTemp := nTemp + nSymbol + ' ';
Push(nStack, '*');
end;
end
else
Push(nStack, '*');
tkDiv:
if not IsEmpty(nStack) then
begin
nSymbol := Peek(nStack);
if nSymbol = '(' then
Push(nStack, '/')
else if CompareSymbol('/', nSymbol) then
Push(nStack, '/')
else
begin
nSymbol := Pop(nStack);
nTemp := nTemp + nSymbol + ' ';
Push(nStack, '/');
end;
end
else
Push(nStack, '/');
tkLBracket:
Push(nStack, '(');
tkRBracket:
while nStack.Count > do
begin
nSymbol := Pop(nStack);
if nSymbol = '(' then
Break;
nTemp := nTemp + nSymbol + ' ';
end;
end;
end;
for i := to nStack.Count do
begin
nSymbol := Pop(nStack);
nTemp := nTemp + nSymbol + ' ';
end;
nStack.Free;
Result := Trim(nTemp);
end; function Evaluate(ASuExpr: String): Double;
var
nTemp: String;
nStack: TStack;
i, nLen: Integer;
nTempA, nTempB, nResult: Double;
begin
i := ;
nLen := Length(ASuExpr);
nStack := TStack.Create;
try
While i <= nLen do
begin
Case ASuExpr[i] of
''..'':
begin
nTemp := '';
While i <= nLen do
begin
if ASuExpr[i] in [''..'', '.'] then
nTemp := nTemp + ASuExpr[i]
else
begin
Dec(i);
Break;
end;
Inc(i);
end;
Push(nStack, nTemp);
end;
'+':
begin
nTempA := StrToFloat(Pop(nStack));
nTempB := StrToFloat(Pop(nStack));
nResult := nTempB + nTempA;
Push(nStack, FloatToStr(nResult));
end;
'-':
begin
nTempA := StrToFloat(Pop(nStack));
nTempB := StrToFloat(Pop(nStack));
nResult := nTempB - nTempA;
Push(nStack, FloatToStr(nResult));
end;
'*':
begin
nTempA := StrToFloat(Pop(nStack));
nTempB := StrToFloat(Pop(nStack));
nResult := nTempB * nTempA;
Push(nStack, FloatToStr(nResult));
end;
'/':
begin
nTempA := StrToFloat(Pop(nStack));
nTempB := StrToFloat(Pop(nStack));
nResult := nTempB / nTempA;
Push(nStack, FloatToStr(nResult));
end;
end;
Inc(i);
end;
Result := StrToFloat(Pop(nStack));
finally
nStack.Free;
end;
end; end.
一个简易的四则运算单元...(15.12.15 BUG更新)的更多相关文章
- 基于OpenGL编写一个简易的2D渲染框架-12 重构渲染器-BlockAllocator
BlockAllocator 的内存管理情况可以用下图表示 整体思路是,先分配一大块内存 Chunk,然后将 Chunk 分割成小块 Block.由于 Block 是链表的一个结点,所以可以通过链表的 ...
- 2021.12.15 P2328 [SCOI2005]超级格雷码(找规律填空)
2021.12.15 P2328 [SCOI2005]超级格雷码(找规律填空) https://www.luogu.com.cn/problem/P2328 题意: 输出n位B进制的格雷码. 分析: ...
- Tencent Cloud Developers Conference(2018.12.15)
时间:2018.12.15地点:北京朝阳悠唐皇冠假日酒店
- WPF 使用鼠标拖动一个控件的实现[2018.7.15]
原文:WPF 使用鼠标拖动一个控件的实现[2018.7.15] Q:已经把一个Shape和一个TextBlock组合起来放到了一个Grid中,现在想要实现用鼠标拖动这个Grid到任意位置的功能,如何做 ...
- javascript基础修炼(12)——手把手教你造一个简易的require.js
目录 一. 概述 二. require.js 2.1 基本用法 2.2 细说API设计 三. 造轮子 3.1 模块加载执行的步骤 3.2 代码框架 3.3 关键函数的代码实现 示例代码托管在我的代码仓 ...
- .NET Core的文件系统[5]:扩展文件系统构建一个简易版“云盘”
FileProvider构建了一个抽象文件系统,作为它的两个具体实现,PhysicalFileProvider和EmbeddedFileProvider则分别为我们构建了一个物理文件系统和程序集内嵌文 ...
- 做了一个简易的git 代码自动部署脚本
做了一个简易的git 代码自动部署脚本 http://my.oschina.net/caomenglong/blog/472665 发表于2个月前(2015-06-30 21:08) 阅读(200 ...
- simple-todo: 一个简易的 todo 程序 - django版
今天无意间看到 simple-todo: 一个简易的 todo 程序 - web.py 中文教程 ,然后发现竟然有好多的版本 http://simple-is-better.com/news/tag ...
- 手写一个简易的多周期 MIPS CPU
一点前言 多周期 CPU 相比单周期 CPU 以及流水线 CPU 实现来说其实写起来要麻烦那么一些,但是相对于流水线 CPU 和单周期 CPU 而言,多周期 CPU 除了能提升主频之外似乎并没有什么卵 ...
随机推荐
- Spring读写xml文件
一.如果只是读取 新建一个 xml 文件,需要满足Spring格式: <?xml version="1.0" encoding="UTF-8"?> ...
- Android 小笔记
<!-- xml --> android:visibility="gone" 可以隐藏 元素 xmlns:bootstrapbu ...
- python之sys模块详解
python之sys模块详解 sys模块功能多,我们这里介绍一些比较实用的功能,相信你会喜欢的,和我一起走进python的模块吧! sys模块的常见函数列表 sys.argv: 实现从程序外部向程序传 ...
- Mac常用终端命令
一.基本命令 1.列出文件 ls 参数 目录名 例: 看看驱动目录下有什么:ls /System/Library/Extensions 参数 -w 显示中文,-l 详细信息, -a 包括 ...
- 给定n,a求最大的k,使n!可以被a^k整除但不能被a^(k+1)整除。
题目描述: 给定n,a求最大的k,使n!可以被a^k整除但不能被a^(k+1)整除. 输入: 两个整数n(2<=n<=1000),a(2<=a<=1000) 输出: 一个整数. ...
- 微软的R语言发行版本MRO及开发工具RTVS
(此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 题记:微软在收购R语言的开发商后,也独立发行或在自己的产品中集成了R语言,这里就介绍下它们包 ...
- 在Jenkins中获取GitHub对应Repository的Resource Code
1):Install Jenkins 请看如下链接: https://wiki.jenkins-ci.org/display/JENKINS/Installing+Jenkins 2):Install ...
- nfs的挂载方法
对于很多嵌入式驱动开发者,要进行很多次调试,如果nfs搭建不起来,那么对开发是很不方便的.经过三天,我终于把自己编的内核下载到开发板,并实现了nfs文件系统的挂载.今天把过程写下来. 思路 一 编译a ...
- 转:WCF、WebAPI、WCFREST、WebService之间的区别
WCF.WebAPI.WCFREST.WebService之间的区别 注明:转载 在.net平台下,有大量的技术让你创建一个HTTP服务,像Web Service,WCF,现在又出了Web API ...
- PHP 数据库操作类:ezSQL
EZSQL类介绍: 下载地址:http://www.jb51.net/codes/26393.htmlezsql是一个小型的快速的数据库操作类,可以让你很容易地用PHP操作各种数据库( MySQL.o ...