您最好的选择是使用适当的编程语言对其进行实际编码。CFG 是矫枉过正的,因为编写一些(如您所说)“相当复杂”的规则可能非常困难。例如,语法不适合谈论事物的数量。
例如,您将如何用这种语言编写“樱桃的数量大于任何其他物体的数量”?你给程序的人会怎么做?CFG 不能轻易地表达这些概念,而正则表达式无论如何也不能理智地做到这一点。
答案是语法不适合这项任务,除非老虎机试图造英语句子。
您还必须考虑当两个或更多“奖品序列”匹配时会发生什么!假设您想颁发最高奖,您需要一个有序的识别器列表。这并不是说除了任意函数之外,您不能使用(例如)正则表达式对识别器进行编码。我只是说一般的 CFG 解析是多余的,因为 CFG 让你超越常规语言(即正则表达式)的是能够考虑任意深度的解析树(如 N 级或更高级别的嵌套括号),这可能不是你关心什么。
例如,这并不是说您不想允许正则表达式。您可以通过使用解析器生成器来识别涉及樱桃香蕉和梨的正则表达式来简化这项工作,请参阅http://en.wikipedia.org/wiki/Comparison_of_parser_generators,然后您可以将其嵌入,尽管您可能想简单地滚动自己的递归下降解析器(再次假设您不关心 CFG,特别是如果您的令牌是有界长度的)。
例如,下面是我可以用伪代码实现它的方式(理想情况下,您会使用具有良好列表操作的静态类型检查语言,我无法想到):
rules = []
function Rule(name, code) {
this.name = name
this.code = code
rules.push(this) # adds them in order
}
##########################
Rule("All the same", regex(.*))
Rule("No two-in-a-row", function(list, counts) {
not regex(.{2}).match(list)
})
Rule("More cherries than anything else", function(list, counts) {
counts[cherries]>counts[x] for all x in counts
or
sorted(counts.items())[0]==cherries
or
counts.greatest()==cherries
})
for token in [cherry, banana, ...]:
Rule("At least 50% "+token, function(list, counts){
counts[token] >= list.length/2
})