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

--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. strcmp

     C++ Code  123456789101112   int strcmp(const char *dest, const char *source) {     assert((NULL !=  ...

  2. mongodb更新操作

    除了查询条件,还可以使用修改器对文档进行更新. 1. $inc > db.tianyc03.find() { "_id" : ObjectId("50ea6b6f1 ...

  3. ABAP 传入数据到EXCEL自编函数

    DATA: excel    TYPE ole2_object,       workbook TYPE ole2_object,       sheet    TYPE ole2_object,   ...

  4. javaSE基础02

    javaSE基础02 一.javac命令和java命令做什么事情? javac:负责编译,当执行javac时,会启动java的编译程序,对指定扩展名的.java文件进行编译,生成了jvm可以识别的字节 ...

  5. PHP缓存技术

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  6. intellij idea 插件 ideaVim 用法

    intellij idea 插件 ideaVim - Genji_ - 博客园http://www.cnblogs.com/nova-/p/3535636.html IdeaVim插件使用技巧 - - ...

  7. 结合stack数据结构,实现不同进制转换的算法

    #!/usr/bin/env python # -*- coding: utf-8 -*- # learn <<Problem Solving with Algorithms and Da ...

  8. ubuntu下配置jdk

    1.首先下载jdk-7u51-linux-i586.tar.gz.并将它放在例如/home目录. 2.解压安装 sudo tar zxvf ./jdk-7u51-linux-i586.tar.gz  ...

  9. 《DSP using MATLAB》示例Example5.10

    代码: n = 0:10; x = 10*(0.8) .^ n; [xec, xoc] = circevod(x); %% -------------------------------------- ...

  10. Unity4.0的使用

    最近公司用到了Unity,自己就研究了一下. 新建一个ASP.NET MVC基本项目,在NuGet上引入Unity4.0.1最新版. 因为我使用的项目为ASP.NET MVC,所以又添加一个Unity ...