首页 > 解决方案 > Haskell 解析查询 (Parsec)

问题描述

我正在尝试在 Haskell 中创建查询解析器,但不明白我应该如何允许解析器逻辑的不同可选路径。我的尝试:

query :: Parser Query
query = do
    -- add more queries
    reserved "SELECT"
    select <- sequenceOfExpr
    reserved "FROM"
    table <- identifier
    semi
    return $ Select select table (BoolConst True)
    <|> do
    reserved "SELECT"
    select <- sequenceOfExpr
    reserved "FROM"
    table <- identifier
    reserved "WHERE"
    whereQ <- bExpression
    semi
    return $ Select select table whereQ
    <|> do
    reserved "INSERT"
    insert <- sequenceOfExpr
    reserved "INTO"
    table <- identifier
    semi
    return $ Insert insert table
    <|> do
    reserved "REMOVE"
    reserved "FROM"
    table <- identifier
    reserved "WHERE"
    whereQ <- bExpression
    semi
    return $ Remove table whereQ
    <|> do
    reserved "CREATE"
    table <- identifier
    fields <- sequenceOfExpr
    semi
    return $ Create table fields
    <|> do
    reserved "DROP"
    table <- identifier
    semi
    return $ Drop table

在解析与第一个 do stmt 结构相对应的字符串时有效,例如:

"SELECT testField FROM testTable;"

但不是为了其他人。例如解析时:

"SELECT testField FROM testTable WHERE TRUE"

它没有尝试其他路径,而是返回:

unexpected "W"
expecting ";"

换句话说,它似乎只尝试了第一个逻辑。我究竟做错了什么?

任何帮助将非常感激!

标签: parsinghaskelllogicexpressionparsec

解决方案


发生这种情况是因为SELECT FROM替代方案已成功并返回其结果,解析从未尝试过SELECT FROM WHERE替代方案。

在这种特定情况下,我只会颠倒他们的顺序:SELECT FROM WHERE先尝试,如果这不起作用,则回退到SELECT FROM. 您还需要将其包装在 atry中,以便解析器回滚到查询的开头。

或者,您可以将WHERE解析作为解析器的条件部分SELECT FROM,如下所示:

do
    reserved "SELECT"
    select <- sequenceOfExpr
    reserved "FROM"
    table <- identifier
    whereQ <- try (reserved "WHERE" *> bExpression) <|> (pure $ BoolConst True)
    semi
    return $ Select select table whereQ

推荐阅读