我正在处理我正在制作的语言的解析阶段,并且遇到以下问题。
let test2 = // I'd like this to be an error.
"""
2
+ 2
"""
let result = run (spaces >>. expr) test2
val result : ParserResult<CudaExpr,unit> =
Success: Add (LitInt32 2,LitInt32 2)
当条款缩进时,我已设法制作以下示例
2 +
2
给我一个错误,但不是当操作员处于错误的缩进级别时。我需要像解析前检查一样的东西。
let operators expr i =
let f expr (s: CharStream<_>) = if i <= s.Column then expr s else pzero s
opp.TermParser <- f expr
f opp.ExpressionParser
以上函数是运算符阶段的结构,正如您所看到的,术语解析器包含在执行缩进检查的函数中,但最后一行是错误的。
以下是完整解析器的简化示例。
#r "../../packages/FParsec.1.0.2/lib/net40-client/FParsecCS.dll"
#r "../../packages/FParsec.1.0.2/lib/net40-client/FParsec.dll"
open FParsec
type Expr =
| V of string
| Add of Expr * Expr
let identifier = many1Satisfy2L isAsciiLetter (fun x -> isAsciiLetter x || isDigit x || x = ''') "identifier" .>> spaces |>> V
let indentations expressions (s: CharStream<_>) =
let i = s.Column
let expr_indent expr (s: CharStream<_>) =
let expr (s: CharStream<_>) = if i <= s.Column then expr s else pzero s
many1 expr s
expr_indent (expressions i) s
let expr =
let opp = new OperatorPrecedenceParser<_,_,_>()
opp.AddOperator(InfixOperator("+", spaces, 6, Associativity.Left, fun x y -> Add(x,y)))
let operators expr i =
let f (s: CharStream<_>) = if i <= s.Column then expr s else pzero s
opp.TermParser <- f
f opp.ExpressionParser
let rec expr s = indentations (operators identifier) s
expr
let test2 = // I'd like this to be an error.
"""
a
+
b
"""
let result = run (spaces >>. expr) test2
到目前为止,完整的解析器可以找到here。
答案 0 :(得分:0)
expr s
我在2.5周前没有意识到这一点,但是当一个新的块被打开并且let poperator: Parser<_,_> =
let f c = (isAsciiIdContinue c || isAnyOf [|' ';'\t';'\n';'\"';'(';')';'{';'}';'[';']'|] c) = false
(many1Satisfy f .>> spaces)
>>= fun token ->
match dict_operator.TryGetValue token with
| true, x -> preturn x
| false, _ -> fail "unknown operator"
let rec led poperator term left (prec,asoc,m) =
match asoc with
| Associativity.Left | Associativity.None -> tdop poperator term prec |>> m left
| Associativity.Right -> tdop poperator term (prec-1) |>> m left
| _ -> failwith "impossible"
and tdop poperator term rbp =
let rec f left =
poperator >>= fun (prec,asoc,m as v) ->
if rbp < prec then led poperator term left v >>= loop
else pzero
and loop left = attempt (f left) <|>% left
term >>= loop
let operators expr i (s: CharStream<_>) =
let expr_indent expr (s: CharStream<_>) = expr_indent i (<=) expr s
let op s = expr_indent poperator s
let term s = expr_indent expr s
tdop op term 0 s
被调用时会发生的事情是,术语解析器被新的缩进覆盖,并且没有办法备份它退出时恢复它。为了我的目的,我做了一些环顾四周并设法调整了Pratt自上而下的解析方法。
道格拉斯·克罗克福德(Douglas Crockford)就这个方法提出了a talk。
led
执行实际优先级解析的tdop
和select distinct top 1000
u.id as userID
, u.firstName as userFirstName
, u.email as userEmail
, u.phone as userPhone
, ueo.opensEmailCounter
, ush.opensSmsCounter
from dbo.Users u
left join (
select
userID
, count(*) as opensEmailCounter
from dbo.UserEmailsOpens
where targetID = 4
group by userID
) ueo
on u.id = ueo.userID
left join (
select
userID
, count(*) as opensSmsCounter
from dbo.UserSmsHistory
where targetID = 4
and opened = 1
group by userID
) ush
on u.id = ush.userID
where u.deleted = 0
and IsNull(u.firstName, '') != ''
and IsNull(u.email, '') != ''
and IsNull(u.phone, '') != ''
函数长度为10行。上面只是我所用语言的full parser的片段 - 在语法方面它类似于F#并且是缩进敏感的。这是Douglas Crockford F# translation更为直截了当的Javascript example。