【问题标题】:Global variables don't mantain their status after the usage of two distinct functions使用两个不同的函数后,全局变量不会保持其状态
【发布时间】:2016-03-12 20:02:25
【问题描述】:

所以我这几天都遇到了麻烦。基本上,我正在为我使用 python 创建的语言制作编译器。我们得到了 sintax 和 lexic 部分,现在正在创建目录过程和变量表(符号表)。在我的 Yacc 文件中,我有:

Yacc.py

import ply.yacc as yacc
import sys

tokens = Lex.tokens
#Global variables
procs = { }
current_fid = ""

# add new value to the procedure directory
def add_procs_to_dict(fid, ftipo, fparams, fdict):
    proc_dict = {}
    proc_dict[fid] = {
        'Tipo' : ftipo,
        'Params' : fparams,
        'Var_dict' : fdict
    }
    return proc_dict

# add new variable value to the procedure directory
def add_vars_to_dict(vid, vtipo, vparams):
    var_dict = {
        'Nombre' : vid,
        'Tipo' : vtipo,
        'Params' : vparams
        }
    print(current_fid)
    print(procs)    
    return proc_dict


# Parsing Rules    
def p_juego(p):
    '''Juego : JUEGO ID DOSP JuegoA JuegoB MainProgram'''
    current_fid = p[2]
    procs = add_procs_to_dict( p[2], p[1], 'void', {})

def p_vars(p):
    '''Vars : VAR ID COR_I Exp COR_D VarSizeA Vars2 DOSP Tipo PCOMA'''
    add_vars_to_dict( p[2], p[9], p[4])

这里要注意的重要一点是,我正在创建一个保存当前 ID 的变量(命名为 current_fid,这是插入到字典中的最后一个过程的名称)和一个字典变量(命名为 procs这是过程/函数目录)作为全局范围。

当解析器进入解析规则p_juego(p):(假设它输入的代码是正确的,并且我已经单独运行它)它假设设置为变量(current_fidprocs)在解析器进程中找到它的值。它确实设置了正确的值。我可以打印函数内部的变量并返回预期值。

一旦解析器退出函数p_juego(p)并进入另一个函数,如p_vars(p)(此函数将插入全局目录的最后一个过程/函数的符号表写入字典)全局变量(current_fidprocs) 在其中没有任何价值。 p_vars(p) 内有 2 个打印,始终显示变量为 null。

我对 python 比较陌生,也许我错过了一些关于语言的东西。我的意图是如果我在所有内容之前定义一个变量(在代码的顶部),使用这些“全局”变量的函数将更新它们的值并始终保持它们,即使另一个函数试图访问它们。 我尝试在名为 Semantics.py 的新 python 文件中添加过程,但变量的值在先前设置值的函数之外始终为空。

我在这里错过了什么?

【问题讨论】:

  • 请包含足够的代码/信息,以展示和重现您遇到的实际问题。尽量将问题的性质与您的实际代码分离。阅读this
  • 感谢您的编辑。我删除了不属于实际问题的部分代码。发的链接失效了,能再发一下吗?
  • 你在哪里运行这些函数?我认为展示那部分代码可以帮助我们理解问题
  • 这个问题对我来说很难回答,因为我正在使用 Ply.yacc 库,它几乎可以为我做所有事情。这些过程被调用,因为在 source.txt 上找到了正确的语法(该文件有我为编译器创建的 lenguaje)。也许您想问函数是否按我期望的顺序调用?

标签: python compiler-construction global-variables yacc


【解决方案1】:

为了避免这样的范围问题并且更明确,我建议你使用一个类。然后你可以使用 self.variable 来保存类方法调用之间的信息。

【讨论】:

  • 我尝试创建一个类的实例,该实例具有设置变量的过程。但就像 current_fid 字符串变量和 procs 字典变量一样,类的实例忘记了在函数上设置的值。
  • 那么重要的是要知道你运行函数的范围。
【解决方案2】:

[编辑] 你的代码有很多问题。

首先:

您的函数 add_vars_to_dict 定义并分配了一个您永远不会使用的 dict (var_dict) 并尝试返回函数范围内不存在的内容 (proc_dict)。

第二:

函数p_juego,每次被调用时,都会重新分配dict的值,这会让你失去procs

的先前值
procs = add_procs_to_dict( p[2], p[1], 'void', {})

但是,正如 majodi 所建议的那样,通常您可以使用一个类来解决全局变量问题,在该类中您使用实例变量而不是全局变量

类似这样的:

class ClassTest(object):

    def __init__(self):
        self.procs = {}
        self.current_fid = ""

    # add new value to the procedure directory
    def add_procs_to_dict(self, fid, ftipo, fparams, fdict):
        # do something

    # add new variable value to the procedure directory
    def add_vars_to_dict(self, vid, vtipo, vparams):
        # do something

    # Parsing Rules
    def p_juego(self, p):
        # do something

    def p_vars(self, p):
        # do something

【讨论】:

  • 感谢您的回答。第一个答案,我知道变量 var_dict 还没有做任何事情,但它会做。我把它留在那里,但为了示例,我更改了 print proc 的内容,因为我想强调那个特定的“全局”变量没有得到任何内容。第二部分,该函数假设被调用一次,但我认为这是一个主要问题。我想我应该像你说的那样修复那部分,将所有内容封装在一个类中。
【解决方案3】:

感谢大家的快速回复。我确实按照你们大多数人的建议做了另一个课程,但我没有保留我的全局值的原因是因为函数是按我没想到的顺序调用的。 PLY 库使用自下而上的过程来导航 sintax 树。实际上,在设置 even 之前读取值时调用了函数。

感谢大家的回复,因为这是我在 SO 中的第一篇帖子,所有回复答案、问我问题甚至纠正我的帖子以继续使用该网站的人都让我感到鼓舞。

再次感谢。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-21
    • 2020-12-15
    • 1970-01-01
    相关资源
    最近更新 更多