【发布时间】:2009-10-01 20:58:06
【问题描述】:
所以我正在做一个解析器,我更喜欢灵活性而不是速度,我希望它易于编写语法,例如没有棘手的变通规则(解决冲突等的假规则,就像你在 yacc/bison 等中必须做的那样)
有一个带有一组固定标记(例如 PLUS、DECIMAL、STRING_LIT、NAME 等)的手动编码词法分析器,现在有三种类型的规则:
- TokenRule:匹配特定的令牌
- SequenceRule:匹配有序的规则列表
- GroupRule:匹配列表中的任何规则
例如,假设我们有 TokenRule 'varAccess',它匹配令牌 NAME(大致 /[A-Za-z][A-Za-z0-9_]*/)和 SequenceRule 'assignment',匹配[表达式, TokenRule(PLUS), 表达式]。
Expression 是与“assignment”或“varAccess”匹配的 GroupRule(我正在测试的实际规则集更完整,但对于示例来说就可以了)
但是现在假设我要解析
var1 = var2
假设解析器以规则表达式开头(定义它们的顺序无关紧要 - 稍后将解决优先级)。假设 GroupRule 表达式将首先尝试“赋值”。然后由于“表达式”是“赋值”中要匹配的第一个规则,它会尝试再次解析表达式,依此类推,直到堆栈被填满并且计算机 - 正如预期的那样 - 只是在一个闪亮的段错误中放弃。
所以我所做的是 - SequenceRules 将自己作为“叶子”添加到它们的第一条规则中,并成为非根规则。根规则是解析器首先尝试的规则。当其中一个被应用并匹配时,它会尝试一个接一个地子应用它的每个叶子,直到一个匹配。然后它会尝试匹配叶子的叶子,以此类推,直到不再匹配为止。
这样它就可以解析像这样的表达式
var1 = var2 = var3 = var4
恰到好处 =) 现在是有趣的东西。这段代码:
var1 = (var2 + var3)
不会解析。发生的情况是,var1 被解析(varAccess),assign 被子应用,它寻找一个表达式,尝试'括号',开始,在'('之后寻找一个表达式,找到 var2,然后在'+ ' 因为它期待一个 ')'。
为什么它不匹配 'var2 + var3' ? (是的,在你问之前有一个“添加”SequenceRule)。因为 'add' 不是根规则(以避免使用 parse-expression-beginning-with-expression-etc. 进行无限递归),并且叶子没有在 SequenceRules 中测试,否则它会解析类似
reader readLine() println()
作为
reader (readLine() println())
(例如,'1 = 3' 是 add 期望的表达式,varAccess a 的叶子)
而我们希望它是左关联的,例如解析为
(reader readLine()) println()
所以无论如何,现在我们遇到了这个问题,我们应该能够在 SequenceRules 中解析诸如“1 + 2”之类的表达式。该怎么办?添加一个特殊情况,即当 SequenceRules 以 TokenRule 开头时,它包含的 GroupRules 会被测试是否为叶子?在那个特定的例子之外,这甚至有意义吗?或者是否应该能够在 SequenceRule 的每个元素中指定是否应该对其进行叶子测试?告诉我你的想法(除了扔掉整个系统 - 无论如何这可能会在几个月内发生)
P.S:拜托,非常拜托,不要回答诸如“去阅读这本 400 页的书,否则你甚至不值得我们花时间”如果你觉得有必要 - 只是克制自己并在 reddit 上猛烈抨击。好的?提前致谢。
【问题讨论】: