在F#中同时进行Lexing和解析

时间:2012-07-15 18:07:10

标签: parsing f# fsyacc fslex

使用fslex和fsyacc时,是否有一种简单的方法可以让lexing和解析同时运行?

1 个答案:

答案 0 :(得分:1)

首先,在实际案例中,lexing和解析是时间关键的。特别是如果您需要在解析之前处理令牌。例如 - 过滤和收集评论或解决与上下文相关的冲突。在这种情况下,解析器经常等待词法分析器。

问题的答案。您可以与MailboxProcessor同时运行lexing和解析。

理念的核心。您可以在mailBoxProcessor中运行词法分析器。 Lexer应该生成新的令牌,处理并发布它们。 Lexer通常比解析器更快,有时它应该等待解析器。解析器可以在必要时接收下一个令牌。代码如下。您可以修改超时,traceStep以找到最适合您的解决方案。

[<Literal>]
let traceStep = 200000L

let tokenizerFun = 
    let lexbuf = Lexing.LexBuffer<_>.FromTextReader sr                        
    let timeOfIteration = ref System.DateTime.Now
    fun (chan:MailboxProcessor<lexer_reply>) ->
    let post = chan.Post 
    async {
        while not lexbuf.IsPastEndOfStream do
            lastTokenNum := 1L + !lastTokenNum
            if (!lastTokenNum % traceStep) = 0L then 
                let oldTime = !timeOfIteration
                timeOfIteration := System.DateTime.Now
                let mSeconds = int64 ((!timeOfIteration - oldTime).Duration().TotalMilliseconds)
                if int64 chan.CurrentQueueLength > 2L * traceStep then                                                                                  
                    int (int64 chan.CurrentQueueLength * mSeconds / traceStep)  |> System.Threading.Thread.Sleep      
            let tok = Calc.Lexer.token lexbuf
            // Process tokens. Filter comments. Add some context-depenede information.
            post tok
    }   

use tokenizer =  new MailboxProcessor<_>(tokenizerFun)

let getNextToken (lexbuf:Lexing.LexBuffer<_>) =
    let res = tokenizer.Receive 150000 |> Async.RunSynchronously
    i := 1L + !i 

    if (!i % traceStep) = 0L then 
        let oldTime = !timeOfIteration
        timeOfIteration := System.DateTime.Now
        let seconds = (!timeOfIteration - oldTime).TotalSeconds          
    res

let res =         
    tokenizer.Start()            
    Calc.Parser.file getNextToken <| Lexing.LexBuffer<_>.FromString "*this is stub*"

此处提供了完整的解决方案:https://github.com/YaccConstructor/ConcurrentLexPars在此解决方案中,我们仅展示所描述想法的完整实施。性能比较不实际,因为语义计算非常简单,没有令牌处理。

要查找性能比较结果,请查看完整报告https://docs.google.com/document/d/1K43g5jokNKFOEHQJVlHM1gVhZZ7vFK2g9CJHyAVtUtg/edit?usp=sharing这里我们比较T-SQL子集解析器的顺序和并发解决方案的性能。连续:27秒,并发:20秒

我们也在生产T-SQL翻译器中使用这种技术。