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?
Réponse
Trop de publicités?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.