【发布时间】:2021-01-08 06:03:27
【问题描述】:
我正在使用 FParsec 编写递归解析器,因此我正在使用 createParserForwardedToRef 创建一个虚拟解析器和引用单元,如下所示:
let pstatement, pstatementref = createParserForwardedToRef<Statement, Unit>()
参考单元最终“分配”以下内容:
do pstatementref := choice [
pread
pdisplay
pset
pcompute
pif
pwhile
]
当我从创建引用单元格并使用以下代码分配上述值的文件中测试解析器 pstatement 时...
let test p str =
match runParserOnFile p () str Encoding.ASCII with
| Success(result, _, _) -> printfn "Success: %A" result
| Failure(errorMsg, _, _) -> printfn "Failure: %s" errorMsg
[<EntryPoint>]
let main argv =
argv
|> String.concat "+"
|> test (manyTill pstatement (pword "HALT"))
0
...效果很好,我得到了成功的结果。
但是,当我尝试运行完全相同的测试函数时,这次来自另一个项目(称为解释器),该项目引用了其中定义了 pstatement 的项目(称为解析器,在从 Program.fs 中删除主函数之后解析器),我收到以下错误:
Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object.
at FParsec.Primitives.manyTill@890.Invoke(CharStream`1 stream)
at FParsec.CharParsers.applyParser[Result,UserState](FSharpFunc`2 parser, CharStream`1 stream)
at FParsec.CharParsers.runParserOnFile[a,u](FSharpFunc`2 parser, u ustate, String path, Encoding encoding)
at Program.test[a](FSharpFunc`2 p, String str) in /home/rosalogia/Projects/FSharp/PCParser/src/Interpreter/Program.fs:line 16
at Program.main(String[] argv) in /home/rosalogia/Projects/FSharp/PCParser/src/Interpreter/Program.fs:line 32
...这意味着永远不会为引用单元格分配任何值,但是这样做的代码尚未从 Parser 项目中删除。
我不知道导致此问题的参考单元是否存在限制?由于在定义参考单元格的文件中一切正常,因此可以安全地得出结论,问题在于从定义它的文件或项目之外的文件或项目访问其值。
编辑:
这里有一个更完整的例子来说明如何设置
解析器/库.fs
namespace PCParser
module Parser =
let pstatement, pstatementref = createParserForwardedToRef<Statement, Unit>()
let pread = ...
let pdisplay = ...
...
do pstatementref := choice [
pread
pdisplay
pset
pcompute
pif
pwhile
]
解释器/Program.fs
open PCParser.Parser
open FParsec
open System.Text
let test p str =
match runParserOnFile p () str Encoding.ASCII with
| Success(result, _, _) -> printfn "Success: %A" result
| Failure(errorMsg, _, _) -> printfn "Failure: %s" errorMsg
[<EntryPoint>]
let main argv =
argv
|> String.concat "+"
|> test (manyTill pstatement (pword "HALT"))
0
【问题讨论】:
-
分配引用的调用到底在哪里?你是怎么执行的?
-
分配引用的调用在 Parser 项目和模块中,我
open来自 Interpreter 项目。我的假设是在打开模块时默认会执行分配。 -
你能发布一个最小的复制吗?从您的解释中不清楚什么包含/嵌套在哪里。
-
我试图在编辑中澄清事情是如何设置的。 Tomas 的最小示例可以作为我问题的最小复制,但是我仍然不确定如何解决它。我最近才将 Parser 项目更改为 classlib,但问题仍然存在。
标签: functional-programming f# fparsec