使用解析器

来源:互联网 发布:人工智能研究领域包括 编辑:程序博客网 时间:2024/05/16 17:01

使用解析器

 

使用解析器是非常简单,可以使用它自己的词法分析器,但是,用fsyacc.exe 产生的解析器总是要求词法分析器。在这一小节,我们将讨论如何使用自己的词法分析器,以及与解析器联合。

 

警告

记住F# 编译器不能直接使用.fsl 和 .fsy 文件,需要用fslex.exe 和 fsyacc.exe 进行编译,创建.fs 文件,然后才能使用。通常,使用预编译事件实现,它在 Visual Studio 的项目属性对话框中。

 

为了使用自己的词法分析器,首先需要创建LexBuffer,表示处理的文本。LexBuffer 类有大量的静态方法,能够从不同的文本源中创建它的实例,它们包括FromBinaryReader, FromBytes, FromChars, and FromTextReader。典型的从字符串创建 LexBuffer类,使用 Encoding 类把字符串编码成字节数组,然后,调用静态方法FromBytes。

下面的例子显示了词法分析器的行为。假设,我们已经把词法分析器编译成一个模块Lex,那么,我们使用token 函数去找第一个字符串中的符号,在这里只有一个。

 

open System.Text

open Microsoft.FSharp.Text.Lexing

let lexbuf = LexBuffer<byte>.FromBytes(Encoding.ASCII.GetBytes("1"))

let token = Lex.tokenlexbuf

printfn "%A" token

 

例子的结果如下:

 

FLOAT 1.0

 

只能从缓冲中获取第一个符号,并没有太大的价值,因此,以标准模式使用词法分析器,更为常见的做法是创建循环,从缓冲中重复获取所有的符号。下面的例子就演示了这一做法,输出所有发现的符号:

 

open System.Text

open System.FSharp.Text.lexing

let lexbuf2 = LexBuffer<byte>.FromBytes(Encoding.ASCII.GetBytes("(1 * 1) + 2"))

while notlexbuf2.IsPastEndOfStreamdo

    let token = Lex.token lexbuf2

    printfn "%A" token

 

运行结果如下:

 

LPAREN

FLOAT 1.0

MULTI

FLOAT 1.0

RPAREN

PLUS

FLOAT 2.0

EOF

 

更加常见的做法,是把词法分析器与解析器模块结合在一起使用。由解析器产生的函数期待第一个参数成为函数,接收参数LexBuffer,然后转换成符号(在这里,LexBuffer<'a,'cty> -> Pars.token)。很幸运,这就是我们的词法分析器的 token 函数的签名。下面的例子演示如何实现:

 

open System.Text

openMicrosoft.FSharp.Text.Lexing

openStrangelights.ExpressionParser

let lexbuf3 =

    Lexbuffer<byte>.FromBytes(Encoding.ASCII.GetBytes("(1 * 1) + 2"))

let e =Pars.Expression Lex.token lexbuf3

printfn "%A" e

 

示例的运行结果如下:

 

Plus (Multi (Val 1.0,Val 1.0),Val 2.0)

 

正是如此。一旦有了自己的抽象语法树,语法就有了好的抽象形式,因此,现在就能创建根据树而行动的程序。到这里,我们可能会想跳回前一章,再看一看如何转换抽象语法树,是通过解释还是编译。

0 0