gpt4 book ai didi

parsing - FParsec:如何保存解析器成功的文本

转载 作者:行者123 更新时间:2023-12-04 15:06:45 25 4
gpt4 key购买 nike

为了在后面的步骤中创建更好的错误消息,我想保存解析器成功的位置以及文本。获取位置似乎很容易(因为有 getPosition 解析器),但我不知道如何访问文本。

假设我有这种类型来保存位置

type SourceLocation = {
from: Position
to: Position
text: string
}

我想创建一个函数,它添加了 SourceLocation到另一个解析器的结果:
let trackLocation (parser: Parser<'A, 'B>): Parser<SourceLocation * 'A, 'B> =
let mkLocation ((start: Position, data: 'A), stop: Position: 'Positon) =
let location = { from = start; to = stop } // how do I get the text?
in (location, data)
getPosition .>>. parser .>>. getPositon |>> mkLocation

由于解析器只是采用 CharStream 的函数我以为我可以将流与 Index 一起使用从我的位置获取文本,但我没有看到获取此文本的方法。

那么获取解析器成功的文本的正确方法是什么?

最佳答案

我想你可能想要的是 CharStream.ReadFrom method :

Returns a string with the chars between the index of the stateWhereStringBegins (inclusive) and the current Index of the stream (exclusive).



你要做的是:
let trackLocation (parser: Parser<'A, 'B>): Parser<SourceLocation * 'A, 'B> =
fun (stream : CharStream<'B>) ->
let oldState = stream.State
let parseResult = parser stream
if parseResult.Status = Ok then
let newState = stream.State
let matchedText = stream.ReadFrom (oldState, true)
// Or (oldState, false) if you DON'T want to normalize newlines
let location = { from = oldState.GetPosition stream
``to`` = newState.GetPosition stream
text = matchedText }
let result = (location, parseResult.Result)
Reply(result)
else
Reply(parseResult.Status, parseResult.Error)

使用示例(这也恰好是我编写的用于确认它有效的测试代码):
let pThing = trackLocation pfloat
let test p str =
match run p str with
| Success((loc, result), _, _) -> printfn "Success: %A at location: %A" result loc; result
| Failure(errorMsg, _, _) -> printfn "Failure: %s" errorMsg; 0.0
test pThing "3.5"
// Prints: Success: 3.5 at location: {from = (Ln: 1, Col: 1);
// to = (Ln: 1, Col: 4);
// text = "3.5";}

编辑: Stephan Tolksdorf(FParsec 的作者)在评论中指出 withSkippedString组合器存在。那个可能会更简单,因为您不必编写 CharStream -自己消费功能。 ( skipped 组合器将返回解析器匹配的字符串,但不返回解析器的结果,而 withSkippedString 将解析器的结果和跳过的字符串传递到您提供的函数中)。通过使用 withSkippedString组合器,你可以使用你原来的 trackLocation功能只有很小的变化。 trackLocation的更新版本看起来像这样:
let trackLocation (parser: Parser<'A, 'B>): Parser<SourceLocation * 'A, 'B> =
let mkLocation ((start: Position, (text: string, data: 'A)), stop: Position) =
let location = { from = start; ``to`` = stop; text = text }
in (location, data)
getPosition .>>. (parser |> withSkippedString (fun a b -> a,b)) .>>. getPosition |>> mkLocation

(我对这里元组的排列不是 100% 满意,因为它会导致元组中的元组中的元组。不同的组合子顺序可能会产生更好的签名。但因为它是一个不适合公共(public)消费的内部函数,函数签名中令人讨厌的元组嵌套可能没什么大不了的,所以我保持原样。如果你想要更好的函数签名,你可以重新排列它)。

我原始答案中的相同测试代码在此更新版本的函数中运行良好,并打印相同的结果:开始位置(第 1 行,第 1 列),结束位置(第 1 行,第 4 列)和解析文本 "3.5" .

关于parsing - FParsec:如何保存解析器成功的文本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51017471/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com