python rply反向解析器
我正在使用python rply反向解析器,python,python-3.x,parsing,ply,Python,Python 3.x,Parsing,Ply,我正在使用rply和Python3.6为一个小privat项目创建一个lexer和一个解析器 但我注意到解析器似乎颠倒了lexerstream的顺序 这是我正在分析的文件: let test:string = "test"; print(test); Lexer输出: Token('LET', 'let') Token('NAME', 'test') Token('COLON', ':') Token('NAME', 'string') Token('EQUALS', '=') Token('
rply
和Python3.6为一个小privat项目创建一个lexer和一个解析器
但我注意到解析器似乎颠倒了lexerstream的顺序
这是我正在分析的文件:
let test:string = "test";
print(test);
Lexer输出:
Token('LET', 'let')
Token('NAME', 'test')
Token('COLON', ':')
Token('NAME', 'string')
Token('EQUALS', '=')
Token('STRING', '"test"')
Token('SEMI_COLON', ';')
Token('PRINT', 'print')
Token('OPEN_PARENS', '(')
Token('STRING', '"test"')
Token('CLOSE_PARENS', ')')
Token('SEMI_COLON', ';')
正如您所看到的,它是按照脚本的顺序进行的
我使用解析器创建一个名为test
、类型为string
和值为test
的变量。然后我想打印变量
它确实创建了变量,但当我想打印出来时,什么都没有
但是当我像这样翻转脚本时
print(test);
let test:string = "test";
它能够正确打印值
两个解析器“规则”如下所示:
打印:
创建变量:
@self.pg.production('expression : LET expression COLON expression EQUALS expression SEMI_COLON expression')
def create_var(p):
...
所以我的问题是:我如何改变内容解析的顺序
编辑:我在文档中查找了类似的问题或问题,但没有找到任何内容。这里有一个更简单的示例;希望你能看到这种模式 关键的洞察是,当产品的匹配被完全解析时,就会执行缩减操作(即解析器函数)。这意味着,如果一个产品包含非终端,那么这些非终端的操作将在整个产品的操作之前执行 应该很清楚为什么这是真的。每个生产操作都取决于所有组件的语义值,对于非终端,这些值是通过运行相应的操作生成的
现在,考虑这两种非常类似的方式来分析<代码>清单> />代码>在这两种情况下,我们假设有一个基本产品可以识别空的
列表(列表:
),而不执行任何操作
右递归:
list : thing list
list : list thing
左递归:
list : thing list
list : list thing
在这两种情况下,操作都会打印对象
,在右递归情况下是p[0]
,在左递归情况下是p[1]
正确的递归生成将导致以相反的顺序打印对象
s,因为只有在解析内部列表
之后(并且打印其组件),才能打印对象
但是左递归产品将按从左到右的顺序打印对象
s,原因相同。不同之处在于,在左递归情况下,内部(递归)列表
包含初始的对象
s,而在右递归情况下,列表
包含最终的对象
s
如果您只是在构建一个Python列表,其中包含东西
s,那么这可能并不重要,因为执行顺序并不重要。它只在本例中可见,因为该操作具有副作用(打印值),这使执行顺序可见
在极少数确实必要的情况下,还有其他技术来安排行动。但最佳实践是在语法上可行的时候总是使用左递归。左递归解析器效率更高,因为解析器不需要积累一堆不完整的结果。左递归通常也更适合您的操作
例如,在这里,左递归操作可以追加新值(p[0]。追加(p[1]);返回p[0]
),而右递归操作需要创建一个新列表(return[p[0]+p[1]
)。由于重复追加是平均线性时间,而重复连接是二次的,因此左递归解析器对于大型列表更具可伸缩性。好的,首先:感谢您的回答。这是我所见过的关于这个主题的最佳答案之一。因此,如果表达式依赖于另一个表达式,我基本上必须注意解析器的顺序表达式?因为我认为解析器只是通过lexerstream标记来获取标记。@llj97:解析器从左到右进行解析。它会在右侧边缘立即执行每个缩减操作。但这并不会神奇地将print语句在时间上向后移动。缩减操作中的print语句是在Reduce离子操作被执行,而不是当它打印的任何东西被标记时。这与任何程序都没有区别。当您printf(“%d\n”,a)时
调用printf
时会发生这种情况,而不是设置a
的值时……话虽如此,您通常不必考虑执行顺序,因为这无关紧要。每个非终端的值在使用前都会计算出来。您只需在计算中插入副作用(如pri)时考虑它哦,好吧,现在我明白了。非常感谢!