如何重写/修改当前Python解释器的语法结构,而不是太好地使用Python?

2024-09-27 00:21:29 发布

您现在位置:Python中文网/ 问答频道 /正文

这是我当前的Python解释器,它使用解析规则获取输入,然后打印出表达式。解释器工作得很好,但是我想对我当前的语法规则进行某些修改,并将其添加到新的语法规则中。到目前为止,我只能得到一些我想要的语法修改。你知道吗

以下是我想对当前语法所做的更改:

# <stmt-list> ::= empty | <stmt> <stmt-list>
to
# <stmt_list> ::= <stmt> | <stmt> <stmt_list>


# <factor> ::= id | intnum | ( <expr> )
to
# <base> ::= (<expr>) | id | number


<stmt> ::= id = <expr> ; | print <expr>;
to
<stmt> ::= id = <expr> ; | iprint <expr> ; | rprint <expr> ;

另外,我不确定如何将下面的新语法规则应用到我的解释器中,我想我可能已经有了它们?你知道吗

<prog> ::= <decl_list> <stmt_list>
<decl-list> ::= <decl> | <decl> <decl_list>
<decl> ::= <type> <id_list> ;
<type> ::= int | real
<id_list> ::= id | id {, <id_list>}

这是我当前语法的代码:

import sys

global varTable
varTable = {}

def main():
    global itProgram, nextToken, nextChar, nextLex, flagEof, strStmt
    nextToken = ""
    nextChar = ""
    flagEof = False
    strStmt = ""

    try:
        fileProgram = open(sys.argv[1], "rt")
    except IndexError:
        print "Missing input file!"
        return
    except IOError:
        print "Could not open \'" + sys.argv[1] + "\'!"
        return

    strProgram = fileProgram.read()
    itProgram = iter(strProgram)

    if strProgram == "":
        nextChar = ""
    else:
        nextChar = itProgram.next()

    #while not flagEof:
    funcLex()

    stmtList()

def funcLex():
    global itProgram, nextToken, nextLex, nextChar, flagEof, strStmt
    nextToken = ""
    nextLex = ""

    isFloat = False

    try:
        while nextChar.isspace():
            nextChar = itProgram.next()
    except StopIteration:
        nextChar = ""
        funcLex()

        return

    try:
        if nextChar == "(":
            nextToken = "LPARA"
            nextLex = nextChar
            nextChar = itProgram.next()
        elif nextChar == ")":
            nextToken = "RPARA"
            nextLex = nextChar
            nextChar = itProgram.next()
        elif nextChar == "+":
            nextToken = "ADD"
            nextLex = nextChar
            nextChar = itProgram.next()
        elif nextChar == "-":
            nextToken = "SUB"
            nextLex = nextChar
            nextChar = itProgram.next()
        elif nextChar == "*":
            nextToken = "MULT"
            nextLex = nextChar
            nextChar = itProgram.next()
        elif nextChar == "/":
            nextToken = "DIV"
            nextLex = nextChar
            nextChar = itProgram.next()
        elif nextChar == "=":
            nextToken = "ASSIGN"
            nextLex = nextChar
            nextChar = itProgram.next()
        elif nextChar == ";":
            nextToken = "SEMI"
            nextLex = nextChar
            nextChar = itProgram.next()
        elif nextChar.isalpha():
            nextLex = nextChar
            nextChar = itProgram.next()
            while nextChar.isalnum():
                nextLex += nextChar
                nextChar = itProgram.next()
            if nextLex == "print":
                nextToken = "PRINT"
            else:
                nextToken = "ID"
        elif nextChar.isalnum():
            nextLex = nextChar
            nextChar = itProgram.next()
            while nextChar.isalnum() or nextChar == ".":
                if nextChar == ".":
                    isFloat = True
                nextLex += nextChar
                nextChar = itProgram.next()
            if isFloat:
                nextToken = "FLOAT"
            else:
                nextToken = "INT"
        elif nextChar == "":
            nextLex = nextChar
            nextToken = "EMPTY"
            flagEof = True
        else:
            nextToken = "UNKNOWN"
            #print "Syntax error!"
    except StopIteration:
        nextChar = ""

    strStmt = strStmt + nextLex + " "
    if nextToken == "SEMI":
        print strStmt
        strStmt = ""

# <stmt-list> ::= empty | <stmt> <stmt-list>
def stmtList():
    global nextToken

    if nextToken == "EMPTY":
        print ">>> Empty .tiny file."
    else:
        while nextToken != "EMPTY":
            stmt()

# <stmt> ::= id = <expr> ; |
#            print <expr> ;
def stmt():
    global nextToken, nextLex

    if nextToken == "ID":
        varName = nextLex
        funcLex()
        if nextToken == "ASSIGN":
            funcLex()
            result = expr()
            if result[1] != "UNKNOWN":
                lookupVarTable(varName, result[0], result[1])
            else:
                printError("undefined variable.")
    elif nextToken == "PRINT":
        funcLex()
        result = expr()
        if result[1] != "UNKNOWN" and nextToken == "SEMI":
            print ">>> " + str(result[0])
        elif result[1] == "UNKNOWN":
            printError("undefined variable.")
    else:
        printError("<stmt> syntax error.")
        return

    if nextToken == "SEMI":
        funcLex()
    else:
        printError("<stmt> missing ';'")

# <expr> ::= <term> { + <term> | - <term> }
def expr():
    global nextToken, nextLex

    lResult = term()

    while nextToken == "ADD" or nextToken == "SUB":
        operator = nextToken
        funcLex()
        rResult = term()
        #Variable is not defined
        if lResult[1] == "UNKNOWN" or rResult[1] == "UNKNOWN":
            printError("Undefined variable!")
        if lResult[1] != rResult[1]:    #type mismatch
            printError("Type mismatch!")
        elif operator == "ADD":
            lResult = (lResult[0]+rResult[0], lResult[1])
        else:
            lResult = (lResult[0]-rResult[0], lResult[1])

    return lResult

# <term> ::= <factor> { * <factor> | / <factor> }
def term():
    global nextToken, nextLex

    lResult = factor()

    while nextToken == "MULT" or nextToken == "DIV":
        operator = nextToken
        funcLex()
        rResult = factor()
        #Variable is not defined
        if lResult[1] == "UNKNOWN" or rResult[1] == "UNKNOWN":
            printError("Undefined variable!")
        if lResult[1] != rResult[1]:    #type mismatch
            printError("Type mismatch!")
        elif operator == "MULT":
            lResult = (lResult[0]*rResult[0], lResult[1])
        else:
            lResult = (lResult[0]/rResult[0], lResult[1])

    return lResult

# <factor> ::= id | intnum | ( <expr> )
def factor():
    global nextToken, nextLex

    if nextToken == "ID":
        result = lookupVarTable(nextLex, 0, "UNKNOWN")
        funcLex()
    elif nextToken == "INT":
        result = (int(nextLex), "INT")
        funcLex()
    elif nextToken == "FLOAT":
        result = (float(nextLex), "FLOAT")
        funcLex()
    elif nextToken == "LPARA":
        funcLex()
        result = expr()
        if nextToken == "RPARA":
            funcLex()
        else:
            printError("<factor>")

    return result

def printError(strMessage):
    global strStmt

    if strStmt != "":
        print strStmt

    print ">>> Error: " + strMessage
    exit()

def lookupVarTable(varName, varValue, varType):

    #if varName not in varTable:
    # varValue == "UNKNOWN"
    if varType != "UNKNOWN":
        varTable[varName] = (varValue, varType)
        return varTable[varName]
    elif varName in varTable:
        return varTable[varName]
    else:
        return (varValue, varType)

if __name__ == "__main__":
    main()

Tags: idifresultelselistnextelifexpr
1条回答
网友
1楼 · 发布于 2024-09-27 00:21:29

{你应该考虑使用Python ^}有一个端口。他说

同时,以下是如何设计lexer:

def parser_file(file_obj):
    for line in file_obj:
        for char in line:
            yield char


mapping = {'(': 'LPARA',
           ')': 'RPARA',
           '+': 'ADD',
           '-': 'SUB',
           '*': 'MUL',
           '/': 'DIV',
           '=': 'ASSIGN',
           ';': 'SEMI'}


def lexer(chars):
    it_char = iter(chars)

    char = next(it_char)

    while True:
        # skip spaces
        while char.isspace():
            char = next(it_char)

        # find simple tokens
        if char in mapping:
            yield mapping[char], char
            char = next(it_char)
            continue

        # find complex tokens
        if char.isalpha():
            lex = char
            char = next(it_char)
            while char.isalnum():
                lex += char
                char = next(it_char)
            if lex == "print":
                yield "PRINT", lex
            else:
                yield "ID", lex
            continue
        elif char.isdigit():
            lex = char
            char = next(it_char)
            while char.isdigit():
                lex += char
                char = next(it_char)
            if char == ".":
                lex += char
                char = next(it_char)
                while char.isdigit():
                    lex += char
                    char = next(it_char)
            if "." in lex:
                yield "FLOAT", lex
            else:
                yield "INT", lex
            continue
        else:
            raise SyntaxError(char)

要使用它,您可以按如下方式处理:

import io

content = """\
10 + 12.5 / 18
(8 + 3.14)
"""

file_obj = io.BytesIO(content)

for token in lexer(parser_file(file_obj)):
    print(token)

你会得到:

('INT', '10')
('ADD', '+')
('FLOAT', '12.5')
('DIV', '/')
('INT', '18')
('LPARA', '(')
('INT', '8')
('ADD', '+')
('FLOAT', '3.14')
('RPARA', ')')

你当然可以用一个真正的文件。他说

对于解析器:使用堆栈构建抽象语法树并对其求值。他说

很抱歉,解释的时间太长,也不相关,所以请考虑在Code Review上发布。他说

相关问题 更多 >

    热门问题