网上找的, 没有作者信息, 只能在这里感谢一下了, 支持标准写法的四则运算

--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更新)的更多相关文章

  1. 基于OpenGL编写一个简易的2D渲染框架-12 重构渲染器-BlockAllocator

    BlockAllocator 的内存管理情况可以用下图表示 整体思路是,先分配一大块内存 Chunk,然后将 Chunk 分割成小块 Block.由于 Block 是链表的一个结点,所以可以通过链表的 ...

  2. 2021.12.15 P2328 [SCOI2005]超级格雷码(找规律填空)

    2021.12.15 P2328 [SCOI2005]超级格雷码(找规律填空) https://www.luogu.com.cn/problem/P2328 题意: 输出n位B进制的格雷码. 分析: ...

  3. Tencent Cloud Developers Conference(2018.12.15)

    时间:2018.12.15地点:北京朝阳悠唐皇冠假日酒店

  4. WPF 使用鼠标拖动一个控件的实现[2018.7.15]

    原文:WPF 使用鼠标拖动一个控件的实现[2018.7.15] Q:已经把一个Shape和一个TextBlock组合起来放到了一个Grid中,现在想要实现用鼠标拖动这个Grid到任意位置的功能,如何做 ...

  5. javascript基础修炼(12)——手把手教你造一个简易的require.js

    目录 一. 概述 二. require.js 2.1 基本用法 2.2 细说API设计 三. 造轮子 3.1 模块加载执行的步骤 3.2 代码框架 3.3 关键函数的代码实现 示例代码托管在我的代码仓 ...

  6. .NET Core的文件系统[5]:扩展文件系统构建一个简易版“云盘”

    FileProvider构建了一个抽象文件系统,作为它的两个具体实现,PhysicalFileProvider和EmbeddedFileProvider则分别为我们构建了一个物理文件系统和程序集内嵌文 ...

  7. 做了一个简易的git 代码自动部署脚本

    做了一个简易的git 代码自动部署脚本 http://my.oschina.net/caomenglong/blog/472665 发表于2个月前(2015-06-30 21:08)   阅读(200 ...

  8. simple-todo: 一个简易的 todo 程序 - django版

    今天无意间看到  simple-todo: 一个简易的 todo 程序 - web.py 中文教程 ,然后发现竟然有好多的版本 http://simple-is-better.com/news/tag ...

  9. 手写一个简易的多周期 MIPS CPU

    一点前言 多周期 CPU 相比单周期 CPU 以及流水线 CPU 实现来说其实写起来要麻烦那么一些,但是相对于流水线 CPU 和单周期 CPU 而言,多周期 CPU 除了能提升主频之外似乎并没有什么卵 ...

随机推荐

  1. %u编码

    Escape/Unescape加密解码/编码解码,又叫%u编码,从以往经验看编码字符串出现有"u",它是unicode编码,那么Escape编码采用是那一种unicode实现形式呢 ...

  2. Python演讲笔记1

    参考: 1. The Clean Architecture in Python (Brandon Rhodes) 2. Python Best Practice Patterns (Vladimir ...

  3. DNSmasq – 配置DNS和DHCP

    DNSmasq是一个小巧且方便地用于配置DNS和DHCP的工具,适用于小型网络.它提供了DNS功能和可选择的DHCP功能可以取代dhcpd(DHCPD服务配置)和bind等服务,配置起来更简单,更适用 ...

  4. virtualbox之usb设备的分配

    来源:http://www.cnblogs.com/fsjohnhuang/p/3987545.html 首先下载安装virtualbox的扩展包,因为box原本不支持usb设备.www.virtua ...

  5. SQL中inner join、outer join和cross join的区别

    对于SQL中inner join.outer join和cross join的区别简介:现有两张表,Table A 是左边的表.Table B 是右边的表.其各有四条记录,其中有两条记录name是相同 ...

  6. struts2学习记录

    1.对于使用Struts2框架的应用而言,尽量不要让超级链接直接接到某个视图资源,因为这种方式增加了额外的风险.推荐将所有请求都发送给Struts框架,让该框架来处理用户请求,即使只是简单的超级链接. ...

  7. hive的数据导出方式

    hive有三种导出数据的方式 >导出数据到本地 >导出数据到hdfs >导出数据到另一个表   导出数据到本地文件系统 insert overwrite local director ...

  8. Linux下四款Web服务器压力测试工具(http_load、webbench、ab、siege)介绍

    一.http_load程序非常小,解压后也不到100Khttp_load以并行复用的方式运行,用以测试web服务器的吞吐量与负载.但是它不同于大多数压力测试工具,它可以以一个单一的进程运行,一般不会把 ...

  9. MIT 6.828 JOS学习笔记6. Appendix 1: 实模式(real mode)与保护模式(protected mode)

    在我们阅读boot loader代码时,遇到了两个非常重要的概念,实模式(real mode)和保护模式(protected mode). 首先我们要知道这两种模式都是CPU的工作模式,实模式是早期C ...

  10. HDU 3642 Get The Treasury (线段树扫描线)

    题意:给你一些长方体,问你覆盖三次及以上的体积有多大 首先我们观察x轴y轴一样很大,但是z轴很小,所以我们可以枚举z轴(-500,500),注意我们枚举的是每一段长度为一的z轴的xy轴的面积而不是点. ...