F#库FParsec解析表达式

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
简介: 本文用F#解析器库FParsec对数学公式进行解析,如将(x+2)^7 => Pow (Add (Var "x", CstF 2.0), CstF 7.0),此转换操作对于数学公式的后续推导以及求值等都具有重要的作用。

   上一篇我们介绍了F#FParsec入门,其中给出了具体的示例,来说明如何解析浮点类型的值,解析括号中的值等,如果感兴趣的可以回到这篇博客进行阅读。本次将用讲解F#解析器库FParsec对数学公式的解析,并结构化输出构成AST。

    首先,我们定义一个数学公式这个领域的自定义类型:

typeExpr=|CstFoffloat|Varofstring|AddofExpr*Expr// +|SubofExpr*Expr// -|MulofExpr*Expr// *|DivofExpr*Expr// / |PowofExpr*Expr// ^ |SinofExpr|CosofExpr|ExpofExpr|LnofExpr

    其中的Expr是定义的数学表达式类型,其中由多个元素构成,比如 CstF of float表示浮点类型的数值,Var of string则表示文本类型的变量,Add of Expr * Expr表示数学的加法操作,其中左边可以是一个Expr类型,右边也可以是一个Expr类型。此程序属于模块:

moduleYd.ExpParser.Ast

   如果要使用FParsec,则需要引入此库的命名空间:

openFParsec

   然后,需要用内置的浮点类型解析器,文本类型的解析器等构建一些工具方法:

//忽略空白字符letws=CharParsers.spaces//忽略特定字符并忽略末尾的空白字符letchc=CharParsers.skipCharc>>. ws//解析浮点类型的值,忽略末尾的空白字符,并转换成 CstF 类型letnum=CharParsers.pfloat .>>ws|>> (funx->CstFx)
//变量标识符规则letidentifier=letisIdentifierFirstCharc=isLetterc||c='_'letisIdentifierCharc=isLetterc||isDigitc||c='_'many1Satisfy2LisIdentifierFirstCharisIdentifierChar"identifier"//忽略空白letidentifierws=spaces>>.  identifier  .>>spaces//变量解析letid=identifierws|>>(funx->Varx)
      .>>ws

   其次,创建操作符解析器,示例代码如下:

//创建一个新的具有优先级的操作符解析器letopp=newOperatorPrecedenceParser<_,_,_>()
//重命名表达式解析器ExpressionParser,方便调用letexpr=opp.ExpressionParser//括号中提取表达式letbra_expr=ch'('>>. expr .>>ch')'// 定义支持的术语terms,即操作符外的类型解析器//id表示变量解析器,num表示浮点类型解析器,bra_expr表示表达式解析器letterms=choice[ id; num; bra_expr]
opp.TermParser<-terms

    再次,需要定义操作符解析器的优先级类型:

opp.AddOperator(InfixOperator("+", ws,1, Associativity.Left, funxy->Add(x, y)))
opp.AddOperator(InfixOperator("-", ws,1, Associativity.Left, funxy->Sub(x, y)))
opp.AddOperator(InfixOperator("*", ws,2, Associativity.Left, funxy->Mul(x, y)))
opp.AddOperator(InfixOperator("/", ws,2, Associativity.Left, funxy->Div(x, y)))
opp.AddOperator(InfixOperator("^", ws,3, Associativity.Left, funxy->Pow(x, y)))
opp.AddOperator(PrefixOperator("sin", ws,4, true, funx->Sin(x)))
opp.AddOperator(PrefixOperator("cos", ws,4, true, funx->Cos(x)))
opp.AddOperator(PrefixOperator("exp", ws,4, true, funx->Exp(x)))
opp.AddOperator(PrefixOperator("ln", ws,4, true, funx->Ln(x)))
opp.AddOperator(PostfixOperator("!", ws,5, true, funx->Factorial(x)))

   其中的Associativity.Left代表左结合性。下面给出最终的解析函数:

//忽略空白letexpr_ws=ws>>. expr .>>ws//调用run方法调用字符解析器letparses=CharParsers.runexpr_wss

  最后,给出测试示例:

lettest () =//测试用例printfn"%s => %A""1.0+2.0+a" (parse"1.0+2.0+a")
printfn"%s => %A""(x + 1.0) * 2.0"  (parse"(x + 1.0) * 2.0")
printfn"%s => %A""(x + 2) * y / 3.2"  (parse"(x + 2) * y / 3.2")
printfn"%s => %A""(x+2)^7"  (parse"(x+2)^7")
printfn"%s => %A""sin( x + 2) + 3 "  (parse"sin( x + 2) + 3 ")
printfn"%s => %A""sin( x + 2) + cos(x * 2)"  (parse"sin( x + 2) + cos(x * 2)")
printfn"%s => %A""2+exp(3*y)"  (parse"2+exp(3*y)")
printfn"%s => %A""2+ln(7*x)"  (parse"2+ln(7*x)")
printfn"%s => %A""(7*x)!+2"  (parse"(7*x)!+2")

   运行后,结果如下:

1.0+2.0+a=>Success: Add (Add (CstF1.0, CstF2.0), Var"a")
(x+1.0) *2.0=>Success: Mul (Add (Var"x", CstF1.0), CstF2.0)
(x+2) *y/3.2=>Success: Div (Mul (Add (Var"x", CstF2.0), Var"y"), CstF3.2)
(x+2)^7=>Success: Pow (Add (Var"x", CstF2.0), CstF7.0)
sin( x+2) +3=>Success: Add (Sin (Add (Var"x", CstF2.0)), CstF3.0)
sin( x+2) +cos(x*2) =>Success: Add (Sin (Add (Var"x", CstF2.0)), Cos (Mul (Var"x", CstF2.0)))
2+exp(3*y) =>Success: Add (CstF2.0, Exp (Mul (CstF3.0, Var"y")))
2+ln(7*x) =>Success: Add (CstF2.0, Ln (Mul (CstF7.0, Var"x")))
(7*x)!+2=>Success: Add (Factorial (Mul (CstF7.0, Var"x")), CstF2.0)


相关文章
|
4天前
|
XML JSON 网络协议
超级好用的C++实用库之字节流解析器
超级好用的C++实用库之字节流解析器
|
15天前
|
数据采集 存储 JSON
从零到一构建网络爬虫帝国:HTTP协议+Python requests库深度解析
在网络数据的海洋中,网络爬虫遵循HTTP协议,穿梭于互联网各处,收集宝贵信息。本文将从零开始,使用Python的requests库,深入解析HTTP协议,助你构建自己的网络爬虫帝国。首先介绍HTTP协议基础,包括请求与响应结构;然后详细介绍requests库的安装与使用,演示如何发送GET和POST请求并处理响应;最后概述爬虫构建流程及挑战,帮助你逐步掌握核心技术,畅游数据海洋。
47 3
|
4天前
|
缓存 网络协议 分布式数据库
超级好用的C++实用库之DNS解析
超级好用的C++实用库之DNS解析
14 0
|
7天前
|
设计模式 存储 算法
PHP中的设计模式:策略模式的深入解析与应用在软件开发的浩瀚海洋中,PHP以其独特的魅力和强大的功能吸引了无数开发者。作为一门历史悠久且广泛应用的编程语言,PHP不仅拥有丰富的内置函数和扩展库,还支持面向对象编程(OOP),为开发者提供了灵活而强大的工具集。在PHP的众多特性中,设计模式的应用尤为引人注目,它们如同精雕细琢的宝石,镶嵌在代码的肌理之中,让程序更加优雅、高效且易于维护。今天,我们就来深入探讨PHP中使用频率颇高的一种设计模式——策略模式。
本文旨在深入探讨PHP中的策略模式,从定义到实现,再到应用场景,全面剖析其在PHP编程中的应用价值。策略模式作为一种行为型设计模式,允许在运行时根据不同情况选择不同的算法或行为,极大地提高了代码的灵活性和可维护性。通过实例分析,本文将展示如何在PHP项目中有效利用策略模式来解决实际问题,并提升代码质量。
|
2月前
|
Java API
Java 8新特性:Lambda表达式与Stream API的深度解析
【7月更文挑战第61天】本文将深入探讨Java 8中的两个重要特性:Lambda表达式和Stream API。我们将首先介绍Lambda表达式的基本概念和语法,然后详细解析Stream API的使用和优势。最后,我们将通过实例代码演示如何结合使用Lambda表达式和Stream API,以提高Java编程的效率和可读性。
|
2月前
|
开发者 Python
深入解析Python `requests`库源码,揭开HTTP请求的神秘面纱!
深入解析Python `requests`库源码,揭开HTTP请求的神秘面纱!
128 1
|
2月前
|
XML 存储 JavaScript
xml介绍与解析,及xml库包使用
xml介绍与解析,及xml库包使用
26 0
|
2月前
|
机器学习/深度学习 计算机视觉 Python
深度学习项目中在yaml文件中定义配置,以及使用的python的PyYAML库包读取解析yaml配置文件
深度学习项目中在yaml文件中定义配置,以及使用的python的PyYAML库包读取解析yaml配置文件
41 0
|
2月前
|
JSON 数据格式 索引
【Azure Developer】Azure Logic App 示例: 解析 Request Body 的 JSON 的表达式? triggerBody()?
【Azure Developer】Azure Logic App 示例: 解析 Request Body 的 JSON 的表达式? triggerBody()?
|
2月前
|
测试技术 API Android开发
Android经典实战之简化 Android 相机开发:CameraX 库的全面解析
CameraX是Android Jetpack的一个组件,旨在简化相机应用开发,提供了易于使用的API并支持从Android 5.0(API级别21)起的设备。其主要特性包括广泛的设备兼容性、简洁的API、生命周期感知、简化实现及方便的集成与测试。通过简单的几个步骤即可实现如拍照、视频录制等功能。此外,还提供了最佳实践指导以确保应用的稳定性和性能。
37 0

推荐镜像

更多
下一篇
无影云桌面