如何使用 Python 的 Sly 进行多行解析。解析器类?



我正试图用一个名为sly的库创建自己的编程语言。我已经创建了一个lexer来标记我的程序,但我一直坚持让解析器成功地解析多条指令。当我没有考虑到这一点,并试图制作一个程序来测试解析树时,它给了我一个错误,说一堆令牌无效。我想出的临时解决方案是使用以下解析语句:

@_("expr n expr")
def expr(self, t):
return [t.expr0, t.expr1]
# I have also tried:
#  return t.expr1, t.expr2

这导致了一个令人讨厌的错误,因为解析树会过多地嵌套语句。

[
{
"some statement",
...,
"inner": [
{
"another statment",
...,
"inner": [
{
"another statment",
...,
"inner": []
}
]
}
]
}
]

我希望解析树是平的,这样你就只能得到必要的嵌套。就像下面的解析树一样。

[
{
"another statment",
...,
"inner": []
},
{
"another statment",
...,
"inner": []
},
{
"another statment",
...,
"inner": []
}
]

我想保持解析树的丑陋,然后重新格式化它,但根据树的大小,它可能会使程序变得非常慢。

该语言也是我的一个项目的一部分,github repo链接到这里:

对于所有重要文件:https://github.com/0x32767/0x102-discord-bot/tree/star2py/jpl4py/lang

解析类:https://github.com/0x32767/0x102-discord-bot/blob/a268fe9a63f87a9ebf39088cff13ee9a2edab931/jpl4py/lang/jpl.py#L81

被基因化的解析树:https://github.com/0x32767/0x102-discord-bot/blob/star2py/jpl4py/lang/hWorld.jpl.out.json

快速修复线:https://github.com/0x32767/0x102-discord-bot/blob/a268fe9a63f87a9ebf39088cff13ee9a2edab931/jpl4py/lang/jpl.py#L217

感谢您阅读

夏季

我设法通过在忽略列表中添加新行来解决这个问题。

更多详细信息

每个狡猾的人。Lexer类可以采用ignore类变量。我在这个变量中添加了新行,所以n,所以现在看起来像这样:ignore = "t n",所以现在我的lexer类看起来像:


class MyLexer(sly.Lexer):
ignore = "t n" # this is the edit that I made
# the rest of the MyLexer class

通知

这可能需要分号;来分隔各个语句,但这是个人偏好的问题。

如果在这里回答你自己的问题是一个很好的做法或否,我很抱歉,但我不希望其他人有这个问题。

我还是Sly的一个新手,从Ply开始,但你需要的是一个包含多个语句的规则,最简单的方法是通过递归。因此,您最终会得到如下基本语句:

expr_set : expr_set expr NEWLINE
| expr NEWLINE

expr_set总是导出一组结果。如果遇到第二种情况,则该集合就是单个表达式。如果它是第一个,那么它就是附加了新表达式的现有集合。因此,您最终得到以下代码:

@_("expr_set expr n")
def expr_set(self, t):
myset = t.expr_set
myset.append(t.expr)
return myset
@_("expr n")
def expr_set(self, t):
return [t.expr]

这有道理吗?顺便说一句,相同的expr_set可以用于任何嵌套的代码位,例如在函数或循环中。如果换行符对你来说很重要(似乎是这样(,你可能需要一个第三或第四子句来处理一些情况,比如一行只是换行符,以及程序的最后语句(或命令部分(后面没有换行符。我在这里问了一个类似的问题。

此外,我在早期实现中遇到的另一个小陷阱是,您不希望实现代码示例中建议的换行符忽略例程,因为它会忽略并吃掉这些换行符,并且您需要它们来分离您的语句。

最后,只要你不需要担心换行符本身,或者不需要担心没有换行符的最终语句,以下内容对你的目的是有效的:

@_("{ expr n }")
def expr_set(self, t):
return t.expr

这使用";"重复";符号请注意,大括号和大括号内的内容之间必须有空格。其中的内容将作为列表返回,花括号中的多个项目将呈现为多个列表。以下是我的脚本语言中的一些语句列表示例代码,其中至少有一条语句,每条语句都以换行符结尾:

@_('statement NEWLINE { statement NEWLINE }')
def statement_set(self, p):
statement_list = list(filter(lambda statement: statement != None, 
p.statement1 + [p.statement0]))
return StatementSet(statement_list)

同样,你确实需要花括号和其他符号之间的空格,否则它无法正确解析(你不想知道这让我绊倒了多长时间(。

最新更新