生成解析器:Fsyacc

728 篇文章 1 订阅
86 篇文章 0 订阅

生成解析器:Fsyacc

 

扫描器就是一段程序或模块,把文本流拆成片断,解析器可以看作是把文本重新组织为更有意义的内容。解析器的目标通常是产生抽象语法树,通过定义规则,确定符号应该出现的顺序。工具fsyacc.exe 生成的解析器,是向前看从左到右(look-ahead left-to-right)的解析器,通常称为 LALR(1)[ 好像解释的有点问题,下面的内容来自百度百科 LR 分析法:Look-Ahead为“向前看”,L代表对输入进行从左到右的检查,R代表反向构造出最右推导序列]。这是一种语法解析算法,并不是所有的语法都能用这个算法解析,但是,不能解析的语法是很罕见的。

 

注意

fsyacc.exe 名字中的 YACC 是 Yet AnotherCompiler Compiler 的缩写。

 

工具fsyacc.exe 处理的文本文件的扩展名是.fsy。文件分为三个部分。第一部分是头部,这是一段纯F# 代码,用百分号和大括号括起来(%{ 表示开始,%} 表示结束),这一段通常用于导入(open)自己的抽象语法树模块,以及为创建这个抽象语法树而定义的简单的辅助函数。接下来是声明,定义了语言中的终结符。终结符(terminal)是语法中的一些具体名词,比如标识符名或符号。通常,它会由词法分析器发现。声明有几种不同的形式,汇总在表13-1 中。第三部分包含组成语法的规则,在下一段有具体描述。

 

表 13-1 fsyacc.exe 文件中终结符的声明

声明

描述

%token

它声明了给定符号,作为语言中的符号。

%token<type>

它声明了给定符号,作为语言中的符号,如 %token,但是,有给定类型的参数。当需要存储有关如标识符和文字的信息时,这是有用的。

%start

声明解析器应该开始解析的规则。

%type<type>

声明特定规则的类型,对于开始规则是强制的,而对于其他所有规则都是可选的。

%left

声明符号作为左关联(left-associative),可以帮助解决语法的歧义。

%right

声明符号作为右关联(right-associative),可以帮助解决语法的歧义。

%nonassoc

声明符号作为无关联(nonassociative),可以帮助解决语法的歧义。

 

声明与规则用两个百分号分开,它是文件的最后一段。规则是语法上的非终结符(nonterminals)。非终结符是由几个终结符组成的。这样,每一个规则必须有名字,加冒号,然后是组成规则的所有条目的定义,之间用竖线隔开。组成规则的条目,既可以是已经定义的符号名,也可以是规则名;它后面必须跟一个动作,用大括号括起来的 F# 代码。下面就是一个规则的片断:

 

Expression: ID { Ident($1)}

    | FLOAT {Val($1) }

 

Expession 是规则名,ID 和 FLOAT 是两个规则,只由终结符组成,{ Ident($1) } 和{ Val($1) } 是规则的动作 [ 原文中两个都是 Ident,应该是复制过来,忘记改了]。在这些动作中,可以收集到和终结符、非终结符相关联的数据,用美元符号($)加上数字,表示我们感兴趣条目的位置。动作的结果会和规则相关联。规则的所有的动作都必须有相同的类型,因为,规则实现为 F# 函数,动作作为参数,返回条目。在规则中的所有注释都应该用 C 风格的注释标记/* */。

下面的例子就是我们前面语言的一个简单解析器定义。注意,和规则相关联的所有动作都很简单,只创建了抽象语法树中类型的实例,所有的语言的终结符都大写。当使用 fsyacc.exe 工具编译这个示例时,很重要的一点是使用 --module 开关指定模块名,在这里,应该指定的模块名是Strangelights.ExpressionParser.Parser。

 

/* This example shows how to write a parser filewhich creates */

/* nodes that carry F# values. */

 

%{

openStrangelights.ExpressionParser.Ast

%}

%start Expression

%token <string> ID

%token <System.Double> FLOAT

%token LPAREN RPAREN EOF MULTI DIV PLUS MINUS

%type <Strangelights.ExpressionParser.Ast.Expr > Expression

 

%left MULTI

%left DIV

%left PLUS

%left MINUS

 

%%

 

Expression: ID { Ident($1)}

    | FLOAT {Val($1) }

    | LPARENExpression RPAREN { $2 }

    |Expression MULTI Expression { Multi($1, $3) }

    |Expression DIV Expression { Div($1, $3) }

    |Expression PLUS Expression { Plus($1, $3) }

    |Expression MINUS Expression { Minus($1, $3) }

 

让我们近距离看一下组成规则的条目,最简单的规则条目只由一个终结符组成,在这里,是一个标识符 ID:

 

ID { Ident($1) }

 

在这个规则条目的动作中,字符串,表示标识符的字符串用于创建Ident 构造函数的实例,来自抽象语法树。稍许复杂一些的规则,既包含终结符,也包含非终结符:

 

| Expression MULTI Expression { Multi($1, $3)}

 

这个规则条目可以识别为,一个有效的表达式,加乘号,再加一个有效的表达式。这些表达式然后被装进抽象语法树的构造器Multi;这些表达式可能是语言中的终结符,比如标识符或文字,也可能是由多个终结符组成的表达式,比如,乘法运算。

创建语法最困难的就是保证没有歧义。当有两个或多个规则匹配相同的输入时,语法就有歧义了。幸运的是,fsyacc.exe 可以自动发现,并在发现时发出警告;但也只是警告而已,因为,解析器仍然能够正常,只是有些规则未能匹配,在某些方面可能不正确。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值