Parsing 如何让字符串解析器终止

Parsing 如何让字符串解析器终止,parsing,elm,Parsing,Elm,我有一个用于双引号字符串的解析器,大多数情况下工作正常,但当结束引号丢失时,它将永远循环并使应用程序崩溃 它是用Elm编写的web应用程序的一部分,并使用 它基于来自Elm Github的 下面是一个简单的示例(;将toParse更改为“\”,它会使选项卡崩溃) 模块主显示(主) 导入Html 将解析器导入为P公开((|.),(|=) 导入调试 stringP:P.Parser字符串 斯特林普= 成功身份 |.P.token“\” |=P.loop[]字符串帮助 stringHelp:List

我有一个用于双引号字符串的解析器,大多数情况下工作正常,但当结束引号丢失时,它将永远循环并使应用程序崩溃

它是用Elm编写的web应用程序的一部分,并使用

它基于来自Elm Github的

下面是一个简单的示例(;将toParse更改为“\”,它会使选项卡崩溃)

模块主显示(主)
导入Html
将解析器导入为P公开((|.),(|=)
导入调试
stringP:P.Parser字符串
斯特林普=
成功身份
|.P.token“\”
|=P.loop[]字符串帮助
stringHelp:List String->P.Parser(P.Step(List String)String)
stringHelp revChunks=
第1页
[P.token”\“”
|>P.map(\ \ \->P.Done(String.join”“(List.revChunks)))
,P.chompWhile是无趣的
|>P.getChompedString
|>P.map(\chunk->P.Loop(chunk::revChunks))
]                                                             
无趣:Char->Bool
这是一个无趣的字符=
char/='\\'&&char/=''''
托帕尔斯=
"\""
主要=

Html.text我发现一个解决方案是跟踪解析位置,如果位置没有增加,就退出循环。不过这不是很漂亮;也许有人会想出更好的方法

代码如问题中的示例所示,但有以下更改():

stringP:P.解析器字符串
斯特林普=
成功身份
|.P.token“\”
|=P.loop([],0)stringHelp
|.P.token“\”
stringHelp:(列表字符串,Int)->P.Parser(P.Step(列表字符串,Int)字符串)
stringHelp(revChunks,offset)=
P.成功(stepHelp补偿)
|=stringHelp2 revChunks
|=P.getOffset
stepHelp:Int->(P.Step(列表字符串)字符串)->Int->P.Step(列表字符串,Int)字符串
stepHelp oldOffset步长newOffset=
案例步骤
P.完成str->
P.完成str
P.循环块->
如果newOffset>oldOffset,则
P.循环(revChunks、newOffset)
其他的
P.完成P.getChompedString
|>P.map(\chunk->P.Loop(chunk::revChunks))

这会导致所需的解析器错误,即缺少引号。

这里有一个替代解决方案,如果字符串过早终止(),则检查
end
标记:

模块主显示(主)
导入Html
将解析器导入为P公开((|.),(|=)
导入调试
stringP:P.Parser字符串
斯特林普=
(P.1)身份
|.P.token“\”
|=P.loop[]字符串帮助
)|>P.然后
(\res->
案件
确定str->P.成功str
错误消息->P.问题消息
)
stringHelp:List String->P.Parser(P.Step(List String)(结果字符串))
stringHelp revChunks=
第1页
[P.end
|>P.map(\ \ \->P.Done(Err“字符串过早结束”))
,P.token“\”
|>P.map(\ \ \->P.Done(Ok(String.join”“(List.revChunks)))
,P.chompWhile是无趣的
|>P.getChompedString
|>P.map(\chunk->P.Loop(chunk::revChunks))
]                                                             
无趣:Char->Bool
这是一个无趣的字符=
char/='\\'&&char/=''''
托帕尔斯=
“嗨”
主要=
Html.text
module Main exposing (main)

import Html
import Parser as P exposing ((|.), (|=))
import Debug


stringP : P.Parser String                                             
stringP =
    P.succeed identity 
        |. P.token "\""                                               
        |= P.loop [] stringHelp


stringHelp : List String -> P.Parser (P.Step (List String) String)    
stringHelp revChunks =                                                
    P.oneOf        
        [ P.token "\""                                                
            |> P.map (\_ -> P.Done (String.join "" (List.reverse revChunks)))  
        , P.chompWhile isUninteresting                                
            |> P.getChompedString                                     
            |> P.map (\chunk -> P.Loop (chunk :: revChunks))          
        ]                                                             


isUninteresting : Char -> Bool
isUninteresting char =
    char /= '\\' && char /= '"'


toParse =
    "\""


main =
    Html.text <| Debug.toString <| P.run stringP toParse
stringP : P.Parser String                                             
stringP =
    P.succeed identity 
        |. P.token "\""                                               
        |= P.loop ([], 0) stringHelp
        |. P.token "\""


stringHelp : (List String, Int) -> P.Parser (P.Step (List String, Int) String)
stringHelp (revChunks, offset) =
    P.succeed (stepHelp offset)
        |= stringHelp2 revChunks
        |= P.getOffset


stepHelp : Int -> (P.Step (List String) String) -> Int -> P.Step (List String, Int) String
stepHelp oldOffset step newOffset =
    case step of
        P.Done str ->
            P.Done str

        P.Loop revChunks ->
            if newOffset > oldOffset then                              
                P.Loop (revChunks, newOffset)
            else
                P.Done <| String.join "" <| List.reverse revChunks    



stringHelp2 : List String -> P.Parser (P.Step (List String) String)    
stringHelp2 revChunks =                                                
    P.chompWhile isUninteresting                                
        |> P.getChompedString                                     
        |> P.map (\chunk -> P.Loop (chunk :: revChunks))          
module Main exposing (main)

import Html
import Parser as P exposing ((|.), (|=))
import Debug


stringP : P.Parser String                                             
stringP =
    ( P.succeed identity 
        |. P.token "\""                                               
        |= P.loop [] stringHelp
    ) |> P.andThen
    ( \res ->
      case res of
        Ok str -> P.succeed str
        Err msg -> P.problem msg
    )
                                                                      
        
stringHelp : List String -> P.Parser (P.Step (List String) (Result String String))
stringHelp revChunks =                                                
    P.oneOf        
        [ P.end
            |> P.map (\_ -> P.Done (Err "string ended prematurely"))
        , P.token "\""                                                
            |> P.map (\_ -> P.Done (Ok (String.join "" (List.reverse revChunks))))
        , P.chompWhile isUninteresting                                
            |> P.getChompedString                                     
            |> P.map (\chunk -> P.Loop (chunk :: revChunks))          
        ]                                                             


isUninteresting : Char -> Bool
isUninteresting char =
    char /= '\\' && char /= '"'


toParse =
    "\"hi\""


main =
    Html.text <| Debug.toString <| P.run stringP toParse