37 votes

Lexer et analyser simultanément en fa #

Existe-t-il un moyen simple d’exécuter simultanément le lexing et l’analyse lors de l’utilisation de fslex et de fsyacc?

1voto

gsv Points 66

Tout d'abord dans le cas réel lexing et l'analyse est critique. Surtout si vous avez besoin de traiter les jetons avant l'analyse. Par exemple, le filtrage et la collecte de commentaires ou de résolution de contexte-sont tributaires des conflits. Dans ce cas, l'analyseur souvent attendre un analyseur lexical.

La réponse à une question. Vous pouvez exécuter lexing et l'analyse simultanément avec MailboxProcessor.

Base de l'idée. Vous pouvez exécuter l'analyseur lexical dans mailBoxProcessor. Analyseur lexical doit produire de nouveaux jetons, les processus et les afficher. Lexer souvent plus rapide que de l'analyseur, et parfois il faut attendre un analyseur. L'analyseur peut recevoir jeton lorsque nécessaire. Code fourni ci-dessous. Vous pouvez modifier les délais d'attente, traceStep de trouver de manière optimale pour votre solution.

[<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*"

Solution complète est disponible ici: https://github.com/YaccConstructor/ConcurrentLexPars Dans cette solution, nous seulement de démontrer la pleine mise en œuvre de l'décrit idée . Comparaison des performances n'est pas réelle, car la sémantique de calcul est très simple et pas de jetons de traitement.

Pour en savoir rendement résultat de la comparaison oeil au rapport complet https://docs.google.com/document/d/1K43g5jokNKFOEHQJVlHM1gVhZZ7vFK2g9CJHyAVtUtg/edit?usp=sharing Ici, nous comparons les performances de manière séquentielle et simultanée solution pour analyseur de T-SQL sous-ensemble. Séquentiel: 27 sec, simultanées: 20 secondes.

Aussi, nous utilisons cette technique dans la production de T-SQL traducteur.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X