变量存储 EQUALS 而不是字符串 |基于Python的解释器

问题描述 投票:0回答:1

我一直在用Python制作一个解释器,但遇到了一个问题,它识别字符串、变量、数字和表达式。在测试

 .lang
文件时,我注意到它输出了
{'$var': 'EQUALS'}
而不是变量的字符串或数字。 它完美地输出 "print"、"num"、"expr" 值,但不是变量,首先我尝试重新评估代码并将
 symbols[varname[4:]] = varvalue
更改为
symbols[varname[4:]] = varvalue[6:]
,这让我得到
{'$var': ' '}

它将“变量”识别为与

$var
关联的字符串,但输出
{'$var': 'EQUALS'}
,如字符串、num 或 expr 之前的 equal 一样。我希望它将“变量”存储为变量的字符串,如
{'$var': 'STRING: "variable"'}
中所示。

我似乎没有意识到某些事情,但我认为问题可能出在我的 parsedoASSIGN 函数中,有人可以告诉我或给我一个提示我可能做错了什么吗?

OUTPUT:
PS C:\Users\<user>\Desktop\spl> python basic.py test.lang
hello world
55
48
{'$var': 'EQUALS'}
test.lang:
print "hello world"
print 55
print (10 + 2) * 4
$var = "variable"
from sys import *

tokens = []
num_stack = []
symbols = {}

def open_file(filename):
    data = open(filename, 'r').read()
    data += "<EOF>"
    return data

def lex(filecontents):
    tok = ""
    state = 0
    varstarted = 0
    var = ""
    string = ""
    expr = ""
    n = ""
    isexpr = 0
    for char in filecontents:
        tok += char
        if tok == " ":
            if state == 0:
                tok = ""
            else:
                tok = " "
        elif tok == "\n" or tok =="<EOF>":
            if expr != "" and isexpr == 1:
                tokens.append("EXPR:" + expr)
                expr = ""
            elif expr != "" and isexpr == 0:
                tokens.append("NUM:" + expr)
                expr = ""
            elif var != "":
                tokens.append("VAR:" + var)
                var = ""
                varstarted = 0
            tok = ""
        elif tok == "=" and state == 0:
            if var != "":
                tokens.append("VAR:" + var)
                var = ""
                varstarted = 0
            tokens.append("EQUALS")
            tok = ""
        elif tok == "$" and state == 0:
            varstarted = 1
            var += tok
            tok = ""
        elif varstarted == 1:
            var += tok
            tok = ""
        elif tok == "PRINT" or tok == "print":
            tokens.append("PRINT")
            tok = ""
        elif tok == "0" or tok == "1" or tok == "2" or tok == "3" or tok == "4" or tok == "5" or tok == "6" or tok == "7" or tok == "8" or tok == "9":
            expr += tok
            tok = ""
        elif tok == "+" or tok == "-" or tok == "*" or tok == "/" or tok == "(" or tok == ")":
            isexpr = 1
            expr += tok
            tok = ""
        elif tok == "\"":
            if state == 0:
                state = 1
            elif state == 1:
                tokens.append("STRING:" + string + "\"")
                string = ""
                state = 0
                tok = ""
        elif state == 1:
            string += tok
            tok = ""
    #print(tokens)
    #return ''
    return tokens

def evalExpression(expr):
    return eval(expr)

def doPRINT(toPRINT):
    if(toPRINT[0:6] == "STRING"):
        toPRINT = toPRINT[8:]
        toPRINT = toPRINT[:-1]
    elif(toPRINT[0:3] == "NUM"):
        toPRINT = toPRINT[4:]
    elif(toPRINT[0:4] == "EXPR"):
        toPRINT = evalExpression(toPRINT[5:])
    print(toPRINT)

def doASSIGN(varname, varvalue):
    symbols[varname[4:]] = varvalue

def parse(toks):
    i = 0
    while(i < len(toks) - 1):
        if toks[i] + " " + toks[i+1][0:6] == "PRINT STRING" or toks[i] + " " + toks[i+1][0:3] == "PRINT NUM" or toks[i] + " " + toks[i+1][0:4] == "PRINT EXPR":
            if toks[i+1][0:6] == "STRING":
                doPRINT(toks[i+1])
            elif toks[i+1][0:3] == "NUM":
                doPRINT(toks[i+1])
            elif toks[i+1][0:4] == "EXPR":
                doPRINT(toks[i+1])
            i+= 2
        if toks[i][0:3] + " " + toks[i+1] + " " + toks[i+2][0:6] == "VAR EQUALS STRING" or toks[i][0:3] + " " + toks[i+1] + " " + toks[i+2][0:3] == "VAR EQUALS NUM" or toks[i][0:3] + " " + toks[i+1] + " " + toks[i+2][0:4] == "VAR EQUALS EXPR":
            if toks[i+2][0:6] == "STRING":
                doASSIGN(toks[i],toks[i+1])
            elif toks[i+2][0:3] == "NUM":
                doASSIGN(toks[i],toks[i+1])
            elif toks[i+2][0:4] == "EXPR":
                doASSIGN(evalExpression(toks[i+2][5:]))
            i += 3
    print(symbols)

def run():
    data = open_file(argv[1])
    toks = lex(data)
    parse(toks)

run()
python variables var interpreter
1个回答
0
投票

我们实际上可以通过仅更改解析器中的一个字符来解决问题!正如有人已经指出的那样,使用以下代码片段,每次在源程序中的某个位置找到

EQUALS
时,您都会附加
=

...
elif tok == "=" and state == 0:
    if var != "":
        tokens.append("VAR:" + var)
        var = ""
        varstarted = 0
    tokens.append("EQUALS")
    tok = ""
...

说明

这是因为您的程序会迭代源文件 (

test.lang
) 并尝试查找与含义上的相应标记匹配的任何符号。一旦您的词法分析器找到
=
EQUALS
就会被附加到标记列表中,无论上下文如何。为
EQUALS
代币实现上下文是一项具有挑战性但并非完全不可能的任务。

因此,虽然有一种方法可以通过对词法分析器进行一些更改来解决此问题,但如果语言本身没有变得比现在更复杂,则没有必要。我的意思是声明变量的结构不会比

$var = "string"
更复杂。一旦复杂性超过这个值,对词法分析器的更改就足够了(复杂,我的意思是类型声明之类的东西:
$var str = "string"
)。

解决方案

无论如何,让我们看一个简单的修复方法:

if toks[i][0:3] + " " + toks[i+1] + " " + toks[i+2][0:6] == "VAR EQUALS STRING" or ...:
    if toks[i+2][0:6] == "STRING":
        doASSIGN(toks[i],toks[i+2]) #: line I changed

我没有使用

doASSIGN(toks[I], toks[i+1]
,而是使用
doASSIGN(toks[i],toks[i+2])
,因为
toks[i+1]
会直接落在
EQUALS
而不是
STRING
上,因此导致
{'$var', 'EQUALS'}
。在试用该程序一段时间后,我发现没有理由不实现这一点,因为包含
EQUALS
只是一种形式,如果您决定实现程序优化,您可以在技术上包含它。

现在,这是最漂亮、最佳实践的解决方案吗?可能不是,但坦率地说,这是最简单、最快的一种。如果您需要在某处记录

doASSIGN
的存在,您始终可以通过向
EQUALS
函数添加第三个可选参数来创建后备变量。

但是,这个修复程序确实可以实现与所有其他修复程序相同的效果,无需付出太多努力,几乎不需要任何重写。或者,您也可以尝试使用

itertools
来实现前瞻技术。这也是一种非常流行的对源文件进行词法分析的方法。

所有其他解决方案都需要重写您的程序的大部分内容,这是我想避免做的事情,因为它应该仍然是您自己的工作。尽管如此,我建议您更深入地研究解释器设计并查看一些最佳实践!此外,您可能想查看用于构建解释器和编译器的流行库! :)

© www.soinside.com 2019 - 2024. All rights reserved.