多行 PLY 解析器
Multiline PLY parser
我正在使用 PLY 来解析跨越多行(或通过“;”分隔)的算术表达式。我不确定是否要忽略换行符,因为我真的不需要它们。如果忽略它们(return None in 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?
这似乎更像是一个语言设计问题,而不是实现问题,当然,即使设计已完全指定,实现也可能并不明显。
允许多行表达式的语言有几种可能的方法,我完全不清楚您对实现哪一种感兴趣:
Python风格。表达式以 ;
或换行符终止,但括号表达式 ((...)
、[...]
、{...}
).
[=75= 中的换行符将被忽略]
ECMAscript 风格。表达式需要以 ;
结束,但如果下一个标记不能扩展表达式,将在行尾自动插入 ;
。
最大咀嚼。表达式是最长可能的标记流,可以将其解析为表达式,但是 ;
可以在必要时用于分隔表达式。
我实际上不知道实现此选项的通用语言。但是它(或一些变体)可以编写,例如,
a = 3 b = 7 c = a + b
这看起来应该是不含糊的。
实施策略。
1。括号隐藏换行符。
在语言变得复杂之前,这实现起来相当简单。对于简单的表达式,您只需要保留一个全局括号深度计数,它随着(任何类型的)左括号增加而随着右括号减少;那么 \n
规则 return 如果括号深度为 0,则为 ;
,否则吞下换行符。
我个人觉得这种续行风格很烦人,尽管每次我回到 Python 编程时我很快就习惯了它。尽管如此,它总是有点烦人,你不能写:
x = some * long * sub-expression +
another * long * sub-expression +
magical-constant
这在 ECMAscript 中工作得很好。
2。自动分号
事实证明,您可以在词法分析器的 ECMAscript 中处理这个问题,方法是查找一行中的第一个标记和合法标记对字典中的前一个标记。如果令牌对不在字典中,则使用分号令牌 returned 而不是行中的第一个令牌;该标记会被记住,以便下一次调用词法分析器时 return 它。构建合法的 token-pairs 字典并不简单,验证它是否正确更难,但只需要在每次更改语法时都这样做:)
ECMAscript 实际上有一些规则的例外情况,因此一些原本合法的表达式在用换行符分隔时变得非法。这些例外可以通过从合法对字典中删除一些标记对来实现(碰巧)。例如,++
post-increment operator 不能用换行符与其操作数分开,因此在下面插入一个分号:
a
++b
否则会出现语法错误。 (前两个标记将被解析为 a++
,然后无法解析 b
。)
另一个有趣的案例是:
a + b
(c + d).format("x")
这可以解析为函数调用:
a + b(c + d).format("x")
所以最好在 b
和 (
之间自动插入分号。
3。最大咀嚼
这实际上只是自动分号插入的一个变体,即使两个标记之间没有换行符也可以插入分号。由于上述例外情况,您可能希望拥有两组不同的合法令牌对,或者将某些令牌对标记为仅在未用换行符分隔时才有效。
我正在使用 PLY 来解析跨越多行(或通过“;”分隔)的算术表达式。我不确定是否要忽略换行符,因为我真的不需要它们。如果忽略它们(return None in 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?
这似乎更像是一个语言设计问题,而不是实现问题,当然,即使设计已完全指定,实现也可能并不明显。
允许多行表达式的语言有几种可能的方法,我完全不清楚您对实现哪一种感兴趣:
Python风格。表达式以
[=75= 中的换行符将被忽略];
或换行符终止,但括号表达式 ((...)
、[...]
、{...}
).ECMAscript 风格。表达式需要以
;
结束,但如果下一个标记不能扩展表达式,将在行尾自动插入;
。最大咀嚼。表达式是最长可能的标记流,可以将其解析为表达式,但是
;
可以在必要时用于分隔表达式。我实际上不知道实现此选项的通用语言。但是它(或一些变体)可以编写,例如,
a = 3 b = 7 c = a + b
这看起来应该是不含糊的。
实施策略。
1。括号隐藏换行符。
在语言变得复杂之前,这实现起来相当简单。对于简单的表达式,您只需要保留一个全局括号深度计数,它随着(任何类型的)左括号增加而随着右括号减少;那么 \n
规则 return 如果括号深度为 0,则为 ;
,否则吞下换行符。
我个人觉得这种续行风格很烦人,尽管每次我回到 Python 编程时我很快就习惯了它。尽管如此,它总是有点烦人,你不能写:
x = some * long * sub-expression +
another * long * sub-expression +
magical-constant
这在 ECMAscript 中工作得很好。
2。自动分号
事实证明,您可以在词法分析器的 ECMAscript 中处理这个问题,方法是查找一行中的第一个标记和合法标记对字典中的前一个标记。如果令牌对不在字典中,则使用分号令牌 returned 而不是行中的第一个令牌;该标记会被记住,以便下一次调用词法分析器时 return 它。构建合法的 token-pairs 字典并不简单,验证它是否正确更难,但只需要在每次更改语法时都这样做:)
ECMAscript 实际上有一些规则的例外情况,因此一些原本合法的表达式在用换行符分隔时变得非法。这些例外可以通过从合法对字典中删除一些标记对来实现(碰巧)。例如,++
post-increment operator 不能用换行符与其操作数分开,因此在下面插入一个分号:
a
++b
否则会出现语法错误。 (前两个标记将被解析为 a++
,然后无法解析 b
。)
另一个有趣的案例是:
a + b
(c + d).format("x")
这可以解析为函数调用:
a + b(c + d).format("x")
所以最好在 b
和 (
之间自动插入分号。
3。最大咀嚼
这实际上只是自动分号插入的一个变体,即使两个标记之间没有换行符也可以插入分号。由于上述例外情况,您可能希望拥有两组不同的合法令牌对,或者将某些令牌对标记为仅在未用换行符分隔时才有效。