我找到了一个网站[Python: Writing a Compiler and Interpreter in 160 lines of code],它实现了一个简单的解释器,我对代码留下了非常深刻的印象并想要改进它,下面是源代码的修改版本:
#****************** Grammer ************************
# stmtlist := (statement)*
#
# statement := 'if' condition ('{')? stmtlist ['else' stmtlist] '}'
# | 'while' condition ('{')? stmtlist '}'
# | variable '=' expression
# | variable '+=' expression
# | variable '-=' expression
# | variable '*=' expression
# | variable '/=' expression
# | 'print' expression
#
# condition := expression ('=='|'!='|'>'|'<'|'>='|'<=') expression
#
# expression := term ('+'|'-' term)*
#
# term := factor ('*'|'/' factor)*
#
# factor := variable|digit
#****************** Lexer ************************
tokenlist = []
currtoken = ("", "", 0) # token, identifier name, value
keywords = set(["while", "if", "else", "print",
"=", "==", "!=", ">", ">=", "<", "<=",
"+", "-", "*", "/", "+=", "-=", "*=", "/=",
"{", "}"]) # '}' end 'while' and 'if'
symboltable = dict()
def nextToken():
global currtoken, symboltable
if(len(tokenlist) > 0):
s = tokenlist.pop(0)
if s in keywords:
currtoken = (s, "", 0)
elif s.isdigit():
#currtoken = ("digit", "", int(s))
currtoken = ("digit", "", float(s))
elif s.isalnum():
symboltable[s] = 0
currtoken = ("variable", s, 0)
else:
print("syntax error: " + s)
else:
currtoken = ("", "", 0)
def consume(expected):
if currtoken[0] == expected:
nextToken()
else:
print("expected " + expected + " not found")
#****************** Parser ************************
def parseFile(filename):
inputfile = open(filename, "r")
inputstring = inputfile.read()
global tokenlist
tokenlist = inputstring.split()
nextToken()
pgm = doStatementList()
return execStatementList(pgm)
def doStatementList():
stmts = []
newstmt = []
while currtoken[0] in ["while", "if", "print", "variable"]:
if currtoken[0] == "while":
# ["while", [condition], ['{'] [statementlist], '}']
consume("while")
newstmt = ["while"]
newstmt.append(doCondition())
if currtoken[0] == "{":
consume("{")
newstmt.append(doStatementList())
#consume("endwhile")
consume("}")
elif currtoken[0] == "if":
# ['if' [condition] [statementlist] ['{'] [['else' statementlist]] '}']
consume("if")
newstmt = ["if"]
newstmt.append(doCondition())
if currtoken[0] == "{":
consume("{")
newstmt.append(doStatementList())
if currtoken[0] == "else":
consume("else")
newstmt.append(doStatementList())
#consume("endif")
consume("}")
elif currtoken[0] == "print":
# ["print", [expression]]
consume("print")
newstmt = ["print"]
newstmt.append(doExpression())
elif currtoken[0] == "variable":
# ["=", [variable], [expression]]
variable = [currtoken[1]]
nextToken()
if currtoken[0] == "=":
consume("=")
newstmt = ["="]
elif currtoken[0] == "+=":
consume("+=")
newstmt = ["+="]
elif currtoken[0] == "-=":
consume("-=")
newstmt = ["-="]
elif currtoken[0] == "*=":
consume("*=")
newstmt = ["*="]
elif currtoken[0] == "/=":
consume("/=")
newstmt = ["/="]
newstmt.append(variable)
newstmt.append(doExpression())
else:
print("invalid statement: " + currtoken[0])
stmts.append(newstmt)
return stmts
def doCondition():
exp = doExpression()
# ["==|!=|>|<|>=|<=", [left side], [right side]]
if currtoken[0] in ["==", "!=", ">", ">=", "<", "<="]:
retval = [currtoken[0]]
retval.append(exp)
nextToken()
retval.append(doExpression())
else:
print("expected == or != not found")
return retval
def doExpression():
term = doTerm()
# carry the term in case there's no +|-
exp = term
# ["+|-", [left side], [right side]]
while currtoken[0] in ["+", "-"]:
exp = [currtoken[0]]
nextToken()
exp.append(doExpression())
exp.append(term)
print("exp=", exp)
return exp
def doTerm():
factor = doFactor()
term = factor
# ["*|/", [left side], [right side]]
while currtoken[0] in ["*", "/"]:
term = [currtoken[0]]
nextToken()
term.append(doTerm())
term.append(factor)
print("term=", term)
return term
def doFactor():
if currtoken[0] == "variable":
retval = currtoken[1]
nextToken()
elif currtoken[0] == "digit":
retval = currtoken[2]
nextToken()
return [retval]
#****************** Interpreter ************************
stack = []
def execStatementList(pgm):
for stmt in pgm:
execStatement(stmt)
def execStatement(stmt):
if stmt[0] == "while":
# ["while", [condition], [statementlist]]
execCondition(stmt[1])
while stack.pop():
execStatementList(stmt[2])
execCondition(stmt[1])
elif stmt[0] == "if":
# ['if' [condition] [statementlist] [['else' statementlist]] 'endif']
execCondition(stmt[1])
if stack.pop():
execStatementList(stmt[2])
elif len(stmt) == 4:
execStatementList(stmt[3])
elif stmt[0] == "=":
execExpression(stmt[2])
symboltable[stmt[1][0]] = stack.pop()
elif stmt[0] == "+=":
execExpression(stmt[2])
symboltable[stmt[1][0]] = symboltable[stmt[1][0]] + stack.pop()
elif stmt[0] == "-=":
execExpression(stmt[2])
symboltable[stmt[1][0]] = symboltable[stmt[1][0]] - stack.pop()
elif stmt[0] == "*=":
execExpression(stmt[2])
symboltable[stmt[1][0]] = symboltable[stmt[1][0]] * stack.pop()
elif stmt[0] == "/=":
execExpression(stmt[2])
symboltable[stmt[1][0]] = symboltable[stmt[1][0]] / stack.pop()
elif stmt[0] == "print":
execExpression(stmt[1])
print("output:" + str(stack.pop()))
else:
print("invalid statement")
def execCondition(cond):
# ["==|!=|>|<|>=|<=", [left side], [right side]]
execExpression(cond[1])
execExpression(cond[2])
a = stack.pop()
b = stack.pop()
if cond[0] == "==":
stack.append(a == b)
elif cond[0] == "!=":
stack.append(a != b)
elif cond[0] == ">":
stack.append(b > a)
elif cond[0] == ">=":
stack.append(b >= a)
elif cond[0] == "<":
stack.append(b < a)
elif cond[0] == "<=":
stack.append(b <= a)
def execExpression(exp):
if len(exp) == 3:
execExpression(exp[1])
execExpression(exp[2])
if exp[0] == "+":
a = stack.pop()
b = stack.pop()
stack.append(a + b)
elif exp[0] == "-":
a = stack.pop()
b = stack.pop()
stack.append(a - b)
if exp[0] == "*":
a = stack.pop()
b = stack.pop()
stack.append(a * b)
elif exp[0] == "/":
a = stack.pop()
b = stack.pop()
stack.append(a / b)
else:
#if type(exp[0]) == int:
if type(exp[0]) == float:
stack.append(exp[0])
else:
stack.append(symboltable[exp[0]])
if __name__ == "__main__":
parseFile("./simpleScript.txt")
以下是simpleScript.txt
文件:
d = 2 + 5 * 3 - 2 * 4 + 5
print d
预期结果应为14.0
,但我得到4.0
。我知道问题出在函数doExpression
和doTerm
中,但我无法弄明白如何纠正它,任何人都可以帮助我。
答案 0 :(得分:1)
我现在唯一的想法是为-
做一个特例。我的意思是你可以将它视为+
,如果你的-1
内部有多个表达式(你必须在下一个doExpression
中进行,所以我&#39} ; m传递一个布尔值。)
更改您的doExpression()
(对不起,这有点难看,也许有人会提出其他解决方案):
def doExpression(_b = True):
term = doTerm()
if _b == False:
tp = ['*']
tp.append([-1.0])
tp.append(term)
term = tp
# carry the term in case there's no +|-
exp = term
# ["+|-", [left side], [right side]]
while currtoken[0] in ["+", "-"]:
exp = ['+']
if currtoken[0] == '+':
nextToken()
exp.append(doExpression())
else: # '-'
nextToken()
exp.append(doExpression(_b = False))
exp.append(term)
print("exp=", exp)
return exp