我使用PLY来解析跨越多行的算术表达式(或通过&#34 ;;"分开)。我不确定是否要忽略换行令牌,因为我并不真正需要它们。如果忽略它们(在t_NEWLINE
中返回无),是否有必要在作品中对它们进行说明?
def t_NEWLINE(self, t):
r"""\n+|;+"""
t.lexer.lineno += t.value.count("\n") + t.value.count(";")
return t # or not
def p_expression(self, t):
""" expression : ..."""
def p_expressions(self, t):
""" expressions : expression
| expressions NEWLINE expression
"""
# Do I need NEWLINE at all? How does the production figure out where expression ends without NEWLINE?
答案 0 :(得分:1)
这似乎更像是语言设计而不是实现的问题,尽管当然,即使完全指定了设计,实现也可能并不明显。
有几种可能的语言方法允许多个多行表达式,我对你有兴趣实现哪一个并不清楚:
Python风格。表达式由;
或换行符终止,但在括号表达式((...)
,[...]
,{...}
)内忽略换行符。
ECMAscript风格。表达式必须由;
终止,但如果下一个标记无法扩展表达式,则会在行尾自动插入;
。
最大-蒙克。表达式是可以解析为表达式的最长的令牌流,但如果需要,;
可用于分隔表达式。
我实际上并不知道实现此选项的通用语言。但它(或某些变体)可以编写,例如,
a = 3 b = 7 c = a + b
这似乎应该是明确的。
在语言变得复杂之前,这是非常简单的实现。对于简单表达式,您只需要保留一个全局括号深度计数,该计数通过(任何类型的)左括号递增并随关闭递减;如果括号深度为0,则\n
规则返回;
,否则吞下换行符。
我个人觉得这种线条延续的风格令人恼火,虽然我每次回到Python编程时都会很快习惯它。尽管如此,它仍然有点让你无法写出来:
x = some * long * sub-expression +
another * long * sub-expression +
magical-constant
在ECMAscript中可以正常工作。
事实证明,你可以在词法分析器的ECMAscript中处理这个问题,方法是在一行上查找第一个标记,在合法标记对的字典中查找前一个标记。如果令牌对不在字典中,则返回分号标记而不是行上的第一个标记;记住该令牌,以便下一次对词法分析器的调用将返回它。构建合法令牌对的字典是非常重要的,并且验证它是正确的甚至更难,但只需要在每次更改语法时完成:)
ECMAscript实际上对规则有一些例外,因此在换行符分隔时,某些本来合法的表达式会被视为非法。通过从法律对的字典中删除一些令牌对,可以实现这些异常(当它发生时)。例如,++
后增量运算符不能通过换行符与其操作数分隔,因此在下面插入一个分号:
a
++b
否则会出现语法错误。 (前两个令牌将被解析为a++
,然后无法解析b
。)
另一个有趣的案例是:
a + b
(c + d).format("x")
这可以解析为函数调用:
a + b(c + d).format("x")
所以最好在b
和(
之间进行自动分号插入。
这实际上只是自动分号插入的变体,即使两个令牌之间没有换行符,也可以插入分号。由于上面提到的例外情况,您可能希望拥有两组不同的合法令牌对,或者将某些令牌对标记为仅在未换行时才有效。