如何使用解析器组合器进行条件检查

|| 我试图编写一个简单的html模板引擎(为了好玩),并且想解析这样的结构 A.正常行是HTML B.如果一行以ѭ0开头,则将其视为Java代码行
$ if (isSuper) {
    <span>Are you wearing red underwear?</span>
$ }
C.如果
${}
换行,则其中的所有代码应为Java代码。 D.如果一行以ѭ3开头,则在该行上做一些技巧(调用另一个模板)
$include anotherTemplate(id, name)
这将创建一个新的
anotherTemplate
实例,并调用它的
render()
方法 E.并且会有比“ 3”更多的“命令”,例如“ 8”,“ 9”。 如何在解析器组合器中表达这一点?实际上,它是有条件的分叉 对于1.和2.,我得到的是这样的:
\'$\' ~> ( \'{\' ~> upto(\'}\') <~ \'}\' |  not(\'{\') <~ newline )
从Scalate Scamel解析器中借来的ѭ11(我刚刚开始阅读,不太了解) 我用
not(\'{\')
区分
$....
代码行和
${...}
块。但这很麻烦,并且不会扩展到其他“命令” 那么我该怎么做呢?     
已邀请:
        您使用
not
是多余的。
|
方法实现有序选择;仅当第一件事失败时,才尝试第二件事。这应该可以解决问题:
def directive: Parser[Directive] =
  ( \'$\' ~>
    ( \'{\' ~> javaStuff <~ \'}\'
    | \"include\" ~> includeDirective
    | \"def\"     ~> defDirective
    | \"val\"     ~> valDirective
    | javaDirective
    )
  | htmlDirective
  )

def templateFile: Parser[List[Directive]] = (directive <~ \'\\n\').*
为了更快地分析和提供更好的错误消息,您应该尽可能频繁地“提交”解析器。我认为这是您使用
not(\'{\')
时要尝试达到的目标。 现在,如果上面的解析器看到一个
\'$\'
,接着是一个
\'{\'
,然后看不到
javaStuff
,它将回溯并按顺序考虑其余四个
\'$\'
替代字(
include
def
val
,最后是ѭ26each) ),然后回溯到
\'$\'
之前尝试
htmlDirective
,然后失败,并显示令人困惑的错误消息。但是,如果看到
\'{\'
,我们知道其他任何选择都不可能成功,那么为什么还要检查它们呢?同样,以
\'$\'
开头的行也不能是
htmlDirective
。 我们希望像“ѭ20”这样的东西成为不可回溯的点;如果20后解析器失败并想要回溯,我们应该将其停止在其轨道中,并将造成回溯的失败作为错误直接传播给用户。 这样做的方法是使用
commit
。此功能/组合器在应用于解析器
p
时,会查看从
p
出来的
ParseResult
,如果原本是
Failure
(回溯信号),则将其更改为
Error
(完全放弃信号),而保持不变。除此以外。适当使用
commit
directive
解析器将变为:
def directive: Parser[Directive] =
  ( \'$\' ~> commit( \'{\' ~> commit(javaStuff <~ \'}\')
                 | \"include\" ~> commit(includeDirective)
                 | \"def\"     ~> commit(defDirective)
                 | \"val\"     ~> commit(valDirective
                 | javaDirective
                 )
  | htmlDirective
  )
当我第一次学习使用解析库时,我发现查看ѭ43的源代码确实很有帮助;它使其中的一些内容更加清晰。 (其他一些技巧:
append
ParseResult#append
的目的是决定应将一系列解析方案中的哪些故障传播给用户。现在就忽略它们。而且,我也不必担心
>>
/
flatMap
/
into
,直到您有更多的练习;这时候,请阅读Daniel Sobral的解释。最后,我再也不必使用
|||
,您也可能不会用。 !) 希望这可以帮助。     

要回复问题请先登录注册