上环证明样本(Parser)

如果你对编译原理有一点了解,我相信你必须知道语法和语法分析(Parsing)语法分析算法也见过语法分析器(Parser).当需要处理语言时,语法分析是一个必不可少的阶段,但即使是递归下降算法,实现语法也非常繁琐LL当语法复杂时,家庭会变得非常繁琐和单调,更不用说对编码不友好了LR家族算法了.许多朋友会选择使用语法器生成器(Parsergenerator)编译生成语法分析器,输入文法及相关操作输出语法分析器的源代码.这是一个很好的方法,我相信我们都知道,这里介绍另一种很少理解的方法:语法分析器组合子(Parsercombinator).

上环证明样本:Parsercombinator在C 里的DSL

如果你对编译原理有一点了解,我相信你必须知道语法和语法分析(Parsing)语法分析算法也见过语法分析器(Parser).当需要处理语言时,语法分析是一个必不可少的阶段,但即使是递归下降算法,实现语法也非常繁琐LL当语法复杂时,家庭会变得非常繁琐和单调,更不用说对编码不友好了LR家族算法了.许多朋友会选择使用语法器生成器(Parsergenerator)编译生成语法分析器,输入文法及相关操作输出语法分析器的源代码.这是一个很好的方法,我相信我们都知道,这里介绍另一种很少理解的方法:语法分析器组合子(Parsercombinator).

上环证明样本(Parser)

首先,我们知道语法分析器是函数,输入需要分析的字符串或符号串(Tokenseries)如果输出是语法结构或语义,语法分析器的类型可以定义为:

α语法结构或语义值的类型,如抽象语法树(AST),或者如在之前的文章里的四则运算的Parser在分析过程中,相应的语义值(即表达式计算结果)直接用文法的综合属性计算,数字返回.第二个的String对于剩余需要分析的字符串.

然后我们可以把这个计算器看作是语法分析器的例子(instance),类型为:

这很容易理解.朋友们,我们发现没有喵喵。在这里,我们关注的不是特定语法分析器及其实现,而是语法分析器的抽象.我们关心的是如何进行对某个串的结构分析而不是如何计算语义值.我们在这里分开了两者。.

语法分析器还不够,我们需要在其域定义操作(就像我们有数字是不够的,我们需要加法和乘法操作).语法分析器的操作是语法分析器的组合子,也是全文的主题.语法分析器组合子是语法分析器的高级函数。简单的理解是接受语法分析器作为输入返回新的语法分析器。在这里,我们需要两个组合子连接组合子( )和或组合子(|),连接和或易于理解,直接对应于语法中的符号连接.

给出类型:

如果你对这里的类型运算加乘感到困惑,可以参考代数据类型()或者我的回答中有粗略的介绍.

构造表示:

最后,我们需要一个语法分析器单元(Termparser),这是语法中最基本的单位,对应于语法中的终止符.它是一个单位语法分析器,可以直接识别输入串中的符号,可以简单地理解,如前一篇文章Number符号与相应的函数,即是只接受0-9这10个字符返回数字.

构造表示:

(这里的返回忽略了语义值,返回了一个集合,其中的数字表示剩余需要分析的串的下标index,这和我的定义略有不同,大家都能理解意思就好)

最后,我们还需要单元(identityelement),这里的单位元和上面的不同,这是代数概念上的单位元,对应于文法中的空符号ε(或是empty即任何输入都返回空,不消耗符号,类型为:

构造表示:

另一种是语法解析器,不接受任何符号,返回空、类型和ε一样.

构造表示:

这在实践中没有用,也不会出现在文法中.因为它的代数意义,这里就提到一下.这样,我们就有了所有与文法相对应的结构.为什么这个定义是可行和有意义的,小心点,你可能会发现

形成阿贝尔群(Abeliangroup),其单位元素[0元素]为

构成一个半群(Monoid),其单元元素[1元素]为

然后类型构成一个环(Ring),如果您感兴趣,的性质和条件感兴趣,及的性质和条件.这里并不赘述了.此外,基于集合论,我们应该注意一些逆元素的存在,但不能构造.

这个组合子的结构很优雅吗?~

嗯,也许有些朋友对理论不感兴趣。让我们具体实现它。我在这里用的是C 实现:

首先给大家举个例子:

或者前一篇文章中的四个计算器,文法是:

组合子的使用非常优雅:

简单介绍一下ParserCombinator吃法,笑~

模板参数int表示这个语法解析器是一个接受字符串为输入返回其语义为int语法分析器.

对于文法:

可以直接在C 代码写:

但是这里还是缺少一些东西,那就是Number Decimal我们需要指出这部分正在获得Number和Decimal这两种子语法语义值后的语义是如何计算的?.使用>>指定回调函数:

这是个Lambda表达式表示我们已经分析过了Number后面还有一个数字,那我们就把它拿走Number乘10补这个位数Decimal.然后返回,作为返回值Number Decimal这部分文法的返回值.

最终的完整实现是:

你应该知道如何使用它。

那么这个东西是怎么实现的呢?这个东西太复杂了,我不能面面俱到。我将告诉你所有的细节,我主要关注核心实现和概念.具体分为几个部分:

首先,它分为两部分,ParserCombinator和ParserCombinatorComponent,如名称所示,ParserCombinator它是语法分析器ParserCombinatorComponent它是语法分析器的组成部分,例如A=B C在这个表达式中,A,B,C是一个ParserCombinator而B C是一个ParserCombinatorComponent,表示语法的中间组成.这么区分是为了能够进行递归,使用ParserCombinator类型识别表达式中的那些符号需要引用.

ParserCombinator它不包含具体的实现,但保存了指向具体实现的方向ParserCombinatorComponent的指针, 和用于结构|遇到表达式ParserCombinator将保存指针并进行递归调用.

当你看到上面的表达式时,你必须知道这是由操作符重载完成的。这里重载 和|这两个操作符.

与|两个参数可以是ParserCombinator或ParserCombinatorComponent回到新的ParserCombinatorComponent.

具体实现如下:

ParserCombinatorComponent具体实现的函数对象保存在其中(std::function)为func,完成具体分析和调用.operator 与operator|实现大致如下:

对于单位元(Termparser)的实现大致如下:

这里使用了C 11的userdefinedliteral特性,可直接添加字符_T来生成一个Tokencomponent.

需要递归的实现为(operator 为例):

注意这里捕获的是ParserCombinator指向具体实现的指针lhs.ptr.

注:这里忽略了语义值,将在下面的第二部分讨论。

调用的ParserCombinator入口如下:

由于C 可以推导模板函数的参数类型,为组合子添加一套类型系统,限制组合子在编译期间的语义类型.

一是推导规则如下:

如果不太了解上面的推导规则也没关系。C 解释方法:

首先要建立代数据类型的基础设施,建立两种基本类型的结构和操作:

ProductTypes对应类型乘积,.AdditionTypes对应类型的和,可以理解为笛卡尔乘积类型或列表类型.

ProductTypes实现大致如下:

例如,我现在必须这么做。int和char相乘,那就是:

AdditionTypes实现大致如下:

举例来说,比如我现在要对int和char加起来就是:

对int和int加起来就是:

利用多重继承和std::is_base_of判断是否已经改变了类型,以确保重复类型不会进入AdditionTypes.

注:AdditionTypes里的数据成员Any类型可以容纳任何类型,完整的实现可以参考我之前的回答

拥有类型和积累后,我们可以很容易地使用模板来推导喵喵的类型,第一部分operator 和operator|模板形式:

简单的直觉理解就是语法

A=B C

A=B|C

如果B和C类型一致A即是B与C的类型.

然后我们在第一部分提到了structInfo加一个成员

用于保存返回的语义值,这里使用Any类型擦除的目的是在不改变的情况下解耦structInfo成员可以容纳任何类型的语义值,structInfo它可以在不复杂的情况下在递归函数之间任意传输cast逻辑.

同时在operator 将获得的值用于内部std::tuple_cat添加到ProductTypes的_Data里就好.

回调函数部分在拥有类型系统后很容易实现:

有了类型系统和推导,我们可以确保我们的调用是正确的类型.

记忆技巧可以参考我之前的文章

朋友们可能已经发现上面四个计算器中有左递归,我们的语法分析组合子显然是递归下降算法,所以我们需要做一些处理来兼容左递归语法.

实现记忆化后,在同一位置再次调用同一语法时,会直接在表中提取出值返回,而不是再次求值,这样,语法分析就可以在线性时间内完成.同时,需要注意的是,记忆化的实现为解决左递归问题提供了工具,并在第一次访问语法非终止符时在记忆表上标记访问次数count=1.如果有左递归,再次进入修改法时会发现标记,说明左递归发生了。如果选择不兼容左递归,可以直接抛出左递归异常.

兼容左递归的核心思想是,递归深度不是无限的,因为我们需要分析的串长度需要分析的串长度是有限的,如果左递归语法非终止符成功完成分析,至少必须消耗一个符号(否则会出现空循环,这种病态(ill-formed)语法无法完成分析,所以想想为什么。.因此,当左递归语法非终止符再次进入时,访问次数count加一,如果count如果超过剩余待分析串的长度 1,则可以直接返回分析失败此时不可能完成分析.然后返回,自底向上进行语法分析,选择最长分析作为返回,这个时候相当于做了一个延迟决定,类似于LR分析算法.

值得注意的是,自底向上分析的结果不一定是唯一的。你可以使用最长的匹配原则来确定分支。当然,你可以引入向前的符号或其他不同的方式来选择决策,甚至继续推迟决策,直到信息足够.或者回溯,回溯实现技术将在下一节说明.

具体实现并不复杂,只需要对记忆化表添加上访问计数和相关结构就好了.

这里就不赘述更多细节了。感兴趣的朋友可以阅读
论文:

{n}

如果对CPS不熟悉的小伙伴可以看看我之前的文章和Wiki.这里就不做更多介绍啦.

{n}

由于我们的ParserCombin

你可能还喜欢下面这些文章

毕业证样本网创作《上环证明样本(Parser)》发布不易,请尊重! 转转请注明出处:https://www.czyyhgd.com/173940.html

(0)
上一篇 2022年4月30日
下一篇 2022年4月30日

相关推荐

  • 医院上环证明样本图片

    我从两米高的地方摔下来屁股着地,去医院检查腰第一脊椎压缩性骨折,医生建议保守治疗,躺了两个月,现在起来活动发现,站久了,或者坐久了会腰酸,以后会慢慢好起来还是一直会这样,以后是不是避免不了腰酸痛?

    2022年4月24日
    320
  • 深圳医院的上环证明样本(2020上环证明样本图片)

    但94年河南大学毕业证样本欠债归欠债,侮辱归侮辱,哪条法律说讨债就可以无视法律了借款的不是儿子,欠债与他无关,他看见的只是有人抽出那啥抽她母亲脸,向警方求助他们不管,儿子作为一个正常人做出了正常的选择,怎么判他儿子,跟母亲借高利贷没有任何关系。

    2022年5月28日
    340
  • 上环证明可以办假的吗

    那里能够办假上环证明你们给小孩上户口要上环证明吗?

    2022年6月12日
    290
  • 上海方案生育上环证哪里可以查

    我是较为嫌麻烦,因此自己去医院上的环,一共就花了并且自己感觉又快又整洁,消炎止痛药是医师跟我说家中如果有就不需要开。

    2022年3月21日
    240
  • 上环证明样本(Parser)

    如果你对编译原理有一点了解,我相信你必须知道语法和语法分析(Parsing)语法分析算法也见过语法分析器(Parser).当需要处理语言时,语法分析是一个必不可少的阶段,但即使是递归下降算法,实现语法也非常繁琐LL当语法复杂时,家庭会变得非常繁琐和单调,更不用说对编码不友好了LR家族算法了.许多朋友会选择使用语法器生成器(Parsergenerator)编译生成语法分析器,输入文法及相关操作输出语法分析器的源代码.这是一个很好的方法,我相信我们都知道,这里介绍另一种很少理解的方法:语法分析器组合子(Parsercombinator).

    2022年4月30日 上午10:51
    180
客服微信
客服微信
返回顶部