6

我的 AST 模型需要携带位置信息(文件名、行、索引)。是否有任何内置方法可以访问此信息?从参考文档中,流似乎带有位置,但我希望我不必为了保存位置而实现虚拟解析器,并在任何地方添加它。

提前致谢

4

1 回答 1

9

Parsers are actually type abbreviations for functions from streams to replies:

Parser<_,_> is just CharStream<_> -> Reply<_>

Keeping that in mind, you can easily write a custom parser for positions:

let position : CharStream<_> -> Reply<Position> = fun stream -> Reply(stream.Position)
(* OR *)
let position : Parser<_,_> = fun stream -> Reply stream.Position

and atttach position information to every bit you parse using

position .>>. yourParser (*or tuple2 position yourParser*)

position parser does not consume any input and thus it is safe to combine in that way.

You can keep the code change required restricted to a single line and avoid uncontrollable code spread:

type AST = Slash of int64
         | Hash  of int64

let slash : Parser<AST,_> = char '/' >>. pint64 |>> Slash
let hash  : Parser<AST,_> = char '#' >>. pint64 |>> Hash
let ast   : Parser<AST,_> = slash <|> hash

(*if this is the final parser used for parsing lists of your ASTs*)
let manyAst  : Parser<            AST  list,_> = many                (ast  .>> spaces)

let manyAstP : Parser<(Position * AST) list,_> = many ((position .>>. ast) .>> spaces)
(*you can opt in to parse position information for every bit
  you parse just by modifiying only the combined parser     *)

Update: FParsec has a predefined parser for positions: http://www.quanttec.com/fparsec/reference/charparsers.html#members.getPosition

于 2011-06-14T22:32:57.153 回答