Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >教你一招:用70 行 Python 代码编写一个递归下降解析器

教你一招:用70 行 Python 代码编写一个递归下降解析器

作者头像
CDA数据分析师
发布于 2018-02-05 03:13:12
发布于 2018-02-05 03:13:12
1.2K0
举报
文章被收录于专栏:CDA数据分析师CDA数据分析师

3个月前,我写了一篇文章,详细讲述了用解析库编写计算器的过程。然而,读者们普遍反应,他们对于见到一个从头开始写并且除了电池以外别无他物的计算器更感兴趣。我想,为什么不呢?

写一个计算机很简单,如果你使用针对算术表达式的hacks的话。但是hacks的产生的后果也几乎总是一样的:解决方案不够优雅,不可扩展,并且很难直观的理解。我喜欢挑战,并且打算发一个有益的帖子,所以我决定用通用递归下降解析器来写它。本着与上次相同的精神,我打算用尽可能少的行数来干这件事,所以它充满了hacks和tricks。但它们是表面的,并且不止限于我手头的任务。

这篇文章我将一步一步详细的解释一下。如果你想直接跳到代码,你可以滚动到这篇文章的最后。我希望当你读完后你能更好的理解如何解析内部的工作,启发你用适当的解析库,以避免混乱。

要理解这篇文章,你应该很好的理解Python,建议你要了解一些它是怎么解析,它是用来干什么的。如果你不知道,我建议你阅读我的前一篇文章,在里面我详细解释的语法及怎么去使用。

第一步:标记化

处理表达式的第一步就是将其转化为包含一个个独立符号的列表。这一步很简单,且不是本文的重点,因此在此处我省略了很多。

首先,我定义了一些标记(数字不在此中,它们是默认的标记)和一个标记类型:

下面就是我用来标记expr表达式的代码:

第一行是将表达式分割为基本标记的技巧,因此

下一行命名标记,这样分析器就能通过分类识别它们:

任何不在token_map中的标记被假定为数字。我们的分词器缺少称为验证的属性,以防止非数字被接受,但幸运的是,运算器将在以后处理它。

就是这样。现在我们有了一个标记列表,下一步就是将它解析为一个AST。

第二步:语法定义

我选择的解析器实现自一个本地垂直解析器,其来源于LL解析器的一个简单版本。它是一个最简单的解析器实现,事实上,只有仅仅14行代码。它是一种自上而下的解析器,这意味着解析器从最上层规则开始解析(like:expression),然后以递归方式尝试按照其子规则方式解析,直至符合最下层的规则(like:number)。换句话解释,当自底向上解析器(LR)逐步地收缩标记,使规则被包含在其它规则中,直到最后仅剩下一个规则,而自顶向下解析器(LL)逐步展开规则并进入到少数的抽象规则,直到它能够完全匹配输入的标记。

在深入到实际的解析器实现之前,我们可对语法进行讨论。在我之前发表的文章中,我使用过LR解析器,我可以像如下方式定义计算器语法(标记使用大写字母表示):

(如果您还不理解上述语法,请阅读我之前发表的文章)

现在我使用LL解析器,以如下方式定义计算器的语法:

大家可以看到,这里有一个微妙的变化。有关”addandmul”的递归定义被反转了。这是个非常重要的细节,我会向大家详细说明这一点。

LR版本使用了左递归的模式。当LL解析器遇到递归的时候,它会尝试去匹配规则。所以,当左递归发生是,解析器会进入无穷递归。甚至连聪明的LL解析器例如ANTLR也逃避不了这个问题,它会以友好的错误提示代替无穷的递归,而不像我们这个玩具解析器那样。

左递归可以很容易的转变为右递归,我就这么做的。但是解析器并不是那么简单,它又会产生另一个问题:当左递归正确的解析3-2-1为(3-2)-1,而右递归却错误的解析为3-(2-1)。我还没想到一个简单的解决办法,所以为了让事情简单,我决定让它继续使用错误的解析格式,并在后面处理这个问题(请看步骤4)

第三步:解析为一个AST

算法其实很简单。我们会定义一个接收两个参数的递归方法:第一个参数是我们要尝试匹配的规则名称,第二个参数是我们要保留的标识列表。我们从add(最上层规则)方法开始,其已包含完整的标识列表,递归调用已非常明确。方法将返回一个数组,其包含元素为:一个是当前匹配项,另一个是保留匹配的标识列表。我们将实现标识匹配功能,以使这段代码可用(它们都是字符串类型;一个是大写格式,另一个是小写格式)。

以下是解析器实现的代码:

代码4至5行说明:如果规则名称(rule_name)确实是一个标识,并被包含在标识列表(tokens)中,同时检查其是否匹配当前标识。如果是,表达式将返回匹配方法,标识列表任然进行使用。

代码第6行说明:迭代将循环检查是否匹配该规则名称对应的子规则,通过递归实现每条子规则的匹配。如果规则名称满足匹配标识的条件,get()方法将返回一个空数组,同时代码将返回空值(见16行)。

第9-15行,实现迭代当前的sub-rule,并尝试顺序地匹配他们。每次迭代都尽可能多的匹配标识。如果某一个标识无法匹配,我们就会放弃整个sub-rule。但是,如果所有的标识都匹配成功,我们就到达else语句,并返回rule_name的匹配值,还有剩下标识。

现在运行并看看1.2/(11+3)的结果。

结果是一个tuple,当然我们并没有看到有剩下的标识。匹配结果并不易于阅读,所以让我吧结果画成一个图:

这就是概念上的AST。通过你思维逻辑,或者在纸上描绘,想象解析器是如何运作的,这样是个很好的锻炼。我不敢说这样是必须的,除非你想神交。你可以通过AST来帮助你实现正确的算法。

到目前为止,我们已经完成了可以处理二进制运算,一元运算,括号和操作符优先权的解析器。

现在只剩下一个错误待解决,下面的步骤我们将解决这个错误。

第四步:后续处理

我的解析器并非在任何场合管用。最重要的一点是,它并不能处理左递归,迫使我把代码写成右递归方式。这样导致,解析8/4/2这个表达式的时候,AST结果如下:

如果我们尝试通过AST计算结果,我们将会优先计算4/2,这当然是错误的。一些LL解析器选择修正树里面的关联性。这样需要编写多行代码;)。这个不采纳,我们需要使它扁平化。算法很简单:对于AST里面的每个规则1)需要修正2)是一个二进制运算(拥有sub-rules)3)右边的操作符同样的规则:使后者扁平成前者。通过“扁平”,我意思是在其父节点的上下文中,通过节点的儿子代替这个节点。因为我们的穿越是DFS是后序的,意味着它从树的边缘开始,并一直到达树根,效果将会累加。如下是代码:

这段代码可以让任何结构的加法或乘法表达式变成一个平面列表(不会混淆)。括号会破坏顺序,当然,它们不会受到影响。

基于以上的这些,我可以把代码重构成左关联:

但是,我并不会这样做。我需要更少的代码,并且把计算代码换成处理列表会比重构整棵树需要更少的代码。

第五步:运算器

对树的运算非常简单。只需用与后处理的代码相似的方式对树进行遍历(即DFS后序),并按照其中的每条规则进行运算。对于运算器,因为我们使用了递归算法,所以每条规则必须只包含数字和操作符。代码如下:

我使用calc_binary函数进行加法和减法运算(以及它们的同阶运算)。它以左结合的方式计算列表中的这些运算,这使得我们的LL语法不太容易获取结果。

第六步:REPL

最朴实的REPL:

不要让我解释它:)

附录:将它们合并:一个70行的计算器

end

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2015-12-31,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 CDA数据分析师 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
重磅综述|大脑内在神经时间尺度:时间整合与分离
我们不断地受到来自环境的各种时间尺度的外部输入的轰炸。大脑是如何处理这么多时间尺度的呢?最近的静息状态研究表明,内在神经时间尺度(INT)在单模态区(如视觉皮层和听觉皮层)持续时间较短,而在跨模态区(
悦影科技
2022/08/04
8820
走向最小统一意识模型
Maxwell j . d . Ramstead * 1,2,A,Mahault Albarracin1,3,A,Alex Kiefer1,4,Kenneth Williford5,Adam Safron6,7,Chris Fields8,Mark Solms9和Karl Friston1,2
CreateAMind
2023/10/10
3730
走向最小统一意识模型
回答薛定谔问题: 生命是什么?自由能公式
2017年5月17日收到;已于2017年9月18日收到修订版;2017年9月18日接受
CreateAMind
2022/04/15
7160
回答薛定谔问题: 生命是什么?自由能公式
EEG和MEG稳态和动态静息态网络比较
使用神经影像技术对静息态网络(RSN)进行表征,极大地促进了我们对大脑活动组织的理解。先前的研究已经证实了RSN的电生理基础和其动态性质,揭示了大脑网络的瞬时激活,时间尺度为毫秒级。虽然先前的研究证实了由脑电图(EEG)识别的RSN与由脑磁图(MEG)和功能性磁共振成像(fMRI)识别的RSN之间的可比性,但大多数研究采用了静态分析技术,忽略了大脑活动的动态性质。通常,这些研究使用高密度EEG系统,限制了它们在临床环境中的适用性。针对这些差距,我们的研究使用中密度EEG系统(61个传感器)研究RSN,并将其静态和动态脑网络特征与高密度MEG系统(306个传感器)获得的特征进行比较。我们评估了由EEG推导的RSN与MEG推导的RSN在定性和定量上的可比性,包括它们捕捉年龄相关效应的能力,并探索了模态内和模态间动态RSN的可重复性。我们的研究结果表明,MEG和EEG提供了可比的静态和动态网络描述,尽管MEG在某些情况下具有更高的敏感性和可重复性。这种RSN及其在两种模态之间的可比性在定性上保持一致,但在数据无主体特定结构MRI图像重建时,在定量上存在差异。
悦影科技
2025/01/10
1140
Cerebral Cortex:疼痛热刺激引起的脑功能网络分离与整合
目前的研究旨在确定热痛期间大脑网络整合/分离的变化,使用高时间分辨率的网络连接事件优化方法。参与者(n = 33)主动判断施加于前臂掌侧的热刺激是否疼痛,然后在每次试验后评价温暖/疼痛强度。我们表明,试验中整合/分离的时间演化与疼痛的主观评级相关。具体来说,大脑在处理疼痛刺激时从隔离状态转变为整合状态。在所有的网络中,与主观疼痛评分的关联发生在不同的时间点。然而,当在较低的时间分辨率下测量时变功能连接时,评分和整合/分离之间的关联程度消失了。此外,与疼痛相关的整合增强在一定程度上可以通过网络之间连接的相对增加来解释。我们的研究结果强调了在单一时间点尺度上研究疼痛和大脑网络连接之间关系的重要性,因为通常使用的连接数据的时间聚合可能导致网络连接的细尺度变化可能被忽视。整合/分离之间的相互作用反映了大脑网络之间信息处理需求的变化,这种适应既发生在认知任务中,也发生在痛感处理中。
悦影科技
2022/11/28
3360
研究全脑神经网络时间动态的工具:脑电微状态介绍
瑞士研究者Christoph M.Michel 和ThomasKoenig在NeuroImage发文,介绍了一种用多通道EEG表征人脑静息态活动的办法。这种方法检测大脑的电微态,即短时间内头皮电压分布保持半稳定性,其反映大规模网络节点之间的活动具有准同时性。微状态代表了自发性意识加工的结构链,它们的发生和时间动态决定了心理状态的质量。神经和精神疾病的意识加工紊乱表现为特定微状态的时间动态变化。脑电微状态与静息态网络密切相关,其时间进程的无标度属性解释了为什么相似的脑网络可以在不同的时间尺度中被观察到。
用户1279583
2019/07/10
3K0
分层网络结构作为生物系统分层的动力学
Hierarchical network structure as the source of hierarchical dynamics (power-law frequency spectra) in living and non-living systems: How state-trait continua (body plans, personalities) emerge from first principles in biophysics
CreateAMind
2024/01/17
2970
分层网络结构作为生物系统分层的动力学
AJP:斯坦福加速智能神经调控疗法治疗难治性抑郁症
目的:寻找有效、快速、安全、可耐受的抗抑郁疗法。间歇性theta爆发刺激 (Intermittent theta-burst stimulation, iTBS) 是一种非侵入性脑刺激疗法,已被美国食品和药物管理局批准用于治疗难治性抑郁症。最近的方法学进展表明,目前的iTBS方案可以通过以下方式得到改善:1) 每天以最佳时间间隔多次治疗患者;2) 应用较高的总脉冲刺激剂量;3) 精确定位左侧背外侧前额叶皮层(dorsolateral prefrontal cortex, DLPFC)到膝下前扣带皮层 (subgenual anterior cingulate cortex, sgACC) 的回路。作者研究了斯坦福加速智能神经调控疗法(Stanford Accelerated Intelligent Neuromodulation Therapy, SAINT) 的可行性、耐受性和初步疗效,SAINT是一种加速的、高剂量的静息态功能连接MRI (functional connectivity MRI, fcMRI) 引导下的iTBS方案,用于治疗难治性抑郁症。
用户1279583
2022/02/28
1.6K0
AJP:斯坦福加速智能神经调控疗法治疗难治性抑郁症
PNAS:皮层活动的高振幅共振荡驱动功能连接
静息状态功能连接在整个神经科学中被用于研究大脑组织和产生发育、疾病和认知的生物标志物。然而,人们对引起相关活动的过程知之甚少。在这里,我们使用一个时间展开过程来分解静止状态的功能连接,以评估时刻到时刻的活动共振荡对整体连接模式的贡献。
悦影科技
2021/09/14
7230
训练AI来检测人类意图,扩大制造领域的人机协作
机器和机器人的广泛使用无疑让我们的生活变得更加轻松,更加方便。它们以精确和快速的方式完成工作,而且机器与人类不同,他们不需要休息,因为他们永远不会累。
脑机接口社区
2022/08/17
3870
训练AI来检测人类意图,扩大制造领域的人机协作
大脑内在网络的振荡机制
摘要:无创神经影像学已经揭示了人类大脑在静息状态下基于特定网络的动态特征,但其潜在的神经生理机制仍不清楚。我们对42名受试者采用了颅内脑电图技术,以表征默认模式网络(DMN)、额顶叶网络(FPN)和突显网络(SN)中的局部场电位。我们发现,在DMN中,低频段(θ和α波段)的网络内相位相干性更强;而在FPN中,高频段(γ波段)的网络内相位相干性更强。隐马尔可夫模型表明,DMN表现出对低频相位耦合的偏好。相位-振幅耦合(PAC)分析显示,DMN中的低频相位调制了FPN的高频振幅包络,这表明静息状态下内在脑网络的特征具有频率依赖性。这些发现为支持人类大脑内在组织网络模型提供了颅内电生理证据,并揭示了大脑网络在静息状态下进行通信的方式。
悦影科技
2024/12/19
1650
​以边为中心的时变功能脑网络及其在自闭症中的应用
大脑区域之间的相互作用随着时间的推移而变化,这可以用时变功能连接(tvFC)来描述。估计tvFC的常用方法使用滑动窗口,并提供有限的时间分辨率。另一种替代方法是使用最近提出的边中心方法,这种方法可以跟踪成对大脑区域之间共同波动模式的每时每刻变化。在这里,我们首先研究了边时间序列的动态特征,并将其与滑动窗口tvFC (sw-tvFC)中的动态特征进行了比较。然后,我们使用边时间序列来比较自闭症谱系障碍(ASD)受试者和健康对照组(CN)。我们的结果表明,相对于sw-tvFC,边时间序列捕获了快速和突发的网络水平波动,这些波动在观看电影期间同步。研究的第二部分的结果表明,在CN和ASD中,大脑区域集体共同波动的峰值振幅的大小(估计为边时间序列的平方根(RSS)是相似的。然而,相对于CN, ASD中RSS信号的波谷到波谷持续时间更长。此外,高振幅共波动的边比较表明,网络内边在CN中表现出更大的幅度波动。我们的研究结果表明,由边时间序列捕获的高振幅共波动提供了有关脑功能动力学中断的细节,这可能被用于开发新的精神障碍生物标志物。
悦影科技
2023/04/18
5490
大规模电生理网络动力学
多年来,人们一直认为神经同步对认知至关重要。不同神经群之间的同步时间模式承载的信息超越了这些群的孤立活动,这一观点引发了功能性神经成像领域的焦点转移。具体来说,对某些刺激或任务引起的某些区域内的激活的研究,在一定程度上已经让位于对远端区域之间的共激活模式或功能连接的分析。最近,功能连接学界已经超越了早期工作所基于的平稳性假设,并引入了将时间动态纳入连接分析的方法。特别是,非侵入性电生理数据(脑磁图/脑电图(MEG/EEG))可以直接测量全脑活动和丰富的时间信息,为了解这种(潜在的快速)大脑动态提供了一个特殊的窗口。在本文中,我们讨论了挑战、解决方案以及近年来开发的一系列分析工具,这些工具有助于利用这些成像方式研究动态功能连接。进一步,我们讨论了这些方法在认知和神经精神障碍研究中的应用。最后,我们回顾了一些现有的发展,通过使用现实的计算模型,追求对非平稳连通性的潜在原因的更深入的理解。本文发表在NeuroImage杂志。
用户1279583
2021/09/27
5580
NC:预测阿尔茨海默病的个体进展轨迹
对阿尔茨海默病(AD)进展的预期对于评估二级预防措施是至关重要的,因其被认为可以改变疾病的发展轨迹。然而,很难预测AD的自然进展,特别是不同的功能在不同的年龄下降,不同患者的发生率不同。我们在这里评估了AD进程映射,这是一个统计模型,根据当前疾病早期阶段的医学和放射学数据,预测患者的神经心理评估和成像生物标志物的进展。我们对96000多例患者进行了该方法的测试,其中包括来自四大洲的4600多名患者。我们测量了方法准确性通过选择了在一个假设的试验中显示临床端点进展的被试。我们发现,使用预测进展者丰富人群可以使所需的样本量减少38%至50%,这取决于试验时间、结果和目标疾病阶段,从无症状的AD风险个体到早期和轻度AD被试。我们表明,该方法没有引入关于性别或地理位置的偏差,并且对缺失的数据是稳健的。它在疾病的早期阶段表现最好,因此非常适合用于预防试验。
悦影科技
2023/06/25
8060
R语言随机波动模型SV:马尔可夫蒙特卡罗法MCMC、正则化广义矩估计和准最大似然估计上证指数收益时间序列
本文做SV模型,选取马尔可夫蒙特卡罗法(MCMC)、正则化广义矩估计法和准最大似然估计法估计。
拓端
2023/01/05
3290
人类意识由大脑信号协调的复杂动态模式支持
通过采用大脑动力学框架衡量人类意识,我们确定了在脑损伤之后的有意识和无意识状态下,动态信号的协调是否具有与之相关的特定、可概括的模式。结果发现,健康个体和有最小化意识状态的患者分别表现出协调和不协调的功能磁共振成像信号的动态模式。无反应患者的大脑主要表现出低区域间相干性模式(主要由结构连接性介导),并且在不同动态模式之间的转换概率较小。而复杂的动态模式在具有隐性认知能力的患者中得到了进一步证实,他们可以执行神经影像学心理想象任务,验证了这种模式对意识的作用。而麻醉可以将较不复杂的动态模式的发生概率提高到相等的水平,验证了较不复杂的动态模式在无意识中的作用。我们的研究结果表明,意识依赖于大脑维持丰富的脑动态的能力,并为确定有意识和无意识状态的特定、可概括的动态模式铺平了道路。本文发表在SCIENCE ADVANCES杂志。
用户1279583
2022/06/13
5260
人类意识由大脑信号协调的复杂动态模式支持
R语言随机波动模型SV:马尔可夫蒙特卡罗法MCMC、正则化广义矩估计和准最大似然估计上证指数收益时间序列|附代码数据
本文做SV模型,选取马尔可夫蒙特卡罗法(MCMC)、正则化广义矩估计法和准最大似然估计法估计。
拓端
2023/09/01
2380
使用多尺度扩散实现超分辨率的频域细化
单张图像的超分辨率(SR)是一项至关重要的任务,并吸引了持续的研究兴趣,这对于提高各种下游任务的低分辨率(LR)图像的质量起着至关重要的作用。从频域的角度来看,导致LR图像的自然或人为退化过程可以看作是对相应高分辨率(HR)图像的广泛低通滤波,导致高频细节的显著损失。因此,重建高质量HR图像的主要难点在于对缺失的高频信息的恢复。近年来,随着深度学习技术的不断创新,出现了各种超分辨率方法。这些方法可以分为两类,即基于回归的方法和生成方法。
用户1324186
2024/06/25
9240
使用多尺度扩散实现超分辨率的频域细化
BP:加速iTBS及cTBS治疗难治性抑郁症及自杀意念的疗效比较
背景:难治性抑郁症(TRD)中,自杀意念构成了一项严峻的临床挑战。近期研究揭示,针对无或轻度自杀意念的TRD患者,采用间歇性θ爆发刺激(iTBS)特定方案展现出了显著的抗抑郁疗效。本研究则聚焦于探索加速iTBS方案与持续TBS(cTBS)在具有中度至重度自杀意念患者中的临床效用。
悦影科技
2024/11/12
2910
R语言随机波动模型SV:马尔可夫蒙特卡罗法MCMC、正则化广义矩估计和准最大似然估计上证指数收益时间序列|附代码数据
本文做SV模型,选取马尔可夫蒙特卡罗法(MCMC)、正则化广义矩估计法和准最大似然估计法估计。
拓端
2023/04/05
3360
推荐阅读
相关推荐
重磅综述|大脑内在神经时间尺度:时间整合与分离
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档