我正在为这种形式的字符串编写一个FParsec解析器:
do[ n times]([ action] | \n([action]\n)*endDo)
Run Code Online (Sandbox Code Playgroud)
换句话说,这是一个带有可选时间量词的"do"语句,以及一个"action"语句或"action"列表(每个都在新行上),末尾有"end do"(I为简单起见省略了缩进/尾随空格处理.
这些是有效输入的示例:
do action
do 3 times action
do
endDo
do 3 times
endDo
do
action
action
endDo
do 3 times
action
action
endDo
Run Code Online (Sandbox Code Playgroud)
这看起来并不复杂,但是:
为什么这不起作用?
let statement = pstring "action"
let beginDo = pstring "do"
>>. opt (spaces1 >>. pint32 .>> spaces1 .>> pstring "times")
let inlineDo = tuple2 beginDo (spaces >>. statement |>> fun w -> [w])
let expandedDo = (tuple2 (beginDo .>> newline)
(many (statement .>> newline)))
.>> pstring …
Run Code Online (Sandbox Code Playgroud) 我遇到了解析器有两个递归分支的问题.为了更容易地证明这个问题,我使用Luca Bolognese撰写的文章中的lambda演算的简单语法作为例子:
Run Code Online (Sandbox Code Playgroud)<expression> ::= <name> | <function> | <application> <name> ::= nonblank character sequence <function> ::= \ <name> . <body> <body> ::= <expression> <application> ::= ( <function expression> <argument expression> ) <function expression> ::= <expression> <argument expression> ::= <expression>
文章中的解析器非常简洁:
let ws = " \t\n"
let specialChars = ".)(\\\n"
let pWs = spaces
let pName = manyChars (noneOf (ws + specialChars)) |>> EName
let pExpr, pExprRef = createParserForwardedToRef<Expression, Unit>()
let curry2 f a b = f(a,b)
let pFunction …
Run Code Online (Sandbox Code Playgroud) 我以为我会尝试使用FParsec编写一个快速解析器,并很快意识到many
返回列表是一个严重的性能问题.然后我发现了一个ResizeArray
在文档中使用a的替代方法:
let manyA2 p1 p =
Inline.Many(firstElementParser = p1,
elementParser = p,
stateFromFirstElement = (fun x0 ->
let ra = ResizeArray<_>()
ra.Add(x0)
ra),
foldState = (fun ra x -> ra.Add(x); ra),
resultFromState = (fun ra -> ra.ToArray()),
resultForEmptySequence = (fun () -> [||]))
let manyA p = manyA2 p p
Run Code Online (Sandbox Code Playgroud)
在我的代码中使用它会使它运行速度快几倍.那么为什么FParsec默认使用列表而不是ResizeArray
?
我试图使用库中的pipe3
函数,FParsec
但我得到一个错误,我不知道如何解决.
鉴于记录
type Point = { x: float; y: float }
Run Code Online (Sandbox Code Playgroud)
和以下解析器
let plistoffloats' =
pipe3 pfloat (pchar ',' .>> spaces) pfloat
(fun first z second -> { x = first; y = second })
Run Code Online (Sandbox Code Playgroud)
我试图实现的是一个解析器,它接收格式的字符串"1.1, 3.7"
并返回一个Point
run plistoffloats' "1.1, 3.7"
Run Code Online (Sandbox Code Playgroud)
输入:"1.1, 3.7"
期望的输出:Point = {x = 1.1; y = 3.7;}
错误:
错误FS0030:值限制.值'plistoffloats''被推断为具有泛型类型val plistoffloats':
Parser <Point,'__a>
将'plistoffloats'的参数显式化,或者,如果您不打算将它作为泛型,则添加类型注释.
一个更简单的例子pchar
也没有用.
let parsesA = pchar 'a'
Run Code Online (Sandbox Code Playgroud)
错误FS0030:值限制.值'parsesA'被推断为具有泛型类型val parsesA:
Parser<char,'_a> …
我想将FParsec createParserForwardedToRef函数与通用的Expr联合一起使用,如下所示:
type Expr<'Term> =
| Unary of Operator * Expr<'Term>
| Binary of Operator * Expr<'Term> * Expr<'Term>
| Ternary of Operator * Expr<'Term> * Expr<'Term> * Expr<'Term>
| Term of 'Term
let expr, exprR = createParserForwardedToRef<Expr<'T>,unit>()
Run Code Online (Sandbox Code Playgroud)
我无法摆脱价值限制错误.我不能变成expr
CLR功能,更不用说了exprR
.
我通常如何处理这种情况?
说我有一些文字:
a = "foobarbaz"
b = "foobar"
c = "foo"
d = "rubbish"
e = "foobazbar"
Run Code Online (Sandbox Code Playgroud)
和三个解析器foo,bar和baz分别用于字符串'foo','bar'和'baz'.
我如何创建一个可以给我结果的解析器:
a = ["foo", "bar", "baz"]
b = ["foo", "bar"]
c = ["foo"]
d = []
e = ["foo"]
Run Code Online (Sandbox Code Playgroud)
什么时候对上面的输入运行?在构建列表时,基本上尝试每种可能性直到失败.我可以使用用户状态,但我想尽可能避免.(我想让各个解析器自己对用户状态一无所知)
我得到的最接近的是下面的fooseq:
let foo = pstring "foo"
let bar = pstring "bar"
let baz = pstring "baz"
let foobar = pipe2 foo bar Seq.of2
let foobarbaz = pipe3 foo bar baz Seq.of3
let fooseq = choice (Seq.map attempt [foobarbaz; foobar; foo |>> Seq.of1 ;]) …
Run Code Online (Sandbox Code Playgroud) 我正在尝试使用 FParsec 来解析 TOML 多行字符串,但在使用结束分隔符 ( """
) 时遇到了问题。我有以下解析器:
let controlChars =
['\u0000'; '\u0001'; '\u0002'; '\u0003'; '\u0004'; '\u0005'; '\u0006'; '\u0007';
'\u0008'; '\u0009'; '\u000a'; '\u000b'; '\u000c'; '\u000d'; '\u000e'; '\u000f';
'\u0010'; '\u0011'; '\u0012'; '\u0013'; '\u0014'; '\u0015'; '\u0016'; '\u0017';
'\u0018'; '\u0019'; '\u001a'; '\u001b'; '\u001c'; '\u001d'; '\u001e'; '\u001f';
'\u007f']
let nonSpaceCtrlChars =
Set.difference (Set.ofList controlChars) (Set.ofList ['\n';'\r';'\t'])
let multiLineStringContents : Parser<char,unit> =
satisfy (isNoneOf nonSpaceCtrlChars)
let multiLineString : Parser<string,unit> =
optional newline >>. manyCharsTill multiLineStringContents (pstring "\"\"\"")
|> between (pstring "\"\"\"") (pstring "\"\"\"")
let …
Run Code Online (Sandbox Code Playgroud) I am trying to tackle the scariest part of programming for me and that is parsing and ASTs. I am working on a trivial example using F# and FParsec. I am wanting to parse a simple series of multiplications. I am only getting the first term back though. Here is what I have so far:
open FParsec
let test p str =
match run p str with
| Success(result, _, _) -> printfn "Success: %A" result
| Failure(errorMsg, _, _) …
Run Code Online (Sandbox Code Playgroud) 我想使用FParsec解析字符串文字.通过"字符串文字"我的意思是开始和结束报价(在我的情况下 - 单引号):
'Please, switch off your mobile phone'
Run Code Online (Sandbox Code Playgroud)
我目前正在做的是以下内容:
let string = between (pstring "'") (pstring "'") (manySatisfy isLetter)
Run Code Online (Sandbox Code Playgroud)
但是在消耗掉第一个字母后停止了.有没有办法让它变得贪婪?
我正在尝试使用 FParsec 解析 C 风格注释。不知道为什么会失败:
我的解析器代码:
let openComment : Parser<_,unit> = pstring "/*"
let closeComment : Parser<_,unit> = pstring "*/"
let comment = pstring "//" >>. restOfLine true
<|> openComment >>. (charsTillString "*/" true System.Int32.MaxValue) |>> Comment
//<|> openComment >>. manyCharsTill anyChar closeComment |>> Comment
let spaceComments = many ((spaces1 |>> IgnoreU) <|> comment)
let str s = spaceComments >>. pstring s .>> spaceComments
Run Code Online (Sandbox Code Playgroud)
测试线束:
let testStr = @"
// test comment
/* a block comment
*/
x // another …
Run Code Online (Sandbox Code Playgroud) 是否有一些'日期解析器'库可以用于日期FParsec对字符串的作用?
也就是说,您要么指定规则,要么匹配它们以识别提供的模式.
相反,是否有任何库可以根据一些解析规则生成日期?这个想法是为用户提供"实时"完成,以指导他进行有效的未来fparsec匹配.
(生成解析的这个问题在僻静的解析圈中有一个名字吗?)
我似乎无法使用FParsec成功解析标准输入流.我把我的情况简化为这个非常简单的代码:
match (runParserOnStream (pstring "test" .>> FParsec.CharParsers.newline) () "stdin" (Console.OpenStandardInput ()) Console.InputEncoding) with
| Success(result, _, _) -> printfn "Success: %A" result
| Failure(errorMsg, perr, _) -> printfn "Failure: %s" errorMsg
Run Code Online (Sandbox Code Playgroud)
但是,当我运行程序时,输入字符串测试,然后按Enter,它挂起,我似乎无法弄清楚为什么..
什么是解决方案?