scala – 如何使用解析器组合器进行条件检查
我试图编写一个简单的html模板引擎(为了好玩),并想解析这样的结构
A.正常行是HTML B.如果一行以$开头,则将其视为java代码行 $if (isSuper) { <span>Are you wearing red underwear?</span> $} C.如果${}包装多行,则其中的所有代码都应该是java代码. D.如果一行以$include开头,那就行了一些技巧(调用另一个模板) $include anotherTemplate(id,name) 这将创建anotherTemplate的新实例,并调用它的render()方法 E.除了$include之外还会有更多的“命令”,比如$def,$val. 如何在解析器组合器中表达这一点?实际上它是一个条件分叉 对于1.和2.,我有这样的事情: '$' ~> ( '{' ~> upto('}') <~ '}' | not('{') <~ newline ) 其中upto是从Scalate Scamel解析器借来的(我刚刚开始阅读并且不太了解) 我没有使用(‘{‘)来区分$….代码行和${…}块.但这很麻烦,不会扩展到其他“命令” 那我该怎么办呢? 解决方法
你对not的使用是多余的. |方法实现有序选择;第二件事只有在第一件事失败时才会尝试.这应该做的伎俩:
def directive: Parser[Directive] = ( '$' ~> ( '{' ~> javaStuff <~ '}' | "include" ~> includeDirective | "def" ~> defDirective | "val" ~> valDirective | javaDirective ) | htmlDirective ) def templateFile: Parser[List[Directive]] = (directive <~ 'n').* 为了更快地解析和更好的错误消息,您应该尽可能频繁地“提交”解析器.我认为当你不使用(‘{‘)时,这就是你想要的. 现在,如果上面的解析器看到一个’$’后跟一个'{‘然后看不到javaStuff,它将回溯并考虑剩下的四个’$’中的每一个 – 顺序排列(include,def,val),最后是javaDirective),然后回溯到’$’之前尝试htmlDirective,然后失败了一个莫名其妙的错误消息.但是,如果我们看到'{‘,我们知道其他替代方案都不可能成功,那么我们为什么要检查它们呢?同样,以’$’开头的行永远不会是htmlDirective. 我们希望像'{‘这样的东西成为没有回头路的东西;如果后’ – ”解析器失败并想要回溯,我们应该将其停在轨道上并将导致回溯的故障直接传播给用户作为错误. 执行此操作的方法是使用commit.当应用于解析器p时,此函数/组合器查看从p出来的ParseResult并将其更改为Error(完全放弃信号),如果它最初是故障(回溯信号),则保持不变除此以外.通过适当使用commit,指令解析器变为: def directive: Parser[Directive] = ( '$' ~> commit( '{' ~> commit(javaStuff <~ '}') | "include" ~> commit(includeDirective) | "def" ~> commit(defDirective) | "val" ~> commit(valDirective | javaDirective ) | htmlDirective ) 当我第一次学会使用解析库时,我发现查看the source code for (其他一些提示:append和ParseResult#append的目的是决定应该将一系列解析替代方案中的哪些失败传播给用户.现在暂时忽略它们.另外,我不会太担心> > / flatMap / into直到你得到更多的练习;当它的时间,请阅读Daniel Sobral’s explanation.最后,我从来没有使用过|||,你可能也不会.快乐的解析!) 希望这可以帮助. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |