Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
python rply反向解析器_Python_Python 3.x_Parsing_Ply - Fatal编程技术网

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)时考虑它哦,好吧,现在我明白了。非常感谢!