使用解析器
使用解析器是非常简单,可以使用它自己的词法分析器,但是,用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.IsPastEndOfStream do
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)
正是如此。一旦有了自己的抽象语法树,语法就有了好的抽象形式,因此,现在就能创建根据树而行动的程序。到这里,我们可能会想跳回前一章,再看一看如何转换抽象语法树,是通过解释还是编译。
原文地址:http://blog.csdn.net/hadstj/article/details/31344429